ETHZ_Logo RAMSES_Logo_Right   RAMSES   RAMSES_Logo_Left Systems Ecology  
Start    search button      Modules:   A-Z   Function   Layer        QuickRefs:   DM   AuxLib   AuxLibE   SciLib   EasyMW   MW   ISIS   RMSLib

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.

  Contact RAMSES@env.ethz.ch Last updated: 25-Jul-2011 [Top of page]