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 #include <endian.h> 20 21 #include "ucode/source.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 = 0, lastoff = 0; 78 79 for (i = 0; i < lines->count; i++) { 80 if (lines->entries[i] & 0x80) { 81 lastoff = pos; 82 line++; 83 pos++; 84 } 85 86 pos += (lines->entries[i] & 0x7f); 87 88 if (pos >= *offset) { 89 *offset -= lastoff - 1; 90 91 return line; 92 } 93 } 94 95 return 0; 96 } 97 98 uc_source_type_t 99 uc_source_type_test(uc_source_t *source) 100 { 101 union { char s[sizeof(uint32_t)]; uint32_t n; } buf = { 0 }; 102 uc_source_type_t type = UC_SOURCE_TYPE_PLAIN; 103 FILE *fp = source->fp; 104 size_t rlen; 105 int c = 0; 106 107 if (fread(buf.s, 1, 2, fp) == 2 && !strncmp(buf.s, "#!", 2)) { 108 source->off += 2; 109 110 while ((c = fgetc(fp)) != EOF) { 111 source->off++; 112 113 if (c == '\n') 114 break; 115 } 116 } 117 else { 118 if (fseek(fp, 0L, SEEK_SET) == -1) 119 fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno)); 120 } 121 122 rlen = fread(buf.s, 1, 4, fp); 123 124 if (rlen == 4 && buf.n == htobe32(UC_PRECOMPILED_BYTECODE_MAGIC)) { 125 type = UC_SOURCE_TYPE_PRECOMPILED; 126 } 127 else { 128 uc_source_line_update(source, source->off); 129 130 if (c == '\n') 131 uc_source_line_next(source); 132 } 133 134 if (fseek(fp, -(long)rlen, SEEK_CUR) == -1) 135 fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno)); 136 137 return type; 138 } 139 140 /* lineinfo is encoded in bytes: the most significant bit specifies whether 141 * to advance the line count by one or not, while the remaining 7 bits encode 142 * the amounts of bytes on the current line. 143 * 144 * If a line has more than 127 characters, the first byte will be set to 145 * 0xff (1 1111111) and subsequent bytes will encode the remaining characters 146 * in bits 1..7 while setting bit 8 to 0. A line with 400 characters will thus 147 * be encoded as 0xff 0x7f 0x7f 0x13 (1:1111111 + 0:1111111 + 0:1111111 + 0:1111111). 148 * 149 * The newline character itself is not counted, so an empty line is encoded as 150 * 0x80 (1:0000000). 151 */ 152 153 void 154 uc_source_line_next(uc_source_t *source) 155 { 156 uc_lineinfo_t *lines = &source->lineinfo; 157 158 uc_vector_grow(lines); 159 lines->entries[lines->count++] = 0x80; 160 } 161 162 void 163 uc_source_line_update(uc_source_t *source, size_t off) 164 { 165 uc_lineinfo_t *lines = &source->lineinfo; 166 uint8_t *entry, n; 167 168 if (!lines->count) 169 uc_source_line_next(source); 170 171 entry = uc_vector_last(lines); 172 173 if ((entry[0] & 0x7f) + off <= 0x7f) { 174 entry[0] += off; 175 } 176 else { 177 off -= (0x7f - (entry[0] & 0x7f)); 178 entry[0] |= 0x7f; 179 180 while (off > 0) { 181 n = (off > 0x7f) ? 0x7f : off; 182 uc_vector_grow(lines); 183 entry = uc_vector_last(lines); 184 entry[1] = n; 185 off -= n; 186 lines->count++; 187 } 188 } 189 } 190 191 void 192 uc_source_runpath_set(uc_source_t *source, const char *runpath) 193 { 194 if (source->runpath != source->filename) 195 free(source->runpath); 196 197 source->runpath = runpath ? xstrdup(runpath) : NULL; 198 } 199 200 bool 201 uc_source_export_add(uc_source_t *source, uc_value_t *name) 202 { 203 ssize_t idx = uc_source_export_lookup(source, name); 204 205 if (idx > -1) 206 return false; 207 208 uc_vector_push(&source->exports, ucv_get(name)); 209 210 return true; 211 } 212 213 ssize_t 214 uc_source_export_lookup(uc_source_t *source, uc_value_t *name) 215 { 216 size_t i; 217 218 for (i = 0; i < source->exports.count; i++) 219 if (ucv_is_equal(source->exports.entries[i], name)) 220 return i; 221 222 return -1; 223 } 224
This page was automatically generated by LXR 0.3.1. • OpenWrt