• 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         src->fp = fp;
 35         src->buffer = NULL;
 36         src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), path);
 37 
 38         src->usecount = 1;
 39 
 40         src->lineinfo.count = 0;
 41         src->lineinfo.entries = NULL;
 42 
 43         return src;
 44 }
 45 
 46 uc_source_t *
 47 uc_source_new_buffer(const char *name, char *buf, size_t len)
 48 {
 49         FILE *fp = fmemopen(buf, len, "rb");
 50         uc_source_t *src;
 51 
 52         if (!fp)
 53                 return NULL;
 54 
 55         src = xalloc(ALIGN(sizeof(*src)) + strlen(name) + 1);
 56         src->fp = fp;
 57         src->buffer = buf;
 58         src->filename = strcpy((char *)src + ALIGN(sizeof(*src)), name);
 59 
 60         src->usecount = 1;
 61 
 62         src->lineinfo.count = 0;
 63         src->lineinfo.entries = NULL;
 64 
 65         return src;
 66 }
 67 
 68 size_t
 69 uc_source_get_line(uc_source_t *source, size_t *offset)
 70 {
 71         uc_lineinfo_t *lines = &source->lineinfo;
 72         size_t i, pos = 0, line = 0, lastoff = 0;
 73 
 74         for (i = 0; i < lines->count; i++) {
 75                 if (lines->entries[i] & 0x80) {
 76                         lastoff = pos;
 77                         line++;
 78                         pos++;
 79                 }
 80 
 81                 pos += (lines->entries[i] & 0x7f);
 82 
 83                 if (pos >= *offset) {
 84                         *offset -= lastoff - 1;
 85 
 86                         return line;
 87                 }
 88         }
 89 
 90         return 0;
 91 }
 92 
 93 uc_source_t *
 94 uc_source_get(uc_source_t *source)
 95 {
 96         if (!source)
 97                 return NULL;
 98 
 99         source->usecount++;
100 
101         return source;
102 }
103 
104 void
105 uc_source_put(uc_source_t *source)
106 {
107         if (!source)
108                 return;
109 
110         if (source->usecount > 1) {
111                 source->usecount--;
112 
113                 return;
114         }
115 
116         uc_vector_clear(&source->lineinfo);
117         fclose(source->fp);
118         free(source->buffer);
119         free(source);
120 }
121 
122 uc_source_type_t
123 uc_source_type_test(uc_source_t *source)
124 {
125         union { char s[sizeof(uint32_t)]; uint32_t n; } buf;
126         uc_source_type_t type = UC_SOURCE_TYPE_PLAIN;
127         FILE *fp = source->fp;
128         size_t rlen;
129         int c = 0;
130 
131         if (fread(buf.s, 1, 2, fp) == 2 && !strncmp(buf.s, "#!", 2)) {
132                 source->off += 2;
133 
134                 while ((c = fgetc(fp)) != EOF) {
135                         source->off++;
136 
137                         if (c == '\n')
138                                 break;
139                 }
140         }
141         else {
142                 if (fseek(fp, 0L, SEEK_SET) == -1)
143                         fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno));
144         }
145 
146         rlen = fread(buf.s, 1, 4, fp);
147 
148         if (rlen == 4 && buf.n == htobe32(UC_PRECOMPILED_BYTECODE_MAGIC)) {
149                 type = UC_SOURCE_TYPE_PRECOMPILED;
150         }
151         else {
152                 uc_source_line_update(source, source->off);
153 
154                 if (c == '\n')
155                         uc_source_line_next(source);
156         }
157 
158         if (fseek(fp, -(long)rlen, SEEK_CUR) == -1)
159                 fprintf(stderr, "Failed to rewind source buffer: %s\n", strerror(errno));
160 
161         return type;
162 }
163 
164 /* lineinfo is encoded in bytes: the most significant bit specifies whether
165  * to advance the line count by one or not, while the remaining 7 bits encode
166  * the amounts of bytes on the current line.
167  *
168  * If a line has more than 127 characters, the first byte will be set to
169  * 0xff (1 1111111) and subsequent bytes will encode the remaining characters
170  * in bits 1..7 while setting bit 8 to 0. A line with 400 characters will thus
171  * be encoded as 0xff 0x7f 0x7f 0x13 (1:1111111 + 0:1111111 + 0:1111111 + 0:1111111).
172  *
173  * The newline character itself is not counted, so an empty line is encoded as
174  * 0x80 (1:0000000).
175  */
176 
177 void
178 uc_source_line_next(uc_source_t *source)
179 {
180         uc_lineinfo_t *lines = &source->lineinfo;
181 
182         uc_vector_grow(lines);
183         lines->entries[lines->count++] = 0x80;
184 }
185 
186 void
187 uc_source_line_update(uc_source_t *source, size_t off)
188 {
189         uc_lineinfo_t *lines = &source->lineinfo;
190         uint8_t *entry, n;
191 
192         if (!lines->count)
193                 uc_source_line_next(source);
194 
195         entry = uc_vector_last(lines);
196 
197         if ((entry[0] & 0x7f) + off <= 0x7f) {
198                 entry[0] += off;
199         }
200         else {
201                 off -= (0x7f - (entry[0] & 0x7f));
202                 entry[0] |= 0x7f;
203 
204                 while (off > 0) {
205                         n = (off > 0x7f) ? 0x7f : off;
206                         uc_vector_grow(lines);
207                         entry = uc_vector_last(lines);
208                         entry[1] = n;
209                         off -= n;
210                         lines->count++;
211                 }
212         }
213 }
214 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt