dos_compilers/Digital Research MT+86 Pascal v311/IOMOD.SRC
2024-06-30 11:44:12 -07:00

487 lines
11 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(* VERSION 0019 *)
(* Release 3.0 - April 1, 1982 - MGL *)
(* 06/08/81 *)
(* 08/11/81 *)
(* 12/01/81 FIXED @RNB TO SET IOSIZE *)
(* 01/14/82 FIXED @CLOSE TO FLUSH BUFFER IF BUFIDX = SIZEOF(SECTOR) *)
(* 03/07/82 ADDED maxfcbs and list device i/o, also blockw sets foption *)
(* 03/11/82 Added code to handle multi extent files in block i/o *)
(* 03/12/82 Split block i/o out into a separate file "blkio.src" *)
(* 03/17/82 Added RDR: and PUN: devices *)
(*$S+*)
MODULE IOMODULE;
(* INTERFACE TO CP/M-86 FOR PASCAL/MT+86 *)
(*$I FIBDEF.LIB*)
const
maxfcbs = 9;
TYPE
FPTR = ^FIB;
FCBLK = PACKED ARRAY [0..36] OF CHAR;
SECTOR = PACKED ARRAY [0..127] OF CHAR;
DUMMY = PACKED ARRAY[0..0] OF CHAR;
PTR = ^DUMMY;
FCBREC = RECORD
ACTIVE : BOOLEAN;
FCB : FCBLK;
BUFIDX : INTEGER;
BUFFER : SECTOR;
ENDFILE: BOOLEAN
END;
PTRIX = RECORD
CASE BOOLEAN OF
TRUE : (LO_VAL:INTEGER;
HI_VAL:INTEGER);
FALSE: (P:PTR)
END;
VAR
@LFB : FPTR;
RESULTI : INTEGER;
@FCBS : ARRAY [0..maxfcbs] OF FCBREC;
(* ALLOWS 10 SIMULTANEOUSLY OPEN FILES *)
(* THE CONSOLE TAKES TWO FILE SLOTS *)
(* FOR CON: AS INPUT AND CON: AS OUTPUT *)
EXTERNAL FUNCTION @BDOS86(FUNC:INTEGER; PARM:PTR):BYTE;
EXTERNAL FUNCTION @BDOS86A(FUNC:INTEGER; FIRST,SECOND:INTEGER):BYTE;
(* @BDOS86A WILL RESOLVE TO @BDOS86 AT LINK TIME BUT USE DIFFERENT PARMS *)
EXTERNAL PROCEDURE @BDOSX(FUNC:INTEGER; CH:CHAR);
EXTERNAL PROCEDURE @CHN(P:PTR);
EXTERNAL PROCEDURE @HLT;
(*$E-*)
FUNCTION GET_AN_FCB:INTEGER;
VAR
I : INTEGER;
BEGIN
I := 0;
WHILE I <= maxfcbs+1 DO
BEGIN
IF NOT(@FCBS[I].ACTIVE) THEN (* WE FOUND ONE! *)
BEGIN
GET_AN_FCB := I;
@FCBS[I].ACTIVE := TRUE;
EXIT
END
ELSE
I := I + 1
END;
I := -1;
WRITELN('FCB Table Exhausted!');
@HLT;
END;
PROCEDURE FREE_AN_FCB(FCBNUM:INTEGER);
BEGIN
@FCBS[FCBNUM].ACTIVE := FALSE
END;
PROCEDURE PUTSECTOR(I:INTEGER);
BEGIN
RESULTI := @BDOS86(26,ADDR(@FCBS[I].BUFFER));
RESULTI := @BDOS86(21,ADDR(@FCBS[I].FCB));
END;
FUNCTION GETSECTOR(I:INTEGER):BOOLEAN;
BEGIN
GETSECTOR := TRUE; (* FALSE MEANS EOF *)
RESULTI := @BDOS86(26,ADDR(@FCBS[I].BUFFER));
RESULTI := @BDOS86(20,ADDR(@FCBS[I].FCB));
IF RESULTI <> 0 THEN
GETSECTOR := FALSE;
END;
FUNCTION @SPN(VAR F:FIB):BOOLEAN;
BEGIN
@SPN := FALSE;
IF F.FNAME = 'CON:' THEN
BEGIN
F.OPTION := FCONIO;
@SPN := TRUE
END
ELSE
IF F.FNAME = 'LST:' THEN
BEGIN
F.OPTION := FLSTOUT;
@SPN := TRUE
END
ELSE
IF (F.FNAME = 'KBD:') OR (F.FNAME = 'TRM:') THEN
BEGIN
F.OPTION := FTRMIO;
@SPN := TRUE
END
ELSE
IF (F.FNAME = 'RDR:') OR (F.FNAME = 'PUN:') THEN
BEGIN
F.OPTION := FAUXIO;
@SPN := TRUE
END
END;
FUNCTION @NOK(VAR S:STRING):BOOLEAN;
VAR
I : INTEGER;
ST: SET OF CHAR;
BEGIN
@NOK := FALSE;
ST := [' '..CHR($7E)];
IF (LENGTH(S) > 14) OR (LENGTH(S) < 1) THEN
EXIT;
FOR I := 1 TO LENGTH(S) DO
IF NOT(S[I] IN ST) THEN
EXIT;
@NOK := TRUE
END;
FUNCTION UPPERCASE(CH:CHAR):CHAR;
BEGIN
IF (CH >= 'a') AND (CH <= 'z') THEN
CH := CHR(CH & $DF);
UPPERCASE := CH
END;
(*$E+*)
PROCEDURE @PARSE(VAR F:FCBLK;VAR S:STRING);
VAR
DISK : CHAR;
NAME : PACKED ARRAY [1..8] OF CHAR;
EXT : PACKED ARRAY [1..3] OF CHAR;
I,J,MAX: INTEGER;
BEGIN
(* PARSE CP/M FILE NAME *)
WHILE (LENGTH(S) <> 0) AND (S[1] = ' ') DO
DELETE(S,1,1); (* REMOVE LEADING BLANKS *)
IF LENGTH(S) <> 0 THEN
BEGIN
DISK := '@'; (* DEFAULT *)
NAME := ' ';
EXT := ' ';
IF S[2] = ':' THEN
BEGIN
I := 3;
DISK := UPPERCASE(S[1])
END
ELSE
I := 1;
MAX := I + 8;
J := 1;
WHILE (NOT(S[I] IN ['.',':'])) AND (I < MAX)
AND (I <= LENGTH(S)) DO
BEGIN
NAME[J] := UPPERCASE(S[I]);
J := J + 1;
I := I + 1
END; (* WHILE *)
IF (S[I] = '.') AND (I <= LENGTH(S)) THEN
BEGIN
I := I + 1;
J := 1;
WHILE (J < 4) AND (I <= LENGTH(S)) DO
BEGIN
EXT[J] := UPPERCASE(S[I]);
J := J + 1;
I := I + 1
END (* WHILE *)
END; (* IF *)
FILLCHAR(F,SIZEOF(FCBLK)-18,CHR(0));
F[0] := CHR(ORD(DISK) - ORD('@'));
MOVE(NAME,F[1],8);
MOVE(EXT,F[9],3);
END (* IF *)
END;
PROCEDURE @INI2; (* INIT @FCBS *)
BEGIN
FILLCHAR(@FCBS,SIZEOF(@FCBS),CHR(0))
END;
FUNCTION @OPEN(VAR F:FIB; MODE:INTEGER):INTEGER;
(* NOTE: THIS CODE IS DEPENDENT UPON THE FACT THAT THE FIRST FIELD *)
(* OF THE FIB DEFINITION IS FNAME! *)
VAR
I : INTEGER;
BEGIN
I := GET_AN_FCB;
@OPEN := I;
IF I <> -1 THEN
BEGIN
FILLCHAR(@FCBS[I].FCB,36,CHR(0));
@PARSE(@FCBS[I].FCB,F.FNAME);
IF NOT @NOK(F.FNAME) THEN
BEGIN
@OPEN := -1;
RESULTI := 255;
FREE_AN_FCB(I); (* DONT NEED FCB IF BAD NAME *)
EXIT
END;
IF @SPN(F) THEN
BEGIN
RESULTI := 0;
@FCBS[I].FCB[0] := CHR($FF); {MARK SPECIAL FILE}
{FREE_AN_FCB(I); (* DONT NEED AN FCB ON SPECIAL FILES *)}
{since on 1/16/82 we implemented i/o redirection }
{special files now need an fcb allocated to them! }
EXIT
END;
RESULTI := @BDOS86(15,ADDR(@FCBS[I].FCB));
IF RESULTI = 255 THEN
BEGIN
@OPEN := -1;
FREE_AN_FCB(I); (* DONT NEED FCB IF NOT FOUND *)
END
ELSE
BEGIN
@FCBS[I].BUFIDX := SIZEOF(SECTOR);
@FCBS[I].ENDFILE:= FALSE
END
END
ELSE
RESULTI := 255
END; (* @OPEN *)
FUNCTION @CREAT(VAR F:FIB; MODE:INTEGER):INTEGER;
VAR
I : INTEGER;
BEGIN
I := GET_AN_FCB;
@CREAT := I;
IF I <> -1 THEN
BEGIN
FILLCHAR(@FCBS[I].FCB,36,CHR(0));
@PARSE(@FCBS[I].FCB,F.FNAME);
IF NOT @NOK(F.FNAME) THEN
BEGIN
@CREAT := -1;
RESULTI := 255;
FREE_AN_FCB(I); (* DONT NEED FCB IF BAD NAME *)
EXIT
END;
IF @SPN(F) THEN
BEGIN
RESULTI := 0;
@FCBS[I].FCB[0] := CHR($FF); {MARK SPECIAL FILE}
{FREE_AN_FCB(I); (* DONT NEED AN FCB ON SPECIAL FILES *)}
{since on 1/16/82 we implemented i/o redirection }
{special files now need an fcb allocated to them! }
EXIT
END;
RESULTI := @BDOS86(19,ADDR(@FCBS[I].FCB)); (* DELETE ANY OLD ONES *)
RESULTI := @BDOS86(22,ADDR(@FCBS[I].FCB)); (* AND CREATE A NEW ONE *)
IF RESULTI = 255 THEN
BEGIN
@CREAT := -1;
FREE_AN_FCB(I); (* DONT NEED FCB IF ERROR *)
END;
@FCBS[I].BUFIDX := 0;
END
ELSE
RESULTI := 255
END; (* @CREAT *)
FUNCTION @UNLINK(VAR F:FIB):INTEGER;
BEGIN
IF F.SYSID = 0 THEN (* WE MUST ALLOCATE AN FCB FIRST *)
F.SYSID := @OPEN(F,2);
IF F.SYSID <> -1 THEN (* VALID FILE *)
BEGIN
IF F.OPTION <= FRANDOM THEN (* IT IS A DISK FILE *)
RESULTI := @BDOS86(19,ADDR(@FCBS[F.SYSID].FCB));
@UNLINK := 0;
FREE_AN_FCB(F.SYSID)
END;
END;
PROCEDURE @CLOSE(I:INTEGER; an_infile:boolean);
VAR
J : INTEGER;
BEGIN
if (not an_infile) and (@FCBS[I].FCB[0] <> CHR($FF)) then
begin (* check to see if stuff to flush *)
IF (@FCBS[I].BUFIDX <> 0) THEN
BEGIN
IF (@FCBS[I].BUFIDX <> SIZEOF(SECTOR)) THEN
(* STILL SPACE LEFT TO FILL WITH CTRL/Z'S *)
WITH @FCBS[I] DO
FILLCHAR(BUFFER[BUFIDX],SIZEOF(SECTOR)-BUFIDX,CHR($1A));
PUTSECTOR(I) (* ALWAYS OUTPUT BUFFER IF IDX <> 0 *)
END;
RESULTI := @BDOS86(16,ADDR(@FCBS[I].FCB))
end;
FREE_AN_FCB(I); (* WE ALWAYS DO THIS! *)
END;
PROCEDURE @SFB(P:FPTR);
BEGIN
@LFB := P
END;
(*$E-*)
FUNCTION GETBYTE(I:INTEGER; VAR ENDFIL : BOOLEAN):BYTE;
BEGIN
WITH @FCBS[I] DO
BEGIN
IF BUFIDX >= SIZEOF(SECTOR) THEN (* GOT TO GO READ SOME DATA *)
BEGIN
ENDFIL := NOT GETSECTOR(I);
BUFIDX := 0
END;
GETBYTE := BUFFER[BUFIDX];
BUFIDX := BUFIDX + 1
END
END;
PROCEDURE PUTBYTE(B:BYTE; I:INTEGER);
BEGIN
WITH @FCBS[I] DO
BEGIN
IF BUFIDX >= SIZEOF(SECTOR) THEN
BEGIN
PUTSECTOR(I);
BUFIDX := 0
END;
BUFFER[BUFIDX] := B;
BUFIDX := BUFIDX + 1
END
END;
(*$E+*)
PROCEDURE @RNB;
VAR
I : INTEGER;
J : INTEGER;
CH: CHAR;
ENDFILE:BOOLEAN;
BEGIN
RESULTI := 0;
IF @LFB^.OPTION = FCONIO THEN (* READ CONSOLE NOT A DISK FILE *)
BEGIN
CH := @BDOS86(1,ADDR(I)); (* SECOND PARM IS A DUMMY *)
IF CH = CHR(8) THEN
BEGIN
@BDOSX(2,' ');
@BDOSX(2,CHR(8))
END
ELSE
IF CH = CHR($0D) THEN
@BDOSX(2,CHR($0A));
@LFB^.FBUFFER[0] := CH;
@LFB^.FEOF := (CH = CHR($1A));
EXIT
END;
IF @LFB^.OPTION = FTRMIO THEN
BEGIN
CH := @BDOS86A(6,$FFFF,$FFFF);
@LFB^.FBUFFER[0] := CH;
EXIT
END;
IF @LFB^.OPTION = FAUXIO THEN
BEGIN
CH := @BDOS86(3,ADDR(I));
@LFB^.FBUFFER[0] := CH;
EXIT
END;
(* ELSE NON-CONSOLE, READ USING GETBYTE *)
I := @LFB^.SYSID;
ENDFILE := @LFB^.FEOF;
J := 1;
WHILE (J <= @LFB^.BUFLEN) AND (NOT ENDFILE) DO
BEGIN
WITH @LFB^ DO
FBUFFER[J-1] := GETBYTE(I,ENDFILE);
J := J + 1
END;
@LFB^.FEOF := ENDFILE;
@LFB^.IOSIZE := J-1; (* THIS IS SO GNB CAN TELL THE DIFFERENCE *)
(* BETWEEN A PARTIALLY FULL BUFFER AND *)
(* TRUE EOF *)
END;
PROCEDURE @WNB;
VAR
I : INTEGER;
J : INTEGER;
CH: CHAR;
BEGIN
RESULTI := 0;
IF @LFB^.OPTION = FCONIO THEN (* WRITE TO THE CONSOLE *)
BEGIN
@BDOSX(2,@LFB^.FBUFFER[0]);
EXIT
END;
IF @LFB^.OPTION = FTRMIO THEN (* USE FUNCTION 6 *)
BEGIN
@BDOSX(6,@LFB^.FBUFFER[0]);
EXIT
END;
if @lfb^.option = flstout then (* use function 5 *)
begin
@bdosx(5,@lfb^.fbuffer[0]);
exit
end;
if @lfb^.option = fauxio then (* use function 4 *)
begin
@bdosx(4,@lfb^.fbuffer[0]);
exit
end;
(* ELSE NON-CONSOLE, WRITE USING PUTBYTE *)
I := @LFB^.SYSID;
FOR J := 1 TO @LFB^.BUFLEN DO
WITH @LFB^ DO
PUTBYTE(FBUFFER[J-1],I);
@LFB^.BUFIDX := 0; (* SO CLOSE ON A WNB FILE WORKS PROPERLY *)
END;
PROCEDURE CHAIN(VAR F:FIB; SZ:INTEGER);
BEGIN
@CHN(ADDR(@FCBS[F.SYSID].FCB))
END;
MODEND.