msgOut
msgOut
The most obvious way of producing informational messages from within Fortran or C application
programs is through formatted printf
, WRITE
and PRINT
statements. However:
These considerations have led to the design and implementation of a set of subroutines which form the Message Reporting System. The Message System subroutines have names of the form
where name indicates what the subroutine does and follows the standard Starlink naming convention for C and Fortran. This document will provide examples in both languages, but subroutine names in the text will use the C naming convention.
The primary message reporting subroutine is msgOut
. It has a calling sequence of the form:
where the argument param is a character string giving the name of the message, text is a character
string giving the message text, and status is the integer subroutine status value (a pointer to an int in
C). msgOut
sends the message string, text, to the standard output stream which will normally be the
user’s terminal.
The subroutine msgOut
uses the Starlink convention of inherited status. This means that
calls to msgOut
will not output the message unless the given value of status is equal to
SAI__OK
. If an error is encountered within the subroutine, then status is returned set to an error
value. (The global constant SAI__OK
is defined in the include file sae_par.h (SAE_PAR for
Fortran). The use of this global constant and of inherited status are discussed in detail in
§3.2.)
The maximum length for an output message is 300 characters. If it exceeds this length, then the message is truncated with an ellipsis, i.e. “…”, but no error will result.
By default, messages are split so that output lines do not exceed 79 characters – the split is made on word boundaries if possible. The maximum output line size can be altered using tuning parameters (see §4).
It is recommended that, within the application, the message name, param, should be a unique identifier for the message string, text. However, the message name serves no useful purpose within a stand-alone application and is often given as a blank string. In ADAM applications the message name has a specific purpose which is discussed in detail in Appendix E.2.
Here is an example of using msgOut
:
msgOut
, e.g. For convenience, the subroutine msgBlank
has been provided for this purpose, e.g. The status argument in msgBlank
behaves in the same way as the status argument in
msgOut
.
It is sometimes useful to have varying levels of message output which may be controlled by the user of an application. Instances where this facility might be of use are:
Conditional message output is achieved explicitly in the Message Reporting System using the
subroutine msgOutif
to assign a “priority” to the message, e.g.
MSG__QUIET
MSG__NORM
MSG__VERB
MSG__DEBUG
MSG__DEBUGnn
Whether or not the message will be output depends upon the “conditional message output filter”
which may be set using the subroutine msgIfset
. e.g.
msgIfset
is the required conditional output filter level – it may take the same
values as the message priority with the addition of MSG__NONE
and MSG__ALL
; by default it is set to
MSG__NORM
. The current conditional output filtering level may be inquired using subroutine
msgIflev
or compared against using msgFlevok
. MSG__NONE
and MSG__ALL
allow every message to be
hidden or all messages to be displayed respectively. These levels can not be used with
msgOutif
.
See also msgTune
and msgIfgetenv
that allows the filter level to be set by an environment variable,
and msgIfget
which allows ADAM programs to obtain the filter level from an ADAM
parameter.
The action of msgOutif
resulting from each of the defined priority values is as follows:
MSG__QUIET
MSG__NONE
;
MSG__NORM
MSG__NORM
, MSG__VERB
, MSG__DEBUG
(and related constants) or MSG__ALL
;
MSG__VERB
MSG__VERB
, MSG__DEBUG
(and related constants) or MSG__ALL
.
MSG__DEBUG
MSG__DEBUG
(and related constants) or MSG__ALL
.
In this scheme, messages given the priority MSG__QUIET
the most important messages being
output by an application and can only be turned off if the user is forcing all output to be
disabled.
Here is an example of how conditional message output might be used in an application using interactive graphics with differing levels of informational messages to match how familiar the user is with the application:
The msgBlankif
function works in much the same way as msgOutif
to allow a blank line to be output
conditionally.
The MSG__NONE
and MSG__ALL
levels cannot be used with msgBlankif
.
msgOut
Although conditional message reporting may be handled explicitly by calling msgOutif
, calls to
msgOut
and msgBlank
also have conditional message reporting built in. Their output has priority
MSG__NORM
associated with it and will therefore only be output when the conditional output filter is
set to MSG__NORM
(the default), MSG__VERB
or greater.
In the previous examples of msgOut
and msgOutif
, the message text is “constant” in the sense that it
does not refer to any variable items, e.g. file names or numeric values. However, very often,
applications need to include the values of variables within output messages. This is done
in the Message System using tokens embedded within the message text. For example, a
program which measures the intensity of an emission line in a spectrum can output its result
by:
Here, the subroutine msgSetr
is called to define a token named “FLUX” and assign to it the
value of the REAL
or float
variable FLUX encoded as a character string. The token name,
immediately preceded by the up-arrow, “^
”, escape character is then included in the given message
text. As the given text is processed, the token is expanded to the string assigned to the
token.
For example, If the variable FLUX in this example has the value 2.4, then the message output to the terminal would be:
There is a set of msgSet
x subroutines, one subroutine for each of five standard Fortran 77 data types
(the Fortran type COMPLEX has not been provided for). Here, x corresponds to the Fortran data type
of the value to be assigned to the named message token:
x | Fortran Type |
d | DOUBLE PRECISION |
r | REAL |
i | INTEGER |
l | LOGICAL |
c | CHARACTER |
In each case, the calling sequence is of the form:
where token is a character string giving the name chosen by the user and value is a variable or constant
of the appropriate type. The numeric subroutines, msgSetd
, msgSetr
, and msgSeti
, adopt the most
concise format that will represent the value by removing trailing zeros, leading and trailing blanks,
and by avoiding the use of exponential notation unless it is necessary. msgSetl
uses TRUE
or FALSE
according to the value it is given. msgSetc
removes trailing blanks from the character string; leading
blanks are not removed.
An additional feature of the msgSet
x routines is that calls to these routines using an existing token will
result in the value being appended to the previously assigned token string. Here is the previous
example written to exploit this feature of the msgSet
x routines:
where the CHARACTER variable funits has been assigned the value of an appropriate unit of flux
(e.g. erg/cm2/A/s) earlier in the program. Note that repeated calls to the msgSet
x routines will
append values to the token string with no separator, hence a leading space in the funits string is
needed to separate the flux value and its units in the expanded message.
The text string associated with a message token (i.e. the token value) may be up to 200 characters long. Token names may be up to 15 characters long and should be valid names: i.e. they should begin with an alphabetic character and continue with alphanumeric or underscore characters. A maximum of 64 uniquely named message tokens may be included in any output message.
No message tokens are defined initially and after each call to msgOut
, msgOutif
or msgLoad
(or a
corresponding ERR routine, see §3.4) all existing tokens are left undefined.
The msgSet
x functions encode numeric values in the most concise format that will describe the
supplied value. Sometimes, however, a specific format is required; for example, the message may form
part of a table. More precise control can be obtained by using the msgFmt
function to provide all the
standard sprintf() formats available from the standard C library.
and the previous example could be written as:
There is no restriction on the number of formats that can be included in a single call so the above example can be simplified further:
The Fortran MSG_SET
x subroutines encode numeric values in the most concise format that will describe
the supplied value. This is normally what is wanted for a simple message. The Fortran
interface provides an API similar to that for the C library but using standard Fortran format
conventions.
More precise numeric formats could be achieved using the Fortran WRITE
statement with the Message
System, e.g.
which would produce the message:
In this case, the first call to MSG_SETC
assigns the supplied character string VALUE to the named token
“FLUX”.
Since this sequence of a formatted internal WRITE
followed by a call to MSG_SETC
is of general use, it is
provided in a set of subroutines of the form:
where FORMAT is a valid Fortran 77 format string which can be used to encode the supplied value,
VALUE. As for MSG_SET
x, x corresponds to one of the five standard Fortran data types – D, R, I, L and
C.
Using MSG_FMT
x, the example given above can be performed by:
The use of the MSG_FMT
x routines along with their ability to append values of any type to
existing tokens is a very powerful tool for constructing tabular output from applications
software.
msgOut
The C interface provides variants to the standard msgOut
and msgOutif
functions that can handle
sprintf() style format strings. This can lead to a significant reduction in the number of lines spent
setting up tokens by embedding the formatting directly in the required string. The example from the
previous section can simply be written as:
msgOutf
and msgOutiff
act like printf()
whereas msgOutifv
is a variant of msgOutif
that takes a va_list argument
rather than variadic ””
arguments. The “%” character is special in this context and the ADAM definition (See Appendix E.2.2)
is not available. A literal “%” is obtained by doubling up the symbol (“%%”) as would be used in
printf()
and described in the next section.
Sometimes it is necessary to include the message token escape character, “^
”, literally in a message.
When the message token escape character is immediately followed by a blank space, or is at the end of
the msgOut
text, it is included literally. If this is not the case, then it can be included literally by
duplicating it. So, for example:
would produce the message:
Escape characters and token names will also be output literally if they appear within the value assigned to a message token; i.e. message token substitution is not recursive. This means that if the message system is to be used to output the value of a character variable, the contents of which are unknown and may therefore include escape characters, the value should first be assigned to a message token. Thus,
will output the contents of VALUE literally, whereas
might not produce the desired result. This consideration is particularly important when outputting text values such as file names within the ADAM environment, where a number of additional escape characters are defined (see Appendix E.2).
It may sometimes be convenient within an application to write the text of a message, complete with
decoded message tokens, to a character variable instead of the standard output stream.
The Message System provides subroutine msgLoad
to do this. msgLoad
has the calling
sequence:
Here, the arguments param, text and status are identical to those for msgOut
. The behaviour of
msgLoad
is also the same as msgOut
except that, instead of sending the expanded message text to the
standard output stream, msgLoad
returns it in the character variable optstr (regardless the output
filtering level). oplen returns the length of the message in opstr. If the message text is longer than the
declared length of opstr (as specified in opstr_len in the C interface), then the message is truncated with
an ellipsis, i.e. “…”, but no error results.
The symbolic constant MSG__SZMSG
is provided for defining the length of character variables which
are to hold such messages. This constant is defined in the include files msg_par.h and MSG_PAR (see
§6).
Each call to msgOut
, msgOutif
or msgLoad
will annul any defined message tokens, regardless of the
success of the call. This feature of the Message Reporting System ensures that message token names
can be re-used with safety in a series of calls to, say, msgOut
(e.g. in order to output a table of values
line by line). However, under certain circumstances it is useful to be able to restore, or renew, the
values of any message tokens set prior to the call to the output routine. This can be done using the
subroutine msgRenew
. In order to be effective, msgRenew
must be called after the call which annulled
the required message tokens and prior to any further message token definitions (e.g. using the
msgSet
x and MSG_FMT
x routines). If msgRenew
is called with existing message tokens defined, no action
is taken.
Here is a Fortran example of the use of msgRenew
where a table of values is being output to the user
and to a log file:
Other than msgOut
, msgOutif
, msgBlank
, msgBlankif
and msgLoad
, the Message System
subroutines do not use a status argument. This is because they are intended to be very
robust. In order to construct a message for output to the user, they will attempt to recover
from any internal failure. The STATUS argument in the “output” routines conforms to the
Starlink convention for inherited status (see §3.2). This means that an application can contain
sequences of msgSet
x, MSG_FMT
x and msgOut
calls, and only needs to check the status at the
end.
There are two kinds of “failure” that can occur within the Message System:
If the token “FLUX” is not defined, then this call will produce the text:
There are several reasons why a token may be undefined:
msgSet
x etc.
msgOut
, msgOutif
or msgLoad
(or a
corresponding ERR routine).
MSG_FMT
x subroutines. This error could
be either a syntax error in the FORMAT argument, or the result of specifying a field
width which is too small (referred to as an “output conversion error” in Fortran).Errors in message construction which result from undefined tokens are not considered fatal and STATUS is not set as a result.
msgOut
, msgOutif
, msgBlank
or msgBlankif
attempt
to output the message, then the STATUS argument will be set to an error value and an error
message will be reported (see §3.4). Errors writing the message text to the standard output
stream may occur for a number of reasons – the seriousness of such an error is dependent upon
where the message was intended to go: