; PROGRAM: FINDF ; AUTHOR: RICHARD CONN ; VERSION: 2.0 ; DATE: 18 May 84 ; PREVIOUS VERSIONS: 1.1 (25 July 83), 1.0 (24 JULY 83) ; VERS EQU 20 ;version number z3env SET 0f400h ; ; FINDF searches through all of the known disks for one or more ; files matching the passed file specification. AFNs (Ambiguous File Names) ; are permitted. FINDF is invoked by the following command line: ; FINDF afn,afn,afn,... o ; where "afn" refers to the file sought and "o" is none or more of: ; S - Include System Files ; ; ; System equates: ; BOOT EQU 0000H ;CP/M WARM BOOT JUMP VECTOR BDOS EQU BOOT+05H ;CP/M BDOS CALL JUMP VECTOR TBUFF EQU BOOT+80H ;DISK I/O BUFFER FCB EQU BOOT+5CH ;DEFAULT FILE CONTROL BLOCK CR EQU 'M'-'@' ;CTL-M FOR CARRIAGE RETURN LF EQU 'J'-'@' ;CTL-J FOR LINE FEED CTRLC EQU 'C'-'@' ;ABORT CTRLS EQU 'S'-'@' ;PAUSE ESIZE EQU 12 ;12 BYTES/DIR ENTRY ; ; SYSLIB and Z3LIB Routines ; ext z3init,codend ext cout,crlf,print,padc ; ; 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 z3init ;initialize the ZCPR3 Env and the VLIB Env LXI H,0 ;SAVE STACK PTR DAD SP SHLD STACK CALL CODEND ;DETERMINE FREE SPACE SHLD FNTAB ;FILE NAME TABLE LXI D,512 ;1/2 K SPACE DAD D SHLD SCRATCH ;BEGINNING OF SCRATCH AREA SPHL ;AND TOP OF STACK CALL GTBIOS ;GET BIOS JUMP TABLE CALL HELLO ;SIGN ON MESSAGE CALL HELPCHK ;CHECK FOR AND PRINT HELP MESSAGE CALL OPTCHK ;BUILD FILE NAME TABLE AND PROCESS OPTIONS CALL CRLF ;NEW LINE CALL FIND ;DO THE SEARCHES CALL BYE ;SIGN OFF MESSAGE RETURN: LHLD STACK ;QUIET RETURN SPHL RET ; ; ** Main Routines ** ; ; ; SAY WHO WE ARE ; HELLO: CALL PRINT DB 'FINDF, Version ' DB (VERS/10)+'0','.',(VERS MOD 10)+'0' DB 0 RET ; ; CHECK FOR HELP REQUEST ; HELPCHK: LDA FCB+1 ;GET 1ST BYTE OF FILENAME CPI '/' ;HELP? JZ HCK1 CPI ' ' ;MAKE SURE IT IS NON-BLANK RNZ ;OK - KEEP GOING ; ; IF NO FILE NAME IS SPECIFIED, ABORT WITH NOTICE ; HCK1: CALL PRINT db cr,lf,'Syntax:' DB CR,LF,' FINDF afn,afn,afn,... o' db cr,lf,'Options:' DB CR,LF,' S - Include System Files' DB 0 JMP RETURN ; ; CHECKS FOR S OPTION IN COMMAND LINE AND EXTRACTS FILE NAMES INTO TABLE ; OPTCHK: XRA A ;TURN OFF FLAGS STA SYSTEM ;NO SYSTEM FILES STA FFLAG ;NO FILES FOUND STA ECOUNT ;NO ENTRIES STA FNCOUNT ;NO FILE NAMES LHLD FNTAB ;PT TO TABLE XCHG ;... IN DE LXI H,TBUFF+1 ;SCAN THRU TBUFF, BUILDING A FILE NAME TABLE CALL SBLANK ;SKIP BLANKS FNLOOP: PUSH D ;SAVE TABLE PTR CALL GETFN ;EXTRACT FILE NAME POP D PUSH H LXI H,11 ;PT TO NEXT TABLE ENTRY DAD D XCHG POP H LDA FNCOUNT ;INCREMENT COUNT INR A STA FNCOUNT MOV A,M ;GET TERMINATING CHAR INX H ;PT TO NEXT CPI ',' ;ANOTHER FOLLOWS? JZ FNLOOP DCX H ;POINT BACK TO DELIM CALL SBLANK ;SKIP TO NON-BLANK OPTCK1: MOV A,M ;GET OPTION CALL DELCHK ;DONE IF DELIM RZ CPI 'S' ;SYSTEM? JZ OPTCKS CALL PRINT DB CR,LF,'Invalid Option -- ',0 MOV A,M CALL COUT JMP HCK1 OPTCKS: MVI A,0FFH ;SET FLAG STA SYSTEM INX H JMP OPTCK1 GETFN: PUSH D ;FILL TARGET FCB MVI B,11 ;11 BYTES MVI A,' ' ;SPACE FILL GETFN0: STAX D ;PUT SPACE INX D DCR B JNZ GETFN0 POP D ;PT TO ENTRY AGAIN CALL SCANCOL ;SCAN FOR COLON MVI B,8 ;8 CHARS MAX CALL GETFN1 ;GET AND FILL ENTRY MOV A,M ;GET CHAR CPI '.' ;DELIM? RNZ ;DONE INX H ;PT TO AFTER PERIOD MVI B,3 ;3 CHARS MAX AND DO IT AGAIN GETFN1: MOV A,M ;GET CHAR CPI '.' ;END OF FIELD? JZ GETFN3 CALL DELCHK ;CHECK DELIMITER RZ CPI '*' ;WILD? JZ GETFNQ STAX D ;STORE CHAR INX H ;PT TO NEXT INX D DCR B ;COUNT DOWN JNZ GETFN1 GETFN2: MOV A,M ;FLUSH CHARS TO DELIM CALL DELCHK ;CHECK FOR DELIMITER RZ INX H ;PT TO NEXT JMP GETFN2 GETFN3: INX D ;PT TO AFTER FIELD DCR B ;COUNT DOWN JNZ GETFN3 RET GETFNQ: MVI A,'?' ;FILL WITH QUESTION MARKS STAX D INX D DCR B JNZ GETFNQ JMP GETFN2 ;SKIP TO DELIM DELCHK: ORA A ;END OF LINE? RZ CPI '.' ;END OF FIELD? RZ CPI ',' ;END OF ENTRY? RZ CPI ' ' RET SBLANK: MOV A,M ;SKIP TO NON-BLANK CPI ' ' RNZ INX H JMP SBLANK SCANCOL: PUSH D ;SAVE TABLE PTR PUSH H ;SAVE PTR SCOL1: MOV A,M ;GET CHAR INX H ;PT TO NEXT CPI ':' ;COLON? JZ SCOLX CALL DELCHK ;CHECK FOR DELIMITER JNZ SCOL1 SCOL2: POP H ;RESTORE POP D RET SCOLX: XCHG ;DE PTS TO AFTER COLON POP H ;GET OLD PTR XCHG ;REPLACE IT POP D ;GET TABLE PTR RET ; ; LOOK THROUGH DIRECTORY ; FIND: XRA A ;SELECT FIRST DISK STA FCB CALL NXTDISK ;GET INFO THE FIRST TIME FIND1: RZ ;ABORT IF ERROR FIND2: CALL NXTSEC ;GET A DIRECTORY SECTOR JZ FIND3 ;RETURNS ZERO FLAG IF NO MORE CALL CHKENT ;CHECK IT OUT JMP FIND2 ;KEEP IT UP TILL DONE FIND3: CALL DIRALPHA ;SORT ENTRIES CALL PRFILES ;PRINT SORTED ENTRIES LDA FCB ;NEXT DISK INR A STA FCB CALL NXTDISK ;SELECT NEXT DISK JMP FIND1 ; ; SIGN OFF ; BYE: MVI C,13 ;RESET SYSTEM CALL BDOS LDA FFLAG ;GET FILE FOUND FLAG ORA A ;NO FILES FOUND? JNZ RETURN CALL PRINT DB CR,LF,'NO Files Found',0 JMP RETURN ; ; CHECKS THE CURRENT 4 DIRECTORY ENTRIES AGAINST ARGUMENT ; IF MATCH, REWRITES SECTOR WITH REACTIVATED 1ST BYTES ; CHKENT: MVI B,4 ;NUMBER OF ENTRIES PER SECTOR LXI H,TBUFF ;BEGINNING OF BUFFER CKLUP: PUSH B MOV A,M CPI 0E5H ;CHECK FOR UNUSED JZ CKINC XRA A ;A=0 STA CLPFLG ;SET FLAG FOR NO ENTRIES FOUND LDA FNCOUNT ;GET NUMBER OF FILE NAMES TO LOOK THRU MOV B,A ;... IN B PUSH H LHLD FNTAB ;PT TO TABLE XCHG ;... IN DE POP H CKLUP1: PUSH B ;SAVE COUNT PUSH H ;SAVE BEGINNING ADDRESS PUSH D CALL COMPAR ;COMPARE WITH ARGUMENT AND SAVE IF MATCH POP D LXI H,11 ;PT TO NEXT ENTRY DAD D XCHG POP H POP B DCR B ;COUNT DOWN JNZ CKLUP1 CKINC: POP B LXI D,32 ;LENGTH OF ENTRY DAD D DCR B JNZ CKLUP LHLD DIRMAX DCX H ;REDUCE SECTORS LEFT SHLD DIRMAX LHLD SECTOR ;POINT TO NEXT SECTOR INX H SHLD SECTOR XCHG LHLD MAXSEC ;REACHED LIMIT? INX H ;ONE MORE MOV A,H ;CHECK HIGH CMP D RNZ MOV A,L ;CHECK LOW CMP E RNZ LHLD TRACK ;NEXT TRACK INX H SHLD TRACK LXI H,1 ;FIRST SECTOR OF NEXT TRACK SHLD SECTOR RET ; ; COMPARE 11 BYTES OF DIRECTORY ENTRY AGAINST ARGUMENT; RNZ IF NOT MATCHED ; DE PTS TO TABLE ENTRY TO COMPARE TO ; COMPAR: LDA CLPFLG ;GET FOUND FLAG ORA A ;0=NO RNZ SHLD TEMP ;Hold pointer in case of match INX H XCHG MVI B,11 CMPR1: LDAX D ;GET DIRECTORY ENTRY CHARACTER ANI 7FH ;STRIP ANY FLAGS CMP M JZ CMPR2 MOV A,M CPI '?' RNZ CMPR2: INX D INX H ;BUMP TO NEXT CHARACTER DCR B JNZ CMPR1 ;LOOP FOR 11 CHARACTERS PUSH D ;SAVE ENTRY PTR LDAX D ;GET EXTENT IN B MOV B,A LDA EXTENT ;GET EXTENT MASK CMP B POP D ;GET ENTRY PTR JC CMPR4 ;NO MATCH LDA SYSTEM ;INCLUDE SYSTEM FILES? ORA A ;0=NO JNZ CMPR3 DCX D ;BACK UP 2 BYTES DCX D LDAX D ;GET T2 ANI 80H ;CHECK FOR SYS RNZ CMPR3: LHLD TEMP ;CHECK FOR USER LIMIT MVI A,31 ;MAX USER CMP M ;BEYOND MAX? JC CMPR4 LHLD FCOUNT ;INCREMENT COUNT INX H SHLD FCOUNT LHLD DSTART ;GET PTR TO NEXT ENTRY XCHG LHLD TEMP MVI B,ESIZE ;COPY ENTRY CALL MOVE XCHG SHLD DSTART ;PTR TO NEXT ENTRY XCHG LHLD BDOS+1 ;CHECK FOR MEMORY OVERFLOW MOV A,H SUI 10 ;BELOW CCP CMP D ;PT BEYOND LIMIT? JC MOVFL MVI A,0FFH ;SET FOUND FLAG STA FFLAG XRA A RET ;RETURNS 'ZERO' FLAG SET FOR MATCH CMPR4: MVI A,0FFH ;NO MATCH ORA A RET MOVFL: CALL PRINT DB CR,LF,'ABORT -- Not Enough Memory for Buffers',0 JMP RETURN ; ; ADVANCE TO NEXT DISK ; NXTDISK: LXI B,TBUFF ;SET DMA ADDRESS CALL SETDMA LDA FCB MOV C,A MVI B,0 CALL SELDSK ;MAKE SURE DRIVE IS MOV A,H ; SELECTED ORA L RZ ;ERROR RETURN SHLD DPH ;SAVE THE ADDRESS LXI D,10 ;PT TO DPB DAD D MOV E,M ;GET DPB ADDRESS IN HL INX H MOV D,M XCHG MOV E,M ;NUMBER OF SECTORS/TRACK INX H ;AS 2-BYTE QUANTITY IN DE MOV D,M INX H XCHG SHLD MAXSEC ;SET MAX SECTORS/TRACK XCHG INX H INX H MOV A,M ;GET EXM STA EXTENT INX H ;PT TO DRM INX H INX H MOV E,M ;GET NUMBER OF INX H ; DIRECTORY ENTRIES MOV D,M XCHG INX H ;ACCOUNT FOR - 1 SHLD DSTART ;SAVE NUMBER OF DIRECTORY ENTRIES CALL SHFHL2 ;SHIFT 'HL' RIGHT 2 SHLD DIRMAX ;SAVE NUMBER DIRECTORY SECTORS LXI H,5 ;NOW POINT TO SYSTEM DAD D ; TRACK OFFSET MOV A,M ;PICK UP NUMBER OF INX H MOV H,M MOV L,A SHLD TRACK LXI H,1 ;SET SECTOR SHLD SECTOR LDA ECOUNT ;LAST NEW LINE? ANI 3 CNZ CRLF CALL PRINT DB 'Disk ',0 LDA FCB ADI 'A' CALL COUT CALL PRINT DB ' --',CR,LF,0 LHLD SCRATCH ;PT TO SCRATCH AREA SHLD ORDER ;ADDRESS OF ORDER TABLE XCHG LHLD DSTART ;GET NUMBER OF DIRECTORY ENTRIES DAD H ;DOUBLE FOR NUMBER OF BYTES IN ORDER TABLE DAD D ;PT TO FIRST BYTE OF DIRBUF SHLD DIRBUF ;SET PTR SHLD DSTART ;SET LOOP PTR LXI H,0 ;SET FILE COUNT SHLD FCOUNT XRA A ;SET COUNT STA ECOUNT CMA ;FLIP ORA A ;OK TO CONTINUE RET ; ; GET BIOS JUMPS VECTORS FOR EASY REFERENCE ; GTBIOS: LHLD BOOT+1 ;POINTS TO BIOS JUMP TABLE+3 LXI D,WBOOT ;WHERE WE WILL KEEP A COPY MVI B,16*3 ;MOVE 48 BYTES AND FALL THRU TO MOVE ; ; GENERAL PURPOSE MOVE ROUTINE ; FROM 'HL' TO 'DE' FOR COUNT OF 8 ; MOVE: MOV A,M ;GET A BYTE STAX D ;PUT A BYTE INX D ;INCREMENT TO NEXT INX H DCR B ;COUNT DOWN JNZ MOVE RET ; ; READS NEXT SECTOR (GROUP OF FOUR DIRECTORY ENTRIES) ; RETURNS WITH ZERO FLAG SET IF NO MORE ; NXTSEC: LHLD DIRMAX ;SEE IF MORE SECTORS MOV A,H ORA L RZ ;RETURNS ZERO FLAG IF NO MORE LHLD TRACK ;SET TRACK MOV B,H MOV C,L CALL SETTRK LHLD SECTOR ;SET SECTOR MOV B,H MOV C,L CALL TRNSLT CALL SETSEC CALL READ ;READ A SECTOR ANI 1 ;REVERSE SENSE OF ERROR FLAG XRI 1 ;RETURNS WITH ZERO FLAG SET RET ;IF BAD READ ; ; PRINT FILES IN DIRBUF ; PRFILES: LHLD FCOUNT ;GET COUNT MOV A,H ;ANY? ORA L RZ MOV B,H ;COUNT IN BC MOV C,L LHLD DIRBUF ;PT TO FIRST ONE PRFLOOP: PUSH B ;SAVE COUNT PUSH H ;SAVE PTR CALL PRINTFCB ;PRINT FCB POP H ;GET REGS BACK POP B LXI D,ESIZE ;PT TO NEXT DAD D DCX B ;COUNT DOWN MOV A,B ORA C JNZ PRFLOOP MVI A,0FFH ;SET OK ORA A RET ; ; FCB PRINTING ROUTINE ; PRINTFCB: CALL PRINT ;2 SPACES DB ' ',0 MOV A,M ;GET USER NUMBER CALL PADC ;PRINT IT MVI A,':' CALL COUT INX H PR0: MVI B,8 CALL PR1 MVI A,'.' CALL COUT MVI B,3 CALL PR1 LDA ECOUNT ;INCREMENT COUNT INR A STA ECOUNT ANI 3 ;EVERY 4 CZ CRLF ;NEW LINE RET PR1: MOV A,M ANI 7FH CALL COUT INX H DCR B JNZ PR1 RET ; ; SHIFT REGS 'HL' RIGHT 2 BITS LOGICAL ; SHFHL2: CALL SHFHL ;ROTATE RIGHT 1 BIT AND FALL THRU SHFHL: XRA A ;CLEAR CARRY MOV A,H RAR ;SHIFTED BIT IN CARRY MOV H,A MOV A,L RAR MOV L,A RET ; ; TRANSLATE REG 'BC' FROM LOGICAL TO PHYSICAL SECTOR NUMBER ; TRNSLT: LHLD DPH ;GET PTR TO DPH MOV E,M ;GET ADDRESS OF XLT INX H MOV D,M CALL SECTRAN ;USE BIOS ROUTINE MOV C,L ;RETURN VALUE IN BC MOV B,H RET ; ; DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS ; THE NUMBER OF FILES IN THE DIRECTORY ; DIRALPHA: LHLD FCOUNT ; GET FILE COUNT MOV A,H ; ANY FILES? ORA L RZ SHLD N ; SET "N" MOV B,H ; BC=COUNT MOV C,L LHLD DIRBUF ; PT TO DIRECTORY ; ; 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 AND HL=ADDRESS OF FIRST ENTRY ; 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: CALL PRINT DB 0DH,0AH,'DIRALPHA -- Pointer Error',0 JMP RETURN ; 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 PTDIR ; PT TO ENTRY LXI D,HOLD ; PT TO HOLD BUFFER PUSH B ; SAVE B=NUMBER OF BYTES/ENTRY CALL MOVE 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 MOVE 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 LXI H,HOLD ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST CALL MOVE ; 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 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