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;
#define MU_DEBUG_LEVEL_MASK(lev) (1 << (lev))
#define MU_DEBUG_LEVEL_UPTO(lev) ((1 << ((lev)+1)) - 1)
#define MU_DEBUG_LEVEL_RANGE(a, b) \
((a) == 0 ? MU_DEBUG_LEVEL_UPTO (b) : \
MU_DEBUG_LEVEL_UPTO (b) & ~MU_DEBUG_LEVEL_UPTO ((a) - 1))
struct sockaddr;
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,
void mu_debug_parse_spec (const char *spec);
int mu_debug_format_spec(mu_stream_t str, const char *names, int showunset);
void mu_debug_set_category_level (mu_debug_handle_t catn,
mu_debug_level_t level);
int mu_debug_get_category_level (mu_debug_handle_t catn,
mu_debug_level_t *plev);
int mu_debug_set_category_level (mu_debug_handle_t catn,
mu_debug_level_t level);
void mu_debug_clear_all (void);
void mu_debug_log (const char *fmt, ...) MU_PRINTFLIKE(1,2);
......
......@@ -175,18 +175,73 @@ mu_debug_category_level (const char *catname, size_t catlen,
return 0;
}
void
int
mu_debug_set_category_level (mu_debug_handle_t catn, mu_debug_level_t level)
{
if (catn < catcnt)
{
cattab[catn].isset = 1;
cattab[catn].level = level;
return 0;
}
else
abort ();
return MU_ERR_NOENT;
}
int
mu_debug_get_category_level (mu_debug_handle_t catn, mu_debug_level_t *plev)
{
if (catn < catcnt)
{
if (!cattab[catn].isset)
*plev = 0;
else
*plev = cattab[catn].level;
return 0;
}
return MU_ERR_NOENT;
}
static char *mu_debug_level_str[] = {
"error",
"trace0",
"trace1",
"trace2",
"trace3",
"trace4",
"trace5",
"trace6",
"trace7",
"trace8",
"trace9",
"prot"
};
static int
mu_debug_level_from_string (const char *str, mu_debug_level_t *lev,
char **endp)
{
int i;
const char *p;
char *q;
for (i = 0; i < MU_ARRAY_SIZE (mu_debug_level_str); i++)
{
for (p = str, q = mu_debug_level_str[i]; ; p++, q++)
{
if (!*q)
{
if (endp)
*endp = (char*) p;
*lev = i;
return 0;
}
if (*q != *p)
break;
}
}
return MU_ERR_NOENT;
}
static void
parse_spec (const char *spec)
{
......@@ -231,18 +286,21 @@ parse_spec (const char *spec)
else
{
size_t i;
unsigned lev = 0;
unsigned xlev = 0;
mu_debug_level_t lev = 0;
mu_debug_level_t xlev = 0;
char *end;
for (i = 0; i < ws.ws_wordc; i++)
{
char *s = ws.ws_wordv[i];
int exact = 0;
unsigned n;
unsigned *tgt = &lev;
mu_debug_level_t n;
mu_debug_level_t *tgt = &lev;
if (*s == '!')
{
if (i == 0)
lev = MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT);
tgt = &xlev;
s++;
}
......@@ -252,20 +310,37 @@ parse_spec (const char *spec)
s++;
}
if (strcmp (s, "error") == 0)
n = MU_DEBUG_ERROR;
else if (strcmp (s, "prot") == 0)
n = MU_DEBUG_PROT;
else if (strlen (s) == 6 && memcmp (s, "trace", 5) == 0 &&
mu_isdigit (s[5]))
n = MU_DEBUG_TRACE0 + s[5] - '0';
else
if (mu_debug_level_from_string (s, &n, &end))
{
mu_error (_("unknown level `%s'"), s);
continue;
}
if (exact)
else if (*end == '-')
{
mu_debug_level_t l;
s = end + 1;
if (mu_debug_level_from_string (s, &l, &end))
{
mu_error (_("unknown level `%s'"), s);
continue;
}
else if (*end)
{
mu_error (_("invalid level: %s"), s);
continue;
}
if (n < l)
*tgt |= MU_DEBUG_LEVEL_RANGE (n, l);
else
*tgt |= MU_DEBUG_LEVEL_RANGE (l, n);
}
else if (*end)
{
mu_error (_("invalid level: %s"), s);
continue;
}
else if (exact)
*tgt |= MU_DEBUG_LEVEL_MASK (n);
else
*tgt |= MU_DEBUG_LEVEL_UPTO (n);
......@@ -317,21 +392,6 @@ mu_debug_clear_all ()
#define _LEVEL_ALL MU_DEBUG_LEVEL_UPTO(MU_DEBUG_PROT)
static char *mu_debug_level_str[] = {
"error",
"trace0",
"trace1",
"trace2",
"trace3",
"trace4",
"trace5",
"trace6",
"trace7",
"trace8",
"trace9",
"prot"
};
static int
name_matches (char **names, char *str)
{
......@@ -344,7 +404,7 @@ name_matches (char **names, char *str)
}
int
mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
mu_debug_format_spec (mu_stream_t str, const char *names, int showunset)
{
int i;
size_t cnt = 0;
......@@ -364,6 +424,7 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
{
if (names && !name_matches (ws.ws_wordv, cattab[i].name))
continue;
if (cattab[i].isset && cattab[i].level)
{
if (cnt)
......@@ -372,28 +433,58 @@ mu_debug_format_spec(mu_stream_t str, const char *names, int showunset)
if (rc)
break;
}
rc = mu_stream_printf(str, "%s", cattab[i].name);
rc = mu_stream_printf (str, "%s", cattab[i].name);
if (rc)
break;
if (cattab[i].level != _LEVEL_ALL)
{
int j;
mu_debug_level_t j = MU_DEBUG_ERROR, minl, maxl;
int delim = '.';
for (j = MU_DEBUG_ERROR; j <= MU_DEBUG_PROT; j++)
if (cattab[i].level & MU_DEBUG_LEVEL_MASK(j))
{
rc = mu_stream_printf(str, "%c%s", delim,
mu_debug_level_str[j]);
if (rc)
while (1)
{
/* Find the least bit set */
for (; j <= MU_DEBUG_PROT; j++)
if (cattab[i].level & MU_DEBUG_LEVEL_MASK (j))
break;
delim = ',';
}
if (j > MU_DEBUG_PROT)
break;
minl = j;
for (; j + 1 <= MU_DEBUG_PROT &&
cattab[i].level & MU_DEBUG_LEVEL_MASK (j + 1);
j++)
;
maxl = j++;
if (minl == maxl)
rc = mu_stream_printf (str, "%c=%s", delim,
mu_debug_level_str[minl]);
else if (minl == 0)
rc = mu_stream_printf (str, "%c%s", delim,
mu_debug_level_str[maxl]);
else
rc = mu_stream_printf (str, "%c%s-%s", delim,
mu_debug_level_str[minl],
mu_debug_level_str[maxl]);
if (rc)
break;
delim = ',';
}
}
cnt++;
}
else if (showunset)
{
if (cnt)
{
rc = mu_stream_printf(str, ";");
if (rc)
break;
}
rc = mu_stream_printf(str, "!%s", cattab[i].name);
if (rc)
break;
......
......@@ -6,6 +6,7 @@ testsuite.dir
testsuite.log
addr
argcv
debugspec
decode2047
encode2047
fltst
......
......@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
addr\
debugspec\
decode2047\
encode2047\
fltst\
......@@ -64,6 +65,7 @@ TESTSUITE_AT = \
address.at\
base64d.at\
base64e.at\
debugspec.at\
decode2047.at\
encode2047.at\
fromflt.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2010 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
dnl ------------------------------------------------------------
dnl TESTDBG([KW = `'], [ARGS], [STDOUT = `'],
dnl [STDERR = `'])
dnl
m4_pushdef([TESTDBG],[
AT_SETUP([debugspec: $2])
AT_KEYWORDS([debugspec debug dbgspec $1])
AT_CHECK([debugspec $2],
[0],
[$3],
[$4])
AT_CLEANUP])
dnl ------------------------------------------------------------
TESTDBG([debugspec00],[mailbox],
[mailbox
])
TESTDBG([debugspec01],[mailbox.=trace2],
[mailbox.=trace2
])
TESTDBG([debugspec02],[mailbox.trace3],
[mailbox.trace3
])
TESTDBG([debugspec03],[mailbox.!trace3],
[mailbox.trace4-prot
])
TESTDBG([debugspec04],[mailbox.!=trace3],
[mailbox.trace2,trace4-prot
])
TESTDBG([debugspec05],[mailbox.!=prot],
[mailbox.trace9
])
TESTDBG([debugspec06],[mailbox.prot,!=trace4],
[mailbox.trace3,trace5-prot
])
TESTDBG([debugspec07],[mailbox.prot,!trace4],
[mailbox.trace5-prot
])
TESTDBG([debugspec08],[mailbox.trace2-trace5],
[mailbox.trace2-trace5
])
TESTDBG([debugspec09],[mailbox.trace2-trace5,trace7-prot],
[mailbox.trace2-trace5,trace7-prot
])
TESTDBG([debugspec10],
['mailbox.error,=trace3,=trace7,=trace9;mailer.trace7,!trace2'],
[mailbox.=error,=trace3,=trace7,=trace9;mailer.trace3-trace7
])
TESTDBG([debugspec11],
[-showunset -names='mailbox;mailer;filter' dnl
'mailbox.error,=trace3,=trace7,=trace9;mailer.trace7,!trace2'],
[!filter;mailbox.=error,=trace3,=trace7,=trace9;mailer.trace3-trace7
])
dnl ------------------------------------------------------------
m4_popdef([TESTDBG])
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free Software
Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <mailutils/mailutils.h>
int
main (int argc, char **argv)
{
char *names = NULL;
int showunset = 0;
char *arg;
mu_set_program_name (argv[0]);
mu_stdstream_setup ();
if (argc == 1)
{
mu_printf ("usage: %s spec\n", argv[0]);
return 0;
}
while (argc--)
{
arg = *++argv;
if (strncmp (arg, "-names=", 7) == 0)
names = arg + 7;
else if (strcmp (arg, "-showunset") == 0)
showunset = 1;
else if (arg[0] == '-')
{
if (arg[1] == '-' && arg[2] == 0)
{
argc--;
argv++;
break;
}
mu_error ("unrecognised argument: %s", arg);
return 1;
}
else
break;
}
if (argc != 1)
{
mu_error ("usage: %s spec", mu_program_name);
return 1;
}
mu_debug_parse_spec (arg);
mu_debug_format_spec (mu_strout, names, showunset);
mu_printf ("\n");
return 0;
}
......@@ -68,4 +68,5 @@ m4_include([prop.at])
m4_include([inline-comment.at])
m4_include([hdrflt.at])
m4_include([linecon.at])
m4_include([debugspec.at])
......
......@@ -51,8 +51,8 @@ N_("GNU sieve -- a mail filtering tool.")
"\v"
N_("Debug flags:\n\
g - main parser traces\n\
T - mailutils traces (MU_DEBUG_TRACE0-MU_DEBUG_TRACE1)\n\
P - network protocols (MU_DEBUG_PROT)\n\
T - mailutils traces (same as --debug-level=sieve.trace0-trace1)\n\
P - network protocols (same as --debug-level=sieve.=prot)\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n");
......@@ -104,7 +104,6 @@ static struct argp_option options[] =
int keep_going;
int compile_only;
char *mbox_url;
int debug_level;
int sieve_debug;
int verbose;
char *script;
......@@ -127,16 +126,24 @@ is_true_p (char *p)
static void
set_debug_level (const char *arg)
{
mu_debug_level_t lev;
for (; *arg; arg++)
{
switch (*arg)
{
case 'T':
debug_level |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7);
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle,
lev |
(MU_DEBUG_LEVEL_UPTO(MU_DEBUG_TRACE9) &
~MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR)));
break;
case 'P':
debug_level |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_PROT);
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle,
lev | MU_DEBUG_LEVEL_MASK(MU_DEBUG_PROT));
break;
case 'g':
......@@ -456,9 +463,6 @@ main (int argc, char *argv[])
mu_register_all_formats ();
debug_level = MU_DEBUG_LEVEL_MASK (MU_DEBUG_ERROR);
mu_log_facility = 0;
if (mu_app_init (&argp, sieve_argp_capa, sieve_cfg_param,
argc, argv, ARGP_IN_ORDER, NULL, NULL))
exit (EX_USAGE);
......