Commit 2d75640f 2d75640f30de68fc3659fc740edaa9043fea5e8e by Sergey Poznyakoff

Improve debug parser and output functions.

New parser accepts range specifications (mailbox.trace3-prot).
mu_debug_format_spec outputs specs in the canonical form.

* include/mailutils/debug.h (MU_DEBUG_LEVEL_RANGE): New macro.
(mu_debug_set_category_level): Change return type to int.
(mu_debug_get_category_level): New proto.
* libmailutils/diag/debug.c (mu_debug_set_category_level): Change
return type to int.
(mu_debug_get_category_level): New function.
(mu_debug_level_from_string): New function.
(parse_spec): Accept range specification.  Negation at the start
of spec implies 'proto'.
(mu_debug_format_spec): Rewrite.

* libmailutils/tests/debugspec.c: New file.
* libmailutils/tests/debugspec.at: New file.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add debugspec.
(TESTSUITE_AT): add debugspec.at
* libmailutils/tests/testsuite.at: Include debugspec.at.
* libmailutils/tests/.gitignore: Add debugspec.

* sieve/sieve.c: Do not advertise 'T' and 'P' arguments to --debug.
(debug_level): Remove.
(set_debug_level): Rewrite the handling of legacy debug specifiers 'TP'.
1 parent b2d144c5
...@@ -48,6 +48,10 @@ extern int mu_debug_line_info; ...@@ -48,6 +48,10 @@ extern int mu_debug_line_info;
48 48
49 #define MU_DEBUG_LEVEL_MASK(lev) (1 << (lev)) 49 #define MU_DEBUG_LEVEL_MASK(lev) (1 << (lev))
50 #define MU_DEBUG_LEVEL_UPTO(lev) ((1 << ((lev)+1)) - 1) 50 #define MU_DEBUG_LEVEL_UPTO(lev) ((1 << ((lev)+1)) - 1)
51 #define MU_DEBUG_LEVEL_RANGE(a, b) \
52 ((a) == 0 ? MU_DEBUG_LEVEL_UPTO (b) : \
53 MU_DEBUG_LEVEL_UPTO (b) & ~MU_DEBUG_LEVEL_UPTO ((a) - 1))
54
51 55
52 struct sockaddr; 56 struct sockaddr;
53 void mu_sockaddr_to_str (const struct sockaddr *sa, int salen, 57 void mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
...@@ -67,8 +71,11 @@ int mu_debug_category_level (const char *catname, size_t catlen, ...@@ -67,8 +71,11 @@ int mu_debug_category_level (const char *catname, size_t catlen,
67 void mu_debug_parse_spec (const char *spec); 71 void mu_debug_parse_spec (const char *spec);
68 int mu_debug_format_spec(mu_stream_t str, const char *names, int showunset); 72 int mu_debug_format_spec(mu_stream_t str, const char *names, int showunset);
69 73
70 void mu_debug_set_category_level (mu_debug_handle_t catn, 74 int mu_debug_get_category_level (mu_debug_handle_t catn,
75 mu_debug_level_t *plev);
76 int mu_debug_set_category_level (mu_debug_handle_t catn,
71 mu_debug_level_t level); 77 mu_debug_level_t level);
78
72 void mu_debug_clear_all (void); 79 void mu_debug_clear_all (void);
73 80
74 void mu_debug_log (const char *fmt, ...) MU_PRINTFLIKE(1,2); 81 void mu_debug_log (const char *fmt, ...) MU_PRINTFLIKE(1,2);
......
...@@ -175,16 +175,71 @@ mu_debug_category_level (const char *catname, size_t catlen, ...@@ -175,16 +175,71 @@ mu_debug_category_level (const char *catname, size_t catlen,
175 return 0; 175 return 0;
176 } 176 }
177 177
178 void 178 int
179 mu_debug_set_category_level (mu_debug_handle_t catn, mu_debug_level_t level) 179 mu_debug_set_category_level (mu_debug_handle_t catn, mu_debug_level_t level)
180 { 180 {
181 if (catn < catcnt) 181 if (catn < catcnt)
182 { 182 {
183 cattab[catn].isset = 1; 183 cattab[catn].isset = 1;
184 cattab[catn].level = level; 184 cattab[catn].level = level;
185 return 0;
185 } 186 }
187 return MU_ERR_NOENT;
188 }
189
190 int
191 mu_debug_get_category_level (mu_debug_handle_t catn, mu_debug_level_t *plev)
192 {
193 if (catn < catcnt)
194 {
195 if (!cattab[catn].isset)
196 *plev = 0;
186 else 197 else
187 abort (); 198 *plev = cattab[catn].level;
199 return 0;
200 }
201 return MU_ERR_NOENT;
202 }
203
204 static char *mu_debug_level_str[] = {
205 "error",
206 "trace0",
207 "trace1",
208 "trace2",
209 "trace3",
210 "trace4",
211 "trace5",
212 "trace6",
213 "trace7",
214 "trace8",
215 "trace9",
216 "prot"
217 };
218
219 static int
220 mu_debug_level_from_string (const char *str, mu_debug_level_t *lev,
221 char **endp)
222 {
223 int i;
224 const char *p;
225 char *q;
226
227 for (i = 0; i < MU_ARRAY_SIZE (mu_debug_level_str); i++)
228 {
229 for (p = str, q = mu_debug_level_str[i]; ; p++, q++)
230 {
231 if (!*q)
232 {
233 if (endp)
234 *endp = (char*) p;
235 *lev = i;
236 return 0;
237 }
238 if (*q != *p)
239 break;
240 }
241 }
242 return MU_ERR_NOENT;
188 } 243 }
189 244
190 static void 245 static void
...@@ -231,18 +286,21 @@ parse_spec (const char *spec) ...@@ -231,18 +286,21 @@ parse_spec (const char *spec)
231 else 286 else
232 { 287 {
233 size_t i; 288 size_t i;
234 unsigned lev = 0; 289 mu_debug_level_t lev = 0;
235 unsigned xlev = 0; 290 mu_debug_level_t xlev = 0;
291 char *end;
236 292
237 for (i = 0; i < ws.ws_wordc; i++) 293 for (i = 0; i < ws.ws_wordc; i++)
238 { 294 {
239 char *s = ws.ws_wordv[i]; 295 char *s = ws.ws_wordv[i];
240 int exact = 0; 296 int exact = 0;
241 unsigned n; 297 mu_debug_level_t n;
242 unsigned *tgt = &lev; 298 mu_debug_level_t *tgt = &lev;
243 299
244 if (*s == '!') 300 if (*s == '!')
245 { 301 {
302 if (i == 0)
303 lev = MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT);
246 tgt = &xlev; 304 tgt = &xlev;
247 s++; 305 s++;
248 } 306 }
...@@ -252,20 +310,37 @@ parse_spec (const char *spec) ...@@ -252,20 +310,37 @@ parse_spec (const char *spec)
252 s++; 310 s++;
253 } 311 }
254 312
255 if (strcmp (s, "error") == 0) 313 if (mu_debug_level_from_string (s, &n, &end))
256 n = MU_DEBUG_ERROR;
257 else if (strcmp (s, "prot") == 0)
258 n = MU_DEBUG_PROT;
259 else if (strlen (s) == 6 && memcmp (s, "trace", 5) == 0 &&
260 mu_isdigit (s[5]))
261 n = MU_DEBUG_TRACE0 + s[5] - '0';
262 else
263 { 314 {
264 mu_error (_("unknown level `%s'"), s); 315 mu_error (_("unknown level `%s'"), s);
265 continue; 316 continue;
266 } 317 }
318 else if (*end == '-')
319 {
320 mu_debug_level_t l;
267 321
268 if (exact) 322 s = end + 1;
323 if (mu_debug_level_from_string (s, &l, &end))
324 {
325 mu_error (_("unknown level `%s'"), s);
326 continue;
327 }
328 else if (*end)
329 {
330 mu_error (_("invalid level: %s"), s);
331 continue;
332 }
333 if (n < l)
334 *tgt |= MU_DEBUG_LEVEL_RANGE (n, l);
335 else
336 *tgt |= MU_DEBUG_LEVEL_RANGE (l, n);
337 }
338 else if (*end)
339 {
340 mu_error (_("invalid level: %s"), s);
341 continue;
342 }
343 else if (exact)
269 *tgt |= MU_DEBUG_LEVEL_MASK (n); 344 *tgt |= MU_DEBUG_LEVEL_MASK (n);
270 else 345 else
271 *tgt |= MU_DEBUG_LEVEL_UPTO (n); 346 *tgt |= MU_DEBUG_LEVEL_UPTO (n);
...@@ -317,21 +392,6 @@ mu_debug_clear_all () ...@@ -317,21 +392,6 @@ mu_debug_clear_all ()
317 392
318 #define _LEVEL_ALL MU_DEBUG_LEVEL_UPTO(MU_DEBUG_PROT) 393 #define _LEVEL_ALL MU_DEBUG_LEVEL_UPTO(MU_DEBUG_PROT)
319 394
320 static char *mu_debug_level_str[] = {
321 "error",
322 "trace0",
323 "trace1",
324 "trace2",
325 "trace3",
326 "trace4",
327 "trace5",
328 "trace6",
329 "trace7",
330 "trace8",
331 "trace9",
332 "prot"
333 };
334
335 static int 395 static int
336 name_matches (char **names, char *str) 396 name_matches (char **names, char *str)
337 { 397 {
...@@ -344,7 +404,7 @@ name_matches (char **names, char *str) ...@@ -344,7 +404,7 @@ name_matches (char **names, char *str)
344 } 404 }
345 405
346 int 406 int
347 mu_debug_format_spec(mu_stream_t str, const char *names, int showunset) 407 mu_debug_format_spec (mu_stream_t str, const char *names, int showunset)
348 { 408 {
349 int i; 409 int i;
350 size_t cnt = 0; 410 size_t cnt = 0;
...@@ -364,6 +424,7 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset) ...@@ -364,6 +424,7 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
364 { 424 {
365 if (names && !name_matches (ws.ws_wordv, cattab[i].name)) 425 if (names && !name_matches (ws.ws_wordv, cattab[i].name))
366 continue; 426 continue;
427
367 if (cattab[i].isset && cattab[i].level) 428 if (cattab[i].isset && cattab[i].level)
368 { 429 {
369 if (cnt) 430 if (cnt)
...@@ -372,19 +433,43 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset) ...@@ -372,19 +433,43 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
372 if (rc) 433 if (rc)
373 break; 434 break;
374 } 435 }
375 rc = mu_stream_printf(str, "%s", cattab[i].name); 436 rc = mu_stream_printf (str, "%s", cattab[i].name);
376 if (rc) 437 if (rc)
377 break; 438 break;
378 if (cattab[i].level != _LEVEL_ALL) 439 if (cattab[i].level != _LEVEL_ALL)
379 { 440 {
380 int j; 441 mu_debug_level_t j = MU_DEBUG_ERROR, minl, maxl;
381 int delim = '.'; 442 int delim = '.';
382 443
383 for (j = MU_DEBUG_ERROR; j <= MU_DEBUG_PROT; j++) 444 while (1)
384 if (cattab[i].level & MU_DEBUG_LEVEL_MASK(j))
385 { 445 {
386 rc = mu_stream_printf(str, "%c%s", delim, 446 /* Find the least bit set */
387 mu_debug_level_str[j]); 447 for (; j <= MU_DEBUG_PROT; j++)
448 if (cattab[i].level & MU_DEBUG_LEVEL_MASK (j))
449 break;
450
451 if (j > MU_DEBUG_PROT)
452 break;
453
454 minl = j;
455
456 for (; j + 1 <= MU_DEBUG_PROT &&
457 cattab[i].level & MU_DEBUG_LEVEL_MASK (j + 1);
458 j++)
459 ;
460
461 maxl = j++;
462
463 if (minl == maxl)
464 rc = mu_stream_printf (str, "%c=%s", delim,
465 mu_debug_level_str[minl]);
466 else if (minl == 0)
467 rc = mu_stream_printf (str, "%c%s", delim,
468 mu_debug_level_str[maxl]);
469 else
470 rc = mu_stream_printf (str, "%c%s-%s", delim,
471 mu_debug_level_str[minl],
472 mu_debug_level_str[maxl]);
388 if (rc) 473 if (rc)
389 break; 474 break;
390 delim = ','; 475 delim = ',';
...@@ -394,6 +479,12 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset) ...@@ -394,6 +479,12 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
394 } 479 }
395 else if (showunset) 480 else if (showunset)
396 { 481 {
482 if (cnt)
483 {
484 rc = mu_stream_printf(str, ";");
485 if (rc)
486 break;
487 }
397 rc = mu_stream_printf(str, "!%s", cattab[i].name); 488 rc = mu_stream_printf(str, "!%s", cattab[i].name);
398 if (rc) 489 if (rc)
399 break; 490 break;
......
...@@ -6,6 +6,7 @@ testsuite.dir ...@@ -6,6 +6,7 @@ testsuite.dir
6 testsuite.log 6 testsuite.log
7 addr 7 addr
8 argcv 8 argcv
9 debugspec
9 decode2047 10 decode2047
10 encode2047 11 encode2047
11 fltst 12 fltst
......
...@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac ...@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
41 INCLUDES = @MU_LIB_COMMON_INCLUDES@ 41 INCLUDES = @MU_LIB_COMMON_INCLUDES@
42 noinst_PROGRAMS = \ 42 noinst_PROGRAMS = \
43 addr\ 43 addr\
44 debugspec\
44 decode2047\ 45 decode2047\
45 encode2047\ 46 encode2047\
46 fltst\ 47 fltst\
...@@ -64,6 +65,7 @@ TESTSUITE_AT = \ ...@@ -64,6 +65,7 @@ TESTSUITE_AT = \
64 address.at\ 65 address.at\
65 base64d.at\ 66 base64d.at\
66 base64e.at\ 67 base64e.at\
68 debugspec.at\
67 decode2047.at\ 69 decode2047.at\
68 encode2047.at\ 70 encode2047.at\
69 fromflt.at\ 71 fromflt.at\
......
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2010 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 dnl ------------------------------------------------------------
18 dnl TESTDBG([KW = `'], [ARGS], [STDOUT = `'],
19 dnl [STDERR = `'])
20 dnl
21 m4_pushdef([TESTDBG],[
22 AT_SETUP([debugspec: $2])
23 AT_KEYWORDS([debugspec debug dbgspec $1])
24 AT_CHECK([debugspec $2],
25 [0],
26 [$3],
27 [$4])
28 AT_CLEANUP])
29
30 dnl ------------------------------------------------------------
31 TESTDBG([debugspec00],[mailbox],
32 [mailbox
33 ])
34
35 TESTDBG([debugspec01],[mailbox.=trace2],
36 [mailbox.=trace2
37 ])
38
39 TESTDBG([debugspec02],[mailbox.trace3],
40 [mailbox.trace3
41 ])
42
43 TESTDBG([debugspec03],[mailbox.!trace3],
44 [mailbox.trace4-prot
45 ])
46
47 TESTDBG([debugspec04],[mailbox.!=trace3],
48 [mailbox.trace2,trace4-prot
49 ])
50
51 TESTDBG([debugspec05],[mailbox.!=prot],
52 [mailbox.trace9
53 ])
54
55 TESTDBG([debugspec06],[mailbox.prot,!=trace4],
56 [mailbox.trace3,trace5-prot
57 ])
58
59 TESTDBG([debugspec07],[mailbox.prot,!trace4],
60 [mailbox.trace5-prot
61 ])
62
63 TESTDBG([debugspec08],[mailbox.trace2-trace5],
64 [mailbox.trace2-trace5
65 ])
66
67 TESTDBG([debugspec09],[mailbox.trace2-trace5,trace7-prot],
68 [mailbox.trace2-trace5,trace7-prot
69 ])
70
71 TESTDBG([debugspec10],
72 ['mailbox.error,=trace3,=trace7,=trace9;mailer.trace7,!trace2'],
73 [mailbox.=error,=trace3,=trace7,=trace9;mailer.trace3-trace7
74 ])
75
76 TESTDBG([debugspec11],
77 [-showunset -names='mailbox;mailer;filter' dnl
78 'mailbox.error,=trace3,=trace7,=trace9;mailer.trace7,!trace2'],
79 [!filter;mailbox.=error,=trace3,=trace7,=trace9;mailer.trace3-trace7
80 ])
81
82 dnl ------------------------------------------------------------
83
84 m4_popdef([TESTDBG])
85
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software
3 Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <mailutils/mailutils.h>
27
28 int
29 main (int argc, char **argv)
30 {
31 char *names = NULL;
32 int showunset = 0;
33 char *arg;
34
35 mu_set_program_name (argv[0]);
36 mu_stdstream_setup ();
37
38 if (argc == 1)
39 {
40 mu_printf ("usage: %s spec\n", argv[0]);
41 return 0;
42 }
43
44 while (argc--)
45 {
46 arg = *++argv;
47
48 if (strncmp (arg, "-names=", 7) == 0)
49 names = arg + 7;
50 else if (strcmp (arg, "-showunset") == 0)
51 showunset = 1;
52 else if (arg[0] == '-')
53 {
54 if (arg[1] == '-' && arg[2] == 0)
55 {
56 argc--;
57 argv++;
58 break;
59 }
60 mu_error ("unrecognised argument: %s", arg);
61 return 1;
62 }
63 else
64 break;
65 }
66
67 if (argc != 1)
68 {
69 mu_error ("usage: %s spec", mu_program_name);
70 return 1;
71 }
72
73 mu_debug_parse_spec (arg);
74
75 mu_debug_format_spec (mu_strout, names, showunset);
76 mu_printf ("\n");
77
78 return 0;
79 }
80
81
...@@ -68,4 +68,5 @@ m4_include([prop.at]) ...@@ -68,4 +68,5 @@ m4_include([prop.at])
68 m4_include([inline-comment.at]) 68 m4_include([inline-comment.at])
69 m4_include([hdrflt.at]) 69 m4_include([hdrflt.at])
70 m4_include([linecon.at]) 70 m4_include([linecon.at])
71 m4_include([debugspec.at])
71 72
......
...@@ -51,8 +51,8 @@ N_("GNU sieve -- a mail filtering tool.") ...@@ -51,8 +51,8 @@ N_("GNU sieve -- a mail filtering tool.")
51 "\v" 51 "\v"
52 N_("Debug flags:\n\ 52 N_("Debug flags:\n\
53 g - main parser traces\n\ 53 g - main parser traces\n\
54 T - mailutils traces (MU_DEBUG_TRACE0-MU_DEBUG_TRACE1)\n\ 54 T - mailutils traces (same as --debug-level=sieve.trace0-trace1)\n\
55 P - network protocols (MU_DEBUG_PROT)\n\ 55 P - network protocols (same as --debug-level=sieve.=prot)\n\
56 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\ 56 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
57 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n"); 57 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n");
58 58
...@@ -104,7 +104,6 @@ static struct argp_option options[] = ...@@ -104,7 +104,6 @@ static struct argp_option options[] =
104 int keep_going; 104 int keep_going;
105 int compile_only; 105 int compile_only;
106 char *mbox_url; 106 char *mbox_url;
107 int debug_level;
108 int sieve_debug; 107 int sieve_debug;
109 int verbose; 108 int verbose;
110 char *script; 109 char *script;
...@@ -127,16 +126,24 @@ is_true_p (char *p) ...@@ -127,16 +126,24 @@ is_true_p (char *p)
127 static void 126 static void
128 set_debug_level (const char *arg) 127 set_debug_level (const char *arg)
129 { 128 {
129 mu_debug_level_t lev;
130
130 for (; *arg; arg++) 131 for (; *arg; arg++)
131 { 132 {
132 switch (*arg) 133 switch (*arg)
133 { 134 {
134 case 'T': 135 case 'T':
135 debug_level |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7); 136 mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
137 mu_debug_set_category_level (mu_sieve_debug_handle,
138 lev |
139 (MU_DEBUG_LEVEL_UPTO(MU_DEBUG_TRACE9) &
140 ~MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR)));
136 break; 141 break;
137 142
138 case 'P': 143 case 'P':
139 debug_level |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_PROT); 144 mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
145 mu_debug_set_category_level (mu_sieve_debug_handle,
146 lev | MU_DEBUG_LEVEL_MASK(MU_DEBUG_PROT));
140 break; 147 break;
141 148
142 case 'g': 149 case 'g':
...@@ -456,9 +463,6 @@ main (int argc, char *argv[]) ...@@ -456,9 +463,6 @@ main (int argc, char *argv[])
456 463
457 mu_register_all_formats (); 464 mu_register_all_formats ();
458 465
459 debug_level = MU_DEBUG_LEVEL_MASK (MU_DEBUG_ERROR);
460 mu_log_facility = 0;
461
462 if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param, 466 if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param,
463 argc, argv, ARGP_IN_ORDER, NULL, NULL)) 467 argc, argv, ARGP_IN_ORDER, NULL, NULL))
464 exit (EX_USAGE); 468 exit (EX_USAGE);
......