; ; SYSLIB Module Name: SFILEI ; Author: Richard Conn ; SYSLIB Version Number: 2.0 ; Module Version Number: 1.0 ; Module Entry Points: ; ADRCPY F$GET F$PUT FI$CLOSE ; FI$OPEN FO$CLOSE FO$OPEN ; Module External References: ; F$MOPEN F$OPEN INITFCB ; ; ; SFILEIO.MAC -- BYTE-ORIENTED FILE I/O FOR SYSLIB ; INCLUDED ROUTINES ARE -- FILE INPUT OPEN, FILE OUTPUT OPEN, ; FILE INPUT CLOSE, FILE OUTPUT CLOSE, ; GET, PUT ; Error Diagnostics are returned to the caller via the Zero Flag ; (Zero Flag Set - Z - ALWAYS Means No Error Occurred) ; and the A Register ; If the Zero Flag is Set (Z), then the A Register either contains ; a 0 or the required returned value if A is significant for ; the particular routine. ; If the Zero Flag is Clear (NZ), then the A Register contains the ; error code. No other returned register value in HL, DE, or BC ; should be considered to be valid. The Returned Error Codes ; in A are: ; Code Meaning ; 1 GET or PUT attempted on unopened file ; 2 Disk Full (Ran out of space) ; 3 Input File Not Found ; 4 Attempt to Read Past the EOF ; 5 Directory Full ; 6 Error in Closing a File ; 7 Attempt to Open a File which is already open ; ; ; EXTERNAL LIBRARY FILE DEFINITIONS ; EXT F$OPEN ; OPEN FILE EXT F$MOPEN ; OPEN/CREATE FILE EXT INITFCB ; INIT FCB ; ; CP/M EQUATES AND ASCII CONSTANTS ; CPM EQU 0 ; WARM BOOT FOR CP/M TBUFF EQU 80H ; TEMPORARY FILE I/O BUFFER CR EQU 0DH ; LF EQU 0DH ; BDOS EQU 5 ; BDOS ENTRY POINT B$CL EQU 16 ; CLOSE FILE B$RD EQU 20 ; READ NEXT RECORD B$WR EQU 21 ; WRITE NEXT RECORD B$DMA EQU 26 ; SET DMA ADDRESS ; ; SUPPORTING MACROS ; PUTRG MACRO ; SAVE BC, DE, HL PUSH B PUSH D PUSH H ENDM GETRG MACRO ; RESTORE HL, DE, BC POP H POP D POP B ENDM ;********************************************************************** ; SUPPORTING ROUTINES ; ; ; ADDRESS TABLE COPY ROUTINE ; ADRCPY:: LXI H,I$FLG ; PT TO FIRST ENTRY MVI B,20 ; 20 BYTES (10 ADDRESSES) TO COPY JMP SFCBL ; DO COPY ; ; GET ONE-LEVEL INDIRECT ADDRESS ; HL = ADDRESS CONTAINED AT MEMORY LOCATION PTED TO BY HL ; GETADR: PUSH D ; SAVE DE MOV E,M ; GET LOW INX H MOV D,M ; GET HIGH MOV H,D ; SET HL MOV L,E POP D ; GET DE RET ; ; SAVEFCB UTILITY -- COPY FCB FROM DE TO HL ; SAVEFCB: MVI B,36 ; 36 BYTES SFCBL: LDAX D ; GET BYTE MOV M,A ; PUT BYTE INX H ; PT TO NEXT INX D DCR B ; COUNT DOWN JNZ SFCBL RET ; ; F$ABORT -- FILE ERROR -- ABORT ; F$ABORT: GETRG ; RESTORE REGISTERS ORA A ; SET FLAGS RET ; ; F$CLOS -- CLOSE FILE ; F$CLOS: MVI C,B$CL ; CLOSE FILE CALL BDOS RET ; ; F$READ -- READ ONE 128-BYTE BLOCK VIA CP/M ; F$READ: MVI C,B$RD ; READ BLOCK CALL BDOS RET ; ; F$WRIT -- WRITE ONE 128-BYTE BLOCK VIA CP/M ; F$WRIT: MVI C,B$WR ; WRITE BLOCK CALL BDOS RET ; ; READ$BLOCK -- READ BLOCK FROM INPUT FILE INTO INPUT BUFFER ; ON RETURN, Z=OK AND NZ=NOT OK (PAST EOF) ; READ$BLOCK: LHLD I$FCB ; GET FCB ADDRESS XCHG ; ... IN DE CALL F$READ ; READ BLOCK PUSH PSW ; SAVE STATUS LHLD I$BUF ; PT TO INPUT BUFFER LXI D,TBUFF ; PT TO TEMP BUFFER MVI B,128 ; 128 BYTES CALL SFCBL ; COPY FROM DE TO HL FOR B BYTES POP PSW ; GET STATUS ORA A ; SET ZERO FLAG IF OK RET ; ; WRIT$BLOCK -- WRITE BLOCK TO OUTPUT FILE ; WRIT$BLOCK: LHLD O$BUF ; ADDRESS OF OUTPUT BUFFER XCHG ; ... IN DE LXI H,TBUFF ; PT TO TEMP BUFFER MVI B,128 ; 128 BYTES CALL SFCBL ; COPY FROM DE TO HL FOR B BYTES LHLD O$FCB ; PT TO DEFAULT FCB XCHG ; ... IN DE CALL F$WRIT ; WRITE BLOCK ORA A ; OK? RZ ; OK IF ZERO MVI A,2 ; DISK FULL ERROR CODE RET ; ; **** BASE ROUTINES **** ; ; FI$OPEN -- OPEN FILE WHOSE FCB IS PTED TO BY DE FOR INPUT ; FI$OPEN:: PUTRG ; SAVE REGISTERS PUSH D ; SAVE PTR LXI D,TBUFF ; SET DMA ADDRESS MVI C,B$DMA CALL BDOS POP D ; GET PTR LHLD I$FLG ; ALREADY OPENED? MOV A,M ; GET FLAG ORA A ; 0=NO JZ FI$OP0 MVI A,7 ; FILE ALREADY OPEN ERROR JMP F$ABORT FI$OP0: LHLD I$FCB ; PT TO DEFAULT OPEN FCB PUSH H ; SAVE PTR TO FCB CALL SAVEFCB ; CREATE NEW FCB POP D ; GET PTR TO FCB CALL INITFCB ; CLEAR FCB FIELDS CALL F$OPEN ; OPEN FILE ORA A ; ZERO MEANS OK JZ FI$OP1 MVI A,3 ; FILE NOT FOUND FOR INPUT JMP F$ABORT FI$OP1: CALL READ$BLOCK ; READ FIRST BLOCK JZ FI$OP2 MVI A,4 ; READ PAST EOF ERROR JMP F$ABORT FI$OP2: LHLD I$BUF ; PT TO BUFFER XCHG ; ... ADDRESS IN DE LHLD I$PTR ; SAVE PTR MOV M,E ; SAVE ADDRESS PTR INX H MOV M,D LHLD I$CNT ; GET PTR TO COUNT MVI M,128 ; SET COUNT LHLD I$FLG ; GET PTR TO FLAG MVI M,0FFH ; SET FILE OPENED FLAG GETRG ; RESTORE REGISTERS XRA A ; OK RETURN RET ; ; FO$OPEN -- OPEN FILE WHOSE FCB IS PTED TO BY DE FOR OUTPUT ; FO$OPEN:: PUTRG ; SAVE REGISTERS PUSH D ; SAVE PTR LXI D,TBUFF ; SET DMA ADDRESS MVI C,B$DMA CALL BDOS POP D ; GET PTR LHLD O$FLG ; CHECK FOR FILE ALREADY OPENED MOV A,M ; GET FLAG ORA A ; 0 MEANS NOT YET OPENED JZ FO$OP0 MVI A,7 ; FILE ALREADY OPENED ERROR JMP F$ABORT FO$OP0: LHLD O$FCB ; PT TO DEFAULT OPEN FCB PUSH H ; SAVE PTR TO FCB CALL SAVEFCB ; CREATE NEW FCB POP D ; GET PTR TO FCB CALL INITFCB ; CLEAR FCB FIELDS CALL F$MOPEN ; OPEN AND/OR CREATE FILE JZ FO$OP1 MVI A,5 ; DIRECTORY FULL JMP F$ABORT FO$OP1: LHLD O$BUF ; PT TO BUFFER XCHG ; ... IN DE LHLD O$PTR ; SAVE PTR MOV M,E ; SAVE ADDRESS PTR INX H MOV M,D LHLD O$CNT ; GET PTR TO COUNT MVI M,128 ; SET COUNT LHLD O$FLG ; GET PTR TO FLAG MVI M,0FFH ; SET FILE OPENED FLAG GETRG ; RESTORE REGISTERS XRA A ; OK RETURN RET ; ; F$GET -- GET BYTE FROM INPUT FILE; BYTE RETURNED IN REG A ; ON RETURN, IF CARRY=0 (NC), THEN OK; IF CARRY=1 (C), THEN PAST EOF ; F$GET:: PUTRG ; SAVE REGISTERS LHLD I$FLG ; PT TO FLAG MOV A,M ; GET IT; INPUT OK? ORA A ; ZERO MEANS NO JNZ F$G1 MVI A,1 ; FILE NOT YET OPENED JMP F$ABORT F$G1: LHLD I$PTR ; PT TO NEXT BYTE CALL GETADR ; GET ADDRESS OF BYTE PTED TO BY PTR MOV A,H ; EOF WAS REACHED IF POINTER IS ZERO ORA L JZ F$GEOF MOV A,M ; GET BYTE STA BYTE ; SAVE BYTE FOR RETURN INX H ; PT TO NEXT BYTE XCHG ; ... IN DE LHLD I$PTR ; PT TO POINTER MOV M,E ; SAVE ADDRESS PTR INX H MOV M,D LHLD I$CNT ; PT TO COUNT DCR M ; DECREMENT COUNT JNZ F$GET1 ; READ IN NEXT BLOCK AND RESET POINTERS LHLD I$BUF ; PT TO BUFFER XCHG ; ... IN DE LHLD I$PTR MOV M,E ; SAVE ADDRESS PTR INX H MOV M,D LHLD I$CNT ; PT TO COUNT MVI M,128 ; SET COUNT CALL READ$BLOCK JZ F$GET1 ; OK RETURN LHLD I$PTR ; SET POINTER TO ZERO TO INDICATE EOF REACHED MVI M,0 ; STORE ZEROES INX H MVI M,0 ; NORMAL EXIT F$GET1: GETRG ; RESTORE REGISTERS XRA A ; ZERO MEANS OK LDA BYTE ; GET BYTE VALUE TO RETURN RET ; EOF EXIT F$GEOF: MVI A,4 ; EOF JMP F$ABORT ; ; F$PUT -- PUT BYTE IN REG A INTO OUTPUT FILE ; F$PUT:: PUTRG ; SAVE REGISTERS STA BYTE ; SAVE BYTE TO OUTPUT LHLD O$FLG ; GET FILE OPENED FLAG MOV A,M ; GET FLAG ORA A ; ZERO MEANS NO JNZ F$P1 POP PSW ; CLEAR STACK MVI A,1 ; FILE NOT OPENED JMP F$ABORT F$P1: LHLD O$PTR ; GET PTR TO NEXT BYTE CALL GETADR ; PT TO BYTE PTED TO BY PTR LDA BYTE ; GET BYTE TO OUTPUT MOV M,A ; PUT BYTE INX H ; PT TO NEXT XCHG ; ... IN DE LHLD O$PTR ; PT TO PTR MOV M,E ; SAVE ADDRESS INX H MOV M,D LHLD O$CNT ; PT TO COUNT DCR M ; COUNT DOWN JNZ F$PUT1 ; RETURN IF OK ; BUFFER FULL -- WRITE IT TO DISK AND RESET POINTER AND COUNT LHLD O$BUF ; RESET POINTER XCHG ; ADDR OF BUFFER IN DE LHLD O$PTR MOV M,E ; SAVE ADDRESS PTR INX H MOV M,D LHLD O$CNT ; PT TO COUNT MVI M,128 ; RESET COUNT CALL WRIT$BLOCK MVI A,2 ; ASSUME DISK FULL ERROR JNZ F$ABORT ; ERROR IN WRITE ; NORMAL EXIT F$PUT1: GETRG ; RESTORE REGISTERS XRA A ; Z FOR NO ERROR LDA BYTE ; GET BYTE VALUE RET ; ; FI$CLOS -- CLOSE FILE OPENED FOR INPUT ; FI$CLOS:: PUSH H LHLD I$FLG ; SET INPUT OPENED FLAG MVI M,0 ; INPUT NOT OPENED NOW POP H RET ; ; GENERAL-PURPOSE POINTERS FOR ALL GLOBAL ROUTINES ; I$FLG: DS 2 ; INPUT FILE OPENED FLAG (0=NO) O$FLG: DS 2 ; OUTPUT FILE OPENED FLAG (0=NO) I$FCB: DS 2 ; INPUT FILE FCB O$FCB: DS 2 ; OUTPUT FILE FCB I$BUF: DS 2 ; INPUT BUFFER O$BUF: DS 2 ; OUTPUT BUFFER I$PTR: DS 2 ; INPUT CHAR PTR O$PTR: DS 2 ; OUTPUT CHAR PTR I$CNT: DS 2 ; INPUT CHAR COUNT O$CNT: DS 2 ; OUTPUT CHAR COUNT BYTE: DS 1 ; BYTE STORAGE ; ; FO$CLOS -- CLOSE FILE OPENED FOR OUTPUT ; FO$CLOS:: PUTRG ; SAVE REGS STA BYTE ; SAVE A MVI A,1AH ; PUT CTRL-Z CALL F$PUT CLOSE1: LHLD O$CNT ; PT TO COUNT MOV A,M ; GET COUNT CPI 128 ; CLOSE IF BLOCK JUST WRITTEN JZ CLOSE2 XRA A ; PUT ZERO CALL F$PUT JMP CLOSE1 CLOSE2: LHLD O$FLG ; SET OUTPUT OPENED FLAG MVI M,0 ; NOT OPENED LHLD O$FCB ; PT TO OUTPUT FCB XCHG ; ... PT VIA DE CALL F$CLOS ; CLOSE FILE CPI 0FFH ; ERROR? JNZ CLOSE3 MVI A,6 ; CLOSE ERROR JMP F$ABORT CLOSE3: GETRG ; RESTORE REGS XRA A ; OK RETURN LDA BYTE ; GET ORIGINAL A RET END