• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/source.c

  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_lineinfo_t *lines = &source->lineinfo;
161 
162         uc_vector_grow(lines);
163         lines->entries[lines->count++] = 0x80;
164 }
165 
166 void
167 uc_source_line_update(uc_source_t *source, size_t off)
168 {
169         uc_lineinfo_t *lines = &source->lineinfo;
170         uint8_t *entry, n;
171 
172         if (!lines->count)
173                 uc_source_line_next(source);
174 
175         entry = uc_vector_last(lines);
176 
177         if ((entry[0] & 0x7f) + off <= 0x7f) {
178                 entry[0] += off;
179         }
180         else {
181                 off -= (0x7f - (entry[0] & 0x7f));
182                 entry[0] |= 0x7f;
183 
184                 while (off > 0) {
185                         n = (off > 0x7f) ? 0x7f : off;
186                         uc_vector_grow(lines);
187                         entry = uc_vector_last(lines);
188                         entry[1] = n;
189                         off -= n;
190                         lines->count++;
191                 }
192         }
193 }
194 
195 void
196 uc_source_runpath_set(uc_source_t *source, const char *runpath)
197 {
198         if (source->runpath != source->filename)
199                 free(source->runpath);
200 
201         source->runpath = runpath ? xstrdup(runpath) : NULL;
202 }
203 
204 bool
205 uc_source_export_add(uc_source_t *source, uc_value_t *name)
206 {
207         ssize_t idx = uc_source_export_lookup(source, name);
208 
209         if (idx > -1)
210                 return false;
211 
212         uc_vector_push(&source->exports, ucv_get(name));
213 
214         return true;
215 }
216 
217 ssize_t
218 uc_source_export_lookup(uc_source_t *source, uc_value_t *name)
219 {
220         size_t i;
221 
222         for (i = 0; i < source->exports.count; i++)
223                 if (ucv_is_equal(source->exports.entries[i], name))
224                         return i;
225 
226         return -1;
227 }
228 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt