Files
jq/src/locfile.c
T
Emanuele Torre 527c5abab1 jv_mem_calloc(): always call with (nmemb, size)
It does not matter much since they most likely just get multiplied
together, but some compilers would complain about this if these were
calls to calloc.
2023-12-11 20:47:32 +01:00

93 lines
2.4 KiB
C

#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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; i<length; i++) {
if (data[i] == '\n') l->nlines++;
}
l->linemap = jv_mem_calloc(l->nlines + 1, sizeof(int));
l->linemap[0] = 0;
int line = 1;
for (int i=0; i<length; i++) {
if (data[i] == '\n') {
l->linemap[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);
va_end(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<unknown location>", 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;
}