Commit 2c83d024 2c83d0247675ac08791401dc2b341d7f3f201830 by Sergey Poznyakoff

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.
1 parent 4e7f5b5c
...@@ -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;
147 } 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 }
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);
156 while (n--) 185 if (n > st.n_chars)
186 return ERANGE;
187 else
157 { 188 {
158 if (*ptr == 0) 189 unsigned *ptr = cols_tos_ptr (trk);
190 while (n--)
159 { 191 {
160 ptr = pop (trk); 192 if (*ptr == 0)
161 if (!ptr) 193 {
162 break; 194 ptr = pop (trk);
195 if (!ptr || *ptr == 0)
196 {
197 mu_error ("%s:%d: INTERNAL ERROR: out of pop back\n",
198 __FILE__, __LINE__);
199 return ERANGE;
200 }
201 }
202 --*ptr;
163 } 203 }
164 --*ptr;
165 } 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\
......
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;
......
...@@ -212,3 +212,4 @@ m4_include([msgset.at]) ...@@ -212,3 +212,4 @@ m4_include([msgset.at])
212 212
213 m4_include([globtest.at]) 213 m4_include([globtest.at])
214 214
215 m4_include([loctrack.at])
......