Line | Count | Source |
1 | | #include <assert.h> |
2 | | #include <errno.h> |
3 | | #include <stdarg.h> |
4 | | #include <stdlib.h> |
5 | | #include <stdio.h> |
6 | | #include <string.h> |
7 | | #include "jq.h" |
8 | | #include "jv_alloc.h" |
9 | | #include "locfile.h" |
10 | | #include "util.h" |
11 | | |
12 | 0 | struct locfile* locfile_init(jq_state *jq, const char *fname, const char* data, int length) { |
13 | 0 | struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); |
14 | 0 | l->jq = jq; |
15 | 0 | l->fname = jv_string(fname); |
16 | 0 | l->data = jv_mem_alloc(length); |
17 | 0 | memcpy((char*)l->data,data,length); |
18 | 0 | l->length = length; |
19 | 0 | l->nlines = 1; |
20 | 0 | l->refct = 1; |
21 | 0 | for (int i=0; i<length; i++) { |
22 | 0 | if (data[i] == '\n') l->nlines++; |
23 | 0 | } |
24 | 0 | l->linemap = jv_mem_calloc(l->nlines + 1, sizeof(int)); |
25 | 0 | l->linemap[0] = 0; |
26 | 0 | int line = 1; |
27 | 0 | for (int i=0; i<length; i++) { |
28 | 0 | if (data[i] == '\n') { |
29 | 0 | l->linemap[line] = i+1; // at start of line, not of \n |
30 | 0 | line++; |
31 | 0 | } |
32 | 0 | } |
33 | 0 | l->linemap[l->nlines] = length+1; // virtual last \n |
34 | 0 | return l; |
35 | 0 | } |
36 | | |
37 | 0 | struct locfile* locfile_retain(struct locfile* l) { |
38 | 0 | l->refct++; |
39 | 0 | return l; |
40 | 0 | } |
41 | 0 | void locfile_free(struct locfile* l) { |
42 | 0 | if (--(l->refct) == 0) { |
43 | 0 | jv_free(l->fname); |
44 | 0 | jv_mem_free(l->linemap); |
45 | 0 | jv_mem_free((char*)l->data); |
46 | 0 | jv_mem_free(l); |
47 | 0 | } |
48 | 0 | } |
49 | | |
50 | 0 | int locfile_get_line(struct locfile* l, int pos) { |
51 | 0 | assert(pos < l->length); |
52 | 0 | int line = 1; |
53 | 0 | while (l->linemap[line] <= pos) line++; // == if pos at start (before, never ==, because pos never on \n) |
54 | 0 | assert(line-1 < l->nlines); |
55 | 0 | return line-1; |
56 | 0 | } |
57 | | |
58 | 0 | static int locfile_line_length(struct locfile* l, int line) { |
59 | 0 | assert(line < l->nlines); |
60 | 0 | return l->linemap[line+1] - l->linemap[line] -1; // -1 to omit \n |
61 | 0 | } |
62 | | |
63 | 0 | void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { |
64 | 0 | va_list fmtargs; |
65 | 0 | va_start(fmtargs, fmt); |
66 | |
|
67 | 0 | jv m1 = jv_string_vfmt(fmt, fmtargs); |
68 | 0 | va_end(fmtargs); |
69 | 0 | if (!jv_is_valid(m1)) { |
70 | 0 | jq_report_error(l->jq, m1); |
71 | 0 | return; |
72 | 0 | } |
73 | 0 | if (loc.start == -1) { |
74 | 0 | jq_report_error(l->jq, jv_string_fmt("jq: error: %s", jv_string_value(m1))); |
75 | 0 | jv_free(m1); |
76 | 0 | return; |
77 | 0 | } |
78 | | |
79 | 0 | int startline = locfile_get_line(l, loc.start); |
80 | 0 | int offset = l->linemap[startline]; |
81 | 0 | int end = MIN(loc.end, MAX(l->linemap[startline+1] - 1, loc.start + 1)); |
82 | 0 | jv underline = jv_string_repeat(jv_string("^"), end - loc.start); |
83 | 0 | jv m2 = jv_string_fmt("%s at %s, line %d, column %d:\n %.*s\n %*s", |
84 | 0 | jv_string_value(m1), jv_string_value(l->fname), |
85 | 0 | startline + 1, loc.start - offset + 1, |
86 | 0 | locfile_line_length(l, startline), l->data + offset, |
87 | 0 | end - offset, jv_string_value(underline)); |
88 | 0 | jv_free(m1); |
89 | 0 | jv_free(underline); |
90 | 0 | jq_report_error(l->jq, m2); |
91 | 0 | return; |
92 | 0 | } |