Commit f2980e5a f2980e5a1a7495e31f75b979b258bd0fffdb310e by Sergey Poznyakoff

Redo sieve debugging support

Instead of keeping individual debug flags for each Sieve machine,
use global debugging mechanism, category "sieve".  The following
levels are defined:

  trace1  -  print parse tree before optimization
  trace2  -  print parse tree after optimization
  trace3  -  print parser traces
  trace4  -  print tests and actions being executed
  trace8  -  print disassembled code, don't run
  trace9  -  print each Sieve instruction being executed

* include/mailutils/sieve.h (mu_sieve_get_debug_level)
(mu_sieve_set_debug_level): Remove.
(mu_sieve_is_dry_run,mu_sieve_set_dry_run
* lib/script.c (mu_script_debug_flags): Redo.
* lib/sieve.c (sieve_init): Remove call to obsoleted
mu_sieve_set_debug_level.

* examples/numaddr.c: Use mu_sieve_trace
* libmu_sieve/extensions/list.c: Likewise.
* libmu_sieve/extensions/moderator.c: Likewise.
* libmu_sieve/extensions/pipe.c: Likewise.
* libmu_sieve/extensions/spamd.c: Likewise.
* libmu_sieve/extensions/timestamp.c: Likewise.
* libmu_sieve/extensions/vacation.c: Likewise.
* libmu_sieve/tests.c: Likewise.

* libmu_sieve/runtime.c (INSTR_DEBUG,INSTR_DISASS): Rewrite.
(mu_sieve_get_debug_level): Remove.
(mu_sieve_is_dry_run_: Rewrite.
(mu_sieve_set_dry_run): New function.
(mu_sieve_disass): Rewrite.
* libmu_sieve/sieve-priv.h (mu_sieve_machine) <debug_level>: Remove.
<dry_run>: New field.
* libmu_sieve/sieve.y (mu_sieve_set_debug_level): Remove.
* libmu_sieve/util.c (mu_sieve_trace): New function.
* sieve/sieve.c: Rewrite support for --dry-run and --debug.

* sieve/tests/ext.at: Use --libdir-prefix instead of -L
1 parent 4e162e9b
......@@ -84,10 +84,7 @@ numaddr_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
struct val_ctr vc;
int rc;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "NUMADDR");
}
mu_sieve_trace (mach, "NUMADDR");
/* Retrieve required arguments: */
/* First argument: list of header names */
......
......@@ -231,13 +231,15 @@ void *mu_sieve_get_data (mu_sieve_machine_t mach);
void mu_sieve_set_data (mu_sieve_machine_t mach, void *);
mu_message_t mu_sieve_get_message (mu_sieve_machine_t mach);
size_t mu_sieve_get_message_num (mu_sieve_machine_t mach);
int mu_sieve_get_debug_level (mu_sieve_machine_t mach);
int mu_sieve_is_dry_run (mu_sieve_machine_t mach);
int mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val);
mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t mach);
int mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *);
char *mu_sieve_get_daemon_email (mu_sieve_machine_t mach);
const char *mu_sieve_get_identifier (mu_sieve_machine_t mach);
void mu_sieve_set_debug_level (mu_sieve_machine_t mach, int level);
void mu_sieve_set_logger (mu_sieve_machine_t mach,
mu_sieve_action_log_t logger);
void mu_sieve_set_mailer (mu_sieve_machine_t mach, mu_mailer_t mailer);
......
......@@ -39,6 +39,8 @@ struct mu_script_fun *script_tab[] = {
int
mu_script_debug_flags (const char *arg, char **endp)
{
mu_debug_level_t lev;
for (; *arg; arg++)
{
switch (*arg)
......@@ -48,11 +50,15 @@ mu_script_debug_flags (const char *arg, char **endp)
break;
case 't':
mu_script_debug_sieve |= MU_SIEVE_DEBUG_TRACE;
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_TRACE4));
break;
case 'i':
mu_script_debug_sieve |= MU_SIEVE_DEBUG_INSTR;
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_TRACE9));
break;
case 'l':
......
......@@ -81,7 +81,6 @@ sieve_init (const char *prog, mu_script_descr_t *pdescr)
rc = mu_sieve_machine_init (&mach);
if (rc == 0)
{
mu_sieve_set_debug_level (mach, mu_script_debug_sieve);
if (mu_script_sieve_log)
mu_sieve_set_logger (mach, _sieve_action_log);
rc = mu_sieve_compile (mach, prog);
......
......@@ -152,10 +152,7 @@ list_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
struct header_closure clos;
int result;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "LIST");
}
mu_sieve_trace (mach, "LIST");
memset (&clos, 0, sizeof clos);
if (mu_sieve_tag_lookup (tags, "delim", &arg))
......
......@@ -273,11 +273,8 @@ moderator_action (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
int discard = 0;
int ismime;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "moderator_test %lu",
(unsigned long) mu_sieve_get_message_num (mach));
}
mu_sieve_trace (mach, "moderator_test %lu",
(unsigned long) mu_sieve_get_message_num (mach));
msg = mu_sieve_get_message (mach);
mu_message_is_multipart (msg, &ismime);
......
......@@ -105,10 +105,7 @@ sieve_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags, int test)
}
cmd = val->v.string;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, test ? "PIPE (test)" : "PIPE (action)");
}
mu_sieve_trace (mach, test ? "PIPE (test)" : "PIPE (action)");
if (mu_sieve_is_dry_run (mach))
return 0;
......
......@@ -368,11 +368,8 @@ spamd_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
mu_header_t hdr;
mu_debug_handle_t lev = 0;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "spamd_test %lu",
(unsigned long) mu_sieve_get_message_num (mach));
}
mu_sieve_trace (mach, "spamd_test %lu",
(unsigned long) mu_sieve_get_message_num (mach));
if (mu_sieve_is_dry_run (mach))
return 0;
......
......@@ -57,10 +57,7 @@ timestamp_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
time_t tlimit, tval;
int rc;
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "TIMESTAMP");
}
mu_sieve_trace (mach, "TIMESTAMP");
/* Retrieve required arguments: */
/* First argument: header name */
......
......@@ -136,10 +136,7 @@ build_mime (mu_sieve_machine_t mach, mu_list_t tags, mu_mime_t *pmime,
static int
diag (mu_sieve_machine_t mach)
{
if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
{
mu_sieve_debug (mach, "VACATION");
}
mu_sieve_trace (mach, "VACATION");
mu_sieve_log_action (mach, "VACATION", NULL);
return mu_sieve_is_dry_run (mach);
......
......@@ -28,8 +28,9 @@
#define SIEVE_ADJUST(m,n) (m)->pc+=(n)
#define INSTR_DEBUG(m) \
((m)->debug_level & (MU_SIEVE_DEBUG_INSTR|MU_SIEVE_DEBUG_DISAS))
#define INSTR_DISASS(m) ((m)->debug_level & MU_SIEVE_DEBUG_DISAS)
(mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9))
#define INSTR_DISASS(m) \
(mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE8))
void
_mu_i_sv_instr_nop (mu_sieve_machine_t mach)
......@@ -263,12 +264,6 @@ mu_sieve_get_message_num (mu_sieve_machine_t mach)
return mach->msgno;
}
int
mu_sieve_get_debug_level (mu_sieve_machine_t mach)
{
return mach->debug_level;
}
const char *
mu_sieve_get_identifier (mu_sieve_machine_t mach)
{
......@@ -278,7 +273,15 @@ mu_sieve_get_identifier (mu_sieve_machine_t mach)
int
mu_sieve_is_dry_run (mu_sieve_machine_t mach)
{
return mach->debug_level & MU_SIEVE_DRY_RUN;
return mach->dry_run;
}
int
mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val)
{
if (mach->state != mu_sieve_state_compiled)
return EINVAL; //FIXME: another error code
return mach->dry_run = val;
}
int
......@@ -304,12 +307,15 @@ sieve_run (mu_sieve_machine_t mach)
int
mu_sieve_disass (mu_sieve_machine_t mach)
{
int level = mach->debug_level;
mu_debug_level_t lev;
int rc;
mach->debug_level = MU_SIEVE_DEBUG_INSTR | MU_SIEVE_DEBUG_DISAS;
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle,
MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE8)
| MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9));
rc = sieve_run (mach);
mach->debug_level = level;
mu_debug_set_category_level (mu_sieve_debug_handle, lev);
return rc;
}
......
......@@ -77,7 +77,7 @@ struct mu_sieve_machine
long reg; /* Numeric register */
mu_list_t stack; /* Runtime stack */
int debug_level; /* Debugging level */
int dry_run; /* Dry-run mode */
jmp_buf errbuf; /* Target location for non-local exits */
const char *identifier; /* Name of action or test being executed */
......
......@@ -1037,7 +1037,7 @@ mu_sieve_machine_inherit (mu_sieve_machine_t const parent,
return rc;
child->logger = parent->logger;
child->debug_level = parent->debug_level;
child->dry_run = parent->dry_run;
*pmach = child;
return 0;
}
......@@ -1071,7 +1071,7 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
mach->reg = 0;
mach->stack = NULL;
mach->debug_level = in->debug_level;
mach->dry_run = in->dry_run;
mach->errstream = in->errstream;
mu_stream_ref (mach->errstream);
......@@ -1100,12 +1100,6 @@ mu_sieve_set_diag_stream (mu_sieve_machine_t mach, mu_stream_t str)
}
void
mu_sieve_set_debug_level (mu_sieve_machine_t mach, int level)
{
mach->debug_level = level;
}
void
mu_sieve_set_logger (mu_sieve_machine_t mach, mu_sieve_action_log_t logger)
{
mach->logger = logger;
......
......@@ -119,8 +119,7 @@ sieve_test_address (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
int rc;
size_t count;
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "ADDRESS");
mu_sieve_trace (mach, "ADDRESS");
h = mu_sieve_value_get (args, 0);
if (!h)
......@@ -183,8 +182,7 @@ sieve_test_header (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
size_t count, mcount = 0;
struct header_closure clos;
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "HEADER");
mu_sieve_trace (mach, "HEADER");
h = mu_sieve_value_get (args, 0);
if (!h)
......@@ -267,8 +265,7 @@ sieve_test_envelope (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
int rc;
size_t count;
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "ENVELOPE");
mu_sieve_trace (mach, "ENVELOPE");
h = mu_sieve_value_get (args, 0);
if (!h)
......@@ -334,8 +331,7 @@ sieve_test_exists (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
mu_header_t header = NULL;
mu_sieve_value_t *val;
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "EXISTS");
mu_sieve_trace (mach, "EXISTS");
mu_message_get_header (mu_sieve_get_message (mach), &header);
val = mu_sieve_value_get (args, 0);
......
......@@ -230,6 +230,27 @@ mu_sieve_debug (mu_sieve_machine_t mach, const char *fmt, ...)
}
void
mu_sieve_trace (mu_sieve_machine_t mach, const char *fmt, ...)
{
va_list ap;
if (!mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE4))
return;
va_start (ap, fmt);
mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_DEBUG);
if (mach->locus.mu_file)
mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>",
MU_LOGMODE_LOCUS,
(unsigned) strlen (mach->locus.mu_file),
mach->locus.mu_file,
mach->locus.mu_line);
mu_stream_vprintf (mach->errstream, fmt, ap);
mu_stream_write (mach->errstream, "\n", 1, NULL);
va_end (ap);
}
void
mu_sieve_log_action (mu_sieve_machine_t mach, const char *action,
const char *fmt, ...)
{
......
......@@ -55,45 +55,46 @@ int sieve_debug;
int verbose;
char *script;
int expression_option;
int dry_run;
static int sieve_print_locus = 1; /* Should the log messages include the
locus */
static void
set_debug_level (const char *arg)
modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr)
{
mu_debug_level_t lev;
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle, (lev & ~clr) | set);
}
static void
set_debug_level (const char *arg)
{
for (; *arg; arg++)
{
switch (*arg)
{
case 'T':
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)));
modify_debug_flags (MU_DEBUG_LEVEL_UPTO(MU_DEBUG_TRACE9),
MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR));
break;
case 'P':
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));
modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_PROT), 0);
break;
case 'g':
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_TRACE1));
modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE1), 0);
break;
case 't':
sieve_debug |= MU_SIEVE_DEBUG_TRACE;
modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE4), 0);
break;
case 'i':
sieve_debug |= MU_SIEVE_DEBUG_INSTR;
modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9), 0);
break;
default:
......@@ -103,13 +104,6 @@ set_debug_level (const char *arg)
}
static void
cli_dry_run (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
sieve_debug |= MU_SIEVE_DRY_RUN;
verbose = 1;
}
static void
cli_compile_and_dump (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
......@@ -138,10 +132,10 @@ cli_no_program_name (struct mu_parseopt *po, struct mu_option *opt,
}
static struct mu_option sieve_options[] = {
{ "no-actions", 'n', NULL, MU_OPTION_DEFAULT,
{ "dry-run", 'n', NULL, MU_OPTION_DEFAULT,
N_("do not execute any actions, just print what would be done"),
mu_c_string, NULL, cli_dry_run },
{ "dry-run", 0, NULL, MU_OPTION_ALIAS },
mu_c_bool, &dry_run },
{ "no-actions", 0, NULL, MU_OPTION_ALIAS },
{ "keep-going", 'k', NULL, MU_OPTION_DEFAULT,
N_("keep on going if execution fails on a message"),
mu_c_bool, &keep_going },
......@@ -159,7 +153,7 @@ static struct mu_option sieve_options[] = {
mu_c_string, &mu_ticket_file },
{ "debug", 'd', N_("FLAGS"), MU_OPTION_ARG_OPTIONAL,
N_("debug flags (defaults to \"" D_DEFAULT "\")"),
mu_c_string, NULL, cli_debug },
mu_c_string, NULL, cli_debug, D_DEFAULT },
{ "verbose", 'v', NULL, MU_OPTION_DEFAULT,
N_("log all actions"),
mu_c_bool, &verbose },
......@@ -334,7 +328,7 @@ sieve_mailbox (mu_sieve_machine_t mach)
}
/* Open the mailbox read-only if we aren't going to modify it. */
if (sieve_debug & MU_SIEVE_DRY_RUN)
if (mu_sieve_is_dry_run (mach))
rc = mu_mailbox_open (mbox, MU_STREAM_READ);
else
rc = mu_mailbox_open (mbox, MU_STREAM_RDWR);
......@@ -360,7 +354,7 @@ sieve_mailbox (mu_sieve_machine_t mach)
rc = mu_sieve_mailbox (mach, mbox);
cleanup:
if (mbox && !(sieve_debug & MU_SIEVE_DRY_RUN))
if (mbox && !dry_run)
{
int e;
......@@ -405,7 +399,9 @@ main (int argc, char *argv[])
mu_register_all_formats ();
mu_cli (argc, argv, &cli, sieve_capa, NULL, &argc, &argv);
if (dry_run)
verbose++;
if (argc == 0)
{
mu_error (_("script must be specified"));
......@@ -448,7 +444,7 @@ main (int argc, char *argv[])
return EX_OK;
}
mu_sieve_set_debug_level (mach, sieve_debug);
mu_sieve_set_dry_run (mach, dry_run);
if (mbox_url && strcmp (mbox_url, "-") == 0)
rc = sieve_message (mach);
......
......@@ -32,7 +32,7 @@ if numaddr [[ "to", "cc" ]] :over 5
MUT_MBCOPY($abs_top_srcdir/testsuite/spool/bigto.mbox)
sieve MUT_SIEVE_CMDLINE dnl
--clearpath -L "${abs_top_builddir}/examples" -f ./bigto.mbox prog
--clearpath --libdir-prefix= "${abs_top_builddir}/examples" -f ./bigto.mbox prog
],
[0],
[],
......