Chapter Contents |
Previous |
Next |
wmi_set |
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:
quiet
function, or previous failures in message
processing
indicate possible damage to the C environment.
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:
msgnum
)
errnoval
)
arg
)
info
)
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
errno
, and the program is not informed of the associated
condition.
WMI_WARN
errno
, and after which execution will
continue.
WMI_ERR
WMI_HUSH
WMI_SUPPRESSED
WMI_FORCED
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
WMI_PASS
does not prevent either augmenting the message with
additional text or capturing it.
WMI_SUPPRESS
WMI_FORCE
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
WMIC_OK
WMIC_OK
is returned when the recursion flag has been set,
the return value is treated as WMIC_FAIL
.
WMIC_RECOVER
WMIC_RECOVER
is returned and the recursion flag has not been set, the return value is treated
as WMIC_FAIL
.
WMIC_RESTART
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.
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.
#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.