#include #include #include #include #include #include #include "jq.h" #include "jv_alloc.h" #include "locfile.h" struct locfile* locfile_init(jq_state *jq, const char* data, int length) { struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); l->jq = jq; l->data = jv_mem_alloc(length); memcpy((char*)l->data,data,length); l->length = length; l->nlines = 1; l->refct = 1; for (int i=0; inlines++; } l->linemap = jv_mem_alloc(sizeof(int) * (l->nlines + 1)); l->linemap[0] = 0; int line = 1; for (int i=0; ilinemap[line] = i+1; // at start of line, not of \n line++; } } l->linemap[l->nlines] = length+1; // virtual last \n return l; } struct locfile* locfile_retain(struct locfile* l) { l->refct++; return l; } void locfile_free(struct locfile* l) { if (--(l->refct) == 0) { jv_mem_free(l->linemap); jv_mem_free((char*)l->data); jv_mem_free(l); } } static int locfile_get_line(struct locfile* l, int pos) { assert(pos < l->length); int line = 1; while (l->linemap[line] <= pos) line++; // == if pos at start (before, never ==, because pos never on \n) assert(line-1 < l->nlines); return line-1; } static int locfile_line_length(struct locfile* l, int line) { assert(line < l->nlines); return l->linemap[line+1] - l->linemap[line] -1; // -1 to omit \n } void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { jq_err_cb cb; void *cb_data; va_list fmtargs; va_start(fmtargs, fmt); int startline; int offset; if (loc.start != -1) { startline = locfile_get_line(l, loc.start); offset = l->linemap[startline]; } jq_get_error_cb(l->jq, &cb, &cb_data); jv m1 = jv_string_vfmt(fmt, fmtargs); if (!jv_is_valid(m1)) { jv_free(m1); goto enomem; } jv m2; if (loc.start == -1) { m2 = jv_string_fmt("%s\n", jv_string_value(m1)); if (cb) cb(cb_data, m2); else fprintf(stderr, "%s", jv_string_value(m2)); jv_free(m1); jv_free(m2); return; } m2 = jv_string_fmt("%s\n%.*s%*s", jv_string_value(m1), locfile_line_length(l, startline), l->data + offset, loc.start - offset, ""); jv_free(m1); if (!jv_is_valid(m2)) { jv_free(m2); goto enomem; } if (cb) cb(cb_data, m2); else fprintf(stderr, "%s", jv_string_value(m2)); jv_free(m2); return; enomem: if (cb != NULL) cb(cb_data, jv_invalid()); else if (errno == ENOMEM || errno == 0) fprintf(stderr, "Error formatting jq compilation error: %s", strerror(errno ? errno : ENOMEM)); else fprintf(stderr, "Error formatting jq compilation error: %s", strerror(errno)); return; }