home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / lambda / soundpot / p / sap44.lbr / SAP44.AZM / SAP44.ASM
Encoding:
Assembly Source File  |  1993-10-25  |  15.6 KB  |  871 lines

  1. ; SAP v44 -- Sort & Pack directory 07/25/85
  2. ;
  3.     ASEG        ; needed for M80, ignore error if using MAC
  4. ;
  5. ; THIS PROGRAM READS THE DISK DIRECTORY TRACKS, SORTS THEM ALPHABETICALLY
  6. ; THEN REPLACES THEM ON THE DISK.  ALL UNUSED OR ERASED AREAS ON THE DI-
  7. ; RECTORY TRACK ARE REFORMATTED WITH CONTINUOUS 'E5' CHARACTERS.  (THIS
  8. ; ERASES PREVIOUS FILE NAMES WHICH HAVE BEEN DEACTIVATED.)  SORTING THE
  9. ; DIRECTORY IN THIS MANNER OFFERS MANY ADVANTAGES.  SOME OF THEM ARE:
  10. ;
  11. ;    1)  ALLOWS 'DIR' TO SHOW AN ALPHABETIZED LISTING
  12. ;    2)  ELIMINATES POTENTIAL PROBLEMS WITH "UNERASE" PROGRAMS
  13. ;    3)  SPEEDS UP ACCESS VIA 'SD' AND OTHER SPECIAL PROGRAMS
  14. ;    4)  ASSISTS ON WORKING DIRECTLY ON THE DISK WITH 'DU', ETC.
  15. ;    5)  REMOVES FILES FROM THE DISK SOMEBODY ELSE COULD RECOVER
  16. ;    6)  OPTIONALLY ERASES ALL FILES OF ZERO LENGTH (EXCEPT THOSE
  17. ;        STARTING WITH '-' FOR CATALOG USE WITH MAST.CAT)
  18. ;
  19. ;                - Notes by Irv Hoff W6FFC
  20. ;
  21. ;=======================================================================
  22. ;
  23. ; 07/25/85  Added some pushes and pops so that the switch routine will
  24. ;   v44        swap the entire contents of the two directory entries.
  25. ;        Previously it only swapped the part after it found a difference
  26. ;        which sometimes resulted in flag bits moving from one file
  27. ;        to another.            - Bob Clyne
  28. ;
  29. ; 03/20/85  Inserted my name where it belonged under the v42 release
  30. ;   v43     notice, added conditional assembly option for verbose mode
  31. ;        which will, if selected, permit the program to assemble in
  32. ;        under 1k.  Added conditional assembly option for CP/M-only
  33. ;        mode which suppresses check for MP/M and CP/M+.
  34. ;                    - Dennis Quinn
  35. ;
  36. ; 03/06/85  Removed "trash directory" feature to make program more user-
  37. ;   v42     friendly, made "delete zero-length files" an assembly-time
  38. ;        option, as there are more programs than MCAT which make use
  39. ;        of zero-length files.    - Dennis Quinn    (added in v43)
  40. ;
  41. ; 02/28/85  Minor cleanup, made compatible with all assemblers.
  42. ;   v41                 - Irv Hoff
  43. ;
  44. ; 09/17/84  Added 'Previously sorted' statement that was included in v37
  45. ;   v40     but got dropped from v38 when the Shell-Metnzer sort was put
  46. ;        in.  It still rewrites the directory even if previously
  47. ;        sorted, to insure erased programs at end of directory are
  48. ;        properly cleared.        - Irv Hoff
  49. ;
  50. ; 07/27/84  Corrected sorting of last directory entry.
  51. ;   v39                 - WOD
  52. ;
  53. ; 10/16/83  Now using a Shell-Metzner sort which speeds the sorting time
  54. ;   v38     considerably, especially on large directories.
  55. ;                    - Sigi Kluger
  56. ;
  57. ; 07/27/83  Shows an error flag for MP/M and CP/M+ both.  Rewrites the
  58. ;   v37     directory even if previously sorted, to insure erased pro-
  59. ;        grams at end of directory are properly cleared.
  60. ;                    - Irv Hoff
  61. ;
  62. ; 1977    Written by L. E. Hughes.  Modified extensively since by Bruce
  63. ;    Ratoff, Keith Petersen, James Prest, Ron Fowler, Frank Gaude,
  64. ;    Sigi Kluger, Irv Hoff and likely others.
  65. ;
  66. ;=======================================================================
  67. ;
  68. NO    EQU    0
  69. YES    EQU    NOT NO
  70. ;
  71. ;=======================================================================
  72. ;
  73. ; User-customizable options:
  74. ;
  75. VERBOSE    EQU    YES    ; Set this to YES to force full-length messages
  76.             ;   as in SAP40), NO to minimize message length.
  77.  
  78. ONLY22    EQU    NO     ; Set this to YES if SAP will be running ONLY
  79.             ;   under CP/M v2.2.  If not sure, set to NO.
  80.  
  81. ONLY14    EQU    NO    ; Set this to YES if SAP will be running ONLY
  82.             ;   under CP/M v1.4.  If not sure, set to NO.
  83.  
  84. CPMONLY    EQU    NO     ; Set this to YES if SAP will be running ONLY
  85.             ;   under CP/M, either v1.4 or 2.2   If possi-
  86.             ;   bility exists that SAP might be executed
  87.             ;   under MP/M or CP/M+, set to NO.
  88.  
  89. DELZRO    EQU    NO     ; Set this to YES to cause SAP to delete all
  90.             ;   zero-length files not beginning with "-" (as
  91.             ;   in SAP40).    If no files are to be deleted
  92.             ;   solely on the basis of file size, set to NO.
  93.  
  94. ;
  95. ;        End of user-selected options
  96. ;=======================================================================
  97. ;
  98. ;
  99. UNSPECI    EQU    NOT (ONLY22 OR ONLY14)
  100. ;
  101.      IF    ONLY22 AND ONLY14
  102.     ERROR    'You must set EITHER only22 or only14 to YES, not both'
  103.      ENDIF
  104. ;
  105. BDOS    EQU    0005H
  106. CR    EQU    0DH
  107. DPBLEN    EQU    15        ; Size of CP/M 2.2 disk parameter block
  108. FCB    EQU    5CH
  109. GETDSK    EQU    25        ; BDOS "get disk #" function
  110. LF    EQU    0AH
  111. SELDRV    EQU    14        ; Select drive
  112. VERNO    EQU    12        ; Provides CP/M version number
  113. ;
  114. ;
  115.     ORG    100H
  116. ;
  117. ;
  118. ; Obtain BIOS vectors
  119. ;
  120. GETVEC:    LXI    D,WBOOT
  121.     LHLD    0001H
  122.     MVI    B,53
  123.     CALL    MOVE
  124. ;
  125. START:    LXI    SP,STACK    ; Use our own stack
  126.     CALL    ILPRT
  127. ;
  128.      IF    VERBOSE
  129.     DB    CR,LF,'SORT AND PACK DIRECTORY v'
  130.      ENDIF            ; VERBOSE
  131. ;
  132.      IF    NOT VERBOSE
  133.     DB    'SAP v'
  134.      ENDIF            ; NOT VERBOSE
  135. ;
  136.     DB    '44 07/25/85'
  137.     DB    CR,LF,0
  138. ;
  139.      IF    UNSPECI
  140.     MVI    C,VERNO        ; Check for CP/M ver 2.2
  141.     CALL    BDOS
  142.      ENDIF            ; UNSPECI
  143. ;
  144.      IF    UNSPECI    AND (NOT CPMONLY)
  145.     DCR    H        ; H=1 for MPM
  146.     JZ    MPMYES        ; Exit if MPM, we can't use it
  147.     MOV    A,L        ; HL = 0022H if CP/M ver 2.2
  148.     CPI    30H        ; Check for MPM or CP/M 3.0
  149.     JNC    MPMYES        ; Exit if CP/M 3.0, we can't user it
  150.      ENDIF            ; UNSPECI AND (NOT CPMONLY)
  151. ;
  152.      IF    UNSPECI
  153.     STA    VERFLG        ; Store the version
  154.      ENDIF
  155. ;
  156. ;
  157. ;=======================================================================
  158. ;
  159. ;            Main program routine
  160. ;
  161. SAP:    CALL    SETUP
  162.     CALL    RDDIR
  163.     CALL    CLEAN
  164.     CALL    SORT
  165.     CALL    PACK
  166.     CALL    WRDIR
  167.     CALL    ILPRT
  168. ;
  169.      IF    VERBOSE
  170.     DB    'Done'
  171.      ENDIF
  172. ;
  173.     DB    CR,LF,0
  174.     JMP    EXIT
  175. ;
  176. ;
  177. ;=======================================================================
  178. ;               Subroutines
  179. ;
  180. CLEAN:    LXI    H,0        ; I = 0
  181. ;
  182. CLNLOP:    SHLD    I
  183.     CALL    INDEX        ; HL = BUF + 16 * I
  184.     MOV    A,M        ; Jump if this is a deleted file
  185.     CPI    0E5H
  186.     JZ    FILL$E5
  187. ;
  188.      IF    DELZRO
  189.     LXI    D,12
  190.     DAD    D        ; HL = HL + 12
  191.     MOV    A,M        ; Check extent field
  192.     ORA    A
  193.     JNZ    CLBUMP        ; Skip if not extent 0
  194.     INX    H        ; Point to record count field
  195.     INX    H
  196.     MOV    A,M        ; Get S2 byte (extended RC)
  197.     ANI    0FH        ; For CP/M 2.2, 0 for CP/M 1.4
  198.     MOV    E,A
  199.     INX    H
  200.     MOV    A,M        ; Check record count field
  201.     ORA    E
  202.     JNZ    CLBUMP        ; Jump if non-zero
  203.     LHLD    I        ; Clear all 32 bytes of
  204.     CALL    INDEX        ; Directory entry to E5
  205.     INX    H
  206.     MOV    A,M        ; Get first character of filename
  207.     DCX    H        ; MAST.CAT catalog programs
  208.     CPI    '-'        ; Have diskname of zero length
  209.     JZ    CLBUMP        ; That start with '-', do not delete
  210.      ENDIF            ; DELZRO
  211. ;
  212.      IF    NOT DELZRO
  213.     JMP    CLBUMP        ; Don't delete this file
  214.      ENDIF            ; NOT DELZRO
  215. ;
  216. FILLE5:    MVI    C,32        ; Number of bytes to clear
  217.  
  218. FILLOP:    MVI    M,0E5H        ; Make it all E5'S
  219.     INX    H
  220.     DCR    C
  221.     JNZ    FILLOP
  222.  
  223. CLBUMP:    LHLD    DRM        ; Get count of filenames
  224.     INX    H
  225.     XCHG
  226.     LHLD    I        ; Our current count
  227.     INX    H
  228.     PUSH    H
  229.     CALL    SUBDE        ; Subtract
  230.     POP    H
  231.     JC    CLNLOP        ; Loop till all cleaned
  232.     RET
  233. ;
  234.      IF    ONLY14 OR UNSPECI
  235. ;
  236. ;
  237. ; CP/M 1.4 routine
  238. ;
  239. CPM14:    LHLD    BDOS+1
  240.     MVI    L,0
  241.     MVI    A,(JMP)
  242.     STA    RECTRN
  243.     PUSH    H
  244.     LXI    D,15        ; RECTRAN offset from BDOS in CP/M 1.4
  245.     DAD    D
  246.     SHLD    RECTRN+1
  247.     POP    H
  248.     LXI    D,3AH        ; Offset from BDOS to 1.4 DPB
  249.     DAD    D
  250.     MVI    D,0
  251.     MOV    E,M
  252.     INX    H
  253.     XCHG
  254.     SHLD    SPT
  255.     XCHG
  256.     MOV    E,M
  257.     INX    H
  258.     XCHG
  259.     SHLD    DRM
  260.     XCHG
  261.     MOV    A,M
  262.     INX    H
  263.     STA    BSH
  264.     MOV    A,M
  265.     INX    H
  266.     STA    BLM
  267.     MOV    E,M
  268.     INX    H
  269.     XCHG
  270.     SHLD    DSM
  271.     XCHG
  272.     MOV    E,M
  273.     INX    H
  274.     XCHG
  275.     SHLD    AL0
  276.     XCHG
  277.     MOV    E,M
  278.     XCHG
  279.     SHLD    SYSTRK
  280.     RET
  281.      ENDIF
  282. ;
  283. ;
  284. ; CP/M 2.2 routine
  285. ;
  286.      IF    ONLY22 OR UNSPECI
  287. CPM22:    MOV    E,M
  288.     INX    H
  289.     MOV    D,M
  290.     INX    H
  291.     XCHG
  292.     SHLD    RECTBL
  293.     XCHG
  294.     LXI    D,8        ; Offset to DPB within header
  295.     DAD    D        ; Returned by seldsk in CP/M 2.2
  296.     MOV    A,M        ; Get adrress of DPB
  297.     INX    H
  298.     MOV    H,M
  299.     MOV    L,A
  300.     LXI    D,DPB        ; Point to destestination: our DPB
  301.     MVI    B,DPBLEN
  302.     CALL    MOVE
  303.     RET
  304.      ENDIF            ; ONLY22 OR UNSPECI
  305. ;
  306. DODIR:    STA    WRFLAG
  307.     LHLD    SYSTRK
  308.     CALL    DOTRAK        ; Set the track
  309.     LXI    H,0
  310.     SHLD    RECORD
  311.     LHLD    DRM        ; Number of directory entries
  312.     INX    H        ; Relative to 1
  313.     CALL    ROTRHL        ; Divide by 4
  314.     CALL    ROTRHL        ; To get record count
  315.     SHLD    DIRCNT
  316.     LXI    H,BUF
  317.     SHLD    ADDR        ; For DMA address
  318. ;
  319. DIRLOP:    LHLD    RECORD        ; Get records per track
  320.     INX    H
  321.     XCHG
  322.     LHLD    SPT        ; Current record
  323.     CALL    SUBDE        ; Record - SPT
  324.     XCHG
  325.     JNC    NOTROV
  326. ;
  327. ;
  328. ; Track overflow, bump to next
  329. ;
  330.     LHLD    TRACK
  331.     INX    H
  332.     CALL    DOTRAK
  333.     LXI    H,1        ; Rewind record number
  334. ;
  335. NOTROV:    CALL    DOREC        ; Set current record
  336.     LHLD    ADDR
  337.     MOV    B,H        ; Set up DMA address
  338.     MOV    C,L
  339.     CALL    SETDMA
  340.     LDA    WRFLAG        ; Time to figure out
  341.     ORA    A        ; If we are reading
  342.     JNZ    DWRT        ; Or writing
  343. ;
  344. ;
  345. ; Read
  346. ;
  347.     CALL    READ
  348.     ORA    A        ; Test flags on read
  349.     JNZ    RERROR        ; NZ=error
  350.     JMP    MORE        ; Good read, go do more
  351. ;
  352. ;
  353. ; Track and record update routines
  354. ;
  355. DOTRAK:    SHLD    TRACK
  356.     MOV    B,H
  357.     MOV    C,L
  358.     CALL    SETTRK
  359.     RET
  360. ;
  361. DOREC:    SHLD    RECORD
  362.     MOV    B,H
  363.     MOV    C,L
  364.     LHLD    RECTBL
  365.     XCHG
  366.     DCX    B
  367.     CALL    RECTRN
  368.     MOV    B,H
  369.     MOV    C,L
  370. ;
  371.      IF    UNSPECI
  372.     LDA    VERFLG
  373.     ORA    A
  374.     RZ
  375.     CALL    SETREC
  376.     RET
  377.      ENDIF            ; UNSPECI
  378. ;
  379.      IF    ONLY14
  380.     RET
  381.      ENDIF            ; ONLY14
  382. ;
  383.      IF    ONLY22
  384.     CALL    SETREC
  385.     RET
  386.      ENDIF            ; ONLY22
  387. ;
  388. ;
  389. ; Write
  390. ;
  391. DWRT:    MVI    C,1        ; For CP/M 2.2 deblocking BIOS's
  392.     CALL    WRITE
  393.     ORA    A        ; Test flags on write
  394.     JNZ    WERROR        ; NZ=bad directory write
  395.     JMP    MORE
  396. ;
  397. EXIT:    JMP    0000H        ; Go warm reboot
  398. ;
  399. ;
  400. ; Print a string:  Address is on top of stack
  401. ;
  402. ILPRT:    XTHL            ; Get address from stack
  403.     MOV    A,M        ; Get character
  404.     INX    H        ; Point to next address
  405.     XTHL            ; Restore to stack
  406.     ORA    A        ; Are we done?
  407.     RZ            ; Yes, return past string
  408.     PUSH    H        ; In case CBIOS clobbers it
  409.     MOV    C,A        ; Character to 'C' for CP/M
  410.     CALL    CO        ; Print character
  411.     POP    H
  412.     JMP    ILPRT        ; Continue
  413. ;
  414. INDEX:    DAD    H
  415.     DAD    H
  416.     DAD    H
  417.     DAD    H
  418.     DAD    H
  419.     LXI    D,BUF
  420.     DAD    D
  421.     RET
  422. ;
  423. ;
  424. ; Good read or write
  425. ;
  426. MORE:    LHLD    ADDR        ; Bump DMA address for next pass
  427.     LXI    D,80H
  428.     DAD    D
  429.     SHLD    ADDR
  430.     LHLD    DIRCNT        ; Countdown entries
  431.     DCX    H
  432.     SHLD    DIRCNT
  433.     MOV    A,H        ; Test for zero left
  434.     ORA    L
  435.     JNZ    DIRLOP        ; Loop till zero
  436. ;
  437. ;
  438. ; Directory I/O done, reset DMA address
  439. ;
  440.     LXI    B,80H
  441.     CALL    SETDMA
  442.     RET
  443. ;
  444. ;
  445. ; Move utility subroutine
  446. ;
  447. MOVE:    MOV    A,M
  448.     STAX    D
  449.     INX    H
  450.     INX    D
  451.     DCR    B
  452.     JNZ    MOVE
  453.     RET
  454. ;
  455. PACK:    LXI    H,0        ; I = 0
  456. ;
  457. PACK1:    SHLD    I
  458.     CALL    INDEX        ; HL = BUF + 16 * I
  459.     LXI    D,9
  460.     DAD    D        ; HL = HL + 9
  461.     MOV    A,M        ; Jump if filetype not 'X$$'
  462.     SUI    '0'
  463.     JC    PACK2
  464.     CPI    10
  465.     JNC    PACK2
  466.     STA    J
  467.     INX    H
  468.     MOV    A,M
  469.     CPI    '$'
  470.     JNZ    PACK2
  471.     INX    H
  472.     MOV    A,M
  473.     CPI    '$'
  474.     JNZ    PACK2
  475.     INX    H        ; Set extent number to x
  476.     LDA    J
  477.     MOV    M,A
  478.     DCX    H        ; Set filetype to '$$$'
  479.     MVI    M,'$'
  480.     DCX    H
  481.     MVI    M,'$'
  482.     DCX    H
  483.     MVI    M,'$'
  484. ;
  485. PACK2:    LHLD    I        ; I = I + 1
  486.     INX    H
  487.     XCHG
  488.     LHLD    DRM
  489.     INX    H
  490.     XCHG
  491.     PUSH    H
  492.     CALL    SUBDE
  493.     POP    H        ; Loop until I > DRM
  494.     JC    PACK1
  495.     RET
  496. ;
  497. ;
  498. ; Read and write directory routines
  499. ;
  500. RDDIR:    CALL    ILPRT
  501. ;
  502.      IF    VERBOSE
  503.     DB    CR,LF,'---> Reading, ',0
  504.      ENDIF            ; VERBOSE
  505. ;
  506.      IF    NOT VERBOSE
  507.     DB    CR,LF,'Rd, ',0
  508.      ENDIF            ; NOT VERBOSE
  509. ;
  510.     JMP    DODIR        ; Zero the write flag for now
  511. ;
  512. ;
  513. ; Divide HL by 2
  514. ;
  515. ROTRHL:    ORA    A        ; Clear carry
  516.     MOV    A,H
  517.     RAR
  518.     MOV    H,A
  519.     MOV    A,L
  520.     RAR
  521.     MOV    L,A
  522.     RET
  523. ;
  524. ;
  525. ; Setup for selecting drive and  loading disk parm block
  526. ;
  527. SETUP:    LDA    FCB
  528.     DCR    A
  529.     JP    SETUP1        ; Exit if disk drive mentioned
  530.     MVI    C,GETDSK    ; Otherwise get current default drive
  531.     CALL    BDOS        ; So query 'BDOS' for drive
  532.  
  533. SETUP1:    MOV    C,A
  534.     CALL    SELDSK
  535. ;
  536.      IF    UNSPECI
  537.     LDA    VERFLG        ; If CPL/M 1.4
  538.     ORA    A
  539.     JZ    CPM14        ; If 1.4, then do it the 1.4 way
  540.     JMP    CPM22        ; Must be 2.2 then since not MP/M
  541.      ENDIF            ; UNSPECI
  542. ;
  543.      IF    ONLY14
  544.     JMP    CPM14
  545.      ENDIF            ; ONLY14
  546. ;
  547.      IF    ONLY22
  548.     JMP    CPM22
  549.      ENDIF            ; ONLY22
  550. ;
  551. ;
  552. ; Sort the directory
  553. ;
  554. SORT:    XRA    A
  555.     STA    NOSWAP        ; Zero the flag in case already sorted
  556.     CALL    ILPRT
  557. ;
  558.      IF    VERBOSE
  559.     DB    'Sorting, ',0
  560.      ENDIF            ; VERBOSE
  561. ;
  562.      IF    NOT VERBOSE
  563.     DB    'Srt, ',0
  564.      ENDIF            ; NOT VERBOSE
  565. ;
  566. ;
  567. ; Shell-Metzner sort
  568. ;
  569.     LHLD    I
  570.     INX    H
  571.     SHLD    SNUMRECW
  572.     LXI    H,BUF
  573.     SHLD    SSTADR
  574.     PUSH    H        ; And save it
  575.     LXI    H,32
  576.     SHLD    SRECLEN
  577.     PUSH    H        ; And save it
  578. ;
  579. ;
  580. ; Now divide # of fields by 2
  581. ;
  582. DIVIDE:    LHLD    SNUMRECW    ; Get value
  583.     CALL    ROTRHL
  584.     SHLD    SNUMRECW    ; Save result
  585.     MOV    A,L        ; If SNUMRECW <> 0
  586.     ORA    H        ; Then
  587.     JNZ    NOTDONE        ; Not done
  588. ;
  589. ;
  590. ; All fields sorted
  591. ;
  592.     POP    B        ; Clean up stack
  593.     POP    D
  594.     RET
  595. ;
  596. ;
  597. ; Not done yet
  598. ;
  599. NOTDONE:XCHG
  600.     LHLD    I
  601.     INX    H
  602.     MOV    A,L
  603.     SUB    E
  604.     MOV    L,A
  605.     MOV    A,H
  606.     SBB    D
  607.     MOV    H,A
  608.     SHLD    SRECLEN
  609.     LXI    H,1
  610.     SHLD    SSORTV1
  611.     SHLD    SSTADR
  612.     DCR    L
  613.     POP    B
  614.     PUSH    B
  615. ;
  616. NDONE1:    DAD    D
  617.     DCX    B
  618.     MOV    A,B
  619.     ORA    C
  620.     JNZ    NDONE1
  621.     SHLD    SSORTV2
  622.     XCHG
  623.     POP    B
  624.     POP    H
  625.     PUSH    H
  626.     PUSH    B
  627. ;
  628. NDONE2:    SHLD    SSORTV4
  629.     SHLD    SSORTV3
  630.     XCHG
  631.     DAD    D
  632.     XCHG
  633. ;
  634. COMPARE:POP    B
  635.     PUSH    B
  636.     PUSH    D        ;Save addresses of the beginning of these
  637.     PUSH    H        ;..2 directory entries.
  638. ;
  639. COMPAR1:LDAX    D
  640.     ANI    7FH
  641.     PUSH    B
  642.     PUSH    PSW
  643.     MOV    A,M
  644.     ANI    7FH
  645.     MOV    B,A
  646.     POP    PSW
  647.     SUB    B
  648.     POP    B
  649.     JNZ    NOTEQU
  650.     INX    H
  651.     INX    D
  652.     DCX    B
  653.     MOV    A,B
  654.     ORA    C
  655.     JNZ    COMPAR1
  656.     JMP    NOSWITCH
  657. ;
  658. ;
  659. ; The condition at NOTEQU has to be changed for descending sort
  660. ;
  661. NOTEQU:    JNC    NOSWITCH
  662.     MVI    A,1
  663.     STA    NOSWAP
  664.     POP    H        ;Get back the addresses of the beginning of
  665.     POP    D        ;..these 2 directory entries
  666.     POP    B        ;..and the number of bytes.
  667.     PUSH    B        ;Leave this on the stack.
  668. ;
  669. SWITCH:    PUSH    B
  670.     MOV    B,M
  671.     LDAX    D
  672.     MOV    M,A
  673.     MOV    A,B
  674.     STAX    D
  675.     INX    H
  676.     INX    D
  677.     POP    B
  678.     DCX    B
  679.     MOV    A,B
  680.     ORA    C
  681.     JNZ    SWITCH
  682.     LHLD    SNUMRECW
  683.     MOV    A,H
  684.     CMA
  685.     MOV    D,A
  686.     MOV    A,L
  687.     CMA
  688.     MOV    E,A
  689.     LHLD    SSORTV1
  690.     DAD    D
  691.     JNC    NOSW1
  692.     INX    H
  693.     SHLD    SSORTV1
  694.     LHLD    SSORTV3
  695.     XCHG
  696.     LHLD    SSORTV2
  697.     MOV    A,E
  698.     SUB    L
  699.     MOV    L,A
  700.     MOV    A,D
  701.     SBB    H
  702.     MOV    H,A
  703.     SHLD    SSORTV3
  704.     JMP    COMPARE
  705. ;
  706. NOSWITCH:
  707.     POP    H        ;Clean up the stack.
  708.     POP    H        ;..and again.
  709. NOSW1:    LHLD    SSTADR
  710.     INX    H
  711.     SHLD    SSTADR
  712.     SHLD    SSORTV1
  713.     XCHG
  714.     LHLD    SRECLEN
  715.     MOV    A,L
  716.     SUB    E
  717.     MOV    A,H
  718.     SBB    D
  719.     JC    DIVIDE
  720.     LHLD    SSORTV4
  721.     POP    D
  722.     PUSH    D
  723.     DAD    D
  724.     XCHG
  725.     LHLD    SSORTV2
  726.     XCHG
  727.     JMP    NDONE2
  728. ;
  729. ;
  730. ; Utility subtraction subroutine...HL = HL-DE
  731. ;
  732. SUBDE:    MOV    A,L
  733.     SUB    E
  734.     MOV    L,A
  735.     MOV    A,H
  736.     SBB    D
  737.     MOV    H,A
  738.     RET
  739. ;
  740. WRDIR:    LDA    NOSWAP
  741.     ORA    A
  742.     JNZ    WRDIR1
  743.     CALL    ILPRT
  744. ;
  745.      IF    VERBOSE
  746.     DB    '(Previously sorted) - ',0
  747.      ENDIF            ; VERBOSE
  748. ;
  749.      IF    NOT VERBOSE
  750.     DB    '(Prv std) ',0
  751.      ENDIF            ; NOT VERBOSE
  752.  
  753. WRDIR1:    CALL    ILPRT
  754. ;
  755.      IF    VERBOSE
  756.     DB    'Writing, ',0
  757.      ENDIF            ; VERBOSE
  758. ;
  759.      IF    NOT VERBOSE
  760.     DB    'Wrt',0
  761.      ENDIF            ; NOT VERBOSE
  762. ;
  763. WRDIR2:    MVI    A,1
  764.     JMP    DODIR
  765. ;
  766. ;
  767. ; Come here if we get a read error
  768. ;
  769. RERROR:    CALL    ILPRT
  770. ;
  771.      IF    VERBOSE
  772.     DB    '++ READ ERROR - NO CHANGE made'
  773.      ENDIF            ; VERBOSE
  774. ;
  775.      IF    NOT VERBOSE
  776.     DB    '+ Rd err +'
  777.      ENDIF            ; NOT VERBOSE
  778. ;
  779.     DB    CR,LF,0
  780.     JMP    EXIT
  781. ;
  782. ;
  783. ; Come here if we get a write error
  784. ;
  785. WERROR:    CALL    ILPRT
  786. ;
  787.      IF    VERBOSE
  788.     DB    '++ WRITE ERROR - '
  789.     DB    'directory left in UNKNOWN condition'
  790.      ENDIF            ; VERBOSE
  791. ;
  792.      IF    NOT VERBOSE
  793.     DB    '+ Wrt err +'
  794.      ENDIF            ; NOT VERBOSE
  795. ;
  796.     DB    CR,LF,0
  797.     JMP    EXIT
  798. ;
  799. ;
  800. ; M/PM OR CP/M 3.0 not allowed with this program
  801. ;
  802.      IF    UNSPECI    AND (NOT CPMONLY)
  803. MPMYES:    CALL    ILPRT
  804.     DB    CR,LF,'SAP not useable with MP/M or CP/M 3.0',0
  805.     JMP    EXIT
  806.      ENDIF            ; UNSPECI AND (NOT CPMONLY)
  807. ;
  808. ;
  809. ; Data area
  810. ;
  811. ADDR:     DS    2
  812. DIRCNT:     DS    2
  813. I:     DS    2
  814. J:     DS    2
  815. MAPPTR:     DS    2
  816. NOSWAP:     DS    1
  817. RECTBL:     DS    2
  818. RECORD:     DS    2
  819. TRACK:     DS    2
  820. VERFLG:     DS    1
  821. WRFLAG:     DS    1
  822. SRECLEN: DS    2
  823. SSTADR:     DS    2
  824. SSORTV1: DS    2
  825. SSORTV2: DS    2
  826. SSORTV3: DS    2
  827. SSORTV4: DS    2
  828. SNUMRECW:DS    2
  829. ;
  830. ; Disk parameter block:
  831. ;
  832. DPB:
  833. SPT:    DS    2
  834. BSH:    DS    1
  835. BLM:    DS    1
  836. EXM:    DS    1
  837. DSM:    DS    2
  838. DRM:    DS    2
  839. AL0:    DS    1
  840. AL1:    DS    1
  841. CKS:    DS    2
  842. SYSTRK:    DS    2
  843. ;
  844. VECTRS:    DS    53        ; Room for jump vectors
  845. ;
  846. WBOOT    EQU    VECTRS+3    ; Do not change these equates
  847. CSTS    EQU    VECTRS+6
  848. CI    EQU    VECTRS+9
  849. CO    EQU    VECTRS+12
  850. LO    EQU    VECTRS+15
  851. PO    EQU    VECTRS+18
  852. RI    EQU    VECTRS+21
  853. HOME    EQU    VECTRS+24
  854. SELDSK    EQU    VECTRS+27
  855. SETTRK    EQU    VECTRS+30
  856. SETREC    EQU    VECTRS+33
  857. SETDMA    EQU    VECTRS+36
  858. READ    EQU    VECTRS+39
  859. WRITE    EQU    VECTRS+42
  860. LSTS    EQU    VECTRS+45    ; Only in CP/M 2.2
  861. RECTRN    EQU    VECTRS+48    ; Only in CP/M 2.2
  862.  
  863.     DS    32        ; Minimum stack depth
  864. EVEN    EQU    ($+255)/256*256    ; Start buffer on even page, which also
  865.                 ; Increase stack area greatly
  866.     ORG    EVEN
  867. STACK    EQU    $-2
  868. BUF:    DS    0
  869. ;
  870.     END
  871.