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)
    {
        // local variables initialization
        char *d = NULL;
        FILE *fp = NULL;

The trunk:

        // malloc a 1024 bytes 0-filled chunk
        dbg_err_sif ((d = u_zalloc(1024)) == NULL);

        // open "my.txt" for writing
        dbg_err_sif ((fp = fopen("my.txt", "w")) == NULL);

        // write to file
        dbg_err_sif (fwrite(d, 1024, 1, fp) < 1);

        // free memory and close the file stream 
        u_free(d);
        (void) fclose(fp);

        return 0;

The exception handling branch:

    err:
        // invoke local resource dtors only in case they have been
        // allocated in the trunk and tell the caller that we have failed
        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:

      // return with PRM_ERROR if input parameter validation fails
      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:

      // return with ~0 and log errno returned by stat(2)
      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);
              // fall through
      ...

Definition at line 364 of file carpal.h.


←Products
© 2005-2012 - KoanLogic S.r.l. - All rights reserved