(*************************************************************************

:Program.    EdParser.mod
:Contents.   Command-Parser for AmokEd
:Author.     Hartmut Goebel, Werner Speer
:Language.   Oberon
:Translator. Amiga Oberon Compiler V2.13
:History.    V1.0     Oct 1990 Werner Speer
:History.    V1.1  12 Dec 1990 Hartmut Goebel [hG] größere Änderungen
:History.    V1.2  07 Feb 1991 [hG] BreakOut geändert
:History.    V1.3  09 Feb 1991 [hG] doCommand nicht mehr Rekursiv
:History.    V1.4  04 Mar 1991 [hG] BreakOut von Matt Dillon integriert
:History.    V1.5  20 Apr 1991 [hG] +implizite Macro-/Appl-Aufrufe
:History.    V1.5b 30 May 1991 [hG] -Bug in BreakOutVar, ^Vars
:History.    V1.5c 11 Jun 1991 [hG] ^Befehls-Liste (soweit mögl. CONST)
:History.    V1.5d 23 Jun 1991 [hG] -Bug in BreakOutVar (again)
:History.    V1.6  12 Oct 1991 [hG] +AEd1-Appl-BreakOut
:Date.       01 Feb 1992 01:53:19

*************************************************************************)

MODULE EdParser;

IMPORT
  e  : Exec,
  ed1: EdCmd1,
  ed2: EdCmd2,
  ed3: EdCmd3,
  eAD: EdApplDefs,
  eAS: EdApplSub,
  edB: EdBlocks,
  edD: EdDisplay,
  edE: EdErrors,
  edF: EdFileTools,
  edG: EdGlobalVars,
  edK: EdKeyboard,
  edL: EdLowLevel,
  eMn: EdMenu,
  edM: EdMovement,
  edT: EdText,
  edR: EdRexx,
  lst: EdLists,
  ol : OberonLib,
  str: Strings,
  s  : SYSTEM;

CONST
  NumComs = 146; (* Anzahl der Kommandos *)
  MaxRec = 10;   (* maximale Rekursionstiefe *)

  (* Flags für alle Befehle *)
  rxOnly = 15;   (* Command only allowed from ARexx-port *)
  applOnly = 14; (* Command only allowed for Applications *)
  clOk = 13;     (* Command allowed in Command Line *)
  iconOk = 12;   (* Command may be executed in iconify Mode *)
  parOk = 11;    (* flag for Escimm: save rest of commandline *)
  argsNoStr = 10; (* no agument is an StringPtr - for ApplBreakOut *)
  noOddArgs = 9; (* argmuents MUST NOT start at an odd address *)

TYPE
  Com = STRUCT
    name : edG.StringPtr; (* Command-Name *)
    proc : edG.ComProc;
    args : INTEGER;       (* Number of Arguments *)
    flags: SET;
  END;

  CommandList = ARRAY NumComs OF Com;

VAR
  HashIndex, CharLast: ARRAY 27 OF INTEGER; (* Index Kommandos *)
  ComIndex: INTEGER; (* Index auf Kommando in Hash-Tabelle f. doCommand *)
  Coms: POINTER TO CommandList; (* Array mit Command-Records *)
  Quoted: BOOLEAN;   (* Kommando/Argument in Klammern *)
  OpenChar, CloseChar: CHAR; (*                        *)
  IsAux: BOOLEAN;            (* used by BreakOut only! *)
  Buffer: edG.String;        (*                        *)

(*------------------------------------------------------------------------*)
(*
TYPE
  ComList = ARRAY 10 OF Com;
CONST                      (*Funktioniert leider nicht!!*)
  Commands = ComList(
    s.ADR("ABORT"),      ed2.dAbort,        0, {iconOk},
    "ARPLOAD",    edF.dFileReq,      0, {edF.newFile},
    "ARPINSFILE", edF.dFileReq,      0, {},
    "ARPSAVE",    edF.dFileReq,      0, {edF.saveAs},
    "BACK",       edT.dBs,           0, {clOk},
    "BACKTAB",    edT.dBackTab,      0, {clOk},
    "BCOPY",      edB.dBCopy,        0, {},
    "BDELETE",    edB.dBDelete,      0, {clOk},
    "BLOCK",      edB.dBlock,        0, {},
    "BMOVE",      edB.dBMove,        0, {});
*)

CONST
  (*
   * Kommandos MÜSSEN im 1. Buchstaben alphabetish sortiert sein !!!
   *)

  Commands = CommandList(
  s.ADR("ABORT"),     NIL,(*ed2.dAbort,*)        0,{clOk,iconOk},
  s.ADR("APPL"),      NIL,(*edR.dAppl,*)         2,{clOk},
  s.ADR("APPLADD"),   NIL,(*edR.dApplAdd,*)      2,{applOnly},
  s.ADR("APPLCLOSE"), NIL,(*edR.dApplClose,*)    1,{clOk},
  s.ADR("ARPBSAVE"),  NIL,(*edF.dFileReq,*)      0,{edF.saveBlock},
  s.ADR("ARPLOAD"),   NIL,(*edF.dFileReq,*)      0,{edF.newFile},
  s.ADR("ARPINSFILE"),NIL,(*edF.dFileReq,*)      0,{},
  s.ADR("ARPSAVE"),   NIL,(*edF.dFileReq,*)      0,{edF.saveAs},
  s.ADR("ARPSOURCE"), NIL,(*edF.dFileReq,*)      0,{edF.source},
  s.ADR("ASCII"),     NIL,(*edT.dAscii,*)        0,{clOk},
  s.ADR("BACK"),      NIL,(*edT.dBs,*)           0,{clOk},
  s.ADR("BACKTAB"),   NIL,(*edM.dBackTab,*)      0,{clOk},
  s.ADR("BCOPY"),     NIL,(*edB.dBCopy,*)        0,{},
  s.ADR("BDELETE"),   NIL,(*edB.dBDelete,*)      0,{clOk},
  s.ADR("BLOCK"),     NIL,(*edB.dBlock,*)        0,{},
  s.ADR("BMOVE"),     NIL,(*edB.dBMove,*)        0,{},
  s.ADR("BOTTOM"),    NIL,(*edM.dBottom,*)       0,{},
  s.ADR("BS"),        NIL,(*edT.dBs,*)           0,{clOk},
  s.ADR("BSAVE"),     NIL,(*edF.dSave,*)         1,{clOk,noOddArgs,edF.saveBlock},
  s.ADR("BSOURCE"),   NIL,(*edB.dBSource,*)      0,{},
  s.ADR("CD"),        NIL,(*edF.dCD,*)           1,{clOk,noOddArgs},
  s.ADR("CHECKSET"),  NIL,(*eMn.dCheckItem,*)    1,{clOk,eMn.set},
  s.ADR("CHECKRESET"),NIL,(*eMn.dCheckItem,*)    1,{clOk,eMn.reset},
  s.ADR("CHECKTOGGLE"),NIL,(*eMn.dCheckItem,*)   1,{clOk},
  s.ADR("CHFILENAME"),NIL,(*edF.dChFilename,*)   1,{clOk},
  s.ADR("CLEARMAP"),  NIL,(*edK.ResetHash,*)     0,{clOk},
  s.ADR("DEL"),       NIL,(*edT.dDel,*)          0,{clOk},
  s.ADR("DELINE"),    NIL,(*edT.dDelLine,*)      0,{},
  s.ADR("DOWN"),      NIL,(*edM.dDown,*)         0,{},
  s.ADR("DOWNADD"),   NIL,(*edT.dDownAdd,*)      0,{},
  s.ADR("ESC"),       NIL,(*ed1.dEsc,*)          0,{clOk},
  s.ADR("ESCIMM"),    NIL,(*ed1.dEsc,*)          1,{parOk,ed1.escImm},
  s.ADR("EXECUTE"),   NIL,(*ed2.dExecute,*)      1,{clOk},
  s.ADR("FIND"),      NIL,(*ed2.dFind,*)         1,{},
  s.ADR("FINDR"),     NIL,(*ed2.dFind,*)         2,{ed2.replace},
  s.ADR("FINDSTR"),   NIL,(*ed2.dFindStr,*)      1,{clOk},
  s.ADR("FIRST"),     NIL,(*edM.dFirstColumn,*)  0,{clOk},
  s.ADR("FIRSTNB"),   NIL,(*edM.dFirstNb,*)      0,{clOk},
  s.ADR("GOTO"),      NIL,(*edM.dGotoLine,*)     1,{},
  s.ADR("GOTOCOL"),   NIL,(*edM.dGotoCol,*)      1,{},
  s.ADR("HEIGHT"),    NIL,(*ed2.dWinEdges,*)     1,{clOk,ed2.height},
  s.ADR("ICONIFY"),   NIL,(*ed1.dIconify,*)      0,{iconOk},
  s.ADR("IF"),        NIL,(*ed1.dIf,*)           2,{clOk,iconOk},
  s.ADR("IFELSE"),    NIL,(*ed1.dIf,*)           3,{clOk,iconOk,ed1.ifElse},
  s.ADR("INDENT"),    NIL,(*edT.dIndent,*)       0,{},
  s.ADR("INSERT"),    NIL,(*edT.dOverWrite,*)    1,{clOk,edT.insert},
  s.ADR(edF.InsFile), NIL,(*edF.dLoad,*)         1,{noOddArgs},
  s.ADR("INSLINE"),   NIL,(*edT.dInsLine,*)      0,{},
  s.ADR("JOIN"),      NIL,(*edT.dJoin,*)         0,{},
  s.ADR("JUSTIFY"),   NIL,(*edT.dJustify,*)      1,{},
  s.ADR("LAST"),      NIL,(*edM.dLastColumn,*)   0,{clOk},
  s.ADR("LEFT"),      NIL,(*edM.dLeft,*)         0,{clOk},
  s.ADR("LEFTEDGE"),  NIL,(*ed2.dWinEdges,*)     1,{clOk}+ed2.leftEdge,
  s.ADR("MAP"),       NIL,(*edK.dMap,*)          2,{clOk},
  s.ADR("MARGIN"),    NIL,(*ed1.dMargin,*)       1,{clOk},
  s.ADR("MENUADD"),   NIL,(*eMn.dMenuAdd,*)      3,{clOk},
  s.ADR("MENUADDSEP"),NIL,(*eMn.dMenuAdd,*)      1,{clOk,eMn.seperator},
  s.ADR("MENUADDT"),  NIL,(*eMn.dMenuAdd,*)      3,{clOk,eMn.checkIt},
  s.ADR("MENUCLEAR"), NIL,(*eMn.dMenuClear,*)    0,{clOk},
  s.ADR("MENUDEL"),   NIL,(*eMn.dMenuDel,*)      2,{clOk},
  s.ADR("MENUDELHDR"),NIL,(*eMn.dMenuDelHdr,*)   1,{clOk},
  s.ADR("MENUOFF"),   NIL,(*eMn.dMenuOff,*)      0,{clOk},
  s.ADR("MENUON"),    NIL,(*eMn.dMenuOn,*)       0,{clOk},
  s.ADR("MULTIREPLACE"),NIL,(*ed2.dMultiReplace,*) 2,{ed2.replace},
  s.ADR("MYPRI"),     NIL,(*ed2.dMyPri,*)        1,{clOk},
  s.ADR(edF.NewFile), NIL,(*edF.dLoad,*)         1,{noOddArgs,edF.newFile},
  s.ADR("NEWWINDOW"), NIL,(*ed2.dNewWindow,*)    0,{iconOk},
  s.ADR("NEXT"),      NIL,(*ed2.dFind,*)         0,{ed2.oldStrings},
  s.ADR("NEXTR"),     NIL,(*ed2.dFind,*)         0,{ed2.oldStrings,ed2.replace},
  s.ADR("NEXTWIN"),   NIL,(*ed3.dRotateTexts,*)  0,{iconOk,ed3.forward},
  s.ADR("NOSCRUPDATE"),NIL,(*ed2.dNoScreenUpdate,*)0,{},
  s.ADR("NULL"),      NIL,(*ed2.dNull,*)         0,{clOk},
  s.ADR("OVERWRITE"), NIL,(*edT.dOverWrite,*)    1,{clOk},
  s.ADR("PAGEDOWN"),  NIL,(*edM.dPage,*)         0,{},
  s.ADR("PAGESET"),   NIL,(*edM.dPage,*)         1,{clOk,edM.pageSet},
  s.ADR("PAGEUP"),    NIL,(*edM.dPage,*)         0,{edM.pageUp},
  s.ADR("PING"),      NIL,(*edM.dPing,*)         1,{},
  s.ADR("PONG"),      NIL,(*edM.dPong,*)         1,{},
  s.ADR("PREV"),      NIL,(*ed2.dFind,*)         0,{ed2.previous,ed2.oldStrings},
  s.ADR("PREVR"),     NIL,(*ed2.dFind,*)         0,{ed2.previous,ed2.replace},
  s.ADR("PREVWIN"),   NIL,(*ed3.dRotateTexts,*)  0,{iconOk},
  s.ADR("POPMARK"),   NIL,(*edB.dPopMark,*)      0,{clOk},
  s.ADR("PURGEMARK"), NIL,(*edB.dPurgeMark,*)    0,{clOk},
  s.ADR("PUSHMARK"),  NIL,(*edB.dPushMark,*)     0,{clOk},
  s.ADR("QUIT"),      NIL,(*ed1.dQuit,*)         0,{iconOk},
  s.ADR("RECALL"),    NIL,(*ed1.dRecall,*)       0,{clOk},
  s.ADR("REFORMAT"),  NIL,(*edT.dReformat,*)     0,{edT.rfmtParag},
  s.ADR("REMBOL"),    NIL,(*edT.dRemToFirst,*)   0,{clOk},
  s.ADR("REMEOL"),    NIL,(*edT.dRemEOL,*)       0,{clOk},
  s.ADR("REPEAT"),    NIL,(*ed1.dRepeat,*)       2,{clOk,iconOk},
  s.ADR("REPSTR"),    NIL,(*ed2.dFindStr,*)      1,{clOk,ed2.replace},
  s.ADR("RESETTOGGLE"),NIL,(*ed1.dToggle,*)      1,{clOk,ed1.resetToggle},
  s.ADR("RESIZE"),    NIL,(*ed2.dResize,*)       2,{},
  s.ADR("RETURN"),    NIL,(*edT.dReturn,*)       0,{clOk},
  s.ADR("RIGHT"),     NIL,(*edM.dRight,*)        0,{clOk},
  s.ADR("RX"),        NIL,(*edR.dRx,*)           1,{},
  s.ADR("RX1"),       NIL,(*edR.dRx1,*)          2,{},
  s.ADR("RX2"),       NIL,(*edR.dRx2,*)          3,{},
  s.ADR("RXS"),       NIL,(*edR.dRx,*)           1,{edR.moString},
  s.ADR(edF.SaveAs),  NIL,(*edF.dSave,*)         1,{clOk,iconOk,noOddArgs,edF.saveAs},
  s.ADR("SAVECONFIG"),NIL,(*edF.dSaveConfig,*)   0,{clOk,iconOk},
  s.ADR("SAVEMAP"),   NIL,(*edF.dSaveMap,*)      1,{clOk,iconOk},
  s.ADR(edF.SaveOld), NIL,(*edF.dSave,*)         0,{clOk,iconOk},
  s.ADR("SAVESMAP"),  NIL,(*edF.dSaveMap,*)      1,{clOk,iconOk,edF.saveSysMap},
  s.ADR("SCANF"),     NIL,(*ed2.dScanf,*)        1,{clOk},
  s.ADR("SCREENBOTTOM"),NIL,(*edM.dScreenBottom,*) 0,{},
  s.ADR("SCREENTOP"), NIL,(*edM.dScreenTop,*)    0,{},
  s.ADR("SCROLLDOWN"),NIL,(*edM.dScrollDown,*)   0,{},
  s.ADR("SCROLLUP"),  NIL,(*edM.dScrollUp,*)     0,{},
  s.ADR("SET"),       NIL,(*ed2.dSet,*)          2,{clOk,iconOk},
  s.ADR("SETENV"),    NIL,(*ed2.dSetEnv,*)       2,{clOk,iconOk},
  s.ADR("SETFONT"),   NIL,(*edD.dSetFont,*)      2,{},
  s.ADR("SETTOGGLE"), NIL,(*ed1.dToggle,*)       1,{clOk,iconOk,ed1.setToggle},
  s.ADR(edF.Source),  NIL,(*edF.dSource,*)       1,{clOk,noOddArgs},
  s.ADR("SPLIT"),     NIL,(*edT.dSplit,*)        0,{},
  s.ADR("SWAPCHAR"),  NIL,(*edT.dSwapChar,*)     0,{clOk},
  s.ADR("SWAPMARK"),  NIL,(*edB.dSwapMark,*)     0,{clOk},
  s.ADR("TAB"),       NIL,(*edM.dTab,*)          0,{clOk},
  s.ADR("TABINDENT"), NIL,(*edT.dIndent,*)       0,{edT.tabIndent},
  s.ADR("TABSTOP"),   NIL,(*ed1.dTabstop,*)      1,{clOk},
  s.ADR("TABUNINDENT"),NIL,(*edT.dUnIndent,*)    0,{edT.tabIndent},
  s.ADR("TITLE"),     NIL,(*edL.dTitle,*)        1,{clOk},
  s.ADR("TLATE"),     NIL,(*edT.dTLate,*)        1,{clOk},
  s.ADR("TMPHEIGHT"), NIL,(*ed2.dWinEdges,*)     1,{clOk,ed2.temp,ed2.height},
  s.ADR("TMPWIDTH"),  NIL,(*ed2.dWinEdges,*)     1,{clOk,ed2.temp},
  s.ADR("TOGGLE"),    NIL,(*ed1.dToggle,*)       1,{clOk},
  s.ADR("TOMOUSE"),   NIL,(*edM.dToMouse,*)      0,{},
  s.ADR("TOP"),       NIL,(*edM.dTop,*)          0,{},
  s.ADR("TOPEDGE"),   NIL,(*ed2.dWinEdges,*)     1,{clOk,ed2.top},
  s.ADR("UNBLOCK"),   NIL,(*edB.dUnblock,*)      0,{clOk},
  s.ADR("UNDELINE"),  NIL,(*edT.dUndelLine,*)    0,{},
  s.ADR("UNDO"),      NIL,(*ed2.dUndo,*)         0,{},
  s.ADR("UNINDENT"),  NIL,(*edT.dUnIndent,*)     0,{},
  s.ADR("UNJUSTIFY"), NIL,(*edT.dUnJustify,*)    0,{},
  s.ADR("UNMAP"),     NIL,(*edK.dUnmap,*)        1,{clOk,iconOk},
  s.ADR("UNSET"),     NIL,(*ed2.dUnset,*)        1,{clOk,iconOk},
  s.ADR("UNSETENV"),  NIL,(*ed2.dUnsetEnv,*)     1,{clOk,iconOk},
  s.ADR("UP"),        NIL,(*edM.dUp,*)           0,{},
  s.ADR("VERSION"),   NIL,(*ed2.dVersion,*)      0,{clOk},
  s.ADR("WHILE"),     NIL,(*ed1.dIf,*)           2,{clOk,iconOk,ed1.while},
  s.ADR("WIDTH"),     NIL,(*ed2.dWinEdges,*)     1,{iconOk},
  s.ADR("WLEFT"),     NIL,(*edM.dWordLeft,*)     0,{clOk},
  s.ADR("WRIGHT"),    NIL,(*edM.dWordRight,*)    0,{clOk},
  s.ADR("XCLRPING"),  NIL,(*eAS.dXClrPing,*)     0,{applOnly,argsNoStr},
  s.ADR("XPING"),     NIL,(*eAS.dXPing,*)        1,{applOnly,argsNoStr},
  s.ADR("XPONG"),     NIL,(*eAS.dXPong,*)        1,{applOnly,argsNoStr}
  );

(*-----------------------------------------------------------------------*)
(*
 *  Break out the next argument.  The argument is space delimited and
 *  might be quoted with `' or (), or single quoted as 'c or )c
 *
(*  Also:  $var   -variable insertion
 *)        ^c     -control character
 *         \c     -override next char's special-meaning
 *)

PROCEDURE BreakOut*(VAR inPtr, paux:edG.StringPtr): edG.StringPtr;
          (* bei Änderungen Def. in edG korrigieren!! *)
VAR
  inCnt: INTEGER;
  bufCnt, realStart, parCnt: INTEGER;
  Base: edG.StringPtr;

  (*
  (*  $varname $(varname) $`varname'.  I.E. three forms are allowed,
   *  which allows one to insert the stringing almost anywhere.  The
   *) first form names are limited to alpha-numerics, '-', and '_'.
   *)

  PROCEDURE BreakOutVar(): BOOLEAN;
  VAR
    cnt: INTEGER;
    len: INTEGER;
    c, ce: CHAR;
    aux: edG.StringPtr;
  BEGIN
    ce := 0X;                      (*  first form  *)
    INC(inCnt);                 (*(*  skip $      *)*)
    CASE inPtr[inCnt] OF
     |"(": ce := ")"; INC(inCnt); (*  second form *)
     |"`": ce := "'"; INC(inCnt); (*  third form  *)
    ELSE END;
    cnt := inCnt;                (* start of varname  *)
    IF ce # 0X THEN               (* until end char OR *)
      WHILE (inPtr[cnt] # 0X) AND (inPtr[cnt] # ce) DO
        INC(cnt); END;
    ELSE                          (* smart end-varname *)
      WHILE edL.IsAscii(inPtr[cnt]) OR (inPtr[cnt] = "-") DO
        INC(cnt); END;
    END;
    len := cnt-inCnt;                 (* length of variable *)
    c := inPtr[cnt]; inPtr[cnt] := 0X; (* temp. terminate 0X *)
    aux := ed2.GetVar(s.ADR(inPtr[inCnt]));
    inPtr[cnt] := c;
    IF aux # NIL THEN
      IsAux := TRUE;
      len := edL.Length(aux^);
      IF (bufCnt + len < s.SIZE(Buffer)-1) THEN
        e.CopyMem(aux^,Buffer[bufCnt],len);
        INC(bufCnt,len);
      END;
      inCnt := cnt;
      IF ce # 0X THEN INC(inCnt); END;
      IF edG.disposeString IN edG.Status THEN
        DISPOSE(aux);
        EXCL(edG.Status,edG.disposeString);
      END;
      RETURN TRUE;
    ELSE
      DEC(inCnt);
      IF ce # 0X THEN DEC(inCnt); END;
      RETURN FALSE;
    END;
  END BreakOutVar;

BEGIN
  Buffer := ""; bufCnt := 0; paux := NIL;

  IF edG.isAppl IN edG.Status THEN
    IF edR.ApplArgCnt > eAD.maxAMArg THEN
      RETURN NIL; END;
    Base := edR.CmdMsg.args[edR.ApplArgCnt];
    INC(edR.ApplArgCnt);
    IF (Base # NIL) AND NOT (argsNoStr IN edG.ArgSet)
    AND (Base[0] = "$") AND BreakOutVar() THEN
      Buffer[bufCnt] := 0X;
      paux := edL.CopyString(s.ADR(Buffer));
      RETURN paux;
    END;
    RETURN Base;
  END;

  inCnt := 0; parCnt := 0; OpenChar := 0X; CloseChar := 0X;
  IsAux := FALSE; Quoted := FALSE;

  WHILE inPtr[inCnt] = 20X DO
    INC(inCnt); END;
  IF inPtr[inCnt] = 0X THEN RETURN NIL; END;
  realStart := inCnt;
  Base := s.ADR(inPtr[inCnt]);

  LOOP
    IF parCnt = 0 THEN
      CASE inPtr[inCnt] OF
        20X: EXIT;
      | "'",")": CloseChar := inPtr[inCnt];
      | "`": OpenChar := "`"; CloseChar := "'";
      | "(": OpenChar := "("; CloseChar := ")";
      ELSE END;
    END;
    IF inPtr[inCnt] = OpenChar THEN
      INC(parCnt);
      IF inCnt = realStart THEN
        Quoted := TRUE;
        INC(inCnt);
        Base := s.ADR(inPtr[inCnt]);
      END;
    END;
    IF inPtr[inCnt] = CloseChar THEN
      DEC(parCnt);
      IF (parCnt = 0) AND Quoted THEN     (*  end of argument     *)
        EXIT; END;
      IF (inCnt = realStart) AND (parCnt < 0) THEN   (* einfach kopieren *)
        Quoted := TRUE;
        INC(inCnt);
        Base := s.ADR(inPtr[inCnt]);
        WHILE inPtr[inCnt] # 0X DO
          IF (bufCnt # s.SIZE(Buffer)-1) THEN
            Buffer[bufCnt] := inPtr[inCnt];
            INC(bufCnt);
          END;
          INC(inCnt);
        END;
        EXIT;
      END;
    END;

    IF (inPtr[inCnt] = "$") AND BreakOutVar() THEN
      IF inPtr[inCnt] = 0X THEN EXIT; END;
    ELSE
      IF (inPtr[inCnt] = "^") AND ((ORD(inPtr[inCnt+1]) MOD 32) # 0) THEN
        INC(inCnt);
        inPtr[inCnt] := CHR(ORD(inPtr[inCnt]) MOD 32);
        IsAux := TRUE;
      ELSIF (inPtr[inCnt] = "\\") AND (inPtr[inCnt+1] # 0X) THEN
        INC(inCnt);
        IsAux := TRUE;
      END;
      Buffer[bufCnt] := inPtr[inCnt];
      INC(bufCnt); INC(inCnt);
      IF inPtr[inCnt] = 0X THEN
        EXIT;
      END;
    END;
  END; (* LOOP *)
  Buffer[bufCnt] := 0X;
  INC(bufCnt);
  IF IsAux OR (ODD(s.VAL(LONGINT,Base)) AND (noOddArgs IN edG.ArgSet)) THEN
    ol.New(paux,bufCnt);
    IF paux = NIL THEN
      edG.Rc := edE.cmdSevere; INCL(edG.Status,edG.memoryFail);
      RETURN NIL
    END;
    e.CopyMem(Buffer,paux^,bufCnt);
    Base := paux;
  END;
  inPtr := s.ADR(inPtr[inCnt]); (*  last arg    *)
  IF inPtr[0] # 0X THEN     (*  space ended *)
    inPtr[0] := 0X;
    inPtr := s.ADR(inPtr[1]);
  END;
  RETURN Base;
END BreakOut;

(*-----------------------------------------------------------------------*)
(* $Debug- *)

PROCEDURE dCommand*(Buffer: edG.StringPtr);
          (* bei Änderungen Def. in edG korrigieren!! *)
VAR
  aux1, aux2, aux3: edG.StringPtr;
  i, Args : INTEGER; (* Laufvariablen *)
  repStr  : ARRAY edG.NumArgs OF edG.StringPtr;
  repi    : INTEGER;

  PROCEDURE FreeReps;
  BEGIN
    WHILE repi > 0 DO
      DEC(repi);
      DISPOSE(repStr[repi]);
    END;
  END FreeReps;

  PROCEDURE LeaveDoCommand;
  BEGIN
    DISPOSE(aux1);
    FreeReps;
    DEC(edG.RecLevel);
    IF (edG.RecLevel = 0) AND NOT (edG.quitQuit IN edG.Status) THEN
      IF edG.NoScreenUpdate > 0 THEN
        edG.NoScreenUpdate := 0;
        edD.TextRedisplay;
      END;
      edD.TextCursor(TRUE);
    END;
  END LeaveDoCommand;

  PROCEDURE CommNotFound;
  BEGIN
    edL.Title(edG.CommNotFound); edG.Rc := edE.cmdError;
  END CommNotFound;

BEGIN
  IF edG.RecLevel = 0 THEN
    ed1.HandleQuitFlags;
    edG.Rc := edE.cmdInitial;
    edD.TextCursor(FALSE);
  END;
  INC(edG.RecLevel);
  IF edG.RecLevel > MaxRec THEN          (* Rekursionstiefe erreicht? *)
    edL.Title(edG.RecTooDeep); edG.Rc := edE.cmdError;
    DEC(edG.RecLevel);
    INCL(edG.Status,edG.cmdFound); (* to prevent us from trying an ARexx macro *)
    RETURN;
  END;
  repi := 0;
  aux1 := NIL;

  LOOP
    aux2 := BreakOut(Buffer,aux1);
    IF (aux2 = NIL) OR edL.BreakCheck() THEN EXIT END;
    IF Quoted THEN
      IF (edG.iconMode IN edG.Text.status) THEN ed1.unIconify; END;
      edT.TextWrite(aux2);
    ELSIF aux2[0]="#" THEN EXIT; (* Kommentar *)
    ELSE   (* aux2^ ist Kommando *)
      IF (CAP(aux2[0])<"A") OR (CAP(aux2[0])>"Z") THEN
        ComIndex := MAX(INTEGER);
      ELSE
        i := ORD(CAP(aux2[0]))-ORD("A");
        ComIndex := HashIndex[i]; (* MAX(INTEGER), wenn nicht verhanden *)
        WHILE (ComIndex <= CharLast[i])
        AND NOT edL.NCStrCmp(Coms[ComIndex].name,aux2) DO  (* ungleich *)
          INC(ComIndex);
        END;
      END;
      IF ComIndex <= CharLast[i] THEN     (* gefunden *)
        INCL(edG.Status,edG.cmdFound);

        IF (rxOnly IN Coms[ComIndex].flags)
        AND NOT (edG.isRexx IN edG.Status) THEN
          edL.Title(edG.RexxOnlyCommand); edG.Rc := edE.cmdError;
          EXIT;
        END;
        Args := Coms[ComIndex].args;
        edG.ArgSet := Coms[ComIndex].flags;
        i := 0;
        WHILE i < Args DO                        (* Argumente holen *)
          edG.Arg[i] := BreakOut(Buffer,aux2);
          IF edG.memoryFail IN edG.Status THEN EXIT; END;
          IF aux2#NIL THEN
            repStr[repi] := aux2; (* kann nicht überlaufen, weil     *)
            INC(repi);            (* repStr[] edG.NumArgs Felder hat *)
          END;
          IF (edG.Arg[i] = NIL) OR (argsNoStr IN edG.ArgSet) THEN
            edL.Title(edG.BadArgument); edG.Rc := edE.cmdError;
            EXIT;
          END;
          INC(i);
        END; (* WHILE a < Args *)
        IF NOT (edG.commLineMode IN edG.Status)
        OR (clOk IN Coms[ComIndex].flags) THEN
          IF parOk IN Coms[ComIndex].flags THEN
            DISPOSE(edG.Particial);
            edG.Particial := edL.CopyString(Buffer);
            Buffer := s.ADR(Buffer[edL.Length(Buffer^)]);  (* skip string *)
          END;
          IF (edG.iconMode IN edG.Text.status)
          AND NOT (iconOk IN Coms[ComIndex].flags) THEN
            ed1.unIconify;
          END;
          Coms[ComIndex].proc; (* Befehl ausführen *)
        END; (* commLineMode Check *)
      ELSE  (* ComIndex <= CharLast[i] *)
(*--------- Command not found, check for macro ---------------------------*)
        aux3 := edK.KeySpectroMacro(aux2);
        IF aux3 = NIL THEN aux3 := eMn.MenuToMacro(aux2); END;
        aux3 := edL.CopyString(aux3);
        IF aux3#NIL THEN
          dCommand(aux3);
          DISPOSE(aux3);
        ELSE
(*--------- Command still not found, check for application ---------------*)
            (*   \/   *)
          aux3 := edR.GetApplPort(aux2);
          IF aux3 # NIL THEN
            edR.dRexx(SHORTSET{},aux3,Buffer);
            EXIT;
          ELSE
(*--------- Command still not found, check for public macro --------------*)
            (*   \/   *)
            edG.Arg[0] := aux2; edG.Arg[1] := Buffer;
            edR.dRx1;
            EXIT;
          END; (* aux3#NIL *)
        END; (* aux3#NIL *)
      END; (* ComIndex <= CharLast[i] *)
    END; (* IF Quoted .. ELSE *)
    IF (edG.Rc >= edE.abortLevel) OR (edG.quitQuit IN edG.Status) THEN
      EXIT; END;
    FreeReps;
  END; (* LOOP *)

  LeaveDoCommand;
END dCommand;
(* $Debug- *)

(*-----------------------------------------------------------------------*)
(*(* $Debug- *) InitComNames *)
BEGIN
  (* $NilChk- *)
  Coms := s.ADR(Commands);
  Coms[0].proc := ed2.dAbort;
  Coms[1].proc := edR.dAppl;
  Coms[2].proc := edR.dApplAdd;
  Coms[3].proc := edR.dApplClose;
  Coms[4].proc := edF.dFileReq;
  Coms[5].proc := edF.dFileReq;
  Coms[6].proc := edF.dFileReq;
  Coms[7].proc := edF.dFileReq;
  Coms[8].proc := edF.dFileReq;
  Coms[9].proc := edT.dAscii;
  Coms[10].proc := edT.dBs;
  Coms[11].proc := edM.dBackTab;
  Coms[12].proc := edB.dBCopy;
  Coms[13].proc := edB.dBDelete;
  Coms[14].proc := edB.dBlock;
  Coms[15].proc := edB.dBMove;
  Coms[16].proc := edM.dBottom;
  Coms[17].proc := edT.dBs;
  Coms[18].proc := edF.dSave;
  Coms[19].proc := edB.dBSource;
  Coms[20].proc := edF.dCD;
  Coms[21].proc := eMn.dCheckItem;
  Coms[22].proc := eMn.dCheckItem;
  Coms[23].proc := eMn.dCheckItem;
  Coms[24].proc := edF.dChFilename;
  Coms[25].proc := edK.ResetHash;
  Coms[26].proc := edT.dDel;
  Coms[27].proc := edT.dDelLine;
  Coms[28].proc := edM.dDown;
  Coms[29].proc := edT.dDownAdd;
  Coms[30].proc := ed1.dEsc;
  Coms[31].proc := ed1.dEsc;
  Coms[32].proc := ed2.dExecute;
  Coms[33].proc := ed2.dFind;
  Coms[34].proc := ed2.dFind;
  Coms[35].proc := ed2.dFindStr;
  Coms[36].proc := edM.dFirstColumn;
  Coms[37].proc := edM.dFirstNb;
  Coms[38].proc := edM.dGotoLine;
  Coms[39].proc := edM.dGotoCol;
  Coms[40].proc := ed2.dWinEdges;
  Coms[41].proc := ed1.dIconify;
  Coms[42].proc := ed1.dIf;
  Coms[43].proc := ed1.dIf;
  Coms[44].proc := edT.dIndent;
  Coms[45].proc := edT.dOverWrite;
  Coms[46].proc := edF.dLoad;
  Coms[47].proc := edT.dInsLine;
  Coms[48].proc := edT.dJoin;
  Coms[49].proc := edT.dJustify;
  Coms[50].proc := edM.dLastColumn;
  Coms[51].proc := edM.dLeft;
  Coms[52].proc := ed2.dWinEdges;
  Coms[53].proc := edK.dMap;
  Coms[54].proc := ed1.dMargin;
  Coms[55].proc := eMn.dMenuAdd;
  Coms[56].proc := eMn.dMenuAdd;
  Coms[57].proc := eMn.dMenuAdd;
  Coms[58].proc := eMn.dMenuClear;
  Coms[59].proc := eMn.dMenuDel;
  Coms[60].proc := eMn.dMenuDelHdr;
  Coms[61].proc := eMn.dMenuOff;
  Coms[62].proc := eMn.dMenuOn;
  Coms[63].proc := ed2.dMultiReplace;
  Coms[64].proc := ed2.dMyPri;
  Coms[65].proc := edF.dLoad;
  Coms[66].proc := ed2.dNewWindow;
  Coms[67].proc := ed2.dFind;
  Coms[68].proc := ed2.dFind;
  Coms[69].proc := ed3.dRotateTexts;
  Coms[70].proc := ed2.dNoScreenUpdate;
  Coms[71].proc := ed2.dNull;
  Coms[72].proc := edT.dOverWrite;
  Coms[73].proc := edM.dPage;
  Coms[74].proc := edM.dPage;
  Coms[75].proc := edM.dPage;
  Coms[76].proc := edM.dPing;
  Coms[77].proc := edM.dPong;
  Coms[78].proc := ed2.dFind;
  Coms[79].proc := ed2.dFind;
  Coms[80].proc := ed3.dRotateTexts;
  Coms[81].proc := edB.dPopMark;
  Coms[82].proc := edB.dPurgeMark;
  Coms[83].proc := edB.dPushMark;
  Coms[84].proc := ed1.dQuit;
  Coms[85].proc := ed1.dRecall;
  Coms[86].proc := edT.dReformat;
  Coms[87].proc := edT.dRemToFirst;
  Coms[88].proc := edT.dRemEOL;
  Coms[89].proc := ed1.dRepeat;
  Coms[90].proc := ed2.dFindStr;
  Coms[91].proc := ed1.dToggle;
  Coms[92].proc := ed2.dResize;
  Coms[93].proc := edT.dReturn;
  Coms[94].proc := edM.dRight;
  Coms[95].proc := edR.dRx;
  Coms[96].proc := edR.dRx1;
  Coms[97].proc := edR.dRx2;
  Coms[98].proc := edR.dRx;
  Coms[99].proc := edF.dSave;
  Coms[100].proc := edF.dSaveConfig;
  Coms[101].proc := edF.dSaveMap;
  Coms[102].proc := edF.dSave;
  Coms[103].proc := edF.dSaveMap;
  Coms[104].proc := ed2.dScanf;
  Coms[105].proc := edM.dScreenBottom;
  Coms[106].proc := edM.dScreenTop;
  Coms[107].proc := edM.dScrollDown;
  Coms[108].proc := edM.dScrollUp;
  Coms[109].proc := ed2.dSet;
  Coms[110].proc := ed2.dSetEnv;
  Coms[111].proc := edD.dSetFont;
  Coms[112].proc := ed1.dToggle;
  Coms[113].proc := edF.dSource;
  Coms[114].proc := edT.dSplit;
  Coms[115].proc := edT.dSwapChar;
  Coms[116].proc := edB.dSwapMark;
  Coms[117].proc := edM.dTab;
  Coms[118].proc := edT.dIndent;
  Coms[119].proc := ed1.dTabstop;
  Coms[120].proc := edT.dUnIndent;
  Coms[121].proc := edL.dTitle;
  Coms[122].proc := edT.dTLate;
  Coms[123].proc := ed2.dWinEdges;
  Coms[124].proc := ed2.dWinEdges;
  Coms[125].proc := ed1.dToggle;
  Coms[126].proc := edM.dToMouse;
  Coms[127].proc := edM.dTop;
  Coms[128].proc := ed2.dWinEdges;
  Coms[129].proc := edB.dUnblock;
  Coms[130].proc := edT.dUndelLine;
  Coms[131].proc := ed2.dUndo;
  Coms[132].proc := edT.dUnIndent;
  Coms[133].proc := edT.dUnJustify;
  Coms[134].proc := edK.dUnmap;
  Coms[135].proc := ed2.dUnset;
  Coms[136].proc := ed2.dUnsetEnv;
  Coms[137].proc := edM.dUp;
  Coms[138].proc := ed2.dVersion;
  Coms[139].proc := ed1.dIf;
  Coms[140].proc := ed2.dWinEdges;
  Coms[141].proc := edM.dWordLeft;
  Coms[142].proc := edM.dWordRight;
  Coms[143].proc := eAS.dXClrPing;
  Coms[144].proc := eAS.dXPing;
  Coms[145].proc := eAS.dXPong;

  (* !!! NumComs !!! muß bei neuen Kommandos mitverändert werden *)

  (* Tabelle mit Kommandos initialisieren *)
  ComIndex := 27; (* 26 Buchstaben +1 *)
  REPEAT
    DEC(ComIndex);
    HashIndex[ComIndex] := MAX(INTEGER); (* steht für nicht vorhandenes Komm *)
  UNTIL ComIndex = 0;

  (* Tabelle erstellen *)
  ComIndex := NumComs;
  REPEAT
    DEC(ComIndex);
    HashIndex[ORD(Coms[ComIndex].name[0])-ORD("A")] := ComIndex;
  UNTIL ComIndex = 0;
  REPEAT
    CharLast[ORD(Coms[ComIndex].name[0])-ORD("A")] := ComIndex;
    INC(ComIndex);
  UNTIL ComIndex = NumComs;
  (* $NilChk= *)

END EdParser.

