{$A-}
PROGRAM TOOLS;
{$I TOOLU.PAS}


  PROCEDURE INITCMD;
    { Initialize command line; modified for double quotes }
    { Pipes added -- Willett Kempton, 3 January 1985      }
    { Multiple processes (sequential) added -- WK, 5 January 1985 }

  CONST
    PIPE = BAR;
    SEQPRCS = SEMICOL;
  VAR
    FD,FDJUNK:FILEDESC;
    FNAME:XSTRING;
    FT:FILTYP;
    IDX:1..MAXSTR;
    JSKIP:INTEGER;
    PendingProcess, { local variable only }
    JUNK:BOOLEAN;
    i,DEBUG2: INTEGER;


   BEGIN
    CMDFIL[STDIN]:=STDIO;
    { make STDOUT and STDERR normal buffered files; this eliminates
      one layer of if checks and procedure calls }
    NAMESTR(FNAME,'CON:');
    for FD := STDOUT to STDERR do begin
      CMDFIL[FD] := CLOSED;
      FDJUNK := MUSTOPEN(FNAME,IOWRITE);
    end;
{    CMDFIL[STDOUT]:=STDIO;
    CMDFIL[STDERR]:=STDIO;
}
    FOR FD:=SUCC(STDERR) TO MAXOPEN DO
     CMDFIL[FD]:=CLOSED;
    KBDN:=0;
    if EntryFromHost then
       begin
        writeln('Software tools, version ',Version,
                ',  type "help" for command list');
        PendingProcess := FALSE;
        SetEntryFromHost(FALSE);
       end
     else PendingProcess := ActiveProcessQ;
    FromPipe := PendingProcess and (PipeCount > 0);
    if PendingProcess
     then
       begin
        SCOPY(ProcessQueue,1,CMDLIN,1);
        if Debug or ListProcess then
          PUTSTR(CMDLIN,STDERR);
        if FromPipe then
           begin
            XCLOSE(STDIN);
            GenPipeName(PipeCount,FNAME);
            FD := MUSTOPEN(FNAME,IOREAD);
           end;
       end
     else
       begin
        PipeCount := 0;
        write(ShellPrompt);
        ReadingShellCmd := true; { flag for GETKBD }
        if (not getline(cmdlin,STDIN,MAXSTR)) then begin
          writeln('  eof to shell'); ExitToHost; end;
        ReadingShellCmd := false;
       end;
    CMDARGS:=0;
    JSKIP:=0;  { counts quotes already skipped }
    IDX:=1;
    WHILE  (not (CMDLIN[IDX] in [ENDSTR,NEWLINE,PIPE,SEQPRCS])) DO
      BEGIN
       WHILE((CMDLIN[IDX]=BLANK)AND(JSKIP MOD 2 <>1))DO
        IDX:=IDX+1;
       IF NOT(CMDLIN[IDX] IN [NEWLINE,PIPE,SEQPRCS]) THEN
          BEGIN { next argument }
           CMDARGS:=CMDARGS+1;
           CMDIDX[CMDARGS]:=IDX-JSKIP;
           WHILE((CMDLIN[IDX]<>NEWLINE) AND
           (NOT(CMDLIN[IDX] IN [BLANK,PIPE,SEQPRCS])OR(ODD(JSKIP)))) DO
             BEGIN
              IF (CMDLIN[IDX]=DQUOTE)
               THEN JSKIP:=JSKIP+1
               ELSE CMDLIN[IDX-JSKIP]:=CMDLIN[IDX];
              IDX := IDX+1;
             END;
           if (CMDLIN[IDX] IN [PIPE,SEQPRCS]) then
             for i:= MAXSTR downto (IDX-JSKIP+1) do { don't overwrite }
              CMDLIN[i] := CMDLIN[i-1];
           CMDLIN[IDX-JSKIP]:=ENDSTR;
           IDX:=IDX+1;
           { redirection }
           IF (CMDLIN[CMDIDX[CMDARGS]]=LESS) THEN
              BEGIN
               XCLOSE(STDIN);
               CMDIDX[CMDARGS]:=CMDIDX[CMDARGS]+1;
               JUNK:=GETARG(CMDARGS,FNAME,MAXSTR);
               FD:=MUSTOPEN(FNAME,IOREAD);
               CMDARGS:=CMDARGS-1;
              END
            ELSE
             IF (CMDLIN[CMDIDX[CMDARGS]]=GREATER) THEN
                BEGIN
                 XCLOSE(STDOUT);
                 CMDIDX[CMDARGS]:=CMDIDX[CMDARGS]+1;
                 JUNK:=GETARG(CMDARGS,FNAME,MAXSTR);
                 FD:=MUSTCREATE(FNAME,IOWRITE);
                 CMDARGS:=CMDARGS-1;
                END
              ELSE
               IF Debug then
                  BEGIN
                   WRITE(' arg ',CMDARGS:1,' ');
                   DEBUG2 := CMDIDX[CMDARGS];
                   WHILE CMDLIN[DEBUG2]<>ENDSTR DO
                     BEGIN
                      WRITE(CHR(CMDLIN[DEBUG2])); DEBUG2:=DEBUG2+1;
                     END;
                   WRITELN;
                  END
          END
      END;
    ToPipe := CMDLIN[IDX] = PIPE;
    ActiveProcessQ := ToPipe or (CMDLIN[IDX]=SEQPRCS);
    if ActiveProcessQ then
       begin
        SCOPY(CMDLIN,(IDX+1),ProcessQueue,1);{ preserve remainder of command }
        if ToPipe then
           begin
            XCLOSE(STDOUT);  PipeCount := PipeCount+1;
            GenPipeName(PipeCount,FNAME);
            FD := MUSTCREATE(FNAME,IOWRITE);
           end;
       end;
   END { INITCMD };



procedure Shell;
{ Chain to proper file }
VAR CMDPTR:FILE;
  str:STRING80;
  COMMAND:XSTRING;
  DONE:BOOLEAN;
  I, Chapter, Position:INTEGER;
CONST
  (* This is horribly non-standard (only Turbo), but saves memory *)
  AllCmds: array[0..8] of string [54] =
    (* must have blank before AND after each command *)
    (' quit help ',
     ' charcount copy linecount wordcount detab list shell ',
     ' entab overstrike compress expand echo translit ',
     ' compare include concat print makecopy archive ',
     ' sort unique kwic unrotate ',   { ' rotate ' not supported }
     ' find change ',
     ' edit ',
     ' format ',
     ' define macro ');

 procedure GiveHelp;
 var ch: integer;
 begin
   writeln; writeln('Commands:');
   for ch:= 1 to 8 do
     begin write(AllCmds[ch]); if ch in[1..3,6] then writeln end;
   writeln(AllCmds[0]); writeln;
   writeln('Symbols:');
   write(' ''|'' pipe, '';'' next process,');
   writeln(' redirection: ''>'' to file, ''<'' from file.');
   write(' ''^Z'' (control-Z) terminate console input,');
   writeln('  " " quote arguments.');
   writeln;
 end { GiveHelp };


 function LowCase(c:char):char;
 begin
   if c in ['A'..'Z']
     then LowCase := char(ord(c)+32)
     else LowCase := c;
 end;


PROCEDURE SETCHAIN(chapnum:char);
  var len : integer; tempstr:string80;
BEGIN
  ASSIGN(CMDPTR,CONCAT(SystemDrive,'CHAPTER',chapnum,'.CHN'));
  (* put non-abbreviated form in global variable *)
  len := length(AllCmds[Chapter]);
  tempstr := copy(AllCmds[Chapter],(Position+1),(len-Position));
  GlobalArg1 :=
        copy( tempstr, 1, (pos(' ',tempstr)-1) ); (* strip commands after *)
  DONE:=TRUE
END;


BEGIN { Shell }
  DONE:=FALSE;
  repeat
    INITCMD;
    IF GETARG(1,COMMAND,MAXSTR) THEN BEGIN
      str:=' ';
      FOR I:=1 TO XLENGTH(COMMAND) DO
         str := CONCAT(str,LowCase(chr(COMMAND[I])));
      if not Abbreviate then str := concat(str,' ');
      Chapter := -1;
      repeat
        Chapter := Chapter + 1;
        Position := Pos(str,AllCmds[Chapter]); { Turbo, nonstandard }
      until (Chapter=9) or (Position>0);
      if Chapter=0 then {pseudo-chapter "0"}
         begin if Position=1 then ExitToHost else GiveHelp end
       else if Position>0
        then SETCHAIN(chr(Chapter+ord('0')))   { good command, real chapter }
        else  { bad command }
                BEGIN WRITELN(str,'?');DONE:=FALSE END;
    END { IF GETARG };
  until DONE;
  CHAIN(CMDPTR)  { <--  if I/O Error 01, check configuration in TOOLU.PAS }
 END { Shell };


BEGIN
  Shell;
END.


