#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 *fname, const char* data, int length) { struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); l->jq = jq; l->fname = jv_string(fname); 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_free(l->fname); jv_mem_free(l->linemap); jv_mem_free((char*)l->data); jv_mem_free(l); } } 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, ...) { 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]; } jv m1 = jv_string_vfmt(fmt, fmtargs); if (!jv_is_valid(m1)) { jq_report_error(l->jq, m1); return; } if (loc.start == -1) { jq_report_error(l->jq, jv_string_fmt("jq: error: %s\n", jv_string_value(m1))); jv_free(m1); return; } jv m2 = jv_string_fmt("%s at %s, line %d:\n%.*s%*s", jv_string_value(m1), jv_string_value(l->fname), startline + 1, locfile_line_length(l, startline), l->data + offset, loc.start - offset, ""); jv_free(m1); jq_report_error(l->jq, m2); return; }