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

  1. ;
  2. ; SYSLIB Module Name:  SSORT
  3. ; Author:  Richard Conn
  4. ; SYSLIB Version Number:  2.0
  5. ; Module Version Number:  1.0
  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. PTPTR:
  144.     DS    2    ; 2-LEVEL INDIRECT PTR
  145. PTFIL:
  146.     DS    2    ; REC PTR
  147.  
  148. ;*
  149. ;*  START OF SORT ROUTINE
  150. ;*
  151. SORT::
  152.     PUSH    H    ; SAVE REGS
  153.     PUSH    D
  154.     PUSH    B
  155.     PUSH    PSW
  156.     XCHG        ; PTR IN HL
  157.     LXI    D,SSB    ; COPY HIS SORT BLOCK INTO MINE FOR EASIER ACCESS
  158.     MVI    B,12    ; 12 BYTES LONG
  159.     CALL    MOVEB
  160.     LHLD    RECNT    ; GET RECORD COUNT
  161.     SHLD    N    ; SET "N"
  162.     MOV    B,H    ; ... IN BC
  163.     MOV    C,L
  164.  
  165. ;*
  166. ;*  CHECK FOR TRIVIAL CASE - 0 OR 1; DON'T DO IT IF SO
  167. ;*
  168.     MOV    A,B    ; SEE IF BC=1
  169.     ORA    A    ; B=0?
  170.     JNZ    SHELL    ; DO SORT IF B<>0
  171.     MOV    A,C    ; C=0 OR 1?
  172.     CPI    2
  173.     JC    SEXIT
  174.  
  175. ;*
  176. ;*  SHELL SORT --
  177. ;*    THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
  178. ;*    BY KERNIGAN AND PLAUGHER, PAGE 106.  COPYRIGHT, 1976, ADDISON-WESLEY.
  179. ;*  ON ENTRY, BC=NUMBER OF ENTRIES
  180. ;*
  181. SHELL:
  182.     LDA    SFLAG    ; USE POINTERS?
  183.     ORA    A    ; 0=NO
  184.     JZ    SORT2
  185.     LHLD    FIRSTP    ; PT TO FIRST RECORD
  186.     XCHG        ; POINTER TO 1ST RECORD IN DE
  187.     LHLD    ORDER    ; PT TO ORDER TABLE
  188. ;*
  189. ;*  SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT
  190. ;*    REC IN FILE, BC = NUMBER OF RECS REMAINING
  191. ;*
  192. SORT1:
  193.     MOV    A,B    ; DONE?
  194.     ORA    C    ; 0 IF SO
  195.     JZ    SORT2
  196.     DCX    B    ; COUNT DOWN
  197.     MOV    M,E    ; STORE LOW-ORDER ADDRESS
  198.     INX    H    ; PT TO NEXT ORDER BYTE
  199.     MOV    M,D    ; STORE HIGH-ORDER ADDRESS
  200.     INX    H    ; PT TO NEXT ORDER ENTRY
  201.     PUSH    H    ; SAVE PTR
  202.     LHLD    RECSIZ    ; HL=NUMBER OF BYTES/ENTRY
  203.     DAD    D    ; PT TO NEXT DIR1 ENTRY
  204.     XCHG        ; DE PTS TO NEXT ENTRY
  205.     POP    H    ; GET PTR TO ORDER TABLE
  206.     JMP    SORT1
  207. ;*
  208. ;*  THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P
  209. ;*
  210. SORT2:
  211.     LHLD    N    ; NUMBER OF ITEMS TO SORT
  212.     SHLD    GAP    ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2
  213.  
  214. ;*  FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
  215. SRTL0:
  216.     ORA    A    ; CLEAR CARRY
  217.     LHLD    GAP    ; GET PREVIOUS GAP
  218.     MOV    A,H    ; ROTATE RIGHT TO DIVIDE BY 2
  219.     RAR
  220.     MOV    H,A
  221.     MOV    A,L
  222.     RAR
  223.     MOV    L,A
  224.  
  225. ;*  TEST FOR ZERO
  226.     ORA    H
  227.     JZ    SDONE    ; DONE WITH SORT IF GAP = 0
  228.  
  229.     SHLD    GAP    ; SET VALUE OF GAP
  230.     SHLD    I    ; SET I=GAP FOR FOLLOWING LOOP
  231.  
  232. ;*  FOR (I = GAP + 1; I <= N; I = I + 1)
  233. SRTL1:
  234.     LHLD    I    ; ADD 1 TO I
  235.     INX    H
  236.     SHLD    I
  237.  
  238. ;*  TEST FOR I <= N
  239.     XCHG        ; I IS IN DE
  240.     LHLD    N    ; GET N
  241.     MOV    A,L    ; COMPARE BY SUBTRACTION
  242.     SUB    E
  243.     MOV    A,H
  244.     SBB    D    ; CARRY SET MEANS I > N
  245.     JC    SRTL0    ; DON'T DO FOR LOOP IF I > N
  246.  
  247.     LHLD    I    ; SET J = I INITIALLY FOR FIRST SUBTRACTION OF GAP
  248.     SHLD    J
  249.  
  250. ;*  FOR (J = I - GAP; J > 0; J = J - GAP)
  251. SRTL2:
  252.     LHLD    GAP    ; GET GAP
  253.     XCHG        ; ... IN DE
  254.     LHLD    J    ; GET J
  255.     MOV    A,L    ; COMPUTE J - GAP
  256.     SUB    E
  257.     MOV    L,A
  258.     MOV    A,H
  259.     SBB    D
  260.     MOV    H,A
  261.     SHLD    J    ; J = J - GAP
  262.     JC    SRTL1    ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT
  263.     MOV    A,H    ; J=0?
  264.     ORA    L
  265.     JZ    SRTL1    ; IF ZERO, J=0 AND ABORT
  266.  
  267. ;*  SET JG = J + GAP
  268.     XCHG        ; J IN DE
  269.     LHLD    GAP    ; GET GAP
  270.     DAD    D    ; J + GAP
  271.     SHLD    JG    ; JG = J + GAP
  272.  
  273. ;*  IF (V(J) <= V(JG))
  274.     CALL    ICOMPARE    ; J IN DE, JG IN HL
  275.  
  276. ;*  ... THEN BREAK
  277.     JC    SRTL1
  278.  
  279. ;*  ... ELSE EXCHANGE
  280.     LHLD    J    ; SWAP J, JG
  281.     XCHG
  282.     LHLD    JG
  283.     CALL    ISWAP    ; J IN DE, JG IN HL
  284.  
  285. ;*  END OF INNER-MOST FOR LOOP
  286.     JMP    SRTL2
  287.  
  288. ;*
  289. ;*  SORT IS DONE -- RESTRUCTURE FILE IN SORTED ORDER IN PLACE
  290. ;*
  291. SDONE:
  292.     LDA    SFLAG    ; USE POINTERS?
  293.     ORA    A    ; 0=NO
  294.     JZ    SEXIT    ; DONE IF NO POINTERS
  295.     LHLD    RECNT    ; NUMBER OF RECORDS
  296.     SHLD    J    ; SAVE COUNT IN J
  297.     LHLD    ORDER    ; PTR TO ORDERED POINTER TABLE
  298.     SHLD    PTPTR    ; SET PTR PTR
  299.     LHLD    FIRSTP    ; PTR TO UNORDERED FILE
  300.     SHLD    PTFIL    ; SET PTR TO FILE BUFFER
  301.  
  302. ;*  FIND PTR TO NEXT FILE ENTRY
  303. SRTDN:
  304.     LHLD    J    ; GET ENTRY COUNT
  305.     MOV    B,H    ; ... IN BC
  306.     MOV    C,L
  307.     LHLD    PTPTR    ; PT TO REMAINING POINTERS
  308.     XCHG        ; ... IN DE
  309.     LHLD    PTFIL    ; HL PTS TO NEXT FILE ENTRY
  310.  
  311. ;*  FIND PTR TABLE ENTRY
  312. SRTDN1:
  313.     LDAX    D    ; GET CURRENT POINTER TABLE ENTRY VALUE
  314.     INX    D    ; PT TO HIGH-ORDER POINTER BYTE
  315.     CMP    L    ; COMPARE AGAINST FILE ADDRESS LOW
  316.     JNZ    SRTDN2    ; NOT FOUND YET
  317.     LDAX    D    ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE
  318.     CMP    H    ; COMPARE AGAINST FILE ADDRESS HIGH
  319.     JZ    SRTDN3    ; MATCH FOUND
  320. SRTDN2:
  321.     INX    D    ; PT TO NEXT PTR TABLE ENTRY
  322.     DCX    B    ; COUNT DOWN
  323.     MOV    A,C    ; END OF TABLE?
  324.     ORA    B
  325.     JNZ    SRTDN1    ; CONTINUE IF NOT
  326.  
  327. ;*  FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT
  328. FERR$PTR:
  329.     CALL    PRINT
  330.     DB    0DH,0AH,'SORT Pointer Error',0
  331.     JMP    CPM
  332.  
  333. ;*  FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED FILE ENTRY
  334. ;*    MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED FILE ENTRY)
  335. ;*    POINT TO SAME LOCATION (PTR TO NEXT FILE ENTRY TO BE ORDERED)
  336. SRTDN3:
  337.     LHLD    PTPTR    ; GET PTR TO NEXT ORDERED ENTRY
  338.     DCX    D    ; DE PTS TO LOW-ORDER POINTER ADDRESS
  339.     MOV    A,M    ; MAKE PTR TO NEXT UNORDERED REC PT TO BUFFER FOR
  340.     STAX    D    ;   FILE REC TO BE MOVED TO NEXT UNORDERED FILE POS
  341.     INX    H    ; PT TO NEXT PTR ADDRESS
  342.     INX    D
  343.     MOV    A,M    ; MAKE HIGH POINT SIMILARLY
  344.     STAX    D
  345.  
  346. ;*  INTERCHANGE NEXT ENTRY IN LINE WITH THE ENTRY CURRENTLY IN ITS POSITION
  347.     LHLD    RECSIZ    ; HL=NUMBER OF BYTES/ENTRY
  348.     MOV    B,H    ; BC=NUMBER OF BYTES/ENTRY
  349.     MOV    C,L
  350.     LHLD    PTFIL    ; PT TO ENTRY
  351.     XCHG
  352.  
  353. ;*  COPY TO-BE-ORDERED FILE ENTRY TO NEXT ORDERED FILE POSITION
  354.     LHLD    PTPTR    ; POINT TO ITS POINTER
  355.     MOV    A,M    ; GET LOW-ADDRESS POINTER
  356.     INX    H
  357.     MOV    H,M    ; GET HIGH-ADDRESS POINTER
  358.     MOV    L,A    ; HL IS ADDRESS OF UNORDERED ENTRY
  359.     XCHG        ; HL PTS TO ORDERED ENTRY TO BE MOVED, DE PTS TO REPL
  360. SRTDN4:
  361.     PUSH    B    ; SAVE COUNT
  362.     LDAX    D    ; GET BYTES
  363.     MOV    C,M
  364.     XCHG        ; EXCHANGE PTRS
  365.     STAX    D    ; PUT BYTE
  366.     MOV    M,C
  367.     XCHG        ; RESTORE PTRS TO ORIGINAL
  368.     POP    B    ; GET COUNT
  369.     INX    H    ; PT TO NEXT
  370.     INX    D
  371.     DCX    B    ; COUNT DOWN
  372.     MOV    A,B    ; DONE?
  373.     ORA    C
  374.     JNZ    SRTDN4
  375.  
  376. ;*  POINT TO NEXT TARGET RECORD POSITION
  377.     LHLD    RECSIZ    ; GET SIZE OF RECORD
  378.     XCHG        ; ... IN DE
  379.     LHLD    PTFIL    ; PT TO ENTRY JUST PLACED
  380.     DAD    D    ; PT TO NEXT ENTRY
  381.     SHLD    PTFIL    ; SET POINTER FOR NEXT LOOP
  382.  
  383. ;*  POINT TO NEXT ENTRY IN POINTER TABLE
  384.     LHLD    PTPTR    ; POINTER TO CURRENT REC
  385.     INX    H    ; PT TO NEXT REC
  386.     INX    H
  387.     SHLD    PTPTR
  388.  
  389. ;*  COUNT DOWN
  390.     LHLD    J    ; GET COUNT
  391.     DCX    H    ; COUNT DOWN
  392.     SHLD    J    ; PUT COUNT
  393.     MOV    A,H    ; DONE?
  394.     ORA    L
  395.     JNZ    SRTDN
  396.  
  397. ;*  EXIT
  398. SEXIT:
  399.     POP    PSW    ; RESTORE REGS
  400.     POP    B
  401.     POP    D
  402.     POP    H
  403.     RET        ; DONE
  404.  
  405. ;*
  406. ;*  ISWAP -- Perform exchange of elements whose indices are in HL and DE
  407. ;*
  408. ISWAP:
  409.     LDA    SFLAG    ; USE POINTERS?
  410.     ORA    A    ; 0=NO
  411.     JNZ    SWAP    ; DO POINTER SWAP
  412.     CALL    ADRCOMP    ; COMPUTE ADDRESS OF RECORDS FROM THEIR INDICES
  413.     PUSH    H    ; SAVE HL PTR
  414.     LHLD    RECSIZ    ; SIZE OF RECORD
  415.     MOV    B,H    ; ... IN BC
  416.     MOV    C,L
  417.     POP    H    ; GET HL PTR
  418. SWAPC:
  419.     PUSH    B    ; SAVE COUNT
  420.     LDAX    D    ; GET BYTES
  421.     MOV    C,M
  422.     MOV    M,A    ; PUT BYTES
  423.     MOV    A,C
  424.     STAX    D    ; PUT BYTES
  425.     INX    H    ; PT TO NEXT
  426.     INX    D
  427.     POP    B    ; GET COUNT
  428.     DCX    B    ; COUNT DOWN
  429.     MOV    A,B    ; DONE?
  430.     ORA    C
  431.     JNZ    SWAPC
  432.     RET
  433.  
  434. ;*
  435. ;*  GIVEN INDICES IN HL AND DE, RETURN ADDRESSES OF RECORDS PTED TO BY
  436. ;*    THESE INDICES IN HL AND DE, RESP
  437. ;*
  438. ADRCOMP:
  439.     PUSH    H    ; SAVE HL RECORD
  440.     CALL    ADROFF    ; COMPUTE OFFSET TO RECORD PTED TO BY DE
  441.     SHLD    REC1    ; SAVE ADDRESS OF RECORD
  442.     POP    D    ; GET OLD HL INDEX
  443.     CALL    ADROFF    ; COMPUTE OFFSET TO THE DESIRED RECORD
  444.     XCHG        ; ADDRESS IN DE
  445.     LHLD    REC1    ; GET ADDRESS
  446.     XCHG        ; ORIGINAL ORDER
  447.     RET
  448. REC1:
  449.     DS    2    ; TEMP STORAGE FOR SWAPC
  450.  
  451. ADROFF:
  452.     LHLD    RECSIZ    ; SIZE OF RECORD
  453.     MOV    B,H    ; ... IN BC
  454.     MOV    C,L
  455.     LXI    H,0    ; OFFSET IN HL
  456. ADRO1:
  457.     DCX    D    ; DECREMENT BY 1 SO BASE-RELATIVE
  458.     MOV    A,D    ; DONE WITH LOOP?
  459.     ORA    E
  460.     JZ    ADRO2
  461.     DAD    B    ; ADD IN RECORD SIZE
  462.     JMP    ADRO1
  463. ADRO2:
  464.     XCHG        ; OFFSET IN DE
  465.     LHLD    FIRSTP    ; PT TO FIRST ENTRY
  466.     DAD    D    ; ADD IN OFFSET
  467.     RET
  468.  
  469. ;*
  470. ;*  SWAP (Exchange) the pointers in the ORDER table whose indexes are in
  471. ;*    HL and DE
  472. ;*
  473. SWAP:
  474.     PUSH    H        ; SAVE HL
  475.     LHLD    ORDER        ; ADDRESS OF ORDER TABLE
  476.     MOV    B,H        ; ... IN BC
  477.     MOV    C,L
  478.     POP    H
  479.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  480.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  481.                 ;   OF ORIGINAL HL (0, 2, 4, ...)
  482.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  483.     XCHG            ; DE NOW PTS TO POINTER INDEXED BY HL
  484.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  485.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  486.                 ;   OF ORIGINAL DE (0, 2, 4, ...)
  487.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  488.     MOV    C,M        ; EXCHANGE POINTERS -- GET OLD (DE)
  489.     LDAX    D        ; -- GET OLD (HL)
  490.     XCHG            ; SWITCH
  491.     MOV    M,C        ; PUT NEW (HL)
  492.     STAX    D        ; PUT NEW (DE)
  493.     INX    H        ; PT TO NEXT BYTE OF POINTER
  494.     INX    D
  495.     MOV    C,M        ; GET OLD (HL)
  496.     LDAX    D        ; GET OLD (DE)
  497.     XCHG            ; SWITCH
  498.     MOV    M,C        ; PUT NEW (DE)
  499.     STAX    D        ; PUT NEW (HL)
  500.     RET
  501.  
  502. ;*
  503. ;*  ICOMPARE - Compares entries whose indices are in HL and DE; on exit,
  504. ;*    Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE))
  505. ;*
  506. ICOMPARE:
  507.     LDA    SFLAG    ; USE POINTERS?
  508.     ORA    A    ; 0=NO
  509.     JNZ    COMPARE
  510.     CALL    ADRCOMP    ; COMPUTE ADDRESSES
  511.     JMP    CALLCMP    ; CALL COMPARE ROUTINE OF USER
  512.  
  513. ;*
  514. ;*  COMPARE compares the entry pointed to by the pointer pointed to by HL
  515. ;*    with that pointed to by DE (1st level indirect addressing); on entry,
  516. ;*    HL and DE contain the numbers of the elements to compare (1, 2, ...);
  517. ;*    on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
  518. ;*    and Non-Zero and No-Carry means ((DE)) > ((HL))
  519. ;*
  520. COMPARE:
  521.     PUSH    H        ; SAVE HL
  522.     LHLD    ORDER        ; ADDRESS OF ORDER
  523.     MOV    B,H        ; ... IN BC
  524.     MOV    C,L
  525.     POP    H
  526.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  527.     DAD    H        ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR
  528.     DAD    B        ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE
  529.     XCHG            ; RESULT IN DE
  530.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  531.     DAD    H        ; DO THE SAME WITH THE ORIGINAL DE
  532.     DAD    B
  533.     XCHG
  534.  
  535. ;*
  536. ;*  HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH
  537. ;*  DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH
  538. ;*    FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL
  539. ;* TO THE 4TH POINTER
  540. ;*
  541.     MOV    C,M        ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO
  542.     INX    H        ; ... BY THE ORIGINAL HL
  543.     MOV    B,M
  544.     XCHG
  545.     MOV    E,M        ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO
  546.     INX    H        ; ... BY THE ORIGINAL DE
  547.     MOV    D,M
  548.     MOV    H,B        ; SET HL = OBJECT PTED TO INDIRECTLY BY BC
  549.     MOV    L,C
  550.  
  551. ;*
  552. ;*  COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
  553. ;*    NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
  554. ;*    RET W/ZERO SET MEANS DE=HL
  555. ;*
  556. CALLCMP:
  557.     PUSH    H    ; SAVE HL ON STACK
  558.     LHLD    CMPADR    ; GET ADDRESS OF COMPARE ROUTINE IN HL
  559.     XTHL        ; ADDRESS OF COMPARE ROUTINE ON STACK AND RESTORE HL
  560.     RET        ; "CALL" ROUTINE AND RETURN TO SORT CORRECTLY
  561.  
  562.     END
  563.