

     (******************************************************************)
     (*                                                                *)
     (*  Copyright (c) 1978 Regents of the University of California.   *)
     (*  Permission to copy or distribute this software or documen-    *)
     (*  tation in hard or soft copy granted only by written license   *)
     (*  obtained from the Institute for Information Systems.          *)
     (*                                                                *)
     (******************************************************************)

 PROCEDURE EXECERROR;
 BEGIN
   WITH SYSCOM^ DO
     BEGIN
       IF XEQERR = 4 THEN
         BEGIN RELEASE(EMPTYHEAP);
           PL := '*STK OFLOW*';
           UNITWRITE(2,PL[1],LENGTH(PL));
           EXIT(COMMAND)
         END;
       BOMBP^.MSIPC := BOMBIPC;
       IF BUGSTATE <> 0 THEN
         BEGIN DEBUGGER; XEQERR := 0 END
       ELSE
         BEGIN RELEASE(EMPTYHEAP);
           GFILES[0] := INPUTFIB; GFILES[1] := OUTPUTFIB;
           BOMBIPC := IORESULT; FWRITELN(SYSTERM^);
           IF UNITABLE[SYSUNIT].UVID = SYVID THEN
             PRINTERROR(XEQERR,BOMBIPC)
           ELSE
             BEGIN
               WRITE(OUTPUT,'Exec err # ',XEQERR);
               IF XEQERR = 10 THEN
                 WRITE(OUTPUT,',',BOMBIPC)
             END;
           WRITELN(OUTPUT);
           IF NOT SPACEWAIT(TRUE) THEN EXIT(COMMAND)
         END
     END
 END (*EXECERROR*) ;

 FUNCTION CHECKDEL(CH: CHAR; VAR SINX: INTEGER): BOOLEAN;
 BEGIN CHECKDEL := FALSE;
   WITH SYSCOM^,CRTCTRL DO
     BEGIN
       IF CH = CRTINFO.LINEDEL THEN
         BEGIN CHECKDEL := TRUE;
           IF (BACKSPACE = CHR(0)) OR (ERASEEOL = CHR(0)) THEN
             BEGIN SINX := 1;
               WRITELN(OUTPUT,'<DEL')
             END
           ELSE
             BEGIN
               WHILE SINX > 1 DO
                 BEGIN SINX := SINX-1; WRITE(OUTPUT,BACKSPACE) END;
               WRITE(OUTPUT,ESCAPE,ERASEEOL)
             END
         END;
       IF CH = CRTINFO.CHARDEL THEN
         BEGIN CHECKDEL := TRUE;
           IF SINX > 1 THEN
             BEGIN SINX := SINX-1;
               IF BACKSPACE = CHR(0) THEN
                 IF CRTINFO.CHARDEL < ' ' THEN
                   WRITE(OUTPUT,'_')
                 ELSE (*ASSUME PRINTABLE*)
               ELSE
                 BEGIN
                   IF CRTINFO.CHARDEL <> BACKSPACE THEN
                     WRITE(OUTPUT,BACKSPACE);
                   WRITE(OUTPUT,' ',BACKSPACE)
                 END
             END
           ELSE
             IF CRTINFO.CHARDEL = BACKSPACE THEN
               WRITE(OUTPUT,' ')
         END
     END
 END (*CHECKDEL*) ;


 PROCEDURE PUTPREFIXED(WHICH:INTEGER; COMMANDCHAR:CHAR);
 BEGIN
   WITH SYSCOM^ DO
     IF COMMANDCHAR <> CHR(0) THEN
       BEGIN
         IF CRTCTRL.PREFIXED[WHICH] THEN
           WRITE(OUTPUT,CRTCTRL.ESCAPE);
         WRITE(OUTPUT,COMMANDCHAR);
         IF LENGTH(FILLER)>0 THEN
           WRITE(OUTPUT,FILLER);
       END;
 END;

 PROCEDURE HOMECURSOR;
 BEGIN
   PUTPREFIXED(4,SYSCOM^.CRTCTRL.HOME);
 END (*HOMECURSOR*) ;
	
 PROCEDURE CLEARSCREEN;
 BEGIN HOMECURSOR;
   WITH SYSCOM^,CRTCTRL DO
     BEGIN
       IF MISCINFO.HAS8510A THEN UNITCLEAR(3);
       IF ERASEEOS <> CHR(0) THEN
         PUTPREFIXED(3,ERASEEOS)
       ELSE
         PUTPREFIXED(6,CLEARSCREEN)
     END
 END (*CLEARSCREEN*) ;

 PROCEDURE CLEARLINE;
 BEGIN
   PUTPREFIXED(2,SYSCOM^.CRTCTRL.ERASEEOL)
 END (*CLEARLINE*) ;

 PROCEDURE PROMPT;
   VAR I: INTEGER;
 BEGIN HOMECURSOR;
   WITH SYSCOM^ DO
     BEGIN
       CLEARLINE;
       IF MISCINFO.SLOWTERM THEN
         BEGIN
           I := SCAN(LENGTH(PL),=':',PL[1]);
           IF I <> LENGTH(PL) THEN PL[0] := CHR(I+1)
         END
     END;
   WRITE(OUTPUT,PL)
 END (*PROMPT*) ;

 PROCEDURE FGOTOXY(*X,Y: INTEGER*);
 BEGIN (*ASSUME DATA MEDIA*)
   WITH SYSCOM^.CRTINFO DO
     BEGIN
       IF X < 0 THEN X := 0;
       IF X > WIDTH THEN X := WIDTH;
       IF Y < 0 THEN Y := 0;
       IF Y > HEIGHT THEN Y := HEIGHT
     END;
   WRITE(OUTPUT,CHR(30),CHR(X+32),CHR(Y+32))
 END (*GOTOXY*) ;

 FUNCTION GETCHAR(*FLUSH: BOOLEAN*);
   VAR CH: CHAR;
 BEGIN
   IF FLUSH THEN UNITCLEAR(1);
   IF INPUTFIB^.FEOF THEN EXIT(COMMAND);
   INPUTFIB^.FSTATE := FNEEDCHAR;
   READ(INPUT,CH);
   IF (CH >= 'a') AND (CH <= 'z') THEN
     CH := CHR(ORD(CH)-ORD('a')+ORD('A'));
   GETCHAR := CH
 END (*GETCHAR*) ;

 FUNCTION SPACEWAIT(*FLUSH: BOOLEAN*);
   VAR CH: CHAR;
 BEGIN
   REPEAT
     WRITE(OUTPUT,'Type <space>');
     IF NOT SYSCOM^.MISCINFO.SLOWTERM THEN
       WRITE(OUTPUT,' to continue');
     CH := GETCHAR(FLUSH);
     IF NOT EOLN(INPUT) THEN
       WRITELN(OUTPUT);
     CLEARLINE
   UNTIL (CH = ' ') OR (CH = SYSCOM^.CRTINFO.ALTMODE);
   SPACEWAIT := CH <> ' '
 END (*SPACEWAIT*) ;

 FUNCTION SCANTITLE(*FTITLE: STRING; VAR FVID: VID; VAR FTID: TID;
                     VAR FSEGS: INTEGER; VAR FKIND: FILEKIND*);
   VAR I,RBRACK: INTEGER; CH: CHAR; OK: BOOLEAN;
 BEGIN
   FVID := ''; FTID := '';
   FSEGS := 0; FKIND := UNTYPEDFILE;
   SCANTITLE := FALSE; I := 1;
   WHILE I <= LENGTH(FTITLE) DO
     BEGIN CH := FTITLE[I];
       IF CH <= ' ' THEN DELETE(FTITLE,I,1)
       ELSE
         BEGIN
           IF (CH >= 'a') AND (CH <= 'z') THEN
             FTITLE[I] := CHR(ORD(CH)-ORD('a')+ORD('A'));
           I := I+1
         END
     END;
   IF LENGTH(FTITLE) > 0 THEN
     BEGIN
       IF FTITLE[1] = '*' THEN
         BEGIN FVID := SYVID; DELETE(FTITLE,1,1) END;
       I := POS(':',FTITLE);
       IF I <= 1 THEN
         BEGIN
           IF LENGTH(FVID) = 0 THEN FVID := DKVID;
           IF I = 1 THEN DELETE(FTITLE,1,1)
         END
       ELSE
         IF I-1 <= VIDLENG THEN
           BEGIN
             FVID := COPY(FTITLE,1,I-1);
             DELETE(FTITLE,1,I)
           END;
       IF LENGTH(FVID) > 0 THEN
         BEGIN
           I := POS('[',FTITLE);
           IF I > 0 THEN I := I-1
           ELSE I := LENGTH(FTITLE);
           IF I <= TIDLENG THEN
             BEGIN
               IF I > 0 THEN
                 BEGIN FTID := COPY(FTITLE,1,I); DELETE(FTITLE,1,I) END;
               IF LENGTH(FTITLE) = 0 THEN OK := TRUE
               ELSE
                 BEGIN OK := FALSE;
                   RBRACK := POS(']',FTITLE);
                   IF RBRACK = 2 THEN OK := TRUE
                   ELSE
                     IF RBRACK > 2 THEN
                       BEGIN OK := TRUE; I := 2;
                         REPEAT CH := FTITLE[I];
                           IF CH IN DIGITS THEN
                             FSEGS := FSEGS*10+(ORD(CH)-ORD('0'))
                           ELSE OK := FALSE;
                           I := I+1
                         UNTIL (I = RBRACK) OR NOT OK;
                         IF (I = 3) AND (RBRACK = 3) THEN
                           IF FTITLE[I-1] = '*' THEN
                             BEGIN FSEGS := -1; OK := TRUE END
                       END
                 END;
               SCANTITLE := OK;
               IF OK AND (LENGTH(FTID) > 5) THEN
                 BEGIN
                   FTITLE := COPY(FTID,LENGTH(FTID)-4,5);
                   IF FTITLE = '.TEXT' THEN FKIND := TEXTFILE
                   ELSE
                   IF FTITLE = '.CODE' THEN FKIND := CODEFILE
                   ELSE
                   IF FTITLE = '.INFO' THEN FKIND := INFOFILE
                   ELSE
                   IF FTITLE = '.GRAF' THEN FKIND := GRAFFILE
                   ELSE
                   IF FTITLE = '.FOTO' THEN FKIND := FOTOFILE
                 END
             END
         END
     END
 END (*SCANTITLE*) ;

 (* VOLUME AND DIRECTORY HANDLERS *)

 FUNCTION FETCHDIR(FUNIT: UNITNUM): BOOLEAN;
   VAR LINX: DIRRANGE; OK: BOOLEAN; HNOW: INTEGER;
 BEGIN FETCHDIR := FALSE;
   WITH SYSCOM^,UNITABLE[FUNIT] DO
     BEGIN (*READ IN AND VALIDATE DIR*)
       IF GDIRP = NIL THEN NEW(GDIRP);
       UNITREAD(FUNIT,GDIRP^,SIZEOF(DIRECTORY),DIRBLK);
       OK := IORSLT = INOERROR;
       IF OK THEN
         WITH GDIRP^[0] DO
           BEGIN OK := FALSE; (*CHECK OUT DIR*)
             IF (DFIRSTBLK = 0) AND
                 (  (MISCINFO.USERKIND=BOOKER)
               OR ( (MISCINFO.USERKIND IN [AQUIZ,PQUIZ]) AND (DFKIND=SECUREDIR) )
                   OR ( (MISCINFO.USERKIND=NORMAL) AND (DFKIND=UNTYPEDFILE) ) )
               THEN
               IF (LENGTH(DVID) > 0) AND (LENGTH(DVID) <= VIDLENG) AND
                  (DNUMFILES >= 0) AND (DNUMFILES <= MAXDIR) THEN
                 BEGIN OK := TRUE; (*SO FAR SO GOOD*)
                   IF DVID <> UVID THEN
                     BEGIN (*NEW VOLUME IN UNIT...CAREFUL*)
                       LINX := 1;
                       WHILE LINX <= DNUMFILES DO
                         WITH GDIRP^[LINX] DO
                           IF (LENGTH(DTID) <= 0) OR
                              (LENGTH(DTID) > TIDLENG) OR
                              (DLASTBLK < DFIRSTBLK) OR
                              (DLASTBYTE > FBLKSIZE) OR
                              (DLASTBYTE <= 0) OR
                              (DACCESS.YEAR >= 100) THEN
                             BEGIN OK := FALSE; DELENTRY(LINX,GDIRP) END
                           ELSE
                             LINX := LINX+1;
                       IF NOT OK THEN
                         BEGIN (*MUST HAVE BEEN CHANGED...WRITEIT*)
                           UNITWRITE(FUNIT,GDIRP^,
                                 (DNUMFILES+1)*SIZEOF(DIRENTRY),DIRBLK);
                           OK := IORSLT = INOERROR
                         END
                     END
                 END;
             IF OK THEN
               BEGIN UVID := DVID; UEOVBLK := DEOVBLK;
                 TIME(HNOW,DLOADTIME)
               END
           END;
       FETCHDIR := OK;
       IF NOT OK THEN
         BEGIN UVID := ''; UEOVBLK := MMAXINT;
           RELEASE(GDIRP); GDIRP := NIL
         END
     END
 END (*FETCHDIR*) ;

 PROCEDURE WRITEDIR(*FUNIT: UNITNUM; FDIR: DIRP*);
   VAR HNOW,LNOW: INTEGER; OK: BOOLEAN; LDE: DIRENTRY;
 BEGIN
   WITH UNITABLE[FUNIT],FDIR^[0] DO
     BEGIN OK := (UVID = DVID) AND ((DFKIND = UNTYPEDFILE) OR
                                    (DFKIND = SECUREDIR));
       IF OK THEN
         BEGIN TIME(HNOW,LNOW);
           OK := (LNOW-DLOADTIME <= AGELIMIT) AND
                 ((LNOW-DLOADTIME) >= 0) AND
                     SYSCOM^.MISCINFO.HASCLOCK;
           IF NOT OK THEN
             BEGIN (*NO CLOCK OR TOO OLD*)
               UNITREAD(FUNIT,LDE,SIZEOF(DIRENTRY),DIRBLK);
               IF IORESULT = ORD(INOERROR) THEN
                 OK := DVID = LDE.DVID;
             END;

           IF OK THEN
             BEGIN (*WE GUESS ALL IS SAFE...WRITEIT*)
               DFIRSTBLK := 0;   (*DIRTY FIX FOR YALOE BUGS*)
               UNITWRITE(FUNIT,FDIR^,
                         (DNUMFILES+1)*SIZEOF(DIRENTRY),DIRBLK);
               OK := IORESULT = ORD(INOERROR);
               IF DLASTBLK = 10 THEN (*REDUNDANT AFTERTHOUGHT*)
                 UNITWRITE(FUNIT,FDIR^,
                           (DNUMFILES+1)*SIZEOF(DIRENTRY),6);
               IF OK THEN TIME(HNOW,DLOADTIME)
             END
         END;
       IF NOT OK THEN
         BEGIN SYSCOM^.IORSLT := ILOSTUNIT;
           UVID := ''; UEOVBLK := MMAXINT
         END
     END
 END (*WRITEDIR*) ;

 FUNCTION VOLSEARCH(*VAR FVID: VID; LOOKHARD: BOOLEAN; VAR FDIR: DIRP*);
   VAR LUNIT: UNITNUM; OK,PHYSUNIT: BOOLEAN; HNOW,LNOW: INTEGER;
 BEGIN VOLSEARCH := 0; FDIR := NIL;
   OK := FALSE; PHYSUNIT := FALSE;
   IF LENGTH(FVID) > 0 THEN
     BEGIN
       IF (FVID[1] = '#') AND (LENGTH(FVID) > 1) THEN
         BEGIN OK := TRUE;
           LUNIT := 0; HNOW := 2;
           REPEAT
             IF FVID[HNOW] IN DIGITS THEN
               LUNIT := LUNIT*10+ORD(FVID[HNOW])-ORD('0')
             ELSE OK := FALSE;
             HNOW := HNOW+1
           UNTIL (HNOW > LENGTH(FVID)) OR NOT OK;
           PHYSUNIT := OK AND (LUNIT > 0) AND (LUNIT <= MAXUNIT)
         END;
       IF NOT PHYSUNIT THEN
         BEGIN OK := FALSE; LUNIT := MAXUNIT;
           REPEAT
             OK := FVID = UNITABLE[LUNIT].UVID;
             IF NOT OK THEN LUNIT := LUNIT-1
           UNTIL OK OR (LUNIT = 0)
         END
     END;
   IF OK THEN
     IF UNITABLE[LUNIT].UISBLKD THEN
       WITH SYSCOM^ DO
         BEGIN OK := FALSE;  (*SEE IF GDIRP IS GOOD*)
           IF GDIRP <> NIL THEN
             IF FVID = GDIRP^[0].DVID THEN
               BEGIN TIME(HNOW,LNOW);
                 OK := LNOW-GDIRP^[0].DLOADTIME <= AGELIMIT
               END;
           IF NOT OK THEN
             BEGIN OK := PHYSUNIT;
               IF FETCHDIR(LUNIT) THEN
                 IF NOT PHYSUNIT THEN
                   OK := FVID = GDIRP^[0].DVID
             END
         END;
   IF NOT OK AND LOOKHARD THEN
     BEGIN LUNIT := MAXUNIT; (*CHECK EACH DISK UNIT*)
       REPEAT
         WITH UNITABLE[LUNIT] DO
           IF UISBLKD THEN
             IF FETCHDIR(LUNIT) THEN
               OK := FVID = UVID;
         IF NOT OK THEN LUNIT := LUNIT-1
       UNTIL OK OR (LUNIT = 0)
     END;
   IF OK THEN
     WITH UNITABLE[LUNIT] DO
       BEGIN VOLSEARCH := LUNIT;
         IF LENGTH(UVID) > 0 THEN FVID := UVID;
         IF UISBLKD AND (SYSCOM^.GDIRP <> NIL) THEN
           BEGIN FDIR := SYSCOM^.GDIRP;
             TIME(HNOW,FDIR^[0].DLOADTIME)
           END
       END
 END (*VOLSEARCH*) ;

 FUNCTION DIRSEARCH(*VAR FTID: TID; FINDPERM: BOOLEAN; FDIR: DIRP*);
   VAR I: DIRRANGE; FOUND: BOOLEAN;
 BEGIN DIRSEARCH := 0; FOUND := FALSE; I := 1;
   WHILE (I <= FDIR^[0].DNUMFILES) AND NOT FOUND DO
     BEGIN
       WITH FDIR^[I] DO
         IF DTID = FTID THEN
           IF FINDPERM = (DACCESS.YEAR <> 100) THEN
             BEGIN DIRSEARCH := I; FOUND := TRUE END;
       I := I+1
     END
 END (*DIRSEARCH*) ;

 PROCEDURE DELENTRY(*FINX: DIRRANGE; FDIR: DIRP*);
   VAR I: DIRRANGE;
 BEGIN
   WITH FDIR^[0] DO
     BEGIN
       FOR I := FINX TO DNUMFILES-1 DO
         FDIR^[I] := FDIR^[I+1];
       FDIR^[DNUMFILES].DTID := '';
       DNUMFILES := DNUMFILES-1
     END
 END (*DELENTRY*) ;

 PROCEDURE INSENTRY(*VAR FENTRY: DIRENTRY; FINX: DIRRANGE; FDIR: DIRP*);
   VAR I: DIRRANGE;
 BEGIN
   WITH FDIR^[0] DO
     BEGIN
       FOR I := DNUMFILES DOWNTO FINX DO
         FDIR^[I+1] := FDIR^[I];
       FDIR^[FINX] := FENTRY;
       DNUMFILES := DNUMFILES+1
     END
 END (*INSENTRY*) ;

 FUNCTION ENTERTEMP(VAR FTID: TID; FSEGS: INTEGER;
                       FKIND: FILEKIND; FDIR: DIRP): DIRRANGE;
   VAR I,LASTI,DINX,SINX: DIRRANGE; RT11ISH: BOOLEAN;
       SSEGS: INTEGER; LDE: DIRENTRY;

   PROCEDURE FINDMAX(CURINX: DIRRANGE; FIRSTOPEN,NEXTUSED: INTEGER);
     VAR FREEAREA: INTEGER;
   BEGIN
     FREEAREA := NEXTUSED-FIRSTOPEN;
     IF FREEAREA > FSEGS THEN
       BEGIN
         SINX := DINX; SSEGS := FSEGS;
         DINX := CURINX; FSEGS := FREEAREA
       END
     ELSE
       IF FREEAREA > SSEGS THEN
         BEGIN SSEGS := FREEAREA; SINX := CURINX END
   END (*FINDMAX*) ;

 BEGIN (*ENTERTEMP*)
   DINX := 0; LASTI := FDIR^[0].DNUMFILES;
   SINX := 0; SSEGS := 0;
   IF FSEGS <= 0 THEN
     BEGIN RT11ISH := FSEGS < 0;
       FOR I := 1 TO LASTI DO
         FINDMAX(I,FDIR^[I-1].DLASTBLK,FDIR^[I].DFIRSTBLK);
       FINDMAX(LASTI+1,FDIR^[LASTI].DLASTBLK,FDIR^[0].DEOVBLK);
       IF RT11ISH THEN
         IF FSEGS DIV 2 <= SSEGS THEN
           BEGIN FSEGS := SSEGS; DINX := SINX END
         ELSE FSEGS := (FSEGS+1) DIV 2
     END
   ELSE
     BEGIN I := 1;
       WHILE I <= LASTI DO
         BEGIN
           IF FDIR^[I].DFIRSTBLK-FDIR^[I-1].DLASTBLK >= FSEGS THEN
             BEGIN DINX := I; I := LASTI END;
           I := I+1
         END;
       IF DINX = 0 THEN
         IF FDIR^[0].DEOVBLK-FDIR^[LASTI].DLASTBLK >= FSEGS THEN
           DINX := LASTI+1
     END;
   IF LASTI = MAXDIR THEN DINX := 0;
   IF DINX > 0 THEN
     BEGIN
       WITH LDE DO
         BEGIN
           DFIRSTBLK := FDIR^[DINX-1].DLASTBLK;
           DLASTBLK := DFIRSTBLK+FSEGS;
           DFKIND := FKIND; DTID := FTID;
           DLASTBYTE := FBLKSIZE;
           WITH DACCESS DO
             BEGIN MONTH := 0; DAY := 0; YEAR := 100 END
         END;
       INSENTRY(LDE,DINX,FDIR)
     END;
   ENTERTEMP := DINX
 END (*ENTERTEMP*) ;

 (* FILE STATE HANDLERS *)

 PROCEDURE FINIT(*VAR F: FIB; WINDOW: WINDOWP; RECWORDS: INTEGER*);
 BEGIN
   WITH F DO
     BEGIN FSTATE := FJANDW;
       FISOPEN := FALSE; FEOF := TRUE;
       FEOLN := TRUE; FWINDOW := WINDOW;
       IF (RECWORDS = 0) OR (RECWORDS = -2) THEN
         BEGIN
           FWINDOW^[1] := CHR(0); FRECSIZE := 1;
           IF RECWORDS = 0 THEN FSTATE := FNEEDCHAR
         END
       ELSE
         IF RECWORDS < 0 THEN
           BEGIN FWINDOW := NIL; FRECSIZE := 0 END
         ELSE FRECSIZE := RECWORDS+RECWORDS
     END
 END (*FINIT*) ;

 PROCEDURE RESETER(VAR F:FIB);
   VAR BIGGER: BOOLEAN;
 BEGIN
   WITH F DO
      BEGIN FREPTCNT := 0;
         FEOLN := FALSE; FEOF := FALSE;
         IF FISBLKD THEN
           BEGIN BIGGER := FNXTBLK > FMAXBLK;
             IF BIGGER THEN FMAXBLK := FNXTBLK;
             IF FSOFTBUF THEN
               BEGIN
                 IF BIGGER THEN FMAXBYTE := FNXTBYTE
                 ELSE
                   IF FNXTBLK = FMAXBLK THEN
                     IF FNXTBYTE > FMAXBYTE THEN
                         BEGIN BIGGER := TRUE; FMAXBYTE := FNXTBYTE END;
                 IF FBUFCHNGD THEN
                   BEGIN FBUFCHNGD := FALSE; FMODIFIED := TRUE;
                     IF BIGGER THEN
                       FILLCHAR(FBUFFER[FNXTBYTE],FBLKSIZE-FNXTBYTE,0);
                     UNITWRITE(FUNIT,FBUFFER,FBLKSIZE,
                                     FHEADER.DFIRSTBLK+FNXTBLK-1);
                     IF BIGGER AND (FHEADER.DFKIND = TEXTFILE)
                         AND ODD(FNXTBLK) THEN
                       BEGIN FMAXBLK := FMAXBLK+1;
                         FILLCHAR(FBUFFER,FBLKSIZE,0);
                         UNITWRITE(FUNIT,FBUFFER,FBLKSIZE,
                                         FHEADER.DFIRSTBLK+FNXTBLK)
                       END
                   END;
                 FNXTBYTE := FBLKSIZE
               END;
             FNXTBLK := 0;
             IF FSOFTBUF AND (FHEADER.DFKIND = TEXTFILE) THEN
                 FNXTBLK := 2
           END
      END
 END (*RESETER*) ;

 PROCEDURE FOPEN(*VAR F: FIB; VAR FTITLE: STRING;
                  FOPENOLD: BOOLEAN; JUNK PARAM*);
   LABEL 1;
   VAR LDIR: DIRP; LUNIT: UNITNUM; LINX: DIRRANGE;
       LSEGS,NBYTES: INTEGER; LKIND: FILEKIND;
       OLDHEAP: ^INTEGER; SWAPPED: BOOLEAN;
       SAVERSLT: IORSLTWD; LVID: VID; LTID: TID;
 BEGIN SYSCOM^.IORSLT := INOERROR;
   WITH F DO
     IF FISOPEN THEN SYSCOM^.IORSLT := INOTCLOSED
     ELSE
       IF SCANTITLE(FTITLE,LVID,LTID,LSEGS,LKIND) THEN
         BEGIN (*GOT AN OK TITLE*)
           IF ORD(FOPENOLD) > 1 THEN (*OLD CODE SPECIAL CASE*)
             FOPENOLD := (ORD(FOPENOLD) = 2) OR (ORD(FOPENOLD) = 4);
           SWAPPED := FALSE;
           WITH SWAPFIB^ DO
             IF FISOPEN AND (SYSCOM^.GDIRP = NIL) THEN
               BEGIN MARK(OLDHEAP);
                 NBYTES := ORD(SYSCOM^.LASTMP)-ORD(OLDHEAP);
                 IF (NBYTES > 0) AND (NBYTES < SIZEOF(DIRECTORY)+400) THEN
                   BEGIN
                     NBYTES := ORD(OLDHEAP)-ORD(EMPTYHEAP);
                     IF (NBYTES > 0) AND (NBYTES > SIZEOF(DIRECTORY)) AND
                         (UNITABLE[FUNIT].UVID = FVID) THEN
                       BEGIN
                         UNITWRITE(FUNIT,EMPTYHEAP^,SIZEOF(DIRECTORY),
                                         FHEADER.DFIRSTBLK);
                         RELEASE(EMPTYHEAP); SWAPPED := TRUE
                       END
                   END
               END;
           LUNIT := VOLSEARCH(LVID,TRUE,LDIR);
           IF LUNIT = 0 THEN SYSCOM^.IORSLT := INOUNIT
           ELSE
             WITH UNITABLE[LUNIT] DO
               BEGIN (*OK...OPEN UP FILE*)
                 FISOPEN := TRUE; FMODIFIED := FALSE;
                 FUNIT := LUNIT; FVID := LVID;
                 FNXTBLK := 0; FISBLKD := UISBLKD;
                 FSOFTBUF := UISBLKD AND (FRECSIZE <> 0);
                 IF (LDIR <> NIL) AND (LENGTH(LTID) > 0) THEN
                   BEGIN (*LOOKUP OR ENTER FHEADER IN DIRECTORY*)
                     LINX := DIRSEARCH(LTID,FOPENOLD,LDIR);
                     IF FOPENOLD THEN
                       IF LINX = 0 THEN
                         BEGIN SYSCOM^.IORSLT := INOFILE; GOTO 1 END
                       ELSE FHEADER := LDIR^[LINX]
                     ELSE (*OPEN NEW FILE*)
                       IF LINX > 0 THEN
                         BEGIN SYSCOM^.IORSLT := IDUPFILE; GOTO 1 END
                       ELSE
                         BEGIN (*MAKE A TEMP ENTRY*)
                           IF LKIND = UNTYPEDFILE THEN LKIND := DATAFILE;
                           LINX := ENTERTEMP(LTID,LSEGS,LKIND,LDIR);
                           IF (LINX > 0) AND (LKIND = TEXTFILE) THEN
                             WITH LDIR^[LINX] DO
                               BEGIN
                                 IF ODD(DLASTBLK-DFIRSTBLK) THEN
                                   DLASTBLK := DLASTBLK-1;
                                 IF DLASTBLK-DFIRSTBLK < 4 THEN
                                   BEGIN DELENTRY(LINX,LDIR); LINX := 0 END
                               END;
                           IF LINX = 0 THEN
                             BEGIN SYSCOM^.IORSLT := INOROOM; GOTO 1 END;
                           FHEADER := LDIR^[LINX]; FMODIFIED := TRUE;
                           WRITEDIR(LUNIT,LDIR)
                         END
                   END
                 ELSE (*FHEADER NOT IN DIRECTORY*)
                   WITH FHEADER DO
                     BEGIN (*DIRECT UNIT OPEN, SET UP DUMMY FHEADER*)
                       DFIRSTBLK := 0; DLASTBLK := MMAXINT;
                       IF UISBLKD THEN DLASTBLK := UEOVBLK;
                       DFKIND := LKIND; DTID := '';
                       DLASTBYTE := FBLKSIZE;
                       WITH DACCESS DO
                         BEGIN MONTH := 0; DAY := 0; YEAR := 0 END
                     END;
                 IF FOPENOLD THEN
                   FMAXBLK := FHEADER.DLASTBLK-FHEADER.DFIRSTBLK
                 ELSE FMAXBLK := 0;
                 IF FSOFTBUF THEN
                   BEGIN
                     FNXTBYTE := FBLKSIZE; FBUFCHNGD := FALSE;
                     IF FOPENOLD THEN FMAXBYTE := FHEADER.DLASTBYTE
                     ELSE FMAXBYTE := FBLKSIZE;
                     WITH FHEADER DO
                       IF DFKIND = TEXTFILE THEN
                         BEGIN FNXTBLK := 2;
                           IF NOT FOPENOLD THEN
                             BEGIN (*NEW .TEXT, PUT NULLS IN FIRST PAGE*)
                               FILLCHAR(FBUFFER,SIZEOF(FBUFFER),0);
                               UNITWRITE(FUNIT,FBUFFER,FBLKSIZE,DFIRSTBLK);
                               UNITWRITE(FUNIT,FBUFFER,FBLKSIZE,DFIRSTBLK+1)
                             END
                         END
                   END;
                 IF FOPENOLD THEN FRESET(F)
                 ELSE RESETER(F); (*NO GET!*)
         1:      IF IORESULT <> ORD(INOERROR) THEN
                   BEGIN FISOPEN := FALSE; FEOF := TRUE; FEOLN := TRUE END
               END;
           IF SWAPPED THEN
             BEGIN RELEASE(OLDHEAP); SYSCOM^.GDIRP := NIL;
               SAVERSLT := SYSCOM^.IORSLT;
               UNITREAD(SWAPFIB^.FUNIT,EMPTYHEAP^,SIZEOF(DIRECTORY),
                                 SWAPFIB^.FHEADER.DFIRSTBLK);
               SYSCOM^.IORSLT := SAVERSLT
             END
         END
       ELSE SYSCOM^.IORSLT := IBADTITLE
 END (*FOPEN*) ;

 PROCEDURE FCLOSE(*VAR F: FIB; FTYPE: CLOSETYPE*);
   LABEL 1;
   VAR LINX,DUPINX: DIRRANGE; LDIR: DIRP; FOUND: BOOLEAN;
 BEGIN SYSCOM^.IORSLT := INOERROR;
   WITH F DO
     IF FISOPEN AND (FWINDOW <> SYSTERM^.FWINDOW) THEN
       BEGIN
         IF FISBLKD THEN
           WITH FHEADER DO
             IF LENGTH(DTID) > 0 THEN
               BEGIN (*FILE IN A DISK DIRECTORY...FIXUP MAYBE*)
                 IF FTYPE = CCRUNCH THEN
                   BEGIN FMAXBLK := FNXTBLK;
                     DACCESS.YEAR := 100; FTYPE := CLOCK;
                     IF FSOFTBUF THEN FMAXBYTE := FNXTBYTE
                   END;
                 RESETER(F);
                 IF FMODIFIED OR (DACCESS.YEAR = 100) OR (FTYPE = CPURGE) THEN
                   BEGIN (*HAVE TO CHANGE DIRECTORY ENTRY*)
                     IF FUNIT <> VOLSEARCH(FVID,FALSE,LDIR) THEN
                       BEGIN SYSCOM^.IORSLT := ILOSTUNIT; GOTO 1 END;
                     LINX := 1; FOUND := FALSE;
                     WHILE (LINX <= LDIR^[0].DNUMFILES) AND NOT FOUND DO
                       BEGIN (*LOOK FOR FIRST BLOCK MATCH*)
                         FOUND := (LDIR^[LINX].DFIRSTBLK = DFIRSTBLK) AND
                                  (LDIR^[LINX].DLASTBLK = DLASTBLK);
                         LINX := LINX + 1
                       END;
                     IF NOT FOUND THEN
                       BEGIN SYSCOM^.IORSLT := ILOSTFILE; GOTO 1 END;
                     LINX := LINX - 1; (*CORRECT OVERRUN*)
                     IF ((FTYPE = CNORMAL) AND (LDIR^[LINX].DACCESS.YEAR = 100))
                            OR (FTYPE = CPURGE) THEN
                         DELENTRY(LINX,LDIR)  (*ZAP FILE OUT OF EXISTANCE*)
                     ELSE
                       BEGIN (*WELL...LOCK IN A PERM DIR ENTRY*)
                         DUPINX := DIRSEARCH(DTID,TRUE,LDIR);
                         IF (DUPINX <> 0) AND (DUPINX <> LINX) THEN
                           BEGIN (*A DUPLICATE PERM ENTRY...ZAP OLD ONE*)
                             DELENTRY(DUPINX,LDIR);
                             IF DUPINX < LINX THEN LINX := LINX-1
                           END;
                         IF LDIR^[LINX].DACCESS.YEAR = 100 THEN
                           IF DACCESS.YEAR = 100 THEN
                             DACCESS := THEDATE
                           ELSE (*LEAVE ALONE...FILER SPECIAL CASE*)
                         ELSE
                           IF FMODIFIED AND (THEDATE.MONTH <> 0) THEN
                             DACCESS := THEDATE
                           ELSE
                             DACCESS := LDIR^[LINX].DACCESS;
                         DLASTBLK := DFIRSTBLK+FMAXBLK;
                         IF FSOFTBUF THEN DLASTBYTE := FMAXBYTE;
                         FMODIFIED := FALSE; LDIR^[LINX] := FHEADER
                       END;
                     WRITEDIR(FUNIT,LDIR)
                   END
               END;
         IF FTYPE = CPURGE THEN
           IF LENGTH(FHEADER.DTID) = 0 THEN
             UNITABLE[FUNIT].UVID := '';
 1:      FEOF := TRUE; FEOLN := TRUE; FISOPEN := FALSE
       END
 END (*FCLOSE*) ;
