• 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 #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 = xstrdup(runpath);
198 }
199 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt