Improve locus tracker; provide a testsuite
* include/mailutils/locus.h (mu_locus_track_stat): New struct. (mu_locus_tracker_stat): New proto. (mu_locus_tracker_retreat): Change return type. * libmailutils/locus/debug.c (mu_stream_vlprintf): Don't print spurious \n. (mu_lrange_debug): Fix incorrect call. * libmailutils/locus/tracker.c (mu_locus_track_create): Allocate storage for at least two lines of text. (mu_locus_tracker_stat): New function. (mu_locus_tracker_advance): Handle empty lines (mu_locus_tracker_retreat): Add error handling. * libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add locktrack. * libmailutils/tests/tracker.c: Rename to loctrack.c * libmailutils/tests/testsuite.at: Add new testcase. * libmailutils/tests/loctrack.at: New test case.
Showing
8 changed files
with
187 additions
and
19 deletions
... | @@ -19,6 +19,13 @@ struct mu_locus_range | ... | @@ -19,6 +19,13 @@ struct mu_locus_range |
19 | 19 | ||
20 | typedef struct mu_locus_track *mu_locus_track_t; | 20 | typedef struct mu_locus_track *mu_locus_track_t; |
21 | 21 | ||
22 | struct mu_locus_track_stat | ||
23 | { | ||
24 | unsigned start_line; | ||
25 | size_t n_lines; | ||
26 | size_t n_chars; | ||
27 | }; | ||
28 | |||
22 | int mu_ident_ref (char const *name, char const **refname); | 29 | int mu_ident_ref (char const *name, char const **refname); |
23 | int mu_ident_deref (char const *); | 30 | int mu_ident_deref (char const *); |
24 | 31 | ||
... | @@ -48,7 +55,10 @@ size_t mu_locus_track_level (mu_locus_track_t trk); | ... | @@ -48,7 +55,10 @@ size_t mu_locus_track_level (mu_locus_track_t trk); |
48 | void mu_locus_tracker_advance (struct mu_locus_track *trk, | 55 | void mu_locus_tracker_advance (struct mu_locus_track *trk, |
49 | struct mu_locus_range *loc, | 56 | struct mu_locus_range *loc, |
50 | char const *text, size_t leng); | 57 | char const *text, size_t leng); |
51 | void mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n); | 58 | int mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n); |
59 | int mu_locus_tracker_stat (struct mu_locus_track *trk, | ||
60 | struct mu_locus_track_stat *st); | ||
61 | |||
52 | 62 | ||
53 | void mu_stream_print_locus_range (mu_stream_t stream, | 63 | void mu_stream_print_locus_range (mu_stream_t stream, |
54 | struct mu_locus_range const *loc); | 64 | struct mu_locus_range const *loc); | ... | ... |
... | @@ -59,8 +59,7 @@ mu_stream_vlprintf (mu_stream_t stream, | ... | @@ -59,8 +59,7 @@ mu_stream_vlprintf (mu_stream_t stream, |
59 | { | 59 | { |
60 | mu_stream_print_locus_range (stream, loc); | 60 | mu_stream_print_locus_range (stream, loc); |
61 | mu_stream_write (stream, ": ", 2, NULL); | 61 | mu_stream_write (stream, ": ", 2, NULL); |
62 | mu_stream_vprintf (mu_strerr, fmt, ap); | 62 | mu_stream_vprintf (stream, fmt, ap); |
63 | mu_stream_write (stream, "\n", 1, NULL); | ||
64 | } | 63 | } |
65 | 64 | ||
66 | void | 65 | void |
... | @@ -91,8 +90,9 @@ mu_lrange_debug (struct mu_locus_range const *loc, | ... | @@ -91,8 +90,9 @@ mu_lrange_debug (struct mu_locus_range const *loc, |
91 | } | 90 | } |
92 | 91 | ||
93 | va_start (ap, fmt); | 92 | va_start (ap, fmt); |
94 | mu_stream_lprintf (mu_strerr, loc, fmt, ap); | 93 | mu_stream_vlprintf (mu_strerr, loc, fmt, ap); |
95 | va_end (ap); | 94 | va_end (ap); |
95 | mu_stream_write (mu_strerr, "\n", 1, NULL); | ||
96 | 96 | ||
97 | if (rc == 0) | 97 | if (rc == 0) |
98 | mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, | 98 | mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, | ... | ... |
... | @@ -2,6 +2,7 @@ | ... | @@ -2,6 +2,7 @@ |
2 | #include <errno.h> | 2 | #include <errno.h> |
3 | #include <mailutils/types.h> | 3 | #include <mailutils/types.h> |
4 | #include <mailutils/locus.h> | 4 | #include <mailutils/locus.h> |
5 | #include <mailutils/error.h> | ||
5 | 6 | ||
6 | struct mu_locus_track | 7 | struct mu_locus_track |
7 | { | 8 | { |
... | @@ -38,6 +39,8 @@ mu_locus_track_create (mu_locus_track_t *ret, | ... | @@ -38,6 +39,8 @@ mu_locus_track_create (mu_locus_track_t *ret, |
38 | return rc; | 39 | return rc; |
39 | } | 40 | } |
40 | 41 | ||
42 | if (max_lines < 2) | ||
43 | max_lines = 2; | ||
41 | trk->max_lines = max_lines; | 44 | trk->max_lines = max_lines; |
42 | trk->head = 0; | 45 | trk->head = 0; |
43 | trk->level = 0; | 46 | trk->level = 0; |
... | @@ -106,14 +109,34 @@ static inline unsigned * | ... | @@ -106,14 +109,34 @@ static inline unsigned * |
106 | pop (mu_locus_track_t trk) | 109 | pop (mu_locus_track_t trk) |
107 | { | 110 | { |
108 | if (trk->level == 0) | 111 | if (trk->level == 0) |
109 | { | 112 | return NULL; |
110 | *cols_tos_ptr (trk) = 0; | ||
111 | return NULL; //FIXME | ||
112 | } | ||
113 | trk->level--; | 113 | trk->level--; |
114 | return cols_tos_ptr (trk); | 114 | return cols_tos_ptr (trk); |
115 | } | 115 | } |
116 | 116 | ||
117 | #ifndef SIZE_MAX | ||
118 | # define SIZE_MAX (~((size_t)0)) | ||
119 | #endif | ||
120 | |||
121 | int | ||
122 | mu_locus_tracker_stat (struct mu_locus_track *trk, | ||
123 | struct mu_locus_track_stat *st) | ||
124 | { | ||
125 | size_t i, nch = 0; | ||
126 | |||
127 | for (i = 0; i <= trk->level; i++) | ||
128 | { | ||
129 | unsigned n = cols_peek (trk, i); | ||
130 | if (SIZE_MAX - nch < n) | ||
131 | return ERANGE; | ||
132 | nch += n; | ||
133 | } | ||
134 | |||
135 | st->start_line = trk->hline; | ||
136 | st->n_lines = trk->level; | ||
137 | st->n_chars = nch; | ||
138 | } | ||
139 | |||
117 | void | 140 | void |
118 | mu_locus_tracker_advance (struct mu_locus_track *trk, | 141 | mu_locus_tracker_advance (struct mu_locus_track *trk, |
119 | struct mu_locus_range *loc, | 142 | struct mu_locus_range *loc, |
... | @@ -142,27 +165,44 @@ mu_locus_tracker_advance (struct mu_locus_track *trk, | ... | @@ -142,27 +165,44 @@ mu_locus_tracker_advance (struct mu_locus_track *trk, |
142 | } | 165 | } |
143 | else | 166 | else |
144 | { | 167 | { |
168 | /* Text ends with a newline. Keep the previos line number. */ | ||
145 | loc->end.mu_line = trk->hline + trk->level - 1; | 169 | loc->end.mu_line = trk->hline + trk->level - 1; |
146 | loc->end.mu_col = cols_peek (trk, trk->level - 1) - 1; | 170 | loc->end.mu_col = cols_peek (trk, trk->level - 1) - 1; |
171 | if (loc->end.mu_col + 1 == loc->beg.mu_col) | ||
172 | { | ||
173 | /* This happens if the previous line contained only newline. */ | ||
174 | loc->beg.mu_col = loc->end.mu_col; | ||
175 | } | ||
147 | } | 176 | } |
148 | } | 177 | } |
149 | 178 | ||
150 | void | 179 | int |
151 | mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n) | 180 | mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n) |
152 | { | 181 | { |
153 | unsigned *ptr; | 182 | struct mu_locus_track_stat st; |
154 | 183 | ||
155 | ptr = cols_tos_ptr (trk); | 184 | mu_locus_tracker_stat (trk, &st); |
185 | if (n > st.n_chars) | ||
186 | return ERANGE; | ||
187 | else | ||
188 | { | ||
189 | unsigned *ptr = cols_tos_ptr (trk); | ||
156 | while (n--) | 190 | while (n--) |
157 | { | 191 | { |
158 | if (*ptr == 0) | 192 | if (*ptr == 0) |
159 | { | 193 | { |
160 | ptr = pop (trk); | 194 | ptr = pop (trk); |
161 | if (!ptr) | 195 | if (!ptr || *ptr == 0) |
162 | break; | 196 | { |
197 | mu_error ("%s:%d: INTERNAL ERROR: out of pop back\n", | ||
198 | __FILE__, __LINE__); | ||
199 | return ERANGE; | ||
200 | } | ||
163 | } | 201 | } |
164 | --*ptr; | 202 | --*ptr; |
165 | } | 203 | } |
204 | } | ||
205 | return 0; | ||
166 | } | 206 | } |
167 | 207 | ||
168 | 208 | ... | ... |
... | @@ -19,6 +19,7 @@ fsfolder | ... | @@ -19,6 +19,7 @@ fsfolder |
19 | globtest | 19 | globtest |
20 | imapio | 20 | imapio |
21 | listop | 21 | listop |
22 | loctrack | ||
22 | logstr | 23 | logstr |
23 | mailcap | 24 | mailcap |
24 | mimehdr | 25 | mimehdr |
... | @@ -34,7 +35,6 @@ strout | ... | @@ -34,7 +35,6 @@ strout |
34 | strtoc | 35 | strtoc |
35 | tcli | 36 | tcli |
36 | tempfile | 37 | tempfile |
37 | tracker | ||
38 | url-comp | 38 | url-comp |
39 | url-parse | 39 | url-parse |
40 | vexp | 40 | vexp | ... | ... |
... | @@ -54,6 +54,7 @@ noinst_PROGRAMS = \ | ... | @@ -54,6 +54,7 @@ noinst_PROGRAMS = \ |
54 | globtest\ | 54 | globtest\ |
55 | imapio\ | 55 | imapio\ |
56 | listop\ | 56 | listop\ |
57 | loctrack\ | ||
57 | logstr\ | 58 | logstr\ |
58 | mailcap\ | 59 | mailcap\ |
59 | mimehdr\ | 60 | mimehdr\ |
... | @@ -68,7 +69,6 @@ noinst_PROGRAMS = \ | ... | @@ -68,7 +69,6 @@ noinst_PROGRAMS = \ |
68 | strout\ | 69 | strout\ |
69 | strtoc\ | 70 | strtoc\ |
70 | tempfile\ | 71 | tempfile\ |
71 | tracker\ | ||
72 | tcli\ | 72 | tcli\ |
73 | url-comp\ | 73 | url-comp\ |
74 | url-parse\ | 74 | url-parse\ |
... | @@ -107,6 +107,7 @@ TESTSUITE_AT = \ | ... | @@ -107,6 +107,7 @@ TESTSUITE_AT = \ |
107 | inline-comment.at\ | 107 | inline-comment.at\ |
108 | linecon.at\ | 108 | linecon.at\ |
109 | list.at\ | 109 | list.at\ |
110 | loctrack.at\ | ||
110 | logstr.at\ | 111 | logstr.at\ |
111 | mailcap.at\ | 112 | mailcap.at\ |
112 | mimehdr.at\ | 113 | mimehdr.at\ | ... | ... |
libmailutils/tests/loctrack.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2017 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # GNU Mailutils is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU General Public License as | ||
6 | # published by the Free Software Foundation; either version 3, or (at | ||
7 | # your option) any later version. | ||
8 | # | ||
9 | # GNU Mailutils is distributed in the hope that it will be useful, but | ||
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_BANNER([Locus tracker]) | ||
18 | |||
19 | m4_pushdef([TRACKTEST],[ | ||
20 | AT_SETUP([$1]) | ||
21 | AT_KEYWORDS([tracker $2]) | ||
22 | AT_CHECK([loctrack liber $3 <<EOT | ||
23 | $4[]EOT | ||
24 | ], | ||
25 | [0], | ||
26 | [$5], | ||
27 | [$6]) | ||
28 | AT_CLEANUP | ||
29 | ]) | ||
30 | |||
31 | TRACKTEST([normal operation],[],[7], | ||
32 | [ | ||
33 | agnosco | ||
34 | veteris\n | ||
35 | vestigia | ||
36 | flamme | ||
37 | \n | ||
38 | \n | ||
39 | Publius | ||
40 | Ovidius | ||
41 | Naso | ||
42 | ], | ||
43 | [liber:1.1-7: agnosco | ||
44 | liber:1.8-14: veteris\n | ||
45 | liber:2.1-8: vestigia | ||
46 | liber:2.9-14: flamme | ||
47 | liber:2.14: \n | ||
48 | liber:3: \n | ||
49 | liber:4.1-7: Publius | ||
50 | liber:4.8-14: Ovidius | ||
51 | liber:4.15-18: Naso | ||
52 | ]) | ||
53 | |||
54 | TRACKTEST([retreat],[],[3], | ||
55 | [ | ||
56 | agnosco | ||
57 | \-4 | ||
58 | veteris | ||
59 | vestigia\n | ||
60 | flamme | ||
61 | \-8 | ||
62 | Publius | ||
63 | ], | ||
64 | [liber:1.1-7: agnosco | ||
65 | liber:1.4-10: veteris | ||
66 | liber:1.11-18: vestigia\n | ||
67 | liber:2.1-6: flamme | ||
68 | liber:1.18-24: Publius | ||
69 | ]) | ||
70 | |||
71 | TRACKTEST([retreat over several lines],[],[4], | ||
72 | [ | ||
73 | one\n | ||
74 | two\n | ||
75 | three | ||
76 | \-11 | ||
77 | four | ||
78 | ], | ||
79 | [liber:1.1-3: one\n | ||
80 | liber:2.1-3: two\n | ||
81 | liber:3.1-5: three | ||
82 | liber:1.3-6: four | ||
83 | ]) | ||
84 | |||
85 | TRACKTEST([retreat to the beginning],[],[4], | ||
86 | [one\n | ||
87 | two\n | ||
88 | \-8 | ||
89 | three | ||
90 | ], | ||
91 | [liber:1.1-3: one\n | ||
92 | liber:2.1-3: two\n | ||
93 | liber:1.1-5: three | ||
94 | ]) | ||
95 | |||
96 | TRACKTEST([too big retreat],[],[2], | ||
97 | [one\n | ||
98 | two\n | ||
99 | \-10 | ||
100 | three | ||
101 | ], | ||
102 | [liber:1.1-3: one\n | ||
103 | liber:2.1-3: two\n | ||
104 | liber:3.1-5: three | ||
105 | ], | ||
106 | [loctrack: retreat count too big | ||
107 | ]) | ||
108 | |||
109 | m4_popdef([TRACKTEST]) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -33,22 +33,29 @@ main (int argc, char **argv) | ... | @@ -33,22 +33,29 @@ main (int argc, char **argv) |
33 | char *tok; | 33 | char *tok; |
34 | 34 | ||
35 | n = mu_rtrim_class (buf, MU_CTYPE_SPACE); | 35 | n = mu_rtrim_class (buf, MU_CTYPE_SPACE); |
36 | if (buf[0] == '\\') | 36 | if (n == 0) |
37 | continue; | ||
38 | if (buf[0] == '\\' && buf[1] == '-') | ||
37 | { | 39 | { |
38 | long x = strtol (buf+1, &end, 10); | 40 | long x = strtol (buf+2, &end, 10); |
39 | if (*end || x == 0) | 41 | if (*end || x == 0) |
40 | { | 42 | { |
41 | mu_error ("bad number"); | 43 | mu_error ("bad number"); |
42 | continue; | 44 | continue; |
43 | } | 45 | } |
44 | mu_locus_tracker_retreat (trk, x); | 46 | rc = mu_locus_tracker_retreat (trk, x); |
47 | if (rc == ERANGE) | ||
48 | mu_error ("retreat count too big"); | ||
49 | else if (rc) | ||
50 | mu_diag_funcall (MU_DIAG_ERROR, "mu_locus_tracker_retreat", buf+2, | ||
51 | rc); | ||
45 | } | 52 | } |
46 | else | 53 | else |
47 | { | 54 | { |
48 | mu_c_str_unescape (buf, "\\\n", "\\n", &tok); | 55 | mu_c_str_unescape (buf, "\\\n", "\\n", &tok); |
49 | mu_locus_tracker_advance (trk, &lr, tok, strlen (tok)); | 56 | mu_locus_tracker_advance (trk, &lr, tok, strlen (tok)); |
50 | free (tok); | 57 | free (tok); |
51 | mu_lrange_debug (&lr, "%s", buf); | 58 | mu_stream_lprintf (mu_strout, &lr, "%s\n", buf); |
52 | } | 59 | } |
53 | } | 60 | } |
54 | return 0; | 61 | return 0; | ... | ... |
-
Please register or sign in to post a comment