; ; Program: DIR ; Author: Richard Conn ; Version: 1.0 ; Date: 23 Mar 84 ; VERS EQU 11 ; Changed manner of calculating disk size ; Using all0 and all1 instead of drm ; Added modified dirqs and fsize jww ; Trial to list files vertically jww ; ;VERS EQU 10 ; Release ; MONTH EQU 1 DAY EQU 2 YEAR EQU 85 ; Z3ENV SET 0F400H ; Set zcpr3 environment descriptor address ; ; Equates ; YES EQU 0FFH NO EQU 0 ; VIDEO EQU YES ; Enhanced video? VOPT EQU YES ; Print signon and vers no VERT EQU YES ; List files vertically (default) ; FCB EQU 5CH FCB2 EQU 6CH CTRLC EQU 03H CR EQU 0DH LF EQU 0AH ; ; VLIB, Z3LIB and SYSLIB References ; EXT Z3VINIT,TINIT,STNDOUT,STNDEND,BDOS EXT CODEND,RETUD,PFN1,DFREE,DUTDIR,DPARAMS EXT CRLF,COUT,PAFDC,PHLDC,PHLFDC,Z3LOG,FILLB,GETCRT,CIN ; ; Environment Definition ; IF Z3ENV NE 0 ; ; External ZCPR3 Environment Descriptor ; JMP START DB 'Z3ENV' ; This is a zcpr3 utility DB 1 ; External environment descriptor Z3EADR: DW Z3ENV START: LHLD Z3EADR ; Pt to zcpr3 environment ; ELSE ; ; Internal ZCPR3 Environment Descriptor ; MACLIB Z3BASE.LIB MACLIB SYSENV.LIB Z3EADR: JMP START SYSENV START: LXI H,Z3EADR ; Pt to zcpr3 environment ENDIF ; ; Start of Program -- Initialize ZCPR3 Environment ; CALL Z3VINIT ; Initialize the zcpr3 env CALL TINIT ; Initialize the terminal ; ; Make FCB Wild if No Entry ; LXI H,FCB+1 ; Pt to first char MOV A,M ; Get it CPI ' ' ; Check for space MVI B,11 ; Prepare to set 11 bytes MVI A,'?' ; To "?" CZ FILLB ; Do it if space ; ; Check for Help ; LXI D,FCB+1 ; Pt to first char of fcb LDAX D ; Get first char of fcb CPI '/' JNZ DOIT CALL PRINT DB 'DIR Vers ' DB (VERS/10)+'0','.',(VERS MOD 10)+'0',CR,LF DB ' Syntax: DIR dir:afn o',CR,LF DB ' Options: A=All, S=Sys, H=Horiz, V=Vert, ' DB 'T=File Type/Name Sor','t'+80H RET ; ; Perform Directory Function ; DOIT: DCX D ; Pt to fcb CALL Z3LOG ; Log into dir XRA A ; Clear disk selection byte STAX D ; ; Process Options in FCB2 ; LXI H,FCB2+1 ; Pt to options MVI B,8 ; Allow for up to 8 options MVI C,10000000B ; Assume just normal files OPTLOOP: MOV A,M ; Get next char INX H ; Advance DCR B ; Count down JZ SETDATA ; Done - set data CPI ' ' JZ OPTLOOP CPI 'H' ; Select horizontal listing JZ SETHORIZ CPI 'V' ; Select vertical listing JZ SETVERT CPI 'T' ; File type? JZ SETTYPE CPI 'S' ; System? JZ SETSYS CPI 'A' ; System and normal? JNZ OPTLOOP ; ; Select Both System and Normal Files ; MVI A,11000000B ; Normal and system files JMP SETSYS1 ; ; Select Horizontal listing ; SETHORIZ: MVI A,YES STA HORIZ JMP OPTLOOP ; ; Select Vertical listing ; SETVERT: MVI A,NO STA HORIZ JMP OPTLOOP ; HORIZ: DB NOT VERT ; Horizontal listing flag ; ; Select File Type/Name Alphabetization ; SETTYPE: MOV A,C ; Get flag ORI 00100000B MOV C,A JMP OPTLOOP ; ; Select Just System Files ; SETSYS: MVI A,01000000B ; System SETSYS1: PUSH PSW MOV A,C ANI 00111111B ; Mask out MOV C,A POP PSW ORA C MOV C,A JMP OPTLOOP ; ; Set Selection Byte in A ; SETDATA: CALL DPARAMS ; Init parameters CALL CODEND ; Pt to free area MOV A,C ; Selection in a ; ; Load and Sort Directory ; CALL DIRQS ; Quick load SHLD DIRBEG ; Beginning of directory area JNZ DISPLAY CALL PRINT DB ' Ovf','l'+80H RET ; ; Display Directory ; DISPLAY: PUSH H ; Save ptr to first entry ; ; Init: ; Total of All File Sizes ; Number of Files Displayed ; Line Counter ; Entry Counter ; IF VOPT ; Signon and version PUSH B IF VIDEO CALL STNDOUT ENDIF MVI C,22 ; Print 22 spaces DIS0: MVI A,' ' CALL COUT DCR C JNZ DIS0 CALL PRINT DB 'DIRectory Version ' DB VERS/10+'0','.',VERS MOD 10+'0' DB ' ',MONTH/10+'0',MONTH MOD 10+'0','/' DB DAY/10+'0',DAY MOD 10+'0','/' DB YEAR/10+'0',YEAR MOD 10+'0' DB CR,LF+80H IF VIDEO CALL STNDEND ENDIF POP B ENDIF ; Vopt ; LXI H,0 ; Set total size count SHLD TOTCOUNT LXI H,FCOUNT ; Save file count MOV M,C INX H MOV M,B ; File count saved from bc PUSH B ; Save file count MOV H,B MOV L,C ; Move it to hl LXI D,4 CALL DIVIDE ; Divide by four columns JZ DIS1 INX B ; Round up if remainder from division DIS1: MOV H,B MOV L,C ; Quotient to hl CALL X16 SHLD LINES POP H ; Get file count PUSH H ; And put it back DCX H ; File count -1 points to last file CALL X16 ; Multiply by 16 chars/line XCHG ; Directory size to de LHLD DIRBEG DAD D SHLD DIREND POP B ; Get file count POP H ; Pt to first entry XRA A STA LCOUNT ; Init line count STA COUNT ; Init entry count MOV A,B ; Check for done ORA C JZ PRREMAIN ; Print remaining space on disk and exit CALL PRINT DB ' '+80H ; Print first leading space ; ; Loop to Display File Entries ; DISPLOOP: ; ; Print Separator if Within a Line ; LDA COUNT ; See if new entry on line ANI 3 JZ DISPL1 ; ; Print Separator if Entry is Within a List ; IF VIDEO CALL STNDOUT ENDIF CALL PRINT ; Print separator DB '|',' '+80H IF VIDEO CALL STNDEND ENDIF ; ; Print Next Entry ; DISPL1: PUSH H ; Save key regs PUSH B ; Hl pts to next entry, bc = count ; ; Print File Name ; INX H ; Pt to file name XCHG CALL PFN1 ; Print file name XCHG DCX H ; Pt to first byte of file entry ; ; Print File Size and Increment Total of All File Sizes ; PUSH H ; Save ptr to first byte of file entry CALL FSIZE ; Compute file size (to de) LHLD TOTCOUNT ; Increment total count DAD D SHLD TOTCOUNT XCHG CALL PHLDC ; Print file size POP H ; Get ptr to first byte of file entry ; ; Check R/O Byte ; MVI B,' ' ; Assume r/w LXI D,9 ; Pt to r/o DAD D MOV A,M ; Get r/o byte ANI 80H ; Look at it JZ ROOUT MVI B,'r' ; Set r/o ROOUT: MOV A,B ; Get char CALL COUT ; ; Increment Entry Count and Issue New Line if Limit Reached ; LDA COUNT ; Increment entry count INR A STA COUNT LDA HORIZ ; Check horiz/vert listing ORA A JZ DISPL2 ; Vertical listing LDA COUNT ANI 3 ; New line? CZ NEWLIN JMP DISPL2 ; ; New Line - Increment Line Count and Issue Page Break if Limit Reached ; NEWLIN: CALL PRNL LDA LCOUNT ; Count down lines INR A STA LCOUNT CALL GETCRT ; Get crt data INX H ; Pt to text line count INX H DCR A ; Back up again CMP M ; Compare RNZ XRA A ; Reset line count STA LCOUNT IF VIDEO CALL STNDOUT ENDIF CALL PRINT DB ' Pause -',' '+80H IF VIDEO CALL STNDEND ENDIF CALL CIN CALL PRNL ; Print new line with leading space CPI CTRLC ; Abort? RNZ POP PSW ; Clear the rest of the stack POP PSW POP PSW RET ; To zcpr3 ; ; Advance to Next Entry ; DISPL2: POP B ; Restore count and ptr to current entry POP H LDA HORIZ ; Check horiz/vert listing ORA A JNZ DISP2 ; Horizontal XCHG ; Pointer to de LHLD LINES DAD D ; Point to next entry XCHG ; New pointer to de LHLD DIREND CALL SUBDE ; Check if new ptr is within the directory XCHG ; New pointer to hl JNC DISP3 ; New pointer is ok LHLD DIRBEG ; Otherwise start new line LXI D,16 ; Next line DAD D SHLD DIRBEG ; Save it XRA A STA COUNT ; Clear column count PUSH H PUSH B CALL NEWLIN POP B POP H JMP DISP3 DISP2: LXI D,16 ; Skip to next entry DAD D DISP3: DCX B ; Count down MOV A,B ; Done? ORA C JNZ DISPLOOP LDA COUNT ; See if new line required ANI 3 CNZ CRLF ; New line if any entries on line ; ; Print Remaining Space on Disk and Exit ; PRREMAIN: ; ; Print DU ; IF VIDEO CALL STNDOUT ENDIF MVI B,8 ; Space over 8 spaces MVI A,' ' SPACER: CALL COUT DCR B JNZ SPACER CALL RETUD ; Get du in bc MOV A,B ; Print disk letter ADI 'A' ; Convert to ascii CALL COUT MOV A,C ; Print user number CALL PAFDC ; Print floating CALL PRINT ; Print separator DB ':'+80H CALL DUTDIR ; See if matching dir JZ PRREM1 ; ; Print DIR if any ; MVI B,8 ; 8 chars max PRREM0: MOV A,M ; Get char INX H ; Pt to next CPI ' ' ; Space? CNZ COUT ; Echo char DCR B ; Count down JNZ PRREM0 ; ; Print File Count ; PRREM1: LHLD FCOUNT ; Print number of files CALL PRINT DB ' --',' '+80H CALL PHLFDC ; ; Print Total of All File Sizes ; LHLD TOTCOUNT ; Print total count CALL PRINT DB ' files using',' '+80H CALL PHLFDC ; Print as floating ; ; Print Amount of Free Space Remaining ; CALL DFREE ; Compute amount of free space XCHG ; In hl CALL PRINT DB 'k ','('+80H CALL PHLFDC CALL PRINT DB 'k remain of',' '+80H CALL DSIZE CALL PHLFDC CALL PRINT DB 'k total',')'+80H IF VIDEO CALL STNDEND ENDIF RET ; ; Print New Line with Leading Space ; PRNL: CALL PRINT DB CR,LF,' '+80H ; New line with leading space RET ; ; Print Routine (String at Return Address) which is terminated by MSB ; PRINT: XTHL ; Pt to string and save hl PUSH PSW PRINT1: MOV A,M ; Get next char ANI 7FH ; Mask msb CALL COUT MOV A,M ; Get next char INX H ; Pt to next ANI 80H ; Check msb JZ PRINT1 POP PSW ; Get a XTHL ; Restore return address and hl RET ; ; DSIZE returns the size of the current disk in HL (k) ; DSIZE: PUSH D PUSH B ; MVI C,31 ; Return dpb address in hl CALL BDOS INX H INX H ; Point to bls MOV A,M ; Bls in a STA BLS INX H INX H INX H ; Point to dsm MOV E,M INX H MOV D,M ; Dsm in de INX D ; Rel 1 PUSH D ; Save dsm on stack INX H ; Point to drm INX H INX H ; Point to all0 MOV D,M INX H ; Point to all1 MOV E,M XCHG ; Allocation vector in hl LXI D,-1 ; Clear a counter DS0: INX D CALL SHLHL JC DS0 CALL SUBDE ; Get complement of count POP D ; Get dsm from stack DAD D ; Hl = groups available LDA BLS ; Block shift factor SUI 3 ; From bls in a JZ DSX DSIZ0: DAD H DCR A JNZ DSIZ0 DSX: POP B POP D RET ; ; DIVIDE divides HL by DE returning quotient in BC and remainder in HL ; Zero flag is set if no remainder ; DIVIDE: LXI B,0 ; Clear quotient DIV0: CALL SUBDE ; Subtract de from hl JC DIV1 ; Overflow INX B ; Increment quotient JMP DIV0 ; Again.. DIV1: DAD D ; Restore remainder in hl MOV A,H ; Check for remainder ORA L ; Equal zero RET ; ; SUBDE subtracts DE from HL returning carry set if de > hl ; SUBDE: MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET ; ; X16 simply shifts HL left four times ; X16: DAD H DAD H DAD H DAD H RET ; ; SHLHL shifts HL left into carry ; SHLHL: ORA A ; Reset carry MOV A,L RAL MOV L,A MOV A,H RAL MOV H,A RET ; ; SYSLIB Module Name: SDIRQS ; Author: Richard Conn ; Part of SYSLIB3 SDIR Series ; SYSLIB Version Number: 3.0 ; Module Version Number: 1.4 ; Module Entry Points: ; DIRQS ; Module External References: ; None ; ;* ;* EQUATES ;* CPM EQU 0 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 ;* DIRQS: PUSH D ; Save ptr to fcb STA SELFLG ; Save select flag for selection and alphabetization SHLD HOLD ; Set ptr to hold buffer LXI B,36 ; Allow 36 bytes DAD B ; Hl now points to temp fcb SHLD TFCB ; Set ptr to temp fcb DAD D ; Hl now pts to scratch area PUSH D ; Save ptr to fcb CALL DBUFFER ; Get ptrs POP D ; Get ptr to fcb PUSH H ; Save ptr to buffer CALL DIRLOAD ; Load directory (fast load) POP H ; Get ptr to buffer POP D ; Get ptr to fcb RZ ; Abort if tpa overflow PUSH PSW ; Save flag to indicate no tpa overflow CALL DIRALPHA ; Alphabetize POP PSW ; 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: SHLD ORDER ; Pt to order table CALL DPARAMS0 ; Get parameters LHLD DIRMAX ; Number of entries in dir XCHG ; In de LHLD ORDER ; Add to order base DAD D ; *1 CALL MEMCHK ; Check for within range DAD D ; Hl pts to dirbuf CALL MEMCHK ; Check for within range SHLD DIRBUF ; Set ptr and hl pts to directory buffer XRA A ; Ok DCR A ; Set flags (nz) RET MEMCHK: PUSH H ; Save regs PUSH D XCHG ; Next address in de LHLD BDOS+1 ; Get address of bdos MOV A,D ; Check for page overrun CMP H JNC MEMORUN ; Overrun if d>=h POP D POP H RET MEMORUN: POP D ; Restore POP H POP PSW ; Clear stack XRA 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) ;* DPARAMS0: ;* ;* VERSION 2.x OR MP/M ;* MVI C,31 ; 2.x or mp/m...request dpb CALL BDOS INX H INX H MOV A,M ; Get block shift STA BLKSHF ; Block shift factor INX H ; Get block mask MOV A,M STA BLKMSK ; Block mask INX H INX H MOV E,M ; Get max block number INX H MOV D,M XCHG INX H ; Add 1 for max number of blocks SHLD BLKMAX ; Maximum number of blocks XCHG INX H MOV E,M ; Get directory size INX H MOV D,M XCHG INX H ; Add 1 for number of entries SHLD DIRMAX ; 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: SHLD DSTART ; Set start of buffer area INX D ; Pt to file name LHLD TFCB ; Pt to tfcb MVI M,0 ; Select current disk INX H ; Pt to file name in tfcb MVI B,11 ; 11 chars DLLOOP: LDAX D ; Copy MOV M,A INX H ; Pt to next INX D DCR B ; Count down JNZ DLLOOP MVI M,'?' ; Select all extents INX H ; Pt to next char MVI M,0 INX H MVI M,'?' ; And all modules INX H MVI B,21 ; 23 chars XRA A ; Zero rest of tfcb DLLOOP1: MOV M,A ; Store zero INX H ; Pt to next DCR B ; Count down JNZ DLLOOP1 ;* ;* THIS SECTION OF CODE INITIALIZES THE COUNTERS USED ;* LXI H,0 ; Hl=0 SHLD FCOUNT0 ; Total files on disk = 0 ;* ;* NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER ;* MVI C,17 ; Search for file JMP DIRLP1 DIRLP: CALL PENTRY ; Place entry in dir JZ DIROVFL ; Memory overflow error MVI C,18 ; Search for next match DIRLP1: LHLD TFCB ; Pt to fcb XCHG CALL BDOS CPI 255 ; Done? JNZ DIRLP ;* ;* NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES ;* DIRDN: XRA A ; Load ok DCR A ; Set flags (nz) DIRDNX: LHLD FCOUNT0 ; Get total number of files MOV B,H ; In bc MOV C,L RET ;* ;* MEMORY OVERFLOW ERROR ;* DIROVFL: XRA A ; Load error JMP 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 ;* FCOUNT0=NUMBER OF FILES IN DIR SO FAR ;* ON OUTPUT, FCOUNT0=NUMBER OF FILES IN DIR SO FAR ;* A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR ;* PENTRY: RRC ; Multiply by 32 for offset computation RRC RRC ANI 60H ; A=byte offset LXI D,BUFF ; Pt to buffer entry MOV L,A ; Let hl=offset MVI H,0 DAD D ; Hl=ptr to fcb ;* ;* HL=ADR OF FCB IN BUFF ;* CALL ATTEST ; Test attributes JZ 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 JZ PEDONE ; Skip if duplicate ;* ;* COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER ;* XCHG ; Save ptr in de LHLD DIRBUF ; Pt to next entry location XCHG ; Hl pts to fcb, de pts to next entry location MVI B,ESIZE ; Number of bytes/entry CALL SDMOVE ; Copy fcb into memory buffer XCHG ; Hl pts to next entry SHLD DIRBUF ; Set ptr XCHG ; Ptr to next entry in de LHLD BDOS+1 ; Base address of bdos in hl MOV A,H ; Get base page of bdos SUI 9 ; Compute 1 page in front of base page of ccp CMP D ; Is ptr to next entry beyond this? RZ ;* INCREMENT TOTAL NUMBER OF FILES LHLD FCOUNT0 ; Total files = total files + 1 INX H SHLD FCOUNT0 ;* DONE WITH PENTRY AND NO ERROR PEDONE: XRA A ; No error DCR 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 H ; Save ptr LXI B,10 ; Pt to system attribute DAD B MOV A,M ; Get system attribute POP H ; Restore ptr ANI 80H ; Check for sys LDA SELFLG ; Get selection flag JZ ATDIR ANI 01000000B ; Check system attribute RET ATDIR: ANI 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, FCOUNT0 = 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 H ; Save ptr to entry to scan for XCHG ; Ptr in de LHLD FCOUNT0 ; Check count MOV A,H ; No entries? ORA L JZ NODUP ; No duplicate entry return MOV B,H ; Bc=number of entries MOV C,L LHLD DSTART ; Hl pts to first entry DUPELOOP: PUSH B ; Save count PUSH H ; Save ptrs PUSH D INX H ; Pt to fn INX D MVI B,11 ; Compare fn and ft CALL COMP JNZ NODUPL ; Continue looking for another entry ; DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT MOV C,M ; Extent in low order INX H INX H MOV B,M ; Module in high order PUSH B ; Save entry size a moment XCHG ; Point hl to target MOV E,M ; Extent in low order INX H INX H MOV D,M ; Module in high order POP H ; Dir in hl, target in de XCHG CALL SUBDE ; Subtract dir size from target size POP D ; Get ptrs POP H JC DUPSMALL ; Target is smaller ; NEW TARGET IS LARGER THAN STORED ENTRY XCHG ; Hl pts to target, de pts to dir entry MVI B,ESIZE ; Number of bytes to move CALL SDMOVE ; Move it ; NEW TARGET IS SMALLER THAN STORED ENTRY DUPSMALL: POP B ; Clear count from stack XRA A ; Indicate dup found POP H ; Restore ptr to entry to scan for RET ; NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY NODUPL: POP D ; Restore ptrs POP H LXI B,ESIZE ; Hl pts to current entry in buffer, so add esize to it DAD B POP B ; Get count DCX B ; Count down MOV A,B ; Check for done ORA C JNZ DUPELOOP ; NO DUPLICATE FOUND NODUP: XRA A ; Indicate dup not found DCR A ; Set flags (nz) POP H ; 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: MOV A,B ; Any files? ORA C RZ PUSH H ; Save regs PUSH D PUSH B SHLD DIRBUF ; Save ptr to directory PUSH H ; Save hl MOV H,B ; Hl=bc=file count MOV L,C SHLD N ; Set "N" POP H ;* ;* 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: XCHG ; Pointer to directory in de LHLD 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: MOV M,E ; Store low-order address INX H ; Pt to next order byte MOV M,D ; Store high-order address INX H ; Pt to next order entry PUSH H ; Save ptr LXI H,ESIZE ; Hl=number of bytes/entry DAD D ; Pt to next dir1 entry XCHG ; De pts to next entry POP H ; Get ptr to order table DCX B ; Count down MOV A,B ; Done? ORA C JNZ 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 ;* LHLD N ; Number of items to sort SHLD GAP ; Set initial gap to n for first division by 2 ;* FOR (GAP = N/2; GAP > 0; GAP = GAP/2) SRTL0: ORA A ; Clear carry LHLD GAP ; Get previous gap MOV A,H ; Rotate right to divide by 2 RAR MOV H,A MOV A,L RAR MOV L,A ;* TEST FOR ZERO ORA H JZ SDONE ; Done with sort if gap = 0 SHLD GAP ; Set value of gap SHLD I ; Set i=gap for following loop ;* FOR (I = GAP + 1; I <= N; I = I + 1) SRTL1: LHLD I ; Add 1 to i INX H SHLD I ;* TEST FOR I <= N XCHG ; I is in de LHLD N ; Get n MOV A,L ; Compare by subtraction SUB E MOV A,H SBB D ; Carry set means i > n JC SRTL0 ; Don't do for loop if i > n LHLD I ; Set j = i initially for first subtraction of gap SHLD J ;* FOR (J = I - GAP; J > 0; J = J - GAP) SRTL2: LHLD GAP ; Get gap XCHG ; In de LHLD J ; Get j MOV A,L ; Compute j - gap SUB E MOV L,A MOV A,H SBB D MOV H,A SHLD J ; J = j - gap JC SRTL1 ; If carry from subtractions, j < 0 and abort MOV A,H ; J=0? ORA L JZ SRTL1 ; If zero, j=0 and abort ;* SET JG = J + GAP XCHG ; J in de LHLD GAP ; Get gap DAD D ; J + gap SHLD JG ; Jg = j + gap ;* IF (V(J) <= V(JG)) CALL ICOMPARE ; J in de, jg in hl ;* ... THEN BREAK JC SRTL1 ;* ... ELSE EXCHANGE LHLD J ; Swap j, jg XCHG LHLD JG CALL ISWAP ; J in de, jg in hl ;* END OF INNER-MOST FOR LOOP JMP SRTL2 ;* ;* SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE ;* SDONE: LHLD N ; Number of entries MOV B,H ; In bc MOV C,L LHLD ORDER ; Ptr to ordered pointer table SHLD PTPTR ; Set ptr ptr LHLD DIRBUF ; Ptr to unordered directory SHLD PTDIR ; Set ptr dir buffer ;* FIND PTR TO NEXT DIR1 ENTRY SRTDN: LHLD PTPTR ; Pt to remaining pointers XCHG ; In de LHLD PTDIR ; Hl pts to next dir entry PUSH B ; Save count of remaining entries ;* FIND PTR TABLE ENTRY SRTDN1: LDAX D ; Get current pointer table entry value INX D ; Pt to high-order pointer byte CMP L ; Compare against dir1 address low JNZ SRTDN2 ; Not found yet LDAX D ; Low-order bytes match -- get high-order pointer byte CMP H ; Compare against dir1 address high JZ SRTDN3 ; Match found SRTDN2: INX D ; Pt to next ptr table entry DCX B ; Count down MOV A,C ; End of table? ORA B JNZ SRTDN1 ; Continue if not ;* FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT FERR$PTR: MVI E,7 ; Ring bell MVI C,2 ; Output CALL BDOS JMP 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: LHLD PTPTR ; Get ptr to next ordered entry DCX D ; De pts to low-order pointer address MOV A,M ; Make ptr to next unordered dir1 pt to buffer for STAX D ; Dir1 entry to be moved to next unordered dir1 pos INX H ; Pt to next ptr address INX D MOV A,M ; Make high point similarly STAX D ;* COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER MVI B,ESIZE ; B=number of bytes/entry LHLD HOLD ; Pt to hold buffer XCHG LHLD PTDIR ; Pt to entry PUSH B ; Save b=number of bytes/entry CALL SDMOVE POP B ;* COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION LHLD PTPTR ; Point to its pointer MOV E,M ; Get low-address pointer INX H MOV D,M ; Get high-address pointer LHLD PTDIR ; Destination address for next ordered dir1 entry XCHG ; Hl pts to entry to be moved, de pts to dest PUSH B ; Save b=number of bytes/entry CALL SDMOVE POP B XCHG ; Hl pts to next unordered dir1 entry SHLD PTDIR ; Set pointer for next loop ;* COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY LHLD PTPTR ; Get ptr to ptr to the destination MOV E,M ; Get low-address pointer INX H MOV D,M ; High-address pointer LHLD 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 LHLD PTPTR ; Pointer to current entry INX H ; Skip over it INX H SHLD PTPTR ;* COUNT DOWN POP B ; Get counter DCX B ; Count down MOV A,C ; Done? ORA B JNZ SRTDN POP B ; Restore regs POP D POP H RET ; Done ;* ;* SWAP (Exchange) the pointers in the ORDER table whose indexes are in ;* HL and DE ;* ISWAP: PUSH H ; Save hl LHLD ORDER ; Address of order table - 2 MOV B,H ; In bc MOV C,L POP H DCX H ; Adjust index to 0...n-1 from 1...n DAD H ; Hl pts to offset address indicated by index ; Of original hl (1, 2, ...) DAD B ; Hl now pts to pointer involved XCHG ; De now pts to pointer indexed by hl DCX H ; Adjust index to 0...n-1 from 1...n DAD H ; Hl pts to offset address indicated by index ; Of original de (1, 2, ...) DAD B ; Hl now pts to pointer involved MOV C,M ; Exchange pointers -- get old (de) LDAX D ; -- get old (hl) XCHG ; Switch MOV M,C ; Put new (hl) STAX D ; Put new (de) INX H ; Pt to next byte of pointer INX D MOV C,M ; Get old (hl) LDAX D ; Get old (de) XCHG ; Switch MOV M,C ; Put new (de) STAX D ; 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 H ; Save hl LHLD ORDER ; Address of order - 2 MOV B,H ; In bc MOV C,L POP H DCX H ; Adjust index to 0...n-1 from 1...n DAD H ; Double the element number to point to the ptr DAD B ; Add to this the base address of the ptr table XCHG ; Result in de DCX H ; Adjust index to 0...n-1 from 1...n DAD H ; Do the same with the original de DAD B XCHG ;* ;* 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 ;* MOV C,M ; Bc is made to point to the object indexed to INX H ; By the original hl MOV B,M XCHG MOV E,M ; De is made to point to the object indexed to INX H ; By the original de MOV D,M MOV H,B ; Set hl = object pted to indirectly by bc MOV 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