wSEN Z80SEPRINT Z80PSEPSTR Z80^SEVAL Z80'SSEVAL1 Z80? SEVAL2 Z80I uASEVAL3 Z80U <SEVAL4 Z80^ArSFAPPENDZ80fXSFCLOSE Z80~~SFDELETEZ80SFEXIST Z80SFILEIO Z80VDSFILL Z80 SFMAKE Z80ؓSFNAME Z80'mSFOPEN Z80 ^RSFREAD Z80SFRENAMEZ80" SFSIZE Z80. DSFWRITE Z80:&SFXIO Z80>e\SFYIO Z80qSGFA Z80SGRR Z80( 4SGRR1 Z805 2SGUA Z80A/SHCAS1 Z80FlSHCAS2 Z80WSHCAS3 Z80i$;SHDR Z80}RxSHGO1 Z80~SHGO2 Z80 iSHIF1 Z80 +SHIF2 Z80 !KSINITFCBZ80VSINLINE Z80-SINSTR Z80 SISALNUMZ80UQSISALPHAZ80oSISCTRL Z80SISDIGITZ80:SISGRAPHZ80 SISHEX Z80SISPRINTZ80zSISPUN Z80SISSP Z80eSLA2HC Z80SLADC Z80 _SLAFDC Z80) SLCRLF Z802SLFN1 Z808[SLFN2 Z80=vSLFN3 Z80BϊSLHL4HC Z80JbSLHL5DC Z80N ˊSLHLFDC Z80[ TSLOUT Z80g*\SLPRINT Z80nSLPSTR Z80r8SLUCLOSEZ80SLUDIR Z80SLUINIT Z80SLUOPEN Z80֎SLUREAD Z80 sP ; ; SYSLIB Module Name: SEN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public en ; ; EN -- ; EXCHANGE NYBBLES OF REG A ; EN: RLCA ; 4 ROTATES RLCA RLCA RLCA RET END ; ; SYSLIB Module Name: SEPRINT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eprint ; ; EPRINT -- ; PRINT STRING PTED TO BY RET ADR UNTIL BINARY 0 ENCOUNTERED ; AFFECT NO REGISTERS OR FLAGS; UNLIKE PRINT, EPRINT DOES NOT ; PERFORM CONTROL CHARACTER INTERPRETATION ; EXT EPSTR EPRINT: EX (SP),HL ; HL=ADR, OLD HL ON STACK CALL EPSTR ; PRINT STRING PTED TO BY HL EX (SP),HL ; RESTORE HL AND NEW RET ADR RET END ; ; SYSLIB Module Name: SEPSTR ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public epstr ; ; EPSTR -- ; PRINT STRING PTED TO BY HL ; AFFECT ONLY HL -- WHEN DONE, HL PTS TO BYTE AFTER STRING ; PERFORM NO CONTROL CHARACTER EXPANSION EXCEPT FOR ; INTERPRET , , , ; EXT COUT EPSTR: PUSH DE ; SAVE REGS PUSH BC PUSH AF ; SAVE REG A AND FLAGS LD C,0 ; SET POSITION COUNT PSL: LD A,(HL) ; GET BYTE INC HL ; PT TO NEXT OR A ; 0=DONE JP Z,PSD CP TAB ; EXPAND JP Z,PST ; ; PRINT CHAR ; INC C ; INCR POSITION CALL COUT ; PRINT IT ON CON: CP CR ; CHECK FOR JP Z,PCR CP LF ; CHECK FOR JP Z,PLF CP BEL ; CHECK FOR JP Z,PLF CP BS ; CHECK FOR JP Z,PBS JP PSL ; ; -- RESET POSITION COUNT ; PCR: LD C,0 ; RESET JP PSL ; ; , , -- CURSOR DIDN'T ADVANCE ; PLF: DEC C ; BACK UP COUNT BY 1 JP PSL ; ; -- CURSOR WENT BACKWARD, MAYBE ; PBS: LD A,C ; CHECK FOR ZERO OR A JP Z,PSL DEC C ; BACK UP COUNT BY 2 DEC C JP PSL ; ; EXPAND ; PST: LD A,C ; GET COUNT AND 7 ; MASK FOR SUB FROM 8 LD B,A ; STORE TEMPORARILY LD A,8 ; SUBTRACT FROM 8 FOR COUNT SUB B LD B,A ; COUNT IN B ADD A,C ; ADD TO POSITION COUNT LD C,A LD A,' ' ; PRINT PSTL: CALL COUT DEC B ; COUNT DOWN JP NZ,PSTL JP PSL ; ; EPSTR DONE ; PSD: POP AF ; RESTORE REG A AND FLAGS POP BC ; RESTORE REGS POP DE RET ; ; ASCII SPECIAL CHARACTER EQUATES ; NULL EQU 0 ; NULL BEL EQU 7 ; BELL BS EQU 8 ; BACKSPACE TAB EQU 9 ; TAB LF EQU 10 ; LINE FEED CR EQU 13 ; CARRIAGE RETURN CTRLR EQU 'R'-40H ; CTRL-R CTRLU EQU 'U'-40H ; CTRL-U CTRLX EQU 'X'-40H ; CTRL-X DEL EQU 7FH ; DELETE CHAR END ; ; SYSLIB Module Name: SEVAL ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eval ; ; EVAL -- ; On input, HL points to a string of ASCII binary, octal, decimal, ; or hexadecimal characters to convert to binary; this string may take ; any of the following forms -- ; ; bbbbbbbbbbbbbbbbB -- b=0 or b=1; binary string ; ttttt or tttttD -- 0<= t <= 9; decimal string ; hhhhH or hhhhX -- 0<= h <= F; hexadecimal string ; oooooooO or oooooooQ -- 0<= o <=7; octal string ; ; On return, DE = value, HL points to next byte after ; string, A=E; BC is not affected. ; On return, CARRY Set means error, and HL pts to byte after error ; EXT CAPS ; CAPITALIZATION ROUTINE EXT EVAL16 ; CONVERT HEX STRING EXT EVAL10 ; CONVERT DEC STRING EXT EVAL8 ; CONVERT OCT STRING EXT EVAL2 ; CONVERT BIN STRING EVAL: PUSH BC ; SAVE BC PUSH HL ; SAVE PTR TO 1ST CHAR XOR A ; A=0 LD (CFLAG),A ; SET CHARACTER FOUND FLAG TO NULL ; Find end of string FEND: LD A,(HL) ; GET BYTE CALL CAPS ; CAPITALIZE SUB '0' ; ASSUME HEX JP C,FEDONE ; DONE CP 10 ; 0-9? JP C,FECONT ; CONTINUE SUB 7 CP 16 ; A-F? JP NC,FEDONE ; Digit found -- set flag and point to next FECONT: LD A,1 ; GET A 1 LD (CFLAG),A ; SET FLAG INC HL ; PT TO NEXT JP FEND ; Found end of string FEDONE: LD A,(HL) ; GET OFFENDING CHAR CALL CAPS ; CAPITALIZE LD C,A DEC HL ; GET PREVIOUS CHAR (POSSIBLY BINARY OR DEC) LD A,(HL) ; GET IT CALL CAPS ; CAPITALIZE LD B,A POP HL ; RESTORE POINTER TO 1ST CHAR IN STRING LD DE,0 ; SET ZERO VALUE (ERROR EXIT) LD A,(CFLAG) ; ANY CHARS? JP Z,DONE ; DONE IF NONE ; Determine type of string (H,X=hex; O,Q=oct; B=bin; D,other=dec) LD A,C ; GET TERMINATING CHAR CP 'H' ; HEX JP Z,EHEX CP 'X' JP Z,EHEX CP 'O' ; OCTAL JP Z,EOCT CP 'Q' JP Z,EOCT LD A,B ; GET PREVIOUS CHAR FOR BINARY CHECK CP 'B' ; BINARY? JP Z,EBIN ; Evaluate string as decimal CALL EVAL10 ; EVALUATE AS DECIMAL LD A,(HL) ; MAY PT TO D CALL CAPS CP 'D' ; INCR HL IF SO JP NZ,DONE INC HL ; PT TO NEXT JP DONE ; Evaluate string as hexadecimal EHEX: CALL EVAL16 ; EVAUATE AS HEXADECIMAL LD A,(HL) ; MUST PT TO H OR X CALL CAPS INC HL ; PT TO NEXT CP 'H' JP Z,DONE CP 'X' JP Z,DONE ; String Error -- set flag ERROR: LD A,E ; LOW-ORDER IN A SCF ; SET CARRY FLAG FOR ERROR POP BC ; RESTORE BC RET ; Evaluate string as octal EOCT: CALL EVAL8 ; EVALUATE AS OCTAL LD A,(HL) ; MUST PT TO O OR Q CALL CAPS INC HL ; PT TO NEXT CP 'O' JP Z,DONE CP 'Q' JP Z,DONE JP ERROR ; ERROR OTHERWISE ; Flag buffer CFLAG: DS 1 ; 0 IF NO CHARS IN STRING, 1 OTHERWISE ; Evaluate string as binary EBIN: CALL EVAL2 ; EVALUATE AS BINARY LD A,(HL) ; MUST PT TO B CALL CAPS INC HL ; PT TO NEXT CP 'B' JP NZ,ERROR ; Done with evaluation -- no error DONE: LD A,E ; LOW-ORDER IN A OR A ; CLEAR CARRY FLAG POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SEVAL1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eval10 ; ; EVAL10 -- ; Convert the string of ASCII decimal digits pointed to by HL ; into a binary value; string is converted until invalid digit is ; encountered. ; On return, HL points to error character, DE=value, A=E (low ; order 8 bits of value). BC not affected. ; EVAL10: PUSH BC ; SAVE BC LD DE,0 ; SET DE=0 INITIALLY ; Get next digit and check for '0' - '9' E10L: LD A,(HL) ; GET BYTE CP '0' ; CHECK FOR RANGE JP C,DONE SUB '0' ; CONVERT TO BINARY CP 10 ; CHECK FOR RANGE JP NC,DONE PUSH AF ; SAVE VALUE ; Multiply DE by 10 MUL10: PUSH HL ; SAVE HL LD H,D ; HL=DE LD L,E ADD HL,HL ; *2 ADD HL,HL ; *4 ADD HL,DE ; *5 ADD HL,HL ; *10 EX DE,HL POP HL ; RESTORE HL ; Add in A POP AF ; GET LATEST DIGIT ADD A,E ; A=A+E LD E,A LD A,D ; ADD TO D IF NECESSARY ADC A,0 LD D,A ; STORE RESULT ; Continue INC HL ; PT TO NEXT CHARACTER JP E10L ; Done -- Result already in DE; Set A=E DONE: LD A,E ; A=E POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SEVAL2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eval16 ; ; EVAL16 -- ; Convert the string of ASCII hexadecimal digits pointed to by HL ; into a binary value; string is converted until invalid digit is ; encountered. ; On return, HL points to error character, DE=value, A=E (low ; order 8 bits of value). BC not affected. ; EXT CAPS ; CAPITALIZATION ROUTINE EVAL16: PUSH BC ; SAVE BC LD DE,0 ; SET DE=0 INITIALLY ; Get next digit and check for '0' - '9' E16L: LD A,(HL) ; GET BYTE CALL CAPS ; CAPITALIZE CP '0' ; CHECK FOR RANGE JP C,DONE CP 'F'+1 ; CHECK FOR RANGE JP NC,DONE CP '9'+1 ; CHECK FOR 0-9 JP C,PRODEC CP 'A' ; CHECK FOR OUT OF RANGE JP C,DONE PRODEC: SUB '0' ; CONVERT TO BINARY CP 10 JP C,PROC SUB 7 ; ADJUST FOR 'A'-'F' ; Proceed with processing PROC: PUSH AF ; SAVE VALUE ; Multiply DE by 16 MUL16: PUSH HL ; SAVE HL LD HL,0 ; ACC=0 LD B,16 ; 16 LOOPS MUL16L: ADD HL,DE ; HL=HL+DE DEC B ; COUNT DOWN JP NZ,MUL16L LD D,H ; NEW DE LD E,L POP HL ; RESTORE HL ; Add in A POP AF ; GET LATEST DIGIT ADD A,E ; A=A+E LD E,A LD A,D ; ADD TO D IF NECESSARY ADC 0 ; Continue INC HL ; PT TO NEXT CHARACTER JP E16L ; Done -- Result already in DE; Set A=E DONE: LD A,E ; A=E POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SEVAL3 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eval8 ; ; EVAL8 -- ; Convert the string of ASCII octal digits pointed to by HL ; into a binary value; string is converted until invalid digit is ; encountered. ; On return, HL points to error character, DE=value, A=E (low ; order 8 bits of value). BC not affected. ; EVAL8: PUSH BC ; SAVE BC LD DE,0 ; SET DE=0 INITIALLY ; Get next digit and check for '0' - '7' E8L: LD A,(HL) ; GET BYTE SUB '0' ; CHECK FOR RANGE JP C,DONE CP 8 JP NC,DONE PUSH AF ; SAVE VALUE ; Multiply DE by 8 MUL8: PUSH HL ; SAVE HL LD HL,0 ; ACC=0 LD B,8 ; 8 LOOPS MUL8L: ADD HL,DE ; HL=HL+DE DEC B ; COUNT DOWN JP NZ,MUL8L LD D,H ; NEW DE LD E,L POP HL ; RESTORE HL ; Add in A POP AF ; GET LATEST DIGIT ADD A,E ; A=A+E LD E,A LD A,D ; ADD TO D IF NECESSARY ADC 0 ; Continue INC HL ; PT TO NEXT CHARACTER JP E8L ; Done -- Result already in DE; Set A=E DONE: LD A,E ; A=E POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SEVAL4 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public eval2 ; ; EVAL2 -- ; Convert the string of ASCII binary digits pointed to by HL ; into a binary value; string is converted until invalid digit is ; encountered. ; On return, HL points to error character, DE=value, A=E (low ; order 8 bits of value). BC not affected. ; EVAL2: PUSH BC ; SAVE BC LD DE,0 ; SET DE=0 INITIALLY ; Get next digit and check for '0' - '1' E2L: LD A,(HL) ; GET BYTE SUB '0' ; CHECK FOR RANGE JP C,DONE CP 2 JP NC,DONE ; Multiply DE by 2 MUL2: PUSH HL ; SAVE HL LD HL,0 ; ACC=0 ADD HL,DE ; HL=DE ADD HL,DE ; HL=DE+DE LD D,H ; DE=HL LD E,L POP HL ; RESTORE HL ADD A,E ; A=A+E LD E,A LD A,D ; ADD TO D IF NECESSARY ADC 0 ; Continue INC HL ; PT TO NEXT CHARACTER JP E2L ; Done -- Result already in DE; Set A=E DONE: LD A,E ; A=E POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SFAPPE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$appl,f$append ; ; SEE DOCUMENTATION WITH EACH ROUTINE FOR DETAILS ; ; ; Externals ; ext initfcb ; ; BDOS Function calls et al ; BDOS EQU 5 ; BDOS address OPENF EQU 15 ; Open file function WRITEF EQU 21 ; Write sequential RREAD EQU 33 ; Random read function GETFS EQU 35 ; Get file size function ; ; Macros ; PUTRG MACRO PUSH HL PUSH DE PUSH BC ENDM ; GETRG MACRO POP BC POP DE POP HL ENDM ; ; F$APPEND OPENS THE INDICATED FILE (WHOSE FCB IS PTED TO BY DE) FOR ; APPENDING, WITH THE NEXT RECORD TO BE APPENDED BEING AFTER THE LAST ; RECORD OF THE FILE. SUBSEQUENT F$WRITE CALLS WILL APPEND TO THE FILE ; AFTER THE LAST RECORD IN THE FILE. ; ; ON INPUT, DE = ADDRESS OF FCB (36 BYTES) ; ON OUTPUT, A = ERROR CODE AND Z IS SET ACCORDINGLY ; A = 0 AND Z IF NO ERROR ; A = 1 AND NZ IF FILE NOT FOUND ; A = 2 AND NZ IF FILE FULL ; A = 3 AND NZ IF FILE EMPTY ; IF SUCCESS, THE TBUFF AREA CONTAINS THE LAST RECORD IN THE FILE ; ; USAGE EXAMPLE: ; ... ; LXI D,FCB ; CALL F$APPEND ; < FILL TBUFF > ; LXI D,FCB ; CALL F$WRITE ; RECORD IS APPENDED AFTER LAST RECORD IN FILE ; ... ; F$APPEND: PUTRG CALL F$APPL ; DO APPEND JP NZ,DONE LD C,WRITEF ; WRITE RECORD CALL BDOS XOR A ; NO ERROR JP DONE ; ; F$APPL OPENS THE INDICATED FILE (WHOSE FCB IS PTED TO BY DE) FOR ; APPENDING. SUBSEQUENT F$WRITE CALLS WILL APPEND TO THE FILE STARTING ; AT THE LAST RECORD IN THE FILE. ; ; ON INPUT, DE = ADDRESS OF FCB (36 BYTES) ; ON OUTPUT, A = ERROR CODE AND Z IS SET ACCORDINGLY ; A = 0 AND Z IF NO ERROR ; A = 1 AND NZ IF FILE NOT FOUND ; A = 2 AND NZ IF FILE FULL ; A = 3 AND NZ IF FILE EMPTY ; IF SUCCESS, THE TBUFF AREA CONTAINS THE LAST RECORD IN THE FILE ; ; USAGE EXAMPLE: ; ... ; LXI D,FCB ; CALL F$APPL ; < FILL TBUFF > ; LXI D,FCB ; CALL F$WRITE ; LAST RECORD OF ORIGINAL FILE IS REWRITTEN ; ... ; F$APPL: PUTRG CALL INITFCB ;INIT THE FCB LD C,OPENF ;OPEN FILE PTED TO BY DE CALL BDOSE CP 0FFH ;ERROR? JP Z,NOFILE LD C,GETFS ;GET FILE SIZE CALL BDOSE LD HL,35 ;CHECK FOR FULL FILE ADD HL,DE LD A,(HL) ;GET VALUE OR A ;MUST BE ZERO JP NZ,FULLFILE DEC HL ;GET RECORD NUMBER OF LAST RECORD LD B,(HL) DEC HL LD C,(HL) ;BC = RECORD NUMBER LD A,B ;CHECK FOR ZERO OR C JP Z,EMFILE ;DONE IF NO RECORDS DEC BC ;DECREMENT TO LAST RECORD LD (HL),C ;STORE RECORD NUMBER - 1 INC HL LD (HL),B LD C,RREAD ;READ LAST RECORD AT RANDOM CALL BDOSE XOR A ;NO ERROR DONE: GETRG RET NOFILE: LD A,1 ;ERROR CODE FOR NO FILE JP FILE FULLFILE: LD A,2 ;ERROR CODE FOR FULL FILE JP FILE EMFILE: LD A,3 ;ERROR CODE FOR EMPTY FILE FILE: GETRG OR A ;SET NZ RET ; ; CALL BDOS AND SAVE DE ; BDOSE: PUSH DE CALL BDOS POP DE RET END ; ; SYSLIB Module Name: SFCLOSE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$close ; ; F$CLOSE -- CLOSE FILE WHOSE FCB IS PTED TO BY DE ; RET W/A=0 IF OK ; EXT BDOS F$CLOSE: PUSH HL ; SAVE HL PUSH BC ; SAVE BC LD C,B$CLOS CALL BDOS CP 255 ; ERROR? JP Z,FCLSDN XOR A ; A=0 FCLSDN: POP BC ; RESTORE BC POP HL ; RESTORE HL RET B$CLOS EQU 16 ; CLOSE FILE END ; ; SYSLIB Module Name: SFDELETE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$delete ; ; F$DELETE -- DELETE FILE WHOSE FCB IS PTED TO BY DE ; EXT BDOS F$DELETE: PUSH HL ; SAVE HL PUSH BC ; SAVE BC LD C,B$DEL CALL BDOS POP BC ; RESTORE BC POP HL ; RESTORE HL RET B$DEL EQU 19 ; DELETE FILE END ; ; SYSLIB Module Name: SFEXIST ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$exist ; ; EXTERNALS ; EXT BDOS ; ; F$EXIST -- Search current disk and user for file whose FCB is pted ; to by DE; return Zero Flag Set (Z) if not found, NZ if found ; F$EXIST: PUSH HL ; SAVE REGS PUSH BC LD C,17 ; SEARCH FOR FIRST CALL BDOS POP BC ; RESTORE REGS POP HL INC A ; 0 IF NOT FOUND RET END ; ; SYSLIB Module Name: SFILEIO ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public fi$open public f$get public fi$clos public fo$open public f$put public fo$clos ; Date: 3 May 85 ; Revised: Al Dunsmuir ; Changes: - Table organization completely changed. ; - Extensive code optimization performed. ; - Actually close input file if it was open ; (required by MP/M and others). ; - Use direct DMA vs DMA to TBUFF and software move. ; Makes byte I/O a bit faster AND safer. ; - Eliminate F$PUT stack error on error 1 ; - Eliminate F$CLOSE PUTS when output buffer is empty ; (was suitable for text files only). ; ; Previous Version: 1.0 (16 Jan 84) ; ; SFILEIO.MAC -- Byte-Oriented File I/O for SYSLIB ; Included routines are -- FILE INPUT OPEN, ; GET, ; FILE INPUT CLOSE, ; FILE OUTPUT OPEN, ; PUT, ; FILE OUTPUT CLOSE ; 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 EXT HMOVB ;Copy (HL) to (DE) for (B) ; CP/M Equates and ASCII Constants ; TBUFF EQU 80H ;Temporary file I/O Buffer EOF EQU 1AH ; 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 ; **** Macro Routines for FILEIO **** ; PUTRG MACRO ;Save BC, DE PUSH BC PUSH DE ENDM GETRG MACRO ;Restore DE, BC, HL POP DE POP BC POP HL ;(HL saved before entry) ENDM ; **** Support Routines for FILEIO **** ; ; ; Error Exits ; E$FNOP: LD A,1 ;"GET or PUT on unopened file" error JP F$EXIT ;Exit ; E$DSKF: LD A,2 ;"Disk Full - no space" error JP F$EXIT ;Exit ; E$IFNF: LD A,3 ;"Input file not found" error JP F$EXIT ;Exit ; E$GEOF: LD A,4 ;"GET past EOF" error JP F$EXIT ;Exit ; E$DIRF: LD A,5 ;"Directory Full" error JP F$EXIT ;Exit ; E$CLOS: LD A,6 ;"File Close" error JP F$EXIT ;Exit ; E$FOPN: LD A,7 ;"File already open" error ; F$EXIT -- Exit, restoring regs and setting flags ; F$EXIT: GETRG ;Restore registers OR A ;Set Flags RET ; READ$BLOCK -- Read block from input file into input buffer ; on return, Z = OK ; NZ = not OK (Past EOF) ; READ$BLOCK: LD HL,(FIO$TBL) ;Get address of Input control table EX DE,HL ; ... in DE LD HL,36+2+1+1 ;Get buffer address. ADD HL,DE EX DE,HL ; ... in DE LD C,B$DMA ;Point BDOS DMA ptr to input buffer CALL BDOS ; LD HL,(FIO$TBL) ;Get address of Input control table INC HL ;Get addr of Input FCB INC HL INC HL INC HL EX DE,HL ;... in DE LD C,B$RD ;Read block via BDOS CALL BDOS ; PUSH AF ;Save return code (A) LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS POP AF ;Restore return code (A) ; OR A ;Set Zero flag if OK RET ; WRIT$BLOCK -- Write block from output buffer into output file ; on return, Z = OK ; NZ = not OK (Disk Full) ; WRIT$BLOCK: LD HL,(FIO$TBL) ;Get address of Output control table EX DE,HL ; ... in DE LD HL,36+2+1+1 ;Get buffer address. ADD HL,DE EX DE,HL ; ... in DE LD C,B$DMA ;Point BDOS DMA ptr to input buffer CALL BDOS ; LD HL,(FIO$TBL) ;Get address of Output control table INC HL ;Get addr of output FCB INC HL INC HL INC HL EX DE,HL ;... in DE LD C,B$WR ;Write block via BDOS CALL BDOS ; PUSH AF ;Save return code (A) LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS POP AF ;Restore return code (A) ; OR A ;Set Zero flag if OK RET ; **** Base Routines for FILEIO **** ; ; ; FI$OPEN -- Open file whose FCB is pted to by DE for Input ; On entry DE -> FCB ; HL -> Input control table ; FI$OPEN: PUTRG ;Save BC, DE LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP NZ,E$FOPN ;"File already open" error ; LD (FIO$TBL),HL ;Save address of Input control table INC HL ;Pt to default open FCB INC HL INC HL INC HL ; PUSH HL ;Save ptr to FCB LD B,36 ;Copy User FCB to internal FCB EX DE,HL ;Hl -> user FCB, DE -> internal FCB CALL HMOVB ;Create new FCB POP DE ;Get ptr to FCB CALL INITFCB ;Clear FCB fields ; CALL F$OPEN ;Open file. OR A ;Zero means OK JP NZ,E$IFNF ;"Input File not found" error ; CALL READ$BLOCK ;Read first block JP NZ,E$GEOF ;"GET past EOF" error ; FOPEN1: LD HL,(FIO$TBL) ;Get address of Input/Output control table LD (HL),0FFH ;Set "file opened" flag INC HL ;Set char count. LD (HL),128 ; INC HL ;Pt to char pointer EX DE,HL ; ... in DE LD HL,36+2 ;Get buffer address. ADD HL,DE EX DE,HL ; ... in DE ; LD (HL),E ;Save buffer start address INC HL LD (HL),D ; XOR A ;File opened OK JP F$EXIT ;Restore regs and exit ; FO$OPEN -- Open file whose FCB is pted to by DE for Output ; On entry DE -> FCB ; HL -> Input control table ; FO$OPEN: PUTRG ;Save BC, DE LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP NZ,E$FOPN ;"File already open" error ; LD (FIO$TBL),HL ;Save address of Input control table INC HL ;Pt to default open FCB INC HL INC HL INC HL ; PUSH HL ;Save ptr to FCB LD B,36 ;Copy User FCB to internal FCB EX DE,HL ;Hl -> user FCB, DE -> internal FCB CALL HMOVB ;Create new FCB POP DE ;Get ptr to FCB CALL INITFCB ;Clear FCB fields CALL F$MOPEN ;Open and/or create file OR A ;Zero means OK JP Z,FOPEN1 ;Set up Output table if OK. JP E$DIRF ;Bad? - "Directory full" error ; F$GET -- Get byte from Input file ; On entry HL -> Input control table ; On return, IF Zero = 1 (Z), then OK (Byte returned in A) ; IF Zero = 0 (NZ), then past EOF ; F$GET: PUTRG ;Save BC, DE LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP Z,E$FNOP ;"File not yet opened" error ; LD (FIO$TBL),HL ;Save address of Input control table INC HL ;Pt to char pointer INC HL LD E,(HL) ;Get char pointer INC HL LD D,(HL) LD A,D ;EOF was reached if pointer is Zero OR E JP Z,E$GEOF ;Indicate EOF, exit ; LD A,(DE) ;GET data byte LD (BYTE),A ;Save byte for return ; INC DE ;Pt to next input byte LD (HL),D ;Update current Input buffer address DEC HL LD (HL),E ; DEC HL ;Pt to buffer data count DEC (HL) ;Decrement count JP NZ,F$GPXT ;Exit if data remains in buffer ; ; Input buffer Empty - read next block & reset pointers and count ; LD (HL),128 ;Set char count. ; INC HL ;Pt to char pointer EX DE,HL ; ... in DE LD HL,36+2 ;Get buffer address. ADD HL,DE EX DE,HL ; ... in DE ; LD (HL),E ;Save buffer start address INC HL LD (HL),D ; CALL READ$BLOCK ;Read next block JP Z,F$GPXT ;GET completed OK - Exit ; LD HL,(FIO$TBL) ;Get address of Input/Output control table INC HL ;Pt to char pointer INC HL LD (HL),0 ;Zero indicates EOF reached INC HL LD (HL),0 ; ; Normal Exit for GET or PUT ; F$GPXT: GETRG ;Restore registers XOR A ;Indicate GET/PUT was OK LD A,(BYTE) ;Get data byte to return RET ; F$PUT -- Put Byte in A into Output File ; On entry HL -> Input control table ; On return, IF Zero = 1 (Z), then OK (Byte returned in A) ; IF Zero = 0 (NZ), then write error ; F$PUT: PUTRG ;Save BC, DE LD (BYTE),A ;Save byte to output LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP Z,E$FNOP ;"File not yet opened" error ; LD (FIO$TBL),HL ;Save address of Output control table INC HL ;Pt to char pointer INC HL LD E,(HL) ;Get char pointer INC HL LD D,(HL) ; LD A,(BYTE) ;Get byte to output LD (DE),A ;PUT data byte ; INC DE ;Pt to next output byte LD (HL),D ;Update current Output buffer address DEC HL LD (HL),E ; DEC HL ;Pt to buffer data count DEC (HL) ;Decrement count JP NZ,F$GPXT ;Exit if space remains in buffer ; ; Output buffer Full - Write to disk & reset pointers and count ; LD (HL),128 ;Set char count. ; INC HL ;Pt to char pointer EX DE,HL ; ... in DE LD HL,36+2 ;Get buffer address. ADD HL,DE EX DE,HL ; ... in DE ; LD (HL),E ;Save buffer start address INC HL LD (HL),D ; CALL WRIT$BLOCK ;Write next block JP Z,F$GPXT ;PUT completed OK - Exit JP E$DSKF ;Error - assume "Disk Full" error ; FI$CLOS -- Close file opened for Input ; FI$CLOS: PUTRG ;Save BC, DE LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP Z,F$EXIT ;Restore regs and exit if not. ; LD (FIO$TBL),HL ;Save address of Input control table JP CLOSE2 ;Close File if open. ; ; FO$CLOS -- CLOSE FILE OPENED FOR OUTPUT ; FO$CLOS: PUTRG ;Save BC, DE LD A,(HL) ;Get open flag... OR A ; 0 = File not open. JP Z,F$EXIT ;Restore regs and exit if not. ; LD (FIO$TBL),HL ;Save address of Output control table INC HL ;Pt to buffer Free space count LD A,(HL) ;Get # bytes remaining CP 128 ;Just close file if Output buffer is empty. JP Z,CLOSE2 ; LD A,EOF ;PUT CP/M text EOF CALL F$PUTI ;Internal call to F$PUT. ; CLOSE1: LD A,(HL) ;Get # bytes remaining CP 128 ;Close if Block just written JP Z,CLOSE2 ; XOR A ;PUT Zero CALL F$PUTI ;Internal call to F$PUT. JP CLOSE1 ;Loop while space remains in buffer ; CLOSE2: LD HL,(FIO$TBL) ;Get address of Input/Output control table LD (HL),0 ;Set file opened flag to NOT opened ; INC HL ;Get addr of output FCB INC HL INC HL INC HL EX DE,HL ;... in DE LD C,B$CL ;Close file. CALL BDOS ;Via BDOS CP 0FFH ;Error? JP Z,E$CLOS ;Yes - "Close file" error ; XOR A ;Input/Output File opened OK JP F$EXIT ;Restore regs and exit ; F$PUTI - Internal call to F$PUT with stack management ; F$PUTI: PUSH HL ;Save Caller's reg LD HL,(FIO$TBL) ;Get address of Output control table JP F$PUT ;Call F$PUT - Very carefully ; Storage for all Global Routines ; FIO$TBL: DW 0 ;Address of Input/Output control table BYTE: DB 0 ;Data byte storage END ; ; SYSLIB Module Name: SFILL ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public fillb,fillbc,hfilb,hfilbc ; ; FILLB and FILLBC, HFILB and HFILBC -- ; Memory fill routines; fill the memory buffer pointed to by HL ; with the byte in Register A; for FILLB and HFILB, B=number of bytes in ; buffer, and for FILLBC and HFILBC, BC=number of bytes in buffer ; No registers are affected for FILL and FILLBC, HL pts to byte after ; last byte filled for HFILB and HFILBC ; FILLB: PUSH BC ; SAVE BC LD C,B ; C=B LD B,0 ; SET B=0 CALL FILLBC ; USE FILLBC POP BC ; RESTORE BC RET FILLBC: PUSH HL ; SAVE REGISTERS PUSH AF PUSH BC PUSH DE LD D,A ; BYTE IN D CALL FILL ; DO FILL POP DE ; RESTORE REGISTERS POP BC POP AF POP HL RET HFILB: PUSH BC ; SAVE BC LD C,B ; C=B LD B,0 ; SET B=0 CALL HFILBC ; USE HFILBC POP BC ; RESTORE BC RET HFILBC: PUSH AF ; SAVE REGISTERS PUSH BC PUSH DE LD D,A ; BYTE IN D CALL FILL ; DO FILL POP DE ; RESTORE REGISTERS POP BC POP AF RET FILL: LD (HL),D ; STORE BYTE INC HL ; PT TO NEXT DEC BC ; COUNT DOWN LD A,B ; DONE? OR C JP NZ,FILL RET END ; ; SYSLIB Module Name: SFMAKE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public f$make ; ; F$MAKE -- MAKE FILE WHOSE FCB IS PTED TO BY DE ; EXT BDOS EXT F$DELETE F$MAKE: CALL F$DELETE ; DELETE FILE PUSH HL ; SAVE HL PUSH BC ; SAVE BC LD C,B$MAKE CALL BDOS OR A ; SET FLAGS (Z FLAG) POP BC ; RESTORE BC POP HL ; RESTORE HL RET B$MAKE EQU 22 ; MAKE FILE END ; ; SYSLIB Module Name: SFNAME ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public fname ; ; FNAME is a file name scanner. Pointing to the first character ; of a file name specification of the form 'du:filename.typ', where ; any part of this specification is optional, this routine fills in ; an FCB with zeros, properly initializes the FN and FT (File Name and ; File Type) fields if 'filename.typ' or any part thereof is present, ; and returns the value of d and u if they are specified (or FFH if they ; are not). ; ; ; EXTERNALS ; EXT CAPS ; CAPITALIZE ROUTINE ; ; BASIC EQUATES ; MAXDISK EQU 16 ; MAX NUMBER OF DISKS MAXUSER EQU 31 ; MAX USER NUMBER CPM EQU 0 ; CP/M ENTRY CR EQU 0DH LF EQU 0AH ; ; MAIN MODULE ; ON ENTRY, DE PTS TO FCB TO BE FILLED AND HL PTS TO FIRST BYTE OF ; TARGET STRING; FCB IS 36 BYTES LONG ; ON EXIT, B=DISK NUMBER (1 FOR A, ETC) AND C=USER NUMBER ; HL PTS TO TERMINATING CHAR ; A=0 AND Z SET IF ERROR IN DISK OR USER NUMBERS, A=0FFH AND NZ ; IF OK ; FNAME: PUSH DE ; SAVE DE LD A,0FFH ; SET DEFAULT DISK AND USER LD (DISK),A LD (USER),A LD B,36 ; INIT FCB PUSH DE ; SAVE PTR XOR A ; A=0 FNINI: LD (DE),A ; STORE ZERO INC DE ; PT TO NEXT DEC B ; COUNT DOWN JP NZ,FNINI POP DE ; GET PTR BACK ; ; SCAN FOR COLON IN STRING ; PUSH HL ; SAVE PTR COLON: LD A,(HL) ; SCAN FOR COLON OR SPACE INC HL ; PT TO NEXT CP ':' ; COLON FOUND? JP Z,COLON1 CP ',' ; COMMA FOUND? JP Z,GETF1 CP ' '+1 ; DELIM? JP C,GETF1 JP COLON ; CONTINUE IF NOT END OF LINE COLON1: POP HL ; CLEAR STACK LD A,(HL) ; SAVE POSSIBLE DRIVE SPEC CALL CAPS ; CAPITALIZE CP 'A' ; DIGIT IF LESS THAN 'A' JP C,USERCK ; PROCESS USER NUMBER SUB 'A' ; CONVERT TO 0-15 CP MAXDISK ; WITHIN BOUNDS? JP C,SVDISK ERREXIT: XOR A ; ERROR INDICATOR POP DE ; RESTORE DE RET ; LOG IN SPECIFIED DISK SVDISK: INC A ; ADJUST TO 1 FOR A LD (DISK),A ; SAVE FLAG INC HL ; PT TO NEXT CHAR ; CHECK FOR USER USERCK: LD A,(HL) ; GET POSSIBLE USER NUMBER CP ':' ; NO USER NUMBER JP Z,GETFILE CP '?' ; ALL USER NUMBERS? JP NZ,USERC1 LD (USER),A ; SET VALUE INC HL ; PT TO AFTER LD A,(HL) ; MUST BE COLON CP ':' JP Z,GETFILE JP ERREXIT ; FATAL ERROR IF NOT COLON AFTER ? USERC1: XOR A ; ZERO USER NUMBER LD B,A ; B=ACCUMULATOR FOR USER NUMBER USRLOOP: LD A,(HL) ; GET DIGIT INC HL ; PT TO NEXT CP ':' ; DONE? JP Z,USRDN SUB '0' ; CONVERT TO BINARY JP C,ERREXIT ; USER NUMBER ERROR? CP 10 JP NC,ERREXIT LD C,A ; NEXT DIGIT IN C LD A,B ; OLD NUMBER IN A ADD A,A ; *2 ADD A,A ; *4 ADD A,B ; *5 ADD A,A ; *10 ADD A,C ; *10+NEW DIGIT LD B,A ; RESULT IN B JP USRLOOP USRDN: LD A,B ; GET NEW USER NUMBER CP MAXUSER+1 ; WITHIN RANGE? JP NC,ERREXIT LD (USER),A ; SAVE IN FLAG JP GETFILE ; EXTRACT FILE NAME GETF1: POP HL ; GET PTR TO BYTE GETFILE: LD A,(HL) ; PTING TO COLON? CP ':' JP NZ,GFILE1 INC HL ; SKIP OVER COLON GFILE1: LD A,(HL) ; GET NEXT CHAR CP ',' ; DELIM? JP Z,GFQUES CP ' '+1 ; NOT A DELIMITER? JP NC,GFILE2 GFQUES: INC DE ; FILL WITH '?' LD B,11 ; 11 BYTES LD A,'?' GFFILL: LD (DE),A ; PUT ? INC DE ; PT TO NEXT DEC B ; COUNT DOWN JP NZ,GFFILL FNDONE: LD A,(DISK) ; GET DISK NUMBER LD B,A ; ... IN B LD A,(USER) ; GET USER NUMBER LD C,A ; ... IN C POP DE ; RESTORE REGS LD A,0FFH ; NO ERROR OR A ; SET FLAGS RET ; GET FILE NAME FIELDS GFILE2: LD B,8 ; AT MOST 8 BYTES FOR FN CALL SCANF ; SCAN AND FILL LD B,3 ; AT MOST 3 BYTES FOR FT LD A,(HL) ; GET DELIMITER CP '.' ; FN ENDING IN '.'? JP NZ,GFILE3 INC HL ; PT TO CHAR AFTER '.' CALL SCANF ; SCAN AND FILL JP FNDONE ; DONE ... RETURN ARGS GFILE3: CALL SCANF4 ; FILL WITH JP FNDONE ; ; SCANNER ROUTINE ; SCANF: CALL DELCK ; CHECK FOR DELIMITER JP Z,SCANF4 ; FILL IF FOUND INC DE ; PT TO NEXT BYTE IN FN CP '*' ; ? FILL? JP NZ,SCANF1 LD A,'?' ; PLACE '?' LD (DE),A JP SCANF2 SCANF1: LD (DE),A ; PLACE CHAR INC HL ; PT TO NEXT POSITION SCANF2: DEC B ; COUNT DOWN JP NZ,SCANF ; CONTINUE LOOP SCANF3: CALL DELCK ; "B" CHARS OR MORE - SKIP TO DELIMITER RET Z INC HL ; PT TO NEXT JP SCANF3 SCANF4: INC DE ; PT TO NEXT FN OR FT LD A,' ' ; FILL LD (DE),A DEC B ; COUNT DOWN JP NZ,SCANF4 RET ; ; BUFFERS ; DISK: DS 1 ; DISK NUMBER USER: DS 1 ; USER NUMBER ; ; CHECK CHAR PTED TO BY HL FOR A DELIMITER ; RET WITH Z FLAG SET IF DELIMITER ; DELCK: LD A,(HL) ; GET CHAR CALL CAPS ; CAPITALIZE OR A ; 0=DELIM RET Z CP ' '+1 ; +1 JP C,DELCK1 ; OR LESS CP '=' RET Z CP 5FH ; UNDERSCORE RET Z CP '.' RET Z CP ':' RET Z CP ';' RET Z CP ',' RET Z CP '<' RET Z CP '>' RET DELCK1: CP (HL) ; COMPARE WITH SELF FOR OK RET END ; ; SYSLIB Module Name: SFOPEN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$mopen,f$open ; ; F$OPEN -- OPEN FILE SPECIFIED BY FCB PTED TO BY DE ; RETURN W/A=0 AND ZERO FLAG SET (Z) IF NO ERROR ; RETURN W/A=0FFH AND NZ IF FILE NOT FOUND OR NO ROOM IN DIRECTORY ; F$MOPEN -- OPEN AND MAKE FILE SPECIFIED BY FCB PTED TO BY DE ; IF FILE DOES NOT EXIST, CREATE IT FIRST ; SAME RETURN CODES ; EXT BDOS PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM F$OPEN: PUTRG ; SAVE REGISTERS LD C,B$OPEN ; OPEN FILE CALL BDOS ; OPEN FILE CP 255 ; NOT PRESENT JP NZ,OPENOK ; OK OPENERR: LD A,0FFH ; ERROR FLAG OR A ; SET FLAGS JP OPENDN OPENOK: XOR A ; OK FLAG OPENDN: GETRG ; RESTORE REGISTERS RET F$MOPEN: PUTRG ; SAVE REGISTERS LD C,B$OPEN ; TRY TO OPEN FILE CALL BDOS CP 0FFH ; NOT PRESENT? JP NZ,OPENOK ; OK LD C,B$CREAT ; TRY TO CREATE FILE CALL BDOS CP 0FFH ; NOT ENOUGH ROOM? JP NZ,OPENOK ; OK JP OPENERR ; ERROR RETURN B$OPEN EQU 15 ; OPEN FILE B$CREAT EQU 22 ; CREATE FILE END ; ; SYSLIB Module Name: SFREAD ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public f$read ; ; F$READ -- READ BLOCK FROM FILE WHOSE FCB IS PTED TO BY DE ; RET W/A=0 IF OK AND FLAGS SET ; EXT BDOS F$READ: PUSH HL ; SAVE HL PUSH BC ; SAVE BC LD C,B$RECR CALL BDOS OR A ; SET FLAGS (Z FLAG) POP BC ; RESTORE BC POP HL ; RESTORE HL RET B$RECR EQU 20 ; READ RECORD END ; ; SYSLIB Module Name: SRENAME ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$rename ; ; F$REN -- RENAME FILES ; THIS ROUTINE RENAMES THE OLD FILE PTED TO BY DE TO THE NEW FILE ; PTED TO BY HL; ONLY THE FN AND FT FIELDS OF THE FCB PTED TO ARE USED, ; AND THE POINTERS POINT TO THE USER NUMBERS, SO FULL FCB'S ARE NOT NECESSARY. ; ONLY THE FIRST 12 BYTES OF AN FCB ARE REQUIRED ; ; ON ENTRY, HL PTS TO NEW FILE NAME, DE PTS TO OLD FILE NAME ; ON EXIT, ZERO FLAG SET (Z) MEANS ERROR (FILE NOT FOUND) ; ; ; EXTERNALS ; EXT BDOS EXT FILLB EXT MOVEB ; ; ROUTINE ; F$RENAME: JP START ; ; FCB FOR RENAME ; RENFCB: DS 36 ; JUST NEED THE SPACE ; ; START OF ROUTINE ; START: PUSH HL ; SAVE REGS PUSH DE PUSH BC PUSH DE ; SAVE OLD NAME PTR PUSH HL ; SAVE NEW NAME PTR LD HL,RENFCB ; INIT THE FCB XOR A ; STORE ZEROES LD B,36 ; 36 BYTES CALL FILLB POP HL ; GET PTR TO NEW NAME LD DE,RENFCB+17 ; PT TO FN PART OF FCB2 INC HL ; PT TO FN LD B,11 ; 11 BYTES CALL MOVEB POP HL ; PT TO 1ST FN LD DE,RENFCB+1 ; PT TO FN PART OF FCB1 INC HL ; PT TO FN LD B,11 ; 11 BYTES CALL MOVEB LD DE,RENFCB ; DO THE RENAME LD C,23 ; BDOS FCT 23 CALL BDOS POP BC ; RESTORE REGS POP DE POP HL CP 0FFH ; ERROR? JP Z,RENERR LD A,0FFH ; SET NO ERROR OR A ; SET FLAGS RET RENERR: XOR A ; SET ERROR RET END ; ; SYSLIB Module Name: SFSIZE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public f$size ; ; BDOS FUNCTION ; GETFSIZ EQU 35 ; GET FILE SIZE ; ; SYSLIB UTILITIES ; EXT MOVEB,INITFCB,BDOS,SHFTRH ; ; MACROS ; PUTRG MACRO PUSH AF PUSH BC PUSH DE ENDM GETRG MACRO POP DE POP BC POP AF ENDM ; ; F$SIZE -- COMPUTE SIZE OF FILE WHOSE FIRST 12 FCB BYTES ARE PTED TO BY DE ; THIS ROUTINE ASSUMES THE FILE IS LESS THAN THE MAX SIZE ; ; ON INPUT, DE PTS TO FIRST 12 BYTES OF FCB (NO MORE IS NECESSARY) ; ON OUTPUT, HL CONTAINS FILE SIZE IN K ; F$SIZE: PUTRG LD HL,FCB ; COPY THEIR 12 BYTES INTO LOCAL FCB EX DE,HL LD B,12 ; 12 BYTES CALL MOVEB LD DE,FCB ; PT TO FCB CALL INITFCB ; INIT IT LD C,GETFSIZ ; GET FILE SIZE USING BDOS FUNCTION CALL BDOS LD D,0 ; SET NO OVERFLOW LD HL,(RANREC) ; GET RANDOM RECORD NUMBER CALL SETOVER ; SET FLAG IF OVER THIS K CALL SHFTRH ; /2 CALL SETOVER CALL SHFTRH ; /4 CALL SETOVER CALL SHFTRH ; /8 FOR K LD A,D ; CHECK FOR OVERFLOW OR A ; 0=OK JP Z,FS1 INC HL ; ADD 1K SINCE OVERFLOW FS1: GETRG RET ; ; SET D=1 IF OVERFLOW OF EVEN BOUNDARY ; SETOVER: LD A,L ; CHECK LSB AND 1 RET Z LD D,1 ; SET OVERFLOW INDICATOR RET ; ; FCB BUFFER ; FCB: DS 32 DB 0 ; SEQ RECORD RANREC: DW 0 ; RANDOM RECORD NUMBER OVFL: DB 0 ; OVERFLOW BYTE END ; ; SYSLIB Module Name: SFWRITE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public f$write ; ; F$WRITE -- WRITE BLOCK TO FILE WHOSE FCB IS PTED TO BY DE ; RET W/A=0 IF OK AND FLAGS ; EXT BDOS F$WRITE: PUSH HL ; SAVE HL PUSH BC ; SAVE BC LD C,B$RECW CALL BDOS OR A ; SET FLAGS (Z FLAG) POP BC ; RESTORE BC POP HL ; RESTORE HL RET B$RECW EQU 21 ; WRITE RECORD END ; ; SYSLIB Module Name: SFXIO ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.3 public fxi$open,fx$get,fxi$close public fxo$open,fx$put,fxo$close ; Date: 28 Apr 85 ; Revised: Al Dunsmuir ; Changes: - FX$GET and FX$PUT routines optimized for speed ; (PUTADR/GETADR not used if disk I/O not required) ; - Use direct DMA vs DMA to TBUFF and software move. ; Makes byte I/O a bit faster AND safer. ; - Some misc. code optimization also performed. ; ; Previous Version: 1.0 (16 Jan 84) ; ; SFXIO provides a group of routines which can perform byte-oriented ; file I/O with a user-defined buffer size. All of these routines work with ; an I/O Control Block which is structured as follows: ; ; Byte Length (Bytes) Function ; 0 1 Number of 128-byte pages in ; working buffer (set by user) ; 1 1 End of File Flag (set and used ; by SFXIO) ; 2 2 Byte Counter (set and used by SFXIO) ; 4 2 Next Byte Pointer (set and used by ; SFXIO) ; 6 2 Address of Working Buffer (set by user) ; 8 36 FCB of File (FN and FT Fields set by ; user, rest set by SFXIO) ; ; The following DB/DS structure can be used in the calling program ; to implement the I/O Control Block: ; ; IOCTL: DB 8 ; Use 8 128-byte pages (1K) ; DS 1 ; Filled by SFXIO ; DS 2 ; Filled by SFXIO ; DS 2 ; Filled by SFXIO ; DW WORKBF ; Address of Working Buffer ; ; IOCFCB: DB 0 ; Current Disk (Inited by SFXIO) ; DB 'MYFILE ' ; File Name ; DB 'TXT' ; File Type ; DS 24 ; Fill Out 36 Bytes ; ; WORKBF: DS 1024 ; Working Buffer ; ; All uses of the routines contain the address of IOCTL in DE. ; Note that if you use a buffer for input, DO NOT use it for output also! ; ; ; External SYSLIB References ; EXT F$OPEN ;Open File EXT F$MOPEN ;Open/Create file EXT INITFCB ;Init FCB EXT F$CLOSE ;Close file EXT SHFTRH ;Shift HL right one bit. EXT SHFTLH ;Shift HL left one bit. ; CP/M Equates and ASCII Constants ; TBUFF EQU 80H ;Temporary File I/O buffer CTRLZ EQU 'Z'-'@' ;^Z 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 ; **** Macro Routines for FXIO **** ; PUTRG MACRO ;Save BC, DE, HL PUSH BC PUSH DE PUSH HL ENDM GETRG MACRO ;Restore BC, DE, HL POP HL POP DE POP BC ENDM ; **** Support Routines for FXIO **** ; ; ; FXIO0 - Routine to read next buffer-full from disk ; FXIO0: LD A,(EOF) ;Check for EOF OR A ;Abort if already at EOF RET NZ ;NZ is error code ; LD HL,(BUFADR) ;Get address of input buffer LD A,(BCNT) ;Get block count LD B,A ;... in B FXIO1: PUSH BC ;Save remaining block count. PUSH HL ;Save current Input buffer ptr EX DE,HL ;Get buffer addr in DE LD C,B$DMA ;Point BDOS DMA ptr to input buffer CALL BDOS ; LD HL,(FCB) ;Get FCB address EX DE,HL ;... IN DE LD C,B$RD ;Read block via BDOS CALL BDOS POP HL ;Restore input buffer ptr POP BC ;Restore remaining block count OR A ;Check Read return code. JP NZ,FXIO2 ;Br if End-of-File ; LD DE,128 ;Get block length ADD HL,DE ;Update buffer addr to point to next block ; DEC B ;One more block processed JP NZ,FXIO1 ;Loop until all blocks written. JP FXIO3 ;Done. FXIO2: LD A,0FFH ;Set "EOF" condition LD (EOF),A ;Set EOF flag ; FXIO3: LD HL,(BUFADR) ;Pt to first byte in buffer LD (BYTENXT),HL ; as "next byte" address ; LD A,(BCNT) ;Get block count SUB B ;Adjust by # empty blocks LD H,A ;Convert to bytes LD L,0 CALL SHFTRH LD (BYTECNT),HL ;Set byte count ; PUSH HL ;Save byte count LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS POP HL ;Get byte count ; LD A,H ;Set EOF return code based on byte count OR L JP Z,FXIO4 XOR A ;Set no error (data available) RET FXIO4: OR 0FFH ;Set error (no data available) RET ; ; FXOO0 - Routine to flush buffer to disk and set up for next write ; FXOO0: LD HL,(BYTECNT) ;Get # of bytes yet to go CALL SHFTLH ;Convert to blocks LD A,(BCNT) ;Get # of blocks in buffer SUB H ;Compute number to write LD B,A ;Get final block count in B LD HL,(BUFADR) ;Pt to first byte to write ; FXOO1: LD A,B ;Check if write complete OR A ;0=Done JP Z,FXOO2 ; DEC B ;Decrement block counter PUSH BC ;Save remaining block count PUSH HL ;Save current Output buffer ptr EX DE,HL ;Get buffer addr in DE LD C,B$DMA ;Point BDOS DMA ptr to output buffer CALL BDOS ; LD HL,(FCB) ;Get FCB address EX DE,HL ;... IN DE LD C,B$WR ;Write block via BDOS CALL BDOS POP HL ;Restore output buffer ptr POP BC ;Restore remaining block count ; LD DE,128 ;Get block length ADD HL,DE ;Update buffer addr to point to next block ; OR A ;Check Write return code. JP Z,FXOO1 ;If OK, Loop until all blocks have been written ; OR 0FFH ;Set error code RET ; FXOO2 - Routine to init buffers for next write ; FXOO2: LD HL,(BUFADR) ;Pt to first byte in buffer LD (BYTENXT),HL ; as "next byte" address ; XOR A ;SET NO EOF LD (EOF),A ; LD A,(BCNT) ;Get block count LD H,A ;Convert to bytes LD L,0 CALL SHFTRH LD (BYTECNT),HL ;Set byte count ; LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS ; XOR A ;No Error RET ; **** Base Routines for FXIO **** ; ; ; FXI$OPEN - Open file/buffers for Byte-Oriented Input (GET) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (File not found) ; FXI$OPEN: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data XOR A ;Set no EOF LD (EOF),A LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL INITFCB ;Init FCB CALL F$OPEN ;Attempt to open file JP NZ,ERRET ;NZ = Error (File not found) ; CALL FXIO0 ;OK - Fill buffer with data ; ; Normal return ; OKRET: CALL GETADR ;Update I/O Control Block data GETRG ;Restore regs OR 0FFH ;Indicate success RET ; Error return ; ERRET: GETRG ;Restore regs XOR A ;Indicate Error RET ; FXO$OPEN - Open file/buffers for Byte-Oriented Output (PUT) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (No Directory space) ; FXO$OPEN: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data CALL FXOO2 ;Init buffers LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL INITFCB ;Init FCB CALL F$MOPEN ;Open and/or Create file JP NZ,ERRET ;NZ = Error (No Directory Space) JP OKRET ;OK- Return and update I/O Control Block ; FX$GET - Get next byte from buffer/file ; on input, DE pts to I/O Control Block ; on output, A=Char and Zero flag set if past EOF ; FX$GET: PUTRG ;Save registers ; ; Check if data byte is in buffer. ; EX DE,HL ;HL -> I/O Control Block data INC HL ;Get caller's BYTECNT in DE INC HL LD E,(HL) INC HL LD D,(HL) DEC HL ;Pt to caller's BYTECNT again. LD A,D ;Is the data byte in the buffer? OR E JP Z,FXGET1 ;No - Fill buffer and GET byte. ; ; It is. GET it and update BYTECNT, BYTENXT as quickly as possible. ; DEC DE ;Update byte count LD (HL),E ;Update caller's BYTECNT. INC HL LD (HL),D ; INC HL ;Get caller's BYTENXT. LD E,(HL) INC HL LD D,(HL) ; LD A,(DE) ;GET data byte from buffer LD (BYTE),A ;Save for return. ; INC DE ;Update caller's BYTENXT. LD (HL),D DEC HL LD (HL),E ; GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; ; Data byte not in buffer - Fill buffer from file first ; FXGET1: EX DE,HL ;DE -> I/O Control Block data. DEC DE DEC DE CALL PUTADR ;Copy I/O Control Block data CALL FXIO0 ;Fill buffer from file JP NZ,ERRET ;NZ = Error (End of File) ; LD HL,(BYTENXT) ;Pt to first byte in buffer LD A,(HL) ;GET from buffer LD (BYTE),A ;Save it INC HL ;Pt to next byte LD (BYTENXT),HL ;Update next byte pointer LD HL,(BYTECNT) ;One less byte in buffer DEC HL LD (BYTECNT),HL ;Update byte count ; ; Normal return ; OKRET1: CALL GETADR ;Update I/O Control Block data GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; FX$PUT - Put next byte into buffer/file ; on input, A=char and DE pts to I/O Control Block ; on output, A=Char and Zero flag set if write error ; FX$PUT: PUTRG ;Save registers LD (BYTE),A ;Save byte to output ; ; Check if data byte will fit in buffer. ; EX DE,HL ;HL -> I/O Control Block data INC HL ;Get caller's BYTECNT in DE INC HL LD E,(HL) INC HL LD D,(HL) DEC HL ;Pt to caller's BYTECNT again. LD A,D ;Will the data byte fit in the buffer? OR E JP Z,FXPUT1 ;No - Flush buffer to file and PUT byte. ; ; It is. PUT it and update BYTECNT, BYTENXT as quickly as possible. ; DEC DE ;Update byte count LD (HL),E ;Update caller's BYTECNT. INC HL LD (HL),D ; INC HL ;Get caller's BYTENXT. LD E,(HL) INC HL LD D,(HL) ; LD A,(BYTE) ;Get data byte LD (DE),A ;PUT data byte in buffer ; INC DE ;Update caller's BYTENXT. LD (HL),D DEC HL LD (HL),E ; GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; ; Data byte will not fit in buffer - Flush buffer to file first. ; FXPUT1: EX DE,HL ;DE -> I/O Control Block data. DEC DE DEC DE CALL PUTADR ;Copy I/O Control Block data CALL FXOO0 ;NO - Flush buffer to file JP NZ,ERRET ;NZ = Error (Write error) ; LD HL,(BYTENXT) ;Pt to first byte in buffer LD A,(BYTE) ;Get next byte LD (HL),A ;PUT in buffer INC HL ;Pt to next byte LD (BYTENXT),HL ;Update next byte pointer LD HL,(BYTECNT) ;One less byte of free space in buffer DEC HL LD (BYTECNT),HL ;Update byte count JP OKRET1 ;OK-return with byte and updated control block ; FXI$CLOSE - Close file/buffers for Byte-Oriented Input (GET) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (Error in closing file) ; FXI$CLOSE: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL F$CLOSE ;Close file JP NZ,ERRET ;NZ = Error (Close file error) JP OKRET ;OK- Return and update I/O Control Block ; FXO$CLOSE - Close file/buffers for Byte-Oriented Output (PUT) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (Error in closing file) ; FXO$CLOSE: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data ; ; Fill last block with ^Z ; FXOCL1: LD HL,(BYTECNT) ;Get free space count. LD A,L ;If on page boundary, done AND 7FH JP Z,FXOCL2 DEC HL ;One less byte of free space in buffer LD (BYTECNT),HL ;Update byte count LD HL,(BYTENXT) ;Pt to next byte LD (HL),CTRLZ ;Store EOF char INC HL LD (BYTENXT),HL JP FXOCL1 ;Loop until last block is full ; ; Close file and exit ; FXOCL2: CALL FXOO0 ;Flush buffers to disk LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL F$CLOSE ;Close file JP NZ,ERRET ;NZ = Error (Close file error) JP OKRET ;OK- Return and update I/O Control Block ; PUTADR - Copy I/O Control Block data to local storage ; PUTADR: EX DE,HL ;Get I/O Control Block addr in HL LD (BUFFER),HL ;Save I/O Control Block address ; LD A,(HL) ;Get block count LD (BCNT),A ; INC HL LD A,(HL) ;Get eof flag LD (EOF),A ; INC HL LD E,(HL) ;Get low count INC HL LD D,(HL) EX DE,HL LD (BYTECNT),HL ;Put byte count ; EX DE,HL INC HL LD E,(HL) ;Get low address INC HL LD D,(HL) EX DE,HL LD (BYTENXT),HL ;Put next byte ptr ; EX DE,HL INC HL LD E,(HL) ;Get low address INC HL LD D,(HL) EX DE,HL LD (BUFADR),HL ;Put buffer address ptr ; EX DE,HL INC HL LD (FCB),HL ;Save address of FCB RET ; GETADR - Update I/O Control Block data from local storage ; GETADR: LD HL,(BUFFER) ;Get I/O Control Block address ; INC HL ;Skip block count ; LD A,(EOF) ;Get EOF flag LD (HL),A ; EX DE,HL LD HL,(BYTECNT) ;Get byte count EX DE,HL INC HL LD (HL),E ;Set low count INC HL LD (HL),D EX DE,HL ; LD HL,(BYTENXT) ;Get next byte pointer EX DE,HL INC HL LD (HL),E ;Set low address INC HL LD (HL),D RET ; ; BUFFERS ; BYTE: DS 1 ;Data byte BUFFER: DS 2 ;Starting address of I/O control block ; The following mirrors the structure of the I/O Control Block ; BCNT: DS 1 ;Number of blocks in buffer EOF: DS 1 ;EOF flag (0=not at EOF, 0FFH=at EOF) BYTECNT: DS 2 ;Number of bytes to go yet BYTENXT: DS 2 ;Address of next byte to PUT/GET BUFADR: DS 2 ;Address of working buffer FCB: DS 2 ;Address of FCB END ; ; SYSLIB Module Name: SFYIO ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.3 ; Derived from SFXIO 1.1 public fyi$open,fy$get,fyi$close,fy$unget public fyo$open,fy$put,fyo$close ; Date: 28 Apr 85 ; Revised: Al Dunsmuir ; Changes: - FY$GET and FX$PUT routines optimized for speed ; (PUTADR/GETADR not used if disk I/O not required) ; - Use direct DMA vs DMA to TBUFF and software move. ; Makes byte I/O a bit faster AND safer. ; - Some misc. code optimization also performed. ; ; Previous Version: 1.0 (16 Jan 84) ; ; SFYIO provides a group of routines which can perform byte-oriented ; file I/O with a user-defined buffer size. All of these routines work with ; an I/O Control Block which is structured as follows: ; ; Byte Length (Bytes) Function ; 0 1 Number of 128-byte pages in ; working buffer (set by user) ; 1 1 End of File Flag (set and used ; by SFYIO) ; 2 2 Byte Counter (set and used by SFYIO) ; 4 2 Next Byte Pointer (set and used by ; SFYIO) ; 6 1 Byte Pending Flag (set by SFYIO) ; 7 1 Pending Byte (set by SFYIO) ; 8 2 Address of Working Buffer (set by user) ; 10 36 FCB of File (FN and FT Fields set by ; user, rest set by SFYIO) ; ; The following DB/DS structure can be used in the calling program ; to implement the I/O Control Block: ; ; IOCTL: DB 8 ; Use 8 128-byte pages (1K) ; DS 1 ; Filled by SFYIO ; DS 2 ; Filled by SFYIO ; DS 2 ; Filled by SFYIO ; DS 2 ; Filled by SFYIO ; DW WORKBF ; Address of Working Buffer ; ; IOCFCB: DB 0 ; Current Disk (Inited by SFYIO) ; DB 'MYFILE ' ; File Name ; DB 'TXT' ; File Type ; DS 24 ; Fill Out 36 Bytes ; ; WORKBF: DS 1024 ; Working Buffer ; ; All uses of the routines contain the address of IOCTL in DE. ; Note that if you use a buffer for input, DO NOT use it for output also. ; ; ; External SYSLIB References ; EXT F$OPEN ;Open File EXT F$MOPEN ;Open/Create file EXT INITFCB ;Init FCB EXT F$CLOSE ;Close file EXT SHFTRH ;Shift HL right one bit. EXT SHFTLH ;Shift HL left one bit. ; CP/M Equates and ASCII Constants ; TBUFF EQU 80H ;Temporary File I/O buffer CTRLZ EQU 'Z'-'@' ;^Z 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 ; **** Macro Routines for FYIO **** ; PUTRG MACRO ;Save BC, DE, HL PUSH BC PUSH DE PUSH HL ENDM GETRG MACRO ;Restore BC, DE, HL POP HL POP DE POP BC ENDM ; **** Support Routines for FYIO **** ; ; ; FYIO0 - Routine to read next buffer-full from disk ; FYIO0: LD A,(EOF) ;Check for EOF OR A ;Abort if already at EOF RET NZ ;NZ is error code ; LD HL,(BUFADR) ;Get address of input buffer LD A,(BCNT) ;Get block count LD B,A ;... in B FYIO1: PUSH BC ;Save remaining block count. PUSH HL ;Save current Input buffer ptr EX DE,HL ;Get buffer addr in DE LD C,B$DMA ;Point BDOS DMA ptr to input buffer CALL BDOS ; LD HL,(FCB) ;Get FCB address EX DE,HL ;... IN DE LD C,B$RD ;Read block via BDOS CALL BDOS POP HL ;Restore input buffer ptr POP BC ;Restore remaining block count OR A ;Check Read return code. JP NZ,FYIO2 ;Br if End-of-File ; LD DE,128 ;Get block length ADD HL,DE ;Update buffer addr to point to next block ; DEC B ;One more block processed JP NZ,FYIO1 ;Loop until all blocks written. JP FYIO3 ;Done. FYIO2: LD A,0FFH ;Set "EOF" condition LD (EOF),A ;Set EOF flag ; FYIO3: LD HL,(BUFADR) ;Pt to first byte in buffer LD (BYTENXT),HL ; as "next byte" address ; LD A,(BCNT) ;Get block count SUB B ;Adjust by # empty blocks LD H,A ;Convert to bytes LD L,0 CALL SHFTRH LD (BYTECNT),HL ;Set byte count ; PUSH HL ;Save byte count LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS POP HL ;Get byte count ; LD A,H ;Determine if any bytes were read OR L JP Z,FYIO4 XOR A ;Set NO error RET FYIO4: OR 0FFH ;Return error code if no bytes read RET ; ; FYOO0 - Routine to flush buffer to disk and set up for next write ; FYOO0: LD HL,(BYTECNT) ;Get # of bytes yet to go CALL SHFTLH ;Convert to blocks LD A,(BCNT) ;Get # of blocks in buffer SUB H ;Compute number to write LD B,A ;Get final block count in B LD HL,(BUFADR) ;Pt to first byte to write ; FYOO1: LD A,B ;Check if write complete OR A ;0=Done JP Z,FYOO2 ; DEC B ;Decrement block counter PUSH BC ;Save remaining block count PUSH HL ;Save current Output buffer ptr EX DE,HL ;Get buffer addr in DE LD C,B$DMA ;Point BDOS DMA ptr to output buffer CALL BDOS ; LD HL,(FCB) ;Get FCB address EX DE,HL ;... IN DE LD C,B$WR ;Write block via BDOS CALL BDOS POP HL ;Restore output buffer ptr POP BC ;Restore remaining block count ; LD DE,128 ;Get block length ADD HL,DE ;Update buffer addr to point to next block ; OR A ;Check Write return code. JP Z,FYOO1 ;If OK, Loop until all blocks have been written ; OR 0FFH ;Set error code RET ; FYOO2 - Routine to init buffers for next write ; FYOO2: LD HL,(BUFADR) ;Pt to first byte in buffer LD (BYTENXT),HL ; as "next byte" address ; XOR A ;SET NO EOF LD (EOF),A ; LD A,(BCNT) ;Get block count LD H,A ;Convert to bytes LD L,0 CALL SHFTRH LD (BYTECNT),HL ;Set byte count ; LD DE,TBUFF ;Reset DMA address (for compatability) LD C,B$DMA CALL BDOS ; XOR A ;No Error RET ; **** Base Routines for FYIO **** ; ; ; FYI$OPEN - Open file/buffers for Byte-Oriented Input (GET) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (File not found) ; FYI$OPEN: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data XOR A LD (EOF),A ;Set no EOF LD (CHPENDFL),A ;Set no pending char LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL INITFCB ;Init FCB CALL F$OPEN ;Attempt to open file JP NZ,ERRET ;NZ = Error (File not found) ; CALL FYIO0 ;OK - Fill buffer with data ; ; Normal return ; OKRET: CALL GETADR ;Update I/O Control Block data GETRG ;Restore regs OR 0FFH ;Indicate success RET ; Error return ; ERRET: GETRG ;Restore regs XOR A ;Indicate Error RET ; FYO$OPEN - Open file/buffers for Byte-Oriented Output (PUT) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (No Directory space) ; FYO$OPEN: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data XOR A LD (CHPENDFL),A ;Set no pending char CALL FYOO2 ;Init buffers LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL INITFCB ;Init FCB CALL F$MOPEN ;Open and/or Create file JP NZ,ERRET ;NZ = Error (No Directory Space) JP OKRET ;OK- Return and update I/O Control Block ; FY$UNGET - Set next byte to be returned by FY$GET ; on input, DE pts to I/O Control Block and A=byte ; on output, Z flag means a character was already pending ; FY$UNGET: PUTRG PUSH AF ;SAVE A CALL PUTADR ;GET DATA INTO BUFFERS LD A,(CHPENDFL) ;CHAR ALREADY PENDING? OR A ;0=NO JP NZ,UNGET1 POP AF ;GET A LD (CHPEND),A ;SET CHAR LD A,0FFH ;SET FLAG LD (CHPENDFL),A ;SET FLAG CALL GETADR ;RESTORE ADDRESS GETRG OR 0FFH ;SET NZ LD A,(CHPEND) ;GET CHAR RET UNGET1: POP AF ;RESTORE A LD (UGTEMP),A ;SAVE A GETRG ;DO NOT RESTORE ADDRESS XOR A ;SET Z LD A,(UGTEMP) ;GET A RET UGTEMP: DS 1 ;TEMP STORAGE ; FY$GET - Get next byte from buffer/file ; on input, DE pts to I/O Control Block ; on output, A=Char and Zero flag set if past EOF ; FY$GET: PUTRG ;Save registers PUSH DE ;SAVE DE CALL PUTADR ;GET DATA INTO BUFFERS POP DE LD A,(CHPENDFL) ;GET CHAR PENDING FLAG OR A ;0=NONE PENDING JP Z,FYGET0 XOR A LD (CHPENDFL),A ;SET NO CHAR PENDING CALL GETADR ;RESTORE BUFFERS LD A,1 ;SET NZ OR A LD A,(CHPEND) ;GET PENDING CHAR GETRG ;RESTORE REGS RET ; ; Check if data byte is in buffer. ; FYGET0: EX DE,HL ;HL -> I/O Control Block data INC HL ;Get caller's BYTECNT in DE INC HL LD E,(HL) INC HL LD D,(HL) DEC HL ;Pt to caller's BYTECNT again. LD A,D ;Is the data byte in the buffer? OR E JP Z,FYGET1 ;No - Fill buffer and GET byte. ; ; It is. GET it and update BYTECNT, BYTENXT as quickly as possible. ; DEC DE ;Update byte count LD (HL),E ;Update caller's BYTECNT. INC HL LD (HL),D ; INC HL ;Get caller's BYTENXT. LD E,(HL) INC HL LD D,(HL) ; LD A,(DE) ;GET data byte from buffer LD (BYTE),A ;Save for return. ; INC DE ;Update caller's BYTENXT. LD (HL),D DEC HL LD (HL),E ; GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; ; Data byte not in buffer - Fill buffer from file first ; FYGET1: EX DE,HL ;DE -> I/O Control Block data. DEC DE DEC DE CALL PUTADR ;Copy I/O Control Block data CALL FYIO0 ;Fill buffer from file JP NZ,ERRET ;NZ = Error (End of File) ; LD HL,(BYTENXT) ;Pt to first byte in buffer LD A,(HL) ;GET from buffer LD (BYTE),A ;Save it INC HL ;Pt to next byte LD (BYTENXT),HL ;Update next byte pointer LD HL,(BYTECNT) ;One less byte in buffer DEC HL LD (BYTECNT),HL ;Update byte count ; ; Normal return ; OKRET1: CALL GETADR ;Update I/O Control Block data GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; FY$PUT - Put next byte into buffer/file ; on input, A=char and DE pts to I/O Control Block ; on output, A=Char and Zero flag set if write error ; FY$PUT: PUTRG ;Save registers LD (BYTE),A ;Save byte to output ; ; Check if data byte will fit in buffer. ; EX DE,HL ;HL -> I/O Control Block data INC HL ;Get caller's BYTECNT in DE INC HL LD E,(HL) INC HL LD D,(HL) DEC HL ;Pt to caller's BYTECNT again. LD A,D ;Will the data byte fit in the buffer? OR E JP Z,FYPUT1 ;No - Flush buffer to file and PUT byte. ; ; It is. PUT it and update BYTECNT, BYTENXT as quickly as possible. ; DEC DE ;Update byte count LD (HL),E ;Update caller's BYTECNT. INC HL LD (HL),D ; INC HL ;Get caller's BYTENXT. LD E,(HL) INC HL LD D,(HL) ; LD A,(BYTE) ;Get data byte LD (DE),A ;PUT data byte in buffer ; INC DE ;Update caller's BYTENXT. LD (HL),D DEC HL LD (HL),E ; GETRG ;Restore regs OR 0FFH ;Indicate success LD A,(BYTE) ;Get data byte RET ; ; Data byte will not fit in buffer - Flush buffer to file first. ; FYPUT1: EX DE,HL ;DE -> I/O Control Block data. DEC DE DEC DE CALL PUTADR ;Copy I/O Control Block data CALL FYOO0 ;NO - Flush buffer to file JP NZ,ERRET ;NZ = Error (Write error) ; LD HL,(BYTENXT) ;Pt to first byte in buffer LD A,(BYTE) ;Get next byte LD (HL),A ;PUT in buffer INC HL ;Pt to next byte LD (BYTENXT),HL ;Update next byte pointer LD HL,(BYTECNT) ;One less byte of free space in buffer DEC HL LD (BYTECNT),HL ;Update byte count JP OKRET1 ;OK-return with byte and updated control block ; FYI$CLOSE - Close file/buffers for Byte-Oriented Input (GET) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (Error in closing file) ; FYI$CLOSE: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL F$CLOSE ;Close file JP NZ,ERRET ;NZ = Error (Close file error) JP OKRET ;OK- Return and update I/O Control Block ; FYO$CLOSE - Close file/buffers for Byte-Oriented Output (PUT) ; on input, DE pts to I/O Control Block ; on output, A=0 and Zero flag set if error (Error in closing file) ; FYO$CLOSE: PUTRG ;Save registers CALL PUTADR ;Copy I/O Control Block data ; ; Fill last block with ^Z ; FYOCL1: LD HL,(BYTECNT) ;Get free space count. LD A,L ;If on page boundary, done AND 7FH JP Z,FYOCL2 DEC HL ;One less byte of free space in buffer LD (BYTECNT),HL ;Update byte count LD HL,(BYTENXT) ;Pt to next byte LD (HL),CTRLZ ;Store EOF char INC HL LD (BYTENXT),HL JP FYOCL1 ;Loop until last block is full ; ; Close file and exit ; FYOCL2: CALL FYOO0 ;Flush buffers to disk LD HL,(FCB) ;Get FCB address EX DE,HL ;... in DE CALL F$CLOSE ;Close file JP NZ,ERRET ;NZ = Error (Close file error) JP OKRET ;OK- Return and update I/O Control Block ; ; PUTADR - Copy I/O Control Block data to local storage ; PUTADR: EX DE,HL ;Get I/O Control Block addr in HL LD (BUFFER),HL ;Save I/O Control Block address ; LD A,(HL) ;Get block count LD (BCNT),A ; INC HL LD A,(HL) ;Get eof flag LD (EOF),A ; INC HL LD E,(HL) ;Get low count INC HL LD D,(HL) EX DE,HL LD (BYTECNT),HL ;Put byte count ; EX DE,HL INC HL LD E,(HL) ;Get low address INC HL LD D,(HL) EX DE,HL LD (BYTENXT),HL ;Put next byte ptr ; EX DE,HL INC HL LD A,(HL) ;Get char pending flag LD (CHPENDFL),A INC HL LD A,(HL) ;Get pending char LD (CHPEND),A ; INC HL LD E,(HL) ;Get low address INC HL LD D,(HL) EX DE,HL LD (BUFADR),HL ;Put buffer address ptr ; EX DE,HL INC HL ;Pt to FCB LD (FCB),HL ;Save address of FCB RET ; ; GETADR - Update I/O Control Block data from local storage ; GETADR: LD HL,(BUFFER) ;Get I/O Control Block address ; INC HL ;Skip block count ; LD A,(EOF) ;Get EOF flag LD (HL),A ; EX DE,HL LD HL,(BYTECNT) ;Get byte count EX DE,HL INC HL LD (HL),E ;Set low count INC HL LD (HL),D EX DE,HL ; LD HL,(BYTENXT) ;Get next byte pointer EX DE,HL INC HL LD (HL),E ;Set low address INC HL LD (HL),D ; INC HL ;Put char pending flag LD A,(CHPENDFL) LD (HL),A INC HL ;Put char pending LD A,(CHPEND) LD (HL),A ; RET ; ; BUFFERS ; BYTE: DS 1 ;Data byte BUFFER: DS 2 ;Starting address of I/O control block ; ; The following mirrors the structure of the I/O Control Block ; BCNT: DS 1 ;Number of blocks in buffer EOF: DS 1 ;EOF flag (0=not at EOF, 0FFH=at EOF) BYTECNT: DS 2 ;Number of bytes to go yet BYTENXT: DS 2 ;Address of next byte to PUT/GET CHPENDFL: DS 1 ;Char pending flag CHPEND: DS 1 ;Char pending BUFADR: DS 2 ;Address of working buffer FCB: DS 2 ;Address of FCB END ; ; SYSLIB Module Name: SGFA ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public gfa ; ; Externals ; ext initfcb ; ; Equates ; bdos equ 5 ; base address of BDOS bsear equ 17 ; set file attributes function code tbuff equ 80h ; DMA address ; ; Macros ; putrg macro push hl ; save regs push de push bc endm getrg macro pop bc ; restore regs pop de pop hl endm ; ; GFA gets the file attributes of the unambiguous file whose FCB ; is pted to by DE; on return, A0 is the R/O bit and A7 is the SYS ; bit, and the MSBs of the FCB in the FN and FT fields are set ; according to the disk entry ; On exit, A=0FFH and NZ if file not found or ambigous file reference ; A=code (A0 is R/O bit and A7 is SYS bit) and Z if OK ; All FCB fields are cleared except for file name and type, and ; these fields are changed in the MSBs to reflect those of the located ; file ; gfa: putrg ; save registers ; ; Check for ambiguous file name ; push de ; save ptr to FCB inc de ; pt to first char ld b,11 ; check 11 bytes amb: ld a,(de) ; get char and 7fh ; mask MSB ld (de),a ; put char cp '?' jp z,amb1 inc de dec b jp nz,amb inc b ; make NZ amb1: pop de jp z,error ; ; Search for file ; push de ; save FCB ptr call initfcb ; clear FCB fields ld c,bsear ; search for first call bdos pop de ; get FCB ptr cp 0ffh ; error? jp z,error ; ; Pt to File Name in TBUFF area ; add a,a ; *2 add a,a ; *4 add a,a ; *8 add a,a ; *16 add a,a ; *32 for TBUFF offset ld c,a ; DE=offset ld b,0 ld hl,tbuff+1 ; pt to DMA address add hl,bc ; HL pts to FN of desired file inc de ; DE pts to FN of target file ld b,8 ; copy 8 bytes copy: ld a,(hl) ; get byte ld (de),a ; put byte inc hl ; pt to next inc de dec b ; count down jp nz,copy ld a,(hl) ; get R/O byte ld (de),a ; put R/O byte rlca ; rotate R/O bit into LSB and 1 ; mask out uninteresting bits ld c,a ; save in C inc hl ; pt to next inc de ld a,(hl) ; get SYS byte ld (de),a ; put SYS byte and 80h ; mask out all but MSB or c ; OR in R/O bit ld c,a ; C=return code inc hl ; pt to next inc de ld a,(hl) ; get and put last byte ld (de),a xor a ; OK return ld a,c ; return code in A getrg ; restore regs ret ; ; Error Return ; error: ld a,0ffh ; set code or a ; set flags getrg ; restore registers ret end ; ; SYSLIB Module Name: SGRR ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 ; public getrr,getfs ; ; This module provides two functions: GETRR and GETFS. ; With the file FCB pted to by DE, GETRR gets the random record ; number (in HL) of the last record read or written sequentially from ; the file. GETFS gets the file size of the file in terms of records ; in HL. The FCB is not affected by these routines. ; ; ; Equates ; GFS EQU 35 SRR EQU 36 BDOS EQU 5 ; ; Macros ; PUTRG MACRO PUSH DE PUSH BC ENDM GETRG MACRO POP BC POP DE ENDM ; ; Get random record number of current record in HL ; A=0 and Z if OK, A=1 and NZ if overflow ; GETRR: PUTRG LD C,SRR ; SET RANDOM RECORD NUMBER GET1: LD HL,LFCB ; SETUP LOCAL FCB LD B,36 ; 36 BYTES PUSH HL ; SAVE PTR TO FCB GET2: LD A,(DE) ; GET BYTE LD (HL),A ; PUT BYTE INC HL ; NEXT INC DE DEC B ; COUNT DOWN JP NZ,GET2 POP DE ; GET PTR TO FCB PUSH DE ; SAVE IT AGAIN CALL BDOS POP DE ; GET PTR TO FCB LD HL,33 ; OFFSET TO RANDOM RECORD NUMBER ADD HL,DE LD E,(HL) ; GET RANDOM RECORD NUMBER IN HL INC HL LD D,(HL) INC HL LD A,(HL) ; OVERFLOW EX DE,HL ; NUMBER IN HL GETRG OR A ; SET ERROR CODE RET ; ; Get file size of file pted to by DE in HL ; This is the size of the file in records ; On input, DE = ptr to FCB ; On output, HL = file size in records ; A = Error flag (0 and Z = OK, 1 and NZ = overflow) ; GETFS: PUTRG LD C,GFS ; GET FILE SIZE JP GET1 ; ; DATA ; LFCB: DS 36 ; LOCAL FCB COPY END ; ; SYSLIB Module Name: SGRR1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 ; public getrr1,getfs1 ; ; This module provides two functions: GETRR1 and GETFS1. ; With the file FCB pted to by DE, GETRR1 gets the random record ; number (in HL) of the last record read or written sequentially from ; the file. GETFS1 gets the file size of the file in terms of records ; in HL. The FCB is affected by these routines, with the random record ; number fields being set. The FCB is not affects for GETRR and GETFS. ; ; ; Equates ; GFS EQU 35 SRR EQU 36 BDOS EQU 5 ; ; Macros ; PUTRG MACRO PUSH DE PUSH BC ENDM GETRG MACRO POP BC POP DE ENDM ; ; Get random record number of current record in HL ; A=0 and Z if OK, A=1 and NZ if overflow ; GETRR1: PUTRG LD C,SRR ; SET RANDOM RECORD NUMBER GET1: PUSH DE ; SAVE FCB PTR CALL BDOS POP DE ; GET PTR TO FCB LD HL,33 ; OFFSET TO RANDOM RECORD NUMBER ADD HL,DE LD E,(HL) ; GET RANDOM RECORD NUMBER IN HL INC HL LD D,(HL) INC HL LD A,(HL) ; OVERFLOW EX DE,HL ; NUMBER IN HL GETRG OR A ; SET ERROR CODE RET ; ; Get file size of file pted to by DE in HL ; This is the size of the file in records ; On input, DE = ptr to FCB ; On output, HL = file size in records ; A = Error flag (0 and Z = OK, 1 and NZ = overflow) ; GETFS1: PUTRG LD C,GFS ; GET FILE SIZE JP GET1 END ; ; SYSLIB Module Name: SGUA ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public gua ; ; Equates ; bdos equ 5 bsua equ 32 ; set user number ; ; Macros ; putrg macro push bc push de push hl endm getrg macro pop hl pop de pop bc endm ; ; GUA gets the current user number. No error code is returned. ; gua: putrg ; save registers ld e,0ffh ; get user ld c,bsua ; set user function call bdos getrg ; restore registers ret end ; ; SYSLIB Module Name: HCASE1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hcase1 ; ; HCASE1 is a case statement processor. On input, register pair HL contains ; a value to test against: ; ; LXI H,TEST ; test value ; CALL HCASE1 ; DW NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in case ; DW VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DW VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DW VALN ; entry value N to test for (N = NUM$ENT) ; DW ADDRN ; address to goto if entry N matches ; ; NUM$ENT is the number of values (VAL1 .. VALN) in the case table ; hcase1: ld (value),hl ; save test value pop hl ; return address in HL push af ; save regs push de ld e,(hl) inc hl ld d,(hl) ; DE = number of entries inc hl ; pt to default ld (default),hl ; save it inc hl ; pt to first entry inc hl ; ; Loop through case table entries, looking for a match ; loop: call test ; compare jp z,match inc hl ; pt to next inc hl inc hl inc hl dec de ; count down ld a,d ; done? or e jp nz,loop ; ; No match found - use default ; ld hl,(default) ; get default jp goto ; ; Match - use HL+1 ; match: inc hl ; point to address inc hl ; ; Get address in HL and return ; goto: ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address pop de ; restore regs pop af push hl ; return address on stack ld hl,(value) ; restore value ret ; ; Test VALUE against two bytes pted to by HL ; Return with ZERO FLAG SET if match ; test: push de ; save DE ex de,hl ; DE has pointer ld hl,(value) ; get value ld a,(de) ; get low cp l ; match? jp nz,testx inc de ; pt to high ld a,(de) ; get high dec de ; pt back cp h ; match? testx: ex de,hl ; flags are set - restore regs pop de ret ; ; Storage buffers ; value: ds 2 ; original HL default: ds 2 ; default address end ; ; SYSLIB Module Name: HCASE2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hcase2 ; ; HCASE2 is a case statement processor. On input, register pair HL contains ; a value to test against and register pair DE contains the address of the ; case table. ; ; LXI H,TEST ; test value ; LXI D,TABLE ; case table address ; CALL HCASE2 ; ... ; TABLE: ; DW NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in case ; DW VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DW VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DW VALN ; entry value N to test for (N = NUM$ENT) ; DW ADDRN ; address to goto if entry N matches ; ; NUM$ENT is the number of values (VAL1 .. VALN) in the case table ; hcase2: ld (value),hl ; save test value pop hl ; flush return address push af ; save regs push de ex de,hl ; case table address in HL ld e,(hl) inc hl ld d,(hl) ; DE = number of entries inc hl ; pt to default ld (default),hl ; save it inc hl ; pt to first entry inc hl ; ; Loop through case table entries, looking for a match ; loop: call test ; compare jp z,match inc hl ; pt to next inc hl inc hl inc hl dec de ; count down ld a,d ; done? or e jp nz,loop ; ; No match found - use default ; ld hl,(default) ; get default jp goto ; ; Match - use HL+1 ; match: inc hl ; point to address inc hl ; ; Get address in HL and return ; goto: ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address pop de ; restore regs pop af push hl ; return address on stack ld hl,(value) ; restore value ret ; ; Test VALUE against two bytes pted to by HL ; Return with ZERO FLAG SET if match ; test: push de ; save DE ex de,hl ; DE has pointer ld hl,(value) ; get value ld a,(de) ; get low cp l ; match? jp nz,testx inc de ; pt to high ld a,(de) ; get high dec de ; pt back cp h ; match? testx: ex de,hl ; flags are set - restore regs pop de ret ; ; Storage buffers ; value: ds 2 ; original HL default: ds 2 ; default address end ; ; SYSLIB Module Name: HCASE3 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hcase3 ; ; HCASE3 is a case statement processor. On input, register pair HL contains ; a value to test against and register pair DE contains the address of the ; case table. Unlike HCASE1 and HCASE2, the return address after the call ; to HCASE3 is preserved, so routines referenced by HCASE3 can resume ; execution right after its call by doing a simple RET. ; ; LXI H,TEST ; test value ; LXI D,TABLE ; case table address ; CALL HCASE3 ; < next instruction > ; control resumes here if routines do a RET ; ... ; TABLE: ; DW NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in case ; DW VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DW VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DW VALN ; entry value N to test for (N = NUM$ENT) ; DW ADDRN ; address to goto if entry N matches ; ; NUM$ENT is the number of values (VAL1 .. VALN) in the case table ; hcase3: ld (value),hl ; save test value push af ; save regs push de ex de,hl ; case table address in HL ld e,(hl) inc hl ld d,(hl) ; DE = number of entries inc hl ; pt to default ld (default),hl ; save it inc hl ; pt to first entry inc hl ; ; Loop through case table entries, looking for a match ; loop: call test ; compare jp z,match inc hl ; pt to next inc hl inc hl inc hl dec de ; count down ld a,d ; done? or e jp nz,loop ; ; No match found - use default ; ld hl,(default) ; get default jp goto ; ; Match - use HL+1 ; match: inc hl ; point to address inc hl ; ; Get address in HL and run routine (original return address is still on ; stack) ; goto: ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address pop de ; restore regs pop af push hl ; return address on stack ld hl,(value) ; restore value ret ; ; Test VALUE against two bytes pted to by HL ; Return with ZERO FLAG SET if match ; test: push de ; save DE ex de,hl ; DE has pointer ld hl,(value) ; get value ld a,(de) ; get low cp l ; match? jp nz,testx inc de ; pt to high ld a,(de) ; get high dec de ; pt back cp h ; match? testx: ex de,hl ; flags are set - restore regs pop de ret ; ; Storage buffers ; value: ds 2 ; original HL default: ds 2 ; default address end ; SYSLIB Module Name: ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.0 ; ; SYSLIB Module Name: HGOTO1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hgoto1 ; ; HGOTO1 is a computed GOTO. When called, register pair HL = index of ; following address to branch to, as indicated: ; ; LXI H,INDEX ; zero-relative ; CALL HGOTO1 ; DW ADDR0 ; IF HL=0 ; DW ADDR1 ; IF HL=1 ; DW ADDR2 ; IF HL=2 ; ... ; ADDR0: ; COME HERE IF HL=0 ; ... ; ADDR1: ; COME HERE IF HL=1 ; ... ; ADDR2: ; COME HERE IF HL=2 ; ... ; ; No error or range checking is done ; hgoto1: ld (hlsave),hl ; save HL ex (sp),hl ; get return address, save HL push de ; save regs push af ex de,hl ; return address in DE ld hl,(hlsave) ; HL = index value add hl,hl ; HL = offset (index * 2) add hl,de ; point to jump in HL ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address to return to pop af ; get regs pop de ex (sp),hl ; restore HL, set address of routine ret ; ; Save buffer ; hlsave: ds 2 end ; ; SYSLIB Module Name: HGOTO2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hgoto2 ; ; HGOTO2 is a computed GOTO. When called, register pair HL = index of ; following address to branch to, as indicated: ; ; LXI H,INDEX ; zero-relative ; CALL HGOTO2 ; JMP ADDR0 ; IF HL=0 ; JMP ADDR1 ; IF HL=1 ; JMP ADDR2 ; IF HL=2 ; ... ; ADDR0: ; COME HERE IF HL=0 ; ... ; ADDR1: ; COME HERE IF HL=1 ; ... ; ADDR2: ; COME HERE IF HL=2 ; ... ; ; No error or range checking is done ; hgoto2: ld (hlsave),hl ; save HL ex (sp),hl ; get return address, save HL push de ; save regs push af ex de,hl ; return address in DE push de ; save return address ld hl,(hlsave) ; HL = index value ld d,h ; DE = HL = index value ld e,l add hl,hl ; HL = index * 2 add hl,de ; HL = offset = index * 3 pop de ; get return address add hl,de ; HL = destination address pop af ; get regs pop de ex (sp),hl ; restore HL, set address of routine ret ; ; Save buffer ; hlsave: ds 2 end ; ; SYSLIB Module Name: HIF1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hif1 ; ; HIF1 is an arithmetic IF facility. A key value is passed in the DE register ; pair and a test value is passed in the HL register pair: ; ; LXI D,5 ; key value ; LXI H,TEST ; test value ; CALL HIF1 ; DW HLTD ; go here if HL < DE ; DW HEQD ; go here if HL = DE ; DW HGTD ; go here if HL > DE ; hif1: ex (sp),hl ; get return address ld (return),hl ex (sp),hl ld (hlsave),hl ; save HL push de ; save regs push af ld a,h ; compare highs cp d jp c,less jp nz,greater ld a,l ; highs are equal, compare lows cp e jp c,less jp nz,greater ld de,2 ; HL = DE, so offset is 2 bytes jp goto greater: ld de,4 ; HL > DE, so offset is 4 bytes jp goto less: ld de,0 ; HL < DE, so offset is 0 bytes goto: ld hl,(return) ; get return address add hl,de ; add in offset ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address to return to pop af ; restore regs pop de ex (sp),hl ; set return address on stack ld hl,(hlsave) ; restore HL ret ; ; Save buffers ; hlsave: ds 2 ; original HL return: ds 2 ; original return address end ; ; SYSLIB Module Name: HIF2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public hif2 ; ; HIF2 is an arithmetic IF facility. A key value is passed in the DE register ; pair and a test value is passed in the HL register pair: ; ; LXI D,5 ; key value ; LXI H,TEST ; test value ; CALL HIF2 ; JMP HLTD ; go here if HL < DE ; JMP HEQD ; go here if HL = DE ; JMP HGTD ; go here if HL > DE ; hif2: ex (sp),hl ; get return address ld (return),hl ex (sp),hl ld (hlsave),hl ; save HL push de ; save regs push af ld a,h ; compare highs cp d jp c,less jp nz,greater ld a,l ; highs are equal, compare lows cp e jp c,less jp nz,greater ld de,3 ; HL = DE, so offset is 3 bytes jp goto greater: ld de,6 ; HL > DE, so offset is 6 bytes jp goto less: ld de,0 ; HL < DE, so offset is 0 bytes goto: ld hl,(return) ; get return address add hl,de ; add in offset pop af ; restore regs pop de ex (sp),hl ; set return address on stack ld hl,(hlsave) ; restore HL ret ; ; Save buffers ; hlsave: ds 2 ; original HL return: ds 2 ; original return address end ; ; SYSLIB Module Name: SINITFCB ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public initfcb ; ; INITFCB -- GIVEN AN FCB PTED TO BY DE, INIT FCB FIELDS OTHER THAN FN ; AND FT (FILE NAME AND FILE TYPE), TO ZERO; FCB MUST BE AT TOTAL OF ; 36 BYTES IN LENGTH (0=DR TO 35=R2) ; ; ON RETURN, NO ERROR CODE RETURNED AND NO REGISTERS AFFECTED ; EXT FILLB ; SYSLIB FILL ROUTINE (USE B REG) PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM INITFCB: PUTRG ; SAVE REGISTERS PUSH AF ; SAVE A EX DE,HL ; HL PTS TO FCB XOR A ; A=0 LD (HL),A ; SET DR FIELD TO ZERO LD DE,12 ; PT TO EX FIELD ADD HL,DE LD B,24 ; CLEAR NEXT 24 BYTES CALL FILLB ; USE SYSLIB ROUTINE POP AF ; GET A GETRG ; GET REGISTERS RET END ; ; SYSLIB Module Name: SINLINE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public inline ; ; INLINE -- ; INPUT LINE EDITOR ; INPUT A LINE FROM CON: INTO THE BUFFER POINTED TO BY H&L ; INPUT PARAMETERS: ; HL PTS TO BUFFER ; A = ECHO FLAG (A=0 MEANS NO ECHO) ; OUTPUT PARAMETERS: ; NO REGS AFFECTED ; INPUT LINE EDITING CHARACTERS ARE -- ; -- DELETE PREVIOUS CHAR AND BACK UP CURSOR (SOFTCOPY) ; -- DELETE PREVIOUS CHAR AND ECHO IT (HARDCOPY) ; -- INPUT COMPLETE ; -- SKIP DOWN TO NEXT LINE AND INSERT ; CTRL-X -- ERASE CURRENT LINE AND BACK UP CURSOR (SOFTCOPY) ; CTRL-U -- ERASE CURRENT LINE (HARDCOPY) ; CTRL-R -- RETYPE CURRENT LINE ; CTRL-E -- GO TO NEXT LINE ; EXT CCOUT EXT CIN EXT COUT EXT CRLF PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM ; ; MAIN INLINE ENTRY POINT ; INLINE: PUTRG ; SAVE REGISTERS PUSH AF ; SAVE PSW LD (ECHO),A ; SAVE ECHO FLAG LD (START),HL ; SAVE START OF STRING ; INLINE RESTART LOOP INL0: LD HL,(START) ; GET START OF STRING LD C,0 ; SET CHAR COUNT ; MAIN LOOP INL1: CALL CIN ; GET INPUT CHAR CP NULL ; DO NOT PERMIT JP Z,INL1 CP BS ; BACKSPACE? JP Z,INBS CP DEL ; DELETE? JP Z,INDEL CP TAB ; TABULATE? JP Z,INTAB CP CR ; CARRIAGE RETURN? JP Z,INCR CP LF ; LINE FEED? JP Z,INLF CP CTRLU ; CTRL-U? JP Z,RESTRT CP CTRLX ; CTRL-X? JP Z,REXSTRT CP CTRLR ; CTRL-R? JP Z,RETYPE CP CTRLE ; CTRL-E? JP Z,NEWLINE LD (HL),A ; STORE CHAR INC HL ; PT TO NEXT CALL CTRL ; PRINT CHAR INC C ; INCR CHAR CNT JP INL1 ; ; ** INLINE MODULES ** ; NEWLINE -- ECHO AND CONTINUE NEWLINE: CALL CRLF JP INL1 ; TAB -- TABULATE TO NEXT TAB STOP INTAB: LD (HL),A ; STORE INC HL ; PT TO NEXT CHAR POSITION CALL INTAB0 ; TABULATE JP INL1 ; CTRL-R -- RETYPE CURRENT LINE RETYPE: LD (HL),0 ; STORE END OF STRING CHAR LD C,0 ; RESET CHAR CNT LD HL,(START) ; GET START ADDRESS CALL HASH ; PRINT HASH CHAR RETY1: LD A,(HL) ; GET CHAR OR A ; ZERO? JP Z,INL1 ; CONTINUE CALL CTRL ; PRINT IT LD A,(HL) ; GET CHAR AGAIN CP TAB ; DON'T COUNT IF JP Z,RETY2 CP BEL ; DON'T COUNT IF JP Z,RETY2 INC C ; INCR CHAR CNT RETY2: INC HL ; PT TO NEXT CHAR JP RETY1 ; CTRL-U -- ERASE LINE AND RESTART RESTRT: CALL HASH ; PRINT HASH CHAR JP INL0 ; START UP AGAIN ; CTRL-X -- ERASE (AND BACKSPACE) LINE AND RESTART REXSTRT: LD A,C ; CHECK FOR EMPTY LINE OR A ; 0 CHARS? JP Z,INL0 CALL EXBS ; JP REXSTRT ; LINE FEED -- INSERT AND ECHO INLF: LD (HL),CR ; STORE INC HL ; PT TO NEXT LD (HL),LF ; STORE INC HL ; PT TO NEXT LD C,0 ; RESET CHAR CNT LD A,(ECHO) ; ECHO ON? OR A ; 0=NO CALL NZ,CRLF ; NEW LINE JP INL1 ; DELETE -- DELETE PREVIOUS CHAR AND ECHO DELETED CHAR INDEL: CALL BOL ; BEGINNING OF LINE? JP Z,INL1 ; CONTINUE DEC HL ; BACK UP LD A,(HL) ; GET CHAR CALL CTRL ; PRINT CHAR CP BEL ; DON'T CHANGE COUNT IF JP Z,INL1 INC C ; INCR DISPLAY CHAR COUNT JP INL1 ; BACKSPACE -- DELETE PREVIOUS CHAR AND BACK UP CURSOR INBS: CALL EXBS ; EXECUTE JP INL1 ; BACKSPACE ROUTINE EXBS: CALL BOL ; BEGINNING OF LINE? RET Z ; CONTINUE IF SO DEC C ; DECR COUNT DEC HL ; BACK UP LD A,(ECHO) ; ECHO ON? OR A ; 0=NO RET Z LD A,BS ; PRINT CALL COUT LD A,' ' ; CALL COUT LD A,BS ; CALL COUT RET ; CARRIAGE RETURN -- DONE; STORE ENDING ZERO INCR: LD (HL),0 ; STORE ENDING ZERO LD A,(ECHO) ; ECHO ON? OR A ; 0=NO CALL NZ,CRLF ; NEW LINE POP AF ; RESTORE PSW GETRG ; RESTORE REGS RET ; ; ** SUPPORT ROUTINES ** ; BOL -- RETURNS W/ZERO FLAG SET IF USER AT BEGINNING OF LINE BOL: EX DE,HL ; DE=HL LD HL,(START) ; GET START ADR EX DE,HL ; HL RESTORED LD A,D ; CHECK FOR MATCH CP H ; MATCH? RET NZ ; NO MATCH LD A,E ; CHECK FOR COMPLETE MATCH CP L RET NZ ; NO MATCH PUSH AF ; SAVE FLAGS LD A,BEL ; BEEP CALL COUT POP AF RET ; CTRL -- IF CHAR>=, PRINT IT; OTHERWISE, PRINT AS CTRL-CHAR CTRL: PUSH BC ; SAVE BC LD B,A ; SAVE CHAR IN B LD A,(ECHO) ; CHECK ECHO FLAG OR A ; 0=NO ECHO LD A,B ; RESTORE CHAR POP BC ; RESTORE BC RET Z ; NO OUTPUT IF NO ECHO CP ' ' ; ? JP C,CTRL1 JP COUT ; PRINT IT NORMALLY CTRL1: CP TAB ; TRAP JP Z,INTAB0 JP CCOUT ; PRINT WITH CTRL-CHAR PROCESSING ; HASH -- PRINT HASH MARK FOLLOWED BY HASH: LD A,'#' ; PRINT HASH CHAR CALL COUT JP CRLF ; BUFFERS START: DS 2 ; TEMPORARY STORAGE FOR BUFFER START ADDRESS ECHO: DS 1 ; ECHO FLAG (0=NO ECHO) ; INTAB0 -- TABULATE ON SCREEN INTAB0: LD A,C ; GET CHAR CNT AND 7 ; MASK FOR DIFFERENCE FROM 8 LD B,A ; STORE IN REG B TEMPORARILY LD A,8 ; SUBTRACT FROM 8 SUB B LD B,A ; COUNT IN B ADD A,C ; ADD TO CHAR COUNT LD C,A LD A,(ECHO) ; ECHO ON? OR A ; 0=NO RET Z LD A,' ' ; IN A INTAB1: CALL COUT ; PRINT DEC B ; COUNT DOWN JP NZ,INTAB1 RET ; ; ASCII SPECIAL CHARACTER EQUATES ; NULL EQU 0 ; NULL BEL EQU 7 ; BELL BS EQU 8 ; BACKSPACE TAB EQU 9 ; TAB LF EQU 10 ; LINE FEED CR EQU 13 ; CARRIAGE RETURN CTRLE EQU 'E'-40H ; CTRL-E CTRLR EQU 'R'-40H ; CTRL-R CTRLU EQU 'U'-40H ; CTRL-U CTRLX EQU 'X'-40H ; CTRL-X DEL EQU 7FH ; DELETE CHAR END ; ; SYSLIB Module Name: SINSTR ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public instr ; ; SINSTR -- ; INSTRING Function. Scan string pointed to by HL for the string ; pointed to by DE. A string in this case is a vector of bytes terminated ; by a binary 0. ; On return, Zero Flag is set if found, and HL points to 1st byte ; of substring within scanned string. DE and BC are not affected. If ; string not found, Zero Flag is not set and HL is not affected. ; INSTR: PUSH BC ; SAVE REGISTERS PUSH HL ; SAVE ORIGINAL HL SCAN: PUSH HL ; SAVE PTR TO STRINGS PUSH DE SCANL: LD A,(DE) ; GET BYTE FROM STRING TO SCAN FOR OR A ; END OF STRING? JP Z,FOUND ; FOUND IF SO LD B,A ; SAVE IN B LD A,(HL) ; GET BYTE OF STRING BEING SCANNED OR A ; END OF STRING? JP Z,NOT$FOUND CP B ; COMPARE STRING ELEMENTS JP NZ,NEXT INC HL ; PT TO NEXT BYTE INC DE JP SCANL ; CONTINUE SCAN ; NO MATCH -- POINT TO NEXT BYTE IN STRING BEING SCANNED NEXT: POP DE ; GET PTRS POP HL INC HL ; PT TO NEXT JP SCAN ; SCAN AGAIN ; MATCH -- ZERO FLAG IS SET -- GET POINTERS FOUND: POP DE ; GET PTRS POP HL POP BC ; CLEAR HL FROM STACK POP BC ; GET BC RET ; NO MATCH -- SET NOT ZERO AND RESTORE ORIGINAL POINTERS NOT$FOUND: POP DE ; GET PTRS POP HL POP HL ; RESTORE ORIGINAL HL POP BC ; GET BC LD A,0FFH ; SET NOT FOUND OR A ; SET NOT ZERO RET END ; ; SYSLIB Module Name: SISALNUM ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isalnum EXT ISDIGIT,ISALPHA ; ; ISALNUM returns Zero Flag Set if char in A is alphanumeric ; (0-9,A-Z,a-z). ISALNUM returns NZ if not. ; ; Char in A is unaffected. ; ISALNUM: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C CALL ISDIGIT ; IS IT A DIGIT? JP Z,YES CALL ISALPHA ; IS IT ALPHABETIC? JP NZ,NO YES: XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISALPHA ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isalpha EXT CAPS ; ; ISALPHA returns Zero Flag Set if char in A is alphabetic (A-Z,a-z). ; ISALPHA returns NZ if not. ; ; Char in A is unaffected. ; ISALPHA: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CALL CAPS ; CAPITALIZE CP 'A' ; LESS THAN A? JP C,NO CP 'Z'+1 ; LESS THAN OR EQUAL TO Z? JP NC,NO XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISCTRL ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isctrl ; ; ISCTRL returns Zero Flag Set if char in A is control (< space, DEL). ; ISCTRL returns NZ if not. ; ; Char in A is unaffected. ; ISCTRL: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CP ' ' ; LESS THAN SPACE? JP C,YES CP 7FH ; DELETE? JP NZ,NO YES: XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISDIGIT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isdigit ; ; ISDIGIT returns Zero Flag Set if char in A is numeric (0-9). ; ISDIGIT returns NZ if not. ; ; Char in A is unaffected. ; ISDIGIT: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CP '0' ; LESS THAN 0? JP C,NO CP '9'+1 ; LESS THAN OR EQUAL TO 9? JP NC,NO XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISGRAPH ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isgraph ; ; ISGRAPH returns Zero Flag Set if char in A is graphic ; ( > space, < DEL). ISGRAPH returns NZ if not. ; ; Char in A is unaffected. ; ISGRAPH: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CP ' '+1 ; LESS THAN OR EQUAL TO SPACE? JP C,NO CP 7FH ; LESS THAN DELETE? JP Z,NO XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISHEX ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public ishex EXT ISDIGIT,CAPS ; ; ISHEX returns Zero Flag Set if char in A is hexadecimal (0-9,A-F,a-f). ; ISHEX returns NZ if not. ; ; Char in A is unaffected. ; ISHEX: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C CALL ISDIGIT ; IS IT A DIGIT? JP Z,YES CALL CAPS ; CAPITALIZE CP 'A' ; LESS THAN A? JP C,NO CP 'F'+1 ; LESS THAN OR EQUAL TO F? JP NC,NO YES: XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISPRINT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public isprint ; ; ISPRINT returns Zero Flag Set if char in A is printable ; ( >= space, < DEL). ISPRINT returns NZ if not. ; ; Char in A is unaffected. ; ISPRINT: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CP ' ' ; LESS THAN SPACE? JP C,NO CP 7FH ; LESS THAN DELETE? JP Z,NO XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISPUN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public ispun ; ; ISPUN returns Zero Flag Set if char in A is a punctuation ; character (any non-alphanumeric greater than space and less than delete). ; ISPUN returns NZ if not. ; ; Char in A is unaffected. ; ; ; DEFINE CHARS ; SPACE EQU ' ' DEL EQU 7FH ISPUN: PUSH BC ; SAVE BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK OUT MSB CP SPACE+1 ; LESS THAN OR EQUAL TO SPACE? JP C,NO CP '0' ; LESS THAN '0'? JP C,YES CP '9'+1 ; LESS THAN OR EQUAL TO '9'? JP C,NO CP 'A' ; LESS THAN 'A'? JP C,YES CP 'Z'+1 ; LESS THAN OR EQUAL TO 'Z'? JP C,NO CP 'a' ; LESS THAN 'a'? JP C,YES CP 'z'+1 ; LESS THAN OR EQUAL TO 'z'? JP C,NO CP DEL ; DELETE? JP Z,NO YES: XOR A ; SET FLAG LD A,C ; GET CHAR POP BC ; RESTORE BC RET NO: LD A,0FFH ; SET FLAG OR A LD A,C ; GET CHAR POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SISSP ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public issp ; ; ISSP returns Zero Flag Set if char in A is a space ; character (null, space, tab, carriage return, line feed, form feed, ; back space, or delete). ISSP returns NZ if not. ; ; Char in A is unaffected. ; ; ; DEFINE SPACE CHARS ; NULL EQU 0 BS EQU 'H'-'@' TAB EQU 'I'-'@' LF EQU 'J'-'@' HT EQU 'K'-'@' FF EQU 'L'-'@' CR EQU 'M'-'@' SPACE EQU ' ' DEL EQU 7FH ISSP: PUSH HL ; SAVE REGS PUSH BC LD C,A ; SAVE CHAR IN C AND 7FH ; MASK MSB LD B,9 ; TABLE COUNT IN B LD HL,SPTAB ; PT TO TABLE ISSPL: CP (HL) ; MATCH? JP Z,ISSP1 INC HL ; PT TO NEXT DEC B JP NZ,ISSPL DEC B ; SET FLAG TO NZ FOR NO MATCH ISSP1: LD A,C ; RESTORE CHAR POP BC ; RESTORE REGS POP HL RET ; ; SPACE TABLE ; SPTAB: DB NULL,SPACE,TAB,LF,FF,CR,BS,HT,DEL END ; ; SYSLIB Module Name: SLA2HC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public la2hc ; ; LA2HC -- ; PRINT REG A AS 2 HEXADECIMAL CHARACTERS ON LST: ; EXT LOUT LA2HC: PUSH AF ; SAVE A PUSH AF RRCA ; EXCHANGE NYBBLES RRCA RRCA RRCA CALL PAHC ; PRINT LOW-ORDER NYBBLE AS HEX POP AF ; GET A CALL PAHC ; PRINT LOW-ORDER NYBBLE AS HEX POP AF ; RESTORE A RET PAHC: AND 0FH ; MASK FOR LOW NYBBLE CP 10 ; LETTER OR DIGIT? JP C,PADIG ; DIGIT IF CARRY ADD 'A'-10 ; CONVERT TO 'A'-'F' JP LOUT ; PRINT PADIG: ADD '0' ; CONVERT TO '0'-'9' JP LOUT ; PRINT END ; ; SYSLIB Module Name: SLADC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public la3dc,ladc EXT LOUT ; ; LA3DC -- ; PRINT REG A AS 3 DECIMAL CHARACTERS ON LST: ; LA3DC: PUSH BC ; SAVE REGS PUSH DE PUSH AF ; SAVE A LD D,0 ; TURN OFF LEADING FLAG JP LADC1 ; ; LADC -- ; PRINT REG A AS DECIMAL CHARACTERS W/LEADING IN 3-CHAR FIELD ; ON LST: ; LADC: PUSH BC ; SAVE REGS PUSH DE PUSH AF ; SAVE A LD D,1 ; TURN ON LEADING FLAG ; ; PRINT ROUTINE ; LADC1: LD B,100 ; PRINT HUNDREDS CALL PAC ; PRINT A CHAR LD B,10 ; PRINT TENS CALL PAC ADD '0' ; CONVERT TO ASCII CALL LOUT ; PRINT POP AF ; RESTORE A POP DE ; RESTORE REGS POP BC RET ; ; PRINT RESULT OF DIVISION OF A BY B W/LEADING (INTEGER DIVISION) ; PAC: LD C,0 ; SET COUNT PACL: SUB B ; COMPUTE COUNT JP C,PACD INC C ; INCR COUNT JP PACL PACD: ADD A,B ; ADD B BACK IN LD E,A ; SAVE A LD A,C ; GET COUNT OR A ; ZERO? JP NZ,PACD1 OR D ; 0 MEANS NO LEADING (A=0, SO A OR D = 0 IF D=0) JP Z,PACD1 LD A,' ' ; PRINT CALL LOUT LD A,E ; RESTORE A RET PACD1: LD D,0 ; D=0 FOR NO LEADING LD A,C ; GET COUNT ADD '0' ; CONVERT TO DECIMAL CALL LOUT ; PRINT IT LD A,E ; RESTORE A RET END ; ; SYSLIB Module Name: SLAFDC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lafdc EXT LOUT ; ; LAFDC -- ; PRINT REG A AS DECIMAL CHARACTERS IN N-CHAR FIELD ON LST: ; FLOATING PRINT, WHERE 1-3 CHARS ARE USED ; LAFDC: PUSH BC ; SAVE REGS PUSH DE PUSH AF ; SAVE A LD D,1 ; TURN ON LEADING FLAG ; ; PRINT ROUTINE ; LD B,100 ; PRINT HUNDREDS CALL PAC ; PRINT A CHAR LD B,10 ; PRINT TENS CALL PAC ADD '0' ; CONVERT TO ASCII CALL LOUT ; PRINT POP AF ; RESTORE A POP DE ; RESTORE REGS POP BC RET ; ; PRINT RESULT OF DIVISION OF A BY B W/LEADING (INTEGER DIVISION) ; PAC: LD C,0 ; SET COUNT PACL: SUB B ; COMPUTE COUNT JP C,PACD INC C ; INCR COUNT JP PACL PACD: ADD A,B ; ADD B BACK IN LD E,A ; SAVE A LD A,C ; GET COUNT OR A ; ZERO? JP NZ,PACD1 OR D ; 0 MEANS NO LEADING (A=0, A OR D = 0 MEANS D=0) JP Z,PACD1 LD A,E ; RESTORE A RET PACD1: LD D,0 ; D=0 FOR NO LEADING LD A,C ; GET COUNT ADD '0' ; CONVERT TO DECIMAL CALL LOUT ; PRINT IT LD A,E ; RESTORE A RET END ; ; SYSLIB Module Name: SLCRLF ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lcrlf ; ; LCRLF -- ; PRINT AND ON LST: ; AFFECT NO REGS ; EXT LOUT LCRLF: PUSH AF ; SAVE REG A AND FLAGS LD A,CR ; PRINT CALL LOUT LD A,LF ; PRINT CALL LOUT POP AF ; RESTORE REG A AND FLAGS RET ; ; ASCII SPECIAL CHARACTER EQUATES ; NULL EQU 0 ; NULL BEL EQU 7 ; BELL BS EQU 8 ; BACKSPACE TAB EQU 9 ; TAB LF EQU 10 ; LINE FEED CR EQU 13 ; CARRIAGE RETURN CTRLR EQU 'R'-40H ; CTRL-R CTRLU EQU 'U'-40H ; CTRL-U CTRLX EQU 'X'-40H ; CTRL-X DEL EQU 7FH ; DELETE CHAR END ; ; SYSLIB Module Name: SLFN1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lfn1 ext lout ; ; Print FCB file name and type pted to by DE on LST: ; Format of Output: xxxxxxxx.xxx ; lfn1: push de ; save regs push bc push af ld b,8 ; 8 chars first call prfnx ld a,'.' ; dot call lout ld b,3 ; 3 more chars call prfnx pop af ; restore regs pop bc pop de ret prfnx: ld a,(de) ; get char and 7fh ; mask out msb call lout ; print it inc de ; pt to next dec b ; count down jp nz,prfnx ret end ; ; SYSLIB Module Name: SLFN2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lfn2 ext lout ; ; Print FCB file name and type pted to by DE on LST: ; Format of Output: xxxxxxxx.yyy (0-8 x's, 0-3 y's) ; lfn2: push de ; save regs push bc push af ld b,8 ; 8 chars first call prfnx ld a,'.' ; dot call lout ld b,3 ; 3 more chars call prfnx pop af ; restore regs pop bc pop de ret prfnx: ld a,(de) ; get char and 7fh ; mask out msb cp ' ' ; space? call nz,lout ; print it inc de ; pt to next dec b ; count down jp nz,prfnx ret end ; ; SYSLIB Module Name: SLFN3 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lfn3 ext lout ; ; Print FCB file name and type pted to by DE on LST: ; Format of Output: xxxxxxxx.yyy (0-8 x's, 0-3 y's, req'd spaces) ; lfn3: push de ; save regs push bc push af ld c,11 ; 11 chars total ld b,8 ; 8 chars first call prfnx ld a,'.' ; dot call lout ld b,3 ; 3 more chars call prfnx ld a,c ; get count of spaces or a ; 0=none call nz,spacer pop af ; restore regs pop bc pop de ret prfnx: ld a,(de) ; get char and 7fh ; mask out msb cp ' ' ; skip space call nz,prout ; print it inc de ; pt to next dec b ; count down jp nz,prfnx ret prout: dec c ; count chars jp lout ; print char spacer: ld a,' ' ; space over call lout dec c ; count down jp nz,spacer ret end ; ; SYSLIB Module Name: SLHL4HC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public lhl4hc ; ; LHL4HC -- Print HL as 4 Hex Characters on LST: ; No Registers are to be affected. ; EXT LA2HC ; PRINT A AS 2 HEX CHARACTERS LHL4HC: PUSH AF ; SAVE A LD A,H ; PRINT H CALL LA2HC LD A,L ; PRINT L CALL LA2HC POP AF ; RESTORE A RET END ; ; SYSLIB Module Name: SLHL5DC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public lhl5dc,lhldc EXT LOUT PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM ; ; LHL5DC -- ; PRINT HL AS 5 DECIMAL CHARACTERS ON LST: ; LHL5DC: PUSH AF ; SAVE ALL REGS PUTRG LD B,0 ; B=0 FOR NO LEADING JP LHDC ; ; LHLDC -- ; PRINT HL AS DECIMAL CHARACTERS W/LEADING SPACES IN 5-CHAR FIELD ; ON LST: ; LHLDC: PUSH AF ; SAVE ALL REGS PUTRG LD B,1 ; A=1 FOR LEADING ; ; PRINT HL USING LEADING FLAG IN B ; LHDC: LD DE,10000 ; PRINT 10000'S CALL PHDC1 LD DE,1000 ; PRINT 1000'S CALL PHDC1 LD DE,100 ; PRINT 100'S CALL PHDC1 LD DE,10 ; PRINT 10'S CALL PHDC1 LD A,L ; PRINT 1'S ADD '0' ; CONVERT TO ASCII CALL LOUT GETRG ; RESTORE ALL REGS POP AF RET ; ; DIVIDE HL BY DE AND PRINT QUOTIENT WITH LEADING S ; PHDC1: LD C,0 ; SET COUNT PHDC2: LD A,L ; SUB E FROM L SUB E LD L,A ; RESULT IN L LD A,H ; SUB D FROM H W/BORROW SBC A,D LD H,A ; RESULT IN H JP C,PHDC3 ; DONE IF CARRY SET (FURTHER BORROW) INC C ; INCR COUNT JP PHDC2 PHDC3: LD A,L ; ADD E TO L ADD A,E LD L,A ; RESULT IN L LD A,H ; ADD D TO H W/CARRY ADC A,D LD H,A ; RESULT IN H LD A,C ; GET RESULT OR A ; CHECK FOR ZERO JP NZ,PHDC4 OR B ; 0 = NO LEADING (A=0, A OR B = 0 IF B=0) JP Z,PHDC4 LD A,' ' ; PRINT JP LOUT PHDC4: LD B,0 ; TURN OFF LEADING LD A,C ; GET VALUE ADD '0' ; CONVERT TO ASCII JP LOUT END ; ; SYSLIB Module Name: SLHLFDC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lhlfdc EXT LOUT PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM ; ; LHLFDC -- ; PRINT HL AS DECIMAL CHARACTERS IN N-CHAR FIELD ON LST: ; FLOATING PRINT, WHERE FIELD SIZE IS FROM 1 TO 5 CHARS ; LHLFDC: PUSH AF ; SAVE ALL REGS PUTRG LD B,1 ; B=1 FOR LEADING ; ; PRINT HL USING LEADING FLAG IN B ; LD DE,10000 ; PRINT 10000'S CALL PHDC1 LD DE,1000 ; PRINT 1000'S CALL PHDC1 LD DE,100 ; PRINT 100'S CALL PHDC1 LD DE,10 ; PRINT 10'S CALL PHDC1 LD A,L ; PRINT 1'S ADD '0' ; CONVERT TO ASCII CALL LOUT GETRG ; RESTORE ALL REGS POP AF RET ; ; DIVIDE HL BY DE AND PRINT QUOTIENT WITH LEADING S ; PHDC1: LD C,0 ; SET COUNT PHDC2: LD A,L ; SUB E FROM L SUB E LD L,A ; RESULT IN L LD A,H ; SUB D FROM H W/BORROW SBC A,D LD H,A ; RESULT IN H JP C,PHDC3 ; DONE IF CARRY SET (FURTHER BORROW) INC C ; INCR COUNT JP PHDC2 PHDC3: LD A,L ; ADD E TO L ADD E LD L,A ; RESULT IN L LD A,H ; ADD D TO H W/CARRY ADC A,D LD H,A ; RESULT IN H LD A,C ; GET RESULT OR A ; CHECK FOR ZERO JP NZ,PHDC4 OR B ; 0=NO LEADING SP (A=0, A OR B = 0 MEANS B = 0) RET NZ PHDC4: LD B,0 ; TURN OFF LEADING LD A,C ; GET VALUE ADD '0' ; CONVERT TO ASCII JP LOUT END ; ; SYSLIB Module Name: SLOUT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lout ; ; LOUT -- ; LIST OUTPUT ROUTINE ; OUTPUT CHAR IN REG A TO LST: ; AFFECT NO REGISTERS OR FLAGS ; PUTRG MACRO PUSH BC ; SAVE BC, DE, HL PUSH DE PUSH HL ENDM GETRG MACRO POP HL ; RESTORE HL, DE, BC POP DE POP BC ENDM LOUT: PUSH AF ; SAVE REG A AND FLAGS PUTRG ; SAVE REGISTERS LD C,A ; CHAR IN C LD HL,(JTABL) ; GET ADDRESS OF JUMP TABLE LD L,L$OFF ; PRINTER OUTPUT ADR LD DE,LRET ; SET UP RET ADR PUSH DE ; ... ON STACK JP (HL) LRET: GETRG ; RESTORE REGISTERS POP AF ; RESTORE REG A AND FLAGS RET BOOT EQU 0 ; CP/M BOOT ADDRESS JTABL EQU BOOT+1 ; CP/M JUMP TABLE ADDRESS L$OFF EQU 0FH ; LIST OUTPUT OFFSET END ; ; SYSLIB Module Name: SLPRINT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lprint ; ; LPRINT -- ; PRINT STRING PTED TO BY RET ADR UNTIL BINARY 0 ENCOUNTERED ON LST: ; AFFECT NO REGISTERS OR FLAGS ; EXT LPSTR LPRINT: EX (SP),HL ; HL=ADR, OLD HL ON STACK CALL LPSTR ; PRINT STRING PTED TO BY HL EX (SP),HL ; RESTORE HL AND NEW RET ADR RET END ; ; SYSLIB Module Name: SLPSTR ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public lpstr ; ; LPSTR -- ; PRINT STRING PTED TO BY HL ON LST: ; AFFECT ONLY HL -- WHEN DONE, HL PTS TO BYTE AFTER STRING ; EXT CLOUT EXT LOUT LPSTR: PUSH DE ; SAVE REGS PUSH BC PUSH AF ; SAVE REG A AND FLAGS LD C,0 ; SET POSITION COUNT PSL: LD A,(HL) ; GET BYTE INC HL ; PT TO NEXT OR A ; 0=DONE JP Z,PSD CP TAB ; EXPAND JP Z,PST ; ; PRINT CHAR ; INC C ; INCR POSITION CALL CLOUT ; PRINT IT ON LST: CP CR ; CHECK FOR JP Z,PCR CP LF ; CHECK FOR JP Z,PLF CP BEL ; CHECK FOR JP Z,PLF CP BS ; CHECK FOR JP Z,PBS JP PSL ; ; -- RESET POSITION COUNT ; PCR: LD C,0 ; RESET JP PSL ; ; , , -- CURSOR DIDN'T ADVANCE ; PLF: DEC C ; BACK UP COUNT BY 1 JP PSL ; ; -- CURSOR WENT BACKWARD, MAYBE ; PBS: LD A,C ; CHECK FOR ZERO OR A JP Z,PSL DEC C ; BACK UP COUNT BY 2 DEC C JP PSL ; ; EXPAND ; PST: LD A,C ; GET COUNT AND 7 ; MASK FOR SUB FROM 8 LD B,A ; STORE TEMPORARILY LD A,8 ; SUBTRACT FROM 8 FOR COUNT SUB B LD B,A ; COUNT IN B ADD A,C ; ADD TO POSITION COUNT LD C,A LD A,' ' ; PRINT PSTL: CALL LOUT DEC B ; COUNT DOWN JP NZ,PSTL JP PSL ; ; PSTR DONE ; PSD: POP AF ; RESTORE REG A AND FLAGS POP BC ; RESTORE REGS POP DE RET ; ; ASCII SPECIAL CHARACTER EQUATES ; NULL EQU 0 ; NULL BEL EQU 7 ; BELL BS EQU 8 ; BACKSPACE TAB EQU 9 ; TAB LF EQU 10 ; LINE FEED CR EQU 13 ; CARRIAGE RETURN CTRLR EQU 'R'-40H ; CTRL-R CTRLU EQU 'U'-40H ; CTRL-U CTRLX EQU 'X'-40H ; CTRL-X DEL EQU 7FH ; DELETE CHAR END ; ; LULIB Module: LUCLOSE ; Author: Richard Conn ; Date: 8 August 85 ; LULIB Version: 1.0 ; LULIB Module Version: 1.0 ; public luclose ; ; LUCLOSE closes the file within a library which was opened by LUOPEN. ; ; On input, DE = ptr to LUD ; .in luddef luclose: push hl ; save regs push bc push af ld hl,ludidx ; pt to index add hl,de ld b,4 ; zero index and length loop: ld (hl),0 ; store zero inc hl ; pt to next djnz loop pop af ; restore regs pop bc pop hl ret end ; ; LULIB Module: LUDIR ; Author: Richard Conn ; Date: 8 August 85 ; LULIB Version: 1.0 ; LULIB Module Version: 1.0 ; public ludir ; ; LUDIR stores selected directory entries from a library in a ; memory buffer. It accepts an ambiguous file name reference and an ; LUD pointer (as provided by LUINIT), and it builds a listing of names ; in memory. This listing is structured as follows: ; ; DB 'FILENAME' ; DB 'TYP' ; DW START_INDEX ; DW LENGTH ; DW CRC ; ... ; entries repeated as necessary ; DB 0 ; indicates end of list ; ; On input, DE = ptr to LUD, HL = ptr to FN.FT, and BC = ptr to ; memory buffer ; On output, A is return code: ; 0 OK ; 0FFH Memory Buffer overflow (encountered top of TPA) ; ; Side Effect: DMA Address is set to 80H ; ; ; Externals and Equates ; lentsz equ 17 ; size of dir entry: ; 11 - for FN.FT ; 2 - for Index ; 2 - for Length ; 2 - for CRC bdose equ 5 ext f$open,r$read .in luddef ludir: push hl ; save regs push de push bc ld c,26 ; set DMA address ld de,tbuff call bdose ; use BDOS call pop bc ; restore and save regs pop de pop hl push hl push de push bc ld a,(bdose+7) ; get upper base page of system sub a,10 ; pt to below ZCPR3 ld (tpaend),a ; set end ptr ld (file),hl ; save ptr to file name ld h,b ; get ptr to memory buffer ld l,c ld (buffer),hl ; save ptr to memory buffer ld hl,ludfcb ; offset to FCB add hl,de ex de,hl ; DE = FCB ld c,(hl) ; get length of directory inc hl ld b,(hl) ld hl,0 ; read directory in (record 0) loop: call r$read ; random read jr nz,error ; file not found if error push hl ; save key regs push de push bc call scan ; scan for file name match and build buffer pop bc ; restore key regs pop de pop hl jr z,error ; TPA full inc hl ; pt to next record dec bc ; count down length of dir ld a,b ; done? or c jr nz,loop ld hl,(buffer) ; point to next byte after last entry ld (hl),0 ; store zero jr done ; A=0 from before the "jr nz,loop" error: or 0ffh ; set 0FFH done: pop bc ; restore regs pop de pop hl or a ; set flags ret ; ; Scan TBUFF for file names ; If memory overflow, A=0 and Zero Flag Set ; If OK, A=0FFH ; scan: ld hl,tbuff ; pt to buffer ld c,4 ; 4 entries possible scan1: ld a,(hl) ; check for active entry or a ; 0=yes jr nz,scanxt push hl inc hl ; pt to name ld de,(file) ; pt to file name ld b,11 ; 11 bytes scanlp: ld a,(de) ; get name and 7fh ; mask msb cp '?' ; match wild jr z,scanlp1 cp (hl) ; compare to dir entry jr nz,scanlp2 scanlp1: inc hl ; pt to next inc de djnz scanlp pop de ; we have a match - pt to entry with DE ld hl,(buffer) ; get address of next buffer entry ld a,(tpaend) ; check for overflow cp h jr c,scanerr ; TPA overflow push de ; save ptr push bc ; save count inc de ; pt to file name ex de,hl ; source in HL ld bc,lentsz ; entry size ldir ld (buffer),de ; save ptr for next copy pop bc ; get count jr scanlp2 ; continue scanerr: xor a ; return with zero for error ret scanlp2: pop hl ; pt to current scanxt: ld de,32 ; pt to next add hl,de dec c ; count down jr nz,scan1 or 0ffh ; set no error ret ; ; Buffers ; file: ds 2 ; pointer to FN.FT buffer: ds 2 ; pointer to memory buffer tpaend: ds 1 ; end page of TPA ludent: ds 2 ; pointer to LUD entry end ; ; LULIB Module: LUINIT ; Author: Richard Conn ; Date: 8 August 85 ; LULIB Version: 1.0 ; LULIB Module Version: 1.0 ; public luinit ; ; LUINIT is used to init a library file for later access. ; On input, DE = ptr to LUD (LU Descriptor) buffer, which contains ; an FCB and other data as follows: ; ; LUD: ; DS 2 ; Length of LU Directory (filled by LUINIT) ; DS 2 ; Index of current entry (filled by LU*) ; DS 2 ; Length of current entry (filled by LU*) ; DS 11 ; Name of current file ; LUD$FCB: ; DS 1 ; Disk (set to current by LUINIT) ; DS 8 ; LU File Name (filled by user) ; DS 3 ; LU File Type (should be LBR, filled by user) ; DS 24 ; dummy (zeroed by LUINIT) ; ; On output, A is return code: ; 0 - No error ; 1 - File not found ; 2 - File empty ; 3 - Library File Format error ; Zero Flag is set accordingly ; ; Side Effect: DMA Address is set to TBUFF ; ; ; Externals ; ext f$open,f$read,initfcb bdose equ 5 .in luddef luinit: push hl ; save regs push de push bc push de ; save LUD ptr ld c,26 ; set DMA ld de,tbuff ; to TBUFF call bdose pop de ; pt to LUD ld hl,ludidx ; fill LUD index and count with zeroes add hl,de ; pt to LUD index ld b,4 ; 4 bytes fill: ld (hl),0 ; store zeroes inc hl dec b jr nz,fill ld hl,ludfcb ; offset to LUD FCB add hl,de ex de,hl ; HL = LUD, DE = FCB call initfcb call f$open ; try to open LU file jr nz,erropen ; error return if file not found call f$read ; read directory block jr nz,errread ; error return if no first block ld a,(tbuff) ; check status (must be 0) or a jr nz,errfmt ld de,tbuff+luidx ; pt to index entry ld a,(de) ; check for 0000H or a jr nz,errfmt inc de ld a,(de) or a jr nz,errfmt inc de ; pt to length ld a,(de) ; get low ld (hl),a ; set LUD length inc de inc hl ld a,(de) ld (hl),a xor a ; no error done: pop bc ; return with no error pop de pop hl or a ; set return flag ret erropen: ld a,1 ; library file not found error jr done errread: ld a,2 ; library file empty error jr done errfmt: ld a,3 ; library file format error jr done end ; ; LULIB Module: LUOPEN ; Author: Richard Conn ; Date: 8 August 85 ; LULIB Version: 1.0 ; LULIB Module Version: 1.0 ; public luopen ; ; LUOPEN opens a file within a library for reading. It locates ; the file and loads the appropriate buffers in the LUD for following ; reads. ; On input, DE = ptr to LUD and HL = ptr to FN.FT ; On output, A is return code: ; 0 OK ; 0FFH File Not Found ; ; Side Effect: DMA Address is set to TBUFF ; ; ; Externals ; ext f$open,r$read bdose equ 5 .in luddef luopen: push hl ; save regs push de push bc push hl ; save key regs push de ld c,26 ; set DMA address ld de,tbuff call bdose pop de ; get key regs pop hl ld (file),hl ; save ptr to file name ld hl,ludfcb ; offset to FCB add hl,de ex de,hl ; DE = FCB push hl ; save ptr to LUD ld c,(hl) ; get length of directory inc hl ld b,(hl) ld hl,0 ; read directory in (record 0) loop: call r$read ; random read jr nz,error ; file not found if error push de ; save key regs push bc call scan ; scan for file name match pop bc ; restore key regs pop de jr z,match inc hl ; pt to next record dec bc ; count down length of dir ld a,b ; done? or c jr nz,loop error: pop hl ; restore LUD ptr or 0ffh ; set 0FFH done: pop bc ; restore regs pop de pop hl or a ; set flags ret ; ; Match - HL pts to entry ; Copy index and length into LUD ; match: ld (ludent),hl ; save ptr to LUD entry ld de,luidx ; offset to index add hl,de ; HL pts to index pop de ; DE pts to LUD inc de ; DE pts to index in LUD inc de ld bc,4 ; copy index and length into LUD ldir ; copy ld hl,(ludent) ; get ptr to LUD entry inc hl ; pt to file name ld bc,11 ; 11 bytes to copy ldir ; copy xor a ; A=0 jr done ; ; Scan TBUFF for file name ; If found, A=0 and HL pts to entry ; If not found, A=0FFH ; scan: push hl ; save regs ld hl,tbuff ; pt to buffer ld c,4 ; 4 entries possible scan1: ld a,(hl) ; check for active entry or a ; 0=yes jr nz,scanxt push hl inc hl ; pt to name ld de,(file) ; pt to file name ld b,11 ; 11 bytes scanlp: ld a,(de) ; get name and 7fh ; mask msb cp '?' ; match wild jr z,scanlp1 cp (hl) ; compare to dir entry jr nz,scanlp2 scanlp1: inc hl ; pt to next inc de djnz scanlp pop hl ; we have a match - pt to entry with HL pop af ; flush old HL xor a ; return with zero for match ret scanlp2: pop hl ; pt to current scanxt: ld de,32 ; pt to next add hl,de dec c ; count down jr nz,scan1 pop hl ; restore HL or 0ffh ; set no match ret ; ; Buffers ; file: ds 2 ; pointer to FN.FT ludent: ds 2 ; pointer to LUD entry end ; ; LULIB Module: LUREAD ; Author: Richard Conn ; Date: 8 August 85 ; LULIB Version: 1.0 ; LULIB Module Version: 1.0 ; public luread ; ; LUREAD reads the next block from the file opened by LUOPEN ; within the current library. ; On input, DE = ptr to LUD ; On output, A is return code ; 0 OK ; 0FFH End of File ; ; Note: DMA Address may be set for reads ; ext r$read .in luddef luread: push hl ; save regs push de push bc ld hl,ludcnt ; pt to count in LUD add hl,de ld c,(hl) ; get length inc hl ld b,(hl) ld a,c ; check for zero or b jr z,eof dec bc ; decrement ld (hl),b ; replace dec hl ld (hl),c dec hl ; pt to index ld b,(hl) ; get index into BC dec hl ld c,(hl) push bc ; save index inc bc ; increment index for next read ld (hl),c ; save new index inc hl ld (hl),b ld de,11+3 ; pt to FCB add hl,de ex de,hl ; DE = FCB pop hl ; HL = index call r$read ; read block jr nz,eof ; any error? if not, A=0 done: pop bc ; restore regs pop de pop hl or a ; set flags ret eof: or 0ffh ; set 0 jr done end