home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
MACLIB
/
SEQIO22.LIB
< prev
next >
Wrap
Text File
|
2000-06-30
|
18KB
|
725 lines
; SEQUENTIAL FILE I/O LIBRARY
; VRS 2.2 Jack Riley, Boulder Colorado(RCPM phone: (303)499-9169)
;
; This is a highly modified version of the original by unknown author
; believed to be Ward Christensen.
; It has been expanded to include the following new features:
; 1) An APPEND mode to the FILE macro to allow the opening of files
; with automatic positioning to the EOF. Both GET and PUT macros
; are expanded to allow full random access to the file. Random
; access reads and writes are used instead of sequential(and also
; in other modes of use of the FILE macro so 1.4 is now incompatible).
; 2) PUBLIC and NONLOC options have been added to the FILE macro
; to allow access to files not in the current user area or on the
; current disk drive. The GET and PUT macros also handle the switching
; needed to provide for multiple opens in multiple areas. The way
; they work is to momentarily switch the user area to the one needed
; for the file undergoing an IO operation. A return is made to the
; 'home' user area to allow for 'local' file accesses or switches
; to other areas to access other files. This is not completely
; satisfactory and one could wish for a more elegant method which
; should have been available under CPM. Also an additional byte
; has been added to the FCB generated by FILLFCB to contain the
; user area. The NONLOC option prevents an otherwise automatic
; sequence to look first in the current user area and on the current
; disk for the file, then switch the user area, then the disk to
; the default locations. When PUBLIC is included in an invocation
; of FILE, then code accessing default and current values is made.
; The allocations for these variables is shown below.
; DEFAULT$USER:
; DB 0 ; or other user area
; DEFAULT$DISK:
; DB 'x'-'A' ; where x is the default
; CUR$USER:
; DB 0FFH ; necessary initial value
; CUR$DISK:
; DB 0FFH ; " "
;
; The intention was to allow the default values to be modified
; at run time(one of the failings of MACRO-economics) so that
; determinations of the availability of hard disks, for example,
; could be included. Also it is sometimes nice to have these
; values at the very beginning of a program so that DDT-style
; customizations can be made.
; 3) A SECTBUF parameter has been added to FILE to turn off the
; standard character buffering previously provided. It seemed
; reasonable to provide this new open machinery even when
; simple sector buffering was intended. Also when SECTBUF=NONE
; all buffering is turned off and only the new open code is
; produced. This can also be done through use of the POPEN macro
; directly(without FCB's being generated).
FILERR SET 0000H ;REBOOT AFTER ERROR
@FALSE SET 0000H
@TRUE SET NOT @FALSE
@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
@MAK EQU 22 ;FILE MAKE
@REN EQU 23 ;FILE RENAME
@DMA EQU 26 ;SET DMA ADDRESS
@FRD EQU 33 ;FILE RANDOM READ OPERATION
@FWR EQU 34 ;FILE RANDOM WRITE OPERATION
@CFS EQU 35 ;COMPUTE FILE SIZE
@SETRR EQU 36 ;SET RANDOM RECORD
;
@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
NONE EQU 1
SECTBUFF EQU @TRUE
NONLOC EQU @TRUE
INFILE EQU 1 ;INPUT FILE
OUTFILE EQU 2 ;OUTPUTFILE
SETFILE EQU 3 ;SETUP NAME ONLY
APPEND EQU 4 ;APPEND TO FILE
;
; 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 EQU $
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 MD,FID,DN,FN,FT,BS,BA
;; FILL THE FILE CONTROL BLOCK WITH DISK NAME
;; DEFINE FILE USING MODE MD:
;; INFILE = 1 INPUT FILE
;; OUTFILE = 2 OUTPUT FILE
;; SETFILE = 3 SETUP FCB
;; 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
;;
FID&TYP SET MD ;;SET MODE FOR LATER REF'S
;; 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
ENDIF
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 23 ;;X,X,RC,DM0...DM15,CR,R0,R1,R2 FIELDS
DB 0FFH ;; DEFAULT CURRENT USER AREA
;;
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 EQU $
DW FID&BUF
;;
FID&SIZ EQU @BS ;;LITERAL SIZE
FID&LEN EQU $
DW @BS ;;BUFFER SIZE
FID&PTR EQU $
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 EQU $
ENDM
;
FILE MACRO FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF
;; (SEE FILLFCB FOR PARAMETERS)
FID&FLG SET 1
IF NUL PU
FID&PUB SET 0
ELSE
FID&PUB SET 1
ENDIF
@SETRC SET @SETRR
IF FMODE=APPEND
@SETRC SET @CFS
GFILE FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,0
FID&TYP SET OUTFILE ;;SET MODE FOR LATER REF'S
ENDIF
GFILE FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC
ENDM
;
GFILE MACRO FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC
LOCAL PSUB,MSG,PMSG
LOCAL PND,EOD,EOB,PNC,GLOOP,SAMEUSR
;; CONSTRUCT THE FILE CONTROL BLOCK
;;
MD SET FMODE
IF FMODE=APPEND
IF @SETRC=0
MD SET INFILE
ELSE
MD SET OUTFILE
ENDIF
ENDIF
IF FID&FLG
FILLFCB MD,FID,DN,FN,FT,BS,BA
ENDIF
IF MD=SETFILE ;;SETUP FCB ONLY, SO EXIT
EXITM
ENDIF
;; FILE CONTROL BLOCK AND RELATED PARAMETERS
;; ARE CREATED INLINE, NOW CREATE IO FUNCTION
BLOCKING SET @TRUE
IF NUL SECTBUF ;;INPUT FILE
JMP PSUB ;;PAST INLINE SUBROUTINE
IF MD=OUTFILE
PUT&FID EQU $
PUSH PSW ;;SAVE OUTPUT CHARACTER
ELSE
GET&FID EQU $
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
ELSE
IF SECTBUF=NONE
BLOCKING SET @FALSE
ENDIF
ENDIF
IF BLOCKING
LXI H,0
SHLD FID&PTR ;;CLEAR NEXT TO GET/PUT
PND EQU $
;; 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
IF FID&PUB
LDA FCB&FID+36 ;; GET USER AREA OF FILE
CPI 0FFH
JZ SAMEUSR
MVI C,32
MOV E,A
CALL @BDOS ;; GO TO FILE USER AREA
SAMEUSR EQU $
ENDIF
LXI D,FCB&FID ;;FCB ADDRESS TO DE
IF MD=INFILE ;;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
IF FID&PUB
CALL RESET$SYSTEM
ENDIF
ORA A ;;CHECK RETURN CODE
JNZ EOD ;;END OF FILE/DISK?
;; NOT END OF FILE/DISK, INCREMENT LENGTH
LHLD FCB&FID+33 ;;INDEX TO RANDOM RECORD #
INX H
SHLD FCB&FID+33 ;;POINTER UPDATED
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 EQU $
;; END OF FILE/DISK ENCOUNTERED
IF MD=INFILE ;;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 EQU $
DB @CR,@LF
DB 'DISK FULL: &FID'
DB '$'
ENDIF
;;
EOB EQU $
;; 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 EQU $
IF NUL SECTBUF
;; 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=INFILE ;;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
ENDIF
RET
ENDIF ; IF BLOCKING
;;
PSUB EQU $
IF FID&FLG
;;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=INFILE ;;INPUT FILE
SHLD FID&PTR ;;CAUSE IMMEDIATE READ
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
LOCALT SET NUL NOLOC
IF NOT FID&PUB OR LOCALT
PUSH D
MVI C,@OPN ;;OPEN FILE FUNCTION
CALL @BDOS ;;OPEN/MAKE OK?
INR A ;;255 BECOMES 00
POP D
JNZ PMSG
ENDIF ; NUL NOLOC OR NUL PU
IF FID&PUB AND MD=INFILE
POPEN NOLOC
JNZ PMSG
ENDIF
IF FMODE=APPEND
MVI A,EOF ;; PRIME THE BUFFER
STA FID&BUF
LXI H,0 ;;SET NEXT TO FILL
SHLD FID&PTR ;;POINTER INITIALIZED
LXI D,FCB&FID
MVI C,@MAK
CALL @BDOS
INR A ;;255 BECOMES 00
JNZ PMSG
ENDIF
MVI C,@MSG ;;PRINT MESSAGE FUNCTION
LXI D,MSG ;;ERROR MESSAGE
CALL @BDOS ;;PRINTED AT CONSOLE
JMP FILERR ;;TO RESTART
MSG EQU $
DB @CR,@LF
IF MD=INFILE AND NOT (FMODE=APPEND) ;;INPUT MESSAGE
DB 'NO &FID FILE'
ELSE
DB 'NO DIR SPACE: &FID'
ENDIF
DB '$'
IF @SETRC=0
BACK&FID EQU $
LXI H,FID&SIZ ;;RESET THE LENGTH, IT MAY BE ZERO
SHLD FID&LEN ;;IF NO EOF CHARACTER WAS FOUND
LHLD FID&PTR ;;GET INDEX TO GET/PUT
MOV A,L ;;IF =0000 NO EOF CHARACTER TO BACK UP OVER
ORA H
RZ
DCX H
SHLD FID&PTR ;;POINTER UPDATED
@@&FID EQU $
LHLD FCB&FID+33 ;;INDEX TO RANDOM RECORD #
MOV A,L ;;=0000? BE SURE WE DON'T GO BELOW
ORA H
RZ
DCX H
SHLD FCB&FID+33 ;;POINTER UPDATED
RET
ENDIF
PMSG EQU $
ENDIF
IF NOT (@SETRC=0)
MVI C,@SETRC ; GET RANDOM RECORD #
LXI D,FCB&FID
CALL @BDOS
IF FMODE=APPEND
CALL @@&FID
GLOOP EQU $ ; MOVE TO EOF IN LAST RECORD
CALL GET&FID
CPI EOF
JNZ GLOOP
CALL BACK&FID
ENDIF ; FMODE=APPEND
IF FID&PUB
CALL RESET$SYSTEM
ENDIF ; FID&PUB
ENDIF ; @SETRC
FID&FLG SET 0
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=OUTFILE
LOCAL EOB?,PEOF,MSG,PMSG,SAMEUSR
;; WRITE ALL PARTIALLY FILLED BUFFERS
EOB? EQU $
;;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 EQU $
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
IF ?F&PUB
LDA FCB&?F+36 ;; GET USER AREA OF FILE
CPI 0FFH
JZ SAMEUSR
MVI C,32
MOV E,A
CALL @BDOS ;; GO TO FILE USER AREA
SAMEUSR EQU $
ENDIF
LXI D,FCB&?F ;;FCB ADDRESS TO DE
MVI C,@CLS
CALL @BDOS ;; CLOSE THE FILE
IF ?F&PUB
CALL RESET$SYSTEM
ENDIF
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 EQU $
DB @CR,@LF
DB 'CANNOT CLOSE &?F'
DB '$'
PMSG EQU $
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 EQU $
;;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 EQU $
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 EQU $
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
;
POPEN MACRO NOLOC
; DE is assumed to point to the file FCB on entry
OPEN SET 0FH
LOCAL PSUB,LEAVE
;OPEN MAST.CAT
* OPTION 1: TRY TO OPEN FILE IN CURRENT USER NUMBER ON CURRENT DISK
JMP PSUB
@OPEN EQU $
PUSH D ; save the FCB
MVI A,0FFH ; DECLARE CURRENT USER AREA ON FILE
STA FILEUA
MVI C,12 ; GET VERSION NUMBER
CALL @BDOS
MOV A,H ; CP/M 1.X?
ORA L
JZ START2$DISK ; CHECK FOR DEFAULT DISK IF SO
* OPTION 2: TRY TO OPEN FILE IN USER 0 ON CURRENT DISK
MVI E,0FFH ; GET CURRENT USER NUMBER
MVI C,32 ; GET USER CODE
CALL @BDOS
MOV C,A
LDA DEFAULT$USER ; CHECK IF AT DEFAULT USER
CMP C
JZ START2$DISK ; DON'T TRY IF AT DEFAULT USER AREA
STA FILEUA ; WHERE THE FILE IS IF ANYWHERE
MOV E,A
MOV A,C
STA CUR$USER ; WHERE WE ARE(SAVE FOR LATER)
MVI C,32 ; SET USER CODE TO DEFAULT$USER
CALL @BDOS
IF NUL NOLOC
POP D ; GET BACK FCB
PUSH D ; PRESERVE THE STACK
MVI C,OPEN
CALL @BDOS ; TRY TO OPEN FILE AGAIN
CPI 255 ; NOT PRESENT?
JNZ LEAVE
ENDIF ; NUL NOLOC
* OPTION 3: TRY TO OPEN FILE IN USER 0 ON DEFAULT DISK IF NOT CURRENT DISK
START2$DISK EQU $
MVI C,25 ; DETERMINE IF CURRENT DISK IS THE DEFAULT
CALL @BDOS
MOV C,A
LDA DEFAULT$DISK ; CHECK IF AT DEFAULT DISK
CMP C
IF NUL NOLOC
JZ LEAVE ;FAILURE TO OPEN SINCE NOTHING LEFT TO TRY
ENDIF
POP H ; FCB INTO HL
PUSH H ; PRESERVE STACK
IF NUL NOLOC
ELSE
JZ START3$DISK
ENDIF
INR A ; ADD ONE TO DISK NUMBER
MOV M,A ; PUT INTO FCB
START3$DISK EQU $
XCHG ; FCB INTO DE
MVI C,15 ; OPEN FILE
CALL @BDOS
CPI 255 ; NOT PRESENT?
LEAVE EQU $
POP D ; GET THE FCB AGAIN(AND CLEAN UP STACK)
PUSH PSW ; SAVE OPEN STATUS ON FILE
LXI H,36
DAD D
LDA FILEUA ; GET THE USER AREA FOR THE FILE
MOV M,A ; PUT USER AREA INTO FCB
POP PSW
RET
;
RESET$SYSTEM EQU $
PUSH PSW
LDA CUR$USER ; CHECK USER
CPI 0FFH ; 0FFH=NO CHANGE
JZ RESET$RET
MOV E,A ; USER IN E
MVI C,32 ; GET/SET USER CODE
CALL @BDOS
RESET$RET EQU $
POP PSW
RET
FILEUA EQU $
DS 1
PSUB EQU $
POPEN MACRO
CALL @OPEN
ENDM
POPEN
ENDM