aboutsummaryrefslogtreecommitdiff
path: root/src/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c142
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);
+}