The most obvious way of producing informational messages from within Fortran or C application
programs is through formatted
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
msgOut sends the message string, text, to the standard output stream which will normally be the
msgOut uses the Starlink convention of inherited status. This means that
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
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
msgBlankhas been provided for this purpose, e.g.
msgBlankbehaves in the same way as the status argument in
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
msgOutif to assign a “priority” to the message, e.g.
Whether or not the message will be output depends upon the “conditional message output filter”
which may be set using the subroutine
msgIfsetis the required conditional output filter level – it may take the same values as the message priority with the addition of
MSG__ALL; by default it is set to
MSG__NORM. The current conditional output filtering level may be inquired using subroutine
msgIflevor compared against using
MSG__ALLallow every message to be hidden or all messages to be displayed respectively. These levels can not be used with
msgIfgetenv that allows the filter level to be set by an environment variable,
msgIfget which allows ADAM programs to obtain the filter level from an ADAM
The action of
msgOutif resulting from each of the defined priority values is as follows:
MSG__DEBUG(and related constants) or
MSG__DEBUG(and related constants) or
MSG__DEBUG(and related constants) or
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
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:
msgBlankif function works in much the same way as
msgOutif to allow a blank line to be output
MSG__ALL levels cannot be used with
Although conditional message reporting may be handled explicitly by calling
msgOutif, calls to
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
MSG__NORM (the default),
MSG__VERB or greater.
In the previous examples of
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
Here, the subroutine
msgSetr is called to define a token named “FLUX” and assign to it the
value of the
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
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
msgSetx 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:
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,
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.
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
msgSetx 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
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
msgSetx 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
msgLoad (or a
corresponding ERR routine, see §3.4) all existing tokens are left undefined.
msgSetx 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:
MSG_SETx 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
More precise numeric formats could be achieved using the Fortran
WRITE statement with the Message
which would produce the message:
In this case, the first call to
MSG_SETC assigns the supplied character string VALUE to the named token
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_SETx, x corresponds to one of the five standard Fortran data types – D, R, I, L and
MSG_FMTx, the example given above can be performed by:
The use of the
MSG_FMTx 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
The C interface provides variants to the standard
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:
msgOutiff act like
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
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
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
Each call to
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
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
MSG_FMTx routines). If
msgRenew is called with existing message tokens defined, no action
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:
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
msgOut calls, and only needs to check the status at the
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:
msgLoad(or a corresponding ERR routine).
MSG_FMTx 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.
msgBlankifattempt 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: