home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / dev / m2 / rexxm2error.lha / RexxM2Error / source / RexxM2Error.mod
Encoding:
Text File  |  1994-03-20  |  33.0 KB  |  1,094 lines

  1. MODULE RexxM2Error;
  2.  
  3.    (** RexxM2Error.mod - Stellt einen AREXX-Port zur Verfügung und
  4.     *                    liefert dann die Fehlermeldungen von M2Amiga.
  5.     * Version     : $VER RexxM2Error.mod 0.97 (© 1994 Fin Schuppenhauer)
  6.     * Autor       : Fin Schuppenhauer
  7.     *               Braußpark 10
  8.     *               20537 Hamburg
  9.     *               (Germany)
  10.     * E-Mail      : schuppen@rzdspc2.informatik.uni-hamburg.de
  11.     * Copyright   : © 1994 Fin Schuppenhauer
  12.     *               "Freely distributable copyrighted software"
  13.     * Erstellt am : 18.03.1994
  14.     * Letzte Änd. : 19.03.1994
  15.     * Geschichte  :
  16.     **)
  17.  
  18. IMPORT   ed:ExecD,      el:ExecL,      es:ExecSupport,
  19.          rxd:RexxD,     rxl:RexxL,
  20.          dd:DosD,       dl:DosL,
  21.          wd:WorkbenchD,
  22.          icl:IconL,
  23.          str:String,
  24.          Arts,
  25.          con:Conversions;
  26.  
  27. FROM Heap      IMPORT Allocate, Deallocate;
  28. FROM UtilityD  IMPORT tagEnd;
  29. FROM SYSTEM    IMPORT ADDRESS, ADR, LONGSET, CAST, TAG;
  30.  
  31.  
  32. CONST VersionStr = "$VER RexxM2Error 0.97 (© 1994 Fin Schuppenhauer)";
  33.  
  34. CONST REXXCOMMPROCS  = 6;
  35.       TEXTLIMIT      = 40000;
  36.  
  37.  
  38. TYPE  Commands = (ERROR, ERRORS, RESET, LOAD, QUIT, QUERY, UNKNOWN);
  39.  
  40. TYPE  String      = ARRAY [0..79] OF CHAR;
  41.       StringPtr   = POINTER TO String;
  42.       TextPtr     = POINTER TO ARRAY [0..TEXTLIMIT] OF CHAR;
  43.       INTEGERPtr = POINTER TO INTEGER;
  44.       LONGINTPtr  = POINTER TO LONGINT;
  45.  
  46.       RexxCommProc = PROCEDURE(VAR LONGINT, VAR LONGINT, BOOLEAN, dd.RDArgsPtr);
  47.  
  48. (* ---------------------------------------------------------------------- *)
  49. (** Debug-Stuff *)
  50. VAR   DEBUG    := BOOLEAN{TRUE};
  51.       dbghdl   : dd.FileHandlePtr;
  52.  
  53. PROCEDURE DbgWrite (msg : ARRAY OF CHAR);
  54. VAR   li : LONGINT;
  55. BEGIN
  56.    (*$ StackParms:=TRUE *)
  57.    li := dl.Write(dbghdl, ADR(msg), str.Length(msg));
  58.    (*$ POP StackParms *)
  59. END DbgWrite;
  60.  
  61. PROCEDURE DbgWriteLn;
  62. VAR   li : LONGINT;
  63. BEGIN
  64.    li := dl.Write(dbghdl, ADR("\n"), 1);
  65. END DbgWriteLn;
  66. (* **)
  67. (* ---------------------------------------------------------------------- *)
  68.  
  69. PROCEDURE TemplateError;
  70. (**   Funktion : Wird aufgerufen, falls es bei der Auswertung eines
  71.   *              Templates zu einem Fehler gekommen ist.
  72.   *              Diese Funktion ermittelt den Fehler und öffnet einen
  73.   *              Requester mit der Fehlermeldung.
  74.   *)
  75. VAR   IoErrMsg   : String;
  76.       b        : BOOLEAN;
  77. BEGIN
  78.    IF dl.Fault(dl.IoErr(), NIL, ADR(IoErrMsg), 75) THEN
  79.       b := Arts.Requester (ADR("REXXM2ERROR detected an IoErr:"),
  80.                            ADR(IoErrMsg), NIL, ADR("Damned!"));
  81.    END;
  82. END TemplateError;
  83. (* **)
  84.  
  85. (* ---------------------------------------------------------------------- *)
  86.  
  87. PROCEDURE CheckToolTypes (VAR name : ARRAY OF CHAR);
  88. (**   Funktion : Liest die Tooltypes ein.
  89.   *)
  90. VAR   info  : wd.DiskObjectPtr;
  91.       type  : ADDRESS;
  92. BEGIN
  93.    (* .info-Datei einlesen: *)
  94.    info := icl.GetDiskObject(ADR("RexxM2Error"));
  95.  
  96.    IF info # NIL THEN
  97.       type := icl.FindToolType(info^.toolTypes, ADR("ERRORMSGFILE"));
  98.       IF type # NIL THEN
  99.          str.Copy (name, StringPtr(type)^);
  100.       ELSE
  101.          str.Copy (name, "M2:Fehler-Meldungen");
  102.       END;
  103.       icl.FreeDiskObject (info);
  104.    END;
  105. END CheckToolTypes;
  106. (* **)
  107.  
  108. (* ---------------------------------------------------------------------- *)
  109. VAR   ErrorMsgBase   := TextPtr{NIL};
  110.       ERRORMSGFILE   : String;
  111.  
  112. PROCEDURE LoadErrorMsgFile (filename : ARRAY OF CHAR) : LONGINT;
  113. (**   Funktion : Lädt die Datei mit den Texten zu den Fehlermeldungen.
  114.  *               Wurde sie nicht gefunden, wird 10, gab es einen
  115.  *               Lesefehler 20, zurückgegeben, bei Erfolg 0.
  116.  *)
  117. VAR   hdl      : dd.FileHandlePtr;
  118.       fib      : dd.FileInfoBlockPtr;
  119.       li       : LONGINT;
  120.       taglist  : ARRAY [0..10] OF LONGINT;
  121. BEGIN
  122.    IF DEBUG THEN
  123.       DbgWrite ("Loading ErrorMsgFile ...\n");
  124.    END;
  125.    (* Für den Fall, daß schon mal die Datei mit den Fehlertexten geladen
  126.     * wurde, werden wir hier mal schnell den belegten Speicher freigeben:
  127.     *)
  128.    IF ErrorMsgBase # NIL THEN
  129.       Deallocate (ErrorMsgBase);
  130.    END;
  131.    ERRORMSGFILE := "";
  132.  
  133.    hdl := dl.Open(ADR(filename), dd.readOnly);
  134.    IF hdl = NIL THEN
  135.       RETURN dd.error;
  136.    END;
  137.  
  138.    fib := dl.AllocDosObject(dd.dosFib, TAG(taglist, tagEnd));
  139.    IF fib = NIL THEN
  140.       dl.Close (hdl);
  141.       RETURN dd.fail;
  142.    END;
  143.  
  144.    IF dl.ExamineFH(hdl, fib) THEN
  145.       Allocate (ErrorMsgBase, fib^.size);
  146.       IF ErrorMsgBase = NIL THEN
  147.          IF DEBUG THEN
  148.             DbgWrite ("   not enough memory\n");
  149.          END;
  150.          dl.Close (hdl);
  151.          dl.FreeDosObject (dd.dosFib, fib);
  152.          RETURN dd.fail;
  153.       END;
  154.       IF DEBUG THEN
  155.          DbgWrite ("   Memory for ErrorMsgBase allocated.\n");
  156.       END;
  157.       li := dl.Read(hdl, ErrorMsgBase, fib^.size);
  158.       dl.Close (hdl);
  159.       IF li < fib^.size THEN
  160.          IF DEBUG THEN
  161.             DbgWrite ("   read error\n");
  162.          END;
  163.          (* Lesefehler *)
  164.          dl.FreeDosObject (dd.dosFib, fib);
  165.          Deallocate (ErrorMsgBase);
  166.          RETURN dd.fail;
  167.       END;
  168.       dl.FreeDosObject (dd.dosFib, fib);
  169.       str.Copy (ERRORMSGFILE, filename);
  170.       IF DEBUG THEN
  171.          DbgWrite ("   ready.\n");
  172.       END;
  173.       RETURN dd.ok;
  174.    ELSE
  175.       dl.FreeDosObject (dd.dosFib, fib);
  176.       RETURN dd.fail;
  177.    END;
  178. END LoadErrorMsgFile;
  179. (* **)
  180.  
  181. (* ---------------------------------------------------------------------- *)
  182.  
  183. TYPE  ErrorDescriptionPtr = POINTER TO ErrorDescription;
  184.       ErrorDescription = RECORD
  185.          offset   : LONGINT;
  186.          ErrNum   : INTEGER;
  187.          ErrMsg   : StringPtr;
  188.          next     : ErrorDescriptionPtr;
  189.       END;
  190.  
  191. VAR   MAXERRORS   := LONGINT{0};
  192.       ErrorArray  : POINTER TO ARRAY [0..150] OF ErrorDescription;
  193.       ERRORFILE   : String;
  194.  
  195. PROCEDURE LoadErrorFile (filename : ARRAY OF CHAR) : LONGINT;
  196. (**   Funktion: Lädt die zu filename zugehöroge Fehlerdatei.
  197.                 Wenn sie nicht gefunden wird, wird 5, bei Lese-
  198.                 fehler o.ä 20 zurückgegeben.
  199. *)
  200. VAR   ErrorBase   : TextPtr;
  201.  
  202.    PROCEDURE ParseErrorPart (ed : ErrorDescriptionPtr; VAR pos : CARDINAL);
  203. (** Funktion: Anlysiert ErrorPart *)
  204.    VAR   i        : CARDINAL;
  205.          errstr   : String;
  206.    VAR   zahlstr  : ARRAY [0..10] OF CHAR;
  207.          err      : BOOLEAN;
  208.    BEGIN
  209.       IF DEBUG THEN
  210.          DbgWrite ("         ParseErrorPart\n");
  211.       END;
  212.       WITH ed^ DO
  213.          IF ErrorBase^[pos] = CHAR(0C2H) THEN
  214.             IF DEBUG THEN
  215.                DbgWrite ("            String = ");
  216.             END;
  217.             ErrNum := 0;
  218.             INC (pos);
  219.             i := 0;
  220.             WHILE ErrorBase^[pos] # 0C DO
  221.                errstr[i] := ErrorBase^[pos];
  222.                INC (i); INC (pos);
  223.             END;
  224.             errstr[i] := 0C;
  225.             INC (pos);
  226.             IF DEBUG THEN
  227.                DbgWrite (errstr);
  228.                DbgWriteLn;
  229.             END;
  230.             IF pos MOD 2 = 1 THEN INC (pos); END;
  231.             Allocate (ErrMsg, str.Length(errstr));
  232.             IF ErrMsg # NIL THEN
  233.                str.Copy (ErrMsg^, errstr);
  234.             END;
  235.          ELSE
  236.             IF DEBUG THEN
  237.                DbgWrite ("            ErrNum = ");
  238.             END;
  239.             ErrNum := CAST(INTEGERPtr, ADDRESS(ErrorBase)+ADDRESS(pos))^;
  240.             IF DEBUG THEN
  241.                con.ValToStr (ErrNum, FALSE, zahlstr, 16, 4, "0", err);
  242.                DbgWrite (zahlstr);
  243.                DbgWriteLn;
  244.             END;
  245.             INC (pos, 2);
  246.             ErrMsg := NIL;
  247.          END;
  248.          IF (CAST(LONGINTPtr, ADDRESS(ErrorBase)+ADDRESS(pos))^ # CAST(LONGINT,"ÁERR")) &
  249.             (CAST(INTEGERPtr, ADDRESS(ErrorBase)+ADDRESS(pos))^ # -1) THEN
  250.             Allocate (next, SIZE(ErrorDescription));
  251.             ParseErrorPart (next, pos);
  252.          END;
  253.       END;
  254.    END ParseErrorPart;
  255. (* **)
  256.  
  257.    PROCEDURE ParseError (nr : CARDINAL; VAR pos : CARDINAL);
  258. (** Funktion: Analysiert die Fehlercodierung *)
  259.    VAR   zahlstr  : ARRAY [0..10] OF CHAR;
  260.          err      : BOOLEAN;
  261.    BEGIN
  262.       IF DEBUG THEN
  263.          DbgWrite ("      ParseError\n");
  264.       END;
  265.  
  266.       IF CAST(LONGINTPtr, ADDRESS(ErrorBase)+ADDRESS(pos))^ # CAST(LONGINT, "ÁERR") THEN
  267.          (* Ugly Incredible Unexpected Catastrophalicy Error:
  268.           * Confused With ErrorFile.
  269.           *)
  270.          WITH ErrorArray^[nr] DO
  271.             offset := -1;
  272.             ErrNum := -1;
  273.             ErrMsg := NIL;
  274.             next   := NIL;
  275.          END;
  276.          RETURN;
  277.       ELSE
  278.          INC (pos, 4);
  279.       END;
  280.  
  281.       WITH ErrorArray^[nr] DO
  282.          offset   := CAST(LONGINTPtr, ADDRESS(ErrorBase)+ADDRESS(pos))^;
  283.          IF DEBUG THEN
  284.             DbgWrite ("         Offset = ");
  285.             zahlstr := "";
  286.             con.ValToStr (offset, FALSE, zahlstr, 16, 4, "0", err);
  287.             DbgWrite (zahlstr);
  288.             DbgWriteLn;
  289.          END;
  290.          INC (pos, 4);
  291.          ParseErrorPart (ADR(ErrorArray^[nr]), pos);
  292.       END;
  293.    END ParseError;
  294. (* **)
  295.  
  296. VAR   hdl         : dd.FileHandlePtr;
  297.       fib         : dd.FileInfoBlockPtr;
  298.       li          : LONGINT;
  299.       pos, i      : CARDINAL;
  300.       taglist     : ARRAY [0..10] OF LONGINT;
  301. VAR   zahlstr  : ARRAY [0..10] OF CHAR;
  302.       err      : BOOLEAN;
  303. BEGIN
  304.    IF DEBUG THEN
  305.       DbgWrite ("Loading ErrorFile ... Filename = ");
  306.       DbgWrite (filename);
  307.       DbgWriteLn;
  308.    END;
  309.    IF ErrorArray # NIL THEN
  310.       Deallocate (ErrorArray);
  311.    END;
  312.    MAXERRORS := 0;
  313.    ERRORFILE := "";
  314.  
  315.    hdl := dl.Open(ADR(filename), dd.readOnly);
  316.    IF hdl = NIL THEN
  317.       RETURN dd.warn;
  318.    END;
  319.  
  320.    fib := dl.AllocDosObject(dd.dosFib, TAG(taglist, tagEnd));
  321.    IF fib = NIL THEN
  322.       dl.Close (hdl);
  323.       RETURN dd.fail;
  324.    END;
  325.  
  326.    IF dl.ExamineFH(hdl, fib) THEN
  327.       Allocate (ErrorBase, fib^.size);
  328.       IF ErrorBase = NIL THEN
  329.          dl.Close (hdl);
  330.          dl.FreeDosObject (dd.dosFib, fib);
  331.          RETURN dd.fail;
  332.       END;
  333.       IF DEBUG THEN
  334.          DbgWrite ("   Memory allocated.\n");
  335.       END;
  336.       li := dl.Read(hdl, ErrorBase, fib^.size);
  337.       dl.Close (hdl);
  338.       IF li < fib^.size THEN
  339.          IF DEBUG THEN
  340.             DbgWrite ("   read error\n");
  341.          END;
  342.          Deallocate (ErrorBase);
  343.          dl.FreeDosObject (dd.dosFib, fib);
  344.          RETURN dd.fail;
  345.       END;
  346.  
  347.       pos := 0;
  348.       WHILE (LONGINT(pos) < fib^.size) DO
  349.          IF ErrorBase^[pos] = "Á" THEN
  350.             IF (ErrorBase^[pos+1] = "E") &
  351.                (ErrorBase^[pos+2] = "R") &
  352.                (ErrorBase^[pos+3] = "R") THEN
  353.                INC (MAXERRORS);
  354.                INC (pos,3);
  355.             END;
  356.          END;
  357.          INC (pos);
  358.       END;
  359.  
  360.       Allocate (ErrorArray, SIZE(ErrorDescription) * MAXERRORS);
  361.       IF DEBUG THEN
  362.          DbgWrite ("   Memory for ErrorArray allocated.\n");
  363.       END;
  364.       IF ErrorArray = NIL THEN
  365.          Deallocate (ErrorBase);
  366.          dl.FreeDosObject (dd.dosFib, fib);
  367.          RETURN dd.fail;
  368.       END;
  369.       IF DEBUG THEN
  370.          DbgWrite ("   converting into ErrorArray ...\n");
  371.       END;
  372.       pos := 4;
  373.       FOR i := 0 TO MAXERRORS-1 DO
  374.          ParseError (i, pos);
  375.          IF ErrorArray^[i].offset = -1 THEN
  376.             (* Verdammt schwerer Fehler beim Parsing aufgetreten! *)
  377.             IF DEBUG THEN
  378.                DbgWrite ("HARD CATASTROPHIE PARSINGERROR !!!!\n");
  379.             END;
  380.             MAXERRORS := -1;
  381.             i := 6000;
  382.          END;
  383.       END;
  384.       dl.FreeDosObject (dd.dosFib, fib);
  385.       str.Copy (ERRORFILE, filename);
  386.       RETURN dd.ok;
  387.    END;
  388. END LoadErrorFile;
  389. (* **)
  390.  
  391. (* ---------------------------------------------------------------------- *)
  392.  
  393. PROCEDURE GetErrorMessage (nr : INTEGER;
  394.                            VAR msg : ARRAY OF CHAR);
  395. (**   Funktion : Ermittelt den zur Fehlernummer <nr> zugehörigen
  396.   *              Fehlertext.
  397.   *)
  398. VAR   i     : CARDINAL;
  399.       pos   : CARDINAL;
  400.       next  : LONGINT;
  401.       currNr: INTEGER;
  402. BEGIN
  403.    IF DEBUG THEN
  404.       DbgWrite ("   GetErrorMessage called ...\n");
  405.    END;
  406.    pos := 0;
  407.    LOOP
  408.       next := CAST(LONGINTPtr, ADDRESS(ErrorMsgBase)+ADDRESS(pos))^;
  409.       INC (pos, 4);
  410.       currNr := CAST(INTEGERPtr, ADDRESS(ErrorMsgBase)+ADDRESS(pos))^;
  411.       INC (pos, 2);
  412.       IF (currNr = nr) OR (currNr = -1) THEN EXIT; END;
  413.       pos := next;
  414.    END;
  415.    i := 0;
  416.    WHILE ErrorMsgBase^[pos-1] # 0C DO
  417.       msg[i] := ErrorMsgBase^[pos];
  418.       INC (i);
  419.       INC (pos);
  420.    END;
  421. END GetErrorMessage;
  422. (* **)
  423.  
  424. (* ---------------------------------------------------------------------- *)
  425.  
  426. PROCEDURE GetM2Error (nr : CARDINAL;
  427.                       VAR off : LONGINT;
  428.                       VAR errnum : INTEGER;
  429.                       VAR errstr : ARRAY OF CHAR);
  430. (**   Funktion : Ermittelt den Byteoffset, die Fehlernummer und
  431.   *              den Fehlertext zum nr-sten Fehler.
  432.   *)
  433. VAR   helpstr     : String;
  434.       helperrnum  : INTEGER;
  435.       ed          : ErrorDescriptionPtr;
  436. BEGIN
  437.    WITH ErrorArray^[nr] DO
  438.       off         := offset;
  439.       errnum      := ErrNum;
  440.       errstr[0]   := 0C;
  441.       helperrnum  := ErrNum;
  442.    END;
  443.    ed := ADR(ErrorArray^[nr]);
  444.    LOOP
  445.       IF helperrnum = 0 THEN
  446.          str.Concat (errstr, ed^.ErrMsg^);
  447.       ELSE
  448.          GetErrorMessage (helperrnum, helpstr);
  449.          str.Concat (errstr, helpstr);
  450.       END;
  451.       IF ed^.next = NIL THEN EXIT; END;
  452.       str.ConcatChar(errstr, " ");
  453.       ed := ed^.next;
  454.       helperrnum := ed^.ErrNum;
  455.    END;
  456. END GetM2Error;
  457. (* **)
  458.  
  459. (* ---------------------------------------------------------------------- *)
  460.  
  461. PROCEDURE GetM2ErrorByte (offset : LONGINT;
  462.                           VAR off      : LONGINT;
  463.                           VAR errnum   : INTEGER;
  464.                           VAR errstr   : ARRAY OF CHAR);
  465. (**   Funktion: Wie GetM2Error, jedoch anhand eines vorgegebenen
  466.   *             Byte-Offsets.
  467.   *)
  468. VAR   i, helperrnum  : INTEGER;
  469.       helpstr        : String;
  470.       ed             : ErrorDescriptionPtr;
  471. BEGIN
  472.    IF DEBUG THEN
  473.       DbgWrite ("GetM2ErrorByte called.\n");
  474.    END;
  475.    i := 0;
  476.    WHILE (offset > ErrorArray^[i].offset) & (i < MAXERRORS) DO
  477.       INC (i);
  478.    END;
  479.    IF i = MAXERRORS THEN
  480.       off := -1;
  481.    ELSE
  482.       WITH ErrorArray^[i] DO
  483.          off      := offset;
  484.          errnum   := ErrNum;
  485.  
  486.          errstr[0]   := 0C;
  487.          helperrnum  := ErrNum;
  488.       END;
  489.       ed := ADR(ErrorArray^[i]);
  490.       LOOP
  491.          IF helperrnum = 0 THEN
  492.             str.Concat (errstr, ed^.ErrMsg^);
  493.          ELSE
  494.             GetErrorMessage (helperrnum, helpstr);
  495.             str.Concat (errstr, helpstr);
  496.          END;
  497.          IF ed^.next = NIL THEN EXIT; END;
  498.          str.ConcatChar(errstr, " ");
  499.          ed := ed^.next;
  500.          helperrnum := ed^.ErrNum;
  501.       END;
  502.    END;
  503. END GetM2ErrorByte;
  504. (* **)
  505.  
  506. (* ---------------------------------------------------------------------- *)
  507.  
  508. PROCEDURE GetRexxCommand (string : ARRAY OF CHAR; VAR cl : INTEGER) : Commands;
  509. (**   Funktion : Extrahiert das Kommando aus der eingegangenen
  510.   *              Rexx-Nachricht. Ist es "RexxM2Error" nicht bekannt,
  511.   *              wird eine Fehlermeldung ausgegeben.
  512.   *)
  513. VAR   i        : INTEGER;
  514.       commstr  : String;
  515.       b        : BOOLEAN;
  516. BEGIN
  517.    i := 0;
  518.    WHILE (string[i] # " ") & (string[i] # 0C) DO
  519.       commstr[i] := string[i];
  520.       INC (i);
  521.    END;
  522.    commstr[i] := 0C;
  523.    cl := str.Length(commstr) + 1;   (* wird für rdargs benötigt *)
  524.  
  525.    IF str.Compare(commstr, "ERROR") = 0 THEN RETURN ERROR;
  526.    ELSIF str.Compare(commstr, "ERRORS") = 0 THEN RETURN ERRORS;
  527.    ELSIF str.Compare(commstr, "RESET") = 0 THEN RETURN RESET;
  528.    ELSIF str.Compare(commstr, "LOAD") = 0 THEN RETURN LOAD;
  529.    ELSIF str.Compare(commstr, "QUIT") = 0 THEN RETURN QUIT;
  530.    ELSIF str.Compare(commstr, "QUERY") = 0 THEN RETURN QUERY;
  531.    ELSE
  532.       b := Arts.Requester (ADR("REXXM2ERROR detected an unknown command:"),
  533.                            ADR(string), NIL, ADR("Huch!"));
  534.       RETURN UNKNOWN;
  535.    END;
  536. END GetRexxCommand;
  537. (* **)
  538.  
  539. (* ---------------------------------------------------------------------- *)
  540. (* ----- AREXX-Kommandos ------------------------------------------------ *)
  541. (* ---------------------------------------------------------------------- *)
  542.  
  543.  
  544. PROCEDURE Quit (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  545. (**   Format      : QUIT
  546.       Schablone   : -
  547.       Funktion    : RexxM2Error beenden
  548.       Beschreibung: Beendet dieses Programm.
  549. *)
  550. BEGIN
  551.    rs1 := dd.ok;
  552. END Quit;
  553. (* **)
  554.  
  555. (* ---------------------------------------------------------------------- *)
  556.  
  557. VAR   CURRERR  := LONGINT{0};
  558.  
  559. PROCEDURE Error (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  560. (**   Format      : ERROR [ NEXT | PREV | FIRST | BYTE=<Byte-Offset> | NUMBER=<Nummer> ]
  561.       Schablone   : NEXT/S,PREV/S,FIRST/S,BYTE/K/N,NUMBER/K/N
  562.       Funktion    : Liefert eine Fehlermeldung
  563.       Beschreibung: Je nach verwendeter Option liefert ERROR den nächsten
  564.                     (NEXT), vorhergehenden (PREV) oder ersten (FIRST)
  565.                     Fehler.
  566.                     Mit der Option BYTE kann ein Offset angegeben werden.
  567.                     Es wird dann der im Quelltext hierauf folgende Fehler
  568.                     zurückgegeben.
  569.                     Mit NUMBER kann ein bestimmter Fehler angesprungen
  570.                     werden: Der <Nummer>. Fehler.
  571.  
  572.                     Wurde noch ein Fehler gefunden, so liefert ERROR das
  573.                     Ergebnis in einem String folgender Form:
  574.  
  575.                         OFFSET/A,ERRNUM/A,ERRMSG/A
  576.  
  577.                     wobei OFFSET den Byteoffset im Quelltext enthält,
  578.                     ERRNUM die Fehlernummer und ERRMSG den Fehlertext.
  579.  
  580.                     Wenn es keinen weiteren Fehler mehr gibt, ist rc = 5.
  581. *)
  582. CONST MAXOPTIONS  = 5;
  583.       next        = 0;
  584.       prev        = 1;
  585.       first       = 2;
  586.       byte        = 3;
  587.       number      = 4;
  588. VAR   template    : String;
  589.       options     : ARRAY [0..MAXOPTIONS-1] OF LONGINT;
  590.       rs2str      : ARRAY [0..255] OF CHAR;
  591.       errnum      : INTEGER;
  592.       errstr      : ARRAY [0..127] OF CHAR;
  593.       zahlstr     : ARRAY [0..10] OF CHAR;
  594.       err         : BOOLEAN;
  595.       i           : INTEGER;
  596.       offset      : LONGINT;
  597.       success     : dd.RDArgsPtr;
  598. BEGIN
  599.    IF DEBUG THEN
  600.       DbgWrite ("REXX: ERROR\n");
  601.    END;
  602.    IF MAXERRORS = 0 THEN
  603.       (* Es gibt überhaupt keine Fehler! *)
  604.       rs1 := dd.warn;
  605.       RETURN;
  606.    ELSE
  607.  
  608.       rs1 := dd.ok;
  609.       template := "NEXT/S,PREV/S,FIRST/S,BYTE/K/N,NUMBER/K/N";
  610.       FOR i := 0 TO MAXOPTIONS-1 DO
  611.          options[i] := 0;
  612.       END;
  613.       success := dl.ReadArgs(ADR(template), ADR(options), rdargs);
  614.       IF success = NIL THEN
  615.          TemplateError;
  616.          rs1 := dd.error;
  617.          RETURN;
  618.       END;
  619.  
  620.       IF options[prev] # 0 THEN
  621.          DEC (CURRERR);
  622.          IF CURRERR < 0 THEN
  623.             rs1 := dd.warn;
  624.             CURRERR := 0;
  625.          ELSE
  626.             GetM2Error (CURRERR, offset, errnum, errstr);
  627.          END;
  628.  
  629.       ELSIF options[first] # 0 THEN
  630.          CURRERR := 0;
  631.          GetM2Error (CURRERR, offset, errnum, errstr);
  632.          INC (CURRERR);
  633.  
  634.       ELSIF options[byte] # 0 THEN
  635.          IF DEBUG THEN
  636.             DbgWrite ("BYTE\n");
  637.          END;
  638.          GetM2ErrorByte (CAST(LONGINTPtr, options[byte])^, offset, errnum, errstr);
  639.  
  640.       ELSIF options[number] # 0 THEN
  641.          IF DEBUG THEN
  642.             DbgWrite ("NUMBER\n");
  643.          END;
  644.          IF (CAST(LONGINTPtr,options[number])^ >= MAXERRORS) OR
  645.             (CAST(LONGINTPtr,options[number])^ < 0) THEN
  646.             rs1 := dd.warn;
  647.          ELSE
  648.             CURRERR := CAST(LONGINTPtr, options[number])^;
  649.             GetM2Error (CURRERR, offset, errnum, errstr);
  650.             INC (CURRERR);
  651.          END;
  652.  
  653.       ELSE
  654.          IF CURRERR >= MAXERRORS THEN
  655.             rs1 := dd.warn;
  656.          ELSE
  657.             GetM2Error (CURRERR, offset, errnum, errstr);
  658.             INC (CURRERR );
  659.          END;
  660.       END;
  661.       dl.FreeArgs (rdargs);
  662.    END;
  663.  
  664.    IF rs1 = dd.ok THEN
  665.       IF errnum >= 0 THEN
  666.          IF result THEN
  667.             con.ValToStr (offset, FALSE, rs2str, 10, -6, 0C, err);
  668.             str.ConcatChar (rs2str, " ");
  669.             con.ValToStr (errnum, FALSE, zahlstr, 10, -6, 0C, err);
  670.             str.Concat (rs2str, zahlstr);
  671.             str.ConcatChar (rs2str, " ");
  672.             str.Concat (rs2str, errstr);
  673.             rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(rs2str), str.Length(rs2str)));
  674.          END;
  675.       ELSE
  676.          rs1 := dd.fail;
  677.       END;
  678.    END;
  679. END Error;
  680. (* **)
  681.  
  682. (* ---------------------------------------------------------------------- *)
  683.  
  684. PROCEDURE Errors (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  685. (**   Format      : ERRORS
  686.       Schablone   : -
  687.       Funktion    : Liefert die Anzahl der Fehler.
  688. *)
  689. VAR   zahlstr  : ARRAY [0..10] OF CHAR;
  690.       err      : BOOLEAN;
  691. BEGIN
  692.    IF DEBUG THEN
  693.       DbgWrite ("REXX: ERRORS\n");
  694.    END;
  695.    rs1 := dd.ok;
  696.    IF result THEN
  697.       con.ValToStr (MAXERRORS, FALSE, zahlstr, 10, -5, 0C, err);
  698.       rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(zahlstr), str.Length(zahlstr)));
  699.    END;
  700. END Errors;
  701. (* **)
  702.  
  703. (* ---------------------------------------------------------------------- *)
  704.  
  705. PROCEDURE Reset (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  706. (**   Format      : RESET [ NUMBER = <Nummer> ]
  707.       Schablone   : NUMBER/K/N
  708.       Funktion    : Setzt den aktuelle Fehler neu.
  709.       Beschreibung: Hiermit wird CURRERR mit einem neuen Wert versehen.
  710.                     Die Option NUMBER setzt CURRERR auf den angegebenen
  711.                     Wert.
  712.                     Ohne Option wird CURRERR auf 0 gesetzt (was dem
  713.                     ersten Fehler entspricht).
  714. *)
  715. CONST MAXOPTIONS  = 1;
  716.       number      = 0;
  717. VAR   template    : String;
  718.       options     : ARRAY [0..MAXOPTIONS-1] OF LONGINT;
  719.       success     : dd.RDArgsPtr;
  720. BEGIN
  721.    IF DEBUG THEN
  722.       DbgWrite ("REXX: RESET\n");
  723.    END;
  724.    template := "NUMBER/K/N";
  725.    options[number] := 0;
  726.  
  727.    success := dl.ReadArgs(ADR(template), ADR(options), rdargs);
  728.    IF success = NIL THEN
  729.       TemplateError;
  730.       rs1 := dd.error;
  731.       RETURN;
  732.    ELSE
  733.       CURRERR := CAST(LONGINTPtr, options[number])^;
  734.       IF (CURRERR >= MAXERRORS) OR (CURRERR < 0) THEN
  735.          CURRERR := 0;
  736.          rs1 := dd.warn;
  737.       ELSE
  738.          rs1 := dd.ok;
  739.       END;
  740.    END;
  741.    dl.FreeArgs (rdargs);
  742. END Reset;
  743. (* **)
  744.  
  745. (* ---------------------------------------------------------------------- *)
  746.  
  747. PROCEDURE Load (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  748. (**   Format      : LOAD <Moduldatei> | <Fehlermeldungen> ERRORMSG
  749.       Schablone   : FILE/A,ERRORMSG/S
  750.       Funktion    : Lädt die Fehlerdatei.
  751.       Beschreibung: Zu dem angegebenen Modul wird die zugehörige Fehler-
  752.                     datei geladen (gleicher Dateiname plus "E").
  753.                     Gibt es keine, wird rc auf 5 gesetzt; bei einem
  754.                     Lesefehler auf 20.
  755.                     Wird die Option ERRORMSG angegeben, so handelt es
  756.                     sich bei der Datei um die Datei mit den Fehler-
  757.                     meldungen.
  758.                     Voreingestellt ist hier M2:Fehler-Meldungen.
  759. *)
  760. CONST MAXOPTIONS  = 2;
  761.       file        = 0;
  762.       errormsg    = 1;
  763. VAR   template    : String;
  764.       options     : ARRAY [0..MAXOPTIONS-1] OF LONGINT;
  765.       filename    : ARRAY [0..255] OF CHAR;
  766.       success     : dd.RDArgsPtr;
  767. BEGIN
  768.    IF DEBUG THEN
  769.       DbgWrite ("REXX: LOAD\n");
  770.    END;
  771.    template := "FILE/A,ERRORMSG/S";
  772.    options[file] := 0;
  773.    options[errormsg] := 0;
  774.    CURRERR := 0;
  775.  
  776.    success := dl.ReadArgs(ADR(template), ADR(options), rdargs);
  777.    IF success = NIL THEN
  778.       TemplateError;
  779.       rs1 := dd.error;
  780.    ELSE
  781.       str.Copy (filename, CAST(StringPtr, options[file])^);
  782.       IF options[errormsg] # 0 THEN
  783.          rs1 := LoadErrorMsgFile (filename);
  784.       ELSE
  785.          str.ConcatChar (filename, "E");
  786.          rs1 := LoadErrorFile (filename);
  787.       END;
  788.    END;
  789.    dl.FreeArgs (rdargs);
  790. END Load;
  791. (* **)
  792.  
  793. (* ---------------------------------------------------------------------- *)
  794.  
  795. PROCEDURE Query (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  796. (**   Format      : QUERY FILE | CURRERR | MAXERRORS | ERRORMSGFILE
  797.       Schablone   : FILE/S,CURRERR/S,MAXERRORS/S,ERRORMSGFILE/S
  798.       Funktion    : Interne Variablen ermitteln.
  799.       Beschreibung:
  800.  
  801.       Dieses Kommando gibt Auskunft über interne Variablen.
  802.       FILE gibt in RESULT den Namen der geladenen Fehlerdatei (mit
  803.       Endung "E") zurück oder eine Warnung, wenn keine Fehlerdatei ge-
  804.       laden ist.
  805.       Mit CURRERR kann der interne Fehlerzähler abgefragt werden.
  806.       MAXERROS liefert wie ERRORS die Anzahl der Fehler und mit
  807.       ERRORMSGFILE kann der Name der Datei abgefragt werden, die zur
  808.       Bestimmung der Fehlertexte verwendet wird.
  809. *)
  810.  
  811. CONST MAXOPTIONS  = 4;
  812.       optFile           = 0;
  813.       optCurrErr        = 1;
  814.       optMaxErrors      = 2;
  815.       optErrorMsgFile   = 3;
  816.  
  817. VAR   template : String;
  818.       success  : dd.RDArgsPtr;
  819.       options  : ARRAY [0..MAXOPTIONS-1] OF LONGINT;
  820.       zahlstr  : ARRAY [0..10] OF CHAR;
  821.       err      : BOOLEAN;
  822.       i        : CARDINAL;
  823. BEGIN
  824.    IF DEBUG THEN
  825.       DbgWrite ("REXX: QUERY\n");
  826.    END;
  827.    template := "FILE/S,CURRERR/S,MAXERRORS/S,ERRORMSGFILE/S";
  828.    FOR i := 0 TO MAXOPTIONS-1 DO
  829.       options[i] := 0;
  830.    END;
  831.    success := dl.ReadArgs(ADR(template), ADR(options), rdargs);
  832.    IF success = NIL THEN
  833.       TemplateError;
  834.       rs1 := dd.error;
  835.    ELSE
  836.       IF DEBUG THEN
  837.          DbgWrite ("   Template erfolgreich\n");
  838.       END;
  839.       IF options[optFile] # 0 THEN
  840.          IF DEBUG THEN
  841.             DbgWrite ("   FILE\n");
  842.          END;
  843.          IF str.Length(ERRORFILE) > 0 THEN
  844.             rs1 := dd.ok;
  845.             rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(ERRORFILE), str.Length(ERRORFILE)));
  846.          ELSE
  847.             rs1 := dd.warn;
  848.          END;
  849.       ELSIF options[optCurrErr] # 0 THEN
  850.          IF DEBUG THEN
  851.             DbgWrite ("   CURRERR\n");
  852.          END;
  853.          con.ValToStr (CURRERR, FALSE, zahlstr, 10, -5, 0C, err);
  854.          rs1 := dd.ok;
  855.          IF result THEN
  856.             rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(zahlstr), str.Length(zahlstr)));
  857.          END;
  858.       ELSIF options[optMaxErrors] # 0 THEN
  859.          IF DEBUG THEN
  860.             DbgWrite ("MAXERRORS\n");
  861.          END;
  862.          con.ValToStr (MAXERRORS, FALSE, zahlstr, 10, -5, 0C, err);
  863.          rs1 := dd.ok;
  864.          IF result THEN
  865.             rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(zahlstr), str.Length(zahlstr)));
  866.          END;
  867.       ELSIF options[optErrorMsgFile] # 0 THEN
  868.          IF DEBUG THEN
  869.             DbgWrite ("ERRORMSGFILE\n");
  870.          END;
  871.          IF str.Length(ERRORMSGFILE) > 0 THEN
  872.             rs1 := dd.ok;
  873.             IF result THEN
  874.                rs2 := CAST(LONGINT, rxl.CreateArgstring(ADR(ERRORMSGFILE), str.Length(ERRORMSGFILE)));
  875.             END;
  876.          ELSE
  877.             rs1 := dd.warn;
  878.          END;
  879.       END;
  880.    END;
  881.    IF DEBUG THEN
  882.       DbgWrite ("   freeing rdargs\n");
  883.    END;
  884.    dl.FreeArgs (rdargs);
  885. END Query;
  886.  
  887. (* ---------------------------------------------------------------------- *)
  888.  
  889. PROCEDURE Unknown (VAR rs1, rs2 : LONGINT; result : BOOLEAN; rdargs : dd.RDArgsPtr);
  890. (**   Format      : intern
  891.       Schablone   : -
  892.       Funktion    : Wird bei nicht identifizierten Kommandos aufgerufen.
  893. *)
  894. BEGIN
  895.    rs1 := dd.fail;
  896. END Unknown;
  897. (* **)
  898.  
  899. (* ---------------------------------------------------------------------- *)
  900.  
  901. CONST (* Konstanten für template-options *)
  902.       opt_errormsgfile  = 0;
  903.       opt_debug         = 1;
  904.  
  905. VAR   rexxPort    := ed.MsgPortPtr{NIL};
  906.       rexxproc    : ARRAY Commands OF RexxCommProc;
  907.       template    := String{"ERRORMSGFILE/K,DEBUG/S"};
  908.       options     : ARRAY [0..2] OF LONGINT;
  909.       help        : String;
  910.       rdargs      := dd.RDArgsPtr{NIL};
  911.       success     : dd.RDArgsPtr;
  912.       errorMsgFile: String;
  913.       done        : BOOLEAN;
  914.       sigmask,
  915.       rcvdsigs    : LONGSET;
  916.       msg         : ADDRESS;
  917.       rexxCommand : Commands;
  918.       arg0        : String;
  919.       taglist     : ARRAY [0..10] OF LONGINT;
  920.       result      : BOOLEAN;
  921.       cl          : INTEGER;  (* Länge des AREXX-Kommandos *)
  922. BEGIN
  923.    IF Arts.wbStarted THEN
  924.       CheckToolTypes (errorMsgFile);
  925.  
  926.    ELSE
  927.       (* Übergebene Parameter überprüfen: *)
  928.       help := "RexxM2Error V 0.97 © 1994 Fin Schuppenhauer";
  929.       rdargs := dl.AllocDosObject(dd.dosRdArgs, TAG(taglist, tagEnd));
  930.       IF rdargs # NIL THEN
  931.          rdargs^.extHelp := ADR(help);
  932.          (* ^^^ Wieso tut das nicht funktionieren ? *)
  933.          options[opt_errormsgfile] := ADR("M2:Fehler-Meldungen");
  934.          success := dl.ReadArgs(ADR(template), ADR(options), rdargs);
  935.          IF success = NIL THEN
  936.             TemplateError;
  937.             Arts.returnVal := dd.error;
  938.             RETURN;
  939.          ELSE
  940.             (* Parameter auswerten: *)
  941.             IF options[opt_errormsgfile] # 0 THEN
  942.                str.Copy (errorMsgFile, CAST(StringPtr, options[opt_errormsgfile])^);
  943.             END;
  944.             DEBUG := options[opt_debug] # 0;
  945.          END;
  946.          dl.FreeArgs (rdargs);
  947.          dl.FreeDosObject (dd.dosRdArgs, rdargs);
  948.          rdargs := NIL;
  949.       END;
  950.    END;
  951.    
  952.    IF DEBUG THEN
  953.       dbghdl := dl.Output();
  954.    END;
  955.  
  956.    
  957.    (* Einen Arexx-Port creieren: *)
  958.    el.Forbid();
  959.       rexxPort := el.FindPort(ADR("REXXM2ERROR"));
  960.    el.Permit();
  961.    IF rexxPort # NIL THEN
  962.       done := Arts.Requester(ADR("REXXM2ERROR detected an error:"),
  963.                      ADR("Program already running!"), NIL, ADR("Ohh"));
  964.       rexxPort := NIL; 
  965.       (* Der CLOSE-Teil darf auf gar keinen Fall diesen Port entfernen! *)
  966.       RETURN;
  967.    END;
  968.    rexxPort := es.CreatePort(ADR("REXXM2ERROR"), 0);
  969.  
  970.    IF LoadErrorMsgFile (errorMsgFile) # 0 THEN
  971.       es.DeletePort (rexxPort);
  972.       rexxPort := NIL;
  973.       Arts.returnVal := 20;
  974.       RETURN;
  975.    END;
  976.  
  977.    rexxproc[ERROR]      := Error;
  978.    rexxproc[ERRORS]     := Errors;
  979.    rexxproc[RESET]      := Reset;
  980.    rexxproc[LOAD]       := Load;
  981.    rexxproc[QUIT]       := Quit;
  982.    rexxproc[QUERY]      := Query;
  983.    rexxproc[UNKNOWN]    := Unknown;
  984.  
  985.    sigmask := LONGSET{dd.ctrlC, rexxPort^.sigBit};
  986.    done := FALSE;
  987.    WHILE ~done DO
  988.       IF DEBUG THEN
  989.          DbgWrite ("Waiting for messages... ");
  990.       END;
  991.       (* Hier warten wir auf eine Arexx-Nachricht oder ein CTRL-C: *)
  992.       rcvdsigs := el.Wait(sigmask);
  993.       IF DEBUG THEN
  994.          DbgWrite (" received.\n");
  995.       END;
  996.  
  997.       IF dd.ctrlC IN rcvdsigs THEN
  998.          (* Ein CTRL-C wurde uns gemeldet; wir werden das Programm
  999.           * beenden:
  1000.           *)
  1001.          done := TRUE;
  1002.       END;
  1003.  
  1004.       LOOP
  1005.          msg := el.GetMsg(rexxPort);
  1006.          IF msg = NIL THEN EXIT; END;
  1007.  
  1008.          IF rxl.IsRexxMsg(msg) THEN
  1009.             (* Die eingegangene Nachricht ist eine Arexx-Nachricht: *)
  1010.  
  1011.             WITH CAST(rxd.RexxMsgPtr, msg)^ DO
  1012.                str.Copy (arg0, CAST(StringPtr, args[0])^);
  1013.                rexxCommand := GetRexxCommand(arg0, cl);
  1014.  
  1015.                IF rxd.comm = action.command THEN
  1016.                   (* Eine Arexx-Kommando; alles steht in args[0]. *)
  1017.                   result := (rxd.result IN action.modifier);
  1018.                   rdargs := dl.AllocDosObject(dd.dosRdArgs, TAG(taglist, tagEnd));
  1019.                   IF rdargs # NIL THEN
  1020.                      (* Jetzt modifizieren wir rdargs, da unsere Eingabe
  1021.                       * für ReadArgs() nicht vom Terminal, sondern hier
  1022.                       * aus unserem Programm kommt:
  1023.                       *)
  1024.                      str.ConcatChar (arg0, "\n");
  1025.                      WITH rdargs^.source DO
  1026.                         (* Das Kommando selber soll nicht Teil unseres
  1027.                          * zu überprüfenden Templates sein:
  1028.                          *)
  1029.                         buffer := ADR(arg0) + ADDRESS(cl);
  1030.                         length := str.Length(CAST(StringPtr, buffer)^);
  1031.                         curChr := 0;
  1032.                      END;
  1033.                      IF DEBUG THEN
  1034.                         DbgWrite ("Calling Rexx-Proc with template: ");
  1035.                         DbgWrite (CAST(StringPtr, rdargs^.source.buffer)^);
  1036.                         DbgWriteLn;
  1037.                      END;
  1038.  
  1039.                      (* Jetzt rufen wir die implementierten ARexx-
  1040.                       * Routinen auf:
  1041.                       *)
  1042.                      rexxproc[rexxCommand] (result1, result2, result, rdargs);
  1043.                      IF (rexxCommand = QUIT) & (result1 = 0) THEN
  1044.                         done := TRUE;
  1045.                      END;
  1046.                      dl.FreeDosObject(dd.dosRdArgs, rdargs);
  1047.                      rdargs := NIL;
  1048.                   ELSE
  1049.                      IF DEBUG THEN
  1050.                         DbgWrite ("rdargs not available.\n");
  1051.                      END;
  1052.                      result1 := 20;
  1053.                   END;
  1054.                ELSIF rxd.func = action.command THEN
  1055.                   (* Wann kann dieses passieren ??? *)
  1056.                   IF DEBUG THEN
  1057.                      DbgWrite ("rxd.func\n");
  1058.                   END;
  1059.                   (* Eine Arexx-Funktion; das Kommando steht in args[0],
  1060.                    * die Parameter in args[>0].
  1061.                    *)
  1062.                   result1 := 20;
  1063.                END;
  1064.             END;
  1065.          END;
  1066.          el.ReplyMsg (msg);
  1067.       END;
  1068.    END;
  1069.  
  1070.    IF DEBUG THEN
  1071.       DbgWrite ("Leaving programm...\n");
  1072.    END;
  1073.    es.DeletePort (rexxPort);
  1074.    rexxPort := NIL;
  1075.  
  1076. CLOSE
  1077.    IF ErrorMsgBase # NIL THEN
  1078.       Deallocate (ErrorMsgBase);
  1079.    END;
  1080.    IF ErrorArray # NIL THEN
  1081.       Deallocate (ErrorArray);
  1082.    END;
  1083.  
  1084.    IF rdargs # NIL THEN
  1085.       dl.FreeDosObject (dd.dosRdArgs, rdargs);
  1086.       rdargs := NIL;
  1087.    END;
  1088.    IF rexxPort # NIL THEN
  1089.       es.DeletePort (rexxPort);
  1090.       rexxPort := NIL;
  1091.    END;
  1092. END RexxM2Error.
  1093.  
  1094.