SUBSYSTEM OVERVIEW

Message Processing Manager (MPM) Subsystem

The MPM subsystem is responsible for all message output to the screen and log files. All messages are issued using a unique ID generated by the message table compiler. Multiple messages may be combined to form one. Errors are a special class of message with an associated severity level. In addition, errors may be added to a stack instead of being issued immediately.

TABLE FORMAT

Message tables are stored in ASCII files which must be compiled before use. The format of the ASCII table is as follows:

SUBSYSTEM [subsystem ID] [subsystem number];
INCLUDE "[include file]"
[message ID];
[message ID] EXCEPTION = [exc ID]
   "[message text]"
   DESC = "[message text]";
   
[message ID] EXCEPTION = [exc ID]
   BRIEF = "[message text]"
   VERBOSE = "[message text]";
   DESC = "[message text]";

The SUBSYSTEM keyword must be present followed by the subsystem ID which represents the designation of the subsystem. This is followed by the subsystem number which is a unique number for that subsystem. The subsystem number must be terminated with a semicolon.

The INCLUDE keyword is optional and specifies an external file to include in the message table.

The messages are defined by a message ID followed by an optional exception ID to raise if this message is issued or set as an error. There are two formats for the message text, brief and verbose. If a brief message is not specified, the default is verbose. In all formats the message text may contain optional C control parameters and user defined specifiers (see mpm_SetFmtSpec). The message text must be enclosed in double quotes and may span more than one line. If multiple lines are used, the resulting text will be concantenated. The new line character may be used to specify hard breaks in the text. The message should end with a newline if a blank line is required after the message. The optional description may be used to further explain the message.

The message table compiler will automatically generate [subsystem]_NOERR for the subsystem.

A sample message table appears below:

SUBSYSTEM mtc 123;
INCLUDE "mtc.mh"
notext;
oneline
   "This is one line.\n";
twolines
   "This is line one.\nThis is line two.\n";
variables
   "This message has an integer %d, "
   "a float %f, and a string %s.\n";
form
   "This is line one of the form\n"
   "This is line two of the form\n"
   "%<MoreLines>\n"
   "This is line n of the form\n";
error EXCEPTION = MTC_ERROR
   BRIEF =
   "This is the brief message"
   VERBOSE =
   "This represents the verbose format of the message";

STATIC TABLE

Once an ASCII message table has been compiled (see mtc), the header file [subsystem]__MsgTbl.h and a call to the function pdx_SetTable ([subsystem]) must be included in the subsystem initialization routine. This loads the subsystem static message table into the master message table. To reference a message ID the [subsystem]__Message.h header file must be included in the source file.

#include "app__MsgTbl.h"
main ()
{
   pdx_Initialize (PDX_NOOPT);
   pdx_SetTable (app);
   return (APP_NOERR);
}

MESSAGES

Any message may be issued with the mpm_IssueMessage function. The mpm_GetMessage function will return a text string corresponding to a specified message ID. The function mpm_ParseToken is provided to extract the tokens from a token argument list. The message id (i.e. the #define) in the form of a text string may be obtained using the mpm_GetMsgName function.

ERRORS

Errors are either issued immediately with the mpm_IssueError function or added to an error stack with the mpm_SetError function. Whether an error is set or issued, an associated severity level of MPM_INFO, MPM_STATUS, MPM_WARNING, MPM_ERROR, or MPM_FATAL must be specified. The error stack may be dumped or cleared at any time with the mpm_DumpStack and mpm_ClearStack functions respectively. Two functions are available to obtain information about the last error; mpm_LastError to get the last error and mpm_GetLastErrorLevel to get the last error level. The routine mpm_GetErrorLevelCount will return the number of errors issued and set for each severity level. The routine mpm_CycleErrorCount will return the number of times each individual error was issued and set. The routine mpm_ClearError will initialize all the internal error processing variables. The maximum number of errors output may be controlled by both mpm_SetMaxError and mpm_SetMaxErrorLevel.

OPTIONS

Any option or combination of options may be set on a specific mpm call and will be in effect for that call only. To globally set an option use the mpm_SetOption function. To clear an option use the mpm_ClearOption function. The following options are avaiable:

MPM_NONEWLINE  do not send newline at end of message
MPM_NOFORMAT   do not format arguments into message
MPM_BRIEF      use the brief message instead of verbose
MPM_NOSTD      do not send message to output function
MPM_NOLOG      do not send message to log file
MPM_TOKEN      process the arguments as tokens of the
               type MPM_TOKTEXT, MPM_TOKARGS, MPM_TOKAP,
               MPM_TOKFILELINE, MPM_TOKSTREAM
MPM_NOSTACK    do not create error stack
MPM_NODUMP     do not dump the stack
MPM_NOBANNER   do not put banner on message
MPM_STACK      dump all the stack entries
MPM_FIRST      dump the first stack entry
MPM_LAST       dump the last stack entry
MPM_LONG_MSG   if the variable arg and message can
               be larger than MPM_MAXLENGTH
MPM_NOCOUNT    do not count message in error summary

NOTE: if both MPM_NOSTD and MPM_NOLOG are set the message will go to output function.

LOG FILE

A log file may be opened with mpm_OpenLog and closed with mpm_CloseLog. Once a log file is open all messages will be directed to the log in addition to the output function.

CONTROL PARAMETERS

Several format parameters are controlled within the message processor. The default output function is fputs with all messages going to stdout and all errors going to stderr. An alternate output function may be specified with the mpm_SetOutput routine. The line jusitification may be set with the mpm_SetJustify function to left (default) , right or center justification. The left margin may be specified with the mpm_SetLeftMargin to any valid value (default is 0). Likewise, the right margin may be specified with the mpm_SetRightMargin (default is 0). The line width may be specified with the mpm_SetLineWidth function (default is 80). The actual text width is defined by the line width minus the left and right margins. If the length of a line exceeds the max text width, the line will be divided into intelligent segments by looking for white space.

FORMAT SPECIFICATIONS

The text of a message may contain standard C format specifications and user defined format specifications. The user defined format specifications must be enclosed in <angle brackets>. To associate a format specification with a function use the mpm_SetFmtSpec routine. Whenever a user defined format specification is encountered within message text, the corresponding function is invoked. The user defined format specification may be cleared with the mpm_ClearFmtSpec function. The syntax of a user defined format specification is %[flags][width].[precision][qualifier]<spec>.

----------------------------------------
SUBSYSTEM app 123;
ITOA
   "%d";
DAYS
   "The date %02d/%02d/%4d is %<Days> "
   "from January 1st.\n";
----------------------------------------
#include "app__Message.h"
PDX_MSGT app_FormatDays (long option,
                         MPM_FMT *fmt,
                         va_list *ap)
/* 
Input
   option            not used
   fmt->flags        '-', '+', ' ', '#', '\0'
   fmt->n_flags      number of flags
   fmt->width        numeric value
   fmt->precision    numeric value
   fmt->qualifier    'l', 'L", '\0'
   fmt->spec         character string
   fmt->spec_len     number of characters in spec
   ap                arguments
      
Output
   fmt->text         character string (allocated)
*/
{
   int mm,dd,yyyy,days,i;
   int count[12] = {31,
                    28,
                    31,
                    30,
                    31,
                    30,
                    31,
                    31,
                    30,
                    31,
                    30,
                    31};
   
/* get the arguments */
   mm = va_arg (*ap,int);
   dd = va_arg (*ap,int);
   yyyy = va_arg (*ap,int);
/* calculate days */
   if (yyyy % 4 == 0)
      count[1] ++;
   days = 0;
   for (i=1;i<mm;i++)
      days += count[i-1];
   days += dd;
/* format days to string */
   mpm_GetMessage (MPM_NOOPT,
                   APP_ITOA,
                   &(fmt-text),
                   days);
   return (MPM_NOERR);
}
main ()
{
   pdx_Initialize (PDX_NOOPT);
   mpm_SetFmtSpec ("Days",
                   app_FormatDays);
   mpm_IssueMessage (MPM_NOOPT,
                     APP_DAYS,
                     4,16,1992);
}

ARGUMENT ORDER

Any standard or user defined format specification may contain an optional argument number. If used, all format specifications defined within the message must have an argument number. The syntax for specifying an argument number is %n$fmt where n is the argument number to use for this format specifcation.

EXCEPTIONS

Messages may have an associated exception to raise when the message is used as an error. To set a function to implicitly call when this error is issued, the routine mpm_SetException must be called before the error is issued. In addition to associated exceptions, every error issued or set will raise an exception for the severity level (MPM_INFO, MPM_STATUS, MPM_WARNING, MPM_ERROR, MPM_FATAL). Also, any exception may be raised with the mpm_RaiseException function or cleared with the mpm_ClearException function.

----------------------------------
SUBSYSTEM app 123;
NOMEMORY;
   "Out of memory.\n";
   
NOENTITY EXCEPTION = APP_NOMEMORY
   "Could not create entity.\n";
NOARRAY EXCEPTION = APP_NOMEMORY
   "Could not create array.\n";
----------------------------------
#include "app__Message.h"
PDX_MSGT app_NoMemory (PDX_MSGT exc, PDX_MSGT message)
{
   mpm_IssueMessage (MPM_NOOPT,
                     exc);
   exit (2);
}
main ()
{
   void *entity,*array;
   pdx_Initialize (PDX_NOOPT);
   mpm_SetException (APP_NOMEMORY,
                     app_NoMemory);
   entity = malloc (1000000);
   if (entity == NULL)
      mpm_IssueError (MPM_NOOPT,
                      APP_NOENTITY,
                      MPM_ERROR);
   array = malloc (1000000);
   if (array == NULL)
      mpm_IssueError (MPM_NOOPT,
                      APP_NOARRAY,
                      MPM_ERROR);
}

BINARY TABLE

A binary message table may be opened with mpm_OpenTable and closed with mpm_CloseTable. A static message table must have been set with the pdx_SetTable function to use the binary table. The table must have been generated with the -B switch on the message table compiler. Once a table has been opened all message text will be extracted from the binary file. If a message is not found in the table the default static message will be used.

MULTI-LANGUAGE

The message processor has the capability of supporting multiple languages through the binary file. It is assumed that a default language will be used as the static table. All ASCII message tables will have to be converted to a specified language and compiled into one binary table. Only the quoted text must be converted, all keywords and identifiers must remain in English. Format specifications must not be altered except to reorder the arguments. Control characters and escape sequences must not be changed unless replaced with appropriate characters.

English
---------------------------------------
SUBSYSTEM app 123;
TODAY
   "Today's date is %02d/%02d/%4d\n";
---------------------------------------
Dutch
---------------------------------------
SUBSYSTEM app 123;
TODAY
   "Vandag is %2$02d.%1$02d.%3$4d\n";
---------------------------------------

Notice the Dutch translation required the month and day arguments to be reversed. This is accomplised with the argument number specified in the format specification (i.e. %2$0d is the second argument). The code that uses this message does not have to be recompiled since the message processor interprets the arguments correctly. The ASCII message table must be compiled into the appropriate binary table and opened with the mpm_OpenTable function to get the translated message.