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.