* PROGRAM: RENAME * AUTHOR: RICHARD CONN * VERSION: 1.1 * DATE: 26 OCT 81 * PREVIOUS VERSIONS: 1.0 (26 OCT 81) VERS EQU 11 ; Version Number * * RENAME -- * RENAME is used to change the name of one or more files. Unlike * the CCP-resident REN function, RENAME permits ambiguous file names and * supports an Inspect mode that allows the user to confirm each rename * before it is done. * * RENAME supports the following forms: * RENAME afn1=afn2 <-- Normal Rename * RENAME afn1=afn2 /I <-- Rename with Inspect * RENAME afn1=afn2 /S <-- Include System Files * RENAME afn1=afn2 /I/S <-- Combine I and S Options * * Examples: * RENAME *.MAC=*.ASM <-- Rename all ASM files to MAC * RENAME *.MAC=*.* /I <-- Rename selected files to MAC * RENAME *.OBJ=*.COM /S <-- Rename all COM files to OBJ * (incl System Files) * * * REN CONSTANTS * DELIM EQU '/' ; OPTION DELIMITER CHAR INSP$OPT EQU 'I' ; OPTION LETTER FOR INSPECTION SYS$OPT EQU 'S' ; OPTION LETTER FOR SYSTEM FILES ENTRY$SIZE EQU 12 ; NUMBER OF BYTES/DIRECTORY ENTRY STORED * * CP/M CONSTANTS * BDOS EQU 5 ; BDOS ENTRY FCB EQU 5CH ; FIRST FCB FCB2 EQU 5CH+16 ; 2ND FCB TBUFF EQU 80H ; INPUT LINE CR EQU 0DH ; LF EQU 0AH ; ORG 100H * * SAVE OLD STACK PTR AND SET NEW * LXI H,0 ; SAVE STACK PTR DAD SP SHLD STACK ; SAVE SP IN BUFFER LXI SP,STACK ; RESET STACK PTR * * PRINT PROGRAM NAME * CALL PRINT$MESSAGE DB 'RENAME Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB 0 * * CHECK FOR USER-SPECIFIED DRIVE AND LOG IN IF SELECTED * LDA FCB ; GET FROM FCB BYTE STA UDRIVE ; SET FLAG ORA A ; 0=DEFAULT JZ REN1 DCR A ; ADJUST FOR LOGIN PUSH PSW ; SAVE A MVI C,25 ; GET CURRENT DISK CALL BDOS INR A ; ADJUST TO 1-16 STA UDRIVE ; SET FLAG POP PSW ; GET NEW DISK MOV E,A ; NUMBER IN E MVI C,14 ; SELECT DRIVE CALL BDOS JMP REN1 * * RETURN TO OS * RETURN: LDA UDRIVE ; GET SELECTED DRIVE ORA A ; 0=DEFAULT JZ RETURN1 DCR A ; ADJUST TO 0-15 MOV E,A MVI C,14 ; SELECT DISK CALL BDOS RETURN1: LHLD STACK ; GET ORIGINAL STACK PTR SPHL ; SET IT RET ; RETURN TO OS * * CONTINUE PROCESSING * REN1: XRA A ; A=0 STA INSP$FLAG ; CLEAR INSPECT FLAG STA SYS$FLAG ; CLEAR SYSTEM FLAG LXI H,TBUFF ; PT TO INPUT LINE MOV B,M ; CHAR COUNT IN B MOV A,B ; CHECK FOR EMPTY LINE ORA A ; 0 CHARS = HELP JNZ REN2 * * PRINT REN HELP MESSAGE * REN$HELP: CALL PRINT$MESSAGE DB CR,LF,'RENAME is invoked by a command of the form:' DB CR,LF,' RENAME afn1=afn2 <-- Rename all matches' DB CR,LF,' \ \__ Old File Name' DB CR,LF,' \__ New File Name' DB CR,LF,' RENAME afn1=afn2 /I <-- Inspect mode' DB CR,LF,' RENAME afn1=afn2 /S <-- Include System Files' DB CR,LF,'Note: /I and /S Options may be combined' DB CR,LF DB CR,LF,' Examples:' DB CR,LF,' RENAME *.MAC=*.ASM <-- Rename *.ASM to *.MAC' DB CR,LF,' RENAME *.MAC=*.* /I <-- Rename *.* to *.MAC with' DB ' inspection' DB CR,LF,' RENAME *.OBJ=*.COM /I/S <-- Rename *.COM to *.OBJ ' DB 'with both I and S' DB 0 JMP RETURN * * CONTINUE PROCESSING * REN2: INX H ; PT TO FIRST CHAR MOV A,M ; GET IT CPI DELIM ; OPTION? JNZ REN3 DCR B ; COUNT DOWN JZ REN$HELP INX H ; PT TO NEXT MOV A,M ; GET OPTION CHAR CPI SYS$OPT ; INCLUDE SYSTEM FILES? JZ REN$SYS CPI INSP$OPT ; INSPECT? JNZ REN$HELP ; HELP OTHERWISE MVI A,0FFH ; SET FLAG STA INSP$FLAG JMP REN3 REN$SYS: MVI A,0FFH ; SET FLAG STA SYS$FLAG REN3: DCR B ; COUNT DOWN JNZ REN2 INX H ; PT TO AFTER LAST CHAR MVI M,0 ; STORE ENDING 0 CALL EXTRACT$SRC ; LOAD 2ND FILE NAME INTO FCB2 * * CHECK FOR FILE NAME SPECIFIED * LDA FCB+1 ; GET FIRST LETTER OF FILE NAME CPI DELIM ; DELIMITER CAUGHT? JZ FN$ERR CPI ' ' ; NO FILE SPECIFIED? JZ FN$ERR LDA FCB2+1 ; GET FIRST BYTE OF NAME CPI DELIM ; OPTION CAUGHT? JZ FN$ERR CPI ' ' ; EMPTY? JZ FN$ERR JMP REN4 FN$ERR: CALL PRINT$MESSAGE DB CR,LF,'ERROR -- File Name not specified' DB CR,LF,' Error FCB: ',0 LXI H,FCB ; PRINT ERROR CALL PRINT$FN MVI A,'=' CALL CHAR$OUT LXI H,FCB2 CALL PRINT$FN JMP RETURN * * COPY 2ND FCB INTO DESTINATION BUFFER * REN4: LXI H,FCB2 ; PT TO FCB2 LXI D,FCB$SRC ; PT TO FCB$SRC MVI B,12 ; COPY 12 BYTES CALL MOVE XCHG ; FILL IN REST MVI B,24 ; EMPTY XRA A ; A=0 CALL FILL * * ALL SET TO GO -- * FCB CONTAINS FILE NAME/TYPE * FCB$SRC CONTAINS SOURCE FILE NAME/TYPE * INSP$FLAG IS SET CORRECTLY * * LOAD DIRECTORY INTO DIR1 BUFFER DIR: LXI H,ENDALL ; PT TO END OF PROGRAM SHLD DIR1 ; AND SET PTR TO DIR1 LXI H,0 ; HL=0 SHLD FILE$COUNT ; TOTAL SELECTED FILES = 0 DIR$USER: MVI C,17 ; SEARCH FOR FILE LXI D,FCB$SRC ; PT TO FILE NAME CALL BDOS CPI 255 ; NO MATCH? JZ DIR$LOOP1 DIR$LOOP: CALL PUT$ENTRY ; PLACE ENTRY IN DIR MVI C,18 ; SEARCH FOR NEXT MATCH CALL BDOS CPI 255 ; DONE? JNZ DIR$LOOP * CHECK FOR ANY SELECTIONS DIR$LOOP1: LHLD FILE$COUNT ; GET COUNT MOV A,H ; ZERO? ORA L JNZ COMP$ORDER CALL PRINT$MESSAGE DB CR,LF,'No Files Selected -- Aborting' DB CR,LF,' Selected FCB: ',0 LXI H,FCB$SRC ; PRINT FILE NAME CALL PRINT$FN JMP RETURN * COMPUTE POINTER TO ORDER TABLE COMP$ORDER: MVI B,ENTRY$SIZE-1 ; B=NUMBER OF BYTES/ENTRY-1 MOV D,H ; DE=HL=NUMBER OF ENTRIES MOV E,L COMP$ORDER$LOOP: DAD D ; HL=HL+DE DCR B ; COUNT DOWN JNZ COMP$ORDER$LOOP XCHG ; DE=NUMBER OF BYTES OCCUPIED BY ENTRIES LHLD DIR1 ; HL PTS TO FIRST ENTRY DAD D ; HL PTS TO AFTER LAST ENTRY INR H ; HL PTS TO NEXT PAGE MVI L,0 SHLD ORDER ; ORDER PTR SET * ALPHABETIZE DIRECTORY ENTRIES CALL ALPHABETIZE * SET RENECTION ATTRIBUTES CALL RENAME * RETURN TO CP/M JMP RETURN * * EXTRACT SOURCE FILE NAME AND PLACE IN FCB2 * EXTRACT$SRC: LXI H,FCB2 ; CLEAR FCB2 MVI M,0 ; STORE BEGINNING ZERO INX H ; PT TO FIRST BYTE OF FILE NAME MVI A,' ' ; FILL MVI B,11 ; 11 BYTES CALL FILL * LOOK FOR = DELIMITER LXI H,TBUFF ; LOOK FOR = ES1: MOV A,M ; GET CHAR INX H ; PT TO NEXT ORA A ; ERROR IF END OF LINE JZ FORMAT$ERR CPI '=' ; EQUAL? JNZ ES1 * PLACE FILE NAME INTO FCB2 LXI D,FCB2+1 ; PT TO FIRST CHAR OF FCB2 FILE NAME MVI B,8 ; UP TO 8 CHARS CALL PUT$CHARS ; COPY HL TO DE CPI '.' ; MUST BE SEPARATED BY DECIMAL DELIMITER RNZ LXI D,FCB2+9 ; PT TO FIRST CHAR OF FCB2 FILE TYPE MVI B,3 ; UP TO 3 CHARS CALL PUT$CHARS ; COPY HL TO DE RET * FORMAT ERROR MESSAGE FORMAT$ERR: CALL PRINT$MESSAGE DB CR,LF,'Format Error -- Missing =',0 JMP RETURN * * COPY HL TO DE FOR UP TO B BYTES * RECOGNIZE DELIMITERS OF '.', ' ', AND 0 * EXPAND * * PUT$CHARS: MOV A,M ; GET CHAR INX H ; PT TO NEXT CPI '.' ; DELIMITER? RZ CPI ' ' ; DELIMITER? RZ ORA A ; DELIMITER? RZ CPI '*' ; EXPAND? JZ PUT$CHARSX STAX D ; STORE CHAR INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ PUT$CHARS MOV A,M ; GET NEXT CHAR INX H ; PT TO CHAR AFTER RET PUT$CHARSX: MVI A,'?' ; '?' FILL STAX D ; PUT CHAR INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ PUT$CHARSX MOV A,M ; GET CHAR AFTER '*' INX H ; PT TO CHAR AFTER THAT RET * * PLACE ENTRY IN DIR1 IF: * 1 -- NOT AN ERASED ENTRY * 2 -- SELECTED USER NUMBER * 3 -- MATCHES SPECIFICATION FCB * 4 -- ATTRIBUTES CORRESPOND * * ON INPUT, A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB * FILE$COUNT=NUMBER OF SELECTED FILES * ON OUTPUT, FILE$COUNT=NUMBER OF SELECTED FILES * PUT$ENTRY: PUSH PSW ! PUSH B ! PUSH D ! PUSH H RRC ; MULTIPLY BY 32 FOR OFFSET COMPUTATION RRC RRC ANI 60H ; A=BYTE OFFSET LXI D,TBUFF ; PT TO BUFFER ENTRY MOV L,A ; LET HL=OFFSET MVI H,0 DAD D ; HL=PTR TO FCB MOV A,M ; GET USER NUMBER CPI 0E5H ; DELETED? JZ PE4 ; SKIP IT IF DELETED XCHG ; DE=PTR TO FCB PUSH D ; SAVE IT LHLD FILE$COUNT ; GET NUMBER OF ENTRIES SO FAR SHLD ECOUNTER MOV A,H ; NONE? ORA L ; ZERO FLAG SET IF SO LHLD DIR1 ; PT TO DIR1 JZ PE2 ; IF NO ENTRIES, THIS IS THE FIRST LXI D,ENTRY$SIZE ; HL PTS TO DIR1 BASE, DE=NUMBER OF BYTES/ENTRY PE1: DAD D ; PT TO NEXT CALL ECOUNT ; ECOUNTER=ECOUNTER-1 JNZ PE1 PE2: POP D ; DE PTS TO FCB TO PLACE IN DIR1 XCHG * * ON INPUT, DE=ADR TO PLACE ENTRY IN DIR1 * HL=ADR OF FCB IN BUFF * * COMPARE ENTRY AGAINST FILE SELECTION FCB PE2$COMP: PUSH H ; SAVE HL, DE PTRS PUSH D MVI B,11 ; 11 BYTES IN FILE NAME AND FILE TYPE LXI D,FCB$SRC+1 ; PT TO FILE NAME IN FCB INX H ; PT TO FILE NAME OF ENTRY * COMPARISON LOOP PE2$COMP1: LDAX D ; GET FCB BYTE ANI 7FH ; MASK MSB CPI '?' ; WILD? JZ PE2$COMP2 MOV C,A ; SAVE BYTE MOV A,M ; GET ENTRY BYTE ANI 7FH ; MASK MSB CMP C ; COMPARE JZ PE2$COMP2 ; MATCH POP D ; RESTORE DE, HL POP H JMP PE4 ; ABORT PE2$COMP2: INX H ; PARTIAL MATCH -- PT TO NEXT INX D DCR B ; COUNT DOWN JNZ PE2$COMP1 POP D ; RESTORE DE, HL POP H * ENTRY COMPLETELY ACCEPTED -- HL PTS TO ENTRY, DE PTS TO DIRECTORY PE2$COPY: PUSH H ; SAVE PTR LXI B,12 ; CHECK FOR ZERO EXTENT DAD B ; HL PTS TO EXTENT MOV A,M ; GET EXTENT POP H ; RESTORE HL ORA A ; ZERO? JNZ PE4 ; ABORT IF NOT * CHECK FOR SYSTEM FILE INCLUSION AND DO OR DON'T DEPENDING LDA SYS$FLAG ; GET FLAG ORA A ; 0=NO JNZ PE3 ; INCLUDE ALL IF YES PUSH H ; SAVE PTR LXI B,10 ; CHECK FOR SYSTEM ATTRIBUTE DAD B ; HL PTS TO SYSTEM ATTRIBUTE MOV A,M ; GET ATTRIBUTE BYTE POP H ; RESTORE PTR ANI 80H ; SELECT BIT JNZ PE4 ; ABORT IF SYSTEM ATTRIBUTE SET * FILE ACCEPTED -- COPY IT PE3: MVI B,ENTRY$SIZE ; B=NUMBER OF BYTES/ENTRY CALL MOVE ; COPY INTO DIRECTORY * INCREMENT FILE COUNT LHLD FILE$COUNT ; INCREMENT FILE COUNT INX H SHLD FILE$COUNT * DONE WITH PUT$ENTRY PE4: POP H ! POP D ! POP B ! POP PSW RET * * COUNT DOWN WITH 16-BIT COUNTER ECOUNTER; SET ZERO FLAG IF IT HITS ZERO * ECOUNT: PUSH H ; SAVE HL LHLD ECOUNTER ; GET COUNT DCX H ; COUNT DOWN SHLD ECOUNTER ; NEW COUNT MOV A,H ; ZERO? ORA L ; ZERO FLAG SET IF SO POP H ; RESTORE HL RET * * ALPHABETIZE -- ALPHABETIZES DIR1; FILE$COUNT CONTAINS * THE NUMBER OF FILES IN DIR1 * ALPHABETIZE: LHLD FILE$COUNT ; GET FILE COUNT MOV A,H ; ANY ENTRIES? ORA L RZ * * SHELL SORT -- * THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS" * BY KERNIGAN AND PLAUGHER, PAGE 106. COPYRIGHT, 1976, ADDISON-WESLEY. * ON ENTRY, HL=NUMBER OF ENTRIES * SORT: MOV B,H ; COUNT IN BC MOV C,L LHLD DIR1 ; SET UP POINTERS TO DIRECTORY ENTRIES XCHG ; ... 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,ENTRY$SIZE ; 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 FILE$COUNT ; 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) SRT$LOOP0: 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 SORT$DONE ; 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) SRT$LOOP1: LHLD I ; ADD 1 TO I INX H SHLD I * TEST FOR I <= N XCHG ; I IS IN DE LHLD FILE$COUNT ; GET N MOV A,L ; COMPARE BY SUBTRACTION SUB E MOV A,H SBB D ; CARRY SET MEANS I > N JC SRT$LOOP0 ; 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) SRT$LOOP2: 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 SRT$LOOP1 ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT MOV A,H ; J=0? ORA L JZ SRT$LOOP1 ; 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 SRT$LOOP1 * ... 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 SRT$LOOP2 * * SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE * SORT$DONE: LHLD FILE$COUNT ; NUMBER OF ENTRIES MOV B,H ; ... IN BC MOV C,L LHLD ORDER ; PTR TO ORDERED POINTER TABLE SHLD PTPTR ; SET PTR PTR LHLD DIR1 ; PTR TO UNORDERED DIRECTORY SHLD PTDIR1 ; SET PTR DIR1 * FIND PTR TO NEXT DIR1 ENTRY SRTDN: LHLD PTPTR ; PT TO REMAINING POINTERS XCHG ; ... IN DE LHLD PTDIR1 ; HL PTS TO NEXT DIR1 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 XDIR ERROR; POINTER TABLE NOT CONSISTENT FERR$PTR: CALL PRINT$MESSAGE DB CR,LF,'RENAME ERROR -- Pointer Table Not Consistent',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,ENTRY$SIZE ; B=NUMBER OF BYTES/ENTRY LHLD PTDIR1 ; 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 PTDIR1 ; 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 PTDIR1 ; 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