home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol108 / ssort.mac < prev    next >
Encoding:
Text File  |  1984-04-29  |  13.3 KB  |  565 lines

  1. ;
  2. ; SYSLIB Module Name:  SSORT
  3. ; Author:  Richard Conn
  4. ; SYSLIB Version Number:  2.5
  5. ; Module Version Number:  1.1
  6. ; Module Entry Points:
  7. ;    SSBINI        SORT
  8. ; Module External References:
  9. ;    MOVEB        PRINT
  10. ;
  11. ;*
  12. ;*  EXTERNALS
  13. ;*
  14.     EXT    MOVEB
  15.     EXT    PRINT
  16.  
  17. ;*
  18. ;*  BASIC EQUATES
  19. ;*
  20. CPM    EQU    0    ; CP/M WARM BOOT
  21. BIOS    EQU    CPM+1    ; BIOS BASE ADDRESS
  22. BDOS    EQU    CPM+5    ; BDOS ENTRY POINT
  23. ESIZE    EQU    16    ; NUMBER OF BYTES/ENTRY IN MEMORY BUFFER
  24. BUFF    EQU    CPM+80H    ; DEFAULT DMA BUFFER
  25.  
  26. ;*
  27. ;*  SSBINI -- Initialize SSB
  28. ;*    This routine sets the value of FIRSTP and ORDER for the SORT
  29. ;* routine.  On Entry, HL pts to first available byte after user's
  30. ;* program (beginning of buffer area) and DE pts to an SSB.  On exit,
  31. ;* HL pts to first available byte for the user's in-memory data file
  32. ;* (same address as FIRSTP).  If the TPA is overflowed by the ORDER
  33. ;* table that would be generated by SORT, then the Z flag is returned set
  34. ;* (Z); if no error, NZ is returned.
  35. ;*    If the user has already loaded his data and just wants to
  36. ;* allocate an ORDER table, then he should have HL before calling SSBINI,
  37. ;* restore HL upon return from SSBINI, and then store HL into his FIRSTP
  38. ;* entry before calling SORT.
  39. ;*
  40. SSBINI::
  41.     PUSH    D    ; SAVE REGS
  42.     PUSH    B
  43.     PUSH    H    ; SAVE NEXT AVAILABLE BYTE ADDRESS
  44.     XCHG        ; MAKE HL PT TO USER'S SSB
  45.     SHLD    USRSSB    ; SAVE PTR TO USER'S SSB
  46.     LXI    D,SSB    ; COPY INTO MY SSB
  47.     MVI    B,12    ; 12 BYTES
  48.     CALL    MOVEB
  49.     POP    H    ; GET NEXT AVAILABLE BYTE ADDRESS
  50.     SHLD    ORDER    ; SET PTR TO IT
  51.     LHLD    RECNT    ; GET NUMBER OF RECORDS
  52.     MOV    A,L    ; DOUBLE IT WITH ERROR CHECKING
  53.     ADD    L
  54.     MOV    L,A
  55.     MOV    A,H
  56.     ADC    H
  57.     MOV    H,A
  58.     JC    SSBOVFL    ; OVERFLOW IF CARRY
  59.     XCHG        ; SIZE OF ORDER TABLE IN DE
  60.     LHLD    ORDER    ; BASE ADDRESS OF ORDER TABLE IN HL
  61.     MOV    A,L    ; ADD HL TO DE WITH ERROR CHECKING
  62.     ADD    E
  63.     MOV    L,A
  64.     MOV    A,H
  65.     ADC    D
  66.     MOV    H,A    ; HL IS NOW ADDRESS OF BYTE AFTER ORDER TABLE
  67.     JC    SSBOVFL    ; OVERFLOW IF CARRY
  68.     SHLD    FIRSTP    ; SET PTR TO NEXT AVAILABLE BYTE
  69.     LHLD    USRSSB    ; PT TO USER'S SSB
  70.     XCHG        ; ... IN DE
  71.     LXI    H,SSB    ; PT TO USER'S NEW SSB
  72.     MVI    B,12    ; COPY IT BACK
  73.     CALL    MOVEB
  74.     POP    B    ; RESTORE REGS
  75.     POP    D
  76.     LHLD    FIRSTP    ; PT TO NEXT AVAILABLE MEMORY ADDRESS
  77.     MVI    A,0FFH    ; SET NO ERROR CODE
  78.     ORA    A
  79.     RET
  80. SSBOVFL:
  81.     POP    B    ; RESTORE REGS
  82.     POP    D
  83.     LHLD    ORDER    ; RESTORE PTR TO USER'S BUFFER
  84.     XRA    A    ; ERROR CODE
  85.     RET
  86. USRSSB:
  87.     DS    2    ; BUFFER FOR ADDRESS OF USER'S SSB
  88.  
  89. ;*
  90. ;*  SORT -- Sort memory-resident file of fixed-length records in an order
  91. ;*    specified by the user;  On entry, DE pts to a SORT Specification
  92. ;*    Block (SSB) which contains the following information:
  93. ;*
  94. ;*        Bytes 0&1:  Starting Address of File (1st byte of 1st record)
  95. ;*        Bytes 2&3:  Number of Records in the File
  96. ;*        Bytes 4&5:  Size of Each Record (in Bytes)
  97. ;*        Bytes 6&7:  Address of a Compare Routine Provided by the User
  98. ;*                This routine compares two records, one pted
  99. ;*                to by HL and the other pted to by DE; if the
  100. ;*                record pted to by DE is less in sorting order
  101. ;*                than that pted to by HL, this routine returns
  102. ;*                with Carry Set (C); if the records are equal
  103. ;*                in sorting order, this routine returns with
  104. ;*                Zero Set (Z); no registers asside from the PSW
  105. ;*                are to be affected by this routine
  106. ;*        Bytes 8&9:  Address of ORDER Buffer (RECNT*2 in size)
  107. ;*        Byte 10:  Flag; 0 means to use pointers, 0FFH means to not
  108. ;*                use pointers
  109. ;*        Byte 11:  Unused
  110. ;*
  111. ;*    SORT does not have any net affect on any registers
  112. ;*
  113.  
  114. ;
  115. ;  SORT SPECIFICATION BLOCK (SSB) FOR USE BY SORT ROUTINE
  116. ;
  117. SSB:
  118. FIRSTP:
  119.     DS    2    ; POINTER TO FIRST RECORD IN FILE
  120. RECNT:
  121.     DS    2    ; NUMBER OF RECORDS IN FILE
  122. RECSIZ:
  123.     DS    2    ; SIZE OF EACH RECORD
  124. CMPADR:
  125.     DS    2    ; ADDRESS OF COMPARE ROUTINE
  126. ORDER:
  127.     DS    2    ; ADDRESS OF ORDER TABLE
  128. SFLAG:
  129.     DS    1    ; USE POINTERS? 0=NO
  130.     DS    1    ; UNUSED, BUT RESERVED, AT THIS TIME
  131.  
  132. ;
  133. ;  SORT AND POINTER BUFFERS
  134. ;
  135. N:
  136.     DS    2    ; NUMBER OF RECS
  137. GAP:
  138.     DS    2    ; VARIABLE GAP
  139. J:
  140.     DS    2    ; REC PTR 1
  141. JG:
  142.     DS    2    ; REC PTR 2
  143. IDX:
  144.     DS    2    ; INDEX PTR
  145. PTPTR:
  146.     DS    2    ; 2-LEVEL INDIRECT PTR
  147. PTFIL:
  148.     DS    2    ; REC PTR
  149.  
  150. ;*
  151. ;*  START OF SORT ROUTINE
  152. ;*
  153. SORT::
  154.     PUSH    H    ; SAVE REGS
  155.     PUSH    D
  156.     PUSH    B
  157.     PUSH    PSW
  158.     XCHG        ; PTR IN HL
  159.     LXI    D,SSB    ; COPY HIS SORT BLOCK INTO MINE FOR EASIER ACCESS
  160.     MVI    B,12    ; 12 BYTES LONG
  161.     CALL    MOVEB
  162.     LHLD    RECNT    ; GET RECORD COUNT
  163.     SHLD    N    ; SET "N"
  164.     MOV    B,H    ; ... IN BC
  165.     MOV    C,L
  166.  
  167. ;*
  168. ;*  CHECK FOR TRIVIAL CASE - 0 OR 1; DON'T DO IT IF SO
  169. ;*
  170.     MOV    A,B    ; SEE IF BC=1
  171.     ORA    A    ; B=0?
  172.     JNZ    SHELL    ; DO SORT IF B<>0
  173.     MOV    A,C    ; C=0 OR 1?
  174.     CPI    2
  175.     JC    SEXIT
  176.  
  177. ;*
  178. ;*  SHELL SORT --
  179. ;*    THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
  180. ;*    BY KERNIGAN AND PLAUGHER, PAGE 106.  COPYRIGHT, 1976, ADDISON-WESLEY.
  181. ;*  ON ENTRY, BC=NUMBER OF ENTRIES
  182. ;*
  183. SHELL:
  184.     LDA    SFLAG    ; USE POINTERS?
  185.     ORA    A    ; 0=NO
  186.     JZ    SORT2
  187.     LHLD    FIRSTP    ; PT TO FIRST RECORD
  188.     XCHG        ; POINTER TO 1ST RECORD IN DE
  189.     LHLD    ORDER    ; PT TO ORDER TABLE
  190. ;*
  191. ;*  SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT
  192. ;*    REC IN FILE, BC = NUMBER OF RECS REMAINING
  193. ;*
  194. SORT1:
  195.     MOV    A,B    ; DONE?
  196.     ORA    C    ; 0 IF SO
  197.     JZ    SORT2
  198.     DCX    B    ; COUNT DOWN
  199.     MOV    M,E    ; STORE LOW-ORDER ADDRESS
  200.     INX    H    ; PT TO NEXT ORDER BYTE
  201.     MOV    M,D    ; STORE HIGH-ORDER ADDRESS
  202.     INX    H    ; PT TO NEXT ORDER ENTRY
  203.     PUSH    H    ; SAVE PTR
  204.     LHLD    RECSIZ    ; HL=NUMBER OF BYTES/ENTRY
  205.     DAD    D    ; PT TO NEXT DIR1 ENTRY
  206.     XCHG        ; DE PTS TO NEXT ENTRY
  207.     POP    H    ; GET PTR TO ORDER TABLE
  208.     JMP    SORT1
  209. ;*
  210. ;*  THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P
  211. ;*
  212. SORT2:
  213.     LHLD    N    ; NUMBER OF ITEMS TO SORT
  214.     SHLD    GAP    ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2
  215.  
  216. ;*  FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
  217. SRTL0:
  218.     ORA    A    ; CLEAR CARRY
  219.     LHLD    GAP    ; GET PREVIOUS GAP
  220.     MOV    A,H    ; ROTATE RIGHT TO DIVIDE BY 2
  221.     RAR
  222.     MOV    H,A
  223.     MOV    A,L
  224.     RAR
  225.     MOV    L,A
  226.  
  227. ;*  TEST FOR ZERO
  228.     ORA    H
  229.     JZ    SDONE    ; DONE WITH SORT IF GAP = 0
  230.  
  231.     SHLD    GAP    ; SET VALUE OF GAP
  232.     SHLD    IDX    ; SET I=GAP FOR FOLLOWING LOOP
  233.  
  234. ;*  FOR (I = GAP + 1; I <= N; I = I + 1)
  235. SRTL1:
  236.     LHLD    IDX    ; ADD 1 TO I
  237.     INX    H
  238.     SHLD    IDX
  239.  
  240. ;*  TEST FOR I <= N
  241.     XCHG        ; I IS IN DE
  242.     LHLD    N    ; GET N
  243.     MOV    A,L    ; COMPARE BY SUBTRACTION
  244.     SUB    E
  245.     MOV    A,H
  246.     SBB    D    ; CARRY SET MEANS I > N
  247.     JC    SRTL0    ; DON'T DO FOR LOOP IF I > N
  248.  
  249.     LHLD    IDX    ; SET J = I INITIALLY FOR FIRST SUBTRACTION OF GAP
  250.     SHLD    J
  251.  
  252. ;*  FOR (J = I - GAP; J > 0; J = J - GAP)
  253. SRTL2:
  254.     LHLD    GAP    ; GET GAP
  255.     XCHG        ; ... IN DE
  256.     LHLD    J    ; GET J
  257.     MOV    A,L    ; COMPUTE J - GAP
  258.     SUB    E
  259.     MOV    L,A
  260.     MOV    A,H
  261.     SBB    D
  262.     MOV    H,A
  263.     SHLD    J    ; J = J - GAP
  264.     JC    SRTL1    ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT
  265.     MOV    A,H    ; J=0?
  266.     ORA    L
  267.     JZ    SRTL1    ; IF ZERO, J=0 AND ABORT
  268.  
  269. ;*  SET JG = J + GAP
  270.     XCHG        ; J IN DE
  271.     LHLD    GAP    ; GET GAP
  272.     DAD    D    ; J + GAP
  273.     SHLD    JG    ; JG = J + GAP
  274.  
  275. ;*  IF (V(J) <= V(JG))
  276.     CALL    ICOMPARE    ; J IN DE, JG IN HL
  277.  
  278. ;*  ... THEN BREAK
  279.     JC    SRTL1
  280.  
  281. ;*  ... ELSE EXCHANGE
  282.     LHLD    J    ; SWAP J, JG
  283.     XCHG
  284.     LHLD    JG
  285.     CALL    ISWAP    ; J IN DE, JG IN HL
  286.  
  287. ;*  END OF INNER-MOST FOR LOOP
  288.     JMP    SRTL2
  289.  
  290. ;*
  291. ;*  SORT IS DONE -- RESTRUCTURE FILE IN SORTED ORDER IN PLACE
  292. ;*
  293. SDONE:
  294.     LDA    SFLAG    ; USE POINTERS?
  295.     ORA    A    ; 0=NO
  296.     JZ    SEXIT    ; DONE IF NO POINTERS
  297.     LHLD    RECNT    ; NUMBER OF RECORDS
  298.     SHLD    J    ; SAVE COUNT IN J
  299.     LHLD    ORDER    ; PTR TO ORDERED POINTER TABLE
  300.     SHLD    PTPTR    ; SET PTR PTR
  301.     LHLD    FIRSTP    ; PTR TO UNORDERED FILE
  302.     SHLD    PTFIL    ; SET PTR TO FILE BUFFER
  303.  
  304. ;*  FIND PTR TO NEXT FILE ENTRY
  305. SRTDN:
  306.     LHLD    J    ; GET ENTRY COUNT
  307.     MOV    B,H    ; ... IN BC
  308.     MOV    C,L
  309.     LHLD    PTPTR    ; PT TO REMAINING POINTERS
  310.     XCHG        ; ... IN DE
  311.     LHLD    PTFIL    ; HL PTS TO NEXT FILE ENTRY
  312.  
  313. ;*  FIND PTR TABLE ENTRY
  314. SRTDN1:
  315.     LDAX    D    ; GET CURRENT POINTER TABLE ENTRY VALUE
  316.     INX    D    ; PT TO HIGH-ORDER POINTER BYTE
  317.     CMP    L    ; COMPARE AGAINST FILE ADDRESS LOW
  318.     JNZ    SRTDN2    ; NOT FOUND YET
  319.     LDAX    D    ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE
  320.     CMP    H    ; COMPARE AGAINST FILE ADDRESS HIGH
  321.     JZ    SRTDN3    ; MATCH FOUND
  322. SRTDN2:
  323.     INX    D    ; PT TO NEXT PTR TABLE ENTRY
  324.     DCX    B    ; COUNT DOWN
  325.     MOV    A,C    ; END OF TABLE?
  326.     ORA    B
  327.     JNZ    SRTDN1    ; CONTINUE IF NOT
  328.  
  329. ;*  FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT
  330. FERR$PTR:
  331.     CALL    PRINT
  332.     DB    0DH,0AH,'SORT Pointer Error',0
  333.     JMP    CPM
  334.  
  335. ;*  FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED FILE ENTRY
  336. ;*    MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED FILE ENTRY)
  337. ;*    POINT TO SAME LOCATION (PTR TO NEXT FILE ENTRY TO BE ORDERED)
  338. SRTDN3:
  339.     LHLD    PTPTR    ; GET PTR TO NEXT ORDERED ENTRY
  340.     DCX    D    ; DE PTS TO LOW-ORDER POINTER ADDRESS
  341.     MOV    A,M    ; MAKE PTR TO NEXT UNORDERED REC PT TO BUFFER FOR
  342.     STAX    D    ;   FILE REC TO BE MOVED TO NEXT UNORDERED FILE POS
  343.     INX    H    ; PT TO NEXT PTR ADDRESS
  344.     INX    D
  345.     MOV    A,M    ; MAKE HIGH POINT SIMILARLY
  346.     STAX    D
  347.  
  348. ;*  INTERCHANGE NEXT ENTRY IN LINE WITH THE ENTRY CURRENTLY IN ITS POSITION
  349.     LHLD    RECSIZ    ; HL=NUMBER OF BYTES/ENTRY
  350.     MOV    B,H    ; BC=NUMBER OF BYTES/ENTRY
  351.     MOV    C,L
  352.     LHLD    PTFIL    ; PT TO ENTRY
  353.     XCHG
  354.  
  355. ;*  COPY TO-BE-ORDERED FILE ENTRY TO NEXT ORDERED FILE POSITION
  356.     LHLD    PTPTR    ; POINT TO ITS POINTER
  357.     MOV    A,M    ; GET LOW-ADDRESS POINTER
  358.     INX    H
  359.     MOV    H,M    ; GET HIGH-ADDRESS POINTER
  360.     MOV    L,A    ; HL IS ADDRESS OF UNORDERED ENTRY
  361.     XCHG        ; HL PTS TO ORDERED ENTRY TO BE MOVED, DE PTS TO REPL
  362. SRTDN4:
  363.     PUSH    B    ; SAVE COUNT
  364.     LDAX    D    ; GET BYTES
  365.     MOV    C,M
  366.     XCHG        ; EXCHANGE PTRS
  367.     STAX    D    ; PUT BYTE
  368.     MOV    M,C
  369.     XCHG        ; RESTORE PTRS TO ORIGINAL
  370.     POP    B    ; GET COUNT
  371.     INX    H    ; PT TO NEXT
  372.     INX    D
  373.     DCX    B    ; COUNT DOWN
  374.     MOV    A,B    ; DONE?
  375.     ORA    C
  376.     JNZ    SRTDN4
  377.  
  378. ;*  POINT TO NEXT TARGET RECORD POSITION
  379.     LHLD    RECSIZ    ; GET SIZE OF RECORD
  380.     XCHG        ; ... IN DE
  381.     LHLD    PTFIL    ; PT TO ENTRY JUST PLACED
  382.     DAD    D    ; PT TO NEXT ENTRY
  383.     SHLD    PTFIL    ; SET POINTER FOR NEXT LOOP
  384.  
  385. ;*  POINT TO NEXT ENTRY IN POINTER TABLE
  386.     LHLD    PTPTR    ; POINTER TO CURRENT REC
  387.     INX    H    ; PT TO NEXT REC
  388.     INX    H
  389.     SHLD    PTPTR
  390.  
  391. ;*  COUNT DOWN
  392.     LHLD    J    ; GET COUNT
  393.     DCX    H    ; COUNT DOWN
  394.     SHLD    J    ; PUT COUNT
  395.     MOV    A,H    ; DONE?
  396.     ORA    L
  397.     JNZ    SRTDN
  398.  
  399. ;*  EXIT
  400. SEXIT:
  401.     POP    PSW    ; RESTORE REGS
  402.     POP    B
  403.     POP    D
  404.     POP    H
  405.     RET        ; DONE
  406.  
  407. ;*
  408. ;*  ISWAP -- Perform exchange of elements whose indices are in HL and DE
  409. ;*
  410. ISWAP:
  411.     LDA    SFLAG    ; USE POINTERS?
  412.     ORA    A    ; 0=NO
  413.     JNZ    SWAP    ; DO POINTER SWAP
  414.     CALL    ADRCOMP    ; COMPUTE ADDRESS OF RECORDS FROM THEIR INDICES
  415.     PUSH    H    ; SAVE HL PTR
  416.     LHLD    RECSIZ    ; SIZE OF RECORD
  417.     MOV    B,H    ; ... IN BC
  418.     MOV    C,L
  419.     POP    H    ; GET HL PTR
  420. SWAPC:
  421.     PUSH    B    ; SAVE COUNT
  422.     LDAX    D    ; GET BYTES
  423.     MOV    C,M
  424.     MOV    M,A    ; PUT BYTES
  425.     MOV    A,C
  426.     STAX    D    ; PUT BYTES
  427.     INX    H    ; PT TO NEXT
  428.     INX    D
  429.     POP    B    ; GET COUNT
  430.     DCX    B    ; COUNT DOWN
  431.     MOV    A,B    ; DONE?
  432.     ORA    C
  433.     JNZ    SWAPC
  434.     RET
  435.  
  436. ;*
  437. ;*  GIVEN INDICES IN HL AND DE, RETURN ADDRESSES OF RECORDS PTED TO BY
  438. ;*    THESE INDICES IN HL AND DE, RESP
  439. ;*
  440. ADRCOMP:
  441.     PUSH    H    ; SAVE HL RECORD
  442.     CALL    ADROFF    ; COMPUTE OFFSET TO RECORD PTED TO BY DE
  443.     SHLD    REC1    ; SAVE ADDRESS OF RECORD
  444.     POP    D    ; GET OLD HL INDEX
  445.     CALL    ADROFF    ; COMPUTE OFFSET TO THE DESIRED RECORD
  446.     XCHG        ; ADDRESS IN DE
  447.     LHLD    REC1    ; GET ADDRESS
  448.     XCHG        ; ORIGINAL ORDER
  449.     RET
  450. REC1:
  451.     DS    2    ; TEMP STORAGE FOR SWAPC
  452.  
  453. ADROFF:
  454.     LHLD    RECSIZ    ; SIZE OF RECORD
  455.     MOV    B,H    ; ... IN BC
  456.     MOV    C,L
  457.     LXI    H,0    ; OFFSET IN HL
  458. ADRO1:
  459.     DCX    D    ; DECREMENT BY 1 SO BASE-RELATIVE
  460.     MOV    A,D    ; DONE WITH LOOP?
  461.     ORA    E
  462.     JZ    ADRO2
  463.     DAD    B    ; ADD IN RECORD SIZE
  464.     JMP    ADRO1
  465. ADRO2:
  466.     XCHG        ; OFFSET IN DE
  467.     LHLD    FIRSTP    ; PT TO FIRST ENTRY
  468.     DAD    D    ; ADD IN OFFSET
  469.     RET
  470.  
  471. ;*
  472. ;*  SWAP (Exchange) the pointers in the ORDER table whose indexes are in
  473. ;*    HL and DE
  474. ;*
  475. SWAP:
  476.     PUSH    H        ; SAVE HL
  477.     LHLD    ORDER        ; ADDRESS OF ORDER TABLE
  478.     MOV    B,H        ; ... IN BC
  479.     MOV    C,L
  480.     POP    H
  481.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  482.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  483.                 ;   OF ORIGINAL HL (0, 2, 4, ...)
  484.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  485.     XCHG            ; DE NOW PTS TO POINTER INDEXED BY HL
  486.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  487.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  488.                 ;   OF ORIGINAL DE (0, 2, 4, ...)
  489.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  490.     MOV    C,M        ; EXCHANGE POINTERS -- GET OLD (DE)
  491.     LDAX    D        ; -- GET OLD (HL)
  492.     XCHG            ; SWITCH
  493.     MOV    M,C        ; PUT NEW (HL)
  494.     STAX    D        ; PUT NEW (DE)
  495.     INX    H        ; PT TO NEXT BYTE OF POINTER
  496.     INX    D
  497.     MOV    C,M        ; GET OLD (HL)
  498.     LDAX    D        ; GET OLD (DE)
  499.     XCHG            ; SWITCH
  500.     MOV    M,C        ; PUT NEW (DE)
  501.     STAX    D        ; PUT NEW (HL)
  502.     RET
  503.  
  504. ;*
  505. ;*  ICOMPARE - Compares entries whose indices are in HL and DE; on exit,
  506. ;*    Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE))
  507. ;*
  508. ICOMPARE:
  509.     LDA    SFLAG    ; USE POINTERS?
  510.     ORA    A    ; 0=NO
  511.     JNZ    COMPARE
  512.     CALL    ADRCOMP    ; COMPUTE ADDRESSES
  513.     JMP    CALLCMP    ; CALL COMPARE ROUTINE OF USER
  514.  
  515. ;*
  516. ;*  COMPARE compares the entry pointed to by the pointer pointed to by HL
  517. ;*    with that pointed to by DE (1st level indirect addressing); on entry,
  518. ;*    HL and DE contain the numbers of the elements to compare (1, 2, ...);
  519. ;*    on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
  520. ;*    and Non-Zero and No-Carry means ((DE)) > ((HL))
  521. ;*
  522. COMPARE:
  523.     PUSH    H        ; SAVE HL
  524.     LHLD    ORDER        ; ADDRESS OF ORDER
  525.     MOV    B,H        ; ... IN BC
  526.     MOV    C,L
  527.     POP    H
  528.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  529.     DAD    H        ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR
  530.     DAD    B        ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE
  531.     XCHG            ; RESULT IN DE
  532.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  533.     DAD    H        ; DO THE SAME WITH THE ORIGINAL DE
  534.     DAD    B
  535.     XCHG
  536.  
  537. ;*
  538. ;*  HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH
  539. ;*  DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH
  540. ;*    FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL
  541. ;* TO THE 4TH POINTER
  542. ;*
  543.     MOV    C,M        ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO
  544.     INX    H        ; ... BY THE ORIGINAL HL
  545.     MOV    B,M
  546.     XCHG
  547.     MOV    E,M        ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO
  548.     INX    H        ; ... BY THE ORIGINAL DE
  549.     MOV    D,M
  550.     MOV    H,B        ; SET HL = OBJECT PTED TO INDIRECTLY BY BC
  551.     MOV    L,C
  552.  
  553. ;*
  554. ;*  COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
  555. ;*    NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
  556. ;*    RET W/ZERO SET MEANS DE=HL
  557. ;*
  558. CALLCMP:
  559.     PUSH    H    ; SAVE HL ON STACK
  560.     LHLD    CMPADR    ; GET ADDRESS OF COMPARE ROUTINE IN HL
  561.     XTHL        ; ADDRESS OF COMPARE ROUTINE ON STACK AND RESTORE HL
  562.     RET        ; "CALL" ROUTINE AND RETURN TO SORT CORRECTLY
  563.  
  564.     END
  565.