Commit 7892e5ba 7892e5bacca59d994918be4999ad0af3a8bbf33b by Sergey Poznyakoff

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
1 parent 4981ab84
...@@ -43,9 +43,8 @@ typedef struct mu_linetrack *mu_linetrack_t; ...@@ -43,9 +43,8 @@ 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 */
49 size_t n_chars; /* Total number of characters */ 48 size_t n_chars; /* Total number of characters */
50 }; 49 };
51 50
...@@ -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,22 +212,26 @@ mu_linetrack_create (mu_linetrack_t *ret, ...@@ -80,22 +212,26 @@ 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)
85 {
86 free (trk->cols);
87 free (trk);
88 return rc;
89 }
90 216
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;
98 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 }
234
99 *ret = trk; 235 *ret = trk;
100 return 0; 236 return 0;
101 } 237 }
...@@ -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
171 for (i = 0; i <= trk->tos; i++)
172 {
173 unsigned n = cols_peek (trk, i);
174 if (SIZE_MAX - nch < n)
175 return ERANGE; 279 return ERANGE;
176 nch += n; 280 st->n_files = count_files (trk);
177 } 281 st->n_lines = count_lines (trk, trk->head);
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,36 +148,38 @@ main (int argc, char **argv) ...@@ -29,36 +148,38 @@ 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 {
40 long x = strtol (buf+2, &end, 10);
41 if (*end || x == 0)
42 { 157 {
43 mu_error ("bad number"); 158 struct command *com;
44 continue; 159
45 } 160 mu_wordsplit (buf+1, &ws, wsf);
46 rc = mu_linetrack_retreat (trk, x); 161 wsf |= MU_WRDSF_REUSE;
47 if (rc == ERANGE) 162
48 mu_error ("retreat count too big"); 163 for (com = comtab; com->name; com++)
49 else if (rc) 164 if (strcmp (com->name, ws.ws_wordv[0]) == 0
50 mu_diag_funcall (MU_DIAG_ERROR, "mu_linetrack_retreat", buf+2, 165 && com->argc == ws.ws_wordc)
51 rc); 166 break;
167 if (com->name)
168 com->fun (trk, ws.ws_wordc, ws.ws_wordv);
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);
59 }
60 mu_locus_range_deinit (&lr); 180 mu_locus_range_deinit (&lr);
61 } 181 }
182 }
62 mu_linetrack_destroy (&trk); 183 mu_linetrack_destroy (&trk);
63 return 0; 184 return 0;
64 } 185 }
......
...@@ -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 }
......