home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / sigmv044.ark / SD-41.ASM < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  45.6 KB  |  1,772 lines

  1. *             SD.ASM Ver 4.1
  2. *               (revised 10/20/81)
  3.  
  4. *            SUPER DIRECTORY PROGRAM
  5. *               by Bruce    R. Ratoff
  6.  
  7. *        Based on 'DIRS' by Keith Petersen, W8SDZ
  8.  
  9. * Displays the directory of a CP/M disk, sorted    alphabetically,
  10. * with the file    size in    K, rounded to the nearest CP/M block size.
  11.  
  12. * This latest variation    on a common theme will automatically adjust
  13. * itself for any block size and    directory length under CP/M 1.4    or 2.x
  14. * or MP/M (any version).  Provisions are made for (1) automatic    pauses
  15. * when the screen fills    up; (2)    searching individual or    multiple drives
  16. * and/or user areas; (3) unconditional or optionally resetting the disk
  17. * system before    execution begins; (4) directing    output to a disk file
  18. * and appending    to it on subsequent runs; (5) summary line output giving
  19. * drive    and user information, #    of files matched and how much space they
  20. * consume, and the amount of free space    remaining on the disk; (6) displaying
  21. * or suppressing CP/M 2    "system" files;    (7) accepting ambiguous    filenames
  22. * with or without a drive name;    and (8)    printer    output.
  23.  
  24. * See SD.DOC for detailed instructions on configuring and running SD.ASM
  25.  
  26. * ==========================================================================
  27.  
  28. *        NOTE: If you add improvements or otherwise update
  29. *        this program, please modem a copy of the new file
  30. *        to "TECHNICAL CBBS"    in Dearborn, Michigan -    phone
  31. *        313-846-6127 (110, 300, 450    or 600 baud).  Use the
  32. *        filename SD-NEW.NEW.  (KBP)
  33.  
  34. *        As SD-41.ASM is "officially experimental", the author
  35. *        of the latest revisions would appreciate feedback on
  36. *        any bugs which may be discovered.  CC bug notes to
  37. *        me c/o Hyde Park RCP/M (phone 312-955-4493).  (DB)
  38.  
  39. * ==========================================================================
  40.  
  41. * Fixes/updates    (in reverse order to minimize reading time):
  42.  
  43. * 10/20/81 MINOR UPDATE to correct (1) malfunction when appending to an
  44. *       existing SD.DIR file with the directory from an empty disk;
  45. *       (2) clobbering data area while closing SD.DIR when last record
  46. *       appended is completely full; and (3) equate interaction error
  47. *       between FOPT and AOPT.  (Ver 4.1 - David Boruff)
  48.  
  49. * 10/19/81 MAJOR UPDATE adding new command line options for
  50. *       (1) disk system reset;  (2) page pause override;
  51. *       (3) displaying directory of a specified user    area;
  52. *       (4) searching ranges    of drives or user areas; and
  53. *       (5) printer output.    Corrected previous name error
  54. *       to avoid confusion with Keith Petersen's old SDIR.
  55.  
  56. *       Corrected obscure file output bug which occurred only
  57. *       when appending on even record or extent boundaries.
  58. *       Reset equate    of Ver 2.3 deleted as redundant    now that
  59. *       command line    reset available    as an option or    default.
  60. *       Shortened page-pause    message    to free-up program space.
  61. *       Optimized much of the existing code to compact the load
  62. *       module and gain space for new features.  Option scanner
  63. *       rewritten to    permit free form input and to simplify any
  64. *       future expansions of    the command line option    set.
  65. *       Reclaimed uninitialized data    memory to further compact
  66. *       load    module size.  By popular demand, restored code to
  67. *       display free    space remaining    when no    files are found.
  68. *       Added tables    to allow restricting directory searches
  69. *       to a    range of drives    and/or user areas.  BDOS intercept
  70. *       added to facilitate searching drives    that may not be
  71. *       on-line (more generally applicable than the FILEFIND
  72. *       method if your BIOS returns control to BDOS on fatal disk
  73. *       errors).  General cosmetic overhaul including tabular
  74. *       realignment and additional comments to enhance readability
  75. *       at the cost of a "few" extra bytes.    (Ver 4.0 - David Boruff)
  76.  
  77. * 09/23/81 MINOR UPDATE    to add equate to allow suppressing user
  78. *       numbers in the directory output. (Ver 3.1 - David Boruff)
  79.  
  80. * 09/18/81 MAJOR UPDATE    implementing new file output option allowing
  81. *       directory output to be appended to a    disk file.  Changed
  82. *       option specification    format to require a dollar sign
  83. *       preceding the option    specifiers.  Changed header format
  84. *       to display drive & user #'s for each line less than 4
  85. *       files wide.    Changed    code for no files found    to display
  86. *       error message only.    (Ver 3.0 - David Boruff)
  87.  
  88. * 09/12/81 MINOR UPDATE    deleting WIDE and NOT WIDE code    in deference
  89. *       to equating screen size.  Added Flashwriter II equate to
  90. *       allow display of file attributes in reverse video.  Changed
  91. *       tag-line to display drive and user #.  Added    equate to allow
  92. *       disk    system reset on    startup.  Other    cosmetic changes made
  93. *       to open up display format and give output a less cramped
  94. *       appearance. (Ver 2.3    - David    Boruff)
  95.  
  96. * 06/05/81 Added PGPAWZ    (page pause) conditional for remote
  97. *       CP/M    systems    where pausing may not be wanted.
  98. *       Setting PGPAWZ and REPSIZ to    FALSE will result in
  99. *       a display like DIR, but sorted and with the stat
  100. *       of space remaining.    Rearranged equates to allow
  101. *       15 lines per    page when narrow display is chosen.
  102. *       (Ver    2.2 - KBP)
  103.  
  104. * 06/01/81 Added version number, restored CTL-C    break, added
  105. *       CTL-C test to allow break at    page pause, added
  106. *       routine to gobble up    any waiting console character
  107. *       at EXIT, added conditional assembly to allow    no
  108. *       report of file sizes, added conditional assembly
  109. *       for direct console I/O for remote CP/M systems
  110. *       where phone line noise would    garbage    display.  (KBP)
  111.  
  112. * 05/06/81 Corrected double printing of    drive name in CALLB.
  113. *       Error only occurred with narrow display when    file
  114. *       wasn't found. (Tim Nicholas)
  115.  
  116. * 02/06/81 Changed sort    to have    odd gap    (KBP say its faster)
  117.  
  118. * 01/06/81 Changed sort    from bubble sort to shell sort
  119. *       for faster speed.
  120.  
  121. * 12/24/80 Changed BIOS    conout to BDOS conout to allow
  122. *       printing of directory with CTL-P.  Also added
  123. *       print of remaining space even if file not
  124. *       found. (Steve Nossen)
  125.  
  126. * 12/15/80 Added space suppression when    printing file
  127. *       totals.  (KBP)
  128.  
  129. * 12/14/80 Added logic to print    space remaining    on disk.
  130. *       Changed ^C test so that interrupting    character is
  131. *       not echoed (makes remote use    cleaner).  (BRR)
  132.  
  133. * 12/02/80 Fixed bug in    print routine which compared last file
  134. *       against garbage before printing. (BRR)
  135.  
  136. * 11/29/80 Changed to allow printing 4 file names. (Ben    Bronson
  137. *       and Keith Petersen)
  138.  
  139. * 11/22/80 Fixed bug in    handling >256 files.  Changed abort test
  140. *       in print routine to only abort on control-c.     (BRR)
  141.  
  142. * ==========================================================================
  143.  
  144. *         Set 'RMAC'    TRUE to    assemble with relocating assembler
  145. *         (requires link with PAGE 0    equates    in separate file).
  146.  
  147. * ==========================================================================
  148.  
  149. FALSE    EQU    0
  150. TRUE    EQU    NOT FALSE
  151.  
  152. ******************************
  153. *                 *
  154. * USER OPTION SPECIFICATIONS *
  155. *                 *
  156. ******************************
  157.  
  158. AOPT    EQU    TRUE        ;True to allow searching all user areas
  159. ALTCPM    EQU    FALSE        ;True for H8 or    TRS-80
  160. DIRCON    EQU    FALSE        ;True for direct console output
  161. DOPT    EQU    TRUE        ;True to allow searching all drives on-line
  162. FOPT    EQU    TRUE        ;True to allow file output option
  163. NOPT    EQU    TRUE        ;True to allow disabling page pause option
  164. OPTION    EQU    TRUE        ;True if allowing ANY command line options
  165. PGPAWZ    EQU    TRUE        ;True for pause after each page
  166. POPT    EQU    TRUE        ;True to allow printer option
  167. REPERR    EQU    TRUE         ;True to report command line option errors
  168. REPSIZ    EQU    TRUE        ;True to report file sizes
  169. REPUSR    EQU    TRUE        ;True to report user numbers
  170. RMAC    EQU    FALSE        ;True for assembly by RMAC
  171. ROPT    EQU    TRUE        ;True to allow reset option
  172. SOPT    EQU    TRUE        ;True to allow system file option
  173. UOPT    EQU    TRUE        ;True to allow user number option
  174. VECTOR    EQU    FALSE        ;True to display attributes on Flashwriter II
  175. VIDEO    EQU    0E009H        ;Entry to Flashwriter video driver PROM
  176.  
  177. DELIM    EQU    7CH        ;Fence (delimiter) character (vertical bar)
  178.  
  179. NPL    EQU    3        ;# of names per line (max of 3 for 64x16)
  180. *                             (max of 4 for 80x24)
  181.  
  182. LPS    EQU    12        ;# of lines per screen (max of 12 for 64x16)
  183. *                               (max of 20 for 80x24)
  184.  
  185.     IF    NOPT AND NOT PGPAWZ
  186.     ++++ NOPT OPTION REDUNDANT WITHOUT PGPAWZ ++++
  187.     ENDIF
  188.  
  189.     IF    REPERR AND NOT OPTION
  190.     ++++ REPERR EQUATE USELESS WITHOUT OPTION ++++
  191.     ENDIF
  192.  
  193. * BDOS equates
  194.  
  195. RDCHR    EQU    1        ;Read char from    console
  196. WRCHR    EQU    2        ;Write char to console
  197. CONST    EQU    11        ;Check cons stat
  198. RESET    EQU    13        ;Reset disk system
  199. SELDSK    EQU    14        ;Select    disk
  200. OPEN    EQU    15        ;0FFH=not found
  201. CLOSE    EQU    16        ;   "    "
  202. SEARCH    EQU    17        ;   "    "
  203. NEXT    EQU    18        ;   "    "
  204. READ    EQU    20        ;not 0 = EOF
  205. WRITE    EQU    21        ;not 0 = disk full
  206. MAKE    EQU    22        ;0FFH =    directory full
  207. CURDSK    EQU    25        ;Get currently logged disk name
  208. SETDMA    EQU    26        ;Set current DMA
  209. GALLOC    EQU    27        ;Get address of    allocation vector
  210. CURDPB    EQU    31        ;Get current disk parameters
  211. CURUSR    EQU    32        ;Get currently logged user number (2.x only)
  212.  
  213.     IF    ALTCPM
  214. BASE    EQU    4200H
  215. TPA    EQU    4300H
  216.     ENDIF
  217.  
  218.     IF    RMAC
  219.     EXTRN    BASE,FCB,BDOS    ;Make base external
  220.     ENDIF
  221.  
  222.     IF    (NOT ALTCPM) AND (NOT RMAC)
  223. BASE    EQU    $        ;Default to 0 (or 100H with MAC    +R option)
  224. TPA    EQU    100H
  225.     ENDIF
  226.  
  227.     IF    NOT RMAC
  228. FCB    EQU    BASE+5CH
  229. BDOS    EQU    BASE+5
  230.     ENDIF
  231.  
  232. FILL    MACRO    BYTES,WITH
  233.     REPT    BYTES
  234.     DB    WITH
  235.     ENDM
  236.     ENDM
  237.  
  238. $-MACRO
  239.  
  240.     PAGE    60
  241.     TITLE    'SD Version 4.1 - 20 Oct 1981'
  242.  
  243. *********************************
  244. *                *
  245. * BEGIN    EXECUTABLE PROGRAM CODE    *
  246. *                *
  247. *********************************
  248.  
  249.     IF    NOT RMAC
  250.     ORG    TPA
  251.     ENDIF
  252.  
  253.     JMP    START
  254.  
  255.     DB    ' SD 4.1 - 10/20/81 '
  256.  
  257. START:    LXI    H,0
  258.     DAD    SP        ;HL=old    stack
  259.     SHLD    STACK        ;Save it
  260.     LXI    SP,STACK    ;Get new stack
  261.  
  262.     MVI    C,12        ;Get and save the CP/M version #
  263.     CALL    BDOS
  264.     MOV    A,L
  265.     STA    VERFLG
  266.     CPI    20H        ;Set carry if CP/M 1.4
  267.  
  268.     MVI    E,0FFH        ;Get current user number if using CP/M 2, or
  269.     MVI    C,CURUSR    ;Fall through with A=0 if not
  270.     CNC    CPM
  271.  
  272.     STA    OLDUSR        ;Initialize startup user number
  273.     STA    NEWUSR        ;..and make new    user match it
  274.  
  275.     IF    DOPT
  276.     STA    BASUSR        ;Save extra copy for multi-disk    directories
  277.     CALL    SWAPEM        ;Swap BDOS error vector    tables
  278.     ENDIF
  279.  
  280.     MVI    C,CURDSK
  281.     CALL    CPM        ;Get current disk nr
  282.     STA    OLDDSK        ;Save for reset    if needed
  283.  
  284.     IF    FOPT
  285.     INR    A
  286.     STA    OUTFCB        ;Set directory output file drive
  287.     ENDIF
  288.  
  289.     LXI    H,FCB
  290.     MOV    A,M        ;Get drive name    for directory search
  291.     ORA    A        ;Any specified?
  292.     JNZ    START2        ;Yes skip next routine
  293.     LDA    OLDDSK        ;Otherwise, get    default    disk
  294.     INR    A
  295. START2:    MOV    M,A        ;Put the absolute drive    code in    directory FCB
  296.  
  297. * If at    least one option is allowed, scan the command line for the
  298. * option field delimiter.  The option field delimiter is considered
  299. * valid    only if    it is preceded by at least 1 space (otherwise, it
  300. * may be part of the directory filename).  Any unrecognized options
  301. * or illegal user numbers will be flagged or ignored (see REPERR).
  302. * (We scan the command line buffer rather than the 2nd default FCB
  303. * because all 8    options    plus a 2 digit user number won't fit in
  304. * the FCB name field).
  305.  
  306.     IF    OPTION
  307.     LXI    H,80H        ;Set command line buffer pointer
  308.     MOV    B,M        ;Get length of command line buffer
  309.  
  310. * Search for the command line delimiter.  If not found, assume no options.
  311.  
  312. SCNDOL:    INX    H
  313.     DCR    B
  314.     JM    CKREST        ;Exit if command line buffer empty
  315.     MOV    A,M
  316.     CPI    '$'
  317.     JNZ    SCNDOL
  318.     DCX    H        ;'$' found - make sure space precedes it
  319.     MOV    A,M
  320.     INX    H
  321.     CPI    ' '
  322.     JNZ    SCNDOL        ;No space - ignore "$" and search again
  323.  
  324. * Valid    delimiter found.  Scan the rest    of the buffer for options.  Errors
  325. * past this point will cause an    abort if the command line error    option is
  326. * enabled.  Otherwise, the dud option will be ignored and SD will attempt
  327. * to continue stumbling    through    the rest of the    field.
  328.  
  329.     XCHG            ;Get option field pointer to DE
  330. SCNOPT:    INX    D        ;Bump to next option field character
  331.     DCR    B        ;Dock characters left in option    field
  332.     JM    CKREST        ;If option field exhausted, exit
  333. SCNAGN:    LDAX    D        ;Get the next option character
  334.     CPI    ' '        ;Do we have a space?
  335.     JZ    SCNOPT        ;Ignore    it if so
  336.     LXI    H,OTBL-1    ;Get base of option lookup table
  337.     MVI    C,OEND-OTBL+1    ;Get length of option lookup table
  338. NOMACH:    INX    H        ;Bump to next option table character
  339.     DCR    C        ;Are we    out of the table?
  340.     JZ    CK4USR        ;If so, check for user option
  341.     CMP    M        ;Compare our character with option table
  342.     JNZ    NOMACH        ;Exit if no match
  343.     MVI    M,0        ;Otherwise, activate the flag
  344.     JMP    SCNOPT        ;..and go get the next option character
  345.  
  346. * If option character doesn't match the table, see if we have a User
  347. * option.
  348.  
  349. CK4USR:    IF    UOPT        ;Check for user    number option
  350.     CPI    'U'
  351.     JNZ    CLERR        ;Last option, so bad deal if that ain't it
  352.  
  353. UAGN:    INX    D        ;Bump to user number digit
  354.     DCR    B
  355.     JM    CLERR        ;Error if nothing left
  356.     LDAX    D        ;Get decimal digit
  357.     CPI    ' '        ;Ignore    leading    spaces
  358.     JZ    UAGN
  359.     SUI    30H        ;Subtract ASCII    BIAS
  360.     JC    CLERR        ;Error if < 0
  361.     CPI    10
  362.     JNC    CLERR        ;Error if > 9
  363.     STA    NEWUSR        ;Save user number as it    may be only 1 digit
  364.  
  365.     IF    DOPT
  366.     STA    BASUSR        ;Duplicate it if multi-disk mode
  367.     ENDIF
  368.  
  369.     INX    D        ;Bump to possible 2nd digit of user number
  370.     DCR    B
  371.     JM    CKREST        ;If no more buffer, exit with complete user #
  372.     LDAX    D        ;Else, check for another digit
  373.     SUI    30H
  374.     JC    SCNAGN        ;If next char not numeric, its not part    of
  375.     CPI    10        ;..user    number so go check for another option
  376.     JNC    SCNAGN
  377.     MOV    L,A        ;Save units digit
  378.     LDA    NEWUSR        ;Get tens digit
  379.     ADD    A        ;Multiply by 10
  380.     MOV    H,A
  381.     ADD    A
  382.     ADD    A
  383.     ADD    H
  384.     ADD    L        ;Combine with units digit
  385.     STA    NEWUSR        ;Save the total    user number
  386.  
  387.     IF    DOPT
  388.     STA    BASUSR        ;Duplicate it if multi-disk mode
  389.     ENDIF
  390.  
  391.     JMP    SCNOPT        ;Continue scanning
  392.     ENDIF            ;Balance UOPT
  393.  
  394. * If command line error    option enabled,    playback the command line up
  395. * to the character that    we gagged on and exit.    If REPERR is not enabled,
  396. * then continue    as if nothing were amiss to avoid acknowledging    that
  397. * some options are available.
  398.  
  399. CLERR:    IF    REPERR
  400.     XRA    A
  401.     INX    D        ;Tag end of command line with terminator
  402.     STAX    D
  403.     CALL    CRLF
  404.     LXI    D,ERRMS2
  405.     CALL    PRINT
  406.     LXI    D,ERRTAG
  407.     CALL    PRINT
  408.     LXI    H,81H        ;Playback bad command line to error point
  409. CLELP:    MOV    A,M
  410.     ORA    A
  411.     JZ    CLEX
  412.     CALL    TYPE
  413.     INX    H
  414.     JMP    CLELP
  415.  
  416. CLEX:    MVI    A,'?'        ;Tag line with a '?' field
  417.     CALL    TYPE
  418.     CALL    CRLF        ;Space down 1 more line
  419.     JMP    EXIT        ;..and return to CP/M
  420.     ELSE
  421.  
  422.     JMP    SCNOPT        ;If not    reporting errors, ignore the dud
  423.  
  424.     ENDIF            ;Balance REPERR
  425.     ENDIF            ;Balance OPTION
  426.  
  427. * Options input or not specified.  If reset option specified, reset
  428. * the disk system now.    Its important that the reset be done OUTSIDE
  429. * the multiple drive loop if the file output option is enabled because
  430. * CP/M 1.4 clobbers the DMA buffer on reset.
  431.  
  432. CKREST: IF    ROPT
  433.     LDA    ROPFLG        ;If reset flag set, reset disk system before
  434.     ORA    A        ;..starting to update allocation vectors
  435.     MVI    C,RESET
  436.     CZ    CPM
  437.     ENDIF            ;Balance ROPT
  438.  
  439. * Validate drive code and user area numbers from the drive table.
  440.  
  441. NOOPT:    LXI    D,DREMSG    ;Get the drive/user error message
  442.     PUSH    D
  443.     LDA    FCB        ;Get directory drive code
  444.     DCR    A        ;Normalize to range of 0-15
  445.     CPI    HIDRV-LODRV    ;Compare with maximum drives on-line
  446.     JNC    ERXIT        ;Take drive error exit if out of range
  447.     LXI    H,USRMSG    ;Switch    to user    # error    message
  448.     XTHL
  449.     MOV    E,A        ;Use drive code    as index into table
  450.     MVI    D,0
  451.     LXI    H,LODRV        ;Point to base of drive/user table
  452.     DAD    D
  453.     MOV    A,M        ;Get the maximum user #    for this drive
  454.     ANI    0FH        ;Make sure its in range    0 - 15
  455.     STA    MAXUSR        ;Save it for later
  456.     LXI    H,NEWUSR    ;Point to the directory    user area
  457.     CMP    M        ;Compare it with the maximum
  458.     JC    ERXIT        ;Take error exit if user number    illegal
  459.     POP    D        ;Destroy error message pointer
  460.  
  461.     LXI    H,FCB+1     ;Point to name
  462.     MOV    A,M        ;Any specified?
  463.     CPI    ' '
  464.     JNZ    GOTFCB
  465.  
  466. * No FCB - make    FCB all    '?'
  467.  
  468.     MVI    B,11        ;FN+FT count
  469.  
  470. QLOOP:    MVI    M,'?'        ;Store '?' IN FCB
  471.     INX    H
  472.     DCR    B
  473.     JNZ    QLOOP
  474.  
  475. GOTFCB:    MVI    A,'?'        ;Force wild extent
  476.     STA    FCB+12
  477.     CALL    SETSRC        ;Set DMA for BDOS media change check
  478.     LXI    H,FCB        ;Point to FCB drive code for directory
  479.     MOV    E,M        ;Get the drive code out of the FCB
  480.     DCR    E        ;Normalize drive code for SELECT
  481.     MVI    C,SELDSK    ;Select the directory drive to retrieve
  482.     CALL    CPM        ;..the proper allocation vector
  483.     CALL    CKVER        ;Check version
  484.     JC    V14        ;Pre-2.X...get params the 1.4 way
  485.  
  486.     MVI    C,CURDPB    ;It's 2.X or MP/M...request DPB
  487.     CALL    BDOS
  488.     INX    H
  489.     INX    H
  490.     MOV    A,M        ;Get block shift
  491.     STA    BLKSHF
  492.     INX    H        ;Bump to block mask
  493.     MOV    A,M
  494.     STA    BLKMSK        ;Get it
  495.     INX    H
  496.     INX    H
  497.     MOV    E,M        ;Get max block #
  498.     INX    H
  499.     MOV    D,M
  500.     XCHG
  501.     SHLD    BLKMAX        ;Save it
  502.     XCHG
  503.     INX    H
  504.     MOV    E,M        ;Get directory size
  505.     INX    H
  506.     MOV    D,M
  507.     XCHG
  508.     JMP    FREE        ;Let FREE save it and setup order table
  509.  
  510. V14:    LHLD    BDOS+1        ;Get params 1.4 style
  511.     MVI    L,3BH        ;Point to directory size
  512.     MOV    E,M        ;Get it
  513.     MVI    D,0        ;Force high order to 0
  514.     PUSH    D        ;Save for later
  515.     INX    H        ;Point to block    shift
  516.     MOV    A,M        ;Fetch
  517.     STA    BLKSHF        ;Save
  518.     INX    H        ;Point to block    mask
  519.     MOV    A,M        ;Fetch it
  520.     STA    BLKMSK        ;And save it
  521.     INX    H
  522.     MOV    E,M        ;Get max. block    no.
  523.     MVI    D,0
  524.     XCHG
  525.     SHLD    BLKMAX        ;Save it
  526.     POP    H        ;Restore directory size
  527.  
  528. * Calculate # of K free    on selected drive now so that the FREE figure
  529. * will not reflect either the creation or additions to the SD.DIR
  530. * file (which we would probably    erase or move anyway).
  531.  
  532. FREE:    SHLD    DIRMAX        ;Save max # of entries in directory
  533.     MVI    C,GALLOC    ;Get address of    allocation vector
  534.     CALL    BDOS
  535.     XCHG
  536.     LHLD    BLKMAX        ;Get its length
  537.     INX    H
  538.     LXI    B,0        ;Init block count to 0
  539.  
  540. GSPBYT:    PUSH    D        ;Save alloc address
  541.     LDAX    D
  542.     MVI    E,8        ;Set to    process    8 blocks
  543.  
  544. GSPLUP:    RAL            ;Test bit
  545.     JC    NOTFRE
  546.     INX    B
  547.  
  548. NOTFRE:    MOV    D,A        ;Save bits
  549.     DCX    H        ;Count down blocks
  550.     MOV    A,L
  551.     ORA    H
  552.     JZ    ENDALC        ;Quit if out of    blocks
  553.     MOV    A,D        ;Restore bits
  554.     DCR    E        ;Count down 8 bits
  555.     JNZ    GSPLUP        ;Do another bit
  556.     POP    D        ;Bump to next byte..
  557.     INX    D        ;..of alloc. vector
  558.     JMP    GSPBYT        ;Process it
  559.  
  560. ENDALC:    POP    D        ;Clear allocation vector pointer from stack
  561.     MOV    L,C        ;Copy blocks to    hl
  562.     MOV    H,B
  563.     LDA    BLKSHF        ;Get block shift factor
  564.     SUI    3        ;Convert from sectors to K
  565.     JZ    SAVFRE        ;Skip shifts if 1K blocks - return free in HL
  566.  
  567. FREKLP: DAD    H        ;Multiply blocks by K/BLK
  568.     DCR    A
  569.     JNZ    FREKLP
  570. SAVFRE: SHLD    FREEBY        ;Save the free space for output later
  571.  
  572. * Reenter here on subsequent passes while in the all-users mode
  573.  
  574. SETTBL:    LHLD    DIRMAX        ;Get directory maximum again
  575.     INX    H        ;Directory size    is DIRMAX+1
  576.     DAD    H        ;Double    directory size
  577.     LXI    D,ORDER        ;To get    size of    order table
  578.     DAD    D        ;Allocate order    table
  579.     SHLD    TBLOC        ;Name table begins where order table ends
  580.     SHLD    NEXTT
  581.     XCHG
  582.     LHLD    BDOS+1        ;Make sure we have room    to continue
  583.     MOV    A,E
  584.     SUB    L
  585.     MOV    A,D
  586.     SBB    H
  587.     JNC    OUTMEM
  588.  
  589.     IF    UOPT
  590.     CALL    CKVER        ;Set carry if pre-CP/M 2
  591.     LDA    NEWUSR        ;Get user area for directory
  592.     MOV    E,A
  593.     MVI    C,CURUSR    ;Get the user function
  594.     CNC    CPM        ;..and set new user number if CP/M 2
  595.     ENDIF
  596.  
  597. * Look up the FCB in the directory
  598.  
  599. SFIRST:    LXI    H,0
  600.     SHLD    COUNT        ;Initialize match counter
  601.     SHLD    TOTFIL        ;     "        total file counter
  602.     SHLD    TOTSIZ        ;     "        total size counter
  603.     CALL    SETSRC        ;Set DMA for directory search
  604.     MVI    C,SEARCH    ;Get 'search first' function
  605.     JMP    LOOK        ;..and go search for 1st match
  606.  
  607. * Read more directory entries
  608.  
  609. MORDIR:    MVI    C,NEXT        ;Search    next
  610. LOOK:    LXI    D,FCB
  611.     CALL    CPM        ;Read directory    entry
  612.     INR    A        ;Check for end (0FFH)
  613.     JZ    SPRINT        ;If no more, sort & print what we have
  614.  
  615. * Point    to directory entry
  616.  
  617. SOME:    DCR    A        ;Undo prev 'INR A'
  618.     ANI    3        ;Make modulus 4
  619.     ADD    A        ;Multiply...
  620.     ADD    A        ;..by 32 because
  621.     ADD    A        ;..each    directory
  622.     ADD    A        ;..entry is 32
  623.     ADD    A        ;..bytes long
  624.     LXI    H,BASE+81H    ;Point to buffer
  625.                 ;(skip to FN/FT)
  626.     ADD    L        ;Point to entry
  627.     ADI    9        ;Point to SYS byte
  628.     MOV    L,A        ;Save (can't carry to H)
  629.  
  630.     IF    SOPT
  631.     LDA    SOPFLG        ;Did user request SYS files?
  632.     ORA    A
  633.     JZ    SYSFOK
  634.     ENDIF
  635.  
  636.     MOV    A,M        ;Get SYS byte
  637.     ORA    A        ;Check bit 7
  638.     JM    MORDIR        ;Skip that file
  639.  
  640. SYSFOK:    MOV    A,L        ;Go back now
  641.     SUI    10        ;Back to user number (alloc flag)
  642.     MOV    L,A        ;HL points to entry now
  643.  
  644.     LDA    NEWUSR        ;Get current user
  645.     CMP    M
  646.     JNZ    MORDIR        ;Ignore    if different
  647.     INX    H
  648.  
  649. * Move entry to    table
  650.  
  651.     XCHG            ;Entry to DE
  652.     LHLD    NEXTT        ;Next table entry to HL
  653.     MVI    B,12        ;Entry length (name, type, extent)
  654.  
  655. TMOVE:    LDAX    D        ;Get entry char
  656.  
  657.     IF    NOT VECTOR
  658.     ANI    7FH        ;Remove    attributes
  659.     ENDIF
  660.  
  661.     MOV    M,A        ;Store in table
  662.     INX    D
  663.     INX    H
  664.     DCR    B        ;More?
  665.     JNZ    TMOVE
  666.     INX    D
  667.     INX    D        ;Point to sector count
  668.     LDAX    D        ;Get it
  669.     MOV    M,A        ;Store in table
  670.     INX    H
  671.     SHLD    NEXTT        ;Save updated table addr
  672.     XCHG
  673.     LHLD    COUNT        ;Bump the # of matches made
  674.     INX    H
  675.     SHLD    COUNT
  676.     LXI    H,13        ;Size of next entry
  677.     DAD    D
  678.     XCHG            ;Future    NEXTT is in DE
  679.     LHLD    BDOS+1        ;Pick up TPA end
  680.     MOV    A,E
  681.     SUB    L        ;Compare NEXTT-TPA end
  682.     MOV    A,D
  683.     SBB    H
  684.     JC    MORDIR        ;If TPA    END > NEXTT then loop back for more
  685.  
  686. OUTMEM:    CALL    ERXIT        ;Exit if directory too large
  687.     DB    'MEMOR','Y' OR 80H
  688.  
  689. * Sort and print
  690.  
  691. SPRINT: IF    AOPT OR FOPT OR UOPT
  692.     CALL    SETFOP        ;Return to file output DMA & user #
  693.     ENDIF
  694.  
  695.     LHLD    COUNT        ;Get file name count
  696.     MOV    A,L
  697.     ORA    H        ;Any found?
  698.     JZ    PRTOTL        ;Exit if no files found
  699.     PUSH    H        ;Save file count
  700.     STA    SUPSPC        ;Enable    leading    zero suppression
  701.  
  702. * Initialize the order table
  703.  
  704.     LHLD    TBLOC        ;Get start of name table
  705.     XCHG            ;Into DE
  706.     LXI    H,ORDER        ;Point to order    table
  707.     LXI    B,13        ;Entry length
  708.  
  709. BLDORD:    MOV    M,E        ;Save low order    address
  710.     INX    H
  711.     MOV    M,D        ;Save high order address
  712.     INX    H
  713.     XCHG            ;Table addr to HL
  714.     DAD    B        ;Point to next entry
  715.     XCHG
  716.     XTHL            ;Save tbl addr,    fetch loop counter
  717.     DCX    H        ;Count down loop
  718.     MOV    A,L
  719.     ORA    H        ;More?
  720.     XTHL            ;(restore tbl addr, save counter)
  721.     JNZ    BLDORD        ;Yes, go do another one
  722.     POP    H        ;Clean loop counter off    stack
  723.     LHLD    COUNT        ;Get count
  724.     SHLD    SCOUNT        ;Save as # to sort
  725.     DCX    H        ;Only 1    entry?
  726.     MOV    A,L
  727.     ORA    H
  728.     JZ    DONE        ;Yes, so skip sort
  729.  
  730. * This sort routine is adapted from SOFTWARE TOOLS
  731. * by Kernigan and Plaugher.
  732.  
  733. SORT:    LHLD    SCOUNT        ;Number    of entries
  734.  
  735. L0:    ORA    A        ;Clear carry
  736.     MOV    A,H        ;GAP=GAP/2
  737.     RAR
  738.     MOV    H,A
  739.     MOV    A,L
  740.     RAR
  741.     MOV    L,A
  742.     ORA    H        ;Is it zero?
  743.     JZ    DONE        ;Then none left
  744.     MOV    A,L        ;Make gap odd
  745.     ORI    01
  746.     MOV    L,A
  747.     SHLD    GAP
  748.     INX    H        ;I=GAP+1
  749.  
  750. L2:    SHLD    I
  751.     XCHG
  752.     LHLD    GAP
  753.     MOV    A,E        ;J=I-GAP
  754.     SUB    L
  755.     MOV    L,A
  756.     MOV    A,D
  757.     SBB    H
  758.     MOV    H,A
  759.  
  760. L3:    SHLD    J
  761.     XCHG
  762.     LHLD    GAP        ;JG=J+GAP
  763.     DAD    D
  764.     SHLD    JG
  765.     MVI    A,12        ;Compare 12 chars
  766.     CALL    COMPARE        ;Compare (J) and (JG)
  767.     JP    L5        ;If A(J)<=A(JG)
  768.     LHLD    J
  769.     XCHG
  770.     LHLD    JG
  771.     CALL    SWAP        ;Exchange A(J) and A(JG)
  772.     LHLD    J        ;J=J-GAP
  773.     XCHG
  774.     LHLD    GAP
  775.     MOV    A,E
  776.     SUB    L
  777.     MOV    L,A
  778.     MOV    A,D
  779.     SBB    H
  780.     MOV    H,A
  781.     JM    L5        ;If J>0    GOTO L3
  782.     ORA    L        ;Check for zero
  783.     JZ    L5
  784.     JMP    L3
  785.  
  786. L5:    LHLD    SCOUNT        ;For later
  787.     XCHG
  788.     LHLD    I        ;I=I+1
  789.     INX    H
  790.     MOV    A,E        ;IF I<=N GOTO L2
  791.     SUB    L
  792.     MOV    A,D
  793.     SBB    H
  794.     JP    L2
  795.     LHLD    GAP
  796.     JMP    L0
  797.  
  798. * Sort is all done - print entries
  799.  
  800. DONE:    IF    FOPT        ;If output option wanted, prepare file
  801.     LDA    FOPFLG
  802.     ORA    A
  803.     JNZ    NOOUT        ;If file output, fall through with A=0
  804.  
  805. * If all user option enabled, and we're not on the first pass, then the
  806. * output file is already open and positioned, so we can skip the open.
  807.  
  808.     LXI    H,OPNFLG    ;Point to output file open flag
  809.     CMP    M        ;A=0, set Z if OPNFLG=0 also
  810.     JNZ    NOOUT        ;If OPNFLG not zero, skip open
  811.     DCR    M        ;Else, make OPNFLG not zero and open
  812.  
  813. * First pass on file append - prepare SD.DIR to receive new or appended
  814. * output.
  815.  
  816.     LXI    D,OUTFCB    ;Does output file already exist?
  817.     MVI    C,SEARCH
  818.     CALL    CPM
  819.     INR    A
  820.     JNZ    OPENIT        ;If it does, then open it for processing
  821.     MVI    C,MAKE        ;Otherwise, create the output file
  822.     CALL    CPM
  823.     INR    A
  824.     JNZ    NOOUT        ;Continue if open successful
  825.  
  826. * If make or open fails, declare error
  827.  
  828. OPNERR:    CALL    ERXIT
  829.     DB    'OPE','N' OR 80H
  830.  
  831. WRTERR:    CALL    ERXIT
  832.     DB    'WRIT','E' OR 80H
  833.  
  834. * Output file already exists - open it and position to the last
  835. * record of the    last extent.
  836.  
  837. OPENIT: MVI    C,OPEN        ;Open 1st extent of output file
  838.     CALL    CPM
  839.     INR    A
  840.     JZ    OPNERR        ;Bad deal if 1st won't open
  841.  
  842. OPNMOR:    LDA    OUTFCB+15
  843.     CPI    128
  844.     JC    LSTEXT        ;If RC<128, this is last extent
  845.     LXI    H,OUTFCB+12
  846.     INR    M        ;Else, bump to next extent
  847.     MVI    C,OPEN        ;..and try to open it
  848.     CALL    CPM
  849.     INR    A
  850.     JNZ    OPNMOR        ;Continue opening extents til no more
  851.     DCR    M        ;Then, reopen preceding    extent
  852.     MVI    C,OPEN
  853.     CALL    CPM
  854.     LDA    OUTFCB+15    ;Get RC    for the    last extent
  855.  
  856. * At this point, OUTFCB is opened to the last extent of the file,
  857. * so read in the last record in the last extent.
  858.  
  859. LSTEXT:    ORA    A        ;Is this extent    empty?
  860.     JZ    NOOUT        ;If so, then we're starting a clean slate
  861.     DCR    A        ;Normalize record count
  862.     STA    OUTFCB+32    ;Set record number to read
  863.     MVI    C,READ        ;..and read last record    of file
  864.     CALL    CPM
  865.     ORA    A        ;Was read successful?
  866.     JZ    RDOK        ;If so,    proceed    to scan    for EOF    mark
  867. APERR:    CALL    ERXIT
  868.     DB    'APPEN','D' OR 80H
  869.  
  870. * We now have the last record in the file in our buffer.
  871. * Scan the last    record for the EOF mark, indicating where
  872. * we can start adding data.
  873.  
  874. RDOK:    LXI    H,OUTBUF    ;Point to start of output buffer
  875.     MVI    B,128        ;Get length of output buffer
  876. SCAN:    MOV    A,M
  877.     CPI    'Z'-40H        ;Have we found end of file?
  878.     JZ    RESCR        ;If so, save pointers and reset CR
  879.     INX    H
  880.     DCR    B
  881.     JNZ    SCAN        ;Otherwise, keep looking til end of buffer
  882.  
  883. * If we find an explicit EOF mark in the last buffer (or an implied EOF
  884. * if the last record is full), move the FCB record and extent pointers
  885. * back to correct for the read operation so that our first write operation
  886. * will effectively replace the last record of the SD.DIR file.
  887.  
  888. RESCR:    PUSH    H        ;Save EOF buffer pointer
  889.     PUSH    B        ;Save EOF buffer remaining
  890.     LXI    H,OUTFCB+32    ;Get current record again
  891.     DCR    M        ;Dock it
  892.     JP    SAMEXT        ;If CR >=0, we're still in same extent
  893.     LXI    H,OUTFCB+12    ;Else, move to previous    extent
  894.     DCR    M
  895.     MVI    C,OPEN        ;Then, reopen the previous extent
  896.     CALL    CPM
  897.     INR    A
  898.     JZ    APERR        ;Append position error if we can't reopen
  899.     LDA    OUTFCB+15    ;Else, position to last record of extent
  900.     DCR    A
  901.     STA    OUTFCB+32
  902. SAMEXT: POP    PSW        ;Recall where EOF is in buffer
  903.     STA    BUFCNT        ;..and set buffer counter
  904.     POP    H        ;Recall next buffer pointer
  905.     SHLD    BUFPNT        ;.. and set pointer for first addition
  906.  
  907.     ENDIF            ;Balance FOPT
  908.  
  909. NOOUT:    LXI    H,ORDER        ;Initialize order table    pointer
  910.     SHLD    NEXTT
  911.     JMP    NEWLIN        ;Start new line    and output the files
  912.  
  913. * Output the directory files we've matched.
  914.  
  915. ENTRY:    LHLD    COUNT
  916.     DCX    H        ;Dock file count
  917.     SHLD    COUNT
  918.     MOV    A,H        ;Is this the last file?
  919.     ORA    L
  920.     JZ    OKPRNT        ;If COUNT=0, last file so skip compare
  921.  
  922. * Compare each entry to    make sure that it isn't part of a multiple
  923. * extent file.    Go only    when we    have the last extent of    the file.
  924.  
  925.     PUSH    B        ;Save NPL
  926.     CALL    CKABRT        ;Check for abort code from keyboard
  927.     LHLD    NEXTT
  928.     MVI    A,11
  929.     CALL    COMPR        ;Does this entry match next one?
  930.     POP    B        ;Recall    NPL
  931.     JNZ    OKPRNT        ;No, print it
  932.     INX    H
  933.     INX    H        ;Skip since highest extent comes last in list
  934.     SHLD    NEXTT
  935.     JMP    ENTRY        ;Loop back for next lowest extent
  936.  
  937. * Valid    entry obtained - spit it out.
  938.  
  939. OKPRNT:    LHLD    NEXTT        ;Get order table pointer
  940.     MOV    E,M        ;Get low order address
  941.     INX    H
  942.     MOV    D,M        ;Get high order    address
  943.     INX    H
  944.     SHLD    NEXTT        ;Save updated table pointer
  945.     XCHG            ;Table entry to    HL
  946.  
  947.     MVI    B,8        ;File name length
  948.     CALL    TYPEIT        ;Type filename
  949.  
  950.     MVI    A,'.'        ;Period    after FN
  951.     CALL    TYPE
  952.  
  953.     MVI    B,3        ;Display 3 characters of filetype
  954.     CALL    TYPEIT
  955.  
  956. * Compute the size of the file and update our summary datum.
  957.  
  958.     MOV    E,M        ;Get extent #
  959.     MVI    D,0
  960.     INX    H
  961.     MOV    A,M        ;Get sector count of last extent
  962.     XCHG
  963.     DAD    H        ;# of extents times 16k
  964.     DAD    H
  965.     DAD    H
  966.     DAD    H
  967.     XCHG            ;Save in DE
  968.     LXI    H,BLKMSK
  969.     ADD    M        ;Round last extent to block size
  970.     RRC
  971.     RRC            ;Convert from sectors to K
  972.     RRC
  973.     ANI    1FH
  974.     MOV    L,A        ;Add to    total K
  975.     MVI    H,0
  976.     DAD    D
  977.     LDA    BLKMSK        ;Get SECTORS/BLK-1
  978.     RRC
  979.     RRC            ;Convert to K/BLK
  980.     RRC
  981.     ANI    1FH
  982.     CMA            ;Use to    finish rounding
  983.     ANA    L
  984.     MOV    L,A
  985.     XCHG            ;Save file size    in DE
  986.     LHLD    TOTSIZ
  987.     DAD    D        ;Add to    total used
  988.     SHLD    TOTSIZ
  989.     LHLD    TOTFIL        ;Increment file    count
  990.     INX    H
  991.     SHLD    TOTFIL
  992.     XCHG            ;Get back file size
  993.  
  994. * If report size enabled, output the size of the individual file.
  995.  
  996.     IF    REPSIZ        ;If file size report wanted
  997.     CALL    DECPRT        ;..go print it
  998.     MVI    A,'k'        ;..and follow with K size
  999.     CALL    TYPE
  1000.     ENDIF
  1001.  
  1002. * One file output - test to see    if we have to output another one.
  1003.  
  1004.     LHLD    COUNT        ;Get current file counter and test it
  1005.     MOV    A,H
  1006.     ORA    L
  1007.     JZ    PRTOTL        ;If no more files, exit    to summary output
  1008.  
  1009. * At least one more file to output - can we put    it on the current line?
  1010.  
  1011.     DCR    C
  1012.     PUSH    PSW
  1013.     CNZ    FENCE        ;If room left, output the fence    character
  1014.     POP    PSW
  1015.     JNZ    ENTRY        ;.. and    go output another file
  1016.  
  1017. * Current line full, start a new one.
  1018.  
  1019. NEWLIN:    MVI    C,NPL        ;Reset names per line counter
  1020.     CALL    CRLF        ;Space down to next line
  1021.  
  1022.     IF    NPL LT 4    ;If printing less than 4 wide ..
  1023.     LDA    FCB        ;.. precede new    line with drive    name
  1024.     ADI    'A'-1
  1025.     CALL    TYPE
  1026.  
  1027.     IF    REPUSR        ;If reporting user numbers and running under
  1028.     CALL    CKVER        ;..CP/M    2, output the user number too
  1029.     CNC    TYPUSR
  1030.     ENDIF            ;Balance REPUSR
  1031.  
  1032.     MVI    A,':'        ;Tag header with a colon and a space
  1033.     CALL    FPAD        ;..and exit back to ENTRY
  1034.  
  1035.     ENDIF            ;Balance NPL GT    3
  1036.  
  1037.     JMP    ENTRY        ;Go back and output another file
  1038.  
  1039. * Print    HL in decimal with leading zero    suppression
  1040.  
  1041. DECPRT:    SUB    A        ;Clear leading zero flag
  1042.     STA    LZFLG
  1043.     LXI    D,-1000        ;Print 1000's digit
  1044.     CALL    DIGIT
  1045.     LXI    D,-100        ;Etc.
  1046.     CALL    DIGIT
  1047.     LXI    D,-10
  1048.     CALL    DIGIT
  1049.     MVI    A,'0'        ;Get 1's digit
  1050.     ADD    L
  1051.     JMP    TYPE
  1052.  
  1053. DIGIT:    MVI    B,'0'        ;Start off with    ASCII 0
  1054.  
  1055. DIGLP:    PUSH    H        ;Save current remainder
  1056.     DAD    D        ;Subtract
  1057.     JNC    DIGEX        ;Quit on overflow
  1058.     POP    PSW        ;Throw away remainder
  1059.     INR    B        ;Bump digit
  1060.     JMP    DIGLP        ;Loop back
  1061.  
  1062. DIGEX:    POP    H        ;Restore pointer
  1063.     MOV    A,B
  1064.     CPI    '0'        ;Zero digit?
  1065.     JNZ    DIGNZ        ;No, type it
  1066.     LDA    LZFLG        ;Leading zero?
  1067.     ORA    A
  1068.     MVI    A,'0'
  1069.     JNZ    TYPE        ;Print digit
  1070.     LDA    SUPSPC        ;Get space suppression flag
  1071.     ORA    A        ;See if    printing file totals
  1072.     RZ            ;Yes, don't give leading spaces
  1073.     JMP    SPACE        ;Leading zero...print space
  1074.  
  1075. DIGNZ:    STA    LZFLG        ;Set leading zero flag so next zero prints
  1076.     JMP    TYPE        ;And print digit
  1077.  
  1078. * Show total space and files used
  1079.  
  1080. PRTOTL:    XRA    A        ;Get a zero to...
  1081.     STA    SUPSPC        ;Suppress leading spaces in totals
  1082.  
  1083.     LHLD    TOTFIL        ;How many files    did we match?
  1084.     MOV    A,H
  1085.     ORA    L
  1086.  
  1087.     JZ    NXTUSR        ;Skip the summary if we    didn't find any
  1088.  
  1089.     PUSH    H        ;Save TOTFIL
  1090.     STA    FNDFLG        ;Set file found flag
  1091.  
  1092.     LXI    D,TOTMS1    ;Print [CR,LF,LF]"DRIVE    "
  1093.     CALL    PRINT
  1094.     LDA    FCB
  1095.     ADI    'A'-1
  1096.     CALL    TYPE        ;Output    the drive code
  1097.  
  1098.     IF    REPUSR
  1099.     CALL    CKVER
  1100.     JC    NOUSER
  1101.     LXI    D,TOTMS2    ;Print ", USER "
  1102.     CALL    PRINT
  1103.     CALL    TYPUSR        ;Output    the user number
  1104.     ENDIF
  1105.  
  1106. NOUSER:    LXI    D,TOTMS3    ;Print " CONTAINS "
  1107.     CALL    PRINT
  1108.     LHLD    TOTSIZ        ;Print total K used by files matched
  1109.     CALL    DECPRT
  1110.     LXI    D,TOTMS4    ;PRINT "K IN "
  1111.     CALL    PRINT
  1112.     POP    H        ;Recall    TOTFIL
  1113.     CALL    DECPRT        ;Print number of files matched
  1114.     LXI    D,TOTMS5    ;Print " FILES WITH "
  1115.     CALL    PRINT
  1116.     CALL    PRTFRE        ;Output    free space remaining & " FREE."
  1117.  
  1118. * Directory for    one user area completed.  If all users option is
  1119. * selected, then go do another directory on the    next user number
  1120. * until    we exceed the maximum user # for the selected drive.
  1121.  
  1122. NXTUSR:    IF    AOPT        ;If all    users option enabled
  1123.     LDA    AOPFLG        ;If not    all users mode - skip next
  1124.     ORA    A
  1125.     JNZ    GOCLZ
  1126.     CALL    CKVER        ;Are we running CP/M 2?
  1127.     JC    GOCLZ        ;Skip user increment if not
  1128.     CALL    CKABRT        ;Check for user    abort first
  1129.     LDA    MAXUSR        ;No abort - get    maximum    user number
  1130.     LXI    H,NEWUSR    ;Bump directory    user number
  1131.     INR    M
  1132.     CMP    M        ;Does next user    # exceed maximum?
  1133.     JNC    SETTBL        ;Continue if more user areas to    go
  1134.  
  1135.     IF    DOPT        ;If multi-disk option enabled
  1136.     LDA    BASUSR        ;Reset base user number    for the
  1137.     MOV    M,A        ;..next    directory search
  1138.     ENDIF            ;Balance DOPT
  1139.  
  1140.     ENDIF            ;Balance AOPT
  1141.  
  1142. * We've finished all of our outputting.  Flush the remainder of the
  1143. * output buffer and close the file before going to exit routine.
  1144.  
  1145. GOCLZ:    IF    FOPT
  1146.     LXI    H,OPNFLG    ;Get file open status then reset flag to
  1147.     MOV    A,M        ;..force reopen on next pass
  1148.     MVI    M,0
  1149.     ORA    A
  1150.     JZ    NXTDSK        ;Skip closing SD.DIR if it wasn't opened
  1151.  
  1152.     LXI    H,BUFCNT
  1153.     MOV    A,M        ;Retrieve # of unflushed characters in buffer
  1154.     MVI    M,128        ;Force BUFCNT to EMPTY status for next drive
  1155.     ORA    A        ;If BUFCNT=128, buffer empty so set sign bit
  1156.     JM    CLOZE        ;Close SD.DIR if buffer is empty
  1157.     JZ    FLUSH        ;Write last record to SD.DIR if buffer full
  1158.  
  1159.     LHLD    BUFPNT        ;Otherwise, pad    unused buffer with CTRL-Zs
  1160. PUTAGN:    MVI    M,'Z'-40H
  1161.     INX    H
  1162.     DCR    A
  1163.     JNZ    PUTAGN        ;Continue padding til buffer filled out
  1164.  
  1165. FLUSH:    LXI    D,OUTFCB    ;Flush the last    output buffer
  1166.     MVI    C,WRITE
  1167.     CALL    CPM
  1168.     ORA    A
  1169.     JNZ    WRTERR
  1170. CLOZE:    LXI    D,OUTFCB    ;Close the output file
  1171.     MVI    C,CLOSE
  1172.     CALL    CPM
  1173.     ENDIF            ;Balance FOPT
  1174.  
  1175. * Directory for    all user areas completed.  If the multi-disk option
  1176. * is enabled and selected, reset to the    base user area and repeat
  1177. * the directory    for next drive on-line until we    either exceed the
  1178. * drives in our    LODRV-HIDRV table, or the BDOS shuts us    down with
  1179. * a select or bad sector error,    which will be intercepted back to
  1180. * the EXIT module.
  1181.  
  1182. NXTDSK: LXI    H,FNDFLG    ;Get file found flag
  1183.     MOV    A,M
  1184.     MVI    M,0        ;Clear file found flag for next drive
  1185.     ORA    A
  1186.     JNZ    NDSK        ;Continue if at least 1 file found
  1187.  
  1188.     IF    FOPT        ;If file output enabled, disable temporarily
  1189.     LXI    H,FOPFLG
  1190.     DCR    M
  1191.     PUSH    H
  1192.     ENDIF
  1193.  
  1194.     LDA    FCB        ;Stash ASCII directory drive in NO FILE msg
  1195.     ADI    'A'-1
  1196.     STA    NOFMS2
  1197.     LXI    D,NOFMS1    ;Print "NO FILE ON ? - "
  1198.     CALL    PRINT
  1199.     CALL    PRTFRE        ;Tag with free message
  1200.  
  1201.     IF    FOPT        ;Restore original file output mode
  1202.     POP    H
  1203.     INR    M
  1204.     ENDIF
  1205.  
  1206. NDSK:    IF    DOPT        ;If multi-disk option enabled
  1207.     LDA    DOPFLG        ;If multi-disk not selected - skip next
  1208.     ORA    A
  1209.     JNZ    EXIT
  1210.     CALL    CKABRT        ;Check for user    abort first
  1211.     MVI    A,HIDRV-LODRV    ;Get maximum drive code    to search
  1212.     LXI    H,FCB        ;Bump directory    FCB drive code
  1213.     INR    M
  1214.     CMP    M        ;Does next disk    exceed maximum?
  1215.     JNC    NOOPT        ;Search    next disk if not
  1216.     ENDIF            ;Balance DOPT
  1217.  
  1218.     JMP    EXIT        ;All done - exit to CCP
  1219.  
  1220. * Print    the user number    of the directory in decimal
  1221.  
  1222. TYPUSR:    IF    REPUSR
  1223.     LDA    NEWUSR
  1224.     CPI    10        ;If user no. > 9 print leading 1
  1225.     JC    DUX
  1226.     MVI    A,'1'
  1227.     CALL    TYPE
  1228.     LDA    NEWUSR        ;Print low digit of user no.
  1229.     SUI    10
  1230. DUX:    ADI    '0'
  1231.     JMP    TYPE
  1232.     ENDIF
  1233.  
  1234. * Force    new line on video and check for    page pause
  1235.  
  1236. CRLF:    MVI    A,0DH        ;Send CR
  1237.     CALL    TYPE
  1238.     MVI    A,0AH        ;Send LF
  1239.     JMP    TYPE        ;Exit to caller    from TYPE
  1240.  
  1241. * Separate the directory output    on a line with a space,    the delimiter,
  1242. * followed by another space.
  1243.  
  1244. FENCE:    CALL    SPACE
  1245.  
  1246.     MVI    A,DELIM        ;Fence character
  1247. FPAD:    CALL    TYPE        ;Print it, fall    into space
  1248.  
  1249. SPACE:    MVI    A,' '        ;Fall through to TYPE
  1250.  
  1251. * Output character in A to console, and optionally to printer and/or
  1252. * the output file.
  1253.  
  1254. TYPE:    PUSH    B
  1255.     PUSH    D
  1256.     PUSH    H
  1257.  
  1258.     IF    FOPT OR    POPT OR    PGPAWZ
  1259.     PUSH    PSW        ;Save the character to output
  1260.     ENDIF
  1261.     CALL    TYPE1        ;Send it to console
  1262.     IF    FOPT OR    POPT OR    PGPAWZ
  1263.     POP    PSW        ;Restore the output character
  1264.     ENDIF
  1265.  
  1266.     IF    VECTOR AND (FOPT OR PGPAWZ)
  1267.     ANI    7FH        ;Strip parity bit on character
  1268.     ENDIF
  1269.  
  1270. * Test file output mode and skip to page pause test if not active.
  1271.  
  1272.     IF    FOPT
  1273.     MOV    B,A        ;Save stripped character to B
  1274.     LDA    FOPFLG        ;Is file output    active?
  1275.     ORA    A
  1276.     JNZ    NOWRIT        ;Go check for page pause if not
  1277.  
  1278. * File output mode active - make sure we have room in buffer to add
  1279. * next character.  If buffer full, write out current record first
  1280. * and then start a new record with current character.
  1281.  
  1282.     LHLD    BUFPNT        ;Get current buffer pointer
  1283.     LDA    BUFCNT        ;Get buffer capacity remaining
  1284.     ORA    A
  1285.     JNZ    PUTBUF        ;Continue if buffer not full
  1286.     LXI    D,OUTFCB    ;Otherwise, write the current buffer out
  1287.     MVI    C,WRITE
  1288.     CALL    CPM        ;(Note call must save character    in B)
  1289.     ORA    A
  1290.     JNZ    WRTERR        ;Take write error exit if disk full or R/O
  1291.     LXI    H,OUTBUF    ;Reset buffer pointer
  1292.     MVI    A,128        ;Reset buffer capacity
  1293.  
  1294. PUTBUF: MOV    M,B        ;Shove character to next buffer position
  1295.     INX    H        ;Bump buffer pointer
  1296.     SHLD    BUFPNT        ;.. and save it
  1297.     DCR    A        ;Dock count of characters left in buffer
  1298.     STA    BUFCNT        ;..and save it
  1299.  
  1300. NOWRIT:    MOV    A,B        ;Recall    stripped character
  1301.  
  1302.     ENDIF            ;Balance FOPT
  1303.  
  1304.     IF    POPT        ;If printer option
  1305.     MOV    E,A        ;Setup list output call
  1306.     MVI    C,5
  1307.     LDA    POPFLG        ;Test printer flag
  1308.     ORA    A
  1309.     CZ    CPM        ;Print character if flag true
  1310.     MOV    A,E        ;Recall    character
  1311.     ENDIF
  1312.  
  1313.     IF    PGPAWZ
  1314.     CPI    0AH        ;Do we have a LF?
  1315.     JNZ    TYPRET        ;Exit if not
  1316.     ENDIF
  1317.  
  1318.     IF    NOPT AND PGPAWZ
  1319.     LDA    NOPFLG        ;Is the    page pause function disabled?
  1320.     ORA    A
  1321.     JZ    TYPRET        ;Exit if so
  1322.     ENDIF
  1323.  
  1324.     IF    PGPAWZ
  1325.     LDA    LINCNT        ;Get line count
  1326.     INR    A        ;Bump it
  1327.     CPI    LPS        ;Are we    at the end of the screen?
  1328.     JC    NOTEOS        ;Skip if not
  1329.     LXI    D,EOSMSG    ;Else, display pause message
  1330.     MVI    C,9        ;..without checking for    LFs
  1331.     CALL    BDOS
  1332.     CALL    CINPUT        ;Wait for character
  1333.     CPI    'C'-40H
  1334.     JZ    EXIT        ;Abort on CTRL-C
  1335.     XRA    A        ;Reset line count
  1336. NOTEOS:    STA    LINCNT        ;Save new line count
  1337.     ENDIF
  1338.  
  1339. TYPRET:    POP    H        ;Exit from TYPE
  1340.     POP    D
  1341.     POP    B
  1342.     RET
  1343.  
  1344. * Output character directly through the    BIOS
  1345.  
  1346. TYPE1:    IF    VECTOR
  1347.     ORA    A        ;Set sign flag if MS bit is on
  1348.     JP    TYPE2        ;If character is ASCII,    continue
  1349.     MOV    B,A        ;Else, get character to    B
  1350.     MVI    A,5        ;Set video driver function for direct output
  1351.     JMP    VIDEO        ;Display in reverse video and exit from    VIDEO
  1352.     ENDIF
  1353.  
  1354.     IF    DIRCON
  1355. TYPE2:    MOV    C,A        ;Get character into BIOS entry register
  1356.     LHLD    BASE+1        ;Get page base of BIOS
  1357.     MVI    L,12        ;Get entry vector to CONOUT
  1358.     JMP    GOHL        ;Call CONOUT direct through the BIOS
  1359.     ELSE
  1360.  
  1361. TYPE2:    MOV    E,A        ;Get character into BDOS entry register
  1362.     MVI    C,WRCHR
  1363.     JMP    BDOS        ;Call CONOUT via the BDOS
  1364.     ENDIF            ;Balance DIRCON
  1365.  
  1366. * Print    a string at HL of length B
  1367.  
  1368. TYPEIT:    MOV    A,M
  1369.     CALL    TYPE
  1370.     INX    H
  1371.     DCR    B
  1372.     JNZ    TYPEIT
  1373.     RET
  1374.  
  1375. * Print    string terminated with last byte high on console.
  1376.  
  1377. PRINT:    LDAX    D
  1378.     PUSH    PSW
  1379.     ANI    7FH
  1380.     CALL    TYPE
  1381.     POP    PSW
  1382.     ORA    A
  1383.     RM
  1384.     INX    D
  1385.     JMP    PRINT
  1386.  
  1387. * Fetch    character from console (without    echo)
  1388.  
  1389. CINPUT:    LHLD    BASE+1
  1390.     MVI    L,9
  1391.     CALL    GOHL
  1392.     ANI    7FH
  1393.     RET
  1394.  
  1395. * Check    for a CTRL-C or    CTRL-S entered from the    keyboard.  Jump    to
  1396. * exit if CTRL-C, pause    on CTRL-S.
  1397.  
  1398. CKABRT:    LHLD    BASE+1
  1399.     MVI    L,6        ;Check status of keyboard
  1400.     CALL    GOHL        ;Any key pressed?
  1401.     ORA    A
  1402.     RZ            ;No, return to caller
  1403.     CALL    CINPUT        ;Get character
  1404.     CPI    'C'-40H        ;CTRL-C?
  1405.     JZ    EXIT        ;If CTRL-C then    quit
  1406.     CPI    'S'-40H        ;CTRL-S?
  1407.     RNZ            ;No, return to caller
  1408.     CALL    CINPUT        ;Yes, wait for another char.
  1409.     CPI    'C'-40H        ;Might be CTRL-C
  1410.     JZ    EXIT        ;Exit if CTRL-C, else fall thru    and continue
  1411.     RET
  1412.  
  1413. * Kludge to allow call to address in HL
  1414.  
  1415. GOHL:    PCHL
  1416.  
  1417. * Entry    to BDOS    saving all extended registers
  1418.  
  1419. CPM:    PUSH    B
  1420.     PUSH    D
  1421.     PUSH    H
  1422.     CALL    BDOS
  1423.     POP    H
  1424.     POP    D
  1425.     POP    B
  1426.     RET
  1427.  
  1428. * For file output mode,    return to old user area    and set    DMA for
  1429. * the file output buffer.
  1430.  
  1431. SETFOP:    IF    UOPT OR    AOPT
  1432.     CALL    CKVER        ;Clear carry if    CP/M 2 or later
  1433.     LDA    OLDUSR        ;Get user number at startup
  1434.     MOV    E,A
  1435.     MVI    C,CURUSR
  1436.     CNC    CPM        ;Reset the old user number if CP/M 2
  1437.     ENDIF
  1438.  
  1439.     IF    FOPT
  1440.     LXI    D,OUTBUF    ;Move DMA from search buffer into the
  1441.     JMP    SET2        ;..output buffer
  1442.     ENDIF
  1443.     RET
  1444.  
  1445. * Move disk buffer DMA to default buffer for directory search operations
  1446. * and BDOS media change routines (necessary for pre-CP/M 2 systems while
  1447. * in file output mode with an active buffer).
  1448.  
  1449. SETSRC: LXI    D,BASE+80H
  1450. SET2:    MVI    C,SETDMA
  1451.     JMP    CPM
  1452.  
  1453. * Print    the amount of free space remaining on the selected drive
  1454.  
  1455. PRTFRE: LHLD    FREEBY        ;Get space left before adding to MASTER.DIR
  1456.     CALL    DECPRT        ;Print K free
  1457.     LXI    D,TOTMS6    ;Print " FREE."
  1458.     JMP    PRINT
  1459.  
  1460. * Compare routine for sort
  1461.  
  1462. COMPR:    PUSH    H        ;Save table addr
  1463.     MOV    E,M        ;Load low order
  1464.     INX    H
  1465.     MOV    D,M        ;Load high order
  1466.     INX    H
  1467.     MOV    C,M
  1468.     INX    H
  1469.     MOV    B,M
  1470.  
  1471. * BC, DE now point to entries to be compared
  1472.  
  1473.     XCHG
  1474.     MOV    E,A        ;Get count
  1475.  
  1476. CMPLP:    LDAX    B
  1477.     CMP    M
  1478.     INX    H
  1479.     INX    B
  1480.     JNZ    NOTEQL        ;Quit on mismatch
  1481.     DCR    E        ;Or end    of count
  1482.     JNZ    CMPLP
  1483.  
  1484. NOTEQL:    POP    H
  1485.     RET            ;Cond code tells all
  1486.  
  1487. * Swap entries in the order table
  1488.  
  1489. SWAP:    LXI    B,ORDER-2    ;Table base
  1490.     DAD    H        ;*2
  1491.     DAD    B        ;+ base
  1492.     XCHG
  1493.     DAD    H        ;*2
  1494.     DAD    B        ;+ base
  1495.     MOV    C,M
  1496.     LDAX    D
  1497.     XCHG
  1498.     MOV    M,C
  1499.     STAX    D
  1500.     INX    H
  1501.     INX    D
  1502.     MOV    C,M
  1503.     LDAX    D
  1504.     XCHG
  1505.     MOV    M,C
  1506.     STAX    D
  1507.     RET
  1508.  
  1509. * New compare routine
  1510.  
  1511. COMPARE:LXI    B,ORDER-2
  1512.     DAD    H
  1513.     DAD    B
  1514.     XCHG
  1515.     DAD    H
  1516.     DAD    B
  1517.     XCHG
  1518.     MOV    C,M
  1519.     INX    H
  1520.     MOV    B,M
  1521.     XCHG
  1522.     MOV    E,M
  1523.     INX    H
  1524.     MOV    D,M
  1525.     XCHG
  1526.     MOV    E,A        ;Count
  1527.  
  1528. CMPLPE:    LDAX    B
  1529.     CMP    M
  1530.     INX    B
  1531.     INX    H
  1532.     RNZ
  1533.     DCR    E
  1534.     JNZ    CMPLPE
  1535.     RET
  1536.  
  1537. * Error    exit
  1538.  
  1539. ERXIT:    IF    FOPT
  1540.     MVI    A,-1
  1541.     STA    FOPFLG        ;Disable file output mode on error
  1542.     ENDIF
  1543.  
  1544.     CALL    CRLF        ;Space down
  1545.     POP    D        ;Get pointer to    message    string
  1546.     CALL    PRINT        ;Print it
  1547.     LXI    D,ERRMS1    ;Print " ERROR"
  1548.     CALL    PRINT
  1549.     CALL    CRLF        ;Space down
  1550.  
  1551. * Exit - all done, restore stack
  1552.  
  1553. EXIT:    MVI    C,CONST        ;Check console status
  1554.     CALL    CPM
  1555.     ORA    A        ;Char waiting?
  1556.     MVI    C,RDCHR
  1557.     CNZ    CPM        ;Gobble    up char
  1558.  
  1559.     IF    DOPT        ;Restore BDOS intercept    vectors
  1560.     CALL    SWAPEM
  1561.     ENDIF
  1562.  
  1563.     IF    ROPT
  1564.     LDA    ROPFLG        ;If disk system    was reset
  1565.     ORA    A
  1566.     LDA    OLDDSK        ;Get default disk at startup
  1567.     MOV    E,A
  1568.     MVI    C,SELDSK    ;Reselect it
  1569.     CZ    CPM
  1570.     ENDIF            ;Balance ROPT
  1571.  
  1572.     LHLD    STACK        ;Get old stack pointer
  1573.     SPHL            ;Move back to old stack
  1574.     RET            ;..and return to CCP
  1575.  
  1576. * Exchange BDOS    select and sector error    vectors    for our    own intercept
  1577. * vectors so we    can catch a reference to an illegal drive.
  1578.  
  1579.     IF    DOPT
  1580. SWAPEM:    LHLD    BDOS+1        ;Get pointer to    base of    BDOS
  1581.     MVI    L,9        ;Point to sector error vector
  1582.     LXI    D,VECTBL    ;Exchanging with our own vector    table
  1583.     MVI    A,4        ;4 bytes to swap
  1584. SWAPLP:    MOV    B,M        ;Get byte from HL
  1585.     XCHG
  1586.     MOV    C,M        ;Get byte from DE
  1587.     MOV    M,B        ;Put byte from HL
  1588.     XCHG
  1589.     MOV    M,C        ;Put byte from DE
  1590.     INX    H        ;Bump exchange pointers
  1591.     INX    D
  1592.     DCR    A        ;Dock counter
  1593.     JNZ    SWAPLP        ;Continue swapping til done
  1594.     RET
  1595.     ENDIF
  1596.  
  1597. * Check    CP/M version number.  Return carry flag    set if pre-CP/M    2.
  1598. * If CP/M 2 or later or    MP/M (any version), return carry clear.
  1599.  
  1600. CKVER:    LDA    VERFLG
  1601.     CPI    20H
  1602.     RET
  1603.  
  1604. * Recovery point from intercepted BDOS select and bad sector errors.
  1605.  
  1606. DSKERR: IF    DOPT
  1607.     LXI    SP,STACK    ;Get out of BDOS' stack
  1608.     JMP    EXIT        ;..and exit back to CCP
  1609.     ENDIF
  1610.  
  1611. ***********************
  1612. *              *
  1613. * End of Program Code *
  1614. *              *
  1615. ***********************
  1616.  
  1617. * Initialized data area
  1618.  
  1619. DREMSG:    DB    'DRIV','E' OR 80H
  1620.  
  1621.     IF    PGPAWZ
  1622. EOSMSG: DB    0AH,'[ More ]',0DH,0AH,0AH,'$'
  1623.     ENDIF
  1624.  
  1625. ERRMS1: DB    ' '
  1626. ERRMS2:    DB    'ERRO','R' OR 80H
  1627.  
  1628.     IF    REPERR
  1629. ERRTAG:    DB    ' -','>' OR 80H
  1630.     ENDIF
  1631.  
  1632. NOFMS1: DB    0DH,0AH,'NO FILE ON '
  1633. NOFMS2: DB    '  -',' ' OR 80H
  1634.  
  1635. TOTMS1:    DB    0DH,0AH,0DH,0AH,'DRIVE',' ' OR 80H
  1636.  
  1637.     IF    REPUSR
  1638. TOTMS2:    DB    ', USER',' ' OR    80H
  1639.     ENDIF
  1640.  
  1641. TOTMS3:    DB    ' CONTAINS',' '    OR 80H
  1642. TOTMS4: DB    'K IN',' ' OR 80H
  1643. TOTMS5:    DB    ' FILES WITH',' ' OR 80H
  1644. TOTMS6: DB    'K FREE',0DH,0AH OR 80H
  1645. USRMSG: DB    'USER ','#' OR 80H
  1646.  
  1647. FNDFLG: DB    0        ;Flag whether any files matched
  1648.  
  1649.     IF    PGPAWZ
  1650. LINCNT:    DB    0        ;Count of lines    printed    on screen
  1651.     ENDIF
  1652.  
  1653. * Drive    code/user area lookup table
  1654.  
  1655. * Note that the    LODRV-HIDRV table is included here fully configured.
  1656. * For your own use, you    should change the maximum user areas as
  1657. * appropriate for each drive on    your system, and then delete any
  1658. * DBs referencing drives that don't exist.  Note also that there
  1659. * are only 16 user areas available under CP/M 2, so the highest
  1660. * legal user area you can specify is 15 (range 0-15 = 16 areas).
  1661. * The program will convert anything over 15 into mod 15.
  1662.  
  1663. LODRV    EQU    $        ;Mark beginning    of drive/user table
  1664.  
  1665.     DB    15        ;Maximum user area for Drive A
  1666.     DB    15        ;   "      "    "    "     "   B
  1667.     DB    15        ;   "      "    "    "     "   C
  1668.     DB    15        ;   "      "    "    "     "   D
  1669.     DB    15        ;   "      "    "    "     "   E
  1670.     DB    15        ;   "      "    "    "     "   F
  1671.     DB    15        ;   "      "    "    "     "   G
  1672.     DB    15        ;   "      "    "    "     "   H
  1673.     DB    15        ;   "      "    "    "     "   I
  1674.     DB    15        ;   "      "    "    "     "   J
  1675.     DB    15        ;   "      "    "    "     "   K
  1676.     DB    15        ;   "      "    "    "     "   L
  1677.     DB    15        ;   "      "    "    "     "   M
  1678.     DB    15        ;   "      "    "    "     "   N
  1679.     DB    15        ;   "      "    "    "     "   O
  1680.     DB    15        ;   "      "    "    "     "   P
  1681.  
  1682. HIDRV    EQU    $        ;Mark end of drive/user    table
  1683.  
  1684. * Option field lookup table.
  1685. * Note that you    can force any of these options as a DEFAULT by
  1686. * changing the letter for the option into a zero (assuming that
  1687. * its enabling equate is true).     Each option that you hard-wire    in
  1688. * this manner will no longer be    recognized as a    command    line OPTION,
  1689. * and if you redundantly key it in, SD will flag it as unrecognized.
  1690.  
  1691. OTBL    EQU    $        ;Mark start of option table
  1692.  
  1693.     IF    AOPT        ;All users-option flag
  1694. AOPFLG:    DB    'A'
  1695.     ENDIF
  1696.  
  1697.     IF    DOPT        ;Multi-disk-option flag
  1698. DOPFLG:    DB    'D'
  1699.     ENDIF
  1700.  
  1701.     IF    FOPT        ;File-output-option flag
  1702. FOPFLG: DB    'F'
  1703.     ENDIF
  1704.  
  1705.     IF    NOPT AND PGPAWZ    ;No page-pause option flag
  1706. NOPFLG:    DB    'N'
  1707.     ENDIF
  1708.  
  1709.     IF    POPT        ;Printer option    flag
  1710. POPFLG:    DB    'P'
  1711.     ENDIF
  1712.  
  1713.     IF    ROPT        ;Reset option flag
  1714. ROPFLG:    DB    'R'
  1715.     ENDIF
  1716.  
  1717.     IF    SOPT        ;System    file option flag
  1718. SOPFLG:    DB    'S'
  1719.     ENDIF
  1720.  
  1721. OEND    EQU    $        ;Mark end of option table
  1722.  
  1723. * End of option    lookup table
  1724.  
  1725.     IF    DOPT
  1726. VECTBL:    DW    DSKERR        ;BDOS sector error intercept vector
  1727.     DW    DSKERR        ;BDOS select error intercept vector
  1728.     ENDIF
  1729.  
  1730.     IF    FOPT
  1731. BUFPNT: DW    OUTBUF        ;Pointer to next location in output buffer
  1732. BUFCNT: DB    128        ;Number of bytes left in output buffer
  1733. OPNFLG: DB    0        ;File open flag for all user file output
  1734. OUTFCB:    DB    0,'SD      DIR'
  1735.     FILL    21,0        ;Rest of SD.DIR FCB
  1736. OUTBUF    DS    128        ;Output    file buffer
  1737.     ENDIF
  1738.  
  1739. * Uninitialized    data area
  1740.  
  1741. BASUSR    DS    1        ;Dupe of original directory user # to search
  1742. BLKMAX    DS    2        ;Highest block # on drive
  1743. BLKMSK    DS    1        ;SEC/BLK - 1
  1744. BLKSHF    DS    1        ;# shifts to mult by SEC/BLK
  1745. COUNT    DS    2        ;Entry count
  1746. DIRMAX    DS    2        ;Highest file #    in directory
  1747. FREEBY    DS    2        ;Contains number of K left on directory    drive
  1748. GAP    DS    2        ;Sort routine storage
  1749. I    DS    2        ;Sort routine storage
  1750. J    DS    2        ;Sort routine storage
  1751. JG    DS    2        ;Sort routine storage
  1752. LZFLG    DS    1        ;0 when    printing leading zeros
  1753. MAXUSR    DS    1        ;Maximum user #    for drive from lookup table
  1754. NEWUSR    DS    1        ;Contains user number selected by "$U" option
  1755. NEXTT    DS    2        ;Next table entry
  1756. OLDDSK    DS    1        ;Holder    for currently logged-in    drive
  1757. OLDUSR    DS    1        ;Contains user number upon invocation
  1758. SCOUNT    DS    2        ;# to sort
  1759. SUPSPC    DS    1        ;Leading space flag for    decimal    routine
  1760. TBLOC    DS    2        ;Pointer to start of name table
  1761. TEMP    DS    2        ;Save dir entry
  1762. TOTFIL    DS    2        ;Total number of files
  1763. TOTSIZ    DS    2        ;Total size of all files
  1764. VERFLG    DS    1        ;CP/M version number (0=pre-CP/M 2)
  1765.  
  1766.     DS    60        ;Stack area
  1767. STACK    DS    2        ;Save old stack    pointer    here
  1768.  
  1769. ORDER    EQU    $        ;Order table starts here
  1770.  
  1771.     END
  1772.