Improve line tracker.
The new version is able to hold input history from several source lines, which makes it easier to implement #line directives in lexers. * include/mailutils/locus.h (mu_linetrack_stat): Remove start_line (mu_linetrack_origin): New proto. * libmailutils/locus/linetrack.c: Improve indexing. Keep track of several input files. * libmailutils/tests/linetrack.at: Add new tests. * libmailutils/tests/linetrack.c: Improve command set. * mimeview/grammar.y (make_node): Initialize locus
Showing
5 changed files
with
514 additions
and
113 deletions
... | @@ -43,10 +43,9 @@ typedef struct mu_linetrack *mu_linetrack_t; | ... | @@ -43,10 +43,9 @@ typedef struct mu_linetrack *mu_linetrack_t; |
43 | 43 | ||
44 | struct mu_linetrack_stat | 44 | struct mu_linetrack_stat |
45 | { | 45 | { |
46 | unsigned start_line; /* Start line number (1-based) */ | 46 | size_t n_files; /* Number of source files */ |
47 | size_t n_lines; /* Number of lines, including the recent (incomplete) | 47 | size_t n_lines; /* Number of lines, including the recent (incomplete) one */ |
48 | one */ | 48 | size_t n_chars; /* Total number of characters */ |
49 | size_t n_chars; /* Total number of characters */ | ||
50 | }; | 49 | }; |
51 | 50 | ||
52 | int mu_ident_ref (char const *name, char const **refname); | 51 | int mu_ident_ref (char const *name, char const **refname); |
... | @@ -81,6 +80,7 @@ mu_locus_point_same_line (struct mu_locus_point const *a, | ... | @@ -81,6 +80,7 @@ mu_locus_point_same_line (struct mu_locus_point const *a, |
81 | 80 | ||
82 | int mu_linetrack_create (mu_linetrack_t *ret, | 81 | int mu_linetrack_create (mu_linetrack_t *ret, |
83 | char const *file_name, size_t max_lines); | 82 | char const *file_name, size_t max_lines); |
83 | int mu_linetrack_origin (mu_linetrack_t trk, struct mu_locus_point const *pt); | ||
84 | int mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt); | 84 | int mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt); |
85 | void mu_linetrack_free (mu_linetrack_t trk); | 85 | void mu_linetrack_free (mu_linetrack_t trk); |
86 | void mu_linetrack_destroy (mu_linetrack_t *trk); | 86 | void mu_linetrack_destroy (mu_linetrack_t *trk); | ... | ... |
... | @@ -21,46 +21,176 @@ | ... | @@ -21,46 +21,176 @@ |
21 | #include <mailutils/locus.h> | 21 | #include <mailutils/locus.h> |
22 | #include <mailutils/error.h> | 22 | #include <mailutils/error.h> |
23 | 23 | ||
24 | /* The line-tracker structure keeps track of the last N lines read from a | 24 | /* The line-tracker structure keeps track of the last N lines read from one |
25 | text input file. For each line read it keeps the number of characters | 25 | or more input files. For each line read it keeps the number of characters |
26 | in that line including the newline. This information is stored in a | 26 | in that line including the newline. This information is stored in a |
27 | syclic stack of N elements. Top of stack always represents the current | 27 | cyclic stack of N elements (N >= 2). Top of stack always represents the |
28 | line. For the purpose of line tracker, current line is the line that is | 28 | current line. For the purpose of line tracker, current line is the line |
29 | being visited, such that its final newline character has not yet been | 29 | that is being visited, such that its final newline character has not yet |
30 | seen. Once the newline is seen, the line is pushed on stack, and a new | 30 | been seen. Once the newline is seen, the line is pushed on stack, and a |
31 | current line is assumed. | 31 | new current line is assumed. |
32 | 32 | ||
33 | The value of N must not be less than 2. | 33 | Each input file is represented by a directory entry keeping its name, |
34 | number of the first line that is stored in the tracker and the index of | ||
35 | that line in the cols stack. Entries form a doubly-linked list, with | ||
36 | head pointing to the most recent (current) source. When a new line is | ||
37 | being added to the stack which is full, its eldest entry is discarded | ||
38 | and is assigned to that line and the directory of the eldest source is | ||
39 | updated accordingly. If the entry represented the only line of the | ||
40 | source, the source is discarded. | ||
34 | */ | 41 | */ |
35 | struct mu_linetrack | 42 | |
43 | struct source | ||
36 | { | 44 | { |
37 | char const *file_name; /* Name of the source file */ | 45 | char const *file_name; /* Name of the source file */ |
46 | size_t idx; /* Index of the first element on stack */ | ||
47 | unsigned line; /* Number of line corresponding to cols[idx] */ | ||
48 | struct source *next, *prev; | ||
49 | }; | ||
50 | |||
51 | struct mu_linetrack | ||
52 | { | ||
53 | struct source *s_head, *s_tail; | ||
54 | /* Directory of source files. Most recent one is | ||
55 | s_head */ | ||
56 | |||
38 | size_t max_lines; /* Max. number of lines history kept by tracker (N) */ | 57 | size_t max_lines; /* Max. number of lines history kept by tracker (N) */ |
39 | size_t head; /* Index of the eldest element on stack */ | 58 | size_t head; /* Index of the eldest element on stack */ |
40 | size_t tos; /* Index of the most recent element on stack | 59 | size_t tos; /* Index of the most recent element on stack |
41 | (< max_lines) */ | 60 | (< max_lines) */ |
42 | unsigned hline; /* Number of line corresponding to cols[head] */ | ||
43 | unsigned *cols; /* Cyclic stack or character counts. | 61 | unsigned *cols; /* Cyclic stack or character counts. |
44 | Number of characters in line (hline + n) is | 62 | Number of characters in line (line + n) is |
45 | cols[head + n] (0 <= n <= tos). */ | 63 | cols[head + n] (0 <= n <= tos). */ |
46 | }; | 64 | }; |
47 | 65 | ||
66 | static inline size_t | ||
67 | trk_incr (struct mu_linetrack *trk, size_t a) | ||
68 | { | ||
69 | return (a + 1) % trk->max_lines; | ||
70 | } | ||
71 | |||
72 | static inline size_t | ||
73 | trk_decr (struct mu_linetrack *trk, size_t a) | ||
74 | { | ||
75 | return (a + trk->max_lines - 1) % trk->max_lines; | ||
76 | } | ||
77 | |||
78 | static inline unsigned | ||
79 | count_lines (mu_linetrack_t trk, size_t from) | ||
80 | { | ||
81 | return (trk->tos + trk->max_lines - from) % trk->max_lines + 1; | ||
82 | } | ||
83 | |||
84 | #ifndef SIZE_MAX | ||
85 | # define SIZE_MAX (~((size_t)0)) | ||
86 | #endif | ||
87 | |||
88 | static int | ||
89 | count_chars (struct mu_linetrack *trk, size_t i, size_t *ret) | ||
90 | { | ||
91 | size_t nch = 0; | ||
92 | |||
93 | while (1) | ||
94 | { | ||
95 | unsigned n = trk->cols[i]; | ||
96 | if (SIZE_MAX - nch < n) | ||
97 | return ERANGE; | ||
98 | nch += n; | ||
99 | if (i == trk->tos) | ||
100 | break; | ||
101 | i = trk_incr (trk, i); | ||
102 | } | ||
103 | *ret = nch; | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static size_t | ||
108 | count_files (struct mu_linetrack *trk) | ||
109 | { | ||
110 | struct source *sp; | ||
111 | size_t n = 0; | ||
112 | for (sp = trk->s_head; sp; sp = sp->next) | ||
113 | n++; | ||
114 | return n; | ||
115 | } | ||
116 | |||
117 | static void | ||
118 | del_source (mu_linetrack_t trk, struct source *sp) | ||
119 | { | ||
120 | if (sp->prev) | ||
121 | sp->prev->next = sp->next; | ||
122 | else | ||
123 | trk->s_head = sp->next; | ||
124 | if (sp->next) | ||
125 | sp->next->prev = sp->prev; | ||
126 | else | ||
127 | trk->s_tail = sp->prev; | ||
128 | mu_ident_deref (sp->file_name); | ||
129 | free (sp); | ||
130 | } | ||
131 | |||
48 | static inline unsigned * | 132 | static inline unsigned * |
49 | cols_ptr (mu_linetrack_t trk, size_t n) | 133 | push (mu_linetrack_t trk) |
50 | { | 134 | { |
51 | return &trk->cols[(trk->head + n) % trk->max_lines]; | 135 | trk->tos = trk_incr (trk, trk->tos); |
136 | if (trk->tos == trk->head) | ||
137 | { | ||
138 | trk->head = trk_incr (trk, trk->head); | ||
139 | trk->s_tail->idx = trk->head; | ||
140 | trk->s_tail->line++; | ||
141 | } | ||
142 | if (trk->s_tail->prev && trk->s_tail->idx == trk->s_tail->prev->idx) | ||
143 | del_source (trk, trk->s_tail); | ||
144 | trk->cols[trk->tos] = 0; | ||
145 | return &trk->cols[trk->tos]; | ||
52 | } | 146 | } |
53 | 147 | ||
54 | static inline unsigned * | 148 | static inline unsigned * |
55 | cols_tos_ptr (mu_linetrack_t trk) | 149 | pop (mu_linetrack_t trk) |
56 | { | 150 | { |
57 | return cols_ptr (trk, trk->tos); | 151 | if (trk->tos == trk->head) |
152 | return NULL; | ||
153 | if (trk->tos == trk->s_head->idx) | ||
154 | del_source (trk, trk->s_head); | ||
155 | |||
156 | trk->tos = trk_decr (trk, trk->tos); | ||
157 | |||
158 | return &trk->cols[trk->tos]; | ||
58 | } | 159 | } |
59 | 160 | ||
60 | static inline unsigned | 161 | int |
61 | cols_peek (mu_linetrack_t trk, size_t n) | 162 | mu_linetrack_origin (mu_linetrack_t trk, struct mu_locus_point const *pt) |
62 | { | 163 | { |
63 | return *cols_ptr (trk, n); | 164 | int rc; |
165 | struct source *sp; | ||
166 | |||
167 | if (!trk || !pt || !pt->mu_file || pt->mu_line == 0) | ||
168 | return EINVAL; | ||
169 | sp = malloc (sizeof *sp); | ||
170 | if (!sp) | ||
171 | return errno; | ||
172 | rc = mu_ident_ref (pt->mu_file, &sp->file_name); | ||
173 | if (rc) | ||
174 | { | ||
175 | free (sp); | ||
176 | return rc; | ||
177 | } | ||
178 | |||
179 | if (trk->cols[trk->tos]) | ||
180 | push (trk); | ||
181 | |||
182 | sp->idx = trk->tos; | ||
183 | sp->line = pt->mu_line; | ||
184 | trk->cols[sp->idx] = pt->mu_col; | ||
185 | |||
186 | sp->prev = NULL; | ||
187 | sp->next = trk->s_head; | ||
188 | if (trk->s_head) | ||
189 | trk->s_head->prev = sp; | ||
190 | else | ||
191 | trk->s_tail = sp; | ||
192 | trk->s_head = sp; | ||
193 | return 0; | ||
64 | } | 194 | } |
65 | 195 | ||
66 | int | 196 | int |
... | @@ -69,10 +199,12 @@ mu_linetrack_create (mu_linetrack_t *ret, | ... | @@ -69,10 +199,12 @@ mu_linetrack_create (mu_linetrack_t *ret, |
69 | { | 199 | { |
70 | int rc; | 200 | int rc; |
71 | struct mu_linetrack *trk; | 201 | struct mu_linetrack *trk; |
202 | struct mu_locus_point pt; | ||
72 | 203 | ||
73 | trk = malloc (sizeof *trk); | 204 | trk = malloc (sizeof *trk); |
74 | if (!trk) | 205 | if (!trk) |
75 | return errno; | 206 | return errno; |
207 | |||
76 | trk->cols = calloc (max_lines, sizeof (trk->cols[0])); | 208 | trk->cols = calloc (max_lines, sizeof (trk->cols[0])); |
77 | if (!trk->cols) | 209 | if (!trk->cols) |
78 | { | 210 | { |
... | @@ -80,21 +212,25 @@ mu_linetrack_create (mu_linetrack_t *ret, | ... | @@ -80,21 +212,25 @@ mu_linetrack_create (mu_linetrack_t *ret, |
80 | free (trk); | 212 | free (trk); |
81 | return rc; | 213 | return rc; |
82 | } | 214 | } |
83 | rc = mu_ident_ref (file_name, &trk->file_name); | 215 | trk->s_head = trk->s_tail = NULL; |
84 | if (rc) | 216 | |
85 | { | ||
86 | free (trk->cols); | ||
87 | free (trk); | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | if (max_lines < 2) | 217 | if (max_lines < 2) |
92 | max_lines = 2; | 218 | max_lines = 2; |
93 | trk->max_lines = max_lines; | 219 | trk->max_lines = max_lines; |
94 | trk->head = 0; | 220 | trk->head = 0; |
95 | trk->tos = 0; | 221 | trk->tos = 0; |
96 | trk->hline = 1; | ||
97 | trk->cols[0] = 0; | 222 | trk->cols[0] = 0; |
223 | |||
224 | pt.mu_file = file_name; | ||
225 | pt.mu_line = 1; | ||
226 | pt.mu_col = 0; | ||
227 | rc = mu_linetrack_origin (trk, &pt); | ||
228 | if (rc) | ||
229 | { | ||
230 | free (trk->cols); | ||
231 | free (trk); | ||
232 | return rc; | ||
233 | } | ||
98 | 234 | ||
99 | *ret = trk; | 235 | *ret = trk; |
100 | return 0; | 236 | return 0; |
... | @@ -107,10 +243,10 @@ mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt) | ... | @@ -107,10 +243,10 @@ mu_linetrack_rebase (mu_linetrack_t trk, struct mu_locus_point const *pt) |
107 | int rc = mu_ident_ref (pt->mu_file, &file_name); | 243 | int rc = mu_ident_ref (pt->mu_file, &file_name); |
108 | if (rc) | 244 | if (rc) |
109 | return rc; | 245 | return rc; |
110 | mu_ident_deref (trk->file_name); | 246 | mu_ident_deref (trk->s_head->file_name); |
111 | trk->file_name = file_name; | 247 | trk->s_head->file_name = file_name; |
112 | trk->hline = pt->mu_line; | 248 | trk->s_head->line = pt->mu_line; |
113 | *cols_ptr (trk, 0) = pt->mu_col; | 249 | trk->cols[trk->s_head->idx] = pt->mu_col; |
114 | return 0; | 250 | return 0; |
115 | } | 251 | } |
116 | 252 | ||
... | @@ -119,7 +255,8 @@ mu_linetrack_free (mu_linetrack_t trk) | ... | @@ -119,7 +255,8 @@ mu_linetrack_free (mu_linetrack_t trk) |
119 | { | 255 | { |
120 | if (trk) | 256 | if (trk) |
121 | { | 257 | { |
122 | mu_ident_deref (trk->file_name); | 258 | while (trk->s_head) |
259 | del_source (trk, trk->s_head); | ||
123 | free (trk->cols); | 260 | free (trk->cols); |
124 | free (trk); | 261 | free (trk); |
125 | } | 262 | } |
... | @@ -135,58 +272,20 @@ mu_linetrack_destroy (mu_linetrack_t *trk) | ... | @@ -135,58 +272,20 @@ mu_linetrack_destroy (mu_linetrack_t *trk) |
135 | } | 272 | } |
136 | } | 273 | } |
137 | 274 | ||
138 | static inline unsigned * | ||
139 | push (mu_linetrack_t trk) | ||
140 | { | ||
141 | unsigned *ptr; | ||
142 | if (trk->tos == trk->max_lines - 1) | ||
143 | { | ||
144 | trk->head++; | ||
145 | trk->hline++; | ||
146 | } | ||
147 | else | ||
148 | trk->tos++; | ||
149 | *(ptr = cols_tos_ptr (trk)) = 0; | ||
150 | return ptr; | ||
151 | } | ||
152 | |||
153 | static inline unsigned * | ||
154 | pop (mu_linetrack_t trk) | ||
155 | { | ||
156 | if (trk->tos == 0) | ||
157 | return NULL; | ||
158 | trk->tos--; | ||
159 | return cols_tos_ptr (trk); | ||
160 | } | ||
161 | |||
162 | #ifndef SIZE_MAX | ||
163 | # define SIZE_MAX (~((size_t)0)) | ||
164 | #endif | ||
165 | |||
166 | int | 275 | int |
167 | mu_linetrack_stat (struct mu_linetrack *trk, struct mu_linetrack_stat *st) | 276 | mu_linetrack_stat (struct mu_linetrack *trk, struct mu_linetrack_stat *st) |
168 | { | 277 | { |
169 | size_t i, nch = 0; | 278 | if (count_chars (trk, trk->head, &st->n_chars)) |
170 | 279 | return ERANGE; | |
171 | for (i = 0; i <= trk->tos; i++) | 280 | st->n_files = count_files (trk); |
172 | { | 281 | st->n_lines = count_lines (trk, trk->head); |
173 | unsigned n = cols_peek (trk, i); | ||
174 | if (SIZE_MAX - nch < n) | ||
175 | return ERANGE; | ||
176 | nch += n; | ||
177 | } | ||
178 | |||
179 | st->start_line = trk->hline; | ||
180 | st->n_lines = trk->tos + 1; | ||
181 | st->n_chars = nch; | ||
182 | |||
183 | return 0; | 282 | return 0; |
184 | } | 283 | } |
185 | 284 | ||
186 | int | 285 | int |
187 | mu_linetrack_at_bol (struct mu_linetrack *trk) | 286 | mu_linetrack_at_bol (struct mu_linetrack *trk) |
188 | { | 287 | { |
189 | return *cols_tos_ptr (trk) == 0; | 288 | return trk->cols[trk->tos] == 0; |
190 | } | 289 | } |
191 | 290 | ||
192 | void | 291 | void |
... | @@ -199,10 +298,11 @@ mu_linetrack_advance (struct mu_linetrack *trk, | ... | @@ -199,10 +298,11 @@ mu_linetrack_advance (struct mu_linetrack *trk, |
199 | if (text == NULL || leng == 0) | 298 | if (text == NULL || leng == 0) |
200 | return; | 299 | return; |
201 | 300 | ||
202 | mu_locus_point_set_file (&loc->beg, trk->file_name); | 301 | mu_locus_point_set_file (&loc->beg, trk->s_head->file_name); |
203 | mu_locus_point_set_file (&loc->end, trk->file_name); | 302 | mu_locus_point_set_file (&loc->end, trk->s_head->file_name); |
204 | loc->beg.mu_line = trk->hline + trk->tos; | 303 | loc->beg.mu_line = |
205 | ptr = cols_tos_ptr (trk); | 304 | trk->s_head->line + count_lines (trk, trk->s_head->idx) - 1; |
305 | ptr = &trk->cols[trk->tos]; | ||
206 | loc->beg.mu_col = *ptr + 1; | 306 | loc->beg.mu_col = *ptr + 1; |
207 | while (leng--) | 307 | while (leng--) |
208 | { | 308 | { |
... | @@ -211,16 +311,18 @@ mu_linetrack_advance (struct mu_linetrack *trk, | ... | @@ -211,16 +311,18 @@ mu_linetrack_advance (struct mu_linetrack *trk, |
211 | ptr = push (trk); | 311 | ptr = push (trk); |
212 | text++; | 312 | text++; |
213 | } | 313 | } |
314 | |||
315 | loc->end.mu_line = | ||
316 | trk->s_head->line + count_lines (trk, trk->s_head->idx) - 1; | ||
214 | if (*ptr) | 317 | if (*ptr) |
215 | { | 318 | { |
216 | loc->end.mu_line = trk->hline + trk->tos; | ||
217 | loc->end.mu_col = *ptr; | 319 | loc->end.mu_col = *ptr; |
218 | } | 320 | } |
219 | else | 321 | else |
220 | { | 322 | { |
221 | /* Text ends with a newline. Keep the previous line number. */ | 323 | /* Text ends with a newline. Keep the previous line number. */ |
222 | loc->end.mu_line = trk->hline + trk->tos - 1; | 324 | loc->end.mu_line--; |
223 | loc->end.mu_col = cols_peek (trk, trk->tos - 1) - 1; | 325 | loc->end.mu_col = trk->cols[trk_decr (trk, trk->tos)] - 1; |
224 | if (loc->end.mu_col + 1 == loc->beg.mu_col) | 326 | if (loc->end.mu_col + 1 == loc->beg.mu_col) |
225 | { | 327 | { |
226 | /* This happens if the previous line contained only newline. */ | 328 | /* This happens if the previous line contained only newline. */ |
... | @@ -232,21 +334,28 @@ mu_linetrack_advance (struct mu_linetrack *trk, | ... | @@ -232,21 +334,28 @@ mu_linetrack_advance (struct mu_linetrack *trk, |
232 | int | 334 | int |
233 | mu_linetrack_locus (struct mu_linetrack *trk, struct mu_locus_point *lp) | 335 | mu_linetrack_locus (struct mu_linetrack *trk, struct mu_locus_point *lp) |
234 | { | 336 | { |
235 | lp->mu_line = trk->hline + trk->tos; | 337 | int rc = mu_locus_point_set_file (lp, trk->s_head->file_name); |
236 | return mu_locus_point_set_file (lp, trk->file_name); | 338 | if (rc == 0) |
339 | { | ||
340 | lp->mu_line = | ||
341 | trk->s_head->line + count_lines (trk, trk->s_head->idx) - 1; | ||
342 | lp->mu_col = trk->cols[trk->tos]; | ||
343 | } | ||
344 | return rc; | ||
237 | } | 345 | } |
238 | 346 | ||
239 | int | 347 | int |
240 | mu_linetrack_retreat (struct mu_linetrack *trk, size_t n) | 348 | mu_linetrack_retreat (struct mu_linetrack *trk, size_t n) |
241 | { | 349 | { |
242 | struct mu_linetrack_stat st; | 350 | size_t nch; |
243 | 351 | ||
244 | mu_linetrack_stat (trk, &st); | 352 | if (count_chars (trk, trk->head, &nch)) |
245 | if (n > st.n_chars) | 353 | return ERANGE; |
354 | if (n > nch) | ||
246 | return ERANGE; | 355 | return ERANGE; |
247 | else | 356 | else |
248 | { | 357 | { |
249 | unsigned *ptr = cols_tos_ptr (trk); | 358 | unsigned *ptr = &trk->cols[trk->tos]; |
250 | while (n--) | 359 | while (n--) |
251 | { | 360 | { |
252 | if (*ptr == 0) | 361 | if (*ptr == 0) | ... | ... |
... | @@ -54,11 +54,11 @@ liber:4.15-18: Naso | ... | @@ -54,11 +54,11 @@ liber:4.15-18: Naso |
54 | TRACKTEST([retreat],[],[3], | 54 | TRACKTEST([retreat],[],[3], |
55 | [ | 55 | [ |
56 | agnosco | 56 | agnosco |
57 | \-4 | 57 | #retreat 4 |
58 | veteris | 58 | veteris |
59 | vestigia\n | 59 | vestigia\n |
60 | flamme | 60 | flamme |
61 | \-8 | 61 | #retreat 8 |
62 | Publius | 62 | Publius |
63 | ], | 63 | ], |
64 | [liber:1.1-7: agnosco | 64 | [liber:1.1-7: agnosco |
... | @@ -73,7 +73,7 @@ TRACKTEST([retreat over several lines],[],[4], | ... | @@ -73,7 +73,7 @@ TRACKTEST([retreat over several lines],[],[4], |
73 | one\n | 73 | one\n |
74 | two\n | 74 | two\n |
75 | three | 75 | three |
76 | \-11 | 76 | #retreat 11 |
77 | four | 77 | four |
78 | ], | 78 | ], |
79 | [liber:1.1-3: one\n | 79 | [liber:1.1-3: one\n |
... | @@ -85,7 +85,7 @@ liber:1.3-6: four | ... | @@ -85,7 +85,7 @@ liber:1.3-6: four |
85 | TRACKTEST([retreat to the beginning],[],[4], | 85 | TRACKTEST([retreat to the beginning],[],[4], |
86 | [one\n | 86 | [one\n |
87 | two\n | 87 | two\n |
88 | \-8 | 88 | #retreat 8 |
89 | three | 89 | three |
90 | ], | 90 | ], |
91 | [liber:1.1-3: one\n | 91 | [liber:1.1-3: one\n |
... | @@ -96,7 +96,7 @@ liber:1.1-5: three | ... | @@ -96,7 +96,7 @@ liber:1.1-5: three |
96 | TRACKTEST([too big retreat],[],[2], | 96 | TRACKTEST([too big retreat],[],[2], |
97 | [one\n | 97 | [one\n |
98 | two\n | 98 | two\n |
99 | \-10 | 99 | #retreat 10 |
100 | three | 100 | three |
101 | ], | 101 | ], |
102 | [liber:1.1-3: one\n | 102 | [liber:1.1-3: one\n |
... | @@ -106,4 +106,174 @@ liber:3.1-5: three | ... | @@ -106,4 +106,174 @@ liber:3.1-5: three |
106 | [linetrack: retreat count too big | 106 | [linetrack: retreat count too big |
107 | ]) | 107 | ]) |
108 | 108 | ||
109 | TRACKTEST([origin 1],[],[10], | ||
110 | [one\n | ||
111 | two\n | ||
112 | three\n | ||
113 | #origin B 5 0 | ||
114 | four\n | ||
115 | five\n | ||
116 | #origin C 2 0 | ||
117 | six\n | ||
118 | seven\n | ||
119 | eight\n | ||
120 | #stat | ||
121 | ], | ||
122 | [liber:1.1-3: one\n | ||
123 | liber:2.1-3: two\n | ||
124 | liber:3.1-5: three\n | ||
125 | B:5.1-4: four\n | ||
126 | B:6.1-4: five\n | ||
127 | C:2.1-3: six\n | ||
128 | C:3.1-5: seven\n | ||
129 | C:4.1-5: eight\n | ||
130 | n_files=3 | ||
131 | n_lines=9 | ||
132 | n_chars=40 | ||
133 | ]) | ||
134 | |||
135 | TRACKTEST([origin 2],[],[8], | ||
136 | [one\n | ||
137 | two\n | ||
138 | three\n | ||
139 | #origin B 5 0 | ||
140 | four\n | ||
141 | five\n | ||
142 | #origin C 2 0 | ||
143 | six\n | ||
144 | seven\n | ||
145 | eight\n | ||
146 | #stat | ||
147 | ], | ||
148 | [liber:1.1-3: one\n | ||
149 | liber:2.1-3: two\n | ||
150 | liber:3.1-5: three\n | ||
151 | B:5.1-4: four\n | ||
152 | B:6.1-4: five\n | ||
153 | C:2.1-3: six\n | ||
154 | C:3.1-5: seven\n | ||
155 | C:4.1-5: eight\n | ||
156 | n_files=3 | ||
157 | n_lines=8 | ||
158 | n_chars=36 | ||
159 | ]) | ||
160 | |||
161 | TRACKTEST([origin 3],[],[7], | ||
162 | [one\n | ||
163 | two\n | ||
164 | three\n | ||
165 | #origin B 5 0 | ||
166 | four\n | ||
167 | five\n | ||
168 | #origin C 2 0 | ||
169 | six\n | ||
170 | seven\n | ||
171 | eight\n | ||
172 | #stat | ||
173 | ], | ||
174 | [liber:1.1-3: one\n | ||
175 | liber:2.1-3: two\n | ||
176 | liber:3.1-5: three\n | ||
177 | B:5.1-4: four\n | ||
178 | B:6.1-4: five\n | ||
179 | C:2.1-3: six\n | ||
180 | C:3.1-5: seven\n | ||
181 | C:4.1-5: eight\n | ||
182 | n_files=3 | ||
183 | n_lines=7 | ||
184 | n_chars=32 | ||
185 | ]) | ||
186 | |||
187 | TRACKTEST([origin 4],[],[6], | ||
188 | [one\n | ||
189 | two\n | ||
190 | three\n | ||
191 | #origin B 5 0 | ||
192 | four\n | ||
193 | five\n | ||
194 | #origin C 2 0 | ||
195 | six\n | ||
196 | seven\n | ||
197 | eight\n | ||
198 | #stat | ||
199 | ], | ||
200 | [liber:1.1-3: one\n | ||
201 | liber:2.1-3: two\n | ||
202 | liber:3.1-5: three\n | ||
203 | B:5.1-4: four\n | ||
204 | B:6.1-4: five\n | ||
205 | C:2.1-3: six\n | ||
206 | C:3.1-5: seven\n | ||
207 | C:4.1-5: eight\n | ||
208 | n_files=2 | ||
209 | n_lines=6 | ||
210 | n_chars=26 | ||
211 | ]) | ||
212 | |||
213 | TRACKTEST([retreat over origin],[],[9], | ||
214 | [one\n | ||
215 | two\n | ||
216 | three\n | ||
217 | #origin B 5 0 | ||
218 | four\n | ||
219 | five\n | ||
220 | #origin C 2 0 | ||
221 | six\n | ||
222 | seven\n | ||
223 | eight\n | ||
224 | #retreat 17 | ||
225 | nine | ||
226 | #stat | ||
227 | ],[liber:1.1-3: one\n | ||
228 | liber:2.1-3: two\n | ||
229 | liber:3.1-5: three\n | ||
230 | B:5.1-4: four\n | ||
231 | B:6.1-4: five\n | ||
232 | C:2.1-3: six\n | ||
233 | C:3.1-5: seven\n | ||
234 | C:4.1-5: eight\n | ||
235 | B:6.5-8: nine | ||
236 | n_files=2 | ||
237 | n_lines=5 | ||
238 | n_chars=27 | ||
239 | ]) | ||
240 | |||
241 | TRACKTEST([retreat over two origins],[],[9], | ||
242 | [one\n | ||
243 | two\n | ||
244 | three\n | ||
245 | #origin B 5 0 | ||
246 | four\n | ||
247 | five\n | ||
248 | #origin C 2 0 | ||
249 | six\n | ||
250 | seven\n | ||
251 | eight\n | ||
252 | #retreat 32 | ||
253 | nine | ||
254 | #stat | ||
255 | ],[liber:1.1-3: one\n | ||
256 | liber:2.1-3: two\n | ||
257 | liber:3.1-5: three\n | ||
258 | B:5.1-4: four\n | ||
259 | B:6.1-4: five\n | ||
260 | C:2.1-3: six\n | ||
261 | C:3.1-5: seven\n | ||
262 | C:4.1-5: eight\n | ||
263 | liber:3.1-4: nine | ||
264 | n_files=1 | ||
265 | n_lines=3 | ||
266 | n_chars=12 | ||
267 | ]) | ||
268 | |||
269 | TRACKTEST([rebase],[],[9], | ||
270 | [one | ||
271 | #rebase archivum 5 3 | ||
272 | two | ||
273 | ], | ||
274 | [liber:1.1-3: one | ||
275 | archivum:5.4-6: two | ||
276 | ]) | ||
277 | |||
278 | |||
109 | m4_popdef([TRACKTEST]) | 279 | m4_popdef([TRACKTEST]) | ... | ... |
... | @@ -2,6 +2,122 @@ | ... | @@ -2,6 +2,122 @@ |
2 | #include <mailutils/locus.h> | 2 | #include <mailutils/locus.h> |
3 | 3 | ||
4 | int | 4 | int |
5 | getnum (char const *arg, unsigned *ret) | ||
6 | { | ||
7 | char *end; | ||
8 | unsigned long x = strtoul (arg, &end, 10); | ||
9 | if (*end) | ||
10 | { | ||
11 | mu_error ("bad number: %s", arg); | ||
12 | return -1; | ||
13 | } | ||
14 | *ret = x; | ||
15 | return 0; | ||
16 | } | ||
17 | |||
18 | static void | ||
19 | com_retreat (mu_linetrack_t trk, size_t argc, char **argv) | ||
20 | { | ||
21 | unsigned x; | ||
22 | if (getnum (argv[1], &x) == 0) | ||
23 | { | ||
24 | int rc = mu_linetrack_retreat (trk, x); | ||
25 | if (rc == ERANGE) | ||
26 | mu_error ("retreat count too big"); | ||
27 | else if (rc) | ||
28 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_retreat", argv[1], rc); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | static void | ||
33 | com_origin (mu_linetrack_t trk, size_t argc, char **argv) | ||
34 | { | ||
35 | int rc; | ||
36 | struct mu_locus_point pt; | ||
37 | |||
38 | pt.mu_file = argv[1]; | ||
39 | if (getnum (argv[2], &pt.mu_line)) | ||
40 | return; | ||
41 | if (getnum (argv[3], &pt.mu_col)) | ||
42 | return; | ||
43 | rc = mu_linetrack_origin (trk, &pt); | ||
44 | if (rc) | ||
45 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_origin", NULL, rc); | ||
46 | } | ||
47 | |||
48 | static void | ||
49 | com_rebase (mu_linetrack_t trk, size_t argc, char **argv) | ||
50 | { | ||
51 | int rc; | ||
52 | struct mu_locus_point pt; | ||
53 | |||
54 | pt.mu_file = argv[1]; | ||
55 | if (getnum (argv[2], &pt.mu_line)) | ||
56 | return; | ||
57 | if (getnum (argv[3], &pt.mu_col)) | ||
58 | return; | ||
59 | rc = mu_linetrack_rebase (trk, &pt); | ||
60 | if (rc) | ||
61 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_rebase", NULL, rc); | ||
62 | } | ||
63 | |||
64 | static void | ||
65 | com_point (mu_linetrack_t trk, size_t argc, char **argv) | ||
66 | { | ||
67 | struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; | ||
68 | int rc; | ||
69 | |||
70 | rc = mu_linetrack_locus (trk, &lr.beg); | ||
71 | if (rc) | ||
72 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_locus", NULL, rc); | ||
73 | else | ||
74 | { | ||
75 | mu_stream_lprintf (mu_strout, &lr, "%s\n", argv[0]); | ||
76 | mu_locus_range_deinit (&lr); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static void | ||
81 | com_bol_p (mu_linetrack_t trk, size_t argc, char **argv) | ||
82 | { | ||
83 | mu_printf ("%d\n", mu_linetrack_at_bol (trk)); | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | com_stat (mu_linetrack_t trk, size_t argc, char **argv) | ||
88 | { | ||
89 | int rc; | ||
90 | struct mu_linetrack_stat st; | ||
91 | |||
92 | rc = mu_linetrack_stat (trk, &st); | ||
93 | if (rc) | ||
94 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_stat", NULL, rc); | ||
95 | else | ||
96 | { | ||
97 | mu_printf ("n_files=%zu\n", st.n_files); | ||
98 | mu_printf ("n_lines=%zu\n", st.n_lines); | ||
99 | mu_printf ("n_chars=%zu\n", st.n_chars); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | struct command | ||
104 | { | ||
105 | char *name; | ||
106 | size_t argc; | ||
107 | void (*fun) (mu_linetrack_t trk, size_t argc, char **argv); | ||
108 | }; | ||
109 | |||
110 | static struct command comtab[] = { | ||
111 | { "retreat", 2, com_retreat }, | ||
112 | { "origin", 4, com_origin }, | ||
113 | { "point", 1, com_point }, | ||
114 | { "rebase", 4, com_rebase }, | ||
115 | { "bol", 1, com_bol_p }, | ||
116 | { "stat", 1, com_stat }, | ||
117 | { NULL } | ||
118 | }; | ||
119 | |||
120 | int | ||
5 | main (int argc, char **argv) | 121 | main (int argc, char **argv) |
6 | { | 122 | { |
7 | unsigned long max_lines; | 123 | unsigned long max_lines; |
... | @@ -10,6 +126,9 @@ main (int argc, char **argv) | ... | @@ -10,6 +126,9 @@ main (int argc, char **argv) |
10 | int rc; | 126 | int rc; |
11 | char *buf = NULL; | 127 | char *buf = NULL; |
12 | size_t size, n; | 128 | size_t size, n; |
129 | struct mu_wordsplit ws; | ||
130 | int wsf = MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | ||
131 | | MU_WRDSF_SHOWERR | MU_WRDSF_ENOMEMABRT; | ||
13 | 132 | ||
14 | mu_set_program_name (argv[0]); | 133 | mu_set_program_name (argv[0]); |
15 | mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); | 134 | mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); |
... | @@ -29,35 +148,37 @@ main (int argc, char **argv) | ... | @@ -29,35 +148,37 @@ main (int argc, char **argv) |
29 | MU_ASSERT (mu_linetrack_create (&trk, argv[1], max_lines)); | 148 | MU_ASSERT (mu_linetrack_create (&trk, argv[1], max_lines)); |
30 | while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0) | 149 | while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0) |
31 | { | 150 | { |
32 | struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; | ||
33 | char *tok; | 151 | char *tok; |
34 | 152 | ||
35 | n = mu_rtrim_class (buf, MU_CTYPE_SPACE); | 153 | n = mu_rtrim_class (buf, MU_CTYPE_SPACE); |
36 | if (n == 0) | 154 | if (n == 0) |
37 | continue; | 155 | continue; |
38 | if (buf[0] == '\\' && buf[1] == '-') | 156 | if (buf[0] == '#') |
39 | { | 157 | { |
40 | long x = strtol (buf+2, &end, 10); | 158 | struct command *com; |
41 | if (*end || x == 0) | 159 | |
42 | { | 160 | mu_wordsplit (buf+1, &ws, wsf); |
43 | mu_error ("bad number"); | 161 | wsf |= MU_WRDSF_REUSE; |
44 | continue; | 162 | |
45 | } | 163 | for (com = comtab; com->name; com++) |
46 | rc = mu_linetrack_retreat (trk, x); | 164 | if (strcmp (com->name, ws.ws_wordv[0]) == 0 |
47 | if (rc == ERANGE) | 165 | && com->argc == ws.ws_wordc) |
48 | mu_error ("retreat count too big"); | 166 | break; |
49 | else if (rc) | 167 | if (com->name) |
50 | mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_retreat", buf+2, | 168 | com->fun (trk, ws.ws_wordc, ws.ws_wordv); |
51 | rc); | 169 | else |
170 | mu_error ("unrecognized command"); | ||
52 | } | 171 | } |
53 | else | 172 | else |
54 | { | 173 | { |
174 | struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER; | ||
175 | |||
55 | mu_c_str_unescape (buf, "\\\n", "\\n", &tok); | 176 | mu_c_str_unescape (buf, "\\\n", "\\n", &tok); |
56 | mu_linetrack_advance (trk, &lr, tok, strlen (tok)); | 177 | mu_linetrack_advance (trk, &lr, tok, strlen (tok)); |
57 | free (tok); | 178 | free (tok); |
58 | mu_stream_lprintf (mu_strout, &lr, "%s\n", buf); | 179 | mu_stream_lprintf (mu_strout, &lr, "%s\n", buf); |
180 | mu_locus_range_deinit (&lr); | ||
59 | } | 181 | } |
60 | mu_locus_range_deinit (&lr); | ||
61 | } | 182 | } |
62 | mu_linetrack_destroy (&trk); | 183 | mu_linetrack_destroy (&trk); |
63 | return 0; | 184 | return 0; | ... | ... |
... | @@ -315,6 +315,7 @@ make_node (enum node_type type, struct mu_locus_range const *loc) | ... | @@ -315,6 +315,7 @@ make_node (enum node_type type, struct mu_locus_range const *loc) |
315 | { | 315 | { |
316 | struct node *p = mimetypes_malloc (sizeof *p); | 316 | struct node *p = mimetypes_malloc (sizeof *p); |
317 | p->type = type; | 317 | p->type = type; |
318 | mu_locus_range_init (&p->loc); | ||
318 | mu_locus_range_copy (&p->loc, loc); | 319 | mu_locus_range_copy (&p->loc, loc); |
319 | return p; | 320 | return p; |
320 | } | 321 | } | ... | ... |
-
Please register or sign in to post a comment