qlibs: errmsg
errmsg is a replacement for the error/strerr lib used in (net)qmail and other djb-like software. The intention to write it was a typical UNIX rules case: I was not satisfied with the existing error handling code, mainly because:
- the code of the replaced libs was hard to read (understand) (you can feel it was written by a mathematician)
- the strerr lib is overloaded with long static
 #define 
's - there were a lot of inconsistencies through packages and its libs, including more or less duplicate code (I hate duplicate code)
- the error codes/messages should be come from the operating system (which is more accurat)
There are some minor reasons additional. It was clearly deliberated to make the errmsg static and not use variable args directly, but the argument *msg could be build with a variable number of arguments through the  B 
macro easily (see examples below). errmsg is part of qlibs.
The switch can be done smoothly - errmsg and strerr can coexists!
Beside the man page (errmsg.3) some more explanation:
Prototype
int errmsg(char *who, int code, unsigned int severity, char *msg) /* build error message from multiple partial strings */ extern char *build_error_msg(char *[]); #define B(...) build_error_msg((char *[]){__VA_ARGS__,NULL})
 who 
is the name of the program which runs into an error,  code 
is the error code (usually  errno 
),  severity 
is the loglevel and  msg 
is an additional internal description of the error.
There are some macros defined in  errmsg.h 
which makes the usage easier:
macro | equivalent (djb) | description | severity | ||||
---|---|---|---|---|---|---|---|
 errsys(c)  | hard error (code 111) | system error | FATAL | ||||
 errtmp(c)  | temp error (code 100) | temporary error (soft/user error) | ERROR | ||||
 errint(c,s)  | “ | w/ additional internal defined error message          | ERROR | ||||
 errlog(c,l,s)  | - | define code, severity and internal error message | (user defined) | ||||
 log(s)  | status log message | log message, suppresses system error messages | NOTICE |
 c 
is the error code,  s 
is an additional message string,  l 
is the severity. The arguments of errmsg which are not have to be given here (e.g.  who 
) will be set automatically.
Severity and loglevel
The header file  errmsg.h 
has constants defined for severity and loglevel:
/* severity constants similar to standard (see syslog.3) */ #define FATAL 0 /* ERMERGENCY (FATAL) */ #define ALERT 1 /* ALERT */ #define CRIT 2 /* CRITICAL (CRIT)*/ #define ERROR 3 /* ERROR */ #define WARN 4 /* WARNING */ #define NOTICE 5 /* NOTICE */ #define INFO 6 /* INFO */ #define DEBUG 7 /* DEBUG */ #define DEF_LOGLEVEL NOTICE extern unsigned int loglevel;
The  loglevel 
variable defines the behavior of errmsg in general. If
 loglevel < WARN 
: errmsg exits with (an*) error code loglevel = WARN 
: errmsg returns with the given error code loglevel > WARN 
: errmsg returns with 0
A  loglevel 
greater than  DEF_LOGLEVEL 
have to be set in the caller program explicitly. Usually this is done by an option like -v to increase verbosity:
int verbosity = 1; ... switch(opt) { case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; ... } ... if (verbosity == 2) loglevel = INFO;
Special control of output
Some “special” error codes have an impact of the behavior of errmsg too. By default errmsg produces the following output (four parts delimited by a colon):
program: severity: system error string (code): <individual msg>
Maybe this is not wanted in some special situations. And a code of 0 (zero) doesn't indicate an error. So if  code 
is not set (same as zero) and  severity 
is smaller than  ERROR 
, then the second part ( severity: 
) and the third part ( system error string (code): 
) of the output will be suppressed. Example:
errlog(0,CRIT,B("usage: ",WHO," <opts> argument"));
Compatibility
For backwards compatibility there are definitions in  errmsg.h 
also:
#define error_str(i) errstr(i) /* djb uses some internal codes */ #define ESOFT -100 /* soft error (reversed negative) */ #define EHARD -111 /* hard error (reversed negative) */ /* djb backwards compat - some programs rely on an exit code 100/111 */ #define errsoft(s) errmsg(WHO,ESOFT,CRIT,s) /* re-think severity here! */ #define errhard(s) errmsg(WHO,EHARD,ALERT,s)
Simply use the constants  ESOFT 
and  EHARD 
to replace the hard-coded exit codes 100/111. But in general it is recommended to use  errno 
instead if possible.
Attention: Keep in mind that some programs (from djb) relies on an exit code of 100/111 (this is a rarely case)!
Thus, if  code 
has the value  EHARD 
or  ESOFT 
, errmsg exits 111 or 100 respective. See man page for details.
Further errmsg contains all the individual error definitions from djb. There is a symlink  errmsg.h –> error.h 
too.
Abbreviations
The macros provide a way to make usage easier.
Example(s):
More rarely - in older code - djb uses  error_temp(errno) 
like:
if (error_temp(errno)) _exit 111;
This could be replaced like:
if (errno) errsys(EHARD);
More standard usage:
#include "errmsg.h" ... #define WHO "my progname" if (argc < 1) errsys(EINVAL); if (argc < 1) errmsg(WHO,EINVAL,ERROR,""); /* call direct w/ all params */ chdir("/does/not/exist"); if (errno) errint(errno,"directory '/does/not/exist' doesn't exist"); /* print an additional message string */ if (errno) errsys(ENOTDIR); /* ... or short (alternative) */ if (!stralloc_copys(&s,"a string")) errsys(errno); /* short, use system message string */ s = socket_tcp6(); if (s < 0) errsys(errno); /* print error message on failure ... */ log(B("connected :",fmtnum(s))); /* ... or log a message (depends on loglevel) */
Replace strerr() by errmsg()
Simply the number in a strerr_* command defines the number of arguments which will be used to create a message. So  strerr_die4x 
expects 4 arguments after the error code. Some examples should make it more clear.
Hint: The constant  FATAL 
in the strerr*-lines below is a hard-coded constants in the original code. They have nothing to do with the equal named severity of errmsg().
First the constant  FATAL 
has to be replaced by the new constant  WHO 
. The severity is now defined by errmsg().
#define FATAL "bouncesaying: fatal: " // --> remove this! #define WHO "bouncesaying"
The new constant  WHO 
have to contain the name of the program only!
The first examples are quite simple:
// strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)"); errint(ESOFT,"Sorry, no mailbox here by that name. (#5.1.1)"); // strerr_die2x(100,FATAL,"SENDER not set"); errint(ESOFT,"SENDER not set"); // strerr_die2x(111,FATAL,"out of memory"); errint(EHARD,"out of memory");
Note: The constant  FATAL 
is now replaced by the constant  WHO 
, which by itself will be used by the errmsg() macros automatically.
If there should be a function like  strerr_die4sys() 
replaced, the long way along the examples above would be (taken from qmail-tcpok.c):
// strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": "); if(!stralloc_copyb(&sa,"unable to chdir to ",19)) errmem; if(!stralloc_cats(&sa,auto_qmail)) errsys(errno); if(!stralloc_catb(&sa,": ",2)) errsys(errno); if(!stralloc_0(&sa)) errsys(errno); errint(EHARD,(char *)sa.s);
This is really more effort as with the original strerr() function. But it is easy to use the  B 
macro like in the next example (taken from preline.c):
// strerr_die4sys(error_temp(errno) ? 111 : 100,FATAL,"unable to run ",*argv,": "); errint((errno),B("unable to run ",*argv,": "));
The part  ? 111 : 100 
doesn't make sense here anymore with errmsg. As mentioned above it is recommended to use the error codes from the operating system.
Some more real examples from  qtcpclient.c 
:
// strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys); return(errlog(errno,WARN,B(CONNECT,ipstr," port ",strnum,": "))); strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0); log(B(": AAA connected to ",ipstr," port ",strnum,0)); // strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); errint(errno,B("temporarily unable to figure out IP address for ",hostname,": ")); if (addresses.len < 16) // strerr_die3x(111,FATAL,"no IP address for ",hostname); errint(errno,B("no IP address for ",hostname));
Makefile changes
To (re-)build an existing program against errmsg there are some changes in the Makefile necessary. Simply replace  strerr.a 
,  error.a 
or  error.o 
/  error_str.o 
/  error_temp.o 
(whatever exists) in a recipe with  errmsg.a 
. A better way is to use a more common (standard) way with library search path(es) and library linking:
preline: $(COMPILE) preline.c $(LOADBIN) preline -Lqlibs -lqlibs
Comments
Error: Class "XMLReader" not found
An unforeseen error has occured. This is most likely a bug somewhere. It might be a problem in the captcha plugin.
More info has been written to the DokuWiki error log.