TITLE "DDDIRQS - Directory Routine with Sizing, Dslib 4.0" ;================================================================= ; Copyright (C) 1989 by Harold F. Bower. Permission granted to ; Alpha Systems Corp. to distribute with The Libraries, Version 4 ;----------------------------------------------------------------- ; Author : Harold F. Bower ; Derived from SDIRQS.Z80 Ver 1.5 by Richard Conn ; Date : 4 Oct 93 ; Version : 1.4 ; Module : DDDIRQS ; Abstract: This module contains the routine DDIRQS which is a ; general-purpose directory select routine WITH sizing and ; Time Stamp information. It Uses a Shell Sort with Pointers ; in memory to return a sorted listing of directory entries. ; Limited capability is provided to alter the sort basis. ; This routine is intended for use where sizing information ; is needed which is not provided by DDIRQ. ; Time Selection may be set to search for DateStamper in ; addition to DosDisk (MS-DOS), P2Dos or NZTIME stamps. If ; DateStamper is selected, and DateStamper is not resident, or ; no valid !!!TIME&.DAT file is found, the program defaults to ; search for DosDisk, P2Dos or NZTIME specs. The search first ; attempts to locate a DosDisk-generated flag word, and adds ; MS-DOS time in the modified field if found. If no flag word ; is found, P2Dos or NZTIME stamps are selected based on the ; signature byte at offset 60H from each Directory sector start. ; If entry conditions specify only the latter types, the search ; begins with DosDisk validation, then P2D/NZTIME if necessary. ; No defaulting to DateStamper format is provided. ; Revision: ; 1.2 - 13 Sep 88 - Initial version. HFB ; 1.3 - 5 Jan 91 - Deleted custom sort to use SYSLIB's SSORT, return ; address of pointer table, added B6 of Select flag #2 to ; control re-ordering after sort. HFB ; 1.4 - 4 Oct 93 - Added NZTime Stamp support, revised algorithm ; to: Load files, sort, delete dupes & compress. HFB ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Module Entry Points PUBLIC DDIRQS EXT FINDCK, CKTDF, OPENTD, RWTD, CLOSTD, FSTNXT ; DsLib EXT P2UTIM, M2UTIM, BIN2BCD ; " EXT BLKSHF, BLKMSK, BLKMAX, DIRMAX, SELFLG, DIRBUF ; Syslib EXT @FNCMP, @AFNCMP, GETMTOP, DPARAMS, SORT, SSBINIT ; " ; Definitions BDOS EQU 5 BUFF EQU 80H ; Default DMA Buffer SETDMA EQU 26 ; Dos command to set DMA transfer address SRCHF EQU 17 ; Dos Command to Search for First file match SRCHN EQU 18 ; Dos Command to Search for Next file match FNSIZE EQU 16 ; Size of basic File Name, Type and size info ESIZE EQU FNSIZE+15 ; 16 Bytes/Entry (+ Creat, Access & Mod Stamps) .Z80 CSEG ;=============================================================== ; NAME - DDIRQS ; Entry: HL - Points to Buffer ; DE - Points to FCB (36 chars) ; A - Contains Select character: ; Bit 7 - 1=Select Non-System Files, 0=No Non-sys ; Bit 6 - 1=Select System Files, 0=No System files ; Bit 5 - 1=Select All Users, 0=Select current users ; Bits 4-0 =Desired User Number ; C - Secondary Select character: ; Bit 7 - 1=Sort Type then Name, 0=Name then Type ; Bit 6 - 1=No Re-order after Sort (w/ptrs), 0=Reorder ; Bits 5-2 - Unused ; Bit 0 - 1=Use DateStamper Stamps, 0=Use MS/P2Dos Stamps ; Exit : A <> 0, Zero Flag Reset (NZ) If Ok ; A=0, Zero Flag Set (Z) if TPA Overflowed (err) ; BC - Contains number of files in array ; DE - Points to start of Pointer table ; HL - Points to First file in buffer ; Special Requirements: Default DMA reset to default of 80H ;=============================================================== DDIRQS: PUSH DE ; Save ptr to FCB LD (SELFLG),A ; Save Select Flag for selection and Alpha LD (TFCB),HL ; Set ptr to temp FCB LD A,C ; Get Stamp method flag BIT 0,A ; Are we going for DateStamper type? JR Z,DDIRV0 ; ..jump if P2Dos type PUSH HL ; Save regs while we test for DS Routines PUSH DE PUSH AF ; ..including flag byte in A CALL FINDCK ; Is DateStamper alive and well? JR Z,NODS ; ..jump to P2D if not CALL CKTDF ; Do we have a valid !!!TIME&.DAT file? JR Z,NODS ; ..jump to P2D if not POP AF ; Else we have everything ready for DS, Do it JR DSOK ; ..bypass defaulting to P2D and continue NODS: POP AF ; Restore flag byte AND 0FEH ; ..Mask out DS bit DSOK: POP DE ; Restore rest of regs POP HL DDIRV0: LD (S2FLG),A ; ..and save Secondary flag byte LD BC,36 ; Offset to after Temp buffer ADD HL,BC ; HL now pts to scratch area CALL DPARAMS ; Set parameters for logged disk ; Set values in the Sort Selection Block EX DE,HL ; Save in DE while we set up SSB LD HL,(DIRMAX) ; Get Max Number of DIR entries LD (FCOUNT),HL ; ..save in SSB LD HL,ESIZE ; Get Size of records LD (ELSIZ),HL ; ..save in SSB LD HL,0 ; Let SSBINIT set buffer addr LD (DSTART),HL DEC L ; (0-->FF) Use pointers for sorting BIT 6,A ; Re-order after sorting? JR Z,REORDR ; ..jump if so to show reordering (H = 0) LD H,L ; Else set for No re-order (H <> 0) REORDR: LD (PTRFLG),HL ; ..place in POINTR (L) and NOREC (H) in SSB LD HL,DICOMP ; Address User Compare routine LD (COMPIT),HL ; ..place addr in SSB EX DE,HL ; Put Memory base back in HL LD DE,SSB ; .point to SSB CALL SSBINIT ; ..and Initialize the sort routine LD (DIRBUF),HL ; Save returned Record Buffer Address POP DE ; Get ptr to FCB CALL NZ,DIRLOAD ; Load directory with Sizing Info (if space) RET Z ; Abort if TPA overflow LD DE,SSB ; Set parm for Sort routine CALL SORT ; .and do it! CALL DELDUP ; ..then Delete Duplicates, keep Stamps & Sizes LD DE,(ORDBUF) LD HL,(DSTART) ; .and load exit parms LD BC,(FCOUNT) OR 0FFH ; Set Ok status and return RET ;..... ; Build Directory Table at DIRBUF ; This is the Optimal Directory load routine; It loads unique file names from ; disk and information to compute the file sizes ; On Input : HL pts to Directory Buffer (ESIZE x N Max) ; DE pts to FCB (only 12 bytes needed) ; On Output: BC is Number 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 A,(SELFLG) BIT 5,A ; Are we selecting All users? LD A,'?' ; .(assume Yes) JR NZ,DIRLO0 ; ..jump if So XOR A ; Else set for current User DIRLO0: LD (HL),A ; Stash User selects INC HL ; Pt to File Name in TFCB LD BC,11 ; 11 chars EX DE,HL LDIR ; Copy the Name and Type EX DE,HL LD (HL),'?' ; Select all extents INC HL ; Pt to next char XOR A ; Zero rest of TFCB LD (HL),A INC HL LD (HL),'?' ; ..and all Data Modules INC HL LD B,21 ; 21 chars remain to be nulled DLLOOP1: LD (HL),A ; Store Zero INC HL ; Pt to next DJNZ DLLOOP1 ; Count down LD L,A ; Initialize counters (A has a Null) LD H,A LD (FCOUNT),HL ; Total Files on Disk = 0 ; Begin by setting default DMA address to 80H LD DE,BUFF LD C,SETDMA CALL BDOS ; Set DMA address to default ; Now we begin scanning for files to place into the Memory Buffer LD C,SRCHF ; Search for file JR DIRLP1 DIRLP: CALL PENTRY ; Place entry in Dir JR Z,DIRDNX ; Memory overflow error LD C,SRCHN ; Search for Next Match DIRLP1: LD DE,(TFCB) ; Pt to FCB CALL FSTNXT CP 0FFH ; Done? JR NZ,DIRLP ; ..loop if not LD A,(S2FLG) ; Are we loading P2D Stamps? RRA JR NC,DIRPDN ; ..jump to exit if so ; We are using DateStamper stamps, so append stamps to FN.FT string XOR A ; Open T&D for Read-only CALL OPENTD ; ..don't check errs cause CKTD was Ok LD BC,(FCOUNT) ; Load this many records LD HL,(DSTART) ; ..starting with this entry LD DE,0FFFFH ; Set dummy Random record # to force read TDLOOP: LD A,B ; Are we done? OR C JR Z,DIRDDN ; ..exit if so PUSH BC ; Save count LD BC,FNSIZE ; Offset to RR # ADD HL,BC LD A,(HL) ; Get Index # PUSH HL ; Save index to entry TD field PUSH AF ; ..and index INC HL LD A,(HL) ; Get RR # to HL INC HL LD H,(HL) LD L,A OR A ; Compare current (DE) w/desired (HL) SBC HL,DE ADD HL,DE JR Z,SAMREC ; ..jump if we already have the record EX DE,HL ; Else put desired rec in DE PUSH DE ; ..and save XOR A CALL RWTD ; Read the T&D file ignoring errors LD (TDBUF),HL ; Save TD buffer start addr JR NZ,TDRDOK ; ..jump if Read Ok LD B,128 ; Else Null out T&D Sector (A already = 0) TDNULL: LD (HL),A INC HL DJNZ TDNULL ; Loop til entire sector clear TDRDOK: POP DE ; ..and restore RR# SAMREC: POP AF ; Restore record Index ADD A,A ; ..and mult by 16 to get relative addr ADD A,A ADD A,A ADD A,A LD C,A LD B,0 LD HL,(TDBUF) ADD HL,BC ; HL Now points at source T&D string in Buffer EX DE,HL ; Swap regs.. EX (SP),HL ; ..to put RR # on stack, Dest adr in HL EX DE,HL ; ...then Dest in DE, source in HL LD BC,15 ; Move all three stamps LDIR EX DE,HL ; HL --> Next Dir entry POP DE ; DE = RR # in BUFF POP BC ; BC = Count DEC BC JR TDLOOP ; Now we are done with the Load -- Set up Return Values DIRDDN: CALL CLOSTD ; Close the T&D File for safety DIRPDN: OR 0FFH ; Load Ok and set flags to NZ DIRDNX: LD BC,(FCOUNT) ; Get total number of files to BC RET ; 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: LD (INDX),A ; Save index in case of P2Dos Stamp load PUSH DE ; Save any DS Indices PUSH BC RRCA ; Multiply by 32 for Offset computation RRCA RRCA 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) CP 20H ; Is it CP/M Plus Volume ID or T&D? JP NC,PEDONE ; ..jump if so PUSH HL ; Save the pointer LD DE,(TFCB) INC HL ; While INC DE ; we EX DE,HL ; compare LD B,11 ; FN.FT CALL @AFNCMP ; ambiguously POP HL ; Jp NZ,PEDONE ; ..jump exit if no match LD A,(SELFLG) ; Else load select flags ; HL = Adr of FCB in Buff. Check for attributes of file PUSH HL ; Save ptr LD BC,10 ; Pt to System Attribute ADD HL,BC BIT 7,(HL) ; Check for System Attribute POP HL ; Restore ptr JR Z,ATDIR ; ..jump if Not System File (Selflg in A) RLA ; Else Rotate System select bit to B7 ATDIR: BIT 7,A ; Check Normal Attribute JR Z,PEDONE ; Skip if attribute not desired ; Increment total number of files LD DE,(FCOUNT) ; Increment total number of files INC DE LD (FCOUNT),DE ; Copy FCB pted to by HL into Directory Buffer LD DE,(DIRBUF) ; DE pts to Next Entry Locn, HL pts to FCB LD BC,FNSIZE ; Number of Bytes in basic entry LDIR ; Copy FCB into Memory Buffer POP BC ; Restore any DS indices POP HL LD A,(S2FLG) ; Which method do we use? RRA JR NC,USEMS ; ..jump if using MS-DOS or P2Dos Time Stamps EX DE,HL ; Put destination in HL LD (HL),B ; stash Index into T&D Sector INC HL LD (HL),E ; ..and T&D Sector number INC HL LD (HL),D INC HL EX DE,HL ; Put Buffer pointer back in DE LD B,ESIZE-FNSIZE-3 JR FILLIT ; Null out remaining USEMS: LD HL,BUFF+16 ; Point to DosDisk Flag bytes LD A,(HL) ; Get the first byte CP 0FDH ; Is it the MS-DOS 40-track flag? JR NZ,USEP2D ; ..jump if not INC HL ; Else check second byte to be sure SUB (HL) JR NZ,USEP2D ; ..jump if no match LD B,10 ; Ok, so null Create and Access fields CALL NULLIT LD HL,BUFF+22 ; Point to source MS-DOS DateSpec CALL M2UTIM ; ..and do the conversions to DE JR P2DONE ; Continue with common code USEP2D: LD HL,BUFF+60H ; Point to P2D Time indicator LD A,(HL) AND 7FH ;1.4 .(mask diff between P2D and NZTime) CP 21H ; Is there a valid time stamp flag? JR NZ,NOTP2D ; ..jump if not P2DOS or NZTIME LD A,(INDX) ; Else calculate offset to correct entry LD C,A ADD A,A ; *2 ADD A,A ; *4 ADD A,C ; *5 ADD A,A ; *10 INC A ; +1 LD C,A ; Entries start at offset=1,11,21 decimal LD B,0 LD A,(HL) ;1.4 Get Flag Byte (A1=NZTime, 21=P2Dos) ADD HL,BC ; Point to Stamp field for desired entry RLA ;1.4 Is it NzTime? JR C,USENZT ;1.4 ..jump if NZTime Stamping CALL P2UTIM ; ..and parse Create Stamp to Table LD B,5 ; Null the Last Accessed field CALL NULLIT CALL P2UTIM ; Parse Modify Stamp JR P2DONE ; ..and continue NOTP2D: LD B,ESIZE-FNSIZE ; Set count to fill entire field FILLIT: CALL NULLIT ; Fill rest of time with Nulls P2DONE: LD (DIRBUF),DE ; Set ptr to Next Entry CALL GETMTOP ; Get top available addr in HL LD A,H ; Get base page of Bdos DEC A ; ..and move one more page down SUB D ; Is ptr to next entry beyond this? RET Z ; ..Ret 00=Overflow DEFB 11H ; Fall thru trashing DE ; Done with PENTRY and No Error PEDONE: POP BC ; Clear the stack POP DE OR 0FFH ; Set Flags for No Error (NZ) RET ; Gather File Stamps from NZTime-stamped directory USENZT: LD (IPTR),HL ;1.4 Save Pointer to input NZTime stamps LD L,(HL) ;1.4 LD A,(INDX) ;1.4 Get Index number (0,1,2) LD B,A ;1.4 .save LD A,8 ;1.4 SUB B ;1.4 Compute current byte when starting LD C,A ;1.4 save INC B ;1.4 DEC B ;1.4 Is Input byte already aligned? JR Z,USENZ1 ;1.4 ..jump if so USENZ0: ADD HL,HL ;1.4 Else rotate input byte (H is don't care) DJNZ USENZ0 ;1.4 ..looping til done USENZ1: LD A,3 ;1.4 Get all three stamps USENZ2: LD (LPCTR),A ;1.4 Set Outer Loop Counter LD B,7 ;1.4 CALL GBITS ;1.4 Get Year (7 bits) LD B,4 ;1.4 CALL GBITS ;1.4 Month (4 bits) LD B,5 ;1.4 CALL GBITS ;1.4 Day (5 bits) LD B,5 ;1.4 CALL GBITS ;1.4 Hour (5 bits) LD B,6 ;1.4 CALL GBITS ;1.4 Minute (6 bits) LD A,(LPCTR) ;1.4 DEC A ;1.4 Have we done all 3 fields? JR NZ,USENZ2 ;1.4 .loop if Not (saving new count) JR P2DONE ;1.4 ..jump to exit when finished ;..... ; Find and Delete Duplicate Entries (Extents) by copying the larger Size ; info to the first entry and moving remaining pointers or records forward. ; ENTER: FCOUNT contains # of entries, ORDBUF pts to ptr table start. ; EXIT : FCOUNT & ORDBUF updated. DELDUP: LD BC,(FCOUNT) ;1.4 Get # of entries LD HL,(ORDBUF) ;1.4 Else point to start of order Table LD A,B ;1.4 OR C ;1.4 Anything there? RET Z ;1.4 ..exit if Not PLOOP: DEC BC ;1.4 Need more than one entry LD A,B ;1.4 OR C ;1.4 Done? RET Z ;1.4 ..exit if So PUSH BC ;1.4 .(save Cntr) PUSH HL ;1.4 ..an Ptr LD E,(HL) ;1.4 Load addrs of two entries INC HL ;1.4 LD D,(HL) ;1.4 INC HL ;1.4 LD A,(HL) ;1.4 INC HL ;1.4 LD H,(HL) ;1.4 LD L,A ;1.4 LD B,12 ; Compare User Number, FN, and FT CALL @FNCMP JR NZ,NODUPP ; Continue looking for another entry ; Second entry is bigger EX or DM. Move Size info to 1st entry; LD BC,FNSIZE-12 ;1.4 Number of bytes to move (EX,RC,etc) LDIR ;1.4 Move it POP HL ;1.4 Restore Ptr into ORDBUF POP BC ;1.4 .and remaining cout PUSH BC ;1.4 .(keep on stack) RL C ;1.4 Count * 2 RL B ;1.4 PUSH HL ;1.4 .(save ptr) INC HL ;1.4 INC HL ;1.4 Avance to Base+1 and Base+2 LD E,L ;1.4 LD D,H ;1.4 .copy to DE (Base+1) INC HL ;1.4 INC HL ;1.4 ..Source in one ptr past (Base+2) LDIR ;1.4 ...move rest of ptrs up LD HL,(FCOUNT) ;1.4 Deduct one from file cout DEC HL ;1.4 LD (FCOUNT),HL ;1.4 POP HL ;1.4 POP BC ;1.4 JR PLOOP ;1.4 Loop NODUPP: POP HL ;1.4 Restore ptr POP BC ;1.4 .and Cntr INC HL ;1.4 Advance to next entry INC HL ;1.4 JR PLOOP ;1.4 ..and do more ;=============================================================== ; NAME - DICOMP ; Entry: HL - Points to one FCB extracted entry ; DE - Points to second FCB extracted entry ; Exit : F - Carry Set (C) means (DE) < (HL) ; Zero Set (Z) means (DE) = (HL) ; Non-Zero (NZ) and No Carry (NC) means (DE) > (HL) ; Uses : AF ; Special Requirements: None ;=============================================================== DICOMP: PUSH BC ; Save count LD A,(S2FLG) ; Group by File Type? RLA JR NC,CPFNFT ; Compare by File Type and File Name (in that order) PUSH HL PUSH DE LD BC,9 ; Pt to FT (8 bytes + 1 byte for User Number) ADD HL,BC EX DE,HL ADD HL,BC EX DE,HL ; DE, HL now pt to their FT'S LD B,3 ; 3 bytes CALL @FNCMP ; Compare FT'S POP DE POP HL JR NZ,CMPEX ; Continue if complete match LD B,8 ; 8 bytes JR CMPFT1 ; Compare by File Name and File Type (in that order) CPFNFT: LD B,11 ; 11 bytes for FN and FT CMPFT1: PUSH HL PUSH DE INC HL ; Pt to FN INC DE CALL @FNCMP ; Do comparison POP DE POP HL JR NZ,CMPEX LD A,(DE) ; Compare User Number CP (HL) JR NZ,CMPEX ;1.4 ..exit if No match PUSH HL ;1.4 Else save ptrs PUSH DE ;1.4 LD BC,14 ;1.4 EX DE,HL ;1.4 Swap ADD HL,BC ;1.4 .offset File 1 to DM EX DE,HL ;1.4 ..swap ADD HL,BC ;1.4 ...offset File 2 t DM LD A,(DE) ;1.4 CP (HL) ;1.4 Compare Data Modules JR NZ,CMPEX0 ;1.4 ..jump if Not Same DEC HL ;1.4 Else back down to EXT DEC HL ;1.4 DEC DE ;1.4 DEC DE ;1.4 LD A,(DE) ;1.4 Fetch EX file 1 CP (HL) ;1.4 ..compare to EX file 2 and return status CMPEX0: POP DE ;1.4 Restore regs POP HL ;1.4 CMPEX: POP BC ; Restore Count RET ; ..and exit ;..... ; NZTime Support Routine. Get # of bits spec'ed from NZTIM, Return BCD Digit ; ENTER: L = Current working byte ; DE = Ptr to Dest of Univ stamps ; C = Bit # currently in position (8..1) ; B = Number of bits to gather ; EXIT : A = BCD Conversion of # bits from entry GBITS: LD H,0 ;1.4 Clear Bit Accumulator GBITS0: ADD HL,HL ;1.4 Shift B7 of L into B0 of H, H shifts left DEC C ;1.4 Have we shifted last of input Byte? JR NZ,GBITS1 ;1.4 ..jump if Not PUSH HL ;1.4 Else need a byte, save regs LD HL,(IPTR) ;1.4 Get input ptr INC HL ;1.4 .go to next byte LD A,(HL) ;1.4 ..fetch LD (IPTR),HL ;1.4 ...save updated ptr POP HL ;1.4 .(restore regs LD L,A ;1.4 Place new Input byte for shifting LD C,8 ;1.4 and init Bits Remaining counter GBITS1: DJNZ GBITS0 ;1.4 ..Shift another if not done LD A,H ;1.4 Else get completed output byte CALL BIN2BCD ;1.4 .make BCD for Universal LD (DE),A ;1.4 ..store in Output INC DE ;1.4 ...and advance to next digit RET ;1.4 ;..... ; Fill the string addressed by DE with a zero for B bytes NULLIT: XOR A ; Load a cheap Null NULL0: LD (DE),A ; Stuff a byte INC DE ; ..and advance DJNZ NULL0 ; Loop til done RET ; Data Storage/Buffers DSEG ; Put in Data Segment IPTR: DEFS 2 ;1.4 Pointer to current NZTime Input Byte LPCTR: DEFS 1 ;1.4 Loop Counter for NZTime Conversion INDX: DEFS 1 ; Directory index into sector S2FLG: DEFS 1 ; Secondary Select Flag (Sort & Stamp method) TFCB: DEFS 2 ; Address of temporary FCB SSB: ; Sort Selection Block: DSTART: DEFS 2 ; Pointer to first Directory Entry FCOUNT: DEFS 2 ; Total Number of Files/Number of Sel Files ELSIZ: DEFS 2 ; Size of each element COMPIT: DEFS 2 ; Addr of compare routine ORDBUF: DEFS 2 ; Addr of Order buffer PTRFLG: DEFS 1 ; FF=use ptrs, 0=No ptrs DEFS 1 ; If Ptrflg<>0, FF=Don't reorder, 0=Reorder TDBUF: DEFS 2 ; Temp storage loc'n for T&D Sector Buffer adr END