1 /* 2 * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <string.h> 18 #include <errno.h> 19 20 #include "ucode/source.h" 21 #include "ucode/platform.h" 22 23 24 uc_source_t * 25 uc_source_new_file(const char *path) 26 { 27 FILE *fp = fopen(path, "rb"); 28 uc_source_t *src; 29 30 if (!fp) 31 return NULL; 32 33 src = xalloc(ALIGN(sizeof(*src)) + strlen(path) + 1); 34 35 src->header.type = UC_SOURCE; 36 src->header.refcount = 1; 37 38 src->fp = fp; 39 src->buffer = NULL; 40 src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), path); 41 src->runpath = src->filename; 42 43 src->lineinfo.count = 0; 44 src->lineinfo.entries = NULL; 45 46 return src; 47 } 48 49 uc_source_t * 50 uc_source_new_buffer(const char *name, char *buf, size_t len) 51 { 52 FILE *fp = fmemopen(buf, len, "rb"); 53 uc_source_t *src; 54 55 if (!fp) 56 return NULL; 57 58 src = xalloc(ALIGN(sizeof(*src)) + strlen(name) + 1); 59 60 src->header.type = UC_SOURCE; 61 src->header.refcount = 1; 62 63 src->fp = fp; 64 src->buffer = buf; 65 src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), name); 66 67 src->lineinfo.count = 0; 68 src->lineinfo.entries = NULL; 69 70 return src; 71 } 72 73 size_t 74 uc_source_get_line(uc_source_t *source, size_t *offset) 75 { 76 uc_lineinfo_t *lines = &source->lineinfo; 77 size_t i, pos = 0, line = 1, lastoff = 0; 78 79 for (i = 0; i <= lines->count; i++) { 80 if (pos >= *offset || i == lines->count) { 81 *offset = (*offset - lastoff) + 1; 82 83 return line; 84 } 85 86 /* don't count first line jump as actual byte */ 87 if (i > 0 && (lines->entries[i] & 0x80)) { 88 line++; 89 pos++; 90 lastoff = pos; 91 } 92 93 pos += (lines->entries[i] & 0x7f); 94 } 95 96 return 0; 97 } 98 99 uc_source_type_t 100 uc_source_type_test(uc_source_t *source) 101 { 102 union { char s[sizeof(uint32_t)]; uint32_t n; } buf = { 0 }; 103 uc_source_type_t type = UC_SOURCE_TYPE_PLAIN; 104 FILE *fp = source->fp; 105 size_t rlen; 106 int c = 0; 107 108 if (fread(buf.s, 1, 2, fp) == 2 && !strncmp(buf.s, "#!", 2)) { 109 source->off += 2; 110 111 while ((c = fgetc(fp)) != EOF) { 112 source->off++; 113 114 if (c == '\n') 115 break; 116 } 117 } 118 else { 119 if (fseek(fp, 0L, SEEK_SET) == -1) 120 fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno)); 121 } 122 123 rlen = fread(buf.s, 1, 4, fp); 124 125 if (rlen == 4 && buf.n == htobe32(UC_PRECOMPILED_BYTECODE_MAGIC)) { 126 type = UC_SOURCE_TYPE_PRECOMPILED; 127 } 128 else { 129 if (c == '\n') { 130 uc_source_line_update(source, source->off - 1); 131 uc_source_line_next(source); 132 } 133 else { 134 uc_source_line_update(source, source->off); 135 } 136 } 137 138 if (fseek(fp, -(long)rlen, SEEK_CUR) == -1) 139 fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno)); 140 141 return type; 142 } 143 144 /* lineinfo is encoded in bytes: the most significant bit specifies whether 145 * to advance the line count by one or not, while the remaining 7 bits encode 146 * the amounts of bytes on the current line. 147 * 148 * If a line has more than 127 characters, the first byte will be set to 149 * 0xff (1 1111111) and subsequent bytes will encode the remaining characters 150 * in bits 1..7 while setting bit 8 to 0. A line with 400 characters will thus 151 * be encoded as 0xff 0x7f 0x7f 0x13 (1:1111111 + 0:1111111 + 0:1111111 + 0:1111111). 152 * 153 * The newline character itself is not counted, so an empty line is encoded as 154 * 0x80 (1:0000000). 155 */ 156 157 void 158 uc_source_line_next(uc_source_t *source) 159 { 160 uc_vector_push(&source->lineinfo, 0x80); 161 } 162 163 void 164 uc_source_line_update(uc_source_t *source, size_t off) 165 { 166 uc_lineinfo_t *lines = &source->lineinfo; 167 uint8_t *entry, n; 168 169 if (!lines->count) 170 uc_source_line_next(source); 171 172 entry = uc_vector_last(lines); 173 174 if ((entry[0] & 0x7f) + off <= 0x7f) { 175 entry[0] += off; 176 } 177 else { 178 off -= (0x7f - (entry[0] & 0x7f)); 179 entry[0] |= 0x7f; 180 181 while (off > 0) { 182 n = (off > 0x7f) ? 0x7f : off; 183 uc_vector_push(lines, n); 184 off -= n; 185 } 186 } 187 } 188 189 void 190 uc_source_runpath_set(uc_source_t *source, const char *runpath) 191 { 192 if (source->runpath != source->filename) 193 free(source->runpath); 194 195 source->runpath = runpath ? xstrdup(runpath) : NULL; 196 } 197 198 bool 199 uc_source_export_add(uc_source_t *source, uc_value_t *name) 200 { 201 ssize_t idx = uc_source_export_lookup(source, name); 202 203 if (idx > -1) 204 return false; 205 206 uc_vector_push(&source->exports, ucv_get(name)); 207 208 return true; 209 } 210 211 ssize_t 212 uc_source_export_lookup(uc_source_t *source, uc_value_t *name) 213 { 214 size_t i; 215 216 for (i = 0; i < source->exports.count; i++) 217 if (ucv_is_equal(source->exports.entries[i], name)) 218 return i; 219 220 return -1; 221 } 222
This page was automatically generated by LXR 0.3.1. • OpenWrt