DEFINITION MODULE Errors;
(*******************************************************************
Module Errors (Version 1.0)
Copyright (c) 1995-2006 by Andreas Fischlin and ETH Zurich.
Purpose Provides simple and consistent error handling
for errors detected by algorithms from library
modules.
Remarks The module provides convenient mechanisms to
generate error messages and to control their
display. In particular, it enables a programmer
to suppress any error display by an algorithm
residing in a lower level library module, yet all
local information describing the error can be
fully retrieved for display or explanation to
the user by the calling program. The module is
basically an enhancement of DMMessages (see the
"Dialog Machine" kernel modules).
Typical Usage (a code excerpt):
...
FROM Errors IMPORT allOk, ActivateMessageFile, SetInsert,
AppendInsert, Str, IStr, RStr, Info, Halt, Kill;
...
VAR
inserts: ARRAY [0..255] OF CHAR;
resCode, aninteger: INTEGER;
...
(* The following routine returns the message text msg associated with
the message or error number msgnr. Note, the symbol Δ (=306C) denotes a
so-called place-holder which will be replaced by the actual parameter
passed for inserts while calling Info, Halt, or Kill (see below),
usually rendering message texts much more understandable if they contain
specific information, e.g. the name of an actual operand etc.: *)
PROCEDURE MyGetMsg (msgnr: INTEGER; VAR msg: ARRAY OF CHAR);
BEGIN
CASE msgnr OF
| 1: AssignString("Please select first a Δ",msg);
| 2: AssignString("Can't find model object 'Δ'",msg);
AppendLnBreak(msg);
Append(msg,"(Hint: Check existence of model)");
| 3: AssignString("...
...
ELSE
msg[0] := 0C; (* signals to Errors to look for other sources *)
END(*CASE*);
END MyGetMsg;
(* The following routine provides an alternative mechanism (see above
MyGetMsg) for associating message texts with error numbers. In
this case you need to pass GetMessage or GetNumberedMessage from
MsgFile as actual paramter for getMsg while calling any of the
routines Info, Halt, or Kill (see below). *)
ActivateMessageFile("Errors.DOC",TRUE, resCode);
...
(* Declare the resCode range for range-specific handling of
error messages, e.g. 20 resCodes: *)
minRC = userBase + 700; maxRc = minRC + 20;
SetErrHdlgModes(suppressed,debug,minRC,maxRC,installed);
(* now an example of generating a warning in an
algorithm of the library module: *)
...
SetInsert(inserts,Str("a string insert item"));
AppendInsert(inserts,IStr(aninteger),);
Halt(errCode,MyGetMsg,"MyModule","ProcedureName",inserts);
(* or *)
Halt(errCode,MsgFile.GetMessage,"MyModule","ProcedureName",inserts);
(* if ActivateMessageFile has previously been called *)
...
(* Upon returning from the algorithm in the library
module, a final handling of the error by the callee: *)
...
GetErrHdlgModes(suppressed,debug,minRC,maxRC, installed);
IF suppressed THEN
FOR i := -1 TO OldestErrIndex(minRC,maxRC) BY -1 DO
GetError(i,err);
WITH err DO
... (* e.g. analyze it and construct a custom message myErr *)
END(*WITH*);
END(*FOR*);
(* e.g. display custom message: *)
DisplayAnError(myErr);
...
(* or display one found in the list, e.g. only the last: *)
DoInfo(err.resCode,MsgFile.GetMessage,
"MyModule","ProcedureName",err.inserts);
(* or use just the field msg: *)
DoInfo(onlyAnInsert,MsgFile.GetMessage,
"MyModule","ProcedureName",err.msg);
...
(* finally don't forget to discard the stored errors, they
are no longer needed: *)
ForgetErrHistory(minRC,maxRC);
END(*IF*);
(* or do it just the poor man's way: *)
...
DisplayErrHistory(minRC,maxRC);
(* But note, above poor man's way may display a large, confusing
number of messages in a row, without allowing for proper
debugging, since the procedure chain does no longer match
that which was present at error detection.
Finally note, by activating the forced debugging mode, e.g.
by pressing
Command^Shift^Capslock^D
simultaneously, can you force an immediate display of
messages at all times. It offers the advantage of proper
debugging, even it the programmer has suppressed the error
display. *)
Programming
o Design
Andreas Fischlin 08/09/1995
o Implementation
Andreas Fischlin 08/09/1995
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 31/03/1998 AF
*******************************************************************)
FROM DMStrings IMPORT String;
FROM DMMessages IMPORT MsgRetrieveProc;
(*********************************)
(*##### Error Constants #####*)
(*********************************)
(*
Note, the following error constants are compatible with the
ones used by the "Dialog Machine", especially the codes
supported by module 'DMLanguage' and are all by default
available from 'DMLanguage'.
*)
CONST
allOk = 0;
(* General 'Dialog Machine' *)
badProgState (* should not occurr *) = -4;
onlyAnInsert = -3;
unknownErr = -2;
insuffMem = -1;
tooOldMac = 9;
tooManyTermProc = 10;
(* DMWindIO arithmetic *)
intOverflow = 1;
lowUpSame = 2;
(* User Input (DMEntryForms etc.) *)
numExpected = 5;
outOfRange = 7;
wrongChar = 3;
wrongCharOrNone = 14;
only1Char = 4;
only1CharOrNone = 15;
stringTooLong = 16;
(* Object access *)
unknownWindow = 8;
unknownEditField = 6;
unknownGraph = 11;
(* DM2DGraphs *)
noLogScale = 12;
graphTooSmall = 17;
(* DMFiles: Subsequent message order fits DMFiles.Response,
i.e. code = fileResBase+ORD(f.res) *)
fileResBase = 20;
fileNotFound = 21;
volNotFound = 22;
fileDlgCancelled = 23;
unknownFile = 24;
tooManyFiles = 25;
diskFull = 26;
insuffMemForFileFct = 27;
fileAlreadyOpen = 28;
fileIsBusy = 29;
fileIsLocked = 30;
fileFctNotDone = 31;
(* reserved for Dialog Machine Auxiliary Library is range
100..199 *)
notImplemented = 100;
userInterrupted = 101;
(* reserved for Dialog Machine applications is range
200..300. In use as of April 1998:
201, 202, 299 *)
(* Error constants beyond userBase may be used freely and
do not conflict with any constants used by the 'Dialog Machine' *)
userBase = 300;
(******************************************)
(*##### Error Message Generation #####*)
(******************************************)
PROCEDURE Info (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
PROCEDURE Halt (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
PROCEDURE Kill (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
(*
Above routines are similar to the ones exported by
DMMessages, but they know about current display and debug
mode settings and behave accordingly. For explanations of
default behavior see DMMessages (for Info see DoInform; for
Halt see DoWarn; for Kill see DoAbort). Typical usage:
VAR inserts: ARRAY [0..63] OF CHAR;
...
SetInsert(inserts,Str(f.filename));
AppendInsert(inserts,IStr(maxNum));
Info(resCode,MyGetMsg,"MyModule","Reading",inserts);
...
Note, the routine getMsg has to provide a message text associated
with the msgnr. Typically it is a routine written by the programmer,
but can also be on of these: DMLanguage.GetString, DMStrings.GetRString,
DMMsgFile.GetMessage, or DMMsgFile.GetNumberedMessage. This technique
enables to have several clients using this module at the same time
since getMsg is used only temporarily to generate the error message;
the previous settings are restored upon returning from any of these
routines.
*)
PROCEDURE DoInfo (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
PROCEDURE DoHalt (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
PROCEDURE DoKill (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
(*
Provided for your convenience, above routines are similar to Info,
Halt, and Kill. They know about current display and debug mode
settings and behave accordingly, except for the flag suppress which
they ignore, i.e. they always produce the error message immediately
regardless of the current settings. For instance DoInfo corresponds
exactly to the following code:
PROCEDURE DoInfo (msgnr: INTEGER; getMsg: MsgRetrieveProc;
modIdent, locDescr, insertions: ARRAY OF CHAR);
VAR saveSuppress: BOOLEAN;
BEGIN (*DoInfo*)
GetErrHdlgModes(saveSuppress,...
SetErrHdlgModes(FALSE,...
Info(msgnr, getMsg, modIdent, locDescr, insertions);
SetErrHdlgModes(saveSuppress,...
END DoInfo;
Typically these routines are used by the callee of auxiliary
library routines after having suppressed any immediate message
display to finally inform the user about the error(s) which
occurred. They are a full replacement of the corresponding
DMMessages routines, since they behave similarily but offer the
advantages of switching the message retrieve procedure
automatically according to the current settings and that they
know about the current debug mode settings.
*)
VAR
nil: String;
PROCEDURE DbgMsg (modIdent, locDescr: ARRAY OF CHAR; s1,s2,s3,s4,s5: String);
(*
Displays a message concatenated from all string parameters
s1..s5 only if debugging mode is currently activated (see
section on modes); otherwise any message generation is
suppressed. For the meaning of modIdent and locDescr see
routines DMMessages.DoInform, DoWarn respectively DoAbort.
The message is always produced on the warn level only (see
DMMessages.DoWarn), which allows for an optional calling
of the debugger and messages are never deferred but always
displayed at generation time.
*)
PROCEDURE ReplacePlaceHolders (VAR newMsg: ARRAY OF CHAR;
oldMsg, insertions: ARRAY OF CHAR);
(*
Copies oldMsg into newMsg by replacing the place holders
in oldMsg (Mac 'Δ' (=306C), IBM-PC '^') with the string
items found in variable insertions. E.g.
ReplacePlaceHolders(newMsg, "Δ is out of range [Δ..Δ]","-1|2|3");
==> newMsg = "-1 is out of range [2..3]"
*)
PROCEDURE AppendLnBreak (VAR s: ARRAY OF CHAR);
(*
Causes in the string s to appear a line break. Typically used
while programming your own GetMessage routine (see
sample code MyGetMsg above).
*)
(****************************************)
(*##### Insertion Construction #####*)
(****************************************)
PROCEDURE SetInsert(VAR inserts: ARRAY OF CHAR; s: String);
(*
First item to be put into inserts used for place holders
in messages
*)
PROCEDURE AppendInsert (VAR inserts: ARRAY OF CHAR; s: String);
(*
Append another item to inserts used for place holders in
messages
*)
PROCEDURE Str(s: ARRAY OF CHAR): String;
(*
Convert string s to String for passing to AppendInsert.
E.g. SetInsert(Str("First insert item"),inserts);
*)
PROCEDURE IStr (x: INTEGER): String;
PROCEDURE LIStr (x: LONGINT): String;
(*
Convert integer number x to String for passing to AppendInsert.
E.g. AppendInsert(IStr(231),inserts);
*)
PROCEDURE RStr (x: REAL): String;
PROCEDURE LRStr (x: LONGREAL): String;
(*
Convert real number x to String for passing to AppendInsert.
E.g. AppendInsert(RStr(2.345),inserts);
*)
PROCEDURE BStr (x: BOOLEAN): String;
(*
Convert boolean x to String for passing to AppendInsert.
E.g. AppendInsert(BStr(flag),inserts);
*)
(************************************)
(*##### Setting Up & Modes #####*)
(************************************)
(************************************************************************
The following optional routines allow to activate and customize
any subsequent error message handling, i.e. to tell this
module e.g. where to get error message texts and how to display
them. This module assumes the following:
- each error detected and to be handled by your code belongs
to a certain error class, where the lowest level simply
informs the user, the second warns her (makes it possible
to call the debugger), or aborts the program (debugger can
also first be called). For more details see underlying module
DMMessages.
- each error is encoded by a unique integer (errNo, msgNr, or
resCode) and associated with a specific message text which
can be displayed to the user. Such texts may not be fully
predefined, but can be completed by variable information only
available at run-time. The latter is called insertions which
are to replace placeholders (on the Macintosh = 'Δ'(=306C),
on the IBM-PC = '^') in the predefined message text.
First a technique needs to be available to the message
generating routines of this module which enable them to
retrieve the message text associated with a given error code.
There are two basic techniques available to accomplish
this:
- Program your own MyGetMsg procedure to return a specific
message text associated with a given error number (for
sample code see below). This technique is the most flexible
and robust method.
- ActivateMessageFile is used to retrieve messages from
a text file which is easy to maintain let's you keep the
code of applications smaller, and which provides a good
overview if many error messages are to be managed.
Important NOTE: Error messages for error codes already defined
by the 'Dialog Machine' (i.e. codes < userBase) are
automatically retrieved from the DM, unless they are defined
again. Not only does this enable to override any definition as
defined by the DM but also to inherit any error messages which
are already defined by DMLanguage.
If you use a message file, i.e. you call ActivateMessageFile,
at a time you can use only a single message file, due the
implementation restriction by the underlying module MsgFile. If
you wish to use more than one message file you have to switch
the message file before each message generation (likely to be
inefficient).
For the display of errors or messages, this module can
basically operate in three modes:
1) suppress TRUE, i.e. any immediate error or message
generation is suppressed. Instead the information is
stored and accumulated in memory; debug FALSE
2) immediate (= NOT suppress), i.e. any error or message
generation takes place immediately, i.e. the very moment
of their generation; nothing is stored in memory,
debug FALSE
3) debug TRUE implies NOT suppress, i.e. any error or message
generation takes not only place immediately - a prerequisite
for meaningful debugging -, but can also produce additional,
debugging messages which remain otherwise always hidden
and turns Info messages into Halt ones (see above). The
latter allows the user to call the debugger each time a
message generating routine from this module is called.
The flag 'suppress' controls whether the display of messages
by Info, Halt, or Kill (see below) is immediate (right at
generation moment) or whether these routines display nothing
and contribute only towards accumulating a so-called error
history. The error history is stored for deferred display or
analysis by the callee or display to the end user.
The possibility to suppress immediate display of error
messages, allows for writing code, typically in a library
module, which can call Info, Halt etc. as soon as an error is
detected by the algorithm, regardless of the current message
display mode. Yet, depending on the suppress mode, the actual
display of these messages to the end user may be deferred,
e.g. the callee want's to inform the user later in a more
context specific way than this would be possible by a general
purpose library module.
With this technique, the implementation of error generation
within general purpose library modules can be elegantly
separated from client error handling including the display to
the end user. The implementor can program the former freely
and in a logical, algorithm suitable way; and the callee can
program the latter in whichever way she likes (see routines
GetError, DisplayAnError below). If suppress = TRUE, any
number of errors generated by the routines Info, Halt, or Kill
are stored in memory for later retrieval. Entire error
history can be inspected anytime for a sophisticated error
analysis and/or display. By default suppress = FALSE.
It is also possible to activate a global debugging mode in
which additional debugging messages become visible and in
which it is possible to call the debugger during any message
generation. This is typically used during testing phases
(available also in final, end-user software), where the
deferring of message display can be suppressed and step by
step software execution is desired. This mode can be
activated by means of not so obvious keyboard shortcuts
anytime during program execution.
Finally, this module provides means to subdivide errors and
their associated messages according to their unique resCode
numbers into three classes:
- range-specific errors/messages
- non range-specific (so-called global) errors/messages
- all errors/messages (unification of the two above)
The first type is characterized by a specific range of
resCodes ([minResCode..maxResCode]) as given by a lower
(minResCode) and upper limit (maxResCode). The second type
encompasses all other resCodes, which fall not into one of
the ranges known to this module. They form the class of the
so-called global or non-range specific error messages.
Finally, the third type include any possible resCode; some
routines operate on all errors and error messages, regardless
wether its resCode's are range-specific or not, i.e. global
ones.
The class global errors is useful for displaying also errors
which are likely to be encountered in the middle of an
operation, which "normally" uses a specific range for its own
specific errors. E.g. errors occurring during file
operations typically belong to the global error class, since
a matrix package reading matrices from a file may use
range-specific errors for its specific error reporting, e.g.
a badly defined matrix, yet errors caused by a file operation
should still be displayable. Global errors are those shared
by several software packages using their own specific error
ranges, i.e. global errors form a common class of errors.
It is important to note that every range can have its own
suppress and debugging modes. Range specific modes affect
only errors or messages falling within range [minResCode ..
maxResCode]. Ranges and their modes can be installed via
routine SetErrHdlgModes (see below). Range-specific modes
allow for the coexistence of several software packages, each
using its particular mode of operation when using this module
Errors. Ranges may not overlap and must be unique globally
at run time. Any handling of global error messages is
preinstalled by this module, with suppress = FALSE, debug =
FALSE (see routine SetErrHdlgModes).
The three types are specified by using particular range intervals
[minResCode .. maxResCode ] range-specific
[globResCode .. globResCode] non range-specific (global)
[allResCode .. allResCode ] unification of the two above
where
minResCode <> MIN(INTEGER)
maxResCode <> MAX(INTEGER)
globResCode = MIN(INTEGER)
allResCode = MAX(INTEGER)
************************************************************************)
(*-----------------------------------------*)
(*===== Setting Up A Message File =====*)
(*-----------------------------------------*)
PROCEDURE ActivateMessageFile(errDocFN: ARRAY OF CHAR; VAR resCode: INTEGER);
(*
Initialize error message display mechanism if you hold the
error messages in a file named "errDocFN". There is only
one message file which can be used at a time. Thus using
a message file is typically reserved for global errors
only, i.e. errors or messages with a resCode which falls
NOT within one of the installed ranges. If resCode is not
allOk, e.g. if the error document file could not be
found, suppress is forced TRUE, to avoid unpredictable
results during subsequent error handling. It is highly
recommended to call at least DisplayErrHistory immediately
after this routine, if it is called with suppress = TRUE.
*)
(*------------------------------------*)
(*===== Error Handling Modes =====*)
(*------------------------------------*)
CONST
globResCode = MIN(INTEGER);
allResCode = MAX(INTEGER);
PROCEDURE SetErrHdlgModes(suppress,debug: BOOLEAN;
minResCode,maxResCode: INTEGER;
VAR done: BOOLEAN);
(*
Set mode for error message display to 'suppress', 'debug'
for the generation or display respectively of any messages
with a resCode falling in range [minResCode..maxResCode].
'suppress' = TRUE => any subsequent immediate message
display will be suppressed, but messages are stored in
memory in form of an error history for later retrieval.
'debug' = TRUE => In debugging mode error messages as
generated by routine DbgMsg (see above) become visible and
all messages as generated by routines Info, Halt, or Kill
(see above) are always immediately displayed regardless of
the current display mode (see routine SuppressMsgDisplay).
The latter makes it possible to properly debug the program
behavior, since only at error detection is the procedure
chain the one you're interested in. Moreover, in this mode,
errors of class inform can be debugged since they are
treated as messages at the warn level.
[minResCode..maxResCode] denotes the range and thereby the
interval of resCode's for which the passed modes ('suppress'
and 'debug') are effective (range-specific modes). To be
effective for non range-specific resCode's, pass range
[globResCode..globResCode]. To affect all at once
regardless of range-specificity pass range
[allResCode..allResCode].
Parameter 'done' returns about successful installation of
range-specific modes. It may fail due to memory limitations
(see below) or range errors. Note, SetErrHdlgModes does
not allow for overlapping ranges, e.g. if another software
layer has installed error modes for a range which overlaps
with range [minResCode..maxResCode], this will lead to a
failure of SetErrHdlgModes. However, you may call
SetErrHdlgModes as many times you wish, as long as the
range as given by the actual parameters minResCode and
maxResCode matches exactly one previously installed. Then
Errors assumes that the same callee is using the range and
that SetErrHdlgModes simply wishes to alter the current
mode settings.
IMPORTANT NOTE: Keyboard shortcut "Command^Shift^Capslock^D"
(or alternatively "Command^Shift^Capslock^G") toggles the
forced debug mode on or off. It's effect is similar to
calling SetErrHdlgModes(FALSE, TRUE, allResCode,
allResCode, done), however, "Command^Shift^Capslock^D"
overrules the settings for particular ranges only
temporarily. After having toggled the forced debug mode
off, previous modes will be restored; this is not the case
after a call to SetErrHdlgModes passing range
[allResCode..allResCode].
IMPLEMENTATION RESTRICTION: Only a limited number of error
ranges can be supported.
*)
PROCEDURE GetErrHdlgModes(VAR suppress,debug: BOOLEAN;
minResCode,maxResCode: INTEGER;
VAR installed: BOOLEAN);
(*
Returns the current modes effective for errors falling
within range [minResCode..maxResCode]. 'installed'
returns wether SetErrHdlgModes has ever been called
for the given range. Calling this routine with
globResCode as actual argument for range limits, will
return the so-called global modes 'suppress' and 'debug'.
They are effective for all messages with a resCode not
falling within one of the ranges declared by means of
SetErrHdlgModes.
*)
PROCEDURE ForgetRange (minResCode,maxResCode: INTEGER; VAR done: BOOLEAN);
(*
Tells the module to forget about the range
[minResCode..maxResCode]. 'done' returns upon success of
action, e.g. may fail if range has never be installed of
it has been automatically remove, e.g. the calling
subprogram level is no longer present.
*)
(****************************************)
(*##### Handling Error History #####*)
(****************************************)
(*------------------------------------------*)
(*===== Easy Retrieval and Display =====*)
(*------------------------------------------*)
PROCEDURE NoOfMsgs (minResCode,maxResCode: INTEGER): INTEGER;
(*
Returns the number of error messages presently stored in
memory with a resCode which falls within range
[minResCode..maxResCode].
*)
PROCEDURE AskAndViewErrHistory(minResCode,maxResCode: INTEGER;
withGlobMsg : BOOLEAN;
VAR answeredToView : BOOLEAN;
doViewOnUserYes : BOOLEAN);
(*
High level utility to handle at once all currently present
error messages which fall into range [minResCode..maxResCode]
and/or global error messages (withGlobMsg = TRUE) as
follows: If a single error message is present it is
displayed immediately (returns answeredToView = FALSE). If
more than one is found, the user is informed about the
number of messages present and asked if she wishes to view
them ('answeredToView' returns what the user answered, i.e.
whether she has wished to view the messages or not). If
doViewOnUserYes = TRUE then the routine calls ViewErrHistory
automatically in case the user has answered to view the
messages (answeredToView = TRUE), otherwise no further
displays are made and the callee may call her own message
display algorithm. A typical call to this routine looks
like this:
AskAndViewErrHistory (myMinRC,myMaxRC,TRUE,answView,TRUE);
*)
PROCEDURE ViewErrHistory(minResCode,maxResCode: INTEGER;
withGlobMsg: BOOLEAN);
(*
Displays the error history currently stored in memory for
all messages which fall into range
[minResCode..maxResCode] and/or global error messages
(withGlobMsg = TRUE) in chronological order (indices from
OldestErrIndex(..) .. -1). Note, does nothing if there
are currently no errors stored. To prevent repeated
displays of the same error message(s), ViewErrHistory
calls at the end implicitely also ForgetErrHistory for
the involved ranges. For alternatives to this routine
see also routine DisplayErrHistory (reverse order) or
AskAndViewErrHistory. Note, the viewing of error
messages can anytime be aborted by pressing key 'q'
(quit) or 'c' (cancel).
*)
PROCEDURE DisplayErrHistory(minResCode,maxResCode: INTEGER);
(*
Displays the error history currently stored in memory for
all messages which fall into range
[minResCode..maxResCode] in reverse order of occurrence,
i.e. starting with the most recent one (-1), then the
previous one (-2) etc. (indices from -1 ..
OldestErrIndex(..)). Note, does nothing if there are
currently no errors stored. To prevent repeated displays
of the same error message(s), DisplayErrHistory calls at
the end implicitely also ForgetErrHistory for range
[minResCode..maxResCode]. For alternatives to this
routine see also routine ViewErrHistory (chronological
order) or AskAndViewErrHistory. Note, the viewing of
error messages can anytime be aborted by pressing key 'q'
(quit) or 'c' (cancel).
*)
(*----------------------------------------------------*)
(*===== Full Analysis, Retrieval and Display =====*)
(*----------------------------------------------------*)
CONST
noMoreErrs = 0;
TYPE
ErrorClass = (inform, warn, fatal); (* for explanation see DMMessages *)
ErrorDescr = RECORD
class: ErrorClass;
msg: ARRAY [0..255] OF CHAR; (* holds entire message text *)
(* the following fields hold only information which
was used to construct msg and may be optionally of use *)
resCode: INTEGER;
modIdent, locDescr, insertions: ARRAY [0..255] OF CHAR;
END(*RECORD*);
PROCEDURE OldestErrNo(): INTEGER;
(*
Returns the index of the oldest error of the currently
stored history of all errors, global and range specific
ones, e.g. -2. Returns 0 if there are no errors stored.
*)
PROCEDURE GetError(n: INTEGER; VAR err: ErrorDescr);
(*
Retrieves the error description of the n'th error. Such
error descriptions are generated and stored by calls to
any of the procedures Info, Halt, or Kill while flag
suppress is TRUE. n designates the error occurrence in
reverse order, where -1 is the very last error, -2 the
error which occurred before the last one, -3 the even
earlier one etc. Typically used immediately after
returning from a routine, which has been called while
suppress was TRUE. It allows for analyzing the error and
for displaying a custom error message or for taking
whatever action the callee prefers (see also
DisplayErrHistory). Only errors stored since the last
call to procedure ForgetErrHistory or DisplayErrHistory
can be retrieved. If n designates an error exceeding
those currently actually stored, an empty err is returned
with err.class = inform, err.resCode = allOk, and all
string fields = "". GetError does not change the storage
of the internal error history.
*)
PROCEDURE DisplayAnError(VAR err: ErrorDescr);
(*
Immediately displays the error as described by err according to
its class and the other fields.
*)
PROCEDURE OldestErrIndex(minResCode,maxResCode: INTEGER): INTEGER;
(*
Returns the index of the oldest error of the currently
stored history for error messages with a resCode which
falls within range [minResCode..maxResCode]. Returns 0 if
there are no errors stored. Note, the index is a number between
OldestErrNo() and 0.
*)
PROCEDURE NextErrIndex (fromIndex,minResCode,maxResCode: INTEGER): INTEGER;
PROCEDURE PrevErrIndex (fromIndex,minResCode,maxResCode: INTEGER): INTEGER;
(*
Similar to OldestErrIndex but return the next/previous
error index of the error message which chronologically
follows/preceeds message 'fromIndex' (see also
DisplayErrHistory which uses only PrevErrIndex starting
with 'fromIndex' = 0). Returns 0 if there are no more errors
stored. Note, the index is a number between OldestErrNo()
and 0, where indices may be returned not as a complete
series, but with gaps inbetween, e.g. if the history
contains inbetween a message falling into another range.
Use the returned index as actual argument when calling
GetError. Ex.:
CONST noMoreErrs = 0;
i := OldestErrIndex(minResCode,maxResCode);
WHILE (i<>noMoreErrs) DO
GetError(i,err);
DisplayAnError(err);
i := NextErrIndex(i,minResCode,maxResCode);
END(*WHILE*);
*)
(*--------------------------------------*)
(*===== Clearing Error History =====*)
(*--------------------------------------*)
PROCEDURE ForgetErrHistory(minResCode,maxResCode: INTEGER);
(*
Discards entire, currently stored error history for all
messages with a resCode falling within range
[minResCode..maxResCode]. Any subsequent calls to
GetError return an empty error or to DisplayErrHistory
display nothing unless at least one of the procedures
Info, Halt, or Kill has been called again while flag
suppress was set to TRUE (see also procedure GetError).
No effect if range has never been installed.
ForgetErrHistory(allResCode, allResCode) discards all
error messages at once, regardless of ranges.
*)
(************************************)
(*##### Module Maintenance #####*)
(************************************)
PROCEDURE ResetErrors;
(*
Resets the entire module to its predefined, initial
defaults. All current error handling modes are set to
their defaults, internal state is reset, message display
is not suppressed (suppress := FALSE), no error message
file will be used any more, debugging modes are all off,
and any error history is discarded.
*)
END Errors.