Flow Control
Overview
The Flow Control module is at the very core of LibU. It defines a number of macros that are used throughout the library code to guide the execution flow. They enforce an assertive programming style in which the code in the function body flows straight to the expected result and all the anomalies catched in the trunk are handled in a a special err:
labelled branch. Each function body can be split into the following three blocks.
A declaration block:
int f (void)
{
char *d = NULL;
FILE *fp = NULL;
The trunk:
dbg_err_sif ((d = u_zalloc(1024)) == NULL);
dbg_err_sif ((fp = fopen("my.txt", "w")) == NULL);
dbg_err_sif (fwrite(d, 1024, 1, fp) < 1);
u_free(d);
(void) fclose(fp);
return 0;
The exception handling branch:
err:
if (fp != NULL)
fclose(fp);
if (d != NULL)
u_free(d);
return ~0;
}
Should the execution fail in the function trunk, a number of interesting info about the failed instruction and context are automatically supplied to the syslog machinery and redirected to the appropriate sink:
Jan 15 12:27:27 tho-2 ./carp[14425]: [dbg][14425:main.c:20:f] (fp = fopen("my.txt", "w")) == ((void *)0) [errno: 13, Permission denied]
As you can see, these macros also show the nice side effect of neatly packing your code -- the LOC compression factor being nearly 1:3 compared to a properly formatted C program -- which of course increases readability and maintainability of the software, but, most of all, tries to protect the professional programmer from the nasty carpal tunnel syndrome (hence the header name carpal.h). This is no doubt a clear case in which "Go To Statement can be
Considered Benefical" -- if Dijkstra allows.
In all the macros that follow, the msg_
prefix can be substituted by any of dbg_
, info_
, notice_
, warn_
, err_
, crit_
, alert_
, emerg_
strings, and the label
argument deleted, since it is absorbed into the explicit prefix. As you may easily spot, each of these variant is in 1:1 correspondence with syslog(1)
error levels. Also, the special con_
prefix can be used to redirect the message to stderr
and nop_
to just don't log.
Defines |
#define | msg_err(label,...) do { msg(label, 0, __VA_ARGS__); goto err; } while(0) |
| Log a message and jump to the err: label.
|
#define | msg_if(label, expr) do { if( expr ) msg_noargs(label, 0, #expr); } while(0) |
| Log a message if expr is true.
|
#define | msg_ifm(label, expr,...) do { if(expr) { msg(label, 0, __VA_ARGS__); } } while(0); |
| Log the given message if expr is true.
|
#define | msg_ifb(label, expr) if( (expr) && (msg_noargs(label, 0, #expr) ? 1 : 1) ) |
| Log a message if expr is true and enter the if-block.
|
#define | msg_return_if(label, expr, err) msg_ifb(label, expr) { return err; } |
| Log a message if expr is true and return with err.
|
#define | msg_return_ifm(label, expr, err,...) if(expr) { msg(label, 0, __VA_ARGS__); return err; } |
| Log the given message if expr is true and return err .
|
#define | msg_return_sifm(label, expr, err,...) if(expr) { msg(label, errno, __VA_ARGS__); return err; } |
| Log the given message plus strerror(errno) if expr is true, and return err .
|
#define | msg_return_sif(label, expr, err) do { if(expr) { msg_noargs(label, errno, #expr); return err; } } while(0) |
| Log a message plus strerror(errno) if expr is true, and return err .
|
#define | msg_goto_if(label, expr, gt) msg_ifb(label, expr) goto gt |
| Log a message if expr is true and goto gt .
|
#define | msg_err_if(label, expr) do { msg_ifb(label, expr) { goto err;} } while(0) |
| Log a message if expr is true and goto to the label err .
|
#define | msg_err_rcif(label, expr, errcode) do { msg_ifb(label, expr) { rc = errcode; goto err;} } while(0) |
| Log a message if expr is true, set errcode and goto to the label err .
|
#define | msg_err_ifm(label, expr,...) do { if( (expr) ) { msg(label, 0, __VA_ARGS__); goto err; } } while(0) |
| Log the given message if expr is true and goto to the label err .
|
#define | msg_err_sif(label, expr) do { if(expr) { msg_noargs(label, errno, #expr); goto err; } } while(0) |
| Log a message and strerror(errno) if expr is true, then goto to the label err .
|
#define | msg_err_sifm(label, expr,...) do { if((expr)) { msg(label, errno, __VA_ARGS__); goto err; } } while(0) |
| Log the user provided message and strerror(errno) if expr is true, then goto to the label err .
|
#define | msg_strerror(label, en) |
| Write a debug message containing the message returned by strerror(errno) .
|
Define Documentation
#define msg_err |
( |
label, |
|
|
... |
|
) |
do { msg(label, 0, __VA_ARGS__); goto err; } while(0) |
Log a message of type label
and jump to err
label
For example:
if (stat(filename, &sb) == -1)
dbg_err("stat failed on file %s", filename);
Definition at line 114 of file carpal.h.
#define msg_err_if |
( |
label, |
|
|
expr |
|
) |
do { msg_ifb(label, expr) { goto err;} } while(0) |
Log a message of type label
if expr
is true and goto
to the label err
(that must be in-scope). The expr
text statement will be written to the log file.
For example:
dbg_err_if ((rc = regexec(&re, uri, 10, pmatch, 0)) != 0);
...
err:
u_dbg("no match found !");
return ~0;
Definition at line 256 of file carpal.h.
#define msg_err_ifm |
( |
label, |
|
|
expr, |
|
|
... |
|
) |
do { if( (expr) ) { msg(label, 0, __VA_ARGS__); goto err; } } while(0) |
Log a message of type label
if expr
is true and goto
to the label err
(that must be in-scope). The user-provided message is used instead of the expr
text statement.
For example:
dbg_err_ifm (cur == s, "empty IPv4address / reg-name");
...
err:
return ~0;
Definition at line 296 of file carpal.h.
#define msg_err_rcif |
( |
label, |
|
|
expr, |
|
|
errcode |
|
) |
do { msg_ifb(label, expr) { rc = errcode; goto err;} } while(0) |
Log a message of type label
if expr
is true, set variable rc
to errcode
and jump to label err
. Both rc
and err
must be in-scope. The expr
text statement will be written to the log file.
For example:
int rc = ERR_NONE;
...
dbg_err_rcif ((madp = u_zalloc(UINT_MAX)) == NULL, ERR_MEM);
...
err:
return rc;
Definition at line 277 of file carpal.h.
#define msg_err_sif |
( |
label, |
|
|
expr |
|
) |
do { if(expr) { msg_noargs(label, errno, #expr); goto err; } } while(0) |
Log a message of type label
if expr
is true and goto
to the label err
(that must be in-scope). Also logs strerror(errno)
.
For example:
dbg_err_sif ((s = u_strdup(huge_string)) == NULL);
...
err:
return ~0;
Definition at line 314 of file carpal.h.
#define msg_err_sifm |
( |
label, |
|
|
expr, |
|
|
... |
|
) |
do { if((expr)) { msg(label, errno, __VA_ARGS__); goto err; } } while(0) |
Log the user provided message of type label
if expr
is true, log strerror(errno)
and goto
to the label err
(that must be in-scope).
For example:
dbg_err_sifm ((fp = fopen(path, "r")) == NULL, "%s", path);
...
err:
return ~0;
Definition at line 332 of file carpal.h.
#define msg_goto_if |
( |
label, |
|
|
expr, |
|
|
gt |
|
) |
msg_ifb(label, expr) goto gt |
Log a message of type label
if expr
is not zero and goto
to the label gt
(that must be in-scope). The expr
text statement will be written to the log file.
For example:
again:
ad = accept(sd, addr, addrlen);
nop_goto_if (ad == -1 && errno == EINTR, again);
Definition at line 237 of file carpal.h.
#define msg_if |
( |
label, |
|
|
expr |
|
) |
do { if( expr ) msg_noargs(label, 0, #expr); } while(0) |
Log a message of type label
if expr
is true. The expr
text statement will be written to the log file.
For example:
warn_if (check(abc) < 0);
Definition at line 128 of file carpal.h.
#define msg_ifb |
( |
label, |
|
|
expr |
|
) |
if( (expr) && (msg_noargs(label, 0, #expr) ? 1 : 1) ) |
Log a message of type label
if expr
is true and enter the following if-block. The expr
text statement will be written to the log file.
A C-style code block should follow. For example:
dbg_ifb (i == 0)
{
statement;
another_statement;
}
Definition at line 160 of file carpal.h.
#define msg_ifm |
( |
label, |
|
|
expr, |
|
|
... |
|
) |
do { if(expr) { msg(label, 0, __VA_ARGS__); } } while(0); |
Log the given message of type label
if expr is true.
For example:
warn_ifm (check(abc) < 0, "check failed on file %s", filename);
Definition at line 141 of file carpal.h.
#define msg_return_if |
( |
label, |
|
|
expr, |
|
|
err |
|
) |
msg_ifb(label, expr) { return err; } |
Log a message if expr
is true and return
with err
to the caller. The expr
text statement will be written to the log file.
For example:
dbg_return_if (param1 == NULL, PRM_ERROR);
Definition at line 175 of file carpal.h.
#define msg_return_ifm |
( |
label, |
|
|
expr, |
|
|
err, |
|
|
... |
|
) |
if(expr) { msg(label, 0, __VA_ARGS__); return err; } |
Log the given message if expr
is true and return err
to the caller.
For example:
dbg_return_ifm (prm == NULL, PRM_ERROR, "param %d must be not NULL", i);
Definition at line 188 of file carpal.h.
#define msg_return_sif |
( |
label, |
|
|
expr, |
|
|
err |
|
) |
do { if(expr) { msg_noargs(label, errno, #expr); return err; } } while(0) |
Log a message plus strerror(errno)
if expr
is true, and return err
to the caller. The expr
text statement will be written to the log file.
For example:
warn_return_sif (stat(filename, &sb) == -1, ~0);
Definition at line 220 of file carpal.h.
#define msg_return_sifm |
( |
label, |
|
|
expr, |
|
|
err, |
|
|
... |
|
) |
if(expr) { msg(label, errno, __VA_ARGS__); return err; } |
Log the given message plus strerror(errno)
if expr
is true, and return err
to the caller.
For example:
dbg_return_sifm (stat(fn, &st) == -1, -1, "file %s access error", fn);
Definition at line 203 of file carpal.h.
#define msg_strerror |
( |
label, |
|
|
en |
|
) |
|
Value:do { \
enum { _DBG_BUFSZ = 256 }; \
char _eb[_DBG_BUFSZ] = { 0 }; \
if(u_strerror_r(en, _eb, _DBG_BUFSZ)) { \
msg(label, 0, "strerror_r(%d, ...) failed", en); \
} else { \
msg(label, 0, "errno: %d (%s)", errno, _eb); \
} \
} while(0)
For example:
switch (inet_pton(AF_INET6, host, &sin6->sin6_addr))
{
case -1:
dbg_strerror(errno);
...
Definition at line 364 of file carpal.h.