home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / beehive / zcat / tptool19.lbr / TOOLU.PQS / TOOLU.PAS
Pascal/Delphi Source File  |  1991-01-31  |  16KB  |  716 lines

  1. CONST
  2.  
  3.   Version ='1.9.e';
  4.           { x.x.y    Revisors: Please only renumber y, let McGee renumber x.x }
  5.  
  6.  
  7.   { ----------  CONFIGURATION to user's system and preferences ------------- }
  8.  
  9.   { hardware and OS configuration }
  10.  
  11.   SystemDrive ='A:';        { SHELL and all .CHN files will be on this disk }
  12.   ShellName   ='SHELL.COM'; { .CMD on CP/M-86, .COM on CP/M-80 and MS-DOS }
  13.   PipePrefix  ='$PIPE';     { prefix with memory disk if available }
  14.   TempEditFile='$EDTEMP';   { same }
  15.                             { (need to move STEMP and ARTEMP here also) }
  16.   TabSpaces   = 8;          { 4 in K&P, but 8 better for most terminals }
  17.   { To configure, also check inclusion of proper OS file in CHAPTER1.PAS  }
  18.  
  19.   { example configurations:
  20.          1.  AppleII with CP/M card and two floppy disks
  21.          2.  DEC Rainbow running CP/M-86, autobooting to
  22.                Winchester E:, with large memory drive M:
  23.          3.  DEC Rainbow running MS-DOS on two floppies,
  24.                system on B:, memory drive on E:
  25.  
  26.                      AppleII         Rainbow        Rainbow
  27.                      CP/M-80         CP/M-86        MS-DOS
  28.                      ----------      ----------     ----------
  29.     SystemDrive      'A:'            'E:'           'B:'
  30.     ShellName        'SHELL.COM'     'SHELL.CMD'    'SHELL.COM
  31.     PipePrefix       '$PIPE'         'M:$PIPE'      'E:$PIPE'
  32.     TempEditFile     '$EDTEMP'       'M:$EDTEMP'    'E:$EDTEMP'
  33.   }
  34.  
  35.  
  36.   { user preference configurations }
  37.  
  38.   ShellPrompt ='$ ';
  39.   EditPrompt  =TRUE;      { not in K&P; very hard to use edit without it }
  40.   Debug   = FALSE ;       { prints more info; can be handy while learning }
  41.   ListProcess = TRUE;     { echo second and subsequent processes }
  42.   Abbreviate = false;     { can shorten commands -- uses first match }
  43.   AppendFNamePAS = FALSE; { converts, i.e. filename "TEXT" to "TEXT.PAS" }
  44.   { K&P had AppendFNamePAS=TRUE, but it's confusing for non-program files }
  45.  
  46.   { --------------------- end of CONFIGURATION section --------------------- }
  47.  
  48.  
  49.   MAXCMD=20; { max arguments to one process }
  50.   ENDFILE=255;
  51.   ENDSTR=0;
  52.   MAXSTR=130;
  53.   { ASCII character set in decimal }
  54.   BLANK=32;
  55.   BACKSPACE=8; { backs up cursor one space; may be different from DELETE! }
  56.   DELETE1 = 127; { user types this to delete prior character entered }
  57.   DELETE2 =   8; { user can also delete with this (=DELETE1 to remove) }
  58.   TAB=9;
  59.   NEWLINE=13;   { internal eol flag; also, terminates console input line }
  60.   EXCLAM=33;
  61.   DQUOTE=34;
  62.   SHARP=35;
  63.   DOLLAR=36;
  64.   PERCENT=37;
  65.   AMPER=38;
  66.   SQUOTE=39;
  67.   ACUTE=SQUOTE;
  68.   LPAREN=40;
  69.   RPAREN=41;
  70.   STAR=42;
  71.   PLUS=43;
  72.   COMMA=44;
  73.   MINUS=45;
  74.   DASH=MINUS;
  75.   PERIOD=46;
  76.   SLASH=47;
  77.   COLON=58;
  78.   SEMICOL=59;
  79.   LESS=60;
  80.   EQUALS=61;
  81.   GREATER=62;
  82.   QUESTION=63;
  83.   ATSIGN=64;
  84.   ESCAPE=ATSIGN;
  85.   LBRACK=91;
  86.   BACKSLASH=92;
  87.   RBRACK=93;
  88.   CARET=94;
  89.   GRAVE=96;
  90.   UNDERLINE=95;
  91.   TILDE=126;
  92.   LBRACE=123;
  93.   BAR=124;
  94.   RBRACE=125;
  95.  
  96. TYPE
  97.   CHARACTER=0..255;
  98.   XSTRING=ARRAY[1..MAXSTR]OF CHARACTER;
  99.   STRING80=string[80];
  100.   FILEDESC=(IOERROR,STDIN,STDOUT,STDERR,F4,F5,F6,F7,F8,F9,F10,MAXOPEN);
  101.        (* add as many Fn numbers as you need files; > F7 needed only by sort *)
  102.   FileModes = (IOREAD,IOWRITE);
  103.   FILTYP=(CLOSED,STDIO,OpenFile);
  104.  
  105. VAR
  106.    { The process and pipe vars MUST be the first declared in every program }
  107.    { chained to.  Thus, do not declare any variables before $I TOOLU.PAS.  }
  108.  
  109.    ActiveProcessQ, FromPipe, ToPipe : boolean;
  110.    PipeCount : integer;
  111.    ProcessQueue : XSTRING;
  112.  
  113.    KBDN,KBDNEXT:INTEGER;
  114.    KBDLINE,CMDLIN:XSTRING;
  115.    CMDARGS:0..MAXCMD;
  116.    CMDIDX:ARRAY[1..MAXCMD] OF 1..MAXSTR;
  117.    GlobalArg1: STRING80;
  118.    CMDFIL:ARRAY[STDIN..MAXOPEN]OF FILTYP;
  119.    CMDText: ARRAY[STDIN..MAXOPEN] OF TEXT;
  120.    ReadingShellCmd : boolean;
  121.  
  122.  
  123. PROCEDURE PUTDEC(N,W:INTEGER);FORWARD;
  124. FUNCTION ITOC(N:INTEGER;VAR S:XSTRING;I:INTEGER):INTEGER;FORWARD;
  125. FUNCTION GETARG(N:INTEGER;VAR S:XSTRING; MAXSIZE:INTEGER):BOOLEAN;FORWARD;
  126.   PROCEDURE SCOPY(VAR SRC:XSTRING;I:INTEGER;VAR DEST:XSTRING;J:INTEGER);FORWARD;
  127. PROCEDURE ENDCMD;FORWARD;
  128. PROCEDURE XCLOSE(FD:FILEDESC);FORWARD;
  129. FUNCTION XLENGTH(VAR S:XSTRING):INTEGER;FORWARD;
  130. PROCEDURE ERROR(STR:STRING80);FORWARD;
  131. FUNCTION MAX(X,Y:INTEGER):INTEGER;FORWARD;
  132. PROCEDURE REMOVE(NAME:XSTRING);FORWARD;
  133. FUNCTION NARGS:INTEGER;FORWARD;
  134. FUNCTION ADDSTR(C:CHARACTER;VAR OUTSET:XSTRING;VAR J:INTEGER;MAXSET:INTEGER):
  135.                  BOOLEAN;FORWARD;
  136. PROCEDURE PUTSTR(STR:XSTRING;FD:FILEDESC);FORWARD;
  137. FUNCTION MIN(X,Y:INTEGER):INTEGER;FORWARD;
  138. FUNCTION ISUPPER(C:CHARACTER):BOOLEAN;FORWARD;
  139. FUNCTION EQUAL(VAR STR1,STR2:XSTRING):BOOLEAN;FORWARD;
  140. FUNCTION INDEX(VAR S:XSTRING;C:CHARACTER):INTEGER;FORWARD;
  141. FUNCTION ISALPHANUM(C:CHARACTER):BOOLEAN;FORWARD;
  142. FUNCTION ESC(VAR S:XSTRING;VAR I:INTEGER): CHARACTER;FORWARD;
  143. PROCEDURE FCOPY(FIN,FOUT:FILEDESC);FORWARD;
  144. FUNCTION CTOI(VAR S:XSTRING;VAR I:INTEGER):INTEGER;FORWARD;
  145. FUNCTION ISDIGIT(C:CHARACTER):BOOLEAN;FORWARD;
  146. FUNCTION ISLOWER(C:CHARACTER):BOOLEAN;FORWARD;
  147. FUNCTION ISLETTER(C:CHARACTER):BOOLEAN;FORWARD;
  148.  
  149.  
  150. { system support }
  151.  
  152.  
  153.  PROCEDURE GenPipeName(PipeNumber: integer; var name: XSTRING);
  154.  { Generate a pipe file name }
  155.  var str: STRING80;
  156.      len, i: integer;
  157.  begin
  158.    str := PipePrefix;  len := LENGTH(STR);
  159.    for i := 1 to len do  name[i] := ORD(str[i]);
  160.    name[len+1] := ENDSTR;
  161.    i := ITOC(PipeNumber,name,(len+1)); { append digits }
  162.  end;
  163.  
  164. procedure AssignPipe0(var f: text);
  165. var s: STRING80; name: XSTRING; i:integer;
  166. begin
  167.   GenPipeName(0,name);
  168.   s := '';  i := 1;
  169.   while name[i] <> ENDSTR do begin
  170.     s := s + chr(name[i]);  i:= i+1;
  171.   end;
  172.   {close(f);} { causes crash on CP/M-86 }
  173.   assign(f,s);
  174. end;
  175.  
  176.  
  177.  
  178. function EntryFromHost: boolean;
  179. { The routines EntryFromHost and SetEntryFromHost implement a boolean
  180.   variable which is always TRUE when SHELL is first invoked, and which
  181.   remains FALSE across subsequent invocations via Chain/Execute }
  182. { Implemented via a file name, which is portable across all Turbo systems }
  183. var pipe0: text;
  184. begin
  185.   AssignPipe0(pipe0);
  186.   {$I- } reset(pipe0);;  {$I+ }
  187.   EntryFromHost := (IOResult<>0);  { false if file exists }
  188.   close(pipe0);
  189.   { CP/M-80 allows minor speedup at cost of portability:  }
  190.   { replace all code in this procedure by: EntryFromHost:= (mem[$80]<>255) }
  191.   { and comment-out all code in SetEntryFromHost                           }
  192. end;
  193.  
  194. procedure SetEntryFromHost(entry: boolean);
  195.   var pipe0: text;
  196. begin
  197.   AssignPipe0(pipe0);
  198.   rewrite(pipe0); close(pipe0);     { access or create (empty) file }
  199.   if entry then erase(pipe0); { remove file }
  200. end;
  201.  
  202.  
  203.  
  204. procedure ExitToHost;
  205. { Exit program by calling this.  DO NOT CALL HALT DIRECTLY! }
  206. BEGIN
  207.   SetEntryFromHost(TRUE);
  208.   HALT;
  209. END;
  210.  
  211. procedure ExitToShell;
  212. VAR cmdptr: file;
  213. BEGIN
  214.   assign(cmdptr,SystemDrive+ShellName);
  215.   execute(cmdptr)
  216. END;
  217.  
  218. procedure RemovePipe(OldPipe: integer);
  219. var name: XSTRING;
  220. begin
  221.     GenPipeName(OldPipe,name);
  222.     REMOVE(name);
  223. end;
  224.  
  225.  
  226. FUNCTION ISDIGIT;
  227. BEGIN
  228.   ISDIGIT:=C IN [ORD('0')..ORD('9')]
  229. END;
  230.  
  231. FUNCTION ISLOWER;
  232. BEGIN
  233.   ISLOWER:=C IN [ORD('a')..ORD('z')]
  234. END;
  235.  
  236. FUNCTION ISLETTER;
  237. BEGIN
  238.   ISLETTER:=C IN [ORD('A')..ORD('Z'),ORD('a')..ORD('z')]
  239. END;
  240.  
  241. FUNCTION CTOI;
  242. VAR N,SIGN:INTEGER;
  243. BEGIN
  244.   WHILE (S[I]=BLANK) OR (S[I]=TAB)DO
  245.     I:=I+1;
  246.   IF(S[I]=MINUS) THEN
  247.     SIGN:=-1
  248.   ELSE
  249.     SIGN:=1;
  250.   IF(S[I]=PLUS)OR(S[I]=MINUS)THEN
  251.     I:=I+1;
  252.   N:=0;
  253.   WHILE(ISDIGIT(S[I])) DO BEGIN
  254.     N:=10*N+S[I]-ORD('0');
  255.     I:=I+1
  256.   END;
  257.   CTOI:=SIGN*N
  258. END;
  259.  
  260.  
  261. FUNCTION GETKBD(VAR C:CHARACTER):CHARACTER;
  262. VAR DONE:BOOLEAN;
  263.     i:integer;
  264.     ch:char;
  265. BEGIN
  266.   IF (KBDN<=0) THEN BEGIN
  267.     KBDNEXT:=1;
  268.     DONE:=FALSE;
  269.     if (kbdn=-2) then begin kbdn:=0 end
  270.     else if (kbdn<0)then done:=true;
  271.     WHILE(NOT DONE) DO BEGIN
  272.       kbdn:=kbdn+1;
  273.       DONE:=TRUE;
  274.       if (eof(TRM)) then kbdn:=-1
  275.       else if eoln(TRM) then begin
  276.         kbdn:=kbdn-1;kbdline[kbdn]:=NEWLINE
  277.       end
  278.       else if (MAXSTR-1<=kbdn) then begin
  279.         if ReadingShellCmd then
  280.           ERROR(' Line too long - ignored')
  281.         else  begin
  282.           writeln(' Line too long - truncated');
  283.           kbdline[kbdn]:=newline
  284.         end
  285.       END
  286.       ELSE begin
  287.         read(TRM,ch);kbdline[kbdn]:=ord(ch);
  288.         if (ord(ch)in ([0..31]-[DELETE1,DELETE2,NEWLINE])) then
  289.            write('^',chr(ord(ch)+64)) else
  290.         if (kbdline[kbdn]<>DELETE1) and (kbdline[kbdn]<>DELETE2) then
  291.         ELSE begin
  292.           write(chr(BACKSPACE),' ',chr(BACKSPACE));
  293.           if (1<kbdn)then begin
  294.             kbdn:=kbdn-2;
  295.             if kbdline[kbdn+1]in[0..31] then
  296.                write(chr(BACKSPACE),' ',chr(BACKSPACE))
  297.           end
  298.           ELSE kbdn:=kbdn-1
  299.         end;
  300.         done:=false
  301.       end;
  302.     END
  303.   END;
  304.   reset(TRM);
  305.   IF(KBDN<=0)THEN
  306.     C:=ENDFILE
  307.   ELSE BEGIN
  308.     C:=KBDLINE[KBDNEXT];
  309.     KBDNEXT:=KBDNEXT+1;
  310.     if (c=NEWLINE) then kbdn:=-2
  311.     ELSE KBDN:=KBDN-1
  312.   END;
  313.   GETKBD:=C
  314. END;
  315.  
  316.  
  317.  
  318. FUNCTION FGETCF(VAR FIL:TEXT):CHARACTER;
  319.  VAR CH:CHAR;
  320.  BEGIN
  321.    {     -disabled -  $  I- do not hang on I/O error }
  322.    IF(EOF(FIL))THEN
  323.       FGETCF:=ENDFILE
  324.    ELSE IF(EOLN(FIL)) THEN BEGIN
  325.       READLN(FIL);
  326.       FGETCF:=NEWLINE
  327.    END
  328.    ELSE BEGIN
  329.      READ(FIL,CH);
  330.      FGETCF:=ORD(CH);
  331.    END;
  332.    if (IOresult <> 0) then
  333.       ERROR('FGETCF: I/O error');
  334.    {$I+ }
  335.  END;
  336.  
  337.  
  338. FUNCTION GETCF(VAR C:CHARACTER;FD:FILEDESC):CHARACTER;
  339.  BEGIN
  340.    IF CMDFIL[FD] = STDIO
  341.      THEN GETCF := GETKBD(C)
  342.      ELSE BEGIN C := FGETCF(CMDText[FD]); GETCF := C; END;
  343.  END;
  344.  
  345.  
  346. FUNCTION GETC(VAR C:CHARACTER):CHARACTER;
  347. BEGIN
  348.   GETC:=GETCF(C,STDIN)
  349. END;
  350.  
  351.  
  352. PROCEDURE PUTCF(C:CHARACTER;FD:FILEDESC);
  353. BEGIN
  354.   (* assert CMDFIL[FD] <> STDIO *)
  355.   if C=NEWLINE
  356.     THEN WRITELN(CMDText[FD])
  357.     ELSE WRITE(CMDText[FD],chr(C));
  358. END;
  359.  
  360.  
  361. PROCEDURE PUTC(C:CHARACTER);
  362. BEGIN
  363.   (* PUTCF(C,STDOUT); *)
  364.   if C=NEWLINE
  365.     then writeln(CMDText[STDOUT])
  366.     else write(CMDText[STDOUT],chr(C));
  367. END;
  368.  
  369.  
  370. PROCEDURE FCOPY;
  371. VAR
  372.   C:CHARACTER;
  373. BEGIN
  374.   WHILE(GETCF(C,FIN)<>ENDFILE) DO
  375.     PUTCF(C,FOUT)
  376. END;
  377.  
  378.  
  379. FUNCTION INDEX;
  380. VAR I:INTEGER;
  381. BEGIN
  382.   I:=1;
  383.   WHILE(S[I]<>C) AND (S[I]<>ENDSTR)DO
  384.     I:=I+1;
  385.   IF (S[I]=ENDSTR) THEN
  386.     INDEX:=0
  387.   ELSE
  388.     INDEX:=I
  389. END;
  390.  
  391. FUNCTION ESC;
  392. BEGIN
  393.   IF(S[I]<>ATSIGN) THEN
  394.     ESC:=S[I]
  395.   ELSE IF(S[I+1]=ENDSTR) THEN (*@ NOT SPECIAL AT END*)
  396.     ESC:=ATSIGN
  397.   ELSE BEGIN
  398.     I:=I+1;
  399.     IF(S[I]=ORD('n'))THEN ESC:=NEWLINE
  400.     ELSE IF (S[I]=ORD('t')) THEN
  401.       ESC:=TAB
  402.     ELSE
  403.       ESC:=S[I]
  404.   END
  405. END;
  406.  
  407. FUNCTION ISALPHANUM;
  408. BEGIN
  409.   ISALPHANUM:=C IN
  410.     [ORD('A')..ORD('Z'),ORD('0')..ORD('9'),
  411.     ORD('a')..ORD('z')]
  412. END;
  413.  
  414. FUNCTION MAX;
  415. BEGIN
  416.   IF(X>Y)THEN
  417.     MAX:=X
  418.   ELSE
  419.     MAX:=Y
  420. END;
  421.  
  422.  
  423. FUNCTION MIN;
  424. BEGIN
  425.   IF X<Y THEN
  426.     MIN:=X
  427.   ELSE
  428.     MIN:=Y
  429. END;
  430.  
  431.  
  432. FUNCTION ISUPPER;
  433.   BEGIN
  434.     ISUPPER:=C IN [ORD('A')..ORD('Z')]
  435.   END;
  436.  
  437.  
  438. FUNCTION XLENGTH;
  439. VAR
  440.   N:INTEGER;
  441. BEGIN
  442.   N:=1;
  443.   WHILE(S[N]<>ENDSTR)DO
  444.     N:=N+1;
  445.   XLENGTH:=N-1
  446. END;
  447.  
  448. FUNCTION GETARG;
  449. BEGIN
  450.   IF((N<1)OR(CMDARGS<N))THEN
  451.     GETARG:=FALSE
  452.   ELSE BEGIN
  453.     SCOPY(CMDLIN,CMDIDX[N],S,1);
  454.     GETARG:=TRUE
  455.   END
  456. END;(*GETARG*)
  457.  
  458.  
  459.   PROCEDURE SCOPY;
  460.   BEGIN
  461.     SRC[MAXSTR]:=ENDSTR;  { safety }
  462.     WHILE(SRC[I]<>ENDSTR)DO BEGIN
  463.       DEST[J]:=SRC[I];
  464.       I:=I+1;
  465.       J:=J+1
  466.     END;
  467.     DEST[J]:=ENDSTR
  468.   END;
  469.  
  470.  
  471. PROCEDURE STRNAME(VAR STR:STRING80;VAR XSTR:XSTRING);
  472. VAR I:INTEGER;
  473. BEGIN
  474.   IF AppendFNamePAS
  475.     THEN STR:='.PAS' else STR := '' ;
  476.   I:=1;
  477.   WHILE(XSTR[I]<>ENDSTR)DO BEGIN
  478.     INSERT('X',STR,I);
  479.     STR[I]:=CHR(XSTR[I]);
  480.     I:=I+1
  481.   END
  482. END;
  483.  
  484. PROCEDURE NAMESTR(VAR XSTR:XSTRING; STR:STRING80);
  485. VAR I: INTEGER;
  486. BEGIN
  487.   FOR I:= 1 TO length(STR) DO XSTR[I]:=ord(STR[I]);
  488.   XSTR[1+length(STR)] := ENDSTR;
  489. END;
  490.  
  491. FUNCTION FDALLOC:FILEDESC;
  492. VAR DONE:BOOLEAN;
  493. FD:FILEDESC;
  494. BEGIN
  495.   IF Debug THEN begin write('entry to FDALLOC: ');
  496.             for FD := STDIN TO MAXOPEN DO case CMDFIL[FD] OF
  497.             CLOSED: WRITE(' c'); STDIO:WRITE(' s'); OpenFile:write(' o'); end;
  498.            writeln;
  499.        end;
  500.   FD:=STDIN;
  501.   DONE:=FALSE;
  502.   WHILE(NOT DONE) DO
  503.     IF((CMDFIL[FD]=CLOSED) OR (FD=MAXOPEN))THEN
  504.       DONE:=TRUE
  505.     ELSE FD:=SUCC(FD);
  506.   IF(CMDFIL[FD]<>CLOSED) THEN
  507.     FDALLOC:=IOERROR
  508.   ELSE BEGIN
  509.     CMDFIL[FD]:= OpenFile;
  510.       FDALLOC:=FD
  511.   END
  512. END;(*FDALLOC*)
  513.  
  514.  
  515. FUNCTION CREATE(VAR NAME:XSTRING;MODE:FileModes):FILEDESC;
  516. VAR
  517.   FD:FILEDESC;
  518.   SNM:STRING80;
  519. BEGIN
  520. (*$I-*)
  521.   FD:=FDALLOC;
  522.   IF(FD<>IOERROR)THEN BEGIN
  523.   STRNAME(SNM,NAME);
  524.   ASSIGN(CMDText[FD],SNM); REWRITE(CMDText[FD]);
  525.   IF(IORESULT<>0)THEN BEGIN
  526.     XCLOSE(FD);
  527.     FD:=IOERROR
  528.   END
  529. END;
  530. CREATE:=FD;
  531. END;
  532. (*$I+*)
  533.  
  534.  
  535. PROCEDURE ERROR;
  536. BEGIN
  537.   WRITELN(STR);
  538.   ActiveProcessQ := FALSE;
  539.   if ToPipe then RemovePipe(PipeCount);
  540.   ENDCMD;
  541. END;
  542.  
  543.  
  544. FUNCTION MUSTCREATE(VAR NAME:XSTRING;MODE:FileModes):FILEDESC;
  545. VAR
  546.   FD:FILEDESC;
  547. BEGIN
  548.   FD:=CREATE(NAME,MODE);
  549.   IF(FD=IOERROR)THEN BEGIN
  550.     PUTSTR(NAME,STDERR);
  551.     ERROR(': can''t create file')
  552.   END;
  553.   MUSTCREATE:=FD
  554. END;
  555.  
  556. FUNCTION NARGS;
  557. BEGIN
  558.   NARGS:=CMDARGS
  559. END;
  560.  
  561. FUNCTION OPEN(VAR NAME:XSTRING;MODE:FileModes):FILEDESC;
  562. VAR FD:FILEDESC;
  563. SNM:STRING80;
  564. BEGIN
  565.   FD:=FDALLOC;
  566.   IF(FD<>IOERROR) THEN BEGIN
  567.     STRNAME(SNM,NAME);
  568.     ASSIGN(CMDText[FD],SNM);
  569. (*$I-*)
  570.     IF TRUE (* MODE=IOREAD *)
  571.       THEN RESET(CMDText[FD])
  572.       ELSE REWRITE(CMDText[FD]);
  573.     IF(IORESULT<>0) THEN BEGIN
  574.       XCLOSE(FD);
  575.       FD:=IOERROR
  576.     END
  577. (*$I+*)
  578.   END;
  579.   OPEN:=FD
  580. END;
  581.  
  582.  
  583. PROCEDURE REMOVE;
  584. VAR
  585.   FD:FILEDESC;
  586. BEGIN
  587.   FD:=OPEN(NAME,IOREAD);
  588.   IF(FD=IOERROR)THEN BEGIN
  589.      PUTSTR(NAME,STDERR);
  590.      WRITELN(': can''t remove file');
  591.   END
  592.   ELSE BEGIN
  593.     IF Debug THEN BEGIN PUTSTR(NAME,STDERR); WRITELN(' being removed'); END;
  594.     (* assert CMDFILE[FD]=OpenFile *)
  595.     CLOSE(CMDText[FD]); ERASE(CMDText[FD]);
  596.   END;
  597.   CMDFIL[FD]:=CLOSED
  598. END;
  599.  
  600. FUNCTION GETLINE(VAR STR:XSTRING;FD:FILEDESC; SIZE:INTEGER):BOOLEAN;
  601. VAR I:INTEGER;
  602.     DONE:BOOLEAN;
  603.     CH:CHARACTER;
  604. BEGIN
  605.  I:=0;
  606.  REPEAT
  607.    DONE:=TRUE;
  608.    CH:=GETCF(CH,FD);
  609.    IF(CH=ENDFILE) THEN
  610.      I:=0
  611.    ELSE IF (CH=NEWLINE) THEN BEGIN
  612.      I:=I+1;
  613.      STR[I]:=NEWLINE
  614.    END
  615.    ELSE IF (SIZE-2<=I) THEN BEGIN
  616.      WRITELN('LINE TOO LONG');
  617.      I:=I+1;
  618.      STR[I]:=NEWLINE
  619.    END
  620.    ELSE BEGIN
  621.      DONE:=FALSE;
  622.      I:=I+1;
  623.      STR[I]:=CH
  624.    END
  625.  UNTIL(DONE);
  626.  STR[I+1]:=ENDSTR;
  627.  GETLINE:=(0<I)
  628. END;(*GETLINE*)
  629.  
  630.  
  631.  
  632. PROCEDURE ENDCMD;
  633. VAR FD:FILEDESC;
  634. BEGIN
  635.   if FromPipe then RemovePipe(PipeCount-ORD(ToPipe));
  636.   if not ToPipe then PipeCount := 0;
  637.   FOR FD:=STDIN TO MAXOPEN DO  XCLOSE(FD);
  638.   ExitToShell;
  639. END;
  640.  
  641. PROCEDURE XCLOSE;
  642. BEGIN
  643.   IF CMDFIL[FD] = OpenFile THEN CLOSE(CMDText[FD]);
  644.   CMDFIL[FD]:=CLOSED
  645. END;
  646.  
  647. FUNCTION ADDSTR;
  648. BEGIN
  649.   IF(J>MAXSET)THEN
  650.     ADDSTR:=FALSE
  651.   ELSE BEGIN
  652.     OUTSET[J]:=C;
  653.     J:=J+1;
  654.     ADDSTR:=TRUE
  655.   END
  656. END;
  657.  
  658. PROCEDURE PUTSTR;
  659. VAR I:INTEGER;
  660. BEGIN
  661.   I:=1;
  662.   WHILE(STR[I]<>ENDSTR) DO BEGIN
  663.     PUTCF(STR[I],FD);
  664.     I:=I+1
  665.   END
  666. END;
  667.  
  668. FUNCTION MUSTOPEN(VAR NAME:XSTRING;MODE:FileModes):FILEDESC;
  669. VAR FD:FILEDESC;
  670. BEGIN
  671.   FD:=OPEN(NAME,MODE);
  672.   IF(FD=IOERROR)THEN BEGIN
  673.     PUTSTR(NAME,STDERR);
  674.     ERROR(': can''t open file.')
  675.   END;
  676.   MUSTOPEN:=FD
  677. END;
  678.  
  679.  
  680. FUNCTION ITOC;
  681. BEGIN
  682.   IF(N<0)THEN BEGIN
  683.     S[I]:=ORD('-');
  684.     ITOC:=ITOC(-N,S,I+1);
  685.   END
  686.   ELSE BEGIN
  687.     IF (N>=10)THEN
  688.       I:=ITOC(N DIV 10,S, I);
  689.     S[I]:=N MOD 10 + ORD('0');
  690.     S[I+1]:=ENDSTR;
  691.     ITOC:=I+1;
  692.   END
  693. END;
  694.  
  695. PROCEDURE PUTDEC;
  696. VAR I,ND:INTEGER;
  697.   S:XSTRING;
  698. BEGIN
  699.   ND:=ITOC(N,S,1);
  700.   FOR I:=ND TO W DO
  701.     PUTC(BLANK);
  702.   FOR I:=1 TO ND-1 DO
  703.     PUTC(S[I])
  704. END;
  705.   
  706. FUNCTION EQUAL;
  707. VAR
  708.   I:INTEGER;
  709. BEGIN
  710.   I:=1;
  711.   WHILE(STR1[I]=STR2[I])AND(STR1[I]<>ENDSTR) DO
  712.     I:=I+1;
  713.   EQUAL:=(STR1[I]=STR2[I])
  714. END;
  715.  
  716.