Commit 75755ec7 75755ec7febf8c891b4b809120f3da77e1e15549 by Sergey Poznyakoff

Implement line number output in linecon and inline-comment filters.

* libmailutils/filter/inline-comment.c: Implement line number info
facility.
* libmailutils/filter/linecon.c: Likewise.
* libmailutils/stream/logstream.c (_log_done, _log_close): Always
close/destroy the underlying transport stream.
* comsat/action.c: Rewrite using a table-driven parser.
Use line-info facility of the linecon filter.
1 parent 9e253b39
...@@ -23,14 +23,18 @@ ...@@ -23,14 +23,18 @@
23 23
24 The following options modify this behavior: 24 The following options modify this behavior:
25 25
26 -r Remove empty lines, i.e. the ones that contain only whitespace 26 -i STR Emit line number information after each contiguous sequence
27 characters. 27 of removed lines. STR supplies "information starter" -- a
28 -s Squeeze whitespace. Each sequence of two or more whitespace 28 sequence of characters which is output before the actual line
29 characters encountered on input is replaced by a single space 29 number.
30 character on output. 30 -r Remove empty lines, i.e. the ones that contain only whitespace
31 -S A "following whitespace mode". A comment sequence is recognized 31 characters.
32 only if followed by a whitespace character. The character itself 32 -s Squeeze whitespace. Each sequence of two or more whitespace
33 is retained on output. 33 characters encountered on input is replaced by a single space
34 character on output.
35 -S A "following whitespace mode". A comment sequence is
36 recognized only if followed by a whitespace character.
37 The character itself is retained on output.
34 38
35 In encode mode, this filter adds a comment sequence at the beginning 39 In encode mode, this filter adds a comment sequence at the beginning
36 of each line. 40 of each line.
...@@ -49,16 +53,19 @@ ...@@ -49,16 +53,19 @@
49 #include <mailutils/errno.h> 53 #include <mailutils/errno.h>
50 #include <mailutils/filter.h> 54 #include <mailutils/filter.h>
51 #include <mailutils/cctype.h> 55 #include <mailutils/cctype.h>
56 #include <mailutils/io.h>
52 57
53 enum ilcmt_state 58 enum ilcmt_state
54 { 59 {
55 ilcmt_initial, 60 ilcmt_initial,
56 ilcmt_newline, 61 ilcmt_newline,
62 ilcmt_newline_ac,
57 ilcmt_copy, 63 ilcmt_copy,
58 ilcmt_comment, 64 ilcmt_comment,
59 ilcmt_partial, 65 ilcmt_partial,
60 ilcmt_comment_ws, 66 ilcmt_comment_ws,
61 ilcmt_ws, 67 ilcmt_ws,
68 ilcmt_rollback,
62 ilcmt_rollback_ws, 69 ilcmt_rollback_ws,
63 ilcmt_rollback_com 70 ilcmt_rollback_com
64 }; 71 };
...@@ -71,13 +78,20 @@ enum ilcmt_state ...@@ -71,13 +78,20 @@ enum ilcmt_state
71 whitespace character. 78 whitespace character.
72 In encode mode: output a space after 79 In encode mode: output a space after
73 each comment prefix. */ 80 each comment prefix. */
81 #define ILCMT_LINE_INFO 0x08 /* Emit line number information */
82
83 #define ILCMT_COMMENT_STATIC 0x0100
84 #define ILCMT_LINE_INFO_STATIC 0x0200
74 85
75 struct ilcmt_data 86 struct ilcmt_data
76 { 87 {
77 enum ilcmt_state state; /* Current state */ 88 enum ilcmt_state state; /* Current state */
78 char *comment; /* Comment sequence ... */ 89 char *comment; /* Comment sequence ... */
79 size_t length; /* and its length */ 90 size_t length; /* and its length */
80 int flags; /* ILCMT_ flags */ 91 int flags; /* ILCMT_ flags */
92 char *line_info_starter; /* Starter for line number info lines */
93 unsigned long line_number; /* Current line number */
94 char sbuf[3]; /* Static location for single-character strings */
81 char *buf; /* Rollback buffer ... */ 95 char *buf; /* Rollback buffer ... */
82 size_t size; /* and its size */ 96 size_t size; /* and its size */
83 size_t level; /* In ilcmt_partial and ilcmt_rollback_com 97 size_t level; /* In ilcmt_partial and ilcmt_rollback_com
...@@ -116,6 +130,17 @@ ilcmt_save (struct ilcmt_data *pd, int c) ...@@ -116,6 +130,17 @@ ilcmt_save (struct ilcmt_data *pd, int c)
116 return 0; 130 return 0;
117 } 131 }
118 132
133 static void
134 _ilcmt_free (struct ilcmt_data *pd)
135 {
136 if (!(pd->flags & ILCMT_COMMENT_STATIC))
137 free (pd->comment);
138 if ((pd->flags & ILCMT_LINE_INFO) &&
139 !(pd->flags & ILCMT_LINE_INFO_STATIC))
140 free (pd->line_info_starter);
141 free (pd->buf);
142 }
143
119 static enum mu_filter_result 144 static enum mu_filter_result
120 _ilcmt_decoder (void *xd, enum mu_filter_command cmd, 145 _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
121 struct mu_filter_io *iobuf) 146 struct mu_filter_io *iobuf)
...@@ -131,8 +156,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd, ...@@ -131,8 +156,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
131 return mu_filter_ok; 156 return mu_filter_ok;
132 157
133 case mu_filter_done: 158 case mu_filter_done:
134 free (pd->comment); 159 _ilcmt_free (pd);
135 free (pd->buf);
136 return mu_filter_ok; 160 return mu_filter_ok;
137 161
138 default: 162 default:
...@@ -150,14 +174,25 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd, ...@@ -150,14 +174,25 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
150 { 174 {
151 case ilcmt_initial: 175 case ilcmt_initial:
152 case ilcmt_newline: 176 case ilcmt_newline:
177 case ilcmt_newline_ac:
153 if (*iptr == *pd->comment) 178 if (*iptr == *pd->comment)
154 { 179 {
155 iptr++; 180 iptr++;
156 pd->level = 1; 181 pd->level = 1;
157 pd->state = ilcmt_partial; 182 pd->state = ilcmt_partial;
158 } 183 }
184 else if (pd->state == ilcmt_newline_ac)
185 {
186 mu_asnprintf (&pd->buf, &pd->size, "%s %lu\n",
187 pd->line_info_starter,
188 pd->line_number);
189 pd->level = strlen (pd->buf);
190 pd->replay = 0;
191 pd->state = ilcmt_rollback;
192 }
159 else if (*iptr == '\n') 193 else if (*iptr == '\n')
160 { 194 {
195 pd->line_number++;
161 if (pd->flags & ILCMT_REMOVE_EMPTY_LINES) 196 if (pd->flags & ILCMT_REMOVE_EMPTY_LINES)
162 { 197 {
163 iptr++; 198 iptr++;
...@@ -230,6 +265,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd, ...@@ -230,6 +265,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
230 case ilcmt_ws: 265 case ilcmt_ws:
231 if (*iptr == '\n') 266 if (*iptr == '\n')
232 { 267 {
268 pd->line_number++;
233 iptr++; 269 iptr++;
234 pd->state = ilcmt_newline; 270 pd->state = ilcmt_newline;
235 } 271 }
...@@ -251,12 +287,21 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd, ...@@ -251,12 +287,21 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
251 287
252 case ilcmt_copy: 288 case ilcmt_copy:
253 if ((*optr++ = *iptr++) == '\n') 289 if ((*optr++ = *iptr++) == '\n')
254 pd->state = ilcmt_newline; 290 {
291 pd->line_number++;
292 pd->state = ilcmt_newline;
293 }
255 break; 294 break;
256 295
257 case ilcmt_comment: 296 case ilcmt_comment:
258 if (*iptr++ == '\n') 297 if (*iptr++ == '\n')
259 pd->state = ilcmt_newline; 298 {
299 pd->line_number++;
300 if (pd->flags & ILCMT_LINE_INFO)
301 pd->state = ilcmt_newline_ac;
302 else
303 pd->state = ilcmt_newline;
304 }
260 break; 305 break;
261 306
262 case ilcmt_rollback_com: 307 case ilcmt_rollback_com:
...@@ -270,13 +315,13 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd, ...@@ -270,13 +315,13 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
270 { 315 {
271 *optr++ = ' '; 316 *optr++ = ' ';
272 pd->state = ilcmt_copy; 317 pd->state = ilcmt_copy;
318 break;
273 } 319 }
274 else 320 /* fall through */
275 { 321 case ilcmt_rollback:
276 *optr++ = pd->buf[pd->replay++]; 322 *optr++ = pd->buf[pd->replay++];
277 if (pd->replay == pd->level) 323 if (pd->replay == pd->level)
278 pd->state = ilcmt_copy; 324 pd->state = ilcmt_copy;
279 }
280 } 325 }
281 } 326 }
282 iobuf->isize = iptr - (const unsigned char *) iobuf->input; 327 iobuf->isize = iptr - (const unsigned char *) iobuf->input;
...@@ -300,8 +345,7 @@ _ilcmt_encoder (void *xd, ...@@ -300,8 +345,7 @@ _ilcmt_encoder (void *xd,
300 return mu_filter_ok; 345 return mu_filter_ok;
301 346
302 case mu_filter_done: 347 case mu_filter_done:
303 free (pd->comment); 348 _ilcmt_free (pd);
304 free (pd->buf);
305 return mu_filter_ok; 349 return mu_filter_ok;
306 350
307 default: 351 default:
...@@ -353,14 +397,15 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) ...@@ -353,14 +397,15 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
353 struct ilcmt_data *pd = malloc (sizeof (*pd)); 397 struct ilcmt_data *pd = malloc (sizeof (*pd));
354 int i; 398 int i;
355 const char *comment = ";"; 399 const char *comment = ";";
356 400 const char *line_info;
401
357 if (!pd) 402 if (!pd)
358 return ENOMEM; 403 return ENOMEM;
359 404
360
361 pd->flags = 0; 405 pd->flags = 0;
362 pd->buf = NULL; 406 pd->buf = NULL;
363 pd->size = pd->level = pd->replay = 0; 407 pd->size = pd->level = pd->replay = 0;
408 pd->line_number = 1;
364 409
365 for (i = 1; i < argc; i++) 410 for (i = 1; i < argc; i++)
366 { 411 {
...@@ -379,7 +424,14 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) ...@@ -379,7 +424,14 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
379 case 'S': 424 case 'S':
380 pd->flags |= ILCMT_FOLLOW_WS; 425 pd->flags |= ILCMT_FOLLOW_WS;
381 break; 426 break;
382 427
428 case 'i':
429 pd->flags |= ILCMT_LINE_INFO;
430 if (i + 1 == argc)
431 return MU_ERR_PARSE;
432 line_info = argv[++i];
433 break;
434
383 default: 435 default:
384 free (pd); 436 free (pd);
385 return MU_ERR_PARSE; 437 return MU_ERR_PARSE;
...@@ -388,13 +440,45 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) ...@@ -388,13 +440,45 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
388 else 440 else
389 comment = argv[i]; 441 comment = argv[i];
390 } 442 }
391 pd->comment = strdup (comment); 443 if (comment[1] == 0)
392 if (!pd->comment) 444 {
445 pd->sbuf[0] = comment[0];
446 pd->comment = pd->sbuf;
447 pd->flags |= ILCMT_COMMENT_STATIC;
448 pd->length = 1;
449 }
450 else
451 {
452 pd->comment = strdup (comment);
453 if (!pd->comment)
454 {
455 free (pd);
456 return ENOMEM;
457 }
458 pd->length = strlen (comment);
459 }
460
461 if (pd->flags & ILCMT_LINE_INFO)
393 { 462 {
394 free (pd); 463 if (line_info[1] == 0)
395 return ENOMEM; 464 {
465 pd->sbuf[1] = line_info[0];
466 pd->sbuf[2] = 0;
467 pd->line_info_starter = pd->sbuf + 1;
468 pd->flags |= ILCMT_LINE_INFO_STATIC;
469 }
470 else
471 {
472 pd->line_info_starter = strdup (line_info);
473 if (!pd->line_info_starter)
474 {
475 if (!(pd->flags & ILCMT_COMMENT_STATIC))
476 free (pd->comment);
477 free (pd);
478 return ENOMEM;
479 }
480 }
396 } 481 }
397 pd->length = strlen (comment);
398 482
399 *pret = pd; 483 *pret = pd;
400 484
......
...@@ -18,31 +18,70 @@ ...@@ -18,31 +18,70 @@
18 18
19 This filter has only decode mode. It removes from the input 19 This filter has only decode mode. It removes from the input
20 backslashes immediately followed by a newline, thus implementing 20 backslashes immediately followed by a newline, thus implementing
21 a familiar UNIX line-continuation facility. */ 21 a familiar UNIX line-continuation facility.
22
23 The following option is accepted:
24
25 -i STR Emit line number information after each contiguous sequence
26 of joined lines. STR supplies "information starter" -- a
27 sequence of characters which is output before the actual line
28 number.
29
30 */
22 31
23 #ifdef HAVE_CONFIG_H 32 #ifdef HAVE_CONFIG_H
24 # include <config.h> 33 # include <config.h>
25 #endif 34 #endif
26 #include <stdlib.h> 35 #include <stdlib.h>
36 #include <string.h>
27 #include <mailutils/errno.h> 37 #include <mailutils/errno.h>
28 #include <mailutils/filter.h> 38 #include <mailutils/filter.h>
29 #include <mailutils/cctype.h> 39 #include <mailutils/cctype.h>
40 #include <mailutils/io.h>
41
42 #define LINECON_LINE_INFO 0x01 /* Emit line number information */
43 #define LINECON_LINE_INFO_STATIC 0x02
44
45 enum linecon_state
46 {
47 linecon_init,
48 linecon_escape,
49 linecon_newline,
50 linecon_rollback
51 };
52
53 struct linecon_data
54 {
55 int flags; /* Mode flags */
56 enum linecon_state state; /* Current state */
57 char *line_info_starter; /* Starter for line number info lines */
58 unsigned long line_number; /* Current line number */
59 char sbuf[2]; /* Static buffer for single-character starters */
60 char *buf; /* Rollback buffer ... */
61 size_t size; /* and its size */
62 size_t level; /* Number of characters stored in buf. */
63 size_t replay; /* Index of the next-to-be-replayed character
64 from buf */
65 };
30 66
31 static enum mu_filter_result 67 static enum mu_filter_result
32 _linecon_decoder (void *xd, enum mu_filter_command cmd, 68 _linecon_decoder (void *xd, enum mu_filter_command cmd,
33 struct mu_filter_io *iobuf) 69 struct mu_filter_io *iobuf)
34 { 70 {
35 int *escaped = xd; 71 struct linecon_data *pd = xd;
36 const unsigned char *iptr, *iend; 72 const unsigned char *iptr, *iend;
37 char *optr, *oend; 73 char *optr, *oend;
38 74
39 switch (cmd) 75 switch (cmd)
40 { 76 {
41 case mu_filter_init: 77 case mu_filter_init:
42 *escaped = 0; 78 pd->state = linecon_init;
43 return mu_filter_ok; 79 return mu_filter_ok;
44 80
45 case mu_filter_done: 81 case mu_filter_done:
82 if ((pd->flags & LINECON_LINE_INFO) &&
83 !(pd->flags & LINECON_LINE_INFO_STATIC))
84 free (pd->line_info_starter);
46 return mu_filter_ok; 85 return mu_filter_ok;
47 86
48 default: 87 default:
...@@ -56,34 +95,57 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd, ...@@ -56,34 +95,57 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd,
56 95
57 while (iptr < iend && optr < oend) 96 while (iptr < iend && optr < oend)
58 { 97 {
59 int c = *iptr++; 98 switch (pd->state)
60 switch (c)
61 { 99 {
62 case '\\': 100 case linecon_init:
63 *escaped = 1; 101 case linecon_newline:
64 continue; 102 switch (*iptr)
65
66 case '\n':
67 if (*escaped)
68 { 103 {
69 *escaped = 0; 104 case '\\':
105 iptr++;
106 pd->state = linecon_escape;
70 continue; 107 continue;
108 case '\n':
109 pd->line_number++;
110 if (pd->state == linecon_newline)
111 {
112 mu_asnprintf (&pd->buf, &pd->size, "%s %lu\n",
113 pd->line_info_starter,
114 pd->line_number);
115 pd->level = strlen (pd->buf);
116 pd->replay = 0;
117 pd->state = linecon_rollback;
118 }
119 /* fall through */
120 default:
121 *optr++ = *iptr++;
122 break;
71 } 123 }
72 *optr++ = c;
73 break; 124 break;
74 125
75 default: 126 case linecon_escape:
76 if (*escaped) 127 if (*iptr == '\n')
128 {
129 pd->line_number++;
130 iptr++;
131 pd->state = (pd->flags & LINECON_LINE_INFO) ?
132 linecon_newline : linecon_init;
133 continue;
134 }
135 else
77 { 136 {
78 *escaped = 0; 137 pd->state = linecon_init;
79 *optr++ = '\\'; 138 *optr++ = '\\';
80 if (optr == oend) 139 if (optr == oend)
81 { 140 break;
82 iptr--; 141 *optr++ = *iptr++;
83 break;
84 }
85 } 142 }
86 *optr++ = c; 143 break;
144
145 case linecon_rollback:
146 *optr++ = pd->buf[pd->replay++];
147 if (pd->replay == pd->level)
148 pd->state = linecon_init;
87 } 149 }
88 } 150 }
89 151
...@@ -95,9 +157,55 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd, ...@@ -95,9 +157,55 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd,
95 static int 157 static int
96 alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) 158 alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
97 { 159 {
98 *pret = malloc (sizeof (int)); 160 int i;
99 if (!*pret) 161 struct linecon_data *pd = malloc (sizeof (pd[0]));
162 const char *line_info;
163
164 if (!pd)
100 return ENOMEM; 165 return ENOMEM;
166 pd->flags = 0;
167 pd->buf = NULL;
168 pd->size = pd->level = pd->replay = 0;
169 pd->line_number = 1;
170 for (i = 1; i < argc; i++)
171 {
172 if (argv[i][0] == '-')
173 {
174 switch (argv[i][1])
175 {
176 case 'i':
177 pd->flags |= LINECON_LINE_INFO;
178 if (i + 1 == argc)
179 return MU_ERR_PARSE;
180 line_info = argv[++i];
181 break;
182
183 default:
184 free (pd);
185 return MU_ERR_PARSE;
186 }
187 }
188 }
189 if (pd->flags & LINECON_LINE_INFO)
190 {
191 if (line_info[1])
192 {
193 pd->line_info_starter = strdup (line_info);
194 if (!pd->line_info_starter)
195 {
196 free (pd);
197 return ENOMEM;
198 }
199 }
200 else
201 {
202 pd->sbuf[0] = line_info[0];
203 pd->sbuf[1] = 0;
204 pd->line_info_starter = pd->sbuf;
205 pd->flags |= LINECON_LINE_INFO_STATIC;
206 }
207 }
208 *pret = pd;
101 return 0; 209 return 0;
102 } 210 }
103 211
......
...@@ -257,17 +257,14 @@ static void ...@@ -257,17 +257,14 @@ static void
257 _log_done (struct _mu_stream *str) 257 _log_done (struct _mu_stream *str)
258 { 258 {
259 struct _mu_log_stream *sp = (struct _mu_log_stream *)str; 259 struct _mu_log_stream *sp = (struct _mu_log_stream *)str;
260 if (str->flags & MU_STREAM_AUTOCLOSE) 260 mu_stream_destroy (&sp->transport);
261 mu_stream_destroy (&sp->transport);
262 } 261 }
263 262
264 static int 263 static int
265 _log_close (struct _mu_stream *str) 264 _log_close (struct _mu_stream *str)
266 { 265 {
267 struct _mu_log_stream *sp = (struct _mu_log_stream *)str; 266 struct _mu_log_stream *sp = (struct _mu_log_stream *)str;
268 if (str->flags & MU_STREAM_AUTOCLOSE) 267 return mu_stream_close (sp->transport);
269 return mu_stream_close (sp->transport);
270 return 0;
271 } 268 }
272 269
273 static int 270 static int
......