/* This file is part of mailfromd. -*- c -*-
Copyright (C) 2007 Sergey Poznyakoff
This program 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.
This program 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 this program. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include "mailfromd.h"
struct modinfo {
char *name;
unsigned code;
};
static char *modname[] = {
"all",
MAKEDEBUGTAB(SRCLIST)
};
#define NMODULES (sizeof modname / sizeof modname[0])
static int modlevel[NMODULES]; /* Per-module levels */
/* Implementation */
int
debug_level_p(int modn, int level)
{
return modn < NMODULES
&& (modlevel[modn] ? (modlevel[modn] >= level)
: modlevel[0] >= level);
}
static int
find_module(const char *name)
{
size_t len, i;
const char *q;
const char *p;
p = strrchr(name, '/');
if (p)
p++;
else
p = name;
q = strrchr(p, '.');
if (q)
len = q - name;
else
len = strlen(p);
for (i = 0; i < NMODULES; i++) {
if (strlen(modname[i]) == len
&& memcmp(modname[i], p, len) == 0)
return i;
}
return -1;
}
void
debug_enable_module(const char *file, int level)
{
int modn = find_module(file);
if (modn < 0) {
mu_error(_("unknown module: %s"), file);
return;
}
modlevel[modn] = level;
}
int
debug_module_level(const char *modname, int *plev)
{
int modn;
if (modname) {
modn = find_module(modname);
if (modn < 0)
return 1;
} else
modn = 0;
*plev = modlevel[modn];
return 0;
}
static void
parse_spec(char *spec)
{
char *p, *q;
int level;
if (isdigit(*spec)) {
modlevel[0] = strtoul(spec, &q, 0);
if (*q)
mu_error(_("%s: wrong debug spec near %s"), spec, q);
if (modlevel[0] >= 100)
enable_prog_trace("all");
return;
}
p = strchr(spec, '=');
if (p) {
*p++ = 0;
level = strtol(p, &q, 0);
if (*q || level < 0) {
mu_error(_("%s: wrong debug spec near %s"), spec, q);
return;
}
} else
level = 100;
debug_enable_module(spec, level);
}
void
debug_parse_spec(const char *spec)
{
char *copy = xstrdup(spec);
char *s;
for (s = strtok(copy, ","); s; s = strtok(NULL, ","))
parse_spec(s);
free(copy);
}
int
debug_spec_string(const char *spec, char **pbuf)
{
char mods[NMODULES];
size_t len = 0, i;
char nbuf[NUMERIC_BUFSIZE_BOUND];
char *buf, *ptr;
if (!spec) {
memset(mods, 0xff, sizeof mods);
} else {
char *copy = xstrdup(spec);
char *s;
memset(mods, 0, sizeof mods);
for (s = strtok(copy, ","); s; s = strtok(NULL, ",")) {
int n = find_module(s);
if (n < 0) {
free(copy);
return EINVAL;
}
mods[n] = 1;
}
}
if (mods[0]) {
snprintf(nbuf, sizeof nbuf, "%d", modlevel[0]);
len += strlen(nbuf) + 1;
}
for (i = 1; i < NMODULES; i++) {
if (mods[i]) {
snprintf(nbuf, sizeof nbuf, "%d", modlevel[i]);
len += strlen(modname[i]) + 1 + strlen(nbuf) + 1;
}
}
buf = malloc(len + 1);
if (!buf)
return ENOMEM;
ptr = buf;
if (mods[0]) {
sprintf(ptr, "%d", modlevel[0]);
ptr += strlen(ptr);
}
for (i = 1; i < NMODULES; i++) {
if (mods[i]) {
if (ptr > buf)
*ptr++ = ',';
sprintf(ptr, "%s=%d", modname[i], modlevel[i]);
ptr += strlen(ptr);
}
}
*ptr = 0;
*pbuf = buf;
return 0;
}