Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM II/MPM II SOURCE/CONTROL/SEQIO.LIB
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

439 lines
10 KiB
Plaintext
Raw 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.

; SEQUENTIAL FILE I/O LIBRARY
;
FILERR SET 0000H ;REBOOT AFTER ERROR
@BDOS EQU 0005H ;BDOS ENTRY POINT
@TFCB EQU 005CH ;DEFAULT FILE CONTROL BLOCK
@TBUF EQU 0080H ;DEFAULT BUFFER ADDRESS
;
; BDOS FUNCTIONS
@MSG EQU 9 ;SEND MESSAGE
@OPN EQU 15 ;FILE OPEN
@CLS EQU 16 ;FILE CLOSE
@DIR EQU 17 ;DIRECTORY SEARCH
@DEL EQU 19 ;FILE DELETE
@FRD EQU 20 ;FILE READ OPERATION
@FWR EQU 21 ;FILE WRITE OPERATION
@MAK EQU 22 ;FILE MAKE
@REN EQU 23 ;FILE RENAME
@DMA EQU 26 ;SET DMA ADDRESS
;
@SECT EQU 128 ;SECTOR SIZE
EOF EQU 1AH ;END OF FILE
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
TAB EQU 09H ;HORIZONTAL TAB
;
@KEY EQU 1 ;KEYBOARD
@CON EQU 2 ;CONSOLE DISPLAY
@RDR EQU 3 ;READER
@PUN EQU 4 ;PUNCH
@LST EQU 5 ;LIST DEVICE
;
; KEYWORDS FOR "FILE" MACRO
INFILE EQU 1 ;INPUT FILE
OUTFILE EQU 2 ;OUTPUTFILE
SETFILE EQU 3 ;SETUP NAME ONLY
;
; THE FOLLOWING MACROS DEFINE SIMPLE SEQUENTIAL
; FILE OPERATIONS:
;
FILLNAM MACRO FC,C
;; FILL THE FILE NAME/TYPE GIVEN BY FC FOR C CHARACTERS
@CNT SET C ;;MAX LENGTH
IRPC ?FC,FC ;;FILL EACH CHARACTER
;; MAY BE END OF COUNT OR NUL NAME
IF @CNT=0 OR NUL ?FC
EXITM
ENDIF
DB '&?FC' ;;FILL ONE MORE
@CNT SET @CNT-1 ;;DECREMENT MAX LENGTH
ENDM ;;OF IRPC ?FC
;;
;; PAD REMAINDER
REPT @CNT ;;@CNT IS REMAINDER
DB ' ' ;;PAD ONE MORE BLANK
ENDM ;;OF REPT
ENDM
;
FILLDEF MACRO FCB,?FL,?LN
;; FILL THE FILE NAME FROM THE DEFAULT FCB
;; FOR LENGTH ?LN (9 OR 12)
LOCAL PSUB
JMP PSUB ;;JUMP PAST THE SUBROUTINE
@DEF: ;;THIS SUBROUTINE FILLS FROM THE TFCB (+16)
MOV A,M ;;GET NEXT CHARACTER TO A
STAX D ;;STORE TO FCB AREA
INX H
INX D
DCR C ;;COUNT LENGTH DOWN TO 0
JNZ @DEF
RET
;; END OF FILL SUBROUTINE
PSUB:
FILLDEF MACRO ?FCB,?F,?L
LXI H,@TFCB+?F ;;EITHER @TFCB OR @TFCB+16
LXI D,?FCB
MVI C,?L ;;LENGTH = 9,12
CALL @DEF
ENDM
FILLDEF FCB,?FL,?LN
ENDM
;
FILLNXT MACRO
;; INITIALIZE BUFFER AND DEVICE NUMBERS
@NXTB SET 0 ;;NEXT BUFFER LOCATION
@NXTD SET @LST+1 ;;NEXT DEVICE NUMBER
FILLNXT MACRO
ENDM
ENDM
;
FILLFCB MACRO FID,DN,FN,FT,BS,BA
;; FILL THE FILE CONTROL BLOCK WITH DISK NAME
;; FID IS AN INTERNAL NAME FOR THE FILE,
;; DN IS THE DRIVE NAME (A,B..), OR BLANK
;; FN IS THE FILE NAME, OR BLANK
;; FT IS THE FILE TYPE
;; BS IS THE BUFFER SIZE
;; BA IS THE BUFFER ADDRESS
LOCAL PFCB
;;
;; SET UP THE FILE CONTROL BLOCK FOR THE FILE
;; LOOK FOR FILE NAME = 1 OR 2
@C SET 1 ;;ASSUME TRUE TO BEGIN WITH
IRPC ?C,FN ;;LOOK THROUGH CHARACTERS OF NAME
IF NOT ('&?C' = '1' OR '&?C' = '2')
@C SET 0 ;;CLEAR IF NOT 1 OR 2
ENDM
;; @C IS TRUE IF FN = 1 OR 2 AT THIS POINT
IF @C ;;THEN FN = 1 OR 2
;; FILL FROM DEFAULT AREA
IF NUL FT ;;TYPE SPECIFIED?
@C SET 12 ;;BOTH NAME AND TYPE
ELSE
@C SET 9 ;;NAME ONLY
ENDIF
FILLDEF FCB&FID,(FN-1)*16,@C ;;TO SELECT THE FCB
JMP PFCB ;;PAST FCB DEFINITION
DS @C ;;SPACE FOR DRIVE/FILENAME/TYPE
FILLNAM FT,12-@C ;;SERIES OF DB'S
ELSE
JMP PFCB ;;PAST INITIALIZED FCB
IF NUL DN
DB 0 ;;USE DEFAULT DRIVE IF NAME IS ZERO
ELSE
DB '&DN'-'A'+1 ;;USE SPECIFIED DRIVE
ENDIF
FILLNAM FN,8 ;;FILL FILE NAME
;; NOW GENERATE THE FILE TYPE WITH PADDED BLANKS
FILLNAM FT,3 ;;AND THREE CHARACTER TYPE
ENDIF
FCB&FID EQU $-12 ;;BEGINNING OF THE FCB
DB 0 ;;EXTENT FIELD 00 FOR SETFILE
;; NOW DEFINE THE 3 BYTE FIELD, AND DISK MAP
DS 20 ;;X,X,RC,DM0...DM15,CR FIELDS
;;
IF FID&TYP<=2 ;;IN/OUTFILE
;; GENERATE CONSTANTS FOR INFILE/OUTFILE
FILLNXT ;;@NXTB=0 ON FIRST CALL
IF BS+0<@SECT
;; BS NOT SUPPLIED, OR TOO SMALL
@BS SET @SECT ;;DEFAULT TO ONE SECTOR
ELSE
;; COMPUTE EVEN BUFFER ADDRESS
@BS SET (BS/@SECT)*@SECT
ENDIF
;;
;; NOW DEFINE BUFFER BASE ADDRESS
IF NUL BA
;; USE NEXT ADDRESS AFTER @NXTB
FID&BUF SET BUFFERS+@NXTB
;; COUNT PAST THIS BUFFER
@NXTB SET @NXTB+@BS
ELSE
FID&BUF SET BA
ENDIF
;; FID&BUF IS BUFFER ADDRESS
FID&ADR:
DW FID&BUF
;;
FID&SIZ EQU @BS ;;LITERAL SIZE
FID&LEN:
DW @BS ;;BUFFER SIZE
FID&PTR:
DS 2 ;;SET IN INFILE/OUTFILE
;; SET DEVICE NUMBER
@&FID SET @NXTD ;;NEXT DEVICE
@NXTD SET @NXTD+1
ENDIF ;;OF FID&TYP<=2 TEST
PFCB: ENDM
;
FILE MACRO MD,FID,DN,FN,FT,BS,BA
;; CREATE FILE USING MODE MD:
;; INFILE = 1 INPUT FILE
;; OUTFILE = 2 OUTPUT FILE
;; SETFILE = 3 SETUP FCB
;; (SEE FILLFCB FOR REMAINING PARAMETERS)
LOCAL PSUB,MSG,PMSG
LOCAL PND,EOD,EOB,PNC
;; CONSTRUCT THE FILE CONTROL BLOCK
;;
FID&TYP EQU MD ;;SET MODE FOR LATER REF'S
FILLFCB FID,DN,FN,FT,BS,BA
IF MD=3 ;;SETUP FCB ONLY, SO EXIT
EXITM
ENDIF
;; FILE CONTROL BLOCK AND RELATED PARAMETERS
;; ARE CREATED INLINE, NOW CREATE IO FUNCTION
JMP PSUB ;;PAST INLINE SUBROUTINE
IF MD=1 ;;INPUT FILE
GET&FID:
ELSE
PUT&FID:
PUSH PSW ;;SAVE OUTPUT CHARACTER
ENDIF
LHLD FID&LEN ;;LOAD CURRENT BUFFER LENGTH
XCHG ;;DE IS LENGTH
LHLD FID&PTR ;;LOAD NEXT TO GET/PUT TO HL
MOV A,L ;;COMPUTE CUR-LEN
SUB E
MOV A,H
SBB D ;;CARRY IF NEXT<LENGTH
JC PNC ;;CARRY IF LEN GTR CURRENT
;; END OF BUFFER, FILL/EMPTY BUFFERS
LXI H,0
SHLD FID&PTR ;;CLEAR NEXT TO GET/PUT
PND:
;; PROCESS NEXT DISK SECTOR:
XCHG ;;FID&PTR TO DE
LHLD FID&LEN ;;DO NOT EXCEED LENGTH
;; DE IS NEXT TO FILL/EMPTY, HL IS MAX LEN
MOV A,E ;;COMPUTE NEXT-LEN
SUB L ;;TO GET CARRY IF MORE
MOV A,D
SBB H ;;TO FILL
JNC EOB
;; CARRY GEN'ED, HENCE MORE TO FILL/EMPTY
LHLD FID&ADR ;;BASE OF BUFFERS
DAD D ;;HL IS NEXT BUFFER ADDR
XCHG
MVI C,@DMA ;;SET DMA ADDRESS
CALL @BDOS ;;DMA ADDRESS IS SET
LXI D,FCB&FID ;;FCB ADDRESS TO DE
IF MD=1 ;;READ BUFFER FUNCTION
MVI C,@FRD ;;FILE READ FUNCTION
ELSE
MVI C,@FWR ;;FILE WRITE FUNCTION
ENDIF
CALL @BDOS ;;RD/WR TO/FROM DMA ADDRESS
ORA A ;;CHECK RETURN CODE
JNZ EOD ;;END OF FILE/DISK?
;; NOT END OF FILE/DISK, INCREMENT LENGTH
LXI D,@SECT ;;SECTOR SIZE
LHLD FID&PTR ;;NEXT TO FILL
DAD D
SHLD FID&PTR ;;BACK TO MEMORY
JMP PND ;;PROCESS ANOTHER SECTOR
;;
EOD:
;; END OF FILE/DISK ENCOUNTERED
IF MD=1 ;;INPUT FILE
LHLD FID&PTR ;;LENGTH OF BUFFER
SHLD FID&LEN ;;RESET LENGTH
ELSE
;; FATAL ERROR, END OF DISK
LOCAL EMSG
MVI C,@MSG ;;WRITE THE ERROR
LXI D,EMSG
CALL @BDOS ;;ERROR TO CONSOLE
POP PSW ;;REMOVE STACKED CHARACTER
JMP FILERR ;;USUALLY REBOOTS
EMSG: DB CR,LF
DB 'DISK FULL: &FID'
DB '$'
ENDIF
;;
EOB:
;; END OF BUFFER, RESET DMA AND POINTER
LXI D,@TBUF
MVI C,@DMA
CALL @BDOS
LXI H,0
SHLD FID&PTR ;;NEXT TO GET
;;
PNC:
;; PROCESS THE NEXT CHARACTER
XCHG ;;INDEX TO GET/PUT IN DE
LHLD FID&ADR ;;BASE OF BUFFER
DAD D ;;ADDRESS OF CHAR IN HL
XCHG ;;ADDRESS OF CHAR IN DE
IF MD=1 ;;INPUT PROCESSING DIFFERS
LHLD FID&LEN ;;FOR EOF CHECK
MOV A,L ;;0000?
ORA H
MVI A,EOF ;;END OF FILE?
RZ ;;ZERO FLAG IF SO
LDAX D ;;NEXT CHAR IN ACCUM
ELSE
;; STORE NEXT CHARACTER FROM ACCUMULATOR
POP PSW ;;RECALL SAVED CHAR
STAX D ;;CHARACTER IN BUFFER
ENDIF
LHLD FID&PTR ;;INDEX TO GET/PUT
INX H
SHLD FID&PTR ;;POINTER UPDATED
;; RETURN WITH NON ZERO FLAG IF GET
RET
;;
PSUB: ;;PAST INLINE SUBROUTINE
XRA A ;;ZERO TO ACC
STA FCB&FID+12 ;;CLEAR EXTENT
STA FCB&FID+32 ;;CLEAR CUR REC
LXI H,FID&SIZ ;;BUFFER SIZE
SHLD FID&LEN ;;SET BUFF LEN
IF MD=1 ;;INPUT FILE
SHLD FID&PTR ;;CAUSE IMMEDIATE READ
MVI C,@OPN ;;OPEN FILE FUNCTION
ELSE ;;OUTPUT FILE
LXI H,0 ;;SET NEXT TO FILL
SHLD FID&PTR ;;POINTER INITIALIZED
MVI C,@DEL
LXI D,FCB&FID ;;DELETE FILE
CALL @BDOS ;;TO CLEAR EXISTING FILE
MVI C,@MAK ;;CREATE A NEW FILE
ENDIF
;; NOW OPEN (IF INPUT), OR MAKE (IF OUTPUT)
LXI D,FCB&FID
CALL @BDOS ;;OPEN/MAKE OK?
INR A ;;255 BECOMES 00
JNZ PMSG
MVI C,@MSG ;;PRINT MESSAGE FUNCTION
LXI D,MSG ;;ERROR MESSAGE
CALL @BDOS ;;PRINTED AT CONSOLE
JMP FILERR ;;TO RESTART
MSG: DB CR,LF
IF MD=1 ;;INPUT MESSAGE
DB 'NO &FID FILE'
ELSE
DB 'NO DIR SPACE: &FID'
ENDIF
DB '$'
PMSG:
ENDM
;
PUT MACRO DEV
;; WRITE CHARACTER FROM ACCUM TO DEVICE
IF @&DEV <= @LST
;; SIMPLE OUTPUT
PUSH PSW ;;SAVE CHARACTER
MVI C,@&DEV ;;WRITE CHAR FUNCTION
MOV E,A ;;READY FOR OUTPUT
CALL @BDOS ;;WRITE CHARACTER
POP PSW ;;RESTORE FOR TESTING
ELSE
CALL PUT&DEV
ENDM
;
FINIS MACRO FID
;; CLOSE THE FILE(S) GIVEN BY FID
IRP ?F,<FID>
;; SKIP ALL BUT OUTPUT FILES
IF ?F&TYP=2
LOCAL EOB?,PEOF,MSG,PMSG
;; WRITE ALL PARTIALLY FILLED BUFFERS
EOB?: ;;ARE WE AT THE END OF A BUFFER?
LHLD ?F&PTR ;;NEXT TO FILL
MOV A,L ;;ON BUFFER BOUNDARY?
ANI (@SECT-1) AND 0FFH
JNZ PEOF ;;PUT EOF IF NOT 00
IF @SECT>255
;; CHECK HIGH ORDER BYTE ALSO
MOV A,H
ANI (@SECT-1) SHR 8
JNZ PEOF ;;PUT EOF IF NOT 00
ENDIF
;; ARRIVE HERE IF END OF BUFFER, SET LENGTH
;; AND WRITE ONE MORE BYTE TO CLEAR BUFFS
SHLD ?F&LEN ;;SET TO SHORTER LENGTH
PEOF: MVI A,EOF ;;WRITE ANOTHER EOF
PUSH PSW ;;SAVE ZERO FLAG
CALL PUT&?F
POP PSW ;;RECALL ZERO FLAG
JNZ EOB? ;;NON ZERO IF MORE
;; BUFFERS HAVE BEEN WRITTEN, CLOSE FILE
MVI C,@CLS
LXI D,FCB&?F ;;READY FOR CALL
CALL @BDOS
INR A ;;255 IF ERR BECOMES 00
JNZ PMSG
;; FILE CANNOT BE CLOSED
MVI C,@MSG
LXI D,MSG
CALL @BDOS
JMP PMSG ;;ERROR MESSAGE PRINTED
MSG: DB CR,LF
DB 'CANNOT CLOSE &?F'
DB '$'
PMSG:
ENDIF
ENDM ;;OF THE IRP
ENDM
;
ERASE MACRO FID
;; DELETE THE FILE(S) GIVEN BY FID
IRP ?F,<FID>
MVI C,@DEL
LXI D,FCB&?F
CALL @BDOS
ENDM ;;OF THE IRP
ENDM
;
DIRECT MACRO FID
;; PERFORM DIRECTORY SEARCH FOR FILE
;; SETS ZERO FLAG IF NOT PRESENT
LXI D,FCB&FID
MVI C,@DIR
CALL @BDOS
INR A ;00 IF NOT PRESENT
ENDM
;
RENAME MACRO NEW,OLD
;; RENAME FILE GIVEN BY "OLD" TO "NEW"
LOCAL PSUB,REN0
;; INCLUDE THE RENAME SUBROUTINE ONCE
JMP PSUB
@RENS: ;;RENAME SUBROUTINE, HL IS ADDRESS OF
;;OLD FCB, DE IS ADDRESS OF NEW FCB
PUSH H ;;SAVE FOR RENAME
LXI B,16 ;;B=00,C=16
DAD B ;;HL = OLD FCB+16
REN0: LDAX D ;;NEW FCB NAME
MOV M,A ;;TO OLD FCB+16
INX D ;;NEXT NEW CHAR
INX H ;;NEXT FCB CHAR
DCR C ;;COUNT DOWN FROM 16
JNZ REN0
;; OLD NAME IN FIRST HALF, NEW IN SECOND HALF
POP D ;;RECALL BASE OF OLD NAME
MVI C,@REN ;;RENAME FUNCTION
CALL @BDOS
RET ;;RENAME COMPLETE
PSUB:
RENAME MACRO N,O ;;REDEFINE RENAME
LXI H,FCB&O ;;OLD FCB ADDRESS
LXI D,FCB&N ;;NEW FCB ADDRESS
CALL @RENS ;;RENAME SUBROUTINE
ENDM
RENAME NEW,OLD
ENDM
;
GET MACRO DEV
;; READ CHARACTER FROM DEVICE
IF @&DEV <= @LST
;; SIMPLE INPUT
MVI C,@&DEV
CALL @BDOS
ELSE
CALL GET&DEV
ENDM
;