Commit 45d49848 45d49848cd34a99cc326be9997a4b5d7142898fe by Sergey Poznyakoff

Scheme: add primitives for manipulating the MU debug levels.

* include/mailutils/debug.h (mu_debug_get_iterator): New proto.
* libmailutils/diag/debug.c (mu_debug_get_iterator): New function.
* libmu_scm/Makefile.am (lib_LTLIBRARIES): Add mu_debug.c.

* include/mailutils/guile.h (mu_scm_debug_init): New proto.
* libmu_scm/mu_scm.c (mu-register-format): Bugfix.
(mu_scm_init): Call mu_scm_debug_init.
1 parent d9044ffe
......@@ -84,6 +84,8 @@ void mu_debug_log_cont (const char *fmt, ...) MU_PRINTFLIKE(1,2);
void mu_debug_log_end (const char *fmt, ...) MU_PRINTFLIKE(1,2);
void mu_debug_log_nl (void);
int mu_debug_get_iterator (mu_iterator_t *piterator, int skipunset);
#define MU_ASSERT(expr) \
do \
......
......@@ -72,6 +72,7 @@ extern void mu_scm_mutil_init (void);
SCM mu_scm_make_debug_port (int level);
void mu_scm_debug_port_init (void);
extern void mu_scm_debug_init (void);
extern void mu_guile_init (int debug);
extern int mu_guile_load (const char *filename, int argc, char **argv);
......
......@@ -146,7 +146,7 @@ mu_iterator_dup (mu_iterator_t *piterator, mu_iterator_t orig)
if (status)
return status;
status = orig->dup(&iterator->owner, orig->owner);
status = orig->dup (&iterator->owner, orig->owner);
if (status)
{
free (iterator);
......
......@@ -32,6 +32,8 @@
#include <mailutils/wordsplit.h>
#include <mailutils/stream.h>
#include <mailutils/stdstream.h>
#include <mailutils/iterator.h>
#include <mailutils/cstr.h>
int mu_debug_line_info; /* Debug messages include source locations */
......@@ -497,6 +499,176 @@ mu_debug_format_spec (mu_stream_t str, const char *names, int showunset)
}
/* Iterator */
static mu_iterator_t iterator_head;
#define ITR_BACKWARDS 0x01
#define ITR_SKIPUNSET 0x02
#define ITR_FINISHED 0x04
struct debug_iterator
{
size_t pos;
int flags;
};
static int
first (void *owner)
{
struct debug_iterator *itr = owner;
itr->flags &= ~ITR_FINISHED;
if (itr->flags & ITR_BACKWARDS)
itr->pos = catcnt - 1;
else
itr->pos = 0;
return 0;
}
static int
next (void *owner)
{
struct debug_iterator *itr = owner;
itr->flags &= ~ITR_FINISHED;
do
{
if (itr->flags & ITR_BACKWARDS)
{
if (itr->pos)
itr->pos--;
else
itr->flags |= ITR_FINISHED;
}
else
{
if (itr->pos < catcnt - 1)
itr->pos++;
else
itr->flags |= ITR_FINISHED;
}
}
while ((itr->flags & ITR_SKIPUNSET) &&
!(itr->flags & ITR_FINISHED) &&
!cattab[itr->pos].isset);
return 0;
}
static int
getitem (void *owner, void **pret, const void **pkey)
{
struct debug_iterator *itr = owner;
*(mu_debug_level_t*) pret = cattab[itr->pos].level;
if (pkey)
*pkey = cattab[itr->pos].name;
return 0;
}
static int
finished_p (void *owner)
{
struct debug_iterator *itr = owner;
return itr->flags & ITR_FINISHED;
}
static int
curitem_p (void *owner, void *item)
{
struct debug_iterator *itr = owner;
return mu_c_strcasecmp (cattab[itr->pos].name, (char *) item) == 0;
}
static int
list_data_dup (void **ptr, void *owner)
{
*ptr = malloc (sizeof (struct debug_iterator));
if (*ptr == NULL)
return ENOMEM;
memcpy (*ptr, owner, sizeof (struct debug_iterator));
return 0;
}
static int
list_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
{
struct debug_iterator *itr = owner;
switch (req)
{
case mu_itrctl_tell:
/* Return current position in the object */
if (!arg)
return EINVAL;
*(size_t*)arg = itr->pos;
break;
case mu_itrctl_delete:
case mu_itrctl_delete_nd:
/* Delete current element */
cattab[itr->pos].level = 0;
cattab[itr->pos].isset = 0;
break;
case mu_itrctl_replace:
case mu_itrctl_replace_nd:
if (!arg)
return EINVAL;
cattab[itr->pos].level = *(mu_debug_level_t*)arg;
break;
case mu_itrctl_qry_direction:
if (!arg)
return EINVAL;
else
*(int*)arg = itr->flags & ITR_BACKWARDS;
break;
case mu_itrctl_set_direction:
if (!arg)
return EINVAL;
else
itr->flags |= ITR_BACKWARDS;
break;
default:
return ENOSYS;
}
return 0;
}
int
mu_debug_get_iterator (mu_iterator_t *piterator, int skipunset)
{
int status;
mu_iterator_t iterator;
struct debug_iterator *itr;
itr = malloc (sizeof *itr);
if (!itr)
return ENOMEM;
itr->pos = 0;
itr->flags = skipunset ? ITR_SKIPUNSET : 0;
status = mu_iterator_create (&iterator, itr);
if (status)
{
free (itr);
return status;
}
mu_iterator_set_first (iterator, first);
mu_iterator_set_next (iterator, next);
mu_iterator_set_getitem (iterator, getitem);
mu_iterator_set_finished_p (iterator, finished_p);
mu_iterator_set_curitem_p (iterator, curitem_p);
mu_iterator_set_dup (iterator, list_data_dup);
mu_iterator_set_itrctl (iterator, list_itrctl);
mu_iterator_attach (&iterator_head, iterator);
*piterator = iterator;
return 0;
}
void
mu_debug_log (const char *fmt, ...)
......
......@@ -24,6 +24,7 @@ lib_LTLIBRARIES=libmu_scm.la
C_SRCS=\
mu_address.c\
mu_body.c\
mu_debug.c\
mu_dbgport.c\
mu_guile.c\
mu_mailbox.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#include "mu_scm.h"
#include <mailutils/iterator.h>
#include <mailutils/stdstream.h>
SCM_DEFINE_PUBLIC (scm_mu_debug_parse, "mu-debug-parse", 1, 0, 0,
(SCM spec),
"Parses @var{spec} and sets MU debugging level according to it.")
#define FUNC_NAME s_scm_mu_debug_parse
{
char *s;
SCM_ASSERT (scm_is_string (spec), spec, SCM_ARG1, FUNC_NAME);
s = scm_to_locale_string (spec);
mu_debug_parse_spec (s);
free (s);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
static int
string_member_p (SCM list, SCM x)
{
return scm_member (x, list) != SCM_BOOL_F;
}
SCM_DEFINE_PUBLIC (scm_mu_debug_set, "mu-debug-set", 1, 0, 0,
(SCM catlist),
"Sets MU debug level according to @var{catlist}, which is a list of\n"
"conses: (cons category level)\n")
#define FUNC_NAME s_scm_mu_debug_set
{
SCM_ASSERT (scm_is_pair (catlist), catlist, SCM_ARG1, FUNC_NAME);
for (; !scm_is_null (catlist); catlist = SCM_CDR (catlist))
{
SCM cell = SCM_CAR (catlist);
SCM x;
char *name;
mu_debug_level_t lev;
SCM_ASSERT (scm_is_pair (cell), cell, SCM_ARGn, FUNC_NAME);
x = scm_car (cell);
SCM_ASSERT (scm_is_string (x), x, SCM_ARGn, FUNC_NAME);
name = scm_to_locale_string (x);
x = scm_cdr (cell);
SCM_ASSERT (scm_is_integer (x), x, SCM_ARGn, FUNC_NAME);
lev = scm_to_int (x);
if (lev == 0)
mu_debug_disable_category (name, strlen (name));
else
mu_debug_enable_category (name, strlen (name), lev);
free (name);
}
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE_PUBLIC (scm_mu_debug_get, "mu-debug-get", 0, 2, 0,
(SCM catlist, SCM skipunset),
"Returns a list of MU debugging categories with corresponding levels.\n"
"If @var{catlist} is supplied, it is a list of category names. In this case\n"
"only categories from this list are returned")
#define FUNC_NAME s_scm_mu_debug_get
{
int skipunset_flag = 0;
mu_iterator_t itr;
SCM head = SCM_EOL, tail = SCM_EOL;
int (*member_p) (SCM list, SCM needle);
if (SCM_UNBNDP (catlist) || catlist == SCM_BOOL_F)
member_p = NULL;
else
{
SCM_ASSERT (scm_is_pair (catlist), catlist, SCM_ARG1, FUNC_NAME);
member_p = string_member_p;
}
if (!SCM_UNBNDP (skipunset))
{
SCM_ASSERT (scm_is_bool (skipunset), skipunset, SCM_ARG2, FUNC_NAME);
skipunset_flag = skipunset == SCM_BOOL_T;
}
mu_debug_get_iterator (&itr, skipunset_flag);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
const char *name;
mu_debug_level_t level;
SCM scm_name;
mu_iterator_current_kv (itr, (const void**) &name, (void**) &level);
scm_name = scm_from_locale_string (name);
if (!member_p || member_p (catlist, scm_name))
{
SCM scm_new = scm_cons (scm_cons (scm_name,
scm_from_uintmax (level)),
SCM_EOL);
if (scm_is_null (head))
head = tail = scm_new;
else
{
SCM_SETCDR (tail, scm_new);
tail = scm_new;
}
}
}
mu_iterator_destroy (&itr);
return head;
}
#undef FUNC_NAME
void
mu_scm_debug_init ()
{
#include "mu_debug.x"
}
......@@ -128,7 +128,7 @@ SCM_DEFINE_PUBLIC (scm_mu_register_format, "mu-register-format", 0, 0, 1,
SCM_ASSERT (scm_is_string (scm), scm, SCM_ARGn, FUNC_NAME);
s = scm_to_locale_string (scm);
status = register_format (s);
free (scm);
free (s);
if (status)
mu_scm_error (FUNC_NAME, status,
"Cannot register format ~A",
......@@ -210,6 +210,7 @@ mu_scm_init ()
mu_scm_port_init ();
mu_scm_mime_init ();
mu_scm_debug_port_init ();
mu_scm_debug_init ();
#include "mu_scm.x"
......