10. Msgno

The msgno(3m) module provides a set of macros that when used consistently will generate stacktrace-like output like the following example:

  src/expatls.c:97:utf8tods: Character encoding error
    src/expatls.c:449:start_fn: 
    src/dom.c:405:DOM_Element_normalize: 
    dump.c:30:main: Failed to process sample.xml
  

Note: As of version 0.9, this implementation no longer uses variadic macros -- it is strict standard C.

Additionally this module provides functions for managing error codes (or more generically message numbers) and associated messages across separate C libraries. This functionality is very similar to the com_err library but with runtime message registration. Each participating library registers a table of messages at runtime with the msgno_add_codes function. The msgno(3m) macros are provided to dispatch messages (e.g. print to stderr).

Note: The msgno(3m) macros operate on a shared buffer and therefore they are not reentrant. Meaning they cannot not be used concurrently by multiple threads.

10.1. MMSG, MMNO, MMNF, PMSG, PMNO, PMNF, AMSG, AMNO, AMNF

The nine msgno macros are used to initiate, append, and finally dispatch messages and formatted output to a user defined handler (the default is stderr).

The 9 Msgno Macros
Synopsis


#include <mba/msgno.h> MMSG(fmt, ...) MMNO(msgno) MMNF(msgno, fmt, ...) /* Primary */ PMSG(fmt, ...) PMNO(msgno) PMNF(msgno, fmt, ...) /* Additional */ AMSG(fmt, ...) AMNO(msgno) AMNF(msgno, fmt, ...) extern int (*msgno_hdlr)(const char *fmt, ...); struct msgno_entry { unsigned int msgno; const char *msg; };
Description
The Primary and Additional macros (begin with P and A) do not dispatch messages to the msgno_hdlr but instead write to a global buffer. The MMSG, MMNO, or MMNF macros will dispatch messages to the msgno_hdlr in addition to any Primary and Additional messages in the global buffer. The general flow should be to use a Primary macro to initiate a new buffered message, then use the Additional macros to append messages, and finally trigger the entire stack-trace-like message to be dispatched to the msgno_hdlr with a MMSG, MMNO, or MMNF macro.
Table 1.
Formatted StringMessage NumberMessage Number and Formatted String
Primary message at the beginning of the message buffer PMSG - The primary message macro writes formated printf like string to the beginning of the message buffer PMNO - The primary message number macro accepts just a message number and writes the associated message the to the beginning of the message buffer PMNF - The primary message number format macro accepts a message number and a formatted printf like string and writes both the message associated with the message number and the formatted output to the beginning of the message buffer
Additional message appended to the message buffer AMSG - The additional message macro appends a formated printf like string to the message buffer AMNO - The additional message number macro accepts just a message number and appends the associated message the to the message buffer AMNF - The additional message number format macro accepts a message number and a formatted printf like string and appends both the message associated with the message number and the formatted output to the message buffer
Dispatched immediatedly to msgno_hdlr MMSG - The message macro writes a formatted string to the registered msgno_hdlr MMNO - THe message number macro writes the message associated with the provided number to the msgno_hdlr MMNF - The message number format macro writes both the message associated with the message number and a formatted printf like string to the msgno_hdlr.

The msgno macros are designed to be the least intrusive way to place debugging information within C source code. The following is an example of how and where these macros might be used to generate the example stack-trace-like output listed above.

  if ((n = dec_mbsncpy(&s, sn, NULL, -1, -1, "UTF-8")) == (size_t)-1) {
  	PMNO(DOM_Exception = DOM_CHARACTER_ENC_ERR);
  	return -1;
  }
  ...
  if (utf8tods(atts[i], -1, ud) == (size_t)-1) {
  	AMSG("");
  	return;
  }
  ...
  if (DOM_DocumentLS_load(doc, argv[1]) == -1 ||
  		DOM_DocumentLS_fwrite(doc, stdout) == -1) {
  	MMSG("Failed to process %s", argv[1]);
  	return EXIT_FAILURE;
  }
  

10.2. Message management functions

The msgno_add_codes function
Synopsis

#include <mba/msgno.h> int msgno_add_codes(struct msgno_entry *list);
Description
The mnsgo_add_codes function registers an array of msgno_entry structures. The array must contain at least one element and the msg member of the last element must be NULL. Each msgno value must be greater than the previous value. Values will be created at runtime if not provided (e.g. all 0s becomes 0,1,2,3,..). Create macros for each message value by referencing the msgno member like the following:

  #define DOM_INDEX_SIZE_ERR              dom_codes[0].msgno
  #define DOM_DOMSTRING_SIZE_ERR          dom_codes[1].msgno
  
  struct msgno_entry dom_codes[] = {      
      { 1, "The index specified was out of range" },
      { 0, "The text size is out of range" },
      ...
      { 0, NULL }
  };
  
Returns
The msgno_add_codes function returns 0 if the operation was successful. Otherwise -1 is returned and errno is set appropriately.

The msgno_msg function
Synopsis

#include <mba/msgno.h> const char *msgno_msg(unsigned int msgno);
Description
The msgno_msg function returns the message associated with the msgno parameters that have previously been registered with msgno_add_codes. If no such message has been registered, then the message "No such msgno list" or "No such message in msgno list" is returned.

The msgno_hdlr_stderr function
Synopsis

#include <mba/msgno.h> int msgno_hdlr_stderr(const char *fmt, ...);
Description
The msgno_hdlr_stderr function writes msgno messages to stderr. It is the default msgno message handler. The msgno message handler may be changed by reassigning a new function that matches the signature to the msgno_hdlr function pointer.

Tip: If you are working on a Microsoft Windows MFC application, create a msgno_hdlr function like the one below that calls AfxMessageBox and set it to msgno_hdlr in InitInstance. This will permit your MFC application to report errors generated from within libmba.

  static int
  MessageBoxHdlr(const char *fmt, ...)
  {
  	char mbs[4096];
  	wchar_t wcs[4096];
  	va_list ap;
  	va_start(ap, fmt);
  
  	_vsnprintf(mbs, 4096, fmt, ap);
  	if (mbstowcs(wcs, mbs, 4096) != (size_t)-1) {
  		AfxMessageBox(wcs);
  	}
  
  	va_end(ap);
  	return 0;
  }
  BOOL CWutApp::InitInstance()
  {
  	...
  	msgno_hdlr = MessageBoxHdlr;
  
Returns
The msgno_hdlr_stderr function (i.e. the msgno_hdlr function) returns the number of characters printed to stderr.


Copyright 2002 Michael B. Allen <mba2000 ioplex.com>