Chapter Contents

Previous

Next
wmi_set

wmi_set



Establish a warning message exit

Portability: SAS/C


SYNOPSIS
DESCRIPTION
RETURN VALUE
EXAMPLES
RELATED FUNCTIONS
SEE ALSO


SYNOPSIS

#include <wmi.h>

typedef enum wmi_outcome (*wmi_exittype)
            (int msgtnum, int errnoval, struct wmi_msg_info *info,
             void *arg);     /* This typedef is in wmi.h */

wmi_token wmi_set(wmi_exittype exitptr, void *arg);


DESCRIPTION

wmi_set is called to define a warning message exit. The exit will be called, with a few exceptions, whenever the library begins processing a runtime warning message. The exit may request that the message be suppressed or that it be forced to print. It may also augment the message with additional text, or request that the message be captured, which means that the lines of the message will be passed to another routine (a capture exit) for further processing such as logging. Once established, a message exit remains in effect until wmi_del is called to delete it.

The exitptr argument to wmi_set is a function pointer specifying the message exit. The arg parameter is an arbitrary pointer value (which may be NULL) that is passed to the message exit each time it is called. wmi_set returns a value of type wmi_token, which identifies this specific exit request. This value should be passed to wmi_del to delete the exit. If wmi_set fails, it returns 0.

The rules for how message exits are called are as follows:

When a message is generated, any message exits are called in the reverse order of their definition, that is, the most recently defined exit is called first. Message exits are not called in any of the following situations:

In general, a message is passed to each defined exit in turn. However, as described below, once an exit is able to completely suppress a message, the message is not passed to any other pending exits.

When a message exit is called, it is passed four parameters:

Note that errnoval may be 0, indicating an informational message that does not set errno, or it may be -1, indicating an error-level condition that will cause program termination after processing of the message is complete.

The info argument is a pointer to a structure of type wmi_msg_info, which is defined in wmi.h as follows:

struct wmi_msg_info {
   char *newtext;
   wmi_captype capture;
   void *captarg;
   enum { WMI_INFO = 1, WMI_WARN = 2, WMI_ERR = 4, WMI_HUSH = 256,
          WMI_SUPPRESSED = 512, WMI_FORCED = 1024 }
      msgtype;
   char recursion;
};

The meaning and usage of the fields of the info structure are as follows:

newtext may be set by the exit to request that text be added to the message. This can be useful for adding information such as time of day or transaction ID to the message. The maximum length of the additional text is 110 characters. If the text begins with a new line character, it is printed on a separate line after the library's description of the problem. If the text does not start with a new line, it is printed on the first message line printed by the library unless it does not fit, in which case it appears on the next line. Except for an initial new line, the new text must not contain any control characters, including new lines.

The capture field may be set by the exit to a function pointer defining a routine which is to capture the message. Each line of the message will be passed to the capture routine after other library processing of the message has completed. Note that it is possible to both suppress and capture a message. In this case, the message will not be printed by the library, but will be passed to the capture routine. If a message is captured but not suppressed, the message is both printed by the library and passed to the capture exit.

The captarg field may be set by the exit to a value of type void* to be passed to the capture routine. If a capture routine is specified but no argument is required, captarg should be set to NULL.

The msgtype field of the info structure provides additional information about the message. This field contains one or more flag bits, each of which is associated with a symbolic name. The bits and their meanings are as follows:

WMI_INFO
The message is informational, that is, it does not set errno, and the program is not informed of the associated condition.

WMI_WARN
The message is a warning message that sets errno, and after which execution will continue.

WMI_ERR
The message is an error message. After processing the message the program will be terminated.

WMI_HUSH
The message has been suppressed internally by the library. Unless an exit forces the message to be printed, it will be suppressed. Messages for which this flag is set indicate situations for which a message is not usually required.

WMI_SUPPRESSED
The message has been suppressed by the library or by another exit.

WMI_FORCED
The message has been forced to print by the library or by another exit. If both WMI_SUPPRESSED and WMI_FORCED are set, WMI_FORCED has precedence.

The recursion field is an integer which is set to either 0 or 1. If recursion is set to 1, the diagnostic message was generated during capture of a message requested by this exit. When recursion is set to 1, an exit may want to avoid capture processing to prevent infinite loops.

When a message exit has completed processing, it must return a value of type enum wmi_outcome, which specifies the disposition of the message. One of the following values must be returned:

WMI_PASS
The exit makes no change in the disposition of the message. That is, it neither suppresses it nor forces it to print. Returning WMI_PASS does not prevent either augmenting the message with additional text or capturing it.

WMI_SUPPRESS
The exit wants to suppress the message. The request may not be honored, if the library or another exit has forced processing. Note that an exit is permitted to both capture and suppress a message. If a message is suppressed by an exit, has not been forced to print, and has not been captured, the message will not be passed to any remaining exits.

WMI_FORCE
The exit wants to force the message to print.

A message exit should be careful not to generate any library diagnostics itself. To prevent infinite loops, a message exit is never called for a message which was generated while it was running. If a diagnostic message is generated, and not completely suppressed, during the execution of a message exit, the exit is terminated via longjmp, and does not complete. Because the use of longjmp with C++ is problematic, you should avoid writing message exits in C++ if there is any chance of generating a diagnostic within the exit.

Unlike message exits, capture exits are called at the end of library message processing. If a message is to be printed as well as captured, it will have been written to stderr before the capture routine is called.

A capture exit should have the following prototype:

enum wmi_capture_outcome capture_name(char *text, 
                                      struct wmi_capture_info *info,
                                      void *arg);

The text argument is a line of the message that ends with a new line character. A library message normally generates at least three lines of output, and a capture routine is called separately for each line. The arg argument contains the value specified for the captarg field of the wmi_msg_info structure by the message exit which requested capture. The info argument addresses a structure of type wmi_captype_info which contains additional information about the message and the situation, as described below.

The text passed to a capture exit for a message includes any text inserted by message exits. It does not include a traceback, even if the runtime option =btrace is specified. The capture exit can generate a traceback itself using the btrace() function if necessary. Note that normally a traceback generated from a capture exit will be the same as one at the time the message was generated, but it can be different for messages which are generated by a message exit routine.

It is possible that a capture exit might itself generate a diagnostic. For instance, if a capture exit's purpose is to keep a log of messages, the log might fill up, or suffer an output error. Because of the timing of calls to capture exits, the library can be more tolerant of messages generated there than of ones from message exits. For a message generated from a capture exit, when a message exit is called, the exit's recursion flag is set, which allows the exit to choose not to capture this message. However, even if the exit chooses to capture this message, the message is placed on a capture queue rather than causing a recursive call to the capture routine. This allows the capture exit to possibly recover from the condition and process the recursive message normally.

To allow a capture exit to deal with having generated a message itself, the wmi_capture_info structure passed to the exit contains a field named recursion. The field is initialized to zero. If a diagnostic is generated from the capture exit, and is not completely suppressed, the recursion flag is set to 1. This allows the capture exit to be aware of the situation. Whether or not the recursion flag has been set changes the effect of some of the return values from a capture exit. This is intended to protect the library from problems caused by capture exits which do not test for recursions.

When a capture exit has completed processing, there are three basic actions it can request. It can inform its caller that it has failed, in which case no more lines of this message will be captured. It can inform its caller that it was successful, in which case it wil be called again for each remaining line of the message. Finally, it can request a restart from its caller. In this case, it is called again for each line of the message, starting with the first line. This is useful if, for instance, due to an error, a capture exit opens a new log file, and wants all lines of the message to appear in that file.

The mapping of the wmi_capture_info structure addressed by the info argument to the capture exit is as follows:

struct wmi_capture_info {
   unsigned char recursion;
   unsigned char recovering;
   unsigned char fatal;
};

The recursion flag is zero on entry to the capture exit, but is set to 1 if an unsuppressed diagnostic message is generated while the capture exit is executing. The recovering flag indicates whether or not the previous call to the exit for this message generated a recursive diagnostic, 0 for the normal case, or 1 where the previous call generated a diagnostic. The recovering flag can allow an exit to detect cases where it is generating warnings repeatedly, and avoid looping in this situation. The fatal flag is used to indicate whether the current message represents a fatal error, after which program execution will terminate. If the capture routine generates a diagnostic processing a fatal error, further capture processing may be bypassed to avoid the possibility of further errors.

A capture exit must return to its caller a value of type enum wmi_capture_outcome. One of the following four symbolic values must be returned:

WMIC_FAIL
indicates that the capture exit has failed. No further lines of this message will be captured.

WMIC_OK
indicates the capture exit has succeeded. If WMIC_OK is returned when the recursion flag has been set, the return value is treated as WMIC_FAIL.

WMIC_RECOVER
indicates that, although a diagnostic was generated from the capture exit, the problem has been recovered, and capture processing for this message should continue. If WMIC_RECOVER is returned and the recursion flag has not been set, the return value is treated as WMIC_FAIL.

WMIC_RESTART
requests that processing of this message resume with the first line of the message. WMIC_RESTART may be returned whether or not the recursion flag is set.

Note:   Although the library attempts to prevent infinite loops in exit processing, they can still occur. Some caution is recommended in dealing with problems which occur in message or capture exits to prevent loops from taking place.  [cautionend]


RETURN VALUE

wmi_add returns a token which represents the exit request. The token can be passed to wmi_del to delete the exit. wmi_add returns a zero token to indicate that the exit could not be defined.


EXAMPLES

This example shows how to define a message exit to add the date and time of day to each library diagnostic.

Note:   In this example the buffer containing the message must be static or external. If the buffer is defined as auto, the memory for the text will be deallocated when the exit returns to its caller, with unpredictable results.  [cautionend]

#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <wmi.h>

static enum wmi_outcome time_exit(int, int, struct wmi_msg_info *, void *);

   main() {
      wmi_token time_exit_token;

      time_exit_token = wmi_set(&time_exit, NULL);
      assert(time_exit_token != 0);
      /* perform main program processing */
      wmi_del(time_exit_token);
      exit(0);
   }

   static enum wim_outcome time_exit(
      int msgnum,
      int errnoval,
      struct wmi_msg_info *info,
      void *arg)
   {
      static char timebuf[111];
      time_t now;
      int result;

      time(&now);
      result = strftime(timebuf, 111, "Date=%d%b%Y Time=%H:%M:%S",
                        localtime(&now));
      if (result > 0)
         info->newtext = timebuf;
      return WMI_PASS;
   }

The next example shows how to use a message exit to capture message lines and write them to a log file. If an error occurs writing to the log, a new log file is opened. Most of the management of the log file is encapsulated as subroutines.

The following example assumes that if a message is generated in the write_to_log() function, but the function does not indicate an error, then the message did not indicate a significant problem. Whether this is a reasonable assumption or not would depend on the code in write_to_log.

#include <stdio.h>
#include <assert.h>
#include <wmi.h>

static enum wmi_outcome msgexit(int, int, struct wmi_msg_info *, void *);
static enum wmi_capture_outcome capture_line(char *, 
                                             struct wmi_capture_info *,
                                             void *);

FILE *logfile;

   main() {
      wmi_token token;

      open_log_file();
      token = wmi_set(&msgexit, NULL);
      assert(token != 0);
      /* perform main program processing */
      wmi_del(token);
      exit(0);
   }

   static enum wmi_outcome msgexit(
      int msgnum,
      int errnoval,
      struct wmi_msg_info *info,
      void * arg)
   {
      if (info->recursion)
         return WMI_PASS;      /* don't capture msg from exit */
      if (info->msgtype & WMI_HUSH)
         return WMI_PASS;      /* don't capture insiginificant messages */
      info->capture = &capture_line;
      info->captarg = 0;
      if (info->msgtype & WMI_ERR) return WMI_PASS;
      else WMI_SUPPRESS;   /* don't print message unless fatal */
   }

   static enum wmi_capture_outcome capture_line(
      char *text,
      struct wmi_capture_info *info,
      void *arg)
   {
      int error_flag;
      int restart = 0;

      error_flag = write_to_log(text);
      if (error_flag != 0) {
         /* don't try to recover in perilous situations */
         if (info->recovering || info->fatal) 
            return WMIC_FAIL;
         error_flag = open_new_log();
         /* give up if we can't open a good log file */
         if (error_flag != 0)
            return WMIC_FAIL;
         else restart = 1;
      }
      if (restart) return WMIC_RESTART;
      else if (info->recursion) return WMIC_RECOVER;
      else return WMIC_OK;
   }

See the examples for the wmifilte and wmifiltn functions, which are generalized exit functions that can be used to suppress specific library messages, for more information.


RELATED FUNCTIONS

wmi_del, wmifilte, wmifiltn, quiet, longjmp


SEE ALSO

"Diagnostic Control Functions" in Chapter 2, "Function Categories."


Chapter Contents

Previous

Next

Top of Page

Copyright © 2004 by SAS Institute Inc., Cary, NC, USA. All rights reserved.