diff options
Diffstat (limited to 'src/common.c')
| -rw-r--r-- | src/common.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..b25b6a2 --- /dev/null +++ b/src/common.c @@ -0,0 +1,142 @@ +#include "ducky.h" + +vartype spec_zero(void) +{ + return 0; +} + +vartype spec_rand(void) +{ + return rand(); +} + +vartype spec_time(void) +{ + return time(NULL); +} + +vartype (*special_funcs[])(void) = { + spec_zero, + spec_rand, + spec_time, +}; + +void __attribute__((noreturn,format(printf,3,4))) error(jmp_buf exit_point, int current_line, const char *fmt, ...) +{ + char fmtbuf[256]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); + if(current_line) + vid_logf("Line %d: ", current_line); + vid_logf("ERROR: %s", fmtbuf); + va_end(ap); + + longjmp(exit_point, 1); +} + +vartype get_special(enum special_id special, jmp_buf exit_point, int current_line) +{ + if(special < ARRAYLEN(special_funcs)) + return special_funcs[special](); + else + error(exit_point, current_line, "unknown special stream"); +} + +/* grabs a line from a file, -1 on error, returns # bytes read otherwise */ +int read_line(int fd, char *buf, size_t sz) +{ + unsigned i = 0; + int bytes_read = 0; + int status = 1; + while(i < sz) + { + char c; + status = read(fd, &c, 1); + if(status != 1) + break; + + ++bytes_read; + + if(c == '\r') + continue; + if(c == '\n' || c == EOF) + { + break; + } + + buf[i++] = c; + } + buf[MIN(i, sz - 1)] = '\0'; + + return (status <= 0)?-1:bytes_read; +} + +/* index_lines() precalculates the offset of each line for faster jumping */ + +off_t *index_lines(int fd, unsigned *numlines, bool labels, bool (*isValidVariable)(const char*), void (*setConst)(const char*, bool), void (*setVariable)(const char*, vartype)) +{ + size_t sz = sizeof(off_t); + off_t *data = malloc(sz); + + /* this uses 1-indexed line numbers, so the first indice is wasted */ + unsigned idx = 1; + + while(1) + { + sz += sizeof(off_t); + data = realloc(data, sz); + data[idx] = lseek(fd, 0, SEEK_CUR); + + char buf[MAX_LINE_LEN]; + + if(read_line(fd, buf, sizeof(buf)) < 0) + break; + + if(labels) + { + char *save = NULL; + char *tok = strtok_r(buf, " \t", &save); + if(tok && (strcmp(tok, "LABEL") == 0 || strcmp("LBL", tok) == 0)) + { + tok = strtok_r(NULL, " \t", &save); + if(tok && isValidVariable(tok)) + { + setVariable(tok, idx); + setConst(tok, true); + } + } + } + + ++idx; + } + + lseek(fd, 0, SEEK_SET); + + *numlines = idx - 1; + + return data; +} + +void __attribute__((format(printf,1,2))) vid_logf(const char *fmt, ...) +{ + char fmtbuf[256]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); + printf("%s\n", fmtbuf); + va_end(ap); +} + +void __attribute__((format(printf,2,3))) warning_real(int current_line, const char *fmt, ...) +{ + char fmtbuf[256]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); + vid_logf("Line %d: WARNING: %s\n", current_line, fmtbuf); + va_end(ap); +} |