local versions of utility files
This commit is contained in:
parent
2e772c1e3e
commit
09d40a0aae
671
src/utils/conftree.cpp
Executable file
671
src/utils/conftree.cpp
Executable file
@ -0,0 +1,671 @@
|
||||
#ifndef lint
|
||||
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.1 2005-11-12 14:24:33 dockes Exp $ (C) 2003 J.F.Dockes";
|
||||
#endif
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef TEST_CONFTREE
|
||||
|
||||
#include <unistd.h> // for access(2)
|
||||
#include <ctype.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "conftree.h"
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using namespace std;
|
||||
using std::list;
|
||||
#endif // NO_NAMESPACES
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(A,B) ((A)<(B) ? (A) : (B))
|
||||
#endif
|
||||
|
||||
static void trimstring(string &s, const char *ws = " \t")
|
||||
{
|
||||
string::size_type pos = s.find_first_not_of(ws);
|
||||
if (pos == string::npos) {
|
||||
s = "";
|
||||
return;
|
||||
}
|
||||
s.replace(0, pos, "");
|
||||
|
||||
pos = s.find_last_not_of(ws);
|
||||
if (pos != string::npos && pos != s.length()-1)
|
||||
s.replace(pos+1, string::npos, "");
|
||||
}
|
||||
|
||||
#define LL 1024
|
||||
void ConfSimple::parseinput(istream &input)
|
||||
{
|
||||
string submapkey;
|
||||
char cline[LL];
|
||||
bool appending = false;
|
||||
string line;
|
||||
|
||||
for (;;) {
|
||||
input.getline(cline, LL-1);
|
||||
//fprintf(stderr, "Line: '%s'\n", cline);
|
||||
if (!input.good()) {
|
||||
if (input.bad()) {
|
||||
status = STATUS_ERROR;
|
||||
//fprintf(stderr, "ConfSimple:parseinput: fatal error\n");
|
||||
return;
|
||||
}
|
||||
// Must be eof ?
|
||||
break;
|
||||
}
|
||||
|
||||
int ll = strlen(cline);
|
||||
while (ll > 0 && (cline[ll-1] == '\n' || cline[ll-1] == '\r')) {
|
||||
cline[ll-1] = 0;
|
||||
ll--;
|
||||
}
|
||||
|
||||
if (appending)
|
||||
line += cline;
|
||||
else
|
||||
line = cline;
|
||||
|
||||
// Note that we trim whitespace before checking for backslash-eol
|
||||
// This avoids invisible problems
|
||||
trimstring(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
if (line[line.length() - 1] == '\\') {
|
||||
line.erase(line.length() - 1);
|
||||
appending = true;
|
||||
continue;
|
||||
}
|
||||
appending = false;
|
||||
|
||||
if (line[0] == '[') {
|
||||
trimstring(line, "[]");
|
||||
submapkey = line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for first equal sign
|
||||
string::size_type eqpos = line.find("=");
|
||||
if (eqpos == string::npos)
|
||||
continue;
|
||||
|
||||
// Compute name and value, trim white space
|
||||
string nm, val;
|
||||
nm = line.substr(0, eqpos);
|
||||
trimstring(nm);
|
||||
val = line.substr(eqpos+1, string::npos);
|
||||
trimstring(val);
|
||||
|
||||
if (nm.length() == 0)
|
||||
continue;
|
||||
|
||||
map<string, map<string, string> >::iterator s;
|
||||
s = submaps.find(submapkey);
|
||||
if (s != submaps.end()) {
|
||||
// submap already exists
|
||||
map<string, string> &sm = s->second;
|
||||
sm[nm] = val;
|
||||
} else {
|
||||
map<string, string> newmap;
|
||||
newmap[nm] = val;
|
||||
submaps[submapkey] = newmap;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ConfSimple::ConfSimple(string *d, int readonly)
|
||||
{
|
||||
filename = "";
|
||||
data = d;
|
||||
status = readonly ? STATUS_RO : STATUS_RW;
|
||||
|
||||
stringstream input(*d, ios::in);
|
||||
parseinput(input);
|
||||
}
|
||||
|
||||
ConfSimple::ConfSimple(const char *fname, int readonly)
|
||||
{
|
||||
filename = string(fname);
|
||||
data = 0;
|
||||
|
||||
ifstream input;
|
||||
if (readonly) {
|
||||
input.open(fname, ios::in);
|
||||
status = STATUS_RO;
|
||||
} else {
|
||||
ios::openmode mode = ios::in|ios::out;
|
||||
// It seems that there is no separate 'create if not exists'
|
||||
// open flag. Have to truncate to create, but dont want to do
|
||||
// this to an existing file !
|
||||
if (access(fname, 0) < 0) {
|
||||
mode |= ios::trunc;
|
||||
}
|
||||
input.open(fname, mode);
|
||||
if (input.is_open()) {
|
||||
status = STATUS_RW;
|
||||
} else {
|
||||
input.clear();
|
||||
input.open(fname, ios::in);
|
||||
if (input.is_open()) {
|
||||
status = STATUS_RO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!input.is_open()) {
|
||||
status = STATUS_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse
|
||||
parseinput(input);
|
||||
}
|
||||
|
||||
ConfSimple::StatusCode ConfSimple::getStatus()
|
||||
{
|
||||
switch (status) {
|
||||
case STATUS_RO: return STATUS_RO;
|
||||
case STATUS_RW: return STATUS_RW;
|
||||
default: return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int ConfSimple::get(const string &nm, string &value, const string &sk)
|
||||
{
|
||||
if (status == STATUS_ERROR)
|
||||
return 0;
|
||||
|
||||
// Find submap
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end())
|
||||
return 0;
|
||||
|
||||
// Find named value
|
||||
map<string, string>::iterator s;
|
||||
if ((s = ss->second.find(nm)) == ss->second.end())
|
||||
return 0;
|
||||
value = s->second;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *ConfSimple::get(const char *nm, const char *sk)
|
||||
{
|
||||
if (status == STATUS_ERROR)
|
||||
return 0;
|
||||
if (sk == 0)
|
||||
sk = "";
|
||||
// Find submap
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end())
|
||||
return 0;
|
||||
|
||||
// Find named value
|
||||
map<string, string>::iterator s;
|
||||
if ((s = ss->second.find(nm)) == ss->second.end())
|
||||
return 0;
|
||||
return (s->second).c_str();
|
||||
}
|
||||
|
||||
static ConfSimple::WalkerCode swalker(void *f, const char *nm,
|
||||
const char *value)
|
||||
{
|
||||
ostream *output = (ostream *)f;
|
||||
if (!nm || !strcmp(nm, ""))
|
||||
*output << "\n[" << value << "]\n";
|
||||
else
|
||||
*output << nm << " = " << value << "\n";
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
int ConfSimple::set(const std::string &nm, const std::string &value,
|
||||
const string &sk)
|
||||
{
|
||||
if (status != STATUS_RW)
|
||||
return 0;
|
||||
|
||||
// Preprocess value: we don't want nl's in there, and we want to keep
|
||||
// lines to a reasonable length
|
||||
if (value.find_first_of("\n\r") != string::npos) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string value1;
|
||||
string::size_type pos = 0;
|
||||
if (value.length() < 60) {
|
||||
value1 = value;
|
||||
} else {
|
||||
while (pos < value.length()) {
|
||||
string::size_type len = MIN(60, value.length() - pos);
|
||||
value1 += value.substr(pos, len);
|
||||
pos += len;
|
||||
if (pos < value.length())
|
||||
value1 += "\\\n";
|
||||
}
|
||||
}
|
||||
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
||||
map<string, string> submap;
|
||||
submap[nm] = value1;
|
||||
submaps[sk] = submap;
|
||||
|
||||
} else {
|
||||
ss->second[nm] = value1;
|
||||
}
|
||||
|
||||
if (filename.length()) {
|
||||
ofstream output(filename.c_str(), ios::out|ios::trunc);
|
||||
if (!output.is_open())
|
||||
return 0;
|
||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (data) {
|
||||
ostringstream output(*data, ios::out | ios::trunc);
|
||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
// ??
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Add parameter to file
|
||||
int ConfSimple::set(const char *nm, const char *value, const char *sk)
|
||||
{
|
||||
string ssk = (sk == 0) ? string("") : string(sk);
|
||||
return set(string(nm), string(value), ssk);
|
||||
}
|
||||
|
||||
ConfSimple::WalkerCode
|
||||
ConfSimple::sortwalk(WalkerCode (*walker)(void *,const char *,const char *),
|
||||
void *clidata)
|
||||
{
|
||||
// For all submaps:
|
||||
for (map<string, map<string, string> >::iterator sit = submaps.begin();
|
||||
sit != submaps.end(); sit++) {
|
||||
|
||||
// Possibly emit submap name:
|
||||
if (!sit->first.empty() && walker(clidata, "", sit->first.c_str())
|
||||
== WALK_STOP)
|
||||
return WALK_STOP;
|
||||
|
||||
// Walk submap
|
||||
map<string, string> &sm = sit->second;
|
||||
for (map<string, string>::iterator it = sm.begin();it != sm.end();
|
||||
it++) {
|
||||
if (walker(clidata, it->first.c_str(), it->second.c_str())
|
||||
== WALK_STOP)
|
||||
return WALK_STOP;
|
||||
}
|
||||
}
|
||||
return WALK_CONTINUE;
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
void ConfSimple::list()
|
||||
{
|
||||
sortwalk(swalker, &std::cout);
|
||||
}
|
||||
|
||||
static ConfSimple::WalkerCode lwalker(void *l, const char *nm, const char *)
|
||||
{
|
||||
list<string> *lst = (list<string> *)l;
|
||||
if (nm && *nm)
|
||||
lst->push_back(nm);
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
list<string> ConfSimple::getKeys()
|
||||
{
|
||||
std::list<string> mylist;
|
||||
sortwalk(lwalker, &mylist);
|
||||
return mylist;
|
||||
}
|
||||
|
||||
static inline void path_catslash(std::string &s) {
|
||||
if (s.empty() || s[s.length() - 1] != '/')
|
||||
s += '/';
|
||||
}
|
||||
|
||||
int ConfTree::get(const std::string &name, string &value, const string &sk)
|
||||
{
|
||||
if (sk.empty() || sk[0] != '/') {
|
||||
// fprintf(stderr, "Looking in global space");
|
||||
return ConfSimple::get(name, value, sk);
|
||||
}
|
||||
|
||||
// Get writable copy of subkey path
|
||||
string msk = sk;
|
||||
|
||||
// Handle the case where the config file path has an ending / and not
|
||||
// the input sk
|
||||
path_catslash(msk);
|
||||
|
||||
// Look in subkey and up its parents until root ('')
|
||||
for (;;) {
|
||||
//fprintf(stderr,"Looking for '%s' in '%s'\n",
|
||||
//name.c_str(), msk.c_str());
|
||||
if (ConfSimple::get(name, value, msk))
|
||||
return 1;
|
||||
string::size_type pos = msk.rfind("/");
|
||||
if (pos != string::npos) {
|
||||
msk.replace(pos, string::npos, "");
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ConfTree::stringToStrings(const string &s, std::list<string> &tokens)
|
||||
{
|
||||
string current;
|
||||
tokens.clear();
|
||||
enum states {SPACE, TOKEN, INQUOTE, ESCAPE};
|
||||
states state = SPACE;
|
||||
for (unsigned int i = 0; i < s.length(); i++) {
|
||||
switch (s[i]) {
|
||||
case '"':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
state=INQUOTE; continue;
|
||||
case TOKEN:
|
||||
current += '"';
|
||||
continue;
|
||||
case INQUOTE:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '"';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
case TOKEN:
|
||||
current += '\\';
|
||||
state=TOKEN;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
state = ESCAPE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '\\';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
continue;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
current += s[i];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch(state) {
|
||||
case ESCAPE:
|
||||
state = INQUOTE;
|
||||
break;
|
||||
case SPACE:
|
||||
state = TOKEN;
|
||||
break;
|
||||
case TOKEN:
|
||||
case INQUOTE:
|
||||
break;
|
||||
}
|
||||
current += s[i];
|
||||
}
|
||||
}
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
break;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
break;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfTree::stringToBool(const string &s)
|
||||
{
|
||||
if (isdigit(s[0])) {
|
||||
int val = atoi(s.c_str());
|
||||
return val ? true : false;
|
||||
}
|
||||
if (strchr("yYoOtT", s[0]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#else // TEST_CONFTREE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "conftree.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char *thisprog;
|
||||
|
||||
ConfSimple::WalkerCode mywalker(void *, const char *nm, const char *value)
|
||||
{
|
||||
if (!nm || nm[0] == 0)
|
||||
printf("\n[%s]\n", value);
|
||||
else
|
||||
printf("'%s' -> '%s'\n", nm, value);
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
const char *longvalue =
|
||||
"Donnees012345678901234567890123456789012345678901234567890123456789AA"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789FIN"
|
||||
;
|
||||
|
||||
void stringtest()
|
||||
{
|
||||
string s;
|
||||
ConfSimple c(&s);
|
||||
cout << "Initial:" << endl;
|
||||
c.list();
|
||||
if (c.set("nom", "avec nl \n 2eme ligne", "")) {
|
||||
fprintf(stderr, "set with embedded nl succeeded !\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!c.set(string("parm1"), string("1"), string("subkey1"))) {
|
||||
fprintf(stderr, "Set error");
|
||||
exit(1);
|
||||
}
|
||||
if (!c.set("sparm", "Parametre \"string\" bla", "s2")) {
|
||||
fprintf(stderr, "Set error");
|
||||
exit(1);
|
||||
}
|
||||
if (!c.set("long", longvalue, "")) {
|
||||
fprintf(stderr, "Set error");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cout << "Final:" << endl;
|
||||
c.list();
|
||||
}
|
||||
|
||||
static char usage [] =
|
||||
"testconftree [opts] filename\n"
|
||||
"[-w] : read/write test.\n"
|
||||
"[-s] : string parsing test. Filename must hold parm 'strings'\n"
|
||||
"[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
|
||||
"[-S] : string io test. No filename in this case\n"
|
||||
;
|
||||
|
||||
void Usage() {
|
||||
fprintf(stderr, "%s:%s\n", thisprog, usage);
|
||||
exit(1);
|
||||
}
|
||||
static int op_flags;
|
||||
#define OPT_MOINS 0x1
|
||||
#define OPT_w 0x2
|
||||
#define OPT_q 0x4
|
||||
#define OPT_s 0x8
|
||||
#define OPT_S 0x10
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *nm = 0;
|
||||
const char *sub = 0;
|
||||
|
||||
thisprog = argv[0];
|
||||
argc--; argv++;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
Usage();
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 'w': op_flags |= OPT_w; break;
|
||||
case 's': op_flags |= OPT_s; break;
|
||||
case 'S': op_flags |= OPT_S; break;
|
||||
case 'q':
|
||||
op_flags |= OPT_q;
|
||||
if (argc < 3)
|
||||
Usage();
|
||||
nm = *(++argv);argc--;
|
||||
sub = *(++argv);argc--;
|
||||
goto b1;
|
||||
|
||||
default: Usage(); break;
|
||||
}
|
||||
b1: argc--; argv++;
|
||||
}
|
||||
|
||||
if ((op_flags & OPT_S)) {
|
||||
if (argc != 0)
|
||||
Usage();
|
||||
stringtest();
|
||||
} else {
|
||||
if (argc < 1)
|
||||
Usage();
|
||||
|
||||
const char *filename = *argv++;argc--;
|
||||
|
||||
if (op_flags & OPT_w) {
|
||||
ConfSimple parms(filename);
|
||||
if (parms.getStatus() != ConfSimple::STATUS_ERROR) {
|
||||
// It's ok for the file to not exist here
|
||||
|
||||
const char *cp = parms.get("mypid");
|
||||
if (cp) {
|
||||
printf("Value for mypid is '%s'\n", cp);
|
||||
} else {
|
||||
printf("mypid not set\n");
|
||||
}
|
||||
cp = parms.get("unstring");
|
||||
if (cp) {
|
||||
printf("Value for unstring is '%s'\n", cp);
|
||||
} else {
|
||||
printf("unstring not set\n");
|
||||
}
|
||||
string myval;
|
||||
if (parms.get(string("unstring"), myval, "")) {
|
||||
printf("std::string value for 'unstring' is '%s'\n",
|
||||
myval.c_str());
|
||||
} else {
|
||||
printf("unstring not set (std::string)\n");
|
||||
}
|
||||
}
|
||||
char spid[100];
|
||||
sprintf(spid, "%d", getpid());
|
||||
parms.set("mypid", spid);
|
||||
|
||||
ostringstream ost;;
|
||||
ost << "mypid" << getpid();
|
||||
parms.set(ost.str(), spid, "");
|
||||
|
||||
parms.set("unstring", "Une jolie phrase pour essayer");
|
||||
} else if (op_flags & OPT_q) {
|
||||
ConfTree parms(filename, 0);
|
||||
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||
fprintf(stderr, "Error opening or parsing file\n");
|
||||
exit(1);
|
||||
}
|
||||
string value;
|
||||
if (!parms.get(nm, value, sub)) {
|
||||
fprintf(stderr, "name '%s' not found in '%s'\n", nm, sub);
|
||||
exit(1);
|
||||
}
|
||||
printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
|
||||
exit(0);
|
||||
} else if (op_flags & OPT_s) {
|
||||
ConfSimple parms(filename, 1);
|
||||
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||
cerr << "Cant open /parse conf file " << filename << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string source;
|
||||
if (!parms.get(string("strings"), source, "")) {
|
||||
cerr << "Cant get param 'strings'" << endl;
|
||||
exit(1);
|
||||
}
|
||||
cout << "source: [" << source << "]" << endl;
|
||||
list<string> strings;
|
||||
if (!ConfTree::stringToStrings(source, strings)) {
|
||||
cerr << "parse failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (list<string>::iterator it = strings.begin();
|
||||
it != strings.end(); it++) {
|
||||
cout << "[" << *it << "]" << endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
ConfSimple parms(filename, 1);
|
||||
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||
fprintf(stderr, "Open failed\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("LIST\n");parms.list();
|
||||
printf("KEYS\n");
|
||||
list<string> keys = parms.getKeys();
|
||||
for (list<string>::iterator it = keys.begin();it!=keys.end();it++)
|
||||
printf("%s\n", (*it).c_str());
|
||||
//printf("WALK\n");parms.sortwalk(mywalker, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
151
src/utils/conftree.h
Executable file
151
src/utils/conftree.h
Executable file
@ -0,0 +1,151 @@
|
||||
#ifndef _CONFTREE_H_
|
||||
#define _CONFTREE_H_
|
||||
/**
|
||||
* A simple configuration file implementation.
|
||||
*
|
||||
* Configuration files have lines like 'name = value', and/or like '[subkey]'
|
||||
*
|
||||
* Lines like '[subkeyname]' in the file define subsections, with independant
|
||||
* configuration namespaces.
|
||||
*
|
||||
* Whitespace around name and value is insignificant.
|
||||
*
|
||||
* Values can be queried for, or set. (the file is then rewritten).
|
||||
* The names are case-sensitive but don't count on it either.
|
||||
* Any line without a '=' is discarded when rewriting the file.
|
||||
* All 'set' calls currently cause an immediate file rewrite.
|
||||
*/
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
// rh7.3 likes iostream better...
|
||||
#if defined(__GNUC__) && __GNUC__ < 3
|
||||
#include <iostream>
|
||||
#else
|
||||
#include <istream>
|
||||
#endif
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using std::string;
|
||||
using std::list;
|
||||
using std::map;
|
||||
#endif // NO_NAMESPACES
|
||||
|
||||
/**
|
||||
* Manages a simple configuration file with subsections.
|
||||
*/
|
||||
class ConfSimple {
|
||||
public:
|
||||
enum StatusCode {STATUS_ERROR=0, STATUS_RO=1, STATUS_RW=2};
|
||||
private:
|
||||
string filename; // set if we're working with a file
|
||||
string *data; // set if we're working with an in-memory string
|
||||
map<string, map<string, string> > submaps;
|
||||
StatusCode status;
|
||||
void parseinput(std::istream &input);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Build the object by reading content from file.
|
||||
*/
|
||||
ConfSimple(const char *fname, int readonly = 0);
|
||||
|
||||
/**
|
||||
* Build the object by reading content from a string
|
||||
*/
|
||||
ConfSimple(string *data, int readonly = 0);
|
||||
|
||||
virtual ~ConfSimple() {};
|
||||
|
||||
/**
|
||||
* Get value for named parameter, from specified subsection (looks in
|
||||
* global space if sk is empty).
|
||||
* @return 0 if name not found, 1 else
|
||||
*/
|
||||
virtual int get(const std::string &name, string &value, const string &sk);
|
||||
virtual int get(const std::string &name, string &value) {
|
||||
return get(name, value, string(""));
|
||||
}
|
||||
/**
|
||||
* See comments for std::string variant
|
||||
* @return 0 if name not found, const C string else
|
||||
*/
|
||||
virtual const char *get(const char *name, const char *sk = 0);
|
||||
|
||||
/**
|
||||
* Set value for named parameter in specified subsection (or global)
|
||||
* @return 0 for error, 1 else
|
||||
*/
|
||||
int set(const std::string &nm, const std::string &val, const string &sk);
|
||||
int set(const char *name, const char *value, const char *sk = 0);
|
||||
|
||||
virtual StatusCode getStatus();
|
||||
|
||||
/**
|
||||
* Walk the configuration values, calling function for each.
|
||||
* The function is called with a null nm when changing subsections (the
|
||||
* value is then the new subsection name)
|
||||
* @return WALK_STOP when/if the callback returns WALK_STOP,
|
||||
* WALK_CONTINUE else (got to end of config)
|
||||
*/
|
||||
enum WalkerCode {WALK_STOP, WALK_CONTINUE};
|
||||
virtual WalkerCode sortwalk(WalkerCode
|
||||
(*wlkr)(void *cldata, const char *nm,
|
||||
const char *val),
|
||||
void *clidata);
|
||||
void list();
|
||||
/**
|
||||
* Return all key names:
|
||||
*/
|
||||
std::list<string> getKeys();
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a configuration class which attaches tree-like signification to the
|
||||
* submap names.
|
||||
*
|
||||
* If a given variable is not found in the specified section, it will be
|
||||
* looked up the tree of section names, and in the global space.
|
||||
*
|
||||
* submap names should be '/' separated paths (ie: /sub1/sub2). No checking
|
||||
* is done, but else the class adds no functionality to ConfSimple.
|
||||
*
|
||||
* NOTE: contrary to common behaviour, the global or root space is NOT
|
||||
* designated by '/' but by '' (empty subkey). A '/' subkey will not
|
||||
* be searched at all.
|
||||
*/
|
||||
class ConfTree : public ConfSimple {
|
||||
|
||||
/* Dont want this to be accessible: keep only the string-based one */
|
||||
virtual const char *get(const char *, const char *) {return 0;}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Build the object by reading content from file.
|
||||
*/
|
||||
ConfTree(const char *fname, int readonly = 0)
|
||||
: ConfSimple(fname, readonly) {}
|
||||
virtual ~ConfTree() {};
|
||||
|
||||
/**
|
||||
* Get value for named parameter, from specified subsection, or its
|
||||
* parents.
|
||||
* @return 0 if name not found, 1 else
|
||||
*/
|
||||
virtual int get(const std::string &name, string &value, const string &sk);
|
||||
|
||||
virtual int get(const char *name, string &value, const char *sk) {
|
||||
return get(string(name), value, sk ? string(sk) : string(""));
|
||||
}
|
||||
/**
|
||||
* Parse input stream into vector of strings.
|
||||
*
|
||||
* Token delimiter is " \t" except inside dquotes. dquote inside
|
||||
* dquotes can be escaped with \ etc...
|
||||
*/
|
||||
static bool stringToStrings(const string &s, std::list<string> &tokens);
|
||||
static bool stringToBool(const string &s);
|
||||
};
|
||||
|
||||
|
||||
#endif /*_CONFTREE_H_ */
|
||||
393
src/utils/debuglog.cpp
Executable file
393
src/utils/debuglog.cpp
Executable file
@ -0,0 +1,393 @@
|
||||
#ifndef lint
|
||||
static char rcsid [] = "@(#$Id: debuglog.cpp,v 1.1 2005-11-12 14:24:33 dockes Exp $ (C) 2002 OKYZ";
|
||||
#endif
|
||||
#ifndef TEST_DEBUGLOG
|
||||
|
||||
#define __USE_GNU
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef INCLUDE_NEW_H
|
||||
#include <new.h>
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "debuglog.h"
|
||||
|
||||
#ifndef freeZ
|
||||
#define freeZ(X) {if (X) {free(X);X=0;}}
|
||||
#endif
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using namespace std;
|
||||
namespace DebugLog {
|
||||
|
||||
#endif // NO_NAMESPACES
|
||||
|
||||
class DebugLogWriter {
|
||||
public:
|
||||
virtual ~DebugLogWriter() {}
|
||||
virtual int put(const char *s) = 0;
|
||||
};
|
||||
|
||||
class DLFWImpl;
|
||||
class DebugLogFileWriter : public DebugLogWriter {
|
||||
DLFWImpl *impl;
|
||||
public:
|
||||
DebugLogFileWriter();
|
||||
~DebugLogFileWriter();
|
||||
virtual const char *getfilename();
|
||||
virtual int setfilename(const char *fname, int trnc = 1);
|
||||
virtual int put(const char *s);
|
||||
};
|
||||
|
||||
class DLFWImpl {
|
||||
char *filename;
|
||||
FILE *fp;
|
||||
int truncate;
|
||||
public:
|
||||
// Open output file if needed, return 0 if ok
|
||||
void maybeopenfp() {
|
||||
if (fp)
|
||||
return;
|
||||
if (filename == 0)
|
||||
return;
|
||||
if (!strcmp(filename, "stdout")) {
|
||||
fp = stdout;
|
||||
} else if (!strcmp(filename, "stderr")) {
|
||||
fp = stderr;
|
||||
} else {
|
||||
fp = fopen(filename, (truncate) ? "w" : "a");
|
||||
if (fp)
|
||||
setvbuf(fp, 0, _IOLBF, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void maybeclosefp() {
|
||||
#ifdef DEBUGDEBUG
|
||||
fprintf(stderr, "DebugLogImpl::maybeclosefp: filename %p, fp %p\n",
|
||||
filename, fp);
|
||||
#endif
|
||||
// Close current file if open, and not stdout/stderr
|
||||
if (fp && (filename == 0 ||
|
||||
(strcmp(filename, "stdout") &&
|
||||
strcmp(filename, "stderr")))) {
|
||||
fclose(fp);
|
||||
}
|
||||
fp = 0;
|
||||
freeZ(filename);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
DLFWImpl() : filename(0), fp(0), truncate(1) {
|
||||
setfilename("stderr", 0);
|
||||
}
|
||||
~DLFWImpl() {
|
||||
maybeclosefp();
|
||||
}
|
||||
int setfilename(const char *fn, int trnc) {
|
||||
maybeclosefp();
|
||||
filename = strdup(fn);
|
||||
truncate = trnc;
|
||||
return 0;
|
||||
}
|
||||
const char *getfilename() {
|
||||
return filename;
|
||||
}
|
||||
int put(const char *s) {
|
||||
maybeopenfp();
|
||||
if (fp)
|
||||
return fputs(s, fp);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
DebugLogFileWriter::DebugLogFileWriter()
|
||||
{
|
||||
impl = new DLFWImpl;
|
||||
}
|
||||
|
||||
DebugLogFileWriter::~DebugLogFileWriter()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
int DebugLogFileWriter::setfilename(const char *fn, int trnc) {
|
||||
return impl ? impl->setfilename(fn, trnc) : -1;
|
||||
}
|
||||
|
||||
const char *DebugLogFileWriter::getfilename()
|
||||
{
|
||||
return impl ? impl->getfilename() : 0;
|
||||
}
|
||||
|
||||
int DebugLogFileWriter::put(const char *s)
|
||||
{
|
||||
return impl ? impl->put(s) : -1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
static void datestring(char *d) {
|
||||
SYSTEMTIME buf;
|
||||
GetLocalTime(&buf);
|
||||
int year = buf.wYear % 100;
|
||||
|
||||
sprintf(d, "%02d%02d%02d%02d%02d%02d", year, int(buf.wMonth),
|
||||
int(buf.wDay), int(buf.wHour), int(buf.wMinute), int(buf.wSecond));
|
||||
}
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
#else // !WINDOWS ->
|
||||
|
||||
#include <time.h>
|
||||
static void datestring(char *d)
|
||||
{
|
||||
struct tm *tmp;
|
||||
time_t tim = time((time_t)0);
|
||||
tmp = localtime(&tim);
|
||||
int year = tmp->tm_year % 100;
|
||||
sprintf(d, "%02d%02d%02d%02d%02d%02d", year, tmp->tm_mon+1,
|
||||
tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
}
|
||||
|
||||
#endif // !WINDOWS
|
||||
|
||||
void
|
||||
DebugLog::prolog(int lev, const char *f, int line)
|
||||
{
|
||||
if (!writer)
|
||||
return;
|
||||
if (dodate) {
|
||||
char dts[100];
|
||||
datestring(dts);
|
||||
writer->put(dts);
|
||||
}
|
||||
char buf[100];
|
||||
sprintf(buf, ":%d:", lev);
|
||||
writer->put(buf);
|
||||
#if DEBUGLOG_USE_THREADS
|
||||
sprintf(buf, "%lx:", (unsigned long)pthread_self());
|
||||
writer->put(buf);
|
||||
#endif
|
||||
writer->put(f);
|
||||
sprintf(buf, ":%d:", line);
|
||||
writer->put(buf);
|
||||
}
|
||||
|
||||
void
|
||||
DebugLog::log(const char *s ...)
|
||||
{
|
||||
if (!writer)
|
||||
return;
|
||||
va_list ap;
|
||||
va_start(ap,s);
|
||||
|
||||
#ifdef HAVE_VASPRINTF_nono // not sure vasprintf is really such a great idea
|
||||
char *buf;
|
||||
vasprintf(&buf, s, ap);
|
||||
if (buf) {
|
||||
#else
|
||||
char buf[4096];
|
||||
// It's possible that they also wouldn't have vsnprintf but what then ?
|
||||
vsnprintf(buf, 4096, s, ap);
|
||||
{
|
||||
#endif
|
||||
writer->put(buf);
|
||||
}
|
||||
|
||||
#ifdef HAVE_VASPRINTF_nono
|
||||
if (buf)
|
||||
free(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DebugLog::setloglevel(int lev)
|
||||
{
|
||||
debuglevel = lev;
|
||||
while (!levels.empty())
|
||||
levels.pop();
|
||||
pushlevel(lev);
|
||||
}
|
||||
|
||||
void DebugLog::pushlevel(int lev)
|
||||
{
|
||||
debuglevel = lev;
|
||||
levels.push(lev);
|
||||
}
|
||||
|
||||
void DebugLog::poplevel()
|
||||
{
|
||||
if (levels.empty())
|
||||
debuglevel = 0;
|
||||
if (levels.size() > 1)
|
||||
levels.pop();
|
||||
debuglevel = levels.top();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Global functions
|
||||
//////////////////////////////////////
|
||||
static DebugLogFileWriter lwriter;
|
||||
static DebugLogFileWriter *theWriter = &lwriter;
|
||||
const char *getfilename()
|
||||
{
|
||||
return theWriter ? theWriter->getfilename() : 0;
|
||||
}
|
||||
int setfilename(const char *fname, int trnc)
|
||||
{
|
||||
return theWriter ? theWriter->setfilename(fname, trnc) : -1;
|
||||
}
|
||||
|
||||
#if DEBUGLOG_USE_THREADS
|
||||
#include <pthread.h>
|
||||
static pthread_key_t dbl_key;
|
||||
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void thrdatadel(void *data)
|
||||
{
|
||||
// fprintf(stderr, "DebugLog:: thrdatadel: %p\n", data);
|
||||
DebugLog *dbl = (DebugLog *)data;
|
||||
delete dbl;
|
||||
pthread_setspecific(dbl_key, 0);
|
||||
}
|
||||
static void once_routine(void)
|
||||
{
|
||||
int status;
|
||||
status = pthread_key_create(&dbl_key, thrdatadel);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "debuglog: cant initialize pthread "
|
||||
"thread private storage key\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
DebugLog *getdbl()
|
||||
{
|
||||
int status = pthread_once(&key_once, once_routine);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "debuglog: cant initialize pthread "
|
||||
"thread private storage key (pthread_once)\n");
|
||||
abort();
|
||||
}
|
||||
DebugLog *dbl;
|
||||
if (!(dbl = (DebugLog *)pthread_getspecific(dbl_key))) {
|
||||
dbl = new DebugLog;
|
||||
dbl->setwriter(theWriter);
|
||||
status = pthread_setspecific(dbl_key, dbl);
|
||||
if (status) {
|
||||
fprintf(stderr, "debuglog: cant initialize pthread "
|
||||
"thread private storage key (pthread_setspecific)\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
return dbl;
|
||||
}
|
||||
|
||||
#else // No threads ->
|
||||
|
||||
static DebugLog *dbl;
|
||||
DebugLog *getdbl()
|
||||
{
|
||||
if (!dbl) {
|
||||
dbl = new DebugLog;
|
||||
dbl->setwriter(theWriter);
|
||||
}
|
||||
return dbl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
}
|
||||
#endif // NO_NAMESPACES
|
||||
|
||||
////////////////////////////////////////// TEST DRIVER //////////////////
|
||||
#else /* TEST_DEBUGLOG */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "debuglog.h"
|
||||
|
||||
#if DEBUGLOG_USE_THREADS
|
||||
#define TEST_THREADS
|
||||
#endif
|
||||
|
||||
#ifdef TEST_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
const int iloop = 5;
|
||||
void *thread_test(void *data)
|
||||
{
|
||||
const char *s = (const char *)data;
|
||||
int lev = atoi(s);
|
||||
DebugLog::getdbl()->setloglevel(DEBDEB);
|
||||
for (int i = 1; i < iloop;i++) {
|
||||
switch (lev) {
|
||||
case 1: LOGFATAL(("Thread: %s count: %d\n", s, i));break;
|
||||
case 2: LOGERR(("Thread: %s count: %d\n", s, i));break;
|
||||
default:
|
||||
case 3: LOGINFO(("Thread: %s count: %d\n", s, i));break;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
#ifdef TEST_THREADS
|
||||
pthread_t t1, t2, t3;
|
||||
|
||||
char name1[20];
|
||||
strcpy(name1, "1");
|
||||
pthread_create(&t1, 0, thread_test, name1);
|
||||
|
||||
char name2[20];
|
||||
strcpy(name2, "2");
|
||||
pthread_create(&t2, 0, thread_test, name2);
|
||||
|
||||
char name3[20];
|
||||
strcpy(name3, "3");
|
||||
pthread_create(&t3, 0, thread_test, name3);
|
||||
|
||||
DebugLog::getdbl()->setloglevel(DEBDEB);
|
||||
for (int i = 1; i < iloop;i++) {
|
||||
LOGINFO(("LOGGING FROM MAIN\n"));
|
||||
sleep(1);
|
||||
}
|
||||
sleep(2);
|
||||
exit(0);
|
||||
#else
|
||||
LOGFATAL(("FATAL\n","Val"));
|
||||
DebugLog::getdbl()->logdate(1);
|
||||
LOGERR(("ERR\n","Val"));
|
||||
LOGINFO(("INFO\n","Val"));
|
||||
LOGDEB0(("DEBUG %s\n","valeur"));
|
||||
|
||||
int lev;
|
||||
printf("Testing push. Initial level: %d\n", DebugLog::getdbl()->getlevel());
|
||||
for (lev = 0; lev < 4;lev++) {
|
||||
DebugLog::getdbl()->pushlevel(lev);
|
||||
printf("Lev now %d\n", DebugLog::getdbl()->getlevel());
|
||||
}
|
||||
printf("Testing pop\n");
|
||||
for (lev = 0; lev < 7;lev++) {
|
||||
DebugLog::getdbl()->poplevel();
|
||||
printf("Lev now %d\n", DebugLog::getdbl()->getlevel());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif /* TEST_DEBUGLOG */
|
||||
101
src/utils/debuglog.h
Executable file
101
src/utils/debuglog.h
Executable file
@ -0,0 +1,101 @@
|
||||
#ifndef _DEBUGLOG_H_
|
||||
#define _DEBUGLOG_H_
|
||||
/* Macros for log and debug messages */
|
||||
#include <stack>
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
namespace DebugLog {
|
||||
using std::stack;
|
||||
#endif // NO_NAMESPACES
|
||||
|
||||
#ifndef DEBUGLOG_USE_THREADS
|
||||
#define DEBUGLOG_USE_THREADS 1
|
||||
#endif
|
||||
|
||||
#define DEBFATAL 1
|
||||
#define DEBERR 2
|
||||
#define DEBINFO 3
|
||||
#define DEBDEB 4
|
||||
#define DEBDEB0 5
|
||||
#define DEBDEB1 6
|
||||
#define DEBDEB2 7
|
||||
#define DEBDEB3 8
|
||||
|
||||
#ifndef STATICVERBOSITY
|
||||
#define STATICVERBOSITY DEBDEB0
|
||||
#endif
|
||||
|
||||
class DebugLogWriter;
|
||||
|
||||
class DebugLog {
|
||||
std::stack<int> levels;
|
||||
int debuglevel;
|
||||
int dodate;
|
||||
DebugLogWriter *writer;
|
||||
public:
|
||||
DebugLog() : debuglevel(-1), dodate(0), writer(0) {}
|
||||
DebugLog(DebugLogWriter *w) : debuglevel(-1), dodate(0), writer(w) {}
|
||||
virtual ~DebugLog() {}
|
||||
virtual void setwriter(DebugLogWriter *w) {writer = w;}
|
||||
virtual DebugLogWriter *getwriter() {return writer;}
|
||||
virtual void prolog(int lev, const char *srcfname, int line);
|
||||
virtual void log(const char *s ...);
|
||||
virtual void setloglevel(int lev);
|
||||
inline int getlevel() {return debuglevel;}
|
||||
virtual void pushlevel(int lev);
|
||||
virtual void poplevel();
|
||||
virtual void logdate(int onoff) {dodate = onoff;}
|
||||
};
|
||||
|
||||
extern DebugLog *getdbl();
|
||||
extern const char *getfilename();
|
||||
extern int setfilename(const char *fname, int trnc = 1);
|
||||
#if STATICVERBOSITY >= DEBFATAL
|
||||
#define LOGFATAL(X) {if (DebugLog::getdbl()->getlevel()>=DEBFATAL){DebugLog::getdbl()->prolog(DEBFATAL,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGFATAL(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBERR
|
||||
#define LOGERR(X) {if (DebugLog::getdbl()->getlevel()>=DEBERR){DebugLog::getdbl()->prolog(DEBERR,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGERR(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBINFO
|
||||
#define LOGINFO(X) {if (DebugLog::getdbl()->getlevel()>=DEBINFO){DebugLog::getdbl()->prolog(DEBINFO,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGINFO(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB
|
||||
#define LOGDEB(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB){DebugLog::getdbl()->prolog(DEBDEB,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB0
|
||||
#define LOGDEB0(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB0){DebugLog::getdbl()->prolog(DEBDEB0,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB0(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB1
|
||||
#define LOGDEB1(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB1){DebugLog::getdbl()->prolog(DEBDEB1,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB1(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB2
|
||||
#define LOGDEB2(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB2){DebugLog::getdbl()->prolog(DEBDEB2,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB2(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB3
|
||||
#define LOGDEB3(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB3){DebugLog::getdbl()->prolog(DEBDEB3,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB3(X)
|
||||
#endif
|
||||
#if STATICVERBOSITY >= DEBDEB4
|
||||
#define LOGDEB4(X) {if (DebugLog::getdbl()->getlevel()>=DEBDEB4){DebugLog::getdbl()->prolog(DEBDEB4,__FILE__,__LINE__) ;DebugLog::getdbl()->log X;}}
|
||||
#else
|
||||
#define LOGDEB4(X)
|
||||
#endif
|
||||
#ifndef NO_NAMESPACES
|
||||
}
|
||||
#endif // NO_NAMESPACES
|
||||
#endif /* _DEBUGLOG_H_ */
|
||||
Loading…
x
Reference in New Issue
Block a user