dos_compilers/Digital Research MT+86 Pascal v311/IOMOD.SRC

487 lines
11 KiB
Plaintext
Raw Normal View History

2024-06-30 20:44:12 +02:00
(* 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.