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

:Program.    EdParser.mod
:Contents.   Command-Parser for AmokEd
:Author.     Hartmut Goebel, Werner Speer
:Language.   Oberon
:Translator. AmigaOberon V2.00
: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.       19 Oct 1991 03:42:26

*************************************************************************)
(* $Debug- *)
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,
  edR: EdRexx,
  lst: EdLists,
  ol : OberonLib,
  str: Strings,
  s  : SYSTEM;

CONST
  (* 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 *)

  NumComs = 129; (* Anzahl der Kommandos *)
  MaxRec = 5;    (* maximale Rekursionstiefe *)
  MaxIA = 5;

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;     (*                        *)
  ImMode,IsAux, Break: BOOLEAN;  (* used by BreakOut only! *)
  Buffer: edG.String;            (*                        *)

(*------------------------------------------------------------------------*)
(*
TYPE
  ComList = ARRAY 10 OF Com;
CONST                      (*Funktioniert leider nicht!!*)
  Commands = ComList(
    "ABORT",      ed2.doAbort,        0, {iconOk},
    "ARPLOAD",    edF.doFileReq,      0, {edF.newFile},
    "ARPINSFILE", edF.doFileReq,      0, {},
    "ARPSAVE",    edF.doFileReq,      0, {edF.saveAs},
    "BACK",       edM.doBs,           0, {clOk},
    "BACKTAB",    edM.doBackTab,      0, {clOk},
    "BCOPY",      edB.doBCopy,        0, {},
    "BDELETE",    edB.doBDelete,      0, {clOk},
    "BLOCK",      edB.doBlock,        0, {},
    "BMOVE",      edB.doBMove,        0, {});
*)

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

  Commands = CommandList(
  s.ADR("ABORT"),     NIL,(*ed2.doAbort,*)        0,{iconOk},
  s.ADR("ARPBSAVE"),  NIL,(*edF.doFileReq,*)      0,{clOk,edF.saveBlock},
  s.ADR("ARPLOAD"),   NIL,(*edF.doFileReq,*)      0,{edF.newFile},
  s.ADR("ARPINSFILE"),NIL,(*edF.doFileReq,*)      0,{},
  s.ADR("ARPSAVE"),   NIL,(*edF.doFileReq,*)      0,{edF.saveAs},
  s.ADR("APPL"),      NIL,(*edR.doAppl,*)         2,{},
  s.ADR("APPLADD"),   NIL,(*edR.doApplAdd,*)      2,{applOnly},
  s.ADR("APPLCLOSE"), NIL,(*edR.doApplClose,*)    1,{},
  s.ADR("BACK"),      NIL,(*edM.doBs,*)           0,{clOk},
  s.ADR("BACKTAB"),   NIL,(*edM.doBackTab,*)      0,{clOk},
  s.ADR("BCOPY"),     NIL,(*edB.doBCopy,*)        0,{},
  s.ADR("BDELETE"),   NIL,(*edB.doBDelete,*)      0,{clOk},
  s.ADR("BLOCK"),     NIL,(*edB.doBlock,*)        0,{},
  s.ADR("BMOVE"),     NIL,(*edB.doBMove,*)        0,{},
  s.ADR("BOTTOM"),    NIL,(*edM.doBottom,*)       0,{},
  s.ADR("BS"),        NIL,(*edM.doBs,*)           0,{clOk},
  s.ADR("BSAVE"),     NIL,(*edF.doSave,*)         1,{clOk,edF.saveBlock},
  s.ADR("BSOURCE"),   NIL,(*edB.doBSource,*)      0,{clOk},
  s.ADR("CD"),        NIL,(*edF.doCD,*)           1,{clOk},
  s.ADR("CHFILENAME"),NIL,(*edF.doChFilename,*)   1,{clOk},
  s.ADR("CLEARMAP"),  NIL,(*edK.ResetHash,*)      0,{clOk},
  s.ADR("DEL"),       NIL,(*edM.doDel,*)          0,{clOk},
  s.ADR("DELINE"),    NIL,(*edM.doDelLine,*)      0,{},
  s.ADR("DOWN"),      NIL,(*edM.doDown,*)         0,{},
  s.ADR("DOWNADD"),   NIL,(*edM.doDownAdd,*)      0,{},
  s.ADR("ESC"),       NIL,(*ed1.doEsc,*)          0,{clOk},
  s.ADR("ESCIMM"),    NIL,(*ed1.doEsc,*)          1,{ed1.escImm},
  s.ADR("EXECUTE"),   NIL,(*ed2.doExecute,*)      1,{clOk},
  s.ADR("FIND"),      NIL,(*ed2.doFind,*)         1,{},
  s.ADR("FINDR"),     NIL,(*ed2.doFind,*)         2,{ed2.replace},
  s.ADR("FINDSTR"),   NIL,(*ed2.doFindStr,*)      1,{},
  s.ADR("FIRST"),     NIL,(*edM.doFirstColumn,*)  0,{clOk},
  s.ADR("FIRSTNB"),   NIL,(*edM.doFirstNb,*)      0,{clOk},
  s.ADR("GOTO"),      NIL,(*edM.doGoto,*)         1,{},
  s.ADR("HEIGHT"),    NIL,(*ed2.doWinEdges,*)     1,{ed2.height},
  s.ADR("ICONIFY"),   NIL,(*ed1.doIconify,*)      0,{iconOk},
  s.ADR("IF"),        NIL,(*ed1.doIf,*)           2,{clOk},
  s.ADR("IFELSE"),    NIL,(*ed1.doIf,*)           3,{clOk,ed1.ifElse},
  s.ADR("INSERT"),    NIL,(*ed3.doOverWrite,*)    1,{ed3.insert},
  s.ADR(edF.InsFile), NIL,(*edF.doLoad,*)         1,{},
  s.ADR("INSLINE"),   NIL,(*edM.doInsLine,*)      0,{},
  s.ADR("JOIN"),      NIL,(*edM.doJoin,*)         0,{},
  s.ADR("LAST"),      NIL,(*edM.doLastColumn,*)   0,{clOk},
  s.ADR("LEFT"),      NIL,(*edM.doLeft,*)         0,{clOk},
  s.ADR("LEFTEDGE"),  NIL,(*ed2.doWinEdges,*)     1, ed2.leftEdge,
  s.ADR("MAP"),       NIL,(*edK.doMap,*)          2,{clOk},
  s.ADR("MARGIN"),    NIL,(*ed1.doMargin,*)       1,{clOk},
  s.ADR("MENUADD"),   NIL,(*eMn.doMenuAdd,*)      3,{clOk},
  s.ADR("MENUCLEAR"), NIL,(*eMn.doMenuClear,*)    0,{clOk},
  s.ADR("MENUDEL"),   NIL,(*eMn.doMenuDel,*)      2,{clOk},
  s.ADR("MENUDELHDR"),NIL,(*eMn.doMenuDelHdr,*)   1,{clOk},
  s.ADR("MENUOFF"),   NIL,(*eMn.doMenuOff,*)      0,{clOk},
  s.ADR("MENUON"),    NIL,(*eMn.doMenuOn,*)       0,{clOk},
  s.ADR("MULTIREPLACE"),NIL,(*ed2.doMultiReplace,*) 2,{ed2.replace},
  s.ADR("MYPRI"),     NIL,(*ed2.doMyPri,*)        1,{clOk},
  s.ADR(edF.NewFile), NIL,(*edF.doLoad,*)         1,{edF.newFile},
  s.ADR("NEWWINDOW"), NIL,(*ed2.doNewWindow,*)    0,{iconOk},
  s.ADR("NEXT"),      NIL,(*ed2.doFind,*)         0,{ed2.oldStrings},
  s.ADR("NEXTR"),     NIL,(*ed2.doFind,*)         0,{ed2.oldStrings,ed2.replace},
  s.ADR("NULL"),      NIL,(*ed2.doNull,*)         0,{clOk},
  s.ADR("OVERWRITE"), NIL,(*ed3.doOverWrite,*)    1,{},
  s.ADR("PAGEDOWN"),  NIL,(*edM.doPage,*)         0,{},
  s.ADR("PAGESET"),   NIL,(*edM.doPage,*)         1,{clOk,  edM.pageSet},
  s.ADR("PAGEUP"),    NIL,(*edM.doPage,*)         0,{edM.pageUp},
  s.ADR("PING"),      NIL,(*edM.doPing,*)         1,{},
  s.ADR("PONG"),      NIL,(*edM.doPong,*)         1,{},
  s.ADR("PREV"),      NIL,(*ed2.doFind,*)         0,{ed2.previous,ed2.oldStrings},
  s.ADR("PREVR"),     NIL,(*ed2.doFind,*)         0,{ed2.previous,ed2.replace},
  s.ADR("POPMARK"),   NIL,(*edB.doPopMark,*)      0,{clOk},
  s.ADR("PURGEMARK"), NIL,(*edB.doPurgeMark,*)    0,{clOk},
  s.ADR("PUSHMARK"),  NIL,(*edB.doPushMark,*)     0,{clOk},
  s.ADR("QUIT"),      NIL,(*ed1.doQuit,*)         0,{},
  s.ADR("QUITQUIT"),  NIL,(*ed1.doQuit,*)         0,{rxOnly,ed1.rxQuit},
  s.ADR("RECALL"),    NIL,(*ed1.doRecall,*)       0,{clOk},
  s.ADR("REFORMAT"),  NIL,(*edM.doReformat,*)     0,{},
  s.ADR("REMEOL"),    NIL,(*edM.doRemEOL,*)       0,{clOk},
  s.ADR("REPEAT"),    NIL,(*ed1.doRepeat,*)       2,{clOk},
  s.ADR("REPSTR"),    NIL,(*ed2.doFindStr,*)      1,{ed2.replace},
  s.ADR("RESETTOGGLE"),NIL,(*ed1.doToggle,*)      1,{clOk,ed1.resetToggle},
  s.ADR("RESIZE"),    NIL,(*ed2.doResize,*)       2,{},
  s.ADR("RETURN"),    NIL,(*ed1.doReturn,*)       0,{clOk},
  s.ADR("RIGHT"),     NIL,(*edM.doRight,*)        0,{clOk},
  s.ADR("RX"),        NIL,(*edR.doRx,*)           1,{},
  s.ADR("RX1"),       NIL,(*edR.doRx1,*)          2,{},
  s.ADR("RX2"),       NIL,(*edR.doRx2,*)          3,{},
  s.ADR("RXS"),       NIL,(*edR.doRx,*)           1,{edR.moString},
  s.ADR(edF.SaveAs),  NIL,(*edF.doSave,*)         1,{clOk,edF.saveAs},
  s.ADR("SAVECONFIG"),NIL,(*edF.doSaveConfig,*)   0,{clOk},
  s.ADR("SAVEMAP"),   NIL,(*edF.doSaveMap,*)      1,{clOk},
  s.ADR(edF.SaveOld), NIL,(*edF.doSave,*)         0,{clOk},
  s.ADR("SAVESMAP"),  NIL,(*edF.doSaveMap,*)      1,{clOk,edF.saveSysMap},
  s.ADR("SCANF"),     NIL,(*ed2.doScanf,*)        1,{},
  s.ADR("SCREENBOTTOM"),NIL,(*edM.doScreenBottom,*) 0,{},
  s.ADR("SCREENTOP"), NIL,(*edM.doScreenTop,*)    0,{},
  s.ADR("SCROLLDOWN"),NIL,(*edM.doScrollDown,*)   0,{},
  s.ADR("SCROLLUP"),  NIL,(*edM.doScrollUp,*)     0,{},
  s.ADR("SETTOGGLE"), NIL,(*ed1.doToggle,*)       1,{clOk,ed1.setToggle},
  s.ADR("SET"),       NIL,(*ed2.doSet,*)          2,{clOk},
  s.ADR("SETENV"),    NIL,(*ed2.doSetEnv,*)       2,{clOk},
  s.ADR("SETFONT"),   NIL,(*edD.doSetFont,*)      2,{},
  s.ADR("SOURCE"),    NIL,(*edF.doSource,*)       1,{clOk},
  s.ADR("SPLIT"),     NIL,(*edM.doSplit,*)        0,{},
  s.ADR("SWAPCHAR"),  NIL,(*ed3.doSwapChar,*)     0,{clOk},
  s.ADR("SWAPMARK"),  NIL,(*edB.doSwapMark,*)     0,{clOk},
  s.ADR("TAB"),       NIL,(*edM.doTab,*)          0,{clOk},
  s.ADR("TABSTOP"),   NIL,(*ed1.doTabstop,*)      1,{clOk},
  s.ADR("TMPHEIGHT"), NIL,(*ed2.doWinEdges,*)     1,{clOk,ed2.temp,ed2.height},
  s.ADR("TMPWIDTH"),  NIL,(*ed2.doWinEdges,*)     1,{clOk,ed2.temp},
  s.ADR("TITLE"),     NIL,(*edL.doTitle,*)        1,{clOk},
  s.ADR("TLATE"),     NIL,(*ed2.doTLate,*)        1,{clOk},
  s.ADR("TOGGLE"),    NIL,(*ed1.doToggle,*)       1,{clOk},
  s.ADR("TOMOUSE"),   NIL,(*edM.doToMouse,*)      0,{},
  s.ADR("TOP"),       NIL,(*edM.doTop,*)          0,{},
  s.ADR("TOPEDGE"),   NIL,(*ed2.doWinEdges,*)     1,{ed2.top},
  s.ADR("UNBLOCK"),   NIL,(*edB.doUnblock,*)      0,{clOk},
  s.ADR("UNDELINE"),  NIL,(*edM.doUndelLine,*)    0,{},
  s.ADR("UNDO"),      NIL,(*ed2.doUndo,*)         0,{},
  s.ADR("UNMAP"),     NIL,(*edK.doUnmap,*)        1,{clOk},
  s.ADR("UNSET"),     NIL,(*ed2.doUnset,*)        1,{clOk},
  s.ADR("UNSETENV"),  NIL,(*ed2.doUnsetEnv,*)     1,{clOk},
  s.ADR("UP"),        NIL,(*edM.doUp,*)           0,{},
  s.ADR("VERSION"),   NIL,(*ed2.doVersion,*)      0,{},
  s.ADR("WHILE"),     NIL,(*ed1.doIf,*)           2,{clOk,ed1.while},
  s.ADR("WIDTH"),     NIL,(*ed2.doWinEdges,*)     1,{},
  s.ADR("WLEFT"),     NIL,(*edM.doWordLeft,*)     0,{clOk},
  s.ADR("WRIGHT"),    NIL,(*edM.doWordRight,*)    0,{clOk},
  s.ADR("XCLRPING"),  NIL,(*eAS.doXClrPing,*)     0,{applOnly,argsNoStr},
  s.ADR("XPING"),     NIL,(*eAS.doXPing,*)        1,{applOnly,argsNoStr},
  s.ADR("XPONG"),     NIL,(*eAS.doXPong,*)        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 ptr, paux:edG.StringPtr): edG.StringPtr;
          (* bei Änderungen Def. in edG korrigieren!! *)
VAR
  string, Base: edG.StringPtr;
  Count: INTEGER;
  di: INTEGER;

  (*
  (*  $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
    ptr: edG.StringPtr;
    c, ce: CHAR;
    l: INTEGER;
    len: LONGINT;
  BEGIN
    ce := 0X;                     (*  first form  *)
    INC(string);                (*(*  skip $      *)*)
    CASE string[0] OF
    |"(": ce := ")"; INC(string); (*  second form *)
    |"`": ce := "'"; INC(string); (*  third form  *)
    ELSE END;
    ptr := string;                (* start of varname  *)
    IF ce # 0X THEN               (* until end char OR *)
      WHILE (ptr[0] # 0X) AND (ptr[0] # ce) DO
        INC(ptr); END;
    ELSE                          (* smart end-varname *)
      WHILE edL.IsAscii(ptr[0]) OR (ptr[0] = "-") DO
        INC(ptr); END;
    END;
    len := s.VAL(LONGINT,ptr)-s.VAL(LONGINT,string); (* length of variable *)
    c := ptr[0]; ptr[0] := 0X;  (* temp. terminate 0X *)
    ptr := ed2.GetVar(string);
    string[len] := c;
    IF c = 0X THEN Break := TRUE; END;
    IF ptr # NIL THEN
      IsAux := TRUE;
      l := str.Length(ptr^);
      IF (di + l < s.SIZE(Buffer)-1) THEN
        e.CopyMem(ptr^,Buffer[di],l);
        INC(di,l);
      END;
      INC(string,len);
      IF ce # 0X THEN INC(string); END;
      IF edG.disposeString IN edG.Status THEN
        DISPOSE(ptr);
        EXCL(edG.Status,edG.disposeString);
      END;
      RETURN TRUE;
    ELSE
      DEC(string);
      IF ce # 0X THEN
        DEC(string); END;
      RETURN FALSE;
    END;
  END BreakOutVar;

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

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

  Count := 0; OpenChar := 0X; CloseChar := 0X; string := ptr;
  ImMode := FALSE; IsAux := FALSE; Quoted := FALSE;

  WHILE string[0] = 20X DO
    INC(string); END;
  IF string[0] = 0X THEN
    RETURN NIL; END;
  ptr := string;
  Base := string;
  Break := FALSE;
  WHILE NOT Break DO
  LOOP
    IF ImMode THEN
      IF (di # s.SIZE(Buffer)-1) THEN
        Buffer[di] := string[0];
        INC(di);
      END;
      INC(string);
      IF string[0] = 0X THEN
        Break := TRUE; END;
      EXIT;
    END;
    IF Count = 0 THEN
      CASE string[0] OF
        20X: Break := TRUE; EXIT;
      | "'",")": CloseChar := string[0];
      | "`": OpenChar := "`"; CloseChar := "'";
      | "(": OpenChar := "("; CloseChar := ")";
      ELSE
      END;
    END;
    IF string[0] = OpenChar THEN
      INC(Count);
      IF string = ptr THEN
        Quoted := TRUE;
        INC(string);
        Base := string;
        EXIT;
      END;
    END;
    IF string[0] = CloseChar THEN
      DEC(Count);
      IF (Count = 0) AND Quoted THEN     (*  end of argument     *)
        Break := TRUE;
        EXIT;
      END;
      IF (string = ptr) AND (Count < 0) THEN
        ImMode := TRUE;
        Quoted := TRUE;
        INC(string);
        Base := string;
        EXIT;
      END;
    END;

    IF (string[0] = "$") AND BreakOutVar() THEN EXIT; END;
    IF (string[0] = "^") AND ((ORD(string[1]) MOD 32) # 0) THEN
      INC(string);
      string[0] := CHR(ORD(string[0]) MOD 32);
      IsAux := TRUE;
    END;
    IF (string[0] = "\\") AND (string[1] # 0X) THEN
      INC(string);
      IsAux := TRUE;
    END;
    Buffer[di] := string[0];
    INC(di);
    INC(string);
    IF string[0] = 0X THEN
      Break := TRUE;
      EXIT;
    END;
  END; (* LOOP *)
  END; (* WHILE *)
  Buffer[di] := 0X;
  INC(di);
  IF IsAux OR ODD(s.VAL(LONGINT,Base)) THEN
    ol.New(paux,di);
    IF paux = NIL THEN
      edG.Rc := edE.cmdSevere; INCL(edG.Status,edG.memoryFail);
      RETURN NIL
    END;
    e.CopyMem(Buffer,paux^,di);
    Base := paux;
  END;
  ptr := string;          (*  last arg    *)
  IF string[0] # 0X THEN  (*  space ended *)
    string[0] := 0X;
    INC(ptr);             (*  next arg    *)
  END;
  RETURN Base;
END BreakOut;

(*-----------------------------------------------------------------------*)

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

  PROCEDURE LeaveDoCommand;
  BEGIN
    DISPOSE(aux1);
    WHILE repi > 0 DO
      DEC(repi);
      DISPOSE(RepStr[repi]);
    END;
    DEC(edG.RecLevel);
    IF (edG.RecLevel = 0) AND NOT (edG.quitQuit IN edG.Status) THEN
      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;
      edM.TextWrite(aux2);
    ELSIF aux2[0]="#" THEN EXIT; (* Kommentar *)
    ELSE   (* aux2^ ist Kommando *)
      IF (CAP(aux2[0])<"A") OR (CAP(aux2[0])>"Z") THEN
        CommNotFound; EXIT;
      END;
      i := ORD(CAP(aux2[0]))-ORD("A");
      ComIndex := HashIndex[i]; (* MAX(INTEGER), wenn nicht verhanden *)
      WHILE (ComIndex <= CharLast[i])
      AND (edL.NCStrCmp(Coms[ComIndex].name,aux2) # 0) DO  (* ungleich *)
        INC(ComIndex);
      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
            IF repi = MaxIA THEN
              DISPOSE(aux2);
              edL.Title(edG.CommandTooComplex); edG.Rc := edE.cmdError;
              EXIT;
            ELSE
              RepStr[repi] := aux2;
              INC(repi);
            END;
          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);
            INC(Buffer,str.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
          doCommand(aux3);
          DISPOSE(aux3);
        ELSE
(*--------- Command still not found, check for application ---------------*)
            (*   \/   *)
          aux3 := edR.GetApplPort(aux2);
          IF aux3 # NIL THEN
            edR.doRexx(SHORTSET{},aux3,Buffer);
            EXIT;
          ELSE
(*--------- Command still not found, check for public macro --------------*)
            (*   \/   *)
            edG.Arg[0] := aux2; edG.Arg[1] := Buffer;
            edR.doRx1;
            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;
  END; (* LOOP *)

  LeaveDoCommand;
END doCommand;

(*-----------------------------------------------------------------------*)
(*(* $Debug- *)*)
BEGIN
  (* $NilChk- *)
  Coms := s.ADR(Commands);
  Coms[0].proc := ed2.doAbort;
  Coms[1].proc := edF.doFileReq;
  Coms[2].proc := edF.doFileReq;
  Coms[3].proc := edF.doFileReq;
  Coms[4].proc := edF.doFileReq;
  Coms[5].proc := edR.doAppl;
  Coms[6].proc := edR.doApplAdd;
  Coms[7].proc := edR.doApplClose;
  Coms[8].proc := edM.doBs;
  Coms[9].proc := edM.doBackTab;
  Coms[10].proc := edB.doBCopy;
  Coms[11].proc := edB.doBDelete;
  Coms[12].proc := edB.doBlock;
  Coms[13].proc := edB.doBMove;
  Coms[14].proc := edM.doBottom;
  Coms[15].proc := edM.doBs;
  Coms[16].proc := edF.doSave;
  Coms[17].proc := edB.doBSource;
  Coms[18].proc := edF.doCD;
  Coms[19].proc := edF.doChFilename;
  Coms[20].proc := edK.ResetHash;
  Coms[21].proc := edM.doDel;
  Coms[22].proc := edM.doDelLine;
  Coms[23].proc := edM.doDown;
  Coms[24].proc := edM.doDownAdd;
  Coms[25].proc := ed1.doEsc;
  Coms[26].proc := ed1.doEsc;
  Coms[27].proc := ed2.doExecute;
  Coms[28].proc := ed2.doFind;
  Coms[29].proc := ed2.doFind;
  Coms[30].proc := ed2.doFindStr;
  Coms[31].proc := edM.doFirstColumn;
  Coms[32].proc := edM.doFirstNb;
  Coms[33].proc := edM.doGoto;
  Coms[34].proc := ed2.doWinEdges;
  Coms[35].proc := ed1.doIconify;
  Coms[36].proc := ed1.doIf;
  Coms[37].proc := ed1.doIf;
  Coms[38].proc := ed3.doOverWrite;
  Coms[39].proc := edF.doLoad;
  Coms[40].proc := edM.doInsLine;
  Coms[41].proc := edM.doJoin;
  Coms[42].proc := edM.doLastColumn;
  Coms[43].proc := edM.doLeft;
  Coms[44].proc := ed2.doWinEdges;
  Coms[45].proc := edK.doMap;
  Coms[46].proc := ed1.doMargin;
  Coms[47].proc := eMn.doMenuAdd;
  Coms[48].proc := eMn.doMenuClear;
  Coms[49].proc := eMn.doMenuDel;
  Coms[50].proc := eMn.doMenuDelHdr;
  Coms[51].proc := eMn.doMenuOff;
  Coms[52].proc := eMn.doMenuOn;
  Coms[53].proc := ed2.doMultiReplace;
  Coms[54].proc := ed2.doMyPri;
  Coms[55].proc := edF.doLoad;
  Coms[56].proc := ed2.doNewWindow;
  Coms[57].proc := ed2.doFind;
  Coms[58].proc := ed2.doFind;
  Coms[59].proc := ed2.doNull;
  Coms[60].proc := ed3.doOverWrite;
  Coms[61].proc := edM.doPage;
  Coms[62].proc := edM.doPage;
  Coms[63].proc := edM.doPage;
  Coms[64].proc := edM.doPing;
  Coms[65].proc := edM.doPong;
  Coms[66].proc := ed2.doFind;
  Coms[67].proc := ed2.doFind;
  Coms[68].proc := edB.doPopMark;
  Coms[69].proc := edB.doPurgeMark;
  Coms[70].proc := edB.doPushMark;
  Coms[71].proc := ed1.doQuit;
  Coms[72].proc := ed1.doQuit;
  Coms[73].proc := ed1.doRecall;
  Coms[74].proc := edM.doReformat;
  Coms[75].proc := edM.doRemEOL;
  Coms[76].proc := ed1.doRepeat;
  Coms[77].proc := ed2.doFindStr;
  Coms[78].proc := ed1.doToggle;
  Coms[79].proc := ed2.doResize;
  Coms[80].proc := ed1.doReturn;
  Coms[81].proc := edM.doRight;
  Coms[82].proc := edR.doRx;
  Coms[83].proc := edR.doRx1;
  Coms[84].proc := edR.doRx2;
  Coms[85].proc := edR.doRx;
  Coms[86].proc := edF.doSave;
  Coms[87].proc := edF.doSaveConfig;
  Coms[88].proc := edF.doSaveMap;
  Coms[89].proc := edF.doSave;
  Coms[90].proc := edF.doSaveMap;
  Coms[91].proc := ed2.doScanf;
  Coms[92].proc := edM.doScreenBottom;
  Coms[93].proc := edM.doScreenTop;
  Coms[94].proc := edM.doScrollDown;
  Coms[95].proc := edM.doScrollUp;
  Coms[96].proc := ed1.doToggle;
  Coms[97].proc := ed2.doSet;
  Coms[98].proc := ed2.doSetEnv;
  Coms[99].proc := edD.doSetFont;
  Coms[100].proc := edF.doSource;
  Coms[101].proc := edM.doSplit;
  Coms[102].proc := ed3.doSwapChar;
  Coms[103].proc := edB.doSwapMark;
  Coms[104].proc := edM.doTab;
  Coms[105].proc := ed1.doTabstop;
  Coms[106].proc := ed2.doWinEdges;
  Coms[107].proc := ed2.doWinEdges;
  Coms[108].proc := edL.doTitle;
  Coms[109].proc := ed2.doTLate;
  Coms[110].proc := ed1.doToggle;
  Coms[111].proc := edM.doToMouse;
  Coms[112].proc := edM.doTop;
  Coms[113].proc := ed2.doWinEdges;
  Coms[114].proc := edB.doUnblock;
  Coms[115].proc := edM.doUndelLine;
  Coms[116].proc := ed2.doUndo;
  Coms[117].proc := edK.doUnmap;
  Coms[118].proc := ed2.doUnset;
  Coms[119].proc := ed2.doUnsetEnv;
  Coms[120].proc := edM.doUp;
  Coms[121].proc := ed2.doVersion;
  Coms[122].proc := ed1.doIf;
  Coms[123].proc := ed2.doWinEdges;
  Coms[124].proc := edM.doWordLeft;
  Coms[125].proc := edM.doWordRight;
  Coms[126].proc := eAS.doXClrPing;
  Coms[127].proc := eAS.doXPing;
  Coms[128].proc := eAS.doXPong;

  (* !!! 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.

