QDS0FILEIOZ80 1S1FILEIOZ80 rS2FILEIOZ80, S3FILEIOZ809 $SACAS1 Z80F SACAS2 Z80SFSACAS3 Z80aSAGO1 Z80qʣSAGO2 Z80ySAIF1 Z80VSAIF2 Z80SALLOC Z80NSARGV Z80TSBBLINE Z80SBDOS Z80ESBGO1 Z80 %4SBGO2 Z80 SBIN Z80CSBIOS Z80LSBIST Z80ݽSBLINE Z80ёSBOUT Z80SCAPIN Z80cSCAPS Z80uSCAPSTR Z80SCATH Z80 SCCOUT Z80% rySCIN Z80.SCLINE Z804 ~xSCLOUT Z80? SCODEND Z80H2wSCOMP Z80O xSCOMPHD Z80Xw@SCONDIN Z80\SCOUT Z80bASCPOUT Z80i `9SCRC Z80rSCRC1 Z80:SSCRC2 Z80PSCRLF Z80SCST Z806SDGO1 Z80 mSDGO2 Z80 SSDIR Z80FSDIR00 Z80HSDIR01 Z80 hSDIR02 Z80 SDIR03 Z80rSDIR04 Z80'7SDIR05 Z8058qSDIR06 Z80mQSDIR07 Z80zASDIR08 Z80 SDIR09 Z80|RSDIR10 Z80 $SDIRBF Z80}/SDIRQ Z80%]SDIRQS Z80; ; ; SYSLIB Module Name: S0FILE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public fi0$open,f0$get,fi0$close public fo0$open,f0$put,fo0$close ; Date: 2 May 85 ; Revised: Al Dunsmuir ; Changes: - Table organization completely changed. ; - Extensive code optimization performed. ; ; Previous Version: 1.0 (16 Jan 84) ; EXTERNAL DECLARATIONS ; EXT FI$OPEN EXT FO$OPEN EXT FI$CLOSE EXT FO$CLOSE EXT F$GET EXT F$PUT ; ; MAIN ROUTINES FOR F0 ; FI0$OPEN: PUSH HL ;Save user REG LD HL,FI0$TBL ;Get FI0 table address. JP FI$OPEN ;Perform function FO0$OPEN: PUSH HL ;Save user REG LD HL,FO0$TBL ;Get FO0 table address. JP FO$OPEN ;Perform function F0$GET: PUSH HL ;Save user REG LD HL,FI0$TBL ;Get FI0 table address. JP F$GET ;Perform function F0$PUT: PUSH HL ;Save user REG LD HL,FO0$TBL ;Get FO0 table address. JP F$PUT ;Perform function FI0$CLOSE: PUSH HL ;Save user REG LD HL,FI0$TBL ;Get FI0 table address. JP FI$CLOSE ;Perform function FO0$CLOSE: PUSH HL ;Save user REG LD HL,FO0$TBL ;Get FO0 table address. JP FO$CLOSE ;Perform function ; Init Table and Buffers for F0 Routines ; FI0$TBL: I0$FLG: DB 0 ;Input file opened flag (0=NO) I0$CNT: DS 1 ;Input char count I0$PTR: DS 2 ;Input char ptr I0$FCB: DS 36 ;Input file FCB I0$BUF: DS 128 ;Input Buffer FO0$TBL: O0$FLG: DB 0 ;Output file opened flag (0=NO) O0$CNT: DS 1 ;Output char count O0$PTR: DS 2 ;Output char ptr O0$FCB: DS 36 ;Output file FCB O0$BUF: DS 128 ;Output Buffer END ; ; SYSLIB Module Name: S1FILE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public fi1$open,f1$get,fi1$close public fo1$open,f1$put,fo1$close ; Date: 2 May 85 ; Revised: Al Dunsmuir ; Changes: - Table organization completely changed. ; - Extensive code optimization performed. ; ; Previous Version: 1.0 (16 Jan 84) ; EXTERNAL DECLARATIONS ; EXT FI$OPEN EXT FO$OPEN EXT FI$CLOSE EXT FO$CLOSE EXT F$GET EXT F$PUT ; ; MAIN ROUTINES FOR F1 ; FI1$OPEN: PUSH HL ;Save user REG LD HL,FI1$TBL ;Get FI1 table address. JP FI$OPEN ;Perform function FO1$OPEN: PUSH HL ;Save user REG LD HL,FO1$TBL ;Get FO1 table address. JP FO$OPEN ;Perform function F1$GET: PUSH HL ;Save user REG LD HL,FI1$TBL ;Get FI1 table address. JP F$GET ;Perform function F1$PUT: PUSH HL ;Save user REG LD HL,FO1$TBL ;Get FO1 table address. JP F$PUT ;Perform function FI1$CLOSE: PUSH HL ;Save user REG LD HL,FI1$TBL ;Get FI1 table address. JP FI$CLOSE ;Perform function FO1$CLOSE: PUSH HL ;Save user REG LD HL,FO1$TBL ;Get FO1 table address. JP FO$CLOSE ;Perform function ; Init Table and Buffers for F1 Routines ; FI1$TBL: I1$FLG: DB 0 ;Input file opened flag (0=NO) I1$CNT: DS 1 ;Input char count I1$PTR: DS 2 ;Input char ptr I1$FCB: DS 36 ;Input file FCB I1$BUF: DS 128 ;Input Buffer FO1$TBL: O1$FLG: DB 0 ;Output file opened flag (0=NO) O1$CNT: DS 1 ;Output char count O1$PTR: DS 2 ;Output char ptr O1$FCB: DS 36 ;Output file FCB O1$BUF: DS 128 ;Output Buffer END ; ; SYSLIB Module Name: S2FILE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public fi2$open,f2$get,fi2$close public fo2$open,f2$put,fo2$close ; Date: 2 May 85 ; Revised: Al Dunsmuir ; Changes: - Table organization completely changed. ; - Extensive code optimization performed. ; ; Previous Version: 1.0 (16 Jan 84) ; EXTERNAL DECLARATIONS ; EXT FI$OPEN EXT FO$OPEN EXT FI$CLOSE EXT FO$CLOSE EXT F$GET EXT F$PUT ; ; MAIN ROUTINES FOR F2 ; FI2$OPEN: PUSH HL ;Save user REG LD HL,FI2$TBL ;Get FI2 table address. JP FI$OPEN ;Perform function FO2$OPEN: PUSH HL ;Save user REG LD HL,FO2$TBL ;Get FO2 table address. JP FO$OPEN ;Perform function F2$GET: PUSH HL ;Save user REG LD HL,FI2$TBL ;Get FI2 table address. JP F$GET ;Perform function F2$PUT: PUSH HL ;Save user REG LD HL,FO2$TBL ;Get FO2 table address. JP F$PUT ;Perform function FI2$CLOSE: PUSH HL ;Save user REG LD HL,FI2$TBL ;Get FI2 table address. JP FI$CLOSE ;Perform function FO2$CLOSE: PUSH HL ;Save user REG LD HL,FO2$TBL ;Get FO2 table address. JP FO$CLOSE ;Perform function ; Init Table and Buffers for F2 Routines ; FI2$TBL: I2$FLG: DB 0 ;Input file opened flag (0=NO) I2$CNT: DS 1 ;Input char count I2$PTR: DS 2 ;Input char ptr I2$FCB: DS 36 ;Input file FCB I2$BUF: DS 128 ;Input Buffer FO2$TBL: O2$FLG: DB 0 ;Output file opened flag (0=NO) O2$CNT: DS 1 ;Output char count O2$PTR: DS 2 ;Output char ptr O2$FCB: DS 36 ;Output file FCB O2$BUF: DS 128 ;Output Buffer END ; ; SYSLIB Module Name: S3FILE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public fi3$open,f3$get,fi3$close public fo3$open,f3$put,fo3$close ; Date: 2 May 85 ; Revised: Al Dunsmuir ; Changes: - Table organization completely changed. ; - Extensive code optimization performed. ; ; Previous Version: 1.0 (16 Jan 84) ; EXTERNAL DECLARATIONS ; EXT FI$OPEN EXT FO$OPEN EXT FI$CLOSE EXT FO$CLOSE EXT F$GET EXT F$PUT ; ; MAIN ROUTINES FOR F3 ; FI3$OPEN: PUSH HL ;Save user REG LD HL,FI3$TBL ;Get FI3 table address. JP FI$OPEN ;Perform function FO3$OPEN: PUSH HL ;Save user REG LD HL,FO3$TBL ;Get FO3 table address. JP FO$OPEN ;Perform function F3$GET: PUSH HL ;Save user REG LD HL,FI3$TBL ;Get FI3 table address. JP F$GET ;Perform function F3$PUT: PUSH HL ;Save user REG LD HL,FO3$TBL ;Get FO3 table address. JP F$PUT ;Perform function FI3$CLOSE: PUSH HL ;Save user REG LD HL,FI3$TBL ;Get FI3 table address. JP FI$CLOSE ;Perform function FO3$CLOSE: PUSH HL ;Save user REG LD HL,FO3$TBL ;Get FO3 table address. JP FO$CLOSE ;Perform function ; Init Table and Buffers for F3 Routines ; FI3$TBL: I3$FLG: DB 0 ;Input file opened flag (0=NO) I3$CNT: DS 1 ;Input char count I3$PTR: DS 2 ;Input char ptr I3$FCB: DS 36 ;Input file FCB I3$BUF: DS 128 ;Input Buffer FO3$TBL: O3$FLG: DB 0 ;Output file opened flag (0=NO) O3$CNT: DS 1 ;Output char count O3$PTR: DS 2 ;Output char ptr O3$FCB: DS 36 ;Output file FCB O3$BUF: DS 128 ;Output Buffer END ; ; SYSLIB Module Name: ACASE1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public acase1 ; ; ACASE1 is a acase1 statement processor. On input, register A contains a ; value to test against: ; ; MVI A,TEST ; test value ; CALL ACASE1 ; DB NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in acase1 ; DB VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DB VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DB 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 ; acase1: ex (sp),hl ; return address in HL push af ; save regs push bc ld b,(hl) ; 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: cp (hl) ; compare jp z,match inc hl ; pt to next inc hl inc hl dec b ; count down 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 ; ; 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 bc ; restore regs pop af ex (sp),hl ; return address on stack, HL restored ret ; ; Storage for default address ; default: ds 2 end ; ; SYSLIB Module Name: ACASE2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public acase2 ; ; ACASE2 is a acase2 statement processor. On input, register A contains a ; value to test against and DE contains the address of the case table: ; ; MVI A,TEST ; test value ; LXI D,TABLE ; case table ; CALL ACASE2 ; ... ; TABLE: ; DB NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in acase2 ; DB VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DB VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DB 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 ; acase2: ex (sp),hl ; return address in HL ld h,d ; HL=DE=case table address ld l,e push af ; save regs push bc ld b,(hl) ; 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: cp (hl) ; compare jp z,match inc hl ; pt to next inc hl inc hl dec b ; count down 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 ; ; 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 bc ; restore regs pop af ex (sp),hl ; return address on stack, HL restored ret ; ; Storage for default address ; default: ds 2 end ; ; SYSLIB Module Name: ACASE3 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public acase3 ; ; ACASE3 is a case statement processor. On input, register A contains a ; value to test against and DE contains the address of the case table. ; Unlike ACASE1 and ACASE2, the return address to ACASE3 is preserved, ; so routines can continue execution by issuing a simple RET, and control ; will resume after the call to ACASE3. ; ; MVI A,TEST ; test value ; LXI D,TABLE ; case table ; CALL ACASE3 ; < instr to return to > ; control resumes here if routines RET ; ... ; TABLE: ; DB NUM$ENT ; number of entries in CASE table ; DW DEFAULT ; address to goto if no match in acase3 ; DB VAL1 ; entry value 1 to test for ; DW ADDR1 ; address to goto if entry 1 matches ; DB VAL2 ; entry value 2 to test for ; DW ADDR2 ; address to goto if entry 2 matches ; ... ; DB 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 ; acase3: push hl ; save HL ld h,d ; HL=DE=case table address ld l,e push af ; save regs push bc ld b,(hl) ; 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: cp (hl) ; compare jp z,match inc hl ; pt to next inc hl inc hl dec b ; count down 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 ; ; Get address in HL and run routine (original return address still on stack) ; goto: ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address pop bc ; restore regs pop af ex (sp),hl ; return address on stack, HL restored ret ; ; Storage for default address ; default: ds 2 end ; ; SYSLIB Module Name: AGOTO1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public agoto1 ; ; AGOTO1 is a computed GOTO. When called, register A = index of following ; address to branch to, as indicated: ; ; MVI A,INDEX ; zero-relative ; CALL AGOTO1 ; DW ADDR0 ; IF A=0 ; DW ADDR1 ; IF A=1 ; DW ADDR2 ; IF A=2 ; ... ; ADDR0: ; COME HERE IF A=0 ; ... ; ADDR1: ; COME HERE IF A=1 ; ... ; ADDR2: ; COME HERE IF A=2 ; ... ; ; No error or range checking is done ; agoto1: ex (sp),hl ; get address of routines, save HL push de ; save regs push af ld d,0 ld e,a ; index in DE ex de,hl ; index in HL, return address in DE add hl,hl ; double index to compute offset 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 end ; ; SYSLIB Module Name: AGOTO2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public agoto2 ; ; AGOTO2 is a computed GOTO. When called, register A = index of following ; jump to branch to, as indicated: ; ; MVI A,INDEX ; zero-relative ; CALL AGOTO2 ; JMP ADDR0 ; IF A=0 ; JMP ADDR1 ; IF A=1 ; JMP ADDR2 ; IF A=2 ; ; IF A=3 ; ... ; ADDR0: ; COME HERE IF A=0 ; ... ; ADDR1: ; COME HERE IF A=1 ; ... ; ADDR2: ; COME HERE IF A=2 ; ... ; ; No error or range checking is done ; agoto2: ex (sp),hl ; get address of routines, save HL push de ; save regs push af push hl ; save return address ld h,0 ld l,a ex de,hl ; index in DE ld hl,0 add hl,de ; HL = index add hl,hl ; HL = index * 2 add hl,de ; HL = index * 3 pop de ; get return address add hl,de ; point to jump in HL pop af ; get regs pop de ex (sp),hl ; restore HL, set address of routine ret end ; ; SYSLIB Module Name: AIF1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public aif1 ; ; AIF1 is an arithmetic IF facility. A key value is passed in the B register ; and a test value is passed in the A register: ; ; MVI B,5 ; key value ; MVI A,TEST ; test value ; CALL AIF1 ; DW ALTB ; go here if A < B ; DW AEQB ; go here if A = B ; DW AGTB ; go here if A > B ; aif1: ex (sp),hl ; get return address push af ; save regs push de cp b ; compare jp c,less jp z,equal ld de,4 ; A > B, so add 4 add hl,de jp less equal: ld de,2 ; A = B, so add 2 add hl,de ; ; A < B, so HL contains the address pointer (no change) ; less: ld a,(hl) ; get low inc hl ld h,(hl) ; get high ld l,a ; HL = address to return to pop de ; restore regs pop af ex (sp),hl ret end ; ; SYSLIB Module Name: AIF2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public aif2 ; ; AIF2 is an arithmetic IF facility. A key value is passed in the B register ; and a test value is passed in the A register: ; ; MVI B,5 ; key value ; MVI A,TEST ; test value ; CALL AIF2 ; JMP ALTB ; go here if A < B ; JMP AEQB ; go here if A = B ; JMP AGTB ; go here if A > B ; aif2: ex (sp),hl ; get return address push af ; save regs push de cp b ; compare jp c,less jp z,equal ld de,6 ; A > B, so add 6 add hl,de jp less equal: ld de,3 ; A = B, so add 3 add hl,de ; ; A < B, so HL contains the return address (no change) ; less: pop de ; restore regs pop af ex (sp),hl ret end ; ; SYSLIB Module Name: SALLOC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public ialloc,alloc ; ; BDOS ENTRY POINT ; BDOSE EQU 5 ; ; SYSLIB FUNCTIONS ; EXT CODEND EXT COMPHD ; ; ALLOC and IALLOC support dynamic memory allocation. IALLOC is ; used to initialize the system, specifying where the first byte of ; the dynamic buffer is and where the last byte of this buffer is. ; The user may explicitly give zero, one, or both of these values, and, ; for those values omitted, IALLOC selects the area just after the ; user program for the beginning of the buffer and the bottom of the CCP ; for the end of the buffer. ALLOC, then, is used to obtain buffers ; from this area. ALLOC is called with the desired space in DE, and it ; returns a pointer to the first byte of the allocated buffer in HL ; with a flag (Z means buffer not allocated due to memory overflow). ; ; ; IALLOC -- Initialize the Allocation Process ; ; On Input, HL = Starting Address of Buffer Area ; DE = End Address of Buffer Area ; A = Flag: ; Bit 0 - if set, set starting address from HL ; if clear, set starting address from CODEND ; Bit 1 - if set, set ending address from DE ; if clear, set ending address from CCP ; IALLOC: PUSH AF ; SAVE REGS PUSH HL PUSH DE PUSH BC LD B,A ; SAVE CODE AND 1 ; SET FROM HL? JP NZ,IAL1 CALL CODEND ; GET STARTING ADDRESS FROM CODEND IAL1: LD (NEXTBYTE),HL ; SET PTR TO NEXT BYTE EX DE,HL ; USE DE NOW LD A,B ; GET CODE AND 2 ; SET FROM HL? JP NZ,IAL2 LD HL,(BDOSE+1) ; GET BDOS BASE ADDRESS FROM ENTRY POINT LD A,H SUB 8 ; PT TO CCP LD H,A LD L,0 ; HL PTS TO BASE OF CCP DEC HL ; ONE BYTE LOWER IAL2: LD (LASTBYTE),HL ; SET PTR TO LAST BYTE POP BC ; RESTORE REGS POP DE POP HL POP AF RET ; ; ALLOC -- Allocate Buffer for user ; On Input, DE = number of bytes requested ; On Output, HL = address of first byte of buffer ; A = Flag: ; A = 0 and Z Flag if CCP Overflow (HL now invalid) ; A = 0FFH and NZ Flag if OK ; ALLOC: PUSH DE LD HL,(NEXTBYTE) ; SET NEXT BYTE ADD HL,DE ; PT TO AFTER LAST BYTE EX DE,HL LD HL,(LASTBYTE) ; OVERFLOW? CALL COMPHD ; OVERFLOW? JP C,ALERR ; ALLOCATION ERROR LD HL,(NEXTBYTE) ; GET PTR TO NEXT BYTE EX DE,HL ; HL PTS TO AFTER LAST BYTE LD (NEXTBYTE),HL ; NEW NEXT BYTE EX DE,HL ; HL CONTAINS DESIRED VALUE LD A,0FFH ; SET FLAG FOR OK OR A POP DE ; RESTORE DE RET ALERR: XOR A ; ERROR CODE POP DE RET ; ; BUFFERS ; NEXTBYTE: DS 2 ; ADDRESS OF NEXT BYTE IN DYNAMIC BUFFER LASTBYTE: DS 2 ; ADDRESS OF LAST BYTE IN DYNAMIC BUFFER END ; ; SYSLIB Module Name: SARGV ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public argv ; ; ARGV is a UNIX-style ARGC/ARGV string parser. It is passed ; a null-terminated string in HL and the address of a token pointer ; table in DE as follows: ; ; LXI H,STRING ; LXI D,ARGV$TABLE ; MVI A,0 ; do not mark token end ; CALL ARGV ; JNZ TOKEN$OVFL ; indicates more tokens than allowed ; ... ; ARGV$TABLE: ; DB MAX$ENT ; max number of entries permitted ; DS 1 ; number of entries stored by ARGV ; DS 2 ; pointer to token 1 ; DS 2 ; pointer to token 2 ; ... ; DS 2 ; pointer to token MAX$ENT ; ; Tokens are delimited by spaces and tabs. ; On input, if A=0, the end of each token is not marked with a null. ; If A<>0, a null is placed after the last byte of each token. ; If all went well, return with A=0 and Zero Flag set. If there ; are possibly more tokens than pointers, return with A=0FFH and NZ. ; argv: push bc ; save regs push de push hl ld c,a ; save mark flag ex de,hl ld b,(hl) ; get max entry count push hl ; save address of max entry count inc hl ; pt to token count inc hl ; pt to first pointer ; ; On each loop, DE = address of next char in string and HL = address of ; next pointer buffer; B = number of pointer buffers remaining and C = ; mark flag (0 = no mark) ; loop: call sksp ; skip spaces and tabs in string pted to by DE or a ; end of string? jp z,done ld (hl),e ; store low inc hl ld (hl),d ; store high inc hl dec b ; count down jp z,loop2 call sknsp ; skip until end of token or a ; done? jp z,done ld a,c ; get mark flag or a ; 0=no mark jp z,loop1 xor a ; mark with null ld (de),a ; store null inc de ; pt to next char loop1: ld a,b ; check count or a jp nz,loop ; continue on loop2: call sknsp ; skip over token call sksp ; any tokens left? or a jp z,done ; none if EOL or 0ffh ; make A = 0FFH to indicate more to come done: pop hl ; get address of max token count push af ; save return flags ld a,(hl) ; get max token count sub b ; subtract counter inc hl ; pt to return count ld (hl),a ; set return count pop af ; get return flag pop hl ; restore regs pop de pop bc ret ; ; Skip over space or tab characters ; sksp: ld a,(de) ; get char and 7fh ; mask inc de ; pt to next cp ' ' ; continue if space jp z,sksp cp 9 ; continue if tab jp z,sksp dec de ; pt to character ret ; ; Skip over non-space and non-tab characters ; sknsp: ld a,(de) ; get char and 7fh ; mask ret z ; done if null cp ' ' ret z ; done if space cp 9 ret z ; done if tab inc de ; pt to next jp sknsp end ; ; SYSLIB Module Name: SBBLIN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bbline ; ; BBLINE -- Buffered BDOS Input Line Editor ; BBLINE provides a very convenient interface to the BDOS for input ; line editor functions. It contains its own internal buffer for storage ; of the input line (200 bytes allocated), and it returns a pointer to ; the first byte of the line upon return. The line stored in this buffer ; is terminated by a binary zero (0). ; To use BBLINE, the user need only call it, with a capitalization flag ; stored in the A Register. If A = 0, BBLINE does not capitalize the input ; line characters; if A <> 0, BBLINE capitalizes the input line characters ; before returning to the caller. ; No error codes are returned by BBLINE. On return, HL points to the ; first byte of the input line and A contains a count of the number of ; characters in that line. ; ; ; EQUATES ; BDOS EQU 5 B$RDLINE EQU 10 ; READ LINE FUNCTION ; ; EXTERNAL DECLARATIONS ; EXT CAPS ; ; MAIN ROUTINE FOR BBLINE ; BBLINE: JP START ; SKIP OVER BUFFER INLINE: DB 200 ; ALLOW 200 BYTES IN BUFFER CCNT: DB 0 ; CHARACTER COUNT LINE: DS 200 ; BUFFER SPACE DB 0 ; TERMINATING ZERO CAPFLG: DS 1 ; CAPITALIZATION FLAG (0=NO CAP) START: PUSH DE ; SAVE DE, BC PUSH BC LD (CAPFLG),A ; SAVE CAPITALIZATION FLAG LD DE,INLINE ; PT TO BUFFER LD C,B$RDLINE ; READ LINE FUNCTION IN BDOS CALL BDOS ; DO READ LINE FUNCTION LD HL,CCNT ; PT TO CHAR COUNT LD A,(HL) ; GET IT INC HL ; PT TO FIRST CHAR ADD A,L ; ADD CHAR COUNT LD L,A LD A,H ADC 0 LD H,A ; HL PTS TO AFTER LAST CHAR LD (HL),0 ; STORE ENDING ZERO LD A,(CAPFLG) ; CAPITALIZE? OR A ; 0=NO JP Z,DONE LD HL,LINE ; MOVE THRU LINE CAPLP: LD A,(HL) ; GET CHAR OR A ; END OF LINE? JP Z,DONE CALL CAPS ; CAPITALIZE CHAR LD (HL),A ; PUT IT BACK INC HL ; PT TO NEXT JP CAPLP DONE: POP BC ; RESTORE REGS POP DE LD HL,LINE ; PT TO FIRST CHAR IN LINE LD A,(CCNT) ; GET CHAR COUNT RET END ; ; SYSLIB Module Name: SBDOS ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bdos ; ; BDOS -- STANDARD ROUTINE FOR CALLING THE CP/M BDOS ; DO NOT AFFECT REGISTERS BC OR DE ; BDOSE EQU 5 ; ENTRY POINT FOR BDOS BDOS: PUSH BC ; SAVE BC PUSH DE ; SAVE DE CALL BDOSE ; MAKE CALL POP DE ; GET DE POP BC ; GET BC RET END ; ; SYSLIB Module Name: BGOTO1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bgoto1 ; ; BGOTO1 is a computed GOTO. When called, register A = index of following ; address to branch to and register B = maximum value allowed, as indicated: ; ; MVI A,INDEX ; zero-relative ; MVI B,2 ; max value allowed ; CALL BGOTO1 ; DW ADDR0 ; IF A=0 ; DW ADDR1 ; IF A=1 ; DW ADDR2 ; IF A=2 ; ; IF A>B ; ... ; ADDR0: ; COME HERE IF A=0 ; ... ; ADDR1: ; COME HERE IF A=1 ; ... ; ADDR2: ; COME HERE IF A=2 ; ... ; ; No error or range checking is done ; bgoto1: ex (sp),hl ; get address of routines, save HL push de ; save regs push af cp b ; test for range error jp c,goto ; OK if A < B jp z,goto ; OK if A = B ld a,b ; set A = error offset (B+1) inc a goto: ld d,0 ld e,a ; index in DE ex de,hl ; index in HL, return address in DE add hl,hl ; double index to compute offset 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 end ; ; SYSLIB Module Name: BGOTO2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bgoto2 ; ; BGOTO2 is a computed GOTO. When called, register A = index of following ; jump to branch to and register B = maximum index value, as indicated: ; ; MVI A,INDEX ; zero-relative ; MVI B,2 ; maximum index value ; CALL BGOTO2 ; JMP ADDR0 ; IF A=0 ; JMP ADDR1 ; IF A=1 ; JMP ADDR2 ; IF A=2 ; ; IF A>B ; ... ; ADDR0: ; COME HERE IF A=0 ; ... ; ADDR1: ; COME HERE IF A=1 ; ... ; ADDR2: ; COME HERE IF A=2 ; ... ; ; No error or range checking is done ; bgoto2: ex (sp),hl ; get address of routines, save HL push de ; save regs push af push hl ; save return address cp b ; test for range error jp c,goto ; OK if A < B jp z,goto ; OK if A = B ld a,b ; set A = error offset (B+1) inc a goto: ld h,0 ld l,a ex de,hl ; index in DE ld hl,0 add hl,de ; HL = index add hl,hl ; HL = index * 2 add hl,de ; HL = index * 3 pop de ; get return address add hl,de ; point to jump in HL pop af ; get regs pop de ex (sp),hl ; restore HL, set address of routine ret end ; ; SYSLIB Module Name: BIN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bin BDOS EQU 5 ; ; GET CHAR FROM USER IN A VIA BDOS CALL ; AFFECT ONLY PSW ; BIN: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD C,1 ; GET CHAR CALL BDOS POP BC ; RESTORE REGS POP DE POP HL RET END ; ; SYSLIB Module Name: SBIOS ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bios ; ; SBIOS -- Direct BIOS I/O Routine ; This routine provides the user with a direct interface into the ; CP/M BIOS. It is called with the A Reg containing the index offset into ; the BIOS JMP table. No registers are preserved by this routine. The ; contents of HL, DE, and BC are passed to the BIOS unchanged. ; ; The following table summarizes the BIOS JMP Table Entries -- ; ; Offset Function ; 0 Cold Start ; 1 Warm Start ; 2 Console Status; Returns A=0FFH if char ready, A=0 if not ; 3 Console Input; Returns char in A ; 4 Console Output; Char passed in C ; 5 List Output; Char passed in C ; 6 Punch Output; Char passed in C ; 7 Reader Input; Returns char in A ; ; 8 Home Disk Head (Return Version Number); Returns Version Number ; in HL ; 9 Select Disk; Disk Number (A=0, etc) passed in C ; 10 Set Track Number; Track Number passed in C ; 11 Set Sector Number; Sector Number passed in C ; 12 Set DMA Address; DMA address passed in BC ; 13 Read Disk; Returns A=0 if OK, A=1 if error ; 14 Write Disk; Returns A=0 if OK, A=1 if error ; ; 15 List Status; Returns A=0FFH if ready to output, A=0 if not ; 16 Sector Translation; Logical-to-Physical Sector Translation; ; Logical Sector Number passed in BC and Translate ; Table Address passed in DE; Returns Physical Sector ; Number in HL ; ; ; EQUATES ; WBADR EQU 1 ; WARM BOOT ADDRESS BIOS: PUSH DE ; SAVE DE LD (HLBUF),HL ; SAVE HL LD HL,(WBADR) ; GET ADDRESS OF WARM BOOT DEC HL ; BACK UP TO POINT TO COLD BOOT DEC HL DEC HL LD DE,3 ; PT TO ENTRY BIOSL: OR A ; DONE? JP Z,BIOSD ADD HL,DE ; PT TO NEXT DEC A ; COUNT DOWN JP BIOSL ; ; HL NOW POINTS TO BIOS JMP TO BE PERFORMED ; BIOSD: POP DE ; GET DE PUSH HL ; PLACE ROUTINE ADDRESS ON STACK LD HL,(HLBUF) ; RESTORE HL RET ; "CALL" INTO BIOS (RET ADR IS CALLER OF BIOS) HLBUF: DS 2 ; BUFFER IN WHICH TO SAVE HL END ; ; SYSLIB Module Name: BIST ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bist BDOS EQU 5 ; ; GET CON CHAR STATUS IN A VIA BDOS CALL ; AFFECT ONLY PSW ; BIST: PUSH HL ; SAVE REGS PUSH DE PUSH BC LD C,11 ; GET STATUS CALL BDOS OR A ; SET FLAGS POP BC ; RESTORE REGS POP DE POP HL RET END ; ; SYSLIB Module Name: SBLINE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bline ; ; BLINE -- BDOS Input Line Editor ; BLINE provides a very convenient interface to the BDOS for input ; line editor functions. It uses a buffer supplied by the user for storage ; of the input line, and it returns a pointer to the first byte of the line ; upon return. The line stored in this buffer is terminated by a binary zero. ; To use BLINE, the user need only call it, with a capitalization flag ; stored in the A Register and HL pointing to the first byte of the user- ; supplied buffer which will contain the line. This buffer is structured ; as follows: ; 1st Byte - Size (filled in by user) ; 2nd Byte - Char count (filled in by BLINE) ; 3rd to nth Byte - Characters of Line (filled in by BLINE) ; n+1st Byte - Terminating Zero ; The number of bytes allocated to the entire buffer is SIZE+3, where SIZE ; is the buffer size as supplied by the user. ; If A = 0, BLINE does not capitalize the input line characters; ; if A <> 0, BLINE capitalizes the input line characters ; before returning to the caller. ; No error codes are returned by BLINE. On return, HL points to the ; first byte of the input line and A contains a count of the number of ; characters in that line. ; ; ; EQUATES ; BDOS EQU 5 B$RDLINE EQU 10 ; READ LINE FUNCTION ; ; EXTERNAL DECLARATIONS ; EXT CAPS ; ; MAIN ROUTINE FOR BLINE ; BLINE: PUSH DE ; SAVE DE, BC PUSH BC LD (CAPFLG),A ; SAVE CAPITALIZATION FLAG LD (LINEST),HL ; SAVE ADDRESS OF FIRST BYTE EX DE,HL ; DE PTS TO BUFFER LD C,B$RDLINE ; READ LINE FUNCTION IN BDOS CALL BDOS ; DO READ LINE FUNCTION LD HL,(LINEST) ; PT TO RETURNED CHAR COUNT INC HL LD A,(HL) ; GET IT INC HL ; PT TO FIRST CHAR PUSH HL ; SAVE PTR TO FIRST CHAR ADD A,L ; ADD CHAR COUNT LD L,A LD A,H ADC 0 LD H,A ; HL PTS TO AFTER LAST CHAR LD (HL),0 ; STORE ENDING ZERO POP HL ; GET PTR TO FIRST CHAR LD A,(CAPFLG) ; CAPITALIZE? OR A ; 0=NO JP Z,DONE PUSH HL ; SAVE PTR TO FIRST CHAR CAPLP: LD A,(HL) ; GET CHAR OR A ; END OF LINE? JP Z,CAPDN CALL CAPS ; CAPITALIZE CHAR LD (HL),A ; PUT IT BACK INC HL ; PT TO NEXT JP CAPLP CAPDN: POP HL ; GET PTR TO FIRST CHAR DONE: POP BC ; RESTORE REGS POP DE DEC HL ; PT TO CHAR COUNT LD A,(HL) ; GET CHAR COUNT INC HL ; PT TO FIRST CHAR OF LINE RET LINEST: DW 0 ; ADDRESS OF START OF LINE BUFFER CAPFLG: DB 0 ; CAPITALIZATION FLAG (0=NO CAP) END ; ; SYSLIB Module Name: BOUT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public bout BDOS EQU 5 ; ; OUTPUT CHAR IN A VIA BDOS CALL ; AFFECT NO REGS ; BOUT: PUSH HL ; SAVE REGS PUSH DE PUSH BC PUSH AF LD C,2 ; PUT CHAR LD E,A ; CHAR IN E CALL BDOS POP AF ; RESTORE REGS POP BC POP DE POP HL RET END ; ; SYSLIB Module Name: SCAPIN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public capin,capine EXT CIN,COUT,CAPS ; ; INPUT CHAR FROM USER, CAPITALIZE IT, AND ECHO IT BACK ; CAPINE: CALL CAPIN ; GET CHAR JP COUT ; ; INPUT CHAR FROM USER AND CAPITALIZE IT ; CAPIN: CALL CIN ; GET CHAR JP CAPS ; CAPITALIZE END ; ; SYSLIB Module Name: SCAPS ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public caps ; ; CAPS -- Capitalize ASCII Character in A ; CAPS: AND 7FH ; MASK OUT MSB CP 61H ; LESS THAN SMALL LETTER A? RET C CP 7AH+1 ; BETWEEN SMALL A AND SMALL Z? RET NC AND 5FH ; REMOVE BIT 5 TO CAPITALIZE (0X0X XXXX) RET END ; ; SYSLIB Module Name: SCAPST ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public capstr ; ; CAPSTR -- Capitalize String Pted to by HL ; This routine simply capitalizes the -terminated string ; pointed to by HL. No Registers are affected. ; EXT CAPS CAPSTR: PUSH AF ; SAVE REGS PUSH HL CAPSLP: LD A,(HL) ; GET CHAR OR A ; DONE? JP Z,CAPSDN CALL CAPS ; CAPITALIZE IT LD (HL),A ; PUT IT BACK INC HL ; PT TO NEXT JP CAPSLP CAPSDN: POP HL ; GET REGS POP AF RET END ; ; SYSLIB Module Name: SCATH ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public cath ; CATH -- CONVERT ASCII TO HEX ; This routine converts the ASCII Hexadecimal char (0-9,A-F) ; in A to the corresponding binary value in A. ; ; On return, A=hex value if no error; if error, A=20H (). ; CATH: SUB '0' ; CONVERT 0-9 JP C,ERROR ; INVALID CHAR CP 10 ; 0-9? RET C SUB 7 ; CONVERT A-F CP 10 JP C,ERROR CP 16 ; A-F? JP NC,ERROR RET ERROR: LD A,' ' ; ERROR CHAR RET END ; ; SYSLIB Module Name: SCCOUT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public ccout ; ; CCOUT -- ; CONSOLE OUTPUT ROUTINE WITH CONTROL CHARACTER PROCESSING ; OUTPUT CHAR IN REG A ON CON: ; AFFECT NO REGISTERS OR FLAGS ; EXT COUT CCOUT: CP ' ' ; CHECK FOR LESS THAN JP NC,COUT ; PROCESS NORMALLY IF EQUAL OR GREATER ; ; TRAP OUT , , , , ; CP NULL ; JP Z,COUT CP BEL ; JP Z,COUT CP BS ; JP Z,COUT CP LF ; JP Z,COUT CP CR ; JP Z,COUT ; ; PRINT AS CTRL-CHAR ; PUSH AF ; SAVE A PUSH AF LD A,'^' ; PRINT UP ARROW CALL COUT POP AF ; GET CHAR ADD 40H ; CONVERT TO CHAR CALL COUT POP AF ; RESTORE A 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: SCIN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public cin ; ; CIN -- ; CONSOLE INPUT ROUTINE ; INPUT CHARACTER FROM CON: INTO REG A ; AFFECT ONLY REG A AND 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 CIN: PUTRG ; SAVE REGISTERS LD HL,(JTABL) ; GET ADDRESS OF JUMP TABLE LD L,CI$OFF ; CONSOLE INPUT ADR LD DE,CRET1 ; SET UP RET ADR PUSH DE ; ... ON STACK JP (HL) CRET1: GETRG ; RESTORE REGISTERS RET BOOT EQU 0 ; CP/M BOOT ADDRESS JTABL EQU BOOT+1 ; CP/M JUMP TABLE ADDRESS CI$OFF EQU 9 ; CONSOLE INPUT OFFSET END ; ; SYSLIB Module Name: SCLINE ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public cline ; ; CLINE -- Save the command line whose character count is pointed ; to by HL away in an internal buffer as a string. The line may be up to ; 255 characters long and will be truncated if it is longer. The string ; will be terminated by a as per the SYSLIB concept of strings. ; ; Input Parameters: HL = Address of Command Line Buffer ; Output Parameters: HL = Address of Command Line String ; A = 0 and Zero Flag Set (Z) if Buffer Truncated ; A <> 0 and Zero Flag Clear (NZ) if Buffer OK ; Registers Affected: HL ; BSIZE EQU 255 ; SIZE OF BUFFER CLINE: PUSH DE ; SAVE REGS PUSH BC LD DE,INBUF ; ADDRESS OF BUFFER LD C,BSIZE ; BUFFER SIZE LD B,(HL) ; GET CHAR COUNT IN B INC HL ; PT TO FIRST CHAR CLINE1: LD A,B ; CHECK FOR DONE OR A ; 0=DONE JP Z,CLINE2 DEC B ; COUNT DOWN LD A,(HL) ; GET BYTE LD (DE),A ; PUT BYTE INC HL ; PT TO NEXT INC DE DEC C ; COUNT DOWN BUFFER LIMIT JP NZ,CLINE1 CLINE2: XOR A ; A=0 LD (DE),A ; PUT ENDING ZERO LD A,C ; GET REMAINING CHAR COUNT POP BC ; RESTORE REGS POP DE LD HL,INBUF ; PT TO BUFFER OR A ; SET FLAGS RET INBUF: DS BSIZE ; SIZE OF BUFFER DS 1 ; + 1 FOR ENDING ZERO END ; ; SYSLIB Module Name: SCLOUT ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public clout ; ; CLOUT -- ; LIST OUTPUT ROUTINE WITH CONTROL CHARACTER PROCESSING ; OUTPUT CHAR IN REG A ON LST: ; AFFECT NO REGISTERS OR FLAGS ; EXT LOUT CLOUT: CP ' ' ; CHECK FOR LESS THAN JP NC,LOUT ; PROCESS NORMALLY IF EQUAL OR GREATER ; ; TRAP OUT , , , , ; CP NULL ; JP Z,LOUT CP BEL ; JP Z,LOUT CP BS ; JP Z,LOUT CP LF ; JP Z,LOUT CP CR ; JP Z,LOUT ; ; PRINT AS CTRL-CHAR ; PUSH AF ; SAVE A PUSH AF LD A,'^' ; PRINT UP ARROW CALL LOUT POP AF ; GET CHAR ADD 40H ; CONVERT TO CHAR CALL LOUT POP AF ; RESTORE A 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: SCODEN ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.2 public codend,$memry ; ; This module returns the address of the last element of code in ; in the user's object program. This address should correspond to ; the first available block for scratch buffer area. ; ; Thanks to Ron Fowler for pointing out the availability of the ; $MEMRY variable. This value is filled in by LINK-80 when the ; external references are resolved. ; ; Input Parameters: None ; Output Parameters: HL = Address of next page ; CODEND: PUSH AF LD HL,($MEMRY) ; GET ADDRESS OF NEXT BYTE LD A,L ; DON'T WASTE SPACE IF AT 256-BYTE OR A ; BLOCK BOUNDARY JP Z,CODE1 INC H ; NEXT BLOCK LD L,0 CODE1: POP AF RET $MEMRY: DS 2 ; FILLED IN BY L80 END ; ; SYSLIB Module Name: SCOMP ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public compb,compbc ; ; SCOMP -- ; Vector Compare Routine. Compare vector pointed to by HL with that ; pointed to by DE. Vector is B bytes long for COMPB and BC bytes long for ; COMPBC. On exit, Zero Flag Set indicates match, Carry Flag Set indicates ; that vector pointed to by HL is binarily less than vector pointed to by DE. ; PSW is affected. HL, DE, BC are not affected. ; COMPB: PUSH BC ; SAVE BC LD C,B ; SET COUNT IN C LD B,0 CALL COMPBC ; USE BC FOR COUNT POP BC ; RESTORE BC RET COMPBC: PUSH HL ; SAVE REGISTERS PUSH DE PUSH BC ; COMPARE LOOP COMP: LD A,(DE) ; GET BYTE PTED TO BY DE CP (HL) ; COMPARE TO BYTE PTED TO BY HL JP NZ,COMPDN ; DONE IF NO MATCH INC HL ; PT TO NEXT INC DE DEC BC ; COUNT DOWN LD A,B ; DONE? OR C JP NZ,COMP ; DONE WITH COMPARE; Z=>MATCH, C=>(HL)>(DE) COMPDN: JP Z,CMPDN ; DON'T COMPLEMENT CARRY IF ZERO SET CCF ; C=>(HL)<(DE) CMPDN: POP BC ; RESTORE REGISTERS POP DE POP HL RET END ; ; SYSLIB Module Name: SCOMPH ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public comphd ; ; SCOMPHD -- ; Compare HL with DE. On return, Zero means HL=DE; Carry means ; HL JP NC,POUT ; PROCESS NORMALLY IF EQUAL OR GREATER ; ; TRAP OUT , , , , ; CP NULL ; JP Z,POUT CP BEL ; JP Z,POUT CP BS ; JP Z,POUT CP LF ; JP Z,POUT CP CR ; JP Z,POUT ; ; PRINT AS CTRL-CHAR ; PUSH AF ; SAVE A PUSH AF LD A,'^' ; PRINT UP ARROW CALL POUT POP AF ; GET CHAR ADD 40H ; CONVERT TO CHAR CALL POUT POP AF ; RESTORE A 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: SCRC ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public crcclr,crcdone,crcupd ; ; These subroutines will compute and check a true 16-bit ; Cyclic Redundancy Code for a message of arbitrary length. ; ; The use of this scheme will guarantee detection of all ; single and double bit errors, all errors with an odd ; number of error bits, all burst errors of length 16 or ; less, 99.9969% of all 17-bit error bursts, and 99.9984% ; of all possible longer error bursts. (Ref: Computer ; Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) ; ; These routines are typically used as follows: ; CRC$MAKE: ; ROUTINE TO ESTABLISH CRC VALUE ; CALL CRCCLR ; CLEAR CRC ; ; ACQUIRE VALUES ; CALL CRCDONE ; GET VALUE ; SHLD CRCVAL ; SAVE VALUE ; CRC$CHECK: ; ROUTINE TO CHECK CRC VALUE ; CALL CRCCLR ; CLEAR CRC ; ; ACQUIRE VALUES ; CALL CRCDONE ; DONE ; XCHG ; VALUE IN DE ; LHLD CRCVAL ; FROM BEFORE ; CALL COMPHD ; COMPARE HL TO DE (SYSLIB ROUTINE) ; JNZ ERROR ; ERROR IF NOT SAME ; ; ; CRCCLR - Clear the CRC accumulator ; This routine must be called at the start of each byte stream. ; ; Input Parameters: None ; ; Output Parameters: None ; CRCCLR: PUSH HL LD HL,0 ;SET CRC TO ZERO LD (CRCVAL),HL POP HL RET ; ; BUFFER FOR CRC VALUE ; CRCVAL: DS 2 ; ; CRCUPD - Update the CRC accumulator ; This routine must be called once for each byte in the ; byte stream for which the CRC is being calculated. ; ; Input Parameters: A = byte to be included in CRC ; ; Output Parameters: None ; CRCUPD: PUSH AF ;SAVE ALL REGS PUSH BC PUSH HL LD B,8 ;ROTATE 8 BITS LD C,A ;BYTE IN C LD HL,(CRCVAL) ;HL=OLD CRC VALUE UPDLOOP: LD A,C ;ROTATE HLC AS A 24-BIT ACC LEFT 1 BIT RLCA LD C,A LD A,L RLA LD L,A LD A,H RLA LD H,A JP NC,SKIPIT LD A,H ; The generator is X^16 + X^12 + X^5 + 1 XOR 10H ; as recommended by CCITT. LD H,A ; An alternate generator which is often LD A,L ; used in synchronous transmission protocols XOR 21H ; is X^16 + X^15 + X^2 + 1. This may be LD L,A ; used by substituting XOR 80H for XOR 10H SKIPIT: ; and XOR 05H for XOR 21H in the adjacent code. DEC B ;COUNT DOWN 8 BITS JP NZ,UPDLOOP LD (CRCVAL),HL ;SAVE NEW CRC VALUE POP HL ;RESTORE ALL POP BC POP AF RET ; ; CRCDONE - Complete the CRC calculation ; This routine is called after the last byte of the byte stream ; has passed thru CRCUPD, and it returns the calculated ; CRC bytes, which must be transmitted as the final ; two bytes of the message (first H, then L). ; ; Input Parameters: None ; ; Output Parameters: HL = calculated CRC bytes ; CRCDONE: PUSH AF ;SAVE A XOR A ;SEND OUT 2 ZEROES CALL CRCUPD CALL CRCUPD LD HL,(CRCVAL) ;RETURN CRC VALUE IN HL POP AF RET END ; ; SYSLIB Module Name: SCRC1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public crc1clr,crc1done,crc1upd ; ; These subroutines will compute and check a true 16-bit ; Cyclic Redundancy Code for a message of arbitrary length. ; ; The use of this scheme will guarantee detection of all ; single and double bit errors, all errors with an odd ; number of error bits, all burst errors of length 16 or ; less, 99.9969% of all 17-bit error bursts, and 99.9984% ; of all possible longer error bursts. (Ref: Computer ; Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) ; ; These routines are typically used as follows: ; CRC1$MAKE: ; ROUTINE TO ESTABLISH CRC VALUE ; CALL CRC1CLR ; CLEAR CRC ; ; ACQUIRE VALUES ; CALL CRC1DONE ; GET VALUE ; SHLD CRC1VAL ; SAVE VALUE ; CRC1$CHECK: ; ROUTINE TO CHECK CRC VALUE ; CALL CRC1CLR ; CLEAR CRC1 ; ; ACQUIRE VALUES ; CALL CRC1DONE ; NOW DONE ; XCHG ; VALUE IN DE ; LHLD CRC1VAL ; FROM BEFORE ; CALL COMPHD ; COMPARE HL TO DE (SYSLIB ROUTINE) ; JNZ ERROR ; ERROR IF NOT EQUAL ; ; ; CRC1CLR - Clear the CRC accumulator ; This routine must be called at the start of each byte stream. ; ; Input Parameters: None ; ; Output Parameters: None ; CRC1CLR: PUSH HL LD HL,0 ;SET CRC TO ZERO LD (CRCVAL),HL POP HL RET ; ; BUFFER FOR CRC VALUE ; CRCVAL: DS 2 ; ; CRC1UPD - Update the CRC accumulator ; This routine must be called once for each byte in the ; byte stream for which the CRC is being calculated. ; ; Input Parameters: A = byte to be included in CRC ; ; Output Parameters: None ; CRC1UPD: PUSH AF ;SAVE ALL REGS PUSH BC PUSH HL LD B,8 ;ROTATE 8 BITS LD C,A ;BYTE IN C LD HL,(CRCVAL) ;HL=OLD CRC VALUE UPDLOOP: LD A,C ;ROTATE HLC AS A 24-BIT ACC LEFT 1 BIT RLCA LD C,A LD A,L RLA LD L,A LD A,H RLA LD H,A JP NC,SKIPIT LD A,H ; The generator is X^16 + X^15 + X^2 + 1 XOR 80H ; as recommended by CCITT. LD H,A ; An alternate generator which is often LD A,L ; used in synchronous transmission protocols XOR 05H ; is X^16 + X^12 + X^5 + 1. This may be LD L,A ; used by substituting XOR 10H for XOR 80H SKIPIT: ; and XOR 21H for XOR 05H in the adjacent code. DEC B ;COUNT DOWN 8 BITS JP NZ,UPDLOOP LD (CRCVAL),HL ;SAVE NEW CRC VALUE POP HL ;RESTORE ALL POP BC POP AF RET ; ; CRC1DONE - Complete the CRC calculation ; This routine is called after the last byte of the byte stream ; has passed thru CRC1UPD, and it returns the calculated ; CRC bytes, which must be transmitted as the final ; two bytes of the message (first H, then L). ; ; Input Parameters: None ; ; Output Parameters: HL = calculated CRC bytes ; CRC1DONE: PUSH AF ;SAVE A XOR A ;SEND OUT 2 ZEROES CALL CRC1UPD CALL CRC1UPD LD HL,(CRCVAL) ;RETURN CRC VALUE IN HL POP AF RET END ; ; SYSLIB Module Name: SCRC2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public crc2clr,crc2done,crc2upd ; ; These subroutines will compute and check a true 16-bit ; Cyclic Redundancy Code for a message of arbitrary length. ; ; The use of this scheme will guarantee detection of all ; single and double bit errors, all errors with an odd ; number of error bits, all burst errors of length 16 or ; less, 99.9969% of all 17-bit error bursts, and 99.9984% ; of all possible longer error bursts. (Ref: Computer ; Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981) ; ; These routines are typically used as follows: ; CRC$MAKE: ; ROUTINE TO ESTABLISH CRC VALUE ; CALL CRC2CLR ; CLEAR CRC ; ; ACQUIRE VALUES ; CALL CRC2DONE ; GET VALUE ; SHLD CRCVAL ; SAVE VALUE ; CRC$CHECK: ; ROUTINE TO CHECK CRC VALUE ; CALL CRC2CLR ; CLEAR CRC ; ; ACQUIRE VALUES ; CALL CRC2DONE ; NOW DONE ; XCHG ; DE=RETURNED CRC ; LHLD CRCVAL ; FROM BEFORE ; CALL COMPHD ; COMPARE HL TO DE FOR EQUALITY ; JNZ ERROR ; ERROR IF NOT EQUAL ; ; ; CRC2CLR - Clear the CRC accumulator ; This routine must be called at the start of each byte stream. ; ; Input Parameters: None ; ; Output Parameters: None ; CRC2CLR: PUSH HL LD HL,0 ;SET CRC TO ZERO LD (CRCVAL),HL POP HL RET ; ; BUFFER FOR CRC VALUE ; CRCVAL: DS 2 ; ; CRC2UPD - Update the CRC accumulator ; This routine must be called once for each byte in the ; byte stream for which the CRC is being calculated. ; ; Input Parameters: A = byte to be included in CRC ; ; Output Parameters: None ; ; Adapted from Keith Petersen's CRCK 4.2 program. ; Routine Originally By Fred Gutman. ; From 'EDN' magazine, June 5, 1979 issue, page 84. ; CRC2UPD: PUSH HL ;SAVE HL PUSH BC ;SAVE BC PUSH AF ;SAVE BYTE TO UPDATE LD B,A ;SAVE BYTE IN B LD HL,(CRCVAL) ;GET REMAINDER LD A,H AND 128 ;Q-BIT MASK PUSH AF ;SAVE STATUS ADD HL,HL ;2 X R(X) LD A,B ;GET BYTE ADD A,L LD L,A POP AF JP Z,CRCU1 ;IF Q-BIT IS ZERO ; LD A,H XOR 0A0H ;MS HALF OF GEN. POLY LD H,A LD A,L XOR 97H ;LS HALF OF GEN. POLY LD L,A ; CRCU1: LD (CRCVAL),HL ;SAVE RESULT POP AF ;RESTORE REGS POP BC POP HL RET ; ; CRC2DONE - Complete the CRC calculation ; This routine is called after the last byte of the byte stream ; has passed thru CRCUPD, and it returns the calculated ; CRC bytes, which must be transmitted as the final ; two bytes of the message (first H, then L). ; ; Input Parameters: None ; ; Output Parameters: HL = calculated CRC bytes ; CRC2DONE: LD HL,(CRCVAL) ;RETURN CRC VALUE IN HL RET END ; ; SYSLIB Module Name: SCRLF ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public crlf ; ; CRLF -- ; PRINT AND ON CON: ; AFFECT NO REGS ; EXT COUT CRLF: PUSH AF ; SAVE REG A AND FLAGS LD A,CR ; PRINT CALL COUT LD A,LF ; PRINT CALL COUT 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: SCST ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public cst ; ; CST -- ; CONSOLE STATUS ROUTINE ; INPUT STATUS OF CON: IN REG A ; RDA IF 0, NOT RDA IF 1 ; 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 CST: PUTRG ; SAVE REGISTERS LD HL,(JTABL) ; GET ADDRESS OF JUMP TABLE LD L,CS$OFF ; CONSOLE STATUS ADR CST1: LD DE,CST1R ; SET UP RET ADR PUSH DE ; ... ON STACK JP (HL) ; RUN ROUTINE CST1R: CPL ; FLIP FLAGS AND 1 ; SET FLAGS -- 0 MEANS RDA GETRG ; RESTORE REGISTERS RET BOOT EQU 0 ; CP/M BOOT ADDRESS JTABL EQU BOOT+1 ; CP/M JUMP TABLE ADDRESS CS$OFF EQU 6 ; CONSOLE STATUS OFFSET END ; ; SYSLIB Module Name: DGOTO1 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public dgoto1 ; ; DGOTO1 is a computed GOTO. When called, register pair HL = index of ; following address to branch to and register pair DE = maximum value ; allowed, as indicated: ; ; LXI H,INDEX ; zero-relative ; LXI D,2 ; max value allowed ; CALL DGOTO1 ; DW ADDR0 ; IF HL=0 ; DW ADDR1 ; IF HL=1 ; DW ADDR2 ; IF HL=2 ; ; IF HL > DE ; ... ; ADDR0: ; COME HERE IF HL=0 ; ... ; ADDR1: ; COME HERE IF HL=1 ; ... ; ADDR2: ; COME HERE IF HL=2 ; ... ; dgoto1: ld (hlsave),hl ; save HL push af ; save regs push de ld a,d ; check for range error cp h jp c,rangerr ; H > D, so set max jp nz,goto ld a,e ; check for range error cp l jp nc,goto ; E >= L, H = D rangerr: ex de,hl ; HL = DE = return index inc hl ; return index + 1 for error return goto: ld (index),hl ; save index pop de ; get regs pop af pop hl ; get return address push de ; save regs push af ex de,hl ; return address in DE ld hl,(index) ; 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 push hl ; set address of routine ld hl,(hlsave) ; restore HL ret ; ; Save buffers ; hlsave: ds 2 ; original HL index: ds 2 ; index value end ; ; SYSLIB Module Name: DGOTO2 ; Author: Richard Conn ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.1 public dgoto2 ; ; DGOTO2 is a computed GOTO. When called, register pair HL = index of ; following address to branch to and register pair DE = maximum value ; allowed, as indicated: ; ; LXI H,INDEX ; zero-relative ; LXI D,2 ; max value allowed ; CALL DGOTO2 ; JMP ADDR0 ; IF HL=0 ; JMP ADDR1 ; IF HL=1 ; JMP ADDR2 ; IF HL=2 ; ; IF HL > DE ; ... ; ADDR0: ; COME HERE IF HL=0 ; ... ; ADDR1: ; COME HERE IF HL=1 ; ... ; ADDR2: ; COME HERE IF HL=2 ; ... ; dgoto2: ld (hlsave),hl ; save HL push af ; save regs push de ld a,d ; check for range error cp h jp c,rangerr ; H > D, so set max jp nz,goto ld a,e ; check for range error cp l jp nc,goto ; E >= L, H = D rangerr: ex de,hl ; HL = DE = return index inc hl ; return index + 1 for error return goto: ld (index),hl ; save index pop de ; restore regs pop af pop hl ; get return address push de ; save regs push af push hl ; save return address ld hl,(index) ; 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 push hl ; set address of routine ld hl,(hlsave) ; restore HL ret ; ; Save buffer ; hlsave: ds 2 ; original HL index: ds 2 ; index entry end ; ; SYSLIB Module Name: SDIR ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dirf MACLIB SDIRHDR.LIB EXT DBUFFER,DIRLOAD,DIRSEL,DIRPACK,DIRALPHA ;* ;* GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITHOUT SIZING INFORMATION ;* THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL. ON EXIT, ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER. ;* THE DIRECTORY BUFFER GENERATED BY DIRF CONTAINS ENTRIES WHICH MAY NOT ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE. THE ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE. THE BASIC TRADEOFF BETWEEN ;* THE TWO ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS IS NOTICABLE ;* IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED. ;* ;* INPUT PARAMETERS: ;* HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG: ;* Bit 7 - Select Non-Sys, Bit 6 - Select Sys ;* Bit 5 - Select All Users, Bits 4-0 - User Number ;* OUTPUT PARAMETERS: ;* HL PTS TO FIRST FILE IN BUFFER ;* BC = NUMBER OF FILES ;* A=0 and Z Flag Set if TPA Overflow ;* DE UNCHANGED ;* DIRF: PUSH DE ; SAVE PTR TO FCB LD (SELFLG),A ; SAVE SELECT FLAG FOR DIRSEL CALL DBUFFER ; GET PTRS CALL DIRLOAD ; LOAD DIRECTORY WITHOUT SIZING INFORMATION (FAST LOAD) POP DE ; GET PTR TO FCB RET Z ; ABORT IF TPA OVERFLOW PUSH AF ; SAVE FLAG TO INDICATE NO TPA OVERFLOW LD A,(SELFLG) ; GET SELECT FLAG CALL DIRSEL ; SELECT FILES CALL DIRPACK ; PACK DIRECTORY XOR A ; SORT FLAG (FN AND FT) CALL DIRALPHA ; ALPHABETIZE POP AF ; GET PSW (TPA OVERFLOW FLAG) RET END ; ; SYSLIB Module Name: SDIR00 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dirfs MACLIB SDIRHDR.LIB EXT DBUFFER,DIRSLOAD,DIRSEL,DIRPACK,DIRALPHA ;* ;* GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITH SIZING INFORMATION ;* THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL. ON EXIT, ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER. ;* THE DIRECTORY BUFFER GENERATED BY DIRFS CONTAINS ENTRIES WHICH MAY ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE. THE ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE. THE BASIC TRADEOFF BETWEEN ;* THE DIRF AND DIRFS ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS ;* IS NOTICABLE IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED. ;* ;* INPUT PARAMETERS: ;* HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG: ;* Bit 7 - Select Non-Sys, Bit 6 - Select Sys ;* Bit 5 - Select All Users, Bits 4-0 - User Number ;* OUTPUT PARAMETERS: ;* HL PTS TO FIRST FILE IN BUFFER ;* BC = NUMBER OF FILES ;* A=0 and Z Flag Set if TPA Overflow ;* DE UNCHANGED ;* DIRFS: PUSH DE ; SAVE PTR TO FCB LD (SELFLG),A ; SAVE SELECT FLAG FOR DIRSEL CALL DBUFFER ; GET PTRS CALL DIRSLOAD ; LOAD DIRECTORY WITH SIZING INFORMATION POP DE ; GET PTR TO FCB RET Z ; ABORT IF TPA OVERFLOW PUSH AF ; SAVE FLAG INDICATING NO OVERFLOW LD A,(SELFLG) ; GET SELECT FLAG CALL DIRSEL ; SELECT FILES CALL DIRPACK ; PACK DIRECTORY XOR A ; SORT FLAG (FN AND FT) CALL DIRALPHA ; ALPHABETIZE POP AF ; GET PSW (NO TPA OVERFLOW FLAG) RET END ; ; SYSLIB Module Name: SDIR01 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dbuffer MACLIB SDIRHDR.LIB EXT DPARAMS ;* ;* THIS ROUTINE ACCEPTS A BASE ADDRESS FOR THE DYNAMIC BUFFERS ;* REQUIRED, DETERMINES HOW MUCH SPACE IS REQUIRED FOR THE BUFFERS, ;* AND SETS THE ORDER PTR TO PT TO THE FIRST AND DIRBUF TO PT TO ;* THE SECOND (ORDER SPACE = DIRMAX*2 AND DIRBUF = DIRMAX * ESIZE) ;* ON INPUT, HL PTS TO AVAILABLE BASE ;* ON OUTPUT, HL PTS TO DIRBUF ;* A=0 AND ZERO FLAG SET IF CCP OVERRUN ;* DBUFFER: PUSH DE ; SAVE DE PUSH BC ; SAVE BC LD (ORDER),HL ; PT TO ORDER TABLE CALL DPARAMS ; GET PARAMETERS LD HL,(DIRMAX) ; NUMBER OF ENTRIES IN DIR EX DE,HL ; ... IN DE LD HL,(ORDER) ; ADD TO ORDER BASE ADD HL,DE ; *1 CALL MEMCHK ; CHECK FOR WITHIN RANGE ADD HL,DE ; HL PTS TO DIRBUF CALL MEMCHK ; CHECK FOR WITHIN RANGE LD (DIRBUF),HL ; SET PTR AND HL PTS TO DIRECTORY BUFFER POP BC ; RESTORE BC POP DE ; RESTORE DE XOR A ; OK DEC A ; SET FLAGS (NZ) RET MEMCHK: PUSH HL ; SAVE REGS PUSH DE EX DE,HL ; NEXT ADDRESS IN DE LD HL,(BDOS+1) ; GET ADDRESS OF BDOS LD A,D ; CHECK FOR PAGE OVERRUN CP H JP NC,MEMORUN ; OVERRUN IF D>=H POP DE POP HL RET MEMORUN: POP DE ; RESTORE POP HL XOR A ; RETURN 0 POP BC ; CLEAR STACK POP BC ; RESTORE BC RET END ; ; SYSLIB Module Name: SDIR02 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dparams MACLIB SDIRHDR.LIB ;* ;* THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND ;* STORES THIS INFORMATION IN: ;* BLKSHF <-- BLOCK SHIFT FACTOR (1 BYTE) ;* BLKMSK <-- BLOCK MASK (1 BYTE) ;* EXTENT <-- EXTENT MASK (1 BYTE) [NOT ANY MORE] ;* BLKMAX <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES) ;* DIRMAX <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES) ;* DPARAMS: PUSH BC ; SAVE REGS PUSH DE PUSH HL PUSH AF LD C,12 ; GET VERSION NUMBER CALL BDOS LD A,H ; CHECK FOR 1.4 OR L JP Z,DPARM1 ; PRE-2.x...GET PARAMS THE 1.4 WAY ;* ;* VERSION 2.x OR MP/M ;* LD C,31 ; 2.x OR MP/M...REQUEST DPB CALL BDOS INC HL INC HL LD A,(HL) ; GET BLOCK SHIFT LD (BLKSHF),A ; BLOCK SHIFT FACTOR INC HL ; GET BLOCK MASK LD A,(HL) LD (BLKMSK),A ; BLOCK MASK INC HL ; MOV A,M ; GET MAX EXTENT NUMBER ; STA EXTENT ; THIS IS CALLED THE EXTENT MASK INC HL LD E,(HL) ; GET MAX BLOCK NUMBER INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR MAX NUMBER OF BLOCKS LD (BLKMAX),HL ; MAXIMUM NUMBER OF BLOCKS EX DE,HL INC HL LD E,(HL) ; GET DIRECTORY SIZE INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR NUMBER OF ENTRIES LD (DIRMAX),HL ; MAXIMUM NUMBER OF DIRECTORY ENTRIES JP DPARM2 ;* ;* CP/M 1.4 ;* DPARM1: LD HL,(BDOS+1) ; GET PARAMS 1.4 STYLE LD L,3BH ; POINT TO DIRECTORY SIZE ENTRY IN 1.4 BDOS LD E,(HL) ; GET IT LD D,0 ; FORCE HI ORDER BYTE TO 0 EX DE,HL ; SAVE SIZE OF DIRECTORY ENTRY INC HL ; ADD 1 LD (DIRMAX),HL ; MAXIMUM NUMBER OF ENTRIES EX DE,HL INC HL ; POINT TO BLOCK SHIFT LD A,(HL) LD (BLKSHF),A ; BLOCK SHIFT FACTOR INC HL ; POINT TO BLOCK MASK LD A,(HL) LD (BLKMSK),A ; BLOCK MASK INC HL LD E,(HL) ; GET MAXIMUM BLOCK NUMBER LD D,0 EX DE,HL INC HL ; ADD 1 LD (BLKMAX),HL ; MAXIMUM NUMBER OF BLOCKS ; XRA A ; A=0 ; STA EXTENT ; SET EXTENT MASK TO 0 FOR CP/M 1.4 EXTENT SIZE ;* ;* ALL PARAMETERS EXTRACTED ;* DPARM2: POP AF ; RESTORE REGS POP HL POP DE POP BC RET END ; ; SYSLIB Module Name: SDIR03 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dfree MACLIB SDIRHDR.LIB ;* ;* COMPUTE AMOUNT OF FREE SPACE LEFT ON DISK ;* ON EXIT, DE=AMOUNT OF FREE SPACE ON DISK IN K ;* THE DPARAMS ROUTINE MUST BE CALLED BEFORE THIS ROUTINE IS USED ;* DFREE: PUSH BC ; SAVE REGS PUSH HL PUSH AF LD C,27 ; GET ADDRESS OF ALLOCATION VECTOR CALL BDOS EX DE,HL LD HL,(BLKMAX) ; GET LENGTH OF ALLOCATION VECTOR LD BC,0 ; INIT BLOCK COUNT TO 0 ;* ;* BC IS ACCUMULATOR FOR SPACE ;* FREE1: PUSH DE ; SAVE ALLOC ADDRESS LD A,(DE) ; GET BIT PATTERN OF ALLOCATION BYTE LD E,8 ; SET TO PROCESS 8 BLOCKS FREE2: RLA ; ROTATE ALLOCATED BLOCK BIT INTO CARRY FLAG JP C,FREE3 ; IF SET (BIT=1), BLOCK IS ALLOCATED INC BC ; IF NOT SET, BLOCK IS NOT ALLOCATED, SO INCREMENT ; FREE BLOCK COUNT FREE3: LD D,A ; SAVE REMAINING ALLOCATION BITS IN D DEC HL ; COUNT DOWN NUMBER OF BLOCKS ON DISK LD A,L OR H JP Z,FREE4 ; DONE IF NO MORE BLOCKS LEFT LD A,D ; A=CURRENT ALLOCATION BIT PATTERN DEC E ; HAVE ALL 8 BITS BEEN EXAMINED? JP NZ,FREE2 ; CONTINUE IF NOT POP DE ; GET POINTER TO ALLOCATION VECTOR INC DE ; POINT TO NEXT ALLOCATION BYTE JP FREE1 ; CONTINUE BY PROCESSING NEXT ALLOCATION BYTE ;* ;* BC = TOTAL AMOUNT OF FREE SPACE IN TERMS OF BLOCKS ;* FREE4: POP DE ; CLEAR DE FROM STACK LD L,C ; HL=BC=NUMBER OF FREE BLOCKS LD H,B LD A,(BLKSHF) ; GET BLOCK SHIFT FACTOR SUB 3 ; CONVERT NUMBER OF BLOCKS TO K JP Z,FREE6 ; DONE IF SINGLE DENSITY (1K PER BLOCK) ;* ;* WE ARE AT A MORE ADVANCED DENSITY LEVEL; MULTIPLY THE NUMBER OF BLOCKS ;* BY THE SIZE OF A BLOCK IN K ;* FREE5: ADD HL,HL ; 2, 4, 8, 16, ETC K/BLK, SO BLOCK SHIFT FACTOR DEC A ; IS A POWER-OF-TWO MULTIPLE JP NZ,FREE5 ;* ;* AT THIS POINT, HL=AMOUNT OF FREE SPACE ON DISK IN K ;* FREE6: EX DE,HL ; DE=ANSWER POP AF ; RESTORE REGS POP HL POP BC RET END ; ; SYSLIB Module Name: SDIR04 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.6 public fsize MACLIB SDIRHDR.LIB ;* ;* COMPUTE SIZE OF FILE WHOSE LAST EXTENT IS POINTED TO BY HL ;* FILE SIZE IS RETURNED IN DE IN K ;* NOTE THAT THE ROUTINE DPARAMS MUST HAVE BEEN CALLED BEFORE THIS ROUTINE ;* IS USED ;* ;* Version 1.5 includes a fix proposed by Sigi Kluger in 6/3/84 which ;* recognized overflow extents in S1. Now files >512K in size are ;* correctly recognized ;* FSIZE: PUSH BC ; SAVE REGS PUSH HL PUSH AF LD DE,12 ; POINT TO EXTENT ADD HL,DE LD E,(HL) ; GET EXTENT # LD D,0 INC HL ; SKIP S1 INC HL ; SKIP S2 PUSH HL ; SAVE PTR TO S2 INC HL ; HL PTS TO RECORD COUNT FIELD LD A,(HL) ; GET RECORD COUNT OF LAST EXTENT EX DE,HL ADD HL,HL ; NUMBER OF EXTENTS TIMES 16K ADD HL,HL ADD HL,HL ADD HL,HL EX DE,HL ; TOTAL SIZE OF PREVIOUS EXTENTS IN DE ; ; SK ; POP HL ; GET PTR TO S2 PUSH AF ; SAVE A LD A,(HL) ; GET S2 OR A ; OVERFLOW JP Z,NOVFL EX DE,HL LD DE,512 LP: ADD HL,DE DEC A JP NZ,LP EX DE,HL NOVFL: POP AF ; GET A BACK ; ;END SK ; LD HL,BLKMSK ADD A,(HL) ; ROUND LAST EXTENT TO BLOCK SIZE RRCA RRCA ; CONVERT FROM RECORDS TO K RRCA AND 1FH LD L,A ; ADD SIZE OF LAST EXTENT TO TOTAL OF PREVIOUS EXTENTS LD H,0 ; HL=SIZE OF LAST EXTENT, DE=TOTAL OF PREVIOUS EXTENTS ADD HL,DE ; HL=TOTAL FILE SIZE IN BLOCKS LD A,(BLKMSK) ; GET RECORDS/BLK-1 RRCA RRCA ; CONVERT TO K/BLK RRCA AND 1FH CPL ; USE TO FINISH ROUNDING AND L LD L,A ; HL NOW EQUALS THE SIZE OF THE FILE IN K INCREMENTS EX DE,HL ; DE=FILE SIZE IN K POP AF ; RESTORE REGS POP HL POP BC RET END ; ; SYSLIB Module Name: SDIR05 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dirload,dirsload MACLIB SDIRHDR.LIB EXT SDMOVE ;* ;* BUILD DIRECTORY TABLE AT DIRBUF ;* THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE ;* FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT ;* TO COMPUTE THE FILE SIZES ;* ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX) ;* ON OUTPUT, BC IS NUM OF FILES ;* A=0 AND ZERO FLAG SET IF TPA OVERFLOW ;* DE, HL UNAFFECTED ;* DIRLOAD: PUSH HL ; SAVE REGISTERS PUSH DE LD A,0FFH ; SELECT FILES OF SMALLER EX LD (DFLAG),A ; SET FLAG DLCOMMON: LD A,'?' ; SELECT FILES FROM ALL USER AREAS LD (TFCB),A ; SET DR FIELD TO ZERO TO DO THIS LD (DIRBUF),HL ; SAVE PTR TO DIRECTORY BUFFER LD (DSTART),HL ; SET START OF BUFFER AREA ;* ;* THIS SECTION OF CODE INITIALIZES THE COUNTERS USED ;* LD HL,0 ; HL=0 LD (FCOUNT),HL ; TOTAL FILES ON DISK = 0 ;* ;* NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER ;* LD C,17 ; SEARCH FOR FILE JP DIRLP1 DIRLP: CALL PENTRY ; PLACE ENTRY IN DIR JP Z,DIROVFL ; MEMORY OVERFLOW ERROR LD C,18 ; SEARCH FOR NEXT MATCH DIRLP1: LD DE,TFCB ; PT TO WILD NAME CALL BDOS CP 255 ; DONE? JP NZ,DIRLP ;* ;* NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES ;* DIRDN: XOR A ; LOAD OK DEC A ; SET FLAGS (NZ) DIRDNX: LD HL,(FCOUNT) ; GET TOTAL NUMBER OF FILES LD B,H ; ... IN BC LD C,L ;* ;* RESTORE REGISTERS AND RETURN ;* POP DE POP HL RET ;* ;* MEMORY OVERFLOW ERROR ;* DIROVFL: XOR A ; LOAD ERROR JP DIRDNX ;* ;* PENTRY -- ;* PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY ;* ;* ON INPUT, A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB ;* FCOUNT=NUMBER OF FILES IN DIR SO FAR ;* ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR ;* A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR ;* PENTRY: PUSH BC ; SAVE REGS PUSH DE PUSH HL RRCA ; MULTIPLY BY 32 FOR OFFSET COMPUTATION RRCA RRCA AND 60H ; A=BYTE OFFSET LD DE,BUFF ; PT TO BUFFER ENTRY LD L,A ; LET HL=OFFSET LD H,0 ADD HL,DE ; HL=PTR TO FCB LD A,(HL) ; GET USER NUMBER CP 0E5H ; DELETED? JP Z,PEDONE ; SKIP IT IF DELETED ;* ;* HL=ADR OF FCB IN BUFF ;* ;* ;* SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME ;* NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX ;* AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT ;* FOUND, RETURN WITH ZERO FLAG RESET (NZ) ;* CALL DUPENTRY ; CHECK FOR DUPLICATE AND SELECT EX JP Z,PEDONE ; SKIP IF DUPLICATE ;* INCREMENT TOTAL NUMBER OF FILES PUSH HL ; SAVE PTR TO FCB LD HL,(FCOUNT) ; TOTAL FILES = TOTAL FILES + 1 INC HL LD (FCOUNT),HL POP HL ; GET PTR TO FCB ;* ;* COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER ;* EX DE,HL ; SAVE PTR IN DE LD HL,(DIRBUF) ; PT TO NEXT ENTRY LOCATION EX DE,HL ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION LD B,ESIZE ; NUMBER OF BYTES/ENTRY CALL SDMOVE ; COPY FCB INTO MEMORY BUFFER EX DE,HL ; HL PTS TO NEXT ENTRY LD (DIRBUF),HL ; SET PTR EX DE,HL ; PTR TO NEXT ENTRY IN DE LD HL,(BDOS+1) ; BASE ADDRESS OF BDOS IN HL LD A,H ; GET BASE PAGE OF BDOS SUB 9 ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP CP D ; IS PTR TO NEXT ENTRY BEYOND THIS? JP NZ,PEDONE ; OK IF NOT AT BUFFER OVERFLOW LEVEL ;* DONE WITH PENTRY WITH MEMORY OVERFLOW ERROR PEOVFL: XOR A ; ERROR POP HL ; RESTORE REGS POP DE POP BC RET ;* DONE WITH PENTRY AND NO ERROR PEDONE: XOR A ; NO ERROR DEC A ; SET FLAGS (NZ) POP HL ; RESTORE REGS POP DE POP BC RET ;* ;* BUILD DIRECTORY TABLE AT DIRBUF ;* THIS DIRECTORY LOAD ROUTINE IS MUST LESS EFFICIENT THAN DIRLOAD, ;* BUT IT DOES LOAD ENOUGH INFORMATION TO COMPUTE THE FILE ;* SIZES USING THE FSIZE ROUTINE ;* ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX) ;* ON OUTPUT, BC IS NUM OF FILES ;* A=0 AND ZERO FLAG SET IF TPA OVERFLOW ;* DE, HL UNAFFECTED ;* DIRSLOAD: PUSH HL ; SAVE REGISTERS PUSH DE XOR A ; SELECT LARGER EX LD (DFLAG),A ; SET FLAG JP DLCOMMON ;* ;* SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME ;* NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX ;* AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT ;* FOUND, RETURN WITH ZERO FLAG RESET (NZ) ;* ON INPUT, HL PTS TO ENTRY TO SCAN FOR, FCOUNT = NUMBER OF ENTRIES SO FAR, ;* AND (DSTART) = STARTING ADDRESS OF DIRECTORY LOADED ;* ON OUTPUT, A=0 AND ZERO FLAG SET IF DUPLICATE ENTRY FOUND; A=0FFH AND NZ ;* IF NO DUP ENTRY FOUND ;* ONLY HL NOT AFFECTED ;* DUPENTRY: PUSH HL ; SAVE PTR TO ENTRY TO SCAN FOR EX DE,HL ; PTR IN DE LD HL,(FCOUNT) ; CHECK COUNT LD A,H ; NO ENTRIES? OR L JP Z,NODUP ; NO DUPLICATE ENTRY RETURN LD B,H ; BC=NUMBER OF ENTRIES LD C,L LD HL,(DSTART) ; HL PTS TO FIRST ENTRY DUPELOOP: PUSH BC ; SAVE COUNT PUSH HL ; SAVE PTRS PUSH DE LD B,12 ; COMPARE USER NUMBER, FN, AND FT CALL COMP POP DE ; RESTORE PTRS POP HL JP NZ,NODUPL ; CONTINUE LOOKING FOR ANOTHER ENTRY ; DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT PUSH HL ; SAVE PTRS AGAIN PUSH DE LD BC,12 ; PT TO EX FIELD ADD HL,BC EX DE,HL ADD HL,BC ; DE PTS TO DIRECTORY ENTRY, HL PTS TO TARGET LD A,(DE) ; GET EXTENT FIELD FROM DIRECTORY ENTRY CP (HL) ; COMPARE WITH THAT IN TARGET POP DE ; GET PTRS POP HL JP NC,DUPSMALL ; NEW TARGET IS LARGER THAN STORED ENTRY LD A,(DFLAG) ; CHECK FLAG FOR LARGE OR SMALL EX OR A ; 0=SELECT LARGER JP NZ,DUPFND DUPSEL: EX DE,HL ; MAKE HL PT TO NEW TARGET, DE PT TO DEST LD B,ESIZE ; NUMBER OF BYTES TO MOVE CALL SDMOVE ; MOVE IT JP DUPFND ; NEW TARGET IS SMALLER THAN STORED ENTRY DUPSMALL: LD A,(DFLAG) ; CHECK FLAG FOR LARGE OR SMALL EX OR A ; 0FFH=SELECT SMALLER JP NZ,DUPSEL ; RETURN INDICATOR THAT DUPLICATE WAS FOUND DUPFND: POP BC ; CLEAR COUNT FROM STACK XOR A ; INDICATE DUP FOUND POP HL ; RESTORE PTR TO ENTRY TO SCAN FOR RET ; NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY NODUPL: LD BC,ESIZE ; HL PTS TO CURRENT ENTRY IN BUFFER, SO ADD ESIZE TO IT ADD HL,BC POP BC ; GET COUNT DEC BC ; COUNT DOWN LD A,B ; CHECK FOR DONE OR C JP NZ,DUPELOOP ; NO DUPLICATE FOUND, PERIOD NODUP: XOR A ; INDICATE DUP NOT FOUND DEC A ; SET FLAGS (NZ) POP HL ; RESTORE PTR TO ENTRY TO SCAN FOR RET ;* ;* COMP COMPARES DE W/HL FOR B BYTES; RET W/CARRY IF DE0 = SORT BY FILE TYPE/NAME) ; DIRALPHA: LD (CMP$FLAG),A ; SET FLAG LD A,B ; ANY FILES? OR C RET Z PUSH HL ; SAVE REGS PUSH DE PUSH BC LD (DIRBUF),HL ; SAVE PTR TO DIRECTORY PUSH HL ; SAVE HL LD H,B ; HL=BC=FILE COUNT LD L,C LD (N),HL ; SET "N" POP HL ; ; SHELL SORT -- ; THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS" ; BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY. ; ON ENTRY, BC=NUMBER OF ENTRIES ; SORT: EX DE,HL ; POINTER TO DIRECTORY IN DE LD HL,(ORDER) ; PT TO ORDER TABLE ; ; SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT ; ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING ; SORT1: LD (HL),E ; STORE LOW-ORDER ADDRESS INC HL ; PT TO NEXT ORDER BYTE LD (HL),D ; STORE HIGH-ORDER ADDRESS INC HL ; PT TO NEXT ORDER ENTRY PUSH HL ; SAVE PTR LD HL,ESIZE ; HL=NUMBER OF BYTES/ENTRY ADD HL,DE ; PT TO NEXT DIR1 ENTRY EX DE,HL ; DE PTS TO NEXT ENTRY POP HL ; GET PTR TO ORDER TABLE DEC BC ; COUNT DOWN LD A,B ; DONE? OR C JP NZ,SORT1 ; ; THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P ; ; ; SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER ; LD HL,(N) ; NUMBER OF ITEMS TO SORT LD (GAP),HL ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2 ; FOR (GAP = N/2; GAP > 0; GAP = GAP/2) SRTL0: OR A ; CLEAR CARRY LD HL,(GAP) ; GET PREVIOUS GAP LD A,H ; ROTATE RIGHT TO DIVIDE BY 2 RRA LD H,A LD A,L RRA LD L,A ; TEST FOR ZERO OR H JP Z,SDONE ; DONE WITH SORT IF GAP = 0 LD (GAP),HL ; SET VALUE OF GAP LD (IVAL),HL ; SET I=GAP FOR FOLLOWING LOOP ; FOR (I = GAP + 1; I <= N; I = I + 1) SRTL1: LD HL,(IVAL) ; ADD 1 TO I INC HL LD (IVAL),HL ; TEST FOR I <= N EX DE,HL ; I IS IN DE LD HL,(N) ; GET N LD A,L ; COMPARE BY SUBTRACTION SUB E LD A,H SBC A,D ; CARRY SET MEANS I > N JP C,SRTL0 ; DON'T DO FOR LOOP IF I > N LD HL,(IVAL) ; SET J = I FOR FIRST SUBTRACTION OF GAP LD (J),HL ; FOR (J = I - GAP; J > 0; J = J - GAP) SRTL2: LD HL,(GAP) ; GET GAP EX DE,HL ; ... IN DE LD HL,(J) ; GET J LD A,L ; COMPUTE J - GAP SUB E LD L,A LD A,H SBC A,D LD H,A LD (J),HL ; J = J - GAP JP C,SRTL1 ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT LD A,H ; J=0? OR L JP Z,SRTL1 ; IF ZERO, J=0 AND ABORT ; SET JG = J + GAP EX DE,HL ; J IN DE LD HL,(GAP) ; GET GAP ADD HL,DE ; J + GAP LD (JG),HL ; JG = J + GAP ; IF (V(J) <= V(JG)) CALL ICOMPARE ; J IN DE, JG IN HL ; ... THEN BREAK JP C,SRTL1 ; ... ELSE EXCHANGE LD HL,(J) ; SWAP J, JG EX DE,HL LD HL,(JG) CALL ISWAP ; J IN DE, JG IN HL ; END OF INNER-MOST FOR LOOP JP SRTL2 ; ; SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE ; SDONE: LD HL,(N) ; NUMBER OF ENTRIES LD B,H ; ... IN BC LD C,L LD HL,(ORDER) ; PTR TO ORDERED POINTER TABLE LD (PTPTR),HL ; SET PTR PTR LD HL,(DIRBUF) ; PTR TO UNORDERED DIRECTORY LD (PTDIR),HL ; SET PTR DIR BUFFER ; FIND PTR TO NEXT DIR1 ENTRY SRTDN: LD HL,(PTPTR) ; PT TO REMAINING POINTERS EX DE,HL ; ... IN DE LD HL,(PTDIR) ; HL PTS TO NEXT DIR ENTRY PUSH BC ; SAVE COUNT OF REMAINING ENTRIES ; FIND PTR TABLE ENTRY SRTDN1: LD A,(DE) ; GET CURRENT POINTER TABLE ENTRY VALUE INC DE ; PT TO HIGH-ORDER POINTER BYTE CP L ; COMPARE AGAINST DIR1 ADDRESS LOW JP NZ,SRTDN2 ; NOT FOUND YET LD A,(DE) ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE CP H ; COMPARE AGAINST DIR1 ADDRESS HIGH JP Z,SRTDN3 ; MATCH FOUND SRTDN2: INC DE ; PT TO NEXT PTR TABLE ENTRY DEC BC ; COUNT DOWN LD A,C ; END OF TABLE? OR B JP NZ,SRTDN1 ; CONTINUE IF NOT ; FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT FERR$PTR: CALL PRINT DB 0DH,0AH,'DIRALPHA Error',0 JP CPM ; FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY ; MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY) ; POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED) SRTDN3: LD HL,(PTPTR) ; GET PTR TO NEXT ORDERED ENTRY DEC DE ; DE PTS TO LOW-ORDER POINTER ADDRESS LD A,(HL) ; MAKE PTR TO NEXT UNORDERED DIR1 PT TO BUFFER FOR LD (DE),A ; DIR1 ENTRY TO BE MOVED TO NEXT UNORDERED DIR1 POS INC HL ; PT TO NEXT PTR ADDRESS INC DE LD A,(HL) ; MAKE HIGH POINT SIMILARLY LD (DE),A ; COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER LD B,ESIZE ; B=NUMBER OF BYTES/ENTRY LD HL,(PTDIR) ; PT TO ENTRY LD DE,HOLD ; PT TO HOLD BUFFER PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC ; COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION LD HL,(PTPTR) ; POINT TO ITS POINTER LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; GET HIGH-ADDRESS POINTER LD HL,(PTDIR) ; DESTINATION ADDRESS FOR NEXT ORDERED ENTRY EX DE,HL ; HL PTS TO ENTRY TO BE MOVED, DE PTS TO DEST PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC EX DE,HL ; HL PTS TO NEXT UNORDERED DIR1 ENTRY LD (PTDIR),HL ; SET POINTER FOR NEXT LOOP ; COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY LD HL,(PTPTR) ; GET PTR TO PTR TO THE DESTINATION LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; HIGH-ADDRESS POINTER LD HL,HOLD ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST CALL SDMOVE ; B=NUMBER OF BYTES/ENTRY ; POINT TO NEXT ENTRY IN POINTER TABLE LD HL,(PTPTR) ; POINTER TO CURRENT ENTRY INC HL ; SKIP OVER IT INC HL LD (PTPTR),HL ; COUNT DOWN POP BC ; GET COUNTER DEC BC ; COUNT DOWN LD A,C ; DONE? OR B JP NZ,SRTDN POP BC ; RESTORE REGS POP DE POP HL RET ; DONE ; ; SWAP (Exchange) the pointers in the ORDER table whose indexes are in ; HL and DE ; ISWAP: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER TABLE - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL HL (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED EX DE,HL ; DE NOW PTS TO POINTER INDEXED BY HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL DE (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED LD C,(HL) ; EXCHANGE POINTERS -- GET OLD (DE) LD A,(DE) ; -- GET OLD (HL) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (HL) LD (DE),A ; PUT NEW (DE) INC HL ; PT TO NEXT BYTE OF POINTER INC DE LD C,(HL) ; GET OLD (HL) LD A,(DE) ; GET OLD (DE) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (DE) LD (DE),A ; PUT NEW (HL) RET ; ; ICOMPARE compares the entry pointed to by the pointer pointed to by HL ; with that pointed to by DE (1st level indirect addressing); on entry, ; HL and DE contain the numbers of the elements to compare (1, 2, ...); ; on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)), ; and Non-Zero and No-Carry means ((DE)) > ((HL)) ; ICOMPARE: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR ADD HL,BC ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE EX DE,HL ; RESULT IN DE DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DO THE SAME WITH THE ORIGINAL DE ADD HL,BC EX DE,HL ; ; HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH ; DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH ; FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL ; TO THE 4TH POINTER ; LD C,(HL) ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL HL LD B,(HL) EX DE,HL LD E,(HL) ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL DE LD D,(HL) LD H,B ; SET HL = OBJECT PTED TO INDIRECTLY BY BC LD L,C ; ; COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE; ; NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE16K) ;* DIRNPACK: PUSH HL ; SAVE REGS PUSH DE PUSH BC PUSH AF DNPACK: LD A,B ; DONE? OR C JP Z,DNPAK1 DEC BC ; COUNT DOWN LD A,(HL) ; GET FIRST BYTE CPL ; FLIP BITS AND 80H ; LOOK AT MOST SIG BIT LD D,A ; SAVE IN D LD A,(HL) ; GET FIRST BYTE AGAIN AND 7FH ; MASK OUT MS BIT OR D ; MASK IN NEW MOST SIG BIT LD (HL),A ; PUT BYTE BACK AND 80H ; SELECTED NOW? JP Z,DNPAK0 ; SKIP IF NOT SELECTED PUSH BC ; SAVE COUNTER CALL SDFCHK ; CHECK FOR FLAGS POP BC ; GET COUNTER JP Z,DNPAK0 LD A,(HL) ; GET BYTE AND 7FH ; DESELECT IT LD (HL),A ; PUT BYTE BACK DNPAK0: LD DE,ESIZE ; POINT TO NEXT ENTRY ADD HL,DE JP DNPACK DNPAK1: POP AF ; RESTORE REGS POP BC POP DE POP HL JP DIRPACK ; NOW BRANCH TO DIRPACK END ; ; SYSLIB Module Name: SDIR09 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dirpack MACLIB SDIRHDR.LIB EXT SDMOVE ;* ;* DIRECTORY PACK UTILITY -- RESTRUCTURE THE DIRECTORY TO INCLUDE ONLY ;* THOSE ENTRIES MARKED BY DIRSEL ;* ;* ON INPUT, HL PTS TO DIRECTORY BUFFER AND BC=NUMBER OF FILES ;* ON EXIT, BC=NUMBER OF SELECTED FILES ;* REQUIRED SIDE EFFECT IS THAT FLAG EXTENT (SET BY DIR::) BE CORRECT ;* (IN MOST CASES, DEFAULT OF 0 IS OK, EXCEPT WHEN EXTENT SIZE >16K) ;* DIRPACK: PUSH HL ; SAVE REGS PUSH DE PUSH AF PUSH HL ; SAVE HL LD HL,0 LD (FCOUNT),HL ; INIT FILE COUNT POP HL ; GET HL LD (DIRBUF),HL ; SAVE PTR PUSH BC ; SAVE COUNTER DPLOOP: POP BC ; GET COUNTER LD A,B ; CHECK FOR DONE OR C JP Z,DPDONE DEC BC ; COUNT DOWN PUSH BC ; SAVE COUNTER LD A,(HL) ; GET 1ST BYTE OF ENTRY AND 80H ; SELECTED? JP Z,DPNEXT ; ;* FOUND SELECTED ENTRY ; LD A,(HL) ; CLEAR MSB OF SELECTED ENTRY AND 7FH LD (HL),A PUSH HL ; SAVE PTR LD HL,(FCOUNT) ; INCREMENT FILE COUNT INC HL LD (FCOUNT),HL POP DE ; PT TO CURRENT ENTRY IN DE LD HL,(DIRBUF) ; PT TO NEXT ENTRY POSITION EX DE,HL ; HL PTS TO CURRENT, DE PTS TO NEXT ENTRY LD B,ESIZE ; COPY ENTRY CALL SDMOVE EX DE,HL ; HL PTS TO NEXT ENTRY LD (DIRBUF),HL ; SAVE IT EX DE,HL ; HL PTS TO NEXT ENTRY TO CHECK JP DPLOOP ; CONTINUE ; ;* SKIP TO NEXT ENTRY ; DPNEXT: LD BC,ESIZE ; SKIP ENTRY ADD HL,BC JP DPLOOP ; CONTINUE ; ;* COMPRESSION COMPLETE -- SET UP RETURNED VALUES ; DPDONE: LD HL,(FCOUNT) ; PUT FILE COUNT LD B,H ; ... IN BC LD C,L POP AF ; RESTORE REGS POP DE POP HL RET ; ; BUFFERS ; FCOUNT: DS 2 ; FILE COUNT END ; ; SYSLIB Module Name: SDIR10 ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public sdmove,sdfchk MACLIB SDIRHDR.LIB ;* ;* COPY FROM HL TO DE FOR B BYTES ;* SDMOVE: LD A,(HL) ; GET BYTE LD (DE),A ; PUT BYTE INC HL ; PT TO NEXT INC DE DEC B ; COUNT DOWN JP NZ,SDMOVE RET ;* ;* WE HAVE A NAME MATCH -- NOW CHECK FLAGS ;* RETURN Z IF MATCH, NZ IF NO MATCH ;* SDFCHK: PUSH DE ; SAVE FCB PTR PUSH HL ; SAVE ENTRY PTR LD DE,10 ; CHECK SYSTEM BIT ADD HL,DE ; HL PTS TO SYSTEM BIT LD A,(HL) ; GET BYTE POP HL ; RESTORE PTRS POP DE AND 80H ; MASK FOR SYSTEM BIT LD A,(SELFLG) ; GET FLAG BYTE JP Z,DSNSBIT ; ; IT IS A SYSTEM FILE, SO LOOK AT BIT 6 OF FLAG ; AND 40H ; LOOK AT BIT 6 JP NZ,DSUSER ; OK, SO LOOK AT USER JP DSNOMAT ; CONTINUE PROCESSING ; ; IT IS A NON-SYSTEM FILE, SO LOOK AT BIT 7 OF FLAG ; DSNSBIT: AND 80H ; LOOK AT BIT 7 JP Z,DSNOMAT ; NOT SET, SO SKIP ENTRY AS FAILING TEST ; ; NOW CHECK FOR PROPER USER AREA ; DSUSER: LD A,(SELFLG) ; GET FLAG AND 20H ; CHECK FOR ALL USERS JP NZ,DSYESMAT ; MATCH IF SET LD A,(SELFLG) ; GET FLAG AND 1FH ; GET USER NUMBER (LOW 5 BITS) LD B,A ; SAVE IN B LD A,(HL) ; COMPARE USER NUMBER TO DIR ENTRY AND 1FH ; LOOK AT USER NUMBER CP B ; COMPARE TO PASSED USER NUMBER JP NZ,DSNOMAT ; SKIP IF NOT SAME USER NUMBER ; ; MATCH, SO RETURN Z ; DSYESMAT: XOR A ; SET ZERO RET ; ; NOT A MATCH, SO RETURN NZ ; DSNOMAT: LD A,0FFH ; SET NO ZERO OR A RET END ; ; SYSLIB Module Name: SDIRn ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public blkshf,blkmsk,blkmax,dirmax,selflg,order,dirbuf ;* ;* BUFFERS ;* BLKSHF: DB 0 ; BLOCK SHIFT FACTOR BLKMSK: DB 0 ; BLOCK MASK BLKMAX: DW 0 ; MAX NUMBER OF BLOCKS DIRMAX: DW 0 ; MAX NUMBER OF DIRECTORY ENTRIES SELFLG: DB 0 ; FILE ATTRIBUTE FLAG ORDER: DW 0 ; POINTER TO ORDER TABLE DIRBUF: DW 0 ; POINTER TO DIRECTORY END ; ; SYSLIB Module Name: SDIRQ ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.6 ; Module Version Number: 1.5 public dirq ; ; EQUATES ; CPM EQU 0 BDOS EQU 5 BUFF EQU 80H ; DMA BUFFER ESIZE EQU 16 ; 16 BYTES/ENTRY ; ; GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITHOUT SIZING INFORMATION ; THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES ; WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL. ON EXIT, ; BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER. ; THE DIRECTORY BUFFER GENERATED BY DIRQ CONTAINS ENTRIES WHICH MAY NOT ; BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE. THE ; DIRQS ROUTINE IS DESIGNED FOR THIS PURPOSE. THE BASIC TRADEOFF BETWEEN ; THE TWO ROUTINES IS THE DIRQ RUNS FASTER THAN DIRQS, AND THIS IS NOTICABLE ; IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED. ; ; THE DIRQ/DIRQS ROUTINES ARE INTENDED TO BE USED IN APPLICATIONS WHERE ; THE ONLY THING DESIRED IS A DIRECTORY LOAD OF THE CURRENT DIRECTORY ; (DISK AND USER). DIRF/DIRFS PROVIDE MORE FLEXIBILITY AT A GREATER COST ; IN TERMS OF SIZE. ; ; INPUT PARAMETERS: ; HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG: ; Bit 7 - Select Non-Sys, Bit 6 - Select Sys ; Bit 5 - Sort by File Name and Type (0) or other (1) ; Bits 4-0 - Unused ; OUTPUT PARAMETERS: ; HL PTS TO FIRST FILE IN BUFFER ; BC = NUMBER OF FILES ; A=0 and Z Flag Set if TPA Overflow ; DE UNCHANGED ; DIRQ: PUSH DE ; SAVE PTR TO FCB LD (SELFLG),A ; SAVE SELECT FLAG FOR SELECTION AND ALPHA LD (HOLD),HL ; SET PTR TO HOLD BUFFER LD BC,36 ; ALLOW 36 BYTES ADD HL,BC ; HL NOW POINTS TO TEMP FCB LD (TFCB),HL ; SET PTR TO TEMP FCB ADD HL,DE ; HL NOW PTS TO SCRATCH AREA PUSH DE ; SAVE PTR TO FCB CALL DBUFFER ; GET PTRS POP DE ; GET PTR TO FCB PUSH HL ; SAVE PTR TO BUFFER CALL DIRLOAD ; LOAD DIRECTORY WITHOUT SIZING INFORMATION (FAST LOAD) POP HL ; GET PTR TO BUFFER POP DE ; GET PTR TO FCB RET Z ; ABORT IF TPA OVERFLOW PUSH AF ; SAVE FLAG TO INDICATE NO TPA OVERFLOW CALL DIRALPHA ; ALPHABETIZE POP AF ; GET PSW (TPA OVERFLOW FLAG) RET ; ; THIS ROUTINE ACCEPTS A BASE ADDRESS FOR THE DYNAMIC BUFFERS ; REQUIRED, DETERMINES HOW MUCH SPACE IS REQUIRED FOR THE BUFFERS, ; AND SETS THE ORDER PTR TO PT TO THE FIRST AND DIRBUF TO PT TO ; THE SECOND (ORDER SPACE = DIRMAX*2 AND DIRBUF = DIRMAX * ESIZE) ; ON INPUT, HL PTS TO AVAILABLE BASE ; ON OUTPUT, HL PTS TO DIRBUF ; A=0 AND ZERO FLAG SET IF CCP OVERRUN ; DBUFFER: LD (ORDER),HL ; PT TO ORDER TABLE CALL DPARAMS ; GET PARAMETERS LD HL,(DIRMAX) ; NUMBER OF ENTRIES IN DIR EX DE,HL ; ... IN DE LD HL,(ORDER) ; ADD TO ORDER BASE ADD HL,DE ; *1 CALL MEMCHK ; CHECK FOR WITHIN RANGE ADD HL,DE ; HL PTS TO DIRBUF CALL MEMCHK ; CHECK FOR WITHIN RANGE LD (DIRBUF),HL ; SET PTR AND HL PTS TO DIRECTORY BUFFER XOR A ; OK DEC A ; SET FLAGS (NZ) RET MEMCHK: PUSH HL ; SAVE REGS PUSH DE EX DE,HL ; NEXT ADDRESS IN DE LD HL,(BDOS+1) ; GET ADDRESS OF BDOS LD A,D ; CHECK FOR PAGE OVERRUN CP H JP NC,MEMORUN ; OVERRUN IF D>=H POP DE POP HL RET MEMORUN: POP DE ; RESTORE POP HL POP AF ; CLEAR STACK XOR A ; RETURN 0 RET ; ; THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND ; STORES THIS INFORMATION IN: ; BLKSHF <-- BLOCK SHIFT FACTOR (1 BYTE) ; BLKMSK <-- BLOCK MASK (1 BYTE) ; EXTENT <-- EXTENT MASK (1 BYTE) [NOT ANY MORE] ; BLKMAX <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES) ; DIRMAX <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES) ; DPARAMS: ; ; VERSION 2.x OR MP/M ; LD C,31 ; 2.x OR MP/M...REQUEST DPB CALL BDOS INC HL INC HL LD A,(HL) ; GET BLOCK SHIFT LD (BLKSHF),A ; BLOCK SHIFT FACTOR INC HL ; GET BLOCK MASK LD A,(HL) LD (BLKMSK),A ; BLOCK MASK INC HL INC HL LD E,(HL) ; GET MAX BLOCK NUMBER INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR MAX NUMBER OF BLOCKS LD (BLKMAX),HL ; MAXIMUM NUMBER OF BLOCKS EX DE,HL INC HL LD E,(HL) ; GET DIRECTORY SIZE INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR NUMBER OF ENTRIES LD (DIRMAX),HL ; MAXIMUM NUMBER OF DIRECTORY ENTRIES RET ; ; BUILD DIRECTORY TABLE AT DIRBUF ; THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE ; FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT ; TO COMPUTE THE FILE SIZES ; ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX) ; DE PTS TO FCB (ONLY 12 BYTES NEEDED) ; ON OUTPUT, BC IS NUM OF FILES ; A=0 AND ZERO FLAG SET IF TPA OVERFLOW ; DIRLOAD: INC DE ; PT TO FILE NAME LD HL,(TFCB) ; PT TO TFCB LD (HL),0 ; SELECT CURRENT DISK INC HL ; PT TO FILE NAME IN TFCB LD B,11 ; 11 CHARS DLLOOP: LD A,(DE) ; COPY LD (HL),A INC HL ; PT TO NEXT INC DE DEC B ; COUNT DOWN JP NZ,DLLOOP LD B,24 ; 24 CHARS (INCL ZERO EX) XOR A ; ZERO REST OF TFCB DLLOOP1: LD (HL),A ; STORE ZERO INC HL ; PT TO NEXT DEC B ; COUNT DOWN JP NZ,DLLOOP1 ; ; THIS SECTION OF CODE INITIALIZES THE COUNTERS USED ; LD HL,0 ; HL=0 LD (FCOUNT),HL ; TOTAL FILES ON DISK = 0 ; ; NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER ; LD C,17 ; SEARCH FOR FILE JP DIRLP1 DIRLP: CALL PENTRY ; PLACE ENTRY IN DIR JP Z,DIROVFL ; MEMORY OVERFLOW ERROR LD C,18 ; SEARCH FOR NEXT MATCH DIRLP1: LD HL,(TFCB) ; PT TO FCB EX DE,HL CALL BDOS CP 255 ; DONE? JP NZ,DIRLP ; ; NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES ; DIRDN: XOR A ; LOAD OK DEC A ; SET FLAGS (NZ) DIRDNX: LD HL,(FCOUNT) ; GET TOTAL NUMBER OF FILES LD B,H ; ... IN BC LD C,L RET ; ; MEMORY OVERFLOW ERROR ; DIROVFL: XOR A ; LOAD ERROR JP DIRDNX ; ; PENTRY -- ; PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY ; ; ON INPUT, A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB ; FCOUNT=NUMBER OF FILES IN DIR SO FAR ; ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR ; A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR ; PENTRY: RRCA ; MULTIPLY BY 32 FOR OFFSET COMPUTATION RRCA RRCA AND 60H ; A=BYTE OFFSET LD DE,BUFF ; PT TO BUFFER ENTRY LD L,A ; LET HL=OFFSET LD H,0 ADD HL,DE ; HL=PTR TO FCB ; ; HL=ADR OF FCB IN BUFF ; CALL ATTEST ; TEST ATTRIBUTES JP Z,PEDONE ; SKIP IF ATTRIBUTE NOT DESIRED ; ; COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER ; EX DE,HL ; SAVE PTR IN DE LD HL,(DIRBUF) ; PT TO NEXT ENTRY LOCATION EX DE,HL ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION LD B,ESIZE ; NUMBER OF BYTES/ENTRY CALL SDMOVE ; COPY FCB INTO MEMORY BUFFER EX DE,HL ; HL PTS TO NEXT ENTRY LD (DIRBUF),HL ; SET PTR EX DE,HL ; PTR TO NEXT ENTRY IN DE LD HL,(BDOS+1) ; BASE ADDRESS OF BDOS IN HL LD A,H ; GET BASE PAGE OF BDOS SUB 9 ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP CP D ; IS PTR TO NEXT ENTRY BEYOND THIS? RET Z ; INCREMENT TOTAL NUMBER OF FILES LD HL,(FCOUNT) ; TOTAL FILES = TOTAL FILES + 1 INC HL LD (FCOUNT),HL ; DONE WITH PENTRY AND NO ERROR PEDONE: XOR A ; NO ERROR DEC A ; SET FLAGS (NZ) RET ; ; CHECK ATTRIBUTES OF FILE ENTRY PTED TO BY HL AGAINST SELFLG ; IF SYSTEM FILE AND SYSTEM ATTRIBUTE SET, RETURN NZ ; IF NORMAL FILE AND NORMAL ATTRIBUTE SET, RETURN NZ ; ATTEST: PUSH HL ; SAVE PTR LD BC,10 ; PT TO SYSTEM ATTRIBUTE ADD HL,BC LD A,(HL) ; GET SYSTEM ATTRIBUTE POP HL ; RESTORE PTR AND 80H ; CHECK FOR SYS LD A,(SELFLG) ; GET SELECTION FLAG JP Z,ATDIR AND 01000000B ; CHECK SYSTEM ATTRIBUTE RET ATDIR: AND 10000000B ; CHECK NORMAL ATTRIBUTE RET ; ; DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS ; THE NUMBER OF FILES IN THE DIRECTORY AND A = SORT FLAG ; (0=SORT BY FILE NAME/TYPE, <>0 = SORT BY FILE TYPE/NAME) ; DIRALPHA: LD A,B ; ANY FILES? OR C RET Z PUSH HL ; SAVE REGS PUSH DE PUSH BC LD (DIRBUF),HL ; SAVE PTR TO DIRECTORY PUSH HL ; SAVE HL LD H,B ; HL=BC=FILE COUNT LD L,C LD (N),HL ; SET "N" POP HL ; ; SHELL SORT -- ; THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS" ; BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY. ; ON ENTRY, BC=NUMBER OF ENTRIES ; SORT: EX DE,HL ; POINTER TO DIRECTORY IN DE LD HL,(ORDER) ; PT TO ORDER TABLE ; ; SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT ; ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING ; SORT1: LD (HL),E ; STORE LOW-ORDER ADDRESS INC HL ; PT TO NEXT ORDER BYTE LD (HL),D ; STORE HIGH-ORDER ADDRESS INC HL ; PT TO NEXT ORDER ENTRY PUSH HL ; SAVE PTR LD HL,ESIZE ; HL=NUMBER OF BYTES/ENTRY ADD HL,DE ; PT TO NEXT DIR1 ENTRY EX DE,HL ; DE PTS TO NEXT ENTRY POP HL ; GET PTR TO ORDER TABLE DEC BC ; COUNT DOWN LD A,B ; DONE? OR C JP NZ,SORT1 ; ; THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P ; ; ; SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER ; LD HL,(N) ; NUMBER OF ITEMS TO SORT LD (GAP),HL ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2 ; FOR (GAP = N/2; GAP > 0; GAP = GAP/2) SRTL0: OR A ; CLEAR CARRY LD HL,(GAP) ; GET PREVIOUS GAP LD A,H ; ROTATE RIGHT TO DIVIDE BY 2 RRA LD H,A LD A,L RRA LD L,A ; TEST FOR ZERO OR H JP Z,SDONE ; DONE WITH SORT IF GAP = 0 LD (GAP),HL ; SET VALUE OF GAP LD (IVAL),HL ; SET I=GAP FOR FOLLOWING LOOP ; FOR (I = GAP + 1; I <= N; I = I + 1) SRTL1: LD HL,(IVAL) ; ADD 1 TO I INC HL LD (IVAL),HL ; TEST FOR I <= N EX DE,HL ; I IS IN DE LD HL,(N) ; GET N LD A,L ; COMPARE BY SUBTRACTION SUB E LD A,H SBC A,D ; CARRY SET MEANS I > N JP C,SRTL0 ; DON'T DO FOR LOOP IF I > N LD HL,(IVAL) ; SET J = I FOR FIRST SUBTRACTION OF GAP LD (J),HL ; FOR (J = I - GAP; J > 0; J = J - GAP) SRTL2: LD HL,(GAP) ; GET GAP EX DE,HL ; ... IN DE LD HL,(J) ; GET J LD A,L ; COMPUTE J - GAP SUB E LD L,A LD A,H SBC A,D LD H,A LD (J),HL ; J = J - GAP JP C,SRTL1 ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT LD A,H ; J=0? OR L JP Z,SRTL1 ; IF ZERO, J=0 AND ABORT ; SET JG = J + GAP EX DE,HL ; J IN DE LD HL,(GAP) ; GET GAP ADD HL,DE ; J + GAP LD (JG),HL ; JG = J + GAP ; IF (V(J) <= V(JG)) CALL ICOMPARE ; J IN DE, JG IN HL ; ... THEN BREAK JP C,SRTL1 ; ... ELSE EXCHANGE LD HL,(J) ; SWAP J, JG EX DE,HL LD HL,(JG) CALL ISWAP ; J IN DE, JG IN HL ; END OF INNER-MOST FOR LOOP JP SRTL2 ; ; SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE ; SDONE: LD HL,(N) ; NUMBER OF ENTRIES LD B,H ; ... IN BC LD C,L LD HL,(ORDER) ; PTR TO ORDERED POINTER TABLE LD (PTPTR),HL ; SET PTR PTR LD HL,(DIRBUF) ; PTR TO UNORDERED DIRECTORY LD (PTDIR),HL ; SET PTR DIR BUFFER ; FIND PTR TO NEXT DIR1 ENTRY SRTDN: LD HL,(PTPTR) ; PT TO REMAINING POINTERS EX DE,HL ; ... IN DE LD HL,(PTDIR) ; HL PTS TO NEXT DIR ENTRY PUSH BC ; SAVE COUNT OF REMAINING ENTRIES ; FIND PTR TABLE ENTRY SRTDN1: LD A,(DE) ; GET CURRENT POINTER TABLE ENTRY VALUE INC DE ; PT TO HIGH-ORDER POINTER BYTE CP L ; COMPARE AGAINST DIR1 ADDRESS LOW JP NZ,SRTDN2 ; NOT FOUND YET LD A,(DE) ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE CP H ; COMPARE AGAINST DIR1 ADDRESS HIGH JP Z,SRTDN3 ; MATCH FOUND SRTDN2: INC DE ; PT TO NEXT PTR TABLE ENTRY DEC BC ; COUNT DOWN LD A,C ; END OF TABLE? OR B JP NZ,SRTDN1 ; CONTINUE IF NOT ; FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT FERR$PTR: LD E,7 ; RING BELL LD C,2 ; OUTPUT CALL BDOS JP CPM ; FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY ; MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY) ; POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED) SRTDN3: LD HL,(PTPTR) ; GET PTR TO NEXT ORDERED ENTRY DEC DE ; DE PTS TO LOW-ORDER POINTER ADDRESS LD A,(HL) ; MAKE PTR TO NEXT UNORDERED DIR1 PT TO BUFFER FOR LD (DE),A ; DIR1 ENTRY TO BE MOVED TO NEXT UNORDERED DIR1 POS INC HL ; PT TO NEXT PTR ADDRESS INC DE LD A,(HL) ; MAKE HIGH POINT SIMILARLY LD (DE),A ; COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER LD B,ESIZE ; B=NUMBER OF BYTES/ENTRY LD HL,(HOLD) ; PT TO HOLD BUFFER EX DE,HL LD HL,(PTDIR) ; PT TO ENTRY PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC ; COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION LD HL,(PTPTR) ; POINT TO ITS POINTER LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; GET HIGH-ADDRESS POINTER LD HL,(PTDIR) ; DESTINATION ADDRESS FOR NEXT ORDERED ENTRY EX DE,HL ; HL PTS TO ENTRY TO BE MOVED, DE PTS TO DEST PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC EX DE,HL ; HL PTS TO NEXT UNORDERED DIR1 ENTRY LD (PTDIR),HL ; SET POINTER FOR NEXT LOOP ; COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY LD HL,(PTPTR) ; GET PTR TO PTR TO THE DESTINATION LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; HIGH-ADDRESS POINTER LD HL,(HOLD) ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST CALL SDMOVE ; B=NUMBER OF BYTES/ENTRY ; POINT TO NEXT ENTRY IN POINTER TABLE LD HL,(PTPTR) ; POINTER TO CURRENT ENTRY INC HL ; SKIP OVER IT INC HL LD (PTPTR),HL ; COUNT DOWN POP BC ; GET COUNTER DEC BC ; COUNT DOWN LD A,C ; DONE? OR B JP NZ,SRTDN POP BC ; RESTORE REGS POP DE POP HL RET ; DONE ; ; SWAP (Exchange) the pointers in the ORDER table whose indexes are in ; HL and DE ; ISWAP: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER TABLE - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL HL (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED EX DE,HL ; DE NOW PTS TO POINTER INDEXED BY HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL DE (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED LD C,(HL) ; EXCHANGE POINTERS -- GET OLD (DE) LD A,(DE) ; -- GET OLD (HL) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (HL) LD (DE),A ; PUT NEW (DE) INC HL ; PT TO NEXT BYTE OF POINTER INC DE LD C,(HL) ; GET OLD (HL) LD A,(DE) ; GET OLD (DE) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (DE) LD (DE),A ; PUT NEW (HL) RET ; ; ICOMPARE compares the entry pointed to by the pointer pointed to by HL ; with that pointed to by DE (1st level indirect addressing); on entry, ; HL and DE contain the numbers of the elements to compare (1, 2, ...); ; on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)), ; and Non-Zero and No-Carry means ((DE)) > ((HL)) ; ICOMPARE: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR ADD HL,BC ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE EX DE,HL ; RESULT IN DE DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DO THE SAME WITH THE ORIGINAL DE ADD HL,BC EX DE,HL ; ; HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH ; DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH ; FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL ; TO THE 4TH POINTER ; LD C,(HL) ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL HL LD B,(HL) EX DE,HL LD E,(HL) ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL DE LD D,(HL) LD H,B ; SET HL = OBJECT PTED TO INDIRECTLY BY BC LD L,C ; ; COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE; ; NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE=H POP DE POP HL RET MEMORUN: POP DE ; RESTORE POP HL POP AF ; CLEAR STACK XOR A ; RETURN 0 RET ; ; THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND ; STORES THIS INFORMATION IN: ; BLKSHF <-- BLOCK SHIFT FACTOR (1 BYTE) ; BLKMSK <-- BLOCK MASK (1 BYTE) ; EXTENT <-- EXTENT MASK (1 BYTE) [NOT ANY MORE] ; BLKMAX <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES) ; DIRMAX <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES) ; DPARAMS: ; ; VERSION 2.x OR MP/M ; LD C,31 ; 2.x OR MP/M...REQUEST DPB CALL BDOS INC HL INC HL LD A,(HL) ; GET BLOCK SHIFT LD (BLKSHF),A ; BLOCK SHIFT FACTOR INC HL ; GET BLOCK MASK LD A,(HL) LD (BLKMSK),A ; BLOCK MASK INC HL INC HL LD E,(HL) ; GET MAX BLOCK NUMBER INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR MAX NUMBER OF BLOCKS LD (BLKMAX),HL ; MAXIMUM NUMBER OF BLOCKS EX DE,HL INC HL LD E,(HL) ; GET DIRECTORY SIZE INC HL LD D,(HL) EX DE,HL INC HL ; ADD 1 FOR NUMBER OF ENTRIES LD (DIRMAX),HL ; MAXIMUM NUMBER OF DIRECTORY ENTRIES RET ; ; BUILD DIRECTORY TABLE AT DIRBUF ; THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE ; FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT ; TO COMPUTE THE FILE SIZES ; ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX) ; DE PTS TO FCB (ONLY 12 BYTES NEEDED) ; ON OUTPUT, BC IS NUM OF FILES ; A=0 AND ZERO FLAG SET IF TPA OVERFLOW ; DIRLOAD: LD (DSTART),HL ; SET START OF BUFFER AREA INC DE ; PT TO FILE NAME LD HL,(TFCB) ; PT TO TFCB LD (HL),0 ; SELECT CURRENT DISK INC HL ; PT TO FILE NAME IN TFCB LD B,11 ; 11 CHARS DLLOOP: LD A,(DE) ; COPY LD (HL),A INC HL ; PT TO NEXT INC DE DEC B ; COUNT DOWN JP NZ,DLLOOP LD (HL),'?' ; SELECT ALL EXTENTS INC HL ; PT TO NEXT CHAR LD B,23 ; 23 CHARS XOR A ; ZERO REST OF TFCB DLLOOP1: LD (HL),A ; STORE ZERO INC HL ; PT TO NEXT DEC B ; COUNT DOWN JP NZ,DLLOOP1 ; ; THIS SECTION OF CODE INITIALIZES THE COUNTERS USED ; LD HL,0 ; HL=0 LD (FCOUNT),HL ; TOTAL FILES ON DISK = 0 ; ; NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER ; LD C,17 ; SEARCH FOR FILE JP DIRLP1 DIRLP: CALL PENTRY ; PLACE ENTRY IN DIR JP Z,DIROVFL ; MEMORY OVERFLOW ERROR LD C,18 ; SEARCH FOR NEXT MATCH DIRLP1: LD HL,(TFCB) ; PT TO FCB EX DE,HL CALL BDOS CP 255 ; DONE? JP NZ,DIRLP ; ; NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES ; DIRDN: XOR A ; LOAD OK DEC A ; SET FLAGS (NZ) DIRDNX: LD HL,(FCOUNT) ; GET TOTAL NUMBER OF FILES LD B,H ; ... IN BC LD C,L RET ; ; MEMORY OVERFLOW ERROR ; DIROVFL: XOR A ; LOAD ERROR JP DIRDNX ; ; PENTRY -- ; PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY ; ; ON INPUT, A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB ; FCOUNT=NUMBER OF FILES IN DIR SO FAR ; ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR ; A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR ; PENTRY: RRCA ; MULTIPLY BY 32 FOR OFFSET COMPUTATION RRCA RRCA AND 60H ; A=BYTE OFFSET LD DE,BUFF ; PT TO BUFFER ENTRY LD L,A ; LET HL=OFFSET LD H,0 ADD HL,DE ; HL=PTR TO FCB ; ; HL=ADR OF FCB IN BUFF ; CALL ATTEST ; TEST ATTRIBUTES JP Z,PEDONE ; SKIP IF ATTRIBUTE NOT DESIRED ; ; SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME ; NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX ; AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT ; FOUND, RETURN WITH ZERO FLAG RESET (NZ) ; CALL DUPENTRY ; CHECK FOR DUPLICATE AND SELECT EX JP Z,PEDONE ; SKIP IF DUPLICATE ; ; COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER ; EX DE,HL ; SAVE PTR IN DE LD HL,(DIRBUF) ; PT TO NEXT ENTRY LOCATION EX DE,HL ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION LD B,ESIZE ; NUMBER OF BYTES/ENTRY CALL SDMOVE ; COPY FCB INTO MEMORY BUFFER EX DE,HL ; HL PTS TO NEXT ENTRY LD (DIRBUF),HL ; SET PTR EX DE,HL ; PTR TO NEXT ENTRY IN DE LD HL,(BDOS+1) ; BASE ADDRESS OF BDOS IN HL LD A,H ; GET BASE PAGE OF BDOS SUB 9 ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP CP D ; IS PTR TO NEXT ENTRY BEYOND THIS? RET Z ; INCREMENT TOTAL NUMBER OF FILES LD HL,(FCOUNT) ; TOTAL FILES = TOTAL FILES + 1 INC HL LD (FCOUNT),HL ; DONE WITH PENTRY AND NO ERROR PEDONE: XOR A ; NO ERROR DEC A ; SET FLAGS (NZ) RET ; ; CHECK ATTRIBUTES OF FILE ENTRY PTED TO BY HL AGAINST SELFLG ; IF SYSTEM FILE AND SYSTEM ATTRIBUTE SET, RETURN NZ ; IF NORMAL FILE AND NORMAL ATTRIBUTE SET, RETURN NZ ; ATTEST: PUSH HL ; SAVE PTR LD BC,10 ; PT TO SYSTEM ATTRIBUTE ADD HL,BC LD A,(HL) ; GET SYSTEM ATTRIBUTE POP HL ; RESTORE PTR AND 80H ; CHECK FOR SYS LD A,(SELFLG) ; GET SELECTION FLAG JP Z,ATDIR AND 01000000B ; CHECK SYSTEM ATTRIBUTE RET ATDIR: AND 10000000B ; CHECK NORMAL ATTRIBUTE RET ; ; SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME ; NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX ; AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT ; FOUND, RETURN WITH ZERO FLAG RESET (NZ) ; ON INPUT, HL PTS TO ENTRY TO SCAN FOR, FCOUNT = NUMBER OF ENTRIES SO FAR, ; AND (DSTART) = STARTING ADDRESS OF DIRECTORY LOADED ; ON OUTPUT, A=0 AND ZERO FLAG SET IF DUPLICATE ENTRY FOUND; A=0FFH AND NZ ; IF NO DUP ENTRY FOUND ; ONLY HL NOT AFFECTED ; DUPENTRY: PUSH HL ; SAVE PTR TO ENTRY TO SCAN FOR EX DE,HL ; PTR IN DE LD HL,(FCOUNT) ; CHECK COUNT LD A,H ; NO ENTRIES? OR L JP Z,NODUP ; NO DUPLICATE ENTRY RETURN LD B,H ; BC=NUMBER OF ENTRIES LD C,L LD HL,(DSTART) ; HL PTS TO FIRST ENTRY DUPELOOP: PUSH BC ; SAVE COUNT PUSH HL ; SAVE PTRS PUSH DE INC HL ; PT TO FN INC DE LD B,11 ; COMPARE FN AND FT CALL COMP JP NZ,NODUPL ; CONTINUE LOOKING FOR ANOTHER ENTRY ; DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT LD A,(DE) ; GET EXTENT FIELD FROM TARGET CP (HL) ; COMPARE WITH THAT IN DIRECTORY ENTRY POP DE ; GET PTRS POP HL JP C,DUPSMALL ; NEW TARGET IS LARGER THAN STORED ENTRY EX DE,HL ; HL PTS TO TARGET, DE PTS TO DIR ENTRY LD B,ESIZE ; NUMBER OF BYTES TO MOVE CALL SDMOVE ; MOVE IT ; NEW TARGET IS SMALLER THAN STORED ENTRY DUPSMALL: POP BC ; CLEAR COUNT FROM STACK XOR A ; INDICATE DUP FOUND POP HL ; RESTORE PTR TO ENTRY TO SCAN FOR RET ; NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY NODUPL: POP DE ; RESTORE PTRS POP HL LD BC,ESIZE ; HL PTS TO CURRENT ENTRY IN BUFFER, ADD HL,BC ; ... SO ADD ESIZE TO IT POP BC ; GET COUNT DEC BC ; COUNT DOWN LD A,B ; CHECK FOR DONE OR C JP NZ,DUPELOOP ; NO DUPLICATE FOUND NODUP: XOR A ; INDICATE DUP NOT FOUND DEC A ; SET FLAGS (NZ) POP HL ; RESTORE PTR TO ENTRY TO SCAN FOR RET ; ; DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS ; THE NUMBER OF FILES IN THE DIRECTORY AND A = SORT FLAG ; (0=SORT BY FILE NAME/TYPE, <>0 = SORT BY FILE TYPE/NAME) ; DIRALPHA: LD A,B ; ANY FILES? OR C RET Z PUSH HL ; SAVE REGS PUSH DE PUSH BC LD (DIRBUF),HL ; SAVE PTR TO DIRECTORY PUSH HL ; SAVE HL LD H,B ; HL=BC=FILE COUNT LD L,C LD (N),HL ; SET "N" POP HL ; ; SHELL SORT -- ; THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS" ; BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY. ; ON ENTRY, BC=NUMBER OF ENTRIES ; SORT: EX DE,HL ; POINTER TO DIRECTORY IN DE LD HL,(ORDER) ; PT TO ORDER TABLE ; ; SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT ; ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING ; SORT1: LD (HL),E ; STORE LOW-ORDER ADDRESS INC HL ; PT TO NEXT ORDER BYTE LD (HL),D ; STORE HIGH-ORDER ADDRESS INC HL ; PT TO NEXT ORDER ENTRY PUSH HL ; SAVE PTR LD HL,ESIZE ; HL=NUMBER OF BYTES/ENTRY ADD HL,DE ; PT TO NEXT DIR1 ENTRY EX DE,HL ; DE PTS TO NEXT ENTRY POP HL ; GET PTR TO ORDER TABLE DEC BC ; COUNT DOWN LD A,B ; DONE? OR C JP NZ,SORT1 ; ; THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P ; ; ; SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER ; LD HL,(N) ; NUMBER OF ITEMS TO SORT LD (GAP),HL ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2 ; FOR (GAP = N/2; GAP > 0; GAP = GAP/2) SRTL0: OR A ; CLEAR CARRY LD HL,(GAP) ; GET PREVIOUS GAP LD A,H ; ROTATE RIGHT TO DIVIDE BY 2 RRA LD H,A LD A,L RRA LD L,A ; TEST FOR ZERO OR H JP Z,SDONE ; DONE WITH SORT IF GAP = 0 LD (GAP),HL ; SET VALUE OF GAP LD (IVAL),HL ; SET I=GAP FOR FOLLOWING LOOP ; FOR (I = GAP + 1; I <= N; I = I + 1) SRTL1: LD HL,(IVAL) ; ADD 1 TO I INC HL LD (IVAL),HL ; TEST FOR I <= N EX DE,HL ; I IS IN DE LD HL,(N) ; GET N LD A,L ; COMPARE BY SUBTRACTION SUB E LD A,H SBC A,D ; CARRY SET MEANS I > N JP C,SRTL0 ; DON'T DO FOR LOOP IF I > N LD HL,(IVAL) ; SET J = I FOR FIRST SUBTRACTION OF GAP LD (J),HL ; FOR (J = I - GAP; J > 0; J = J - GAP) SRTL2: LD HL,(GAP) ; GET GAP EX DE,HL ; ... IN DE LD HL,(J) ; GET J LD A,L ; COMPUTE J - GAP SUB E LD L,A LD A,H SBC A,D LD H,A LD (J),HL ; J = J - GAP JP C,SRTL1 ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT LD A,H ; J=0? OR L JP Z,SRTL1 ; IF ZERO, J=0 AND ABORT ; SET JG = J + GAP EX DE,HL ; J IN DE LD HL,(GAP) ; GET GAP ADD HL,DE ; J + GAP LD (JG),HL ; JG = J + GAP ; IF (V(J) <= V(JG)) CALL ICOMPARE ; J IN DE, JG IN HL ; ... THEN BREAK JP C,SRTL1 ; ... ELSE EXCHANGE LD HL,(J) ; SWAP J, JG EX DE,HL LD HL,(JG) CALL ISWAP ; J IN DE, JG IN HL ; END OF INNER-MOST FOR LOOP JP SRTL2 ; ; SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE ; SDONE: LD HL,(N) ; NUMBER OF ENTRIES LD B,H ; ... IN BC LD C,L LD HL,(ORDER) ; PTR TO ORDERED POINTER TABLE LD (PTPTR),HL ; SET PTR PTR LD HL,(DIRBUF) ; PTR TO UNORDERED DIRECTORY LD (PTDIR),HL ; SET PTR DIR BUFFER ; FIND PTR TO NEXT DIR1 ENTRY SRTDN: LD HL,(PTPTR) ; PT TO REMAINING POINTERS EX DE,HL ; ... IN DE LD HL,(PTDIR) ; HL PTS TO NEXT DIR ENTRY PUSH BC ; SAVE COUNT OF REMAINING ENTRIES ; FIND PTR TABLE ENTRY SRTDN1: LD A,(DE) ; GET CURRENT POINTER TABLE ENTRY VALUE INC DE ; PT TO HIGH-ORDER POINTER BYTE CP L ; COMPARE AGAINST DIR1 ADDRESS LOW JP NZ,SRTDN2 ; NOT FOUND YET LD A,(DE) ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE CP H ; COMPARE AGAINST DIR1 ADDRESS HIGH JP Z,SRTDN3 ; MATCH FOUND SRTDN2: INC DE ; PT TO NEXT PTR TABLE ENTRY DEC BC ; COUNT DOWN LD A,C ; END OF TABLE? OR B JP NZ,SRTDN1 ; CONTINUE IF NOT ; FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT FERR$PTR: LD E,7 ; RING BELL LD C,2 ; OUTPUT CALL BDOS JP CPM ; FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY ; MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY) ; POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED) SRTDN3: LD HL,(PTPTR) ; GET PTR TO NEXT ORDERED ENTRY DEC DE ; DE PTS TO LOW-ORDER POINTER ADDRESS LD A,(HL) ; MAKE PTR TO NEXT UNORDERED DIR1 PT TO BUFFER FOR LD (DE),A ; DIR1 ENTRY TO BE MOVED TO NEXT UNORDERED DIR1 POS INC HL ; PT TO NEXT PTR ADDRESS INC DE LD A,(HL) ; MAKE HIGH POINT SIMILARLY LD (DE),A ; COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER LD B,ESIZE ; B=NUMBER OF BYTES/ENTRY LD HL,(HOLD) ; PT TO HOLD BUFFER EX DE,HL LD HL,(PTDIR) ; PT TO ENTRY PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC ; COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION LD HL,(PTPTR) ; POINT TO ITS POINTER LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; GET HIGH-ADDRESS POINTER LD HL,(PTDIR) ; DESTINATION ADDRESS FOR NEXT ORDERED ENTRY EX DE,HL ; HL PTS TO ENTRY TO BE MOVED, DE PTS TO DEST PUSH BC ; SAVE B=NUMBER OF BYTES/ENTRY CALL SDMOVE POP BC EX DE,HL ; HL PTS TO NEXT UNORDERED DIR1 ENTRY LD (PTDIR),HL ; SET POINTER FOR NEXT LOOP ; COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY LD HL,(PTPTR) ; GET PTR TO PTR TO THE DESTINATION LD E,(HL) ; GET LOW-ADDRESS POINTER INC HL LD D,(HL) ; HIGH-ADDRESS POINTER LD HL,(HOLD) ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST CALL SDMOVE ; B=NUMBER OF BYTES/ENTRY ; POINT TO NEXT ENTRY IN POINTER TABLE LD HL,(PTPTR) ; POINTER TO CURRENT ENTRY INC HL ; SKIP OVER IT INC HL LD (PTPTR),HL ; COUNT DOWN POP BC ; GET COUNTER DEC BC ; COUNT DOWN LD A,C ; DONE? OR B JP NZ,SRTDN POP BC ; RESTORE REGS POP DE POP HL RET ; DONE ; ; SWAP (Exchange) the pointers in the ORDER table whose indexes are in ; HL and DE ; ISWAP: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER TABLE - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL HL (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED EX DE,HL ; DE NOW PTS TO POINTER INDEXED BY HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX ; OF ORIGINAL DE (1, 2, ...) ADD HL,BC ; HL NOW PTS TO POINTER INVOLVED LD C,(HL) ; EXCHANGE POINTERS -- GET OLD (DE) LD A,(DE) ; -- GET OLD (HL) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (HL) LD (DE),A ; PUT NEW (DE) INC HL ; PT TO NEXT BYTE OF POINTER INC DE LD C,(HL) ; GET OLD (HL) LD A,(DE) ; GET OLD (DE) EX DE,HL ; SWITCH LD (HL),C ; PUT NEW (DE) LD (DE),A ; PUT NEW (HL) RET ; ; ICOMPARE compares the entry pointed to by the pointer pointed to by HL ; with that pointed to by DE (1st level indirect addressing); on entry, ; HL and DE contain the numbers of the elements to compare (1, 2, ...); ; on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)), ; and Non-Zero and No-Carry means ((DE)) > ((HL)) ; ICOMPARE: PUSH HL ; SAVE HL LD HL,(ORDER) ; ADDRESS OF ORDER - 2 LD B,H ; ... IN BC LD C,L POP HL DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR ADD HL,BC ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE EX DE,HL ; RESULT IN DE DEC HL ; ADJUST INDEX TO 0...N-1 FROM 1...N ADD HL,HL ; DO THE SAME WITH THE ORIGINAL DE ADD HL,BC EX DE,HL ; ; HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH ; DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH ; FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL ; TO THE 4TH POINTER ; LD C,(HL) ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL HL LD B,(HL) EX DE,HL LD E,(HL) ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO INC HL ; ... BY THE ORIGINAL DE LD D,(HL) LD H,B ; SET HL = OBJECT PTED TO INDIRECTLY BY BC LD L,C ; ; COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE; ; NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE