{ Copyright (c) 1981 By: Bell Telephone Laboratories, Inc. and Whitesmith's Ltd., This software is derived from the book "Software Tools in Pascal", by Brian W. Kernighan and P. J. Plauger Addison-Wesley, 1981 ISBN 0-201-10342-7 Right is hereby granted to freely distribute or duplicate this software, providing distribution or duplication is not for profit or other commercial gain and that this copyright notice remains intact. } CONST IOERROR=0; STDIN=1; STDOUT=2; STDERR=3; (*IO RELEATED STUFF*) MAXOPEN=7; IOREAD=0; IOWRITE=1; MAXCMD=20; ENDFILE=255; BLANK=32; ENDSTR=0; MAXSTR=100; BACKSPACE=8; TAB=9; NEWLINE=10; EXCLAM=33; DQUOTE=34; SHARP=35; DOLLAR=36; PERCENT=37; AMPER=38; SQUOTE=39; ACUTE=SQUOTE; LPAREN=40; RPAREN=41; STAR=42; PLUS=43; COMMA=44; MINUS=45; DASH=MINUS; PERIOD=46; SLASH=47; COLON=58; SEMICOL=59; LESS=60; EQUALS=61; GREATER=62; QUESTION=63; ATSIGN=64; ESCAPE=ATSIGN; LBRACK=91; BACKSLASH=92; RBRACK=93; CARET=94; GRAVE=96; UNDERLINE=95; TILDE=126; LBRACE=123; BAR=124; RBRACE=125; TYPE CHARACTER=0..255; XSTRING=ARRAY[1..MAXSTR]OF CHARACTER; STRING80=string[80]; FILEDESC=IOERROR..MAXOPEN; FILTYP=(CLOSED,STDIO,FIL1,FIL2,FIL3,FIL4); VAR KBDN,KBDNEXT:INTEGER; KBDLINE:XSTRING; CMDARGS:0..MAXCMD; CMDIDX:ARRAY[1..MAXCMD] OF 1..MAXSTR; CMDLIN:XSTRING; CMDLINE:STRING80; CMDFIL:ARRAY[STDIN..MAXOPEN]OF FILTYP; CMDOPEN:ARRAY[FILTYP]OF BOOLEAN; FILE1,FILE2,FILE3,FILE4:TEXT; FUNCTION GETKBD(VAR C:CHARACTER):CHARACTER;FORWARD; FUNCTION FGETCF(VAR FIL:TEXT):CHARACTER;FORWARD; FUNCTION GETCF(VAR C:CHARACTER;FD:FILEDESC):CHARACTER;FORWARD; FUNCTION GETC(VAR C:CHARACTER):CHARACTER;FORWARD; PROCEDURE FPUTCF(C:CHARACTER;VAR FIL:TEXT);FORWARD; PROCEDURE PUTCF(C:CHARACTER;FD:FILEDESC);FORWARD; PROCEDURE PUTC(C:CHARACTER);FORWARD; PROCEDURE PUTDEC(N,W:INTEGER);FORWARD; FUNCTION ITOC(N:INTEGER;VAR S:XSTRING;I:INTEGER):INTEGER;FORWARD; FUNCTION GETARG(N:INTEGER;VAR S:XSTRING; MAXSIZE:INTEGER):BOOLEAN;FORWARD; PROCEDURE SCOPY(VAR SRC:XSTRING;I:INTEGER;VAR DEST:XSTRING;J:INTEGER);FORWARD; PROCEDURE ENDCMD;FORWARD; PROCEDURE XCLOSE(FD:FILEDESC);FORWARD; FUNCTION MUSTCREATE(VAR NAME:XSTRING;MODE:INTEGER): FILEDESC;FORWARD; FUNCTION CREATE(VAR NAME:XSTRING;MODE:INTEGER):FILEDESC;FORWARD; FUNCTION XLENGTH(VAR S:XSTRING):INTEGER;FORWARD; PROCEDURE STRNAME(VAR STR:STRING80;VAR XSTR:XSTRING);FORWARD; PROCEDURE ERROR(STR:STRING80);FORWARD; FUNCTION MAX(X,Y:INTEGER):INTEGER;FORWARD; PROCEDURE REMOVE(NAME:XSTRING);FORWARD; FUNCTION GETLINE(VAR STR:XSTRING;FD:FILEDESC; SIZE:INTEGER):BOOLEAN;FORWARD; FUNCTION OPEN(VAR NAME:XSTRING;MODE:INTEGER): FILEDESC;FORWARD; FUNCTION FDALLOC:FILEDESC;FORWARD; FUNCTION FTALLOC:FILTYP;FORWARD; FUNCTION NARGS:INTEGER;FORWARD; FUNCTION ADDSTR(C:CHARACTER;VAR OUTSET:XSTRING; VAR J:INTEGER;MAXSET:INTEGER):BOOLEAN;FORWARD; PROCEDURE PUTSTR(STR:XSTRING;FD:FILEDESC);FORWARD; FUNCTION MUSTOPEN(VAR NAME:XSTRING;MODE:INTEGER):FILEDESC;FORWARD; FUNCTION MIN(X,Y:INTEGER):INTEGER;FORWARD; FUNCTION ISUPPER(C:CHARACTER):BOOLEAN;FORWARD; FUNCTION EQUAL(VAR STR1,STR2:XSTRING):BOOLEAN;FORWARD; FUNCTION INDEX(VAR S:XSTRING;C:CHARACTER):INTEGER;FORWARD; FUNCTION ISALPHANUM(C:CHARACTER):BOOLEAN;FORWARD; FUNCTION ESC(VAR S:XSTRING;VAR I:INTEGER): CHARACTER;FORWARD; PROCEDURE FCOPY(FIN,FOUT:FILEDESC);FORWARD; FUNCTION CTOI(VAR S:XSTRING;VAR I:INTEGER):INTEGER;FORWARD; FUNCTION ISDIGIT(C:CHARACTER):BOOLEAN;FORWARD; FUNCTION ISLOWER(C:CHARACTER):BOOLEAN;FORWARD; FUNCTION ISLETTER(C:CHARACTER):BOOLEAN;FORWARD; FUNCTION ISDIGIT; BEGIN ISDIGIT:=C IN [ORD('0')..ORD('9')] END; FUNCTION ISLOWER; BEGIN ISLOWER:=C IN [97..122] END; FUNCTION ISLETTER; BEGIN ISLETTER:=C IN [65..90]+[97..122] END; FUNCTION CTOI; VAR N,SIGN:INTEGER; BEGIN WHILE (S[I]=BLANK) OR (S[I]=TAB)DO I:=I+1; IF(S[I]=MINUS) THEN SIGN:=-1 ELSE SIGN:=1; IF(S[I]=PLUS)OR(S[I]=MINUS)THEN I:=I+1; N:=0; WHILE(ISDIGIT(S[I])) DO BEGIN N:=10*N+S[I]-ORD('0'); I:=I+1 END; CTOI:=SIGN*N END; PROCEDURE FCOPY; VAR C:CHARACTER; BEGIN WHILE(GETCF(C,FIN)<>ENDFILE) DO PUTCF(C,FOUT) END; FUNCTION INDEX; VAR I:INTEGER; BEGIN I:=1; WHILE(S[I]<>C) AND (S[I]<>ENDSTR)DO I:=I+1; IF (S[I]=ENDSTR) THEN INDEX:=0 ELSE INDEX:=I END; FUNCTION ESC; BEGIN IF(S[I]<>ATSIGN) THEN ESC:=S[I] ELSE IF(S[I+1]=ENDSTR) THEN (*@ NOT SPECIAL AT END*) ESC:=ATSIGN ELSE BEGIN I:=I+1; IF(S[I]=ORD('N'))THEN ESC:=NEWLINE ELSE IF (S[I]=ORD('T')) THEN ESC:=TAB ELSE ESC:=S[I] END END; FUNCTION ISALPHANUM; BEGIN ISALPHANUM:=C IN [ORD('A')..ORD('Z'),ORD('0')..ORD('9'), 97..122] END; FUNCTION MAX; BEGIN IF(X>Y)THEN MAX:=X ELSE MAX:=Y END; FUNCTION MIN; BEGIN IF XENDSTR)DO N:=N+1; XLENGTH:=N-1 END; FUNCTION GETARG; BEGIN IF((N<1)OR(CMDARGSENDSTR)DO BEGIN DEST[J]:=SRC[I]; I:=I+1; J:=J+1 END; DEST[J]:=ENDSTR; END; (*$I-*) FUNCTION CREATE; VAR FD:FILEDESC; SNM:STRING80; BEGIN FD:=FDALLOC; IF(FD<>IOERROR)THEN BEGIN STRNAME(SNM,NAME); CASE (CMDFIL[FD])OF FIL1: begin assign(FILE1,SNM);rewrite(FILE1) end; FIL2:begin assign(FILE2,SNM);rewrite(FILE2) end; FIL3:begin assign(FILE3,SNM);rewrite(FILE3) end; FIL4:begin assign(FILE4,SNM);rewrite(FILE4) end END; IF(IORESULT<>0)THEN BEGIN XCLOSE(FD); FD:=IOERROR END END; CREATE:=FD; END; (*$I+*) PROCEDURE STRNAME; VAR I:INTEGER; BEGIN STR:='.PAS'; I:=1; WHILE(XSTR[I]<>ENDSTR)DO BEGIN INSERT('X',STR,I); STR[I]:=CHR(XSTR[I]); I:=I+1 END END; PROCEDURE ERROR; BEGIN WRITELN(STR); HALT END; FUNCTION MUSTCREATE; VAR FD:FILEDESC; BEGIN FD:=CREATE(NAME,MODE); IF(FD=IOERROR)THEN BEGIN PUTSTR(NAME,STDERR); ERROR(' :CAN''T CREATE FILE') END; MUSTCREATE:=FD END; FUNCTION NARGS; BEGIN NARGS:=CMDARGS END; PROCEDURE REMOVE; VAR FD:FILEDESC; BEGIN FD:=OPEN(NAME,IOREAD); IF(FD=IOERROR)THEN WRITELN('CAN''T REMOVE FILE') ELSE BEGIN CASE (CMDFIL[FD]) OF FIL1:CLOSE(FILE1); FIL2:CLOSE(FILE2); FIL3:CLOSE(FILE3); FIL4:CLOSE(FILE4); END END; CMDFIL[FD]:=CLOSED END; FUNCTION GETLINE; VAR I,ii:INTEGER; DONE:BOOLEAN; CH:CHARACTER; BEGIN I:=0; REPEAT DONE:=TRUE; CH:=GETCF(CH,FD); IF(CH=ENDFILE) THEN I:=0 ELSE IF (CH=NEWLINE) THEN BEGIN I:=I+1; STR[I]:=NEWLINE END ELSE IF (SIZE-2<=I) THEN BEGIN WRITELN('LINE TOO LONG'); I:=I+1; STR[I]:=NEWLINE END ELSE BEGIN DONE:=FALSE; I:=I+1; STR[I]:=CH; END UNTIL(DONE); STR[I+1]:=ENDSTR; GETLINE:=(0IOERROR) THEN BEGIN STRNAME(SNM,NAME); CASE (CMDFIL[FD]) OF FIL1:begin assign(FILE1,SNM);RESET(FILE1) end; FIL2:begin assign(FILE2,SNM);RESET(FILE2) end; FIL3:begin assign(FILE3,SNM);RESET(FILE3) end; FIL4:begin assign(FILE4,SNM);RESET(FILE4) end END; IF(IORESULT<>0) THEN BEGIN XCLOSE(FD); FD:=IOERROR END END; OPEN:=FD END; (*$I+*) FUNCTION FTALLOC; VAR DONE:BOOLEAN; FT:FILTYP; BEGIN FT:=FIL1; REPEAT DONE:=(NOT CMDOPEN[FT] OR (FT=FIL4)); IF(NOT DONE) THEN FT:=SUCC(FT) UNTIL (DONE); IF(CMDOPEN[FT]) THEN FTALLOC:=CLOSED ELSE FTALLOC:=FT END; FUNCTION FDALLOC; VAR DONE:BOOLEAN; FD:FILEDESC; BEGIN FD:=STDIN; DONE:=FALSE; WHILE(NOT DONE) DO IF((CMDFIL[FD]=CLOSED) OR (FD=MAXOPEN))THEN DONE:=TRUE ELSE FD:=SUCC(FD); IF(CMDFIL[FD]<>CLOSED) THEN FDALLOC:=IOERROR ELSE BEGIN CMDFIL[FD]:=FTALLOC; IF(CMDFIL[FD]=CLOSED) THEN FDALLOC:=IOERROR ELSE BEGIN CMDOPEN[CMDFIL[FD]]:=TRUE; FDALLOC:=FD END END END;(*FDALLOC*) PROCEDURE ENDCMD; VAR FD:FILEDESC; BEGIN FOR FD:=STDIN TO MAXOPEN DO XCLOSE(FD) END; PROCEDURE XCLOSE; BEGIN CASE (CMDFIL[FD])OF CLOSED,STDIO:; FIL1:CLOSE(FILE1); FIL2:CLOSE(FILE2); FIL3:CLOSE(FILE3); FIL4:CLOSE(FILE4) END; CMDOPEN[CMDFIL[FD]]:=FALSE; CMDFIL[FD]:=CLOSED END; FUNCTION ADDSTR; BEGIN IF(J>MAXSET)THEN ADDSTR:=FALSE ELSE BEGIN OUTSET[J]:=C; J:=J+1; ADDSTR:=TRUE END END; PROCEDURE PUTSTR; VAR I:INTEGER; BEGIN I:=1; WHILE(STR[I]<>ENDSTR) DO BEGIN PUTCF(STR[I],FD); I:=I+1 END END; FUNCTION MUSTOPEN; VAR FD:FILEDESC; BEGIN FD:=OPEN(NAME,MODE); IF(FD=IOERROR)THEN BEGIN PUTSTR(NAME,STDERR); WRITELN(': CAN''T OPEN FILE') END; MUSTOPEN:=FD END; FUNCTION GETKBD; VAR DONE:BOOLEAN; i:integer; ch:char; BEGIN IF (KBDN<=0) THEN BEGIN KBDNEXT:=1; DONE:=FALSE; if (kbdn=-2) then begin readln; kbdn:=0 end else if (kbdn<0) then done:=true; WHILE(NOT DONE) DO BEGIN kbdn:=kbdn+1; DONE:=TRUE; if (eof(TRM)) then kbdn:=-1 else if eoln(TRM) then begin kbdline[kbdn]:=NEWLINE; readln(TRM); end else if (MAXSTR-1<=kbdn) then begin writeln('Line too long'); kbdline[kbdn]:=newline end ELSE begin read(TRM,ch); kbdline[kbdn]:=ord(ch); if (ord(ch)in [0..7,9..12,14..31]) then write('^',chr(ord(ch)+64)) else if (kbdline[kbdn]<>BACKSPACE) then {do nothing} ELSE begin write(ch,' ',ch); if (1=10)THEN I:=ITOC(N DIV 10,S, I); S[I]:=N MOD 10 + ORD('0'); S[I+1]:=ENDSTR; ITOC:=I+1; END END; PROCEDURE PUTDEC; VAR I,ND:INTEGER; S:XSTRING; BEGIN ND:=ITOC(N,S,1); FOR I:=ND TO W DO PUTC(BLANK); FOR I:=1 TO ND-1 DO PUTC(S[I]) END; FUNCTION EQUAL; VAR I:INTEGER; BEGIN I:=1; WHILE(STR1[I]=STR2[I])AND(STR1[I]<>ENDSTR) DO I:=I+1; EQUAL:=(STR1[I]=STR2[I]) END;