home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / S / SD132.LBR / SD132.AZM / SD132.ASM
Assembly Source File  |  2000-06-30  |  91KB  |  3,860 lines

  1. ;              SUPER DIRECTORY PROGRAM
  2. ;                   SD132
  3. ;                 17 Apr 88
  4. ;
  5. ;    Read SD.INF for detailed instructions on configuring SD for your
  6. ;    system.  For information regarding this utility's modification
  7. ;    history, read SD.HIS.
  8. ;
  9. ;        This program is being distributed ready
  10. ;        to use on a CP/M v2.2 computer with two
  11. ;        disk drives and no ZCPR in use.
  12. ;
  13. ;        (Options often changed for RCPM use are
  14. ;        marked with an asterisk.)  The typical
  15. ;        RCPM Sysop might change only these:
  16. ;
  17. ;            a)    3 options starting at MAXDRV
  18. ;            b)    how many drives at LODRV and
  19. ;            c)    5 options starting at USEF
  20. ;            d)    USELCW needs wheel to prevent
  21. ;               showing archive bits
  22. ;
  23. ;
  24. ;         NOTE:  This version can be assembled with
  25. ;            ASM, LASM, M80, MAC or SLRMAC.
  26. ;
  27. ; SD displays the directory of a CP/M disk, sorted alphabetically, with
  28. ; the file size in k, rounded to the nearest CP/M block size.  It also
  29. ; displays library and archive files with the file size in k, if the $L
  30. ; option is selected.
  31. ;
  32. ; Current versions of SD automatically adjust for any block size and di-
  33. ; rectory length under CP/M 2.2,  3.0 or MP/M.    They can also handle any
  34. ; number of disk drives or skip those not available.  Current features:
  35. ;
  36. ;     1) Automatic pauses when the screen fills up except when the
  37. ;        F, N, or P options are specified
  38. ;     2) Searching individual or multiple drives and/or user areas
  39. ;     3) Unconditional or optional disk system reset before execution
  40. ;        begins
  41. ;     4) Directing output to a disk file called DISK.DIR and append-
  42. ;        ing to that file on subsequent runs
  43. ;     5) Summary line output giving drive and user information, num-
  44. ;        ber of files matched, how much space they consume and free
  45. ;        space remaining on the disk
  46. ;     6) Displaying or suppressing "system" files
  47. ;     7) Accepting ambiguous filenames with or without a drive name
  48. ;     8) Printer output (automatically suppresses the [more] pauses)
  49. ;     9) Optional help menu with '?'
  50. ;    10) Displaying number of records used by files
  51. ;    11) Alphabetization of files sorted by type (extent)
  52. ;    12) Selecting alternate list format - vertical if horizontal
  53. ;        is default, and vice versa.
  54. ;    13) Shows contents of .ARC, .ARK or .LBR files with $L option
  55. ;    14) Summary line output optionally contains name of ZCPR3 named
  56. ;        directory, if selected
  57. ;    15) ZCPR3 named directory may be used in command line instead
  58. ;        of DU: if selected
  59. ;    16) ZCPR3 Public user areas may be displayed with or without
  60. ;        WHEEL byte
  61. ;
  62. ;-----------------------------------------------------------------------
  63. ;
  64. ;    ASEG            ; Needed for M80 and RMAC, ignore error
  65. ;
  66.     ORG    0100H
  67. ;
  68.     JMP    START
  69. ;
  70. NO    EQU    0
  71. YES    EQU    NOT NO        ; (Some assemblers don't like 0FFh)
  72. ;
  73. ; Define version number
  74. ;
  75. MAIN    EQU    1        ; Main block number
  76. VER    EQU    32        ; Current version
  77. MONTH    EQU    04        ; Month
  78. DAY    EQU    17        ; Day
  79. YEAR    EQU    88        ; Year
  80. ;
  81. ;-----------------------------------------------------------------------
  82. ;                 options
  83. ;
  84. MAXDRV    EQU    NO        ; *Yes if MAXD byte is supported
  85. MAXUR    EQU    NO        ; *Yes if MAXU byte is supported
  86. WHEEL    EQU    NO        ; *Yes if using ZCPR wheel byte
  87.  
  88. MXDRV    EQU    3DH        ; *Set to max drive address if MAXDRV=Yes
  89. MXUSR    EQU    3FH        ; *Set to max user  address if MAXUR=Yes
  90. MXZUSR    EQU    15        ; Maximum user # allowed with WHEEL set
  91. WHLOC    EQU    3EH        ; *Set to wheel location if WHEEL=Yes
  92.  
  93. PRBRDR    EQU    NO        ; Yes = print quasi-borders for libraries
  94. VLIST    EQU    YES        ; Yes for normal vertical alphabetization
  95. WMBOOT    EQU    NO        ; If warmboot is needed on exit
  96.  
  97.     DB    'Z3ENV'        ; For ZCPR3 Environment ID
  98.     DB    1        ; Class 1, External
  99.     DW    0        ; Environment Address.    If using ZCPR33
  100.                 ; This can be left as is.
  101. ;-------------------------------
  102. ;
  103. ; Drive/User area lookup table:
  104. ; ----------------------------
  105. ; Change the following table as appropriate for your version of CP/M.
  106. ; You can limit the maximum user area without wheel byte independently
  107. ; for any drive available.  Use 0FFh for drives that are not available.
  108. ;
  109. ;        CP/M  v2.2 has 16 user areas, 0-15
  110. ;        CP/M  v3.0 has 32 user areas, 0-31
  111. ;
  112. ; NOTE: Use your editor to move the "HIDRV" line below the correct
  113. ; number of drives for your system.  This not only saves time when the
  114. ; highest drive has been reached, but will display a drive/user error
  115. ; message which otherwise will not be shown.
  116. ;
  117. LODRV    EQU    $        ; Mark beginning of drive/user table
  118.  
  119.     DB    15        ; Maximum user area for drive A
  120.     DB    15        ; "      "    "    "    "     B
  121. HIDRV    EQU    $        ; Mark end of drive/user table
  122.     DB    0FFH        ; "      "    "    "    "     C
  123.     DB    0FFH        ; "      "    "    "    "     D
  124.     DB    0FFH        ; "      "    "    "    "     E
  125.     DB    0FFH        ; "      "    "    "    "     F
  126.     DB    0FFH        ; "      "    "    "    "     G
  127.     DB    0FFH        ; "      "    "    "    "     H
  128.     DB    0FFH        ; "      "    "    "    "     I
  129.     DB    0FFH        ; "      "    "    "    "     J
  130.     DB    0FFH        ; "      "    "    "    "     K
  131.     DB    0FFH        ; "      "    "    "    "     L
  132.     DB    0FFH        ; "      "    "    "    "     M
  133.     DB    0FFH        ; "      "    "    "    "     N
  134.     DB    0FFH        ; "      "    "    "    "     O
  135.     DB    0FFH        ; "      "    "    "    "     P
  136. ;
  137. ;-------------------------------
  138. ;
  139. ; Command line options:
  140. ; --------------------
  141. ; If any of the following equates are set NO, it prevents their use by
  142. ; any user (including the SYSOP) unless the wheel byte has been set for
  143. ; SYSOP use.  If running an RCPM, you may wish to say NO for those with
  144. ; an asterisk, such as USEF, USERO, USEP and USES to prevent others from
  145. ; using them - the wheel byte makes them available for SYSOP use.
  146. ;
  147. ; NOTE:  For RCPM use, all 5 would normally be set to "NO" to prevent
  148. ; remote use, but would be available to the Sysop with the WHEEL byte.
  149. ;
  150. USEF    EQU    YES        ; *Allow making a local disk copy?
  151. USEO    EQU    YES        ; *Allow showing only $SYS files?
  152. USEP    EQU    YES        ; *Allow making local printer listing?
  153. USER    EQU    YES        ; *Allow disk system reset?
  154. USES    EQU    YES        ; *Allow showing all, and $SYS files?
  155. ;
  156. ;-------------------------------
  157. ;
  158. ; Showing tagged attributes
  159. ; -------------------------
  160. ; Displaying files with tagged attributes ($R/O, $SYS, $ARC etc.) in an
  161. ; in an unique manner so they are easy to find, if present.
  162. ;
  163. ;    Example:
  164. ;        FILENAME.SyS    -  $SYS attribute set
  165. ;        FILENAME.doC    -  $SYS and $R/O both set
  166. ;        FILENAME.com    -  $SYS, $R/O and $ARC all set
  167. ;
  168. ; The following equates will permit SD to display the files with tagged
  169. ; attributes in lower case letters (a-z) as in example above.
  170. ;
  171. USELC    EQU    YES        ; Allow lower case letters (a-z)
  172. USELCW    EQU    YES        ; *Allow lower case without wheel byte?
  173. ;
  174. ;-----------------------------------------------------------------------
  175. ;
  176. ; Reverse video options
  177. ; ---------------------
  178. ; The following equate will permit SD to display the files with tagged
  179. ; attributes in either reverse video or bright/dim modes.  This will al-
  180. ; low any character tagged to be visible, as opposed to the USELD method.
  181. ; Up to 7 bytes for enter and exit video modes are provided.  These can
  182. ; be easily patched with DDT, etc.
  183. ;
  184. REVID    EQU    NO        ; Yes = inverse or bright/dim display
  185. ;
  186. ; The following equate will highlight/underline the summary line
  187. ;
  188. ULINE    EQU    NO        ; Yes = highlight/underline summary
  189. ;
  190. ;
  191. ; Reverse video control bytes
  192. ; ---------------------------
  193. ; If byte at RVON is 0, simple lower case will be used to display file
  194. ; attributes.
  195. ;
  196.      IF    REVID
  197. RVON:    DB    0,0,0,0,0,0,0    ; Up to 7 characters for ENTER REVERSE
  198.     DB    0        ; String Terminator MUST BE 0
  199. ;
  200. RVOFF:    DB    0,0,0,0,0,0,0    ; Up to 7 characters for EXIT REVERSE
  201.     DB    0        ; String Terminator MUST BE 0
  202.      ENDIF            ; REVID
  203. ;
  204. ; If byte at ULON is 0, no highlighting/underlining will be used in the
  205. ; banner line.
  206. ;
  207.      IF    ULINE
  208. ULON:    DB    0,0,0,0,0,0,0    ; Up to 7 characters for ENTER ULINE
  209.     DB    0        ; String Terminator, MUST BE 0
  210. ;
  211. ULOFF:    DB    0,0,0,0,0,0,0    ; Up to 7 characters for EXIT ULINE
  212.     DB    0        ; String Terminator MUST BE 0
  213.      ENDIF            ; ULINE
  214. ;
  215. ;-------------------------------
  216. ;
  217. ; Time/date options
  218. ; -----------------
  219. ; The following equate will get the TIMEON from BYE, if BYE is active.
  220. ; The message "Time on system is xx Minutes" will be displayed.
  221. ;
  222. TIMEON    EQU    NO        ; Yes, gets TIMEON from BYE5
  223. ;
  224. ; The following equate will permit the date to be displayed using the
  225. ; European system DD/MM/YY or the American system MM/DD/YY.  This only
  226. ; shows when using 'V' to display version number.
  227. ;
  228. EDATE    EQU    NO        ; Yes = European, No = American
  229. ;
  230. ;-------------------------------
  231. ;
  232. ; Z3CPR options
  233. ; -------------
  234. ; for ZCPR33 users - leave all set to NO if not using ZCPR3
  235. ;
  236. ZCPR3    EQU    NO        ; Allow named directory in command line
  237. NDIRS    EQU    NO        ; To display directory names
  238. SHOPUB    EQU    NO        ; To display ZRDOS Public Directories
  239. WHLPUB    EQU    NO        ; To make SHOPUB wheel dependent
  240. ZRDOS    EQU    NO        ; Set to yes if using ZRDOS
  241. ;
  242. ;            end of options
  243. ;-----------------------------------------------------------------------
  244. ;
  245. ; Reference items
  246. ; ---------------
  247. RECORD    EQU    36
  248. FRN    EQU    33
  249. FCR    EQU    32
  250. READRN    EQU    33
  251. HDRSIZ    EQU    27
  252. ARCMAR    EQU    26
  253.  
  254. TMPLT0    EQU    $        ; Start of initialization template
  255.  
  256.      IF    VLIST
  257.     DB    0
  258.      ENDIF            ; VLIST
  259.  
  260.      IF    NOT VLIST
  261.     DB    0FFH
  262.      ENDIF            ; NO VLIST
  263.  
  264.     DB    'A'        ; All-users option flag
  265.     DB    'C'        ; File size in records option
  266.     DB    'D'        ; Multi-disk option flag
  267.  
  268.      IF    USEF
  269.     DB    'F'        ; DISK.DIR file output option
  270.      ENDIF            ; USEF
  271.  
  272.      IF    NOT USEF
  273.     DB    'F'+80H
  274.      ENDIF            ; NOT USEF
  275.  
  276.     DB    'H'        ; Show areas from current to highest
  277.     DB    'L'        ; Display library members flag
  278.     DB    'N'        ; No page-pause option flag
  279.  
  280.      IF    USEO
  281.     DB    'O'        ; To show $SYS files only
  282.      ENDIF            ; USEO
  283.  
  284.      IF    NOT USEO
  285.     DB    'O'+80H
  286.      ENDIF            ; NOT USEO
  287.  
  288.      IF    USEP
  289.     DB    'P'        ; Printer output option
  290.      ENDIF            ; USEP
  291.  
  292.      IF    NOT USEP
  293.     DB    'P'+80H
  294.      ENDIF            ; NOT USEP
  295.  
  296.     DB    'Q'        ; To show only non-$ARC files
  297.  
  298.      IF    USER
  299.     DB    'R'        ; Optional reset of disk system
  300.      ENDIF            ; USER
  301.  
  302.      IF    NOT USER
  303.     DB    'R'+80H
  304.      ENDIF            ; NOT USER
  305.  
  306.      IF    USES
  307.     DB    'S'        ; Include $SYS files
  308.      ENDIF            ; USES
  309.  
  310.      IF    NOT USES
  311.     DB    'S'+80H
  312.      ENDIF            ; NOT USES
  313.  
  314.     DB    'T'        ; Primary sort by file type
  315.     DB    'V'        ; Show SD version
  316.     DB    'X'        ; Alternate alphabetization
  317. ;
  318. ; End of option lookup table
  319. ;
  320.     DW    OUTBUF        ; Next location in output buffer
  321.     DB    128        ; # of bytes left in output buffer
  322.     DB    0,'DISK    DIR'    ; Output Filename.typ
  323. ;
  324. TMPLT1    EQU    $        ; End of initialization data template
  325.  
  326. VERNAME:DB    13,10,'SD',MAIN+'0'
  327.     DB    VER/10+'0',VER MOD 10+'0',' -- '
  328.  
  329.      IF    NOT EDATE
  330.     DB    MONTH/10+'0',MONTH MOD 10+'0','/'
  331.      ENDIF            ; NOT EDATE
  332.  
  333.     DB    DAY/10+'0',DAY MOD 10+'0','/'
  334.  
  335.      IF    EDATE
  336.     DB    MONTH/10+'0',MONTH MOD 10+'0','/'
  337.      ENDIF            ; EDATE
  338.  
  339.     DB    YEAR/10+'0',YEAR MOD 10+'0'
  340.  
  341.      IF    ZCPR3        ;
  342.     DB    ', ZCPR3/ARC/ARK Version'
  343.      ENDIF            ; ZCPR3
  344.  
  345.     DB    0
  346. ;
  347. ;-----------------------------------------------------------------------
  348. ;             Program starts here
  349. ;-----------------------------------------------------------------------
  350. ;
  351. START:    LXI    H,0
  352.     DAD    SP        ; HL=old stack
  353.     SHLD    STACK        ; Save it
  354.     LXI    SP,STACK    ; Get new stack
  355.  
  356.      IF    NDIRS
  357.     LHLD    0109H        ; Get Environment Address
  358.     MVI    D,0
  359.     MVI    E,21        ; Offset to named Directory Buffer Addr.
  360.     DAD    D
  361.     MOV    E,M
  362.     INX    H
  363.     MOV    D,M        ; DE Now contains NDR Address
  364.     INX    H
  365.     MOV    A,M
  366.     ADI    1
  367.     STA    NUMDIR        ; Maximum number of entries plus 1
  368.     XCHG
  369.     SHLD    NAMADR        ; Keep Address for later
  370.      ENDIF            ; NDIRS
  371. ;
  372. ; Clear Public User Areas so they can be displayed
  373. ;
  374.      IF    SHOPUB
  375.     LHLD    0109H        ; Get Environment Address
  376.     MVI    D,0
  377.     MVI    E,07EH
  378.     DAD    D        ; HL Points to Public Drive Byte
  379.     MOV    A,M        ; Get public DRV byte
  380.     STA    PUBDRV
  381.     INX    H
  382.     MOV    A,M        ; Get public USR byte
  383.     STA    PUBUSR
  384.      ENDIF            ; SHOPUB
  385.  
  386.      IF    WHLPUB
  387.     LDA    WHLOC
  388.     ORA    A
  389.     JZ    NOPUB
  390.      ENDIF            ; WHLPUB
  391.  
  392.      IF    SHOPUB
  393.     DCX    H
  394.     MVI    A,0        ; Clear Public Areas temporarily
  395.     MOV    M,A
  396.     INX    H
  397.     MOV    M,A
  398.  
  399.      IF    WHLPUB
  400. NOPUB:    DS    0
  401.      ENDIF            ; WHLPUB
  402. ;
  403. ; (WHLPUB enabled, the R option is redundant)
  404. ;
  405.      ENDIF            ; SHOPUB
  406. ;
  407. ; See if help is wanted
  408. ;
  409.     LXI    H,FCB+1        ; Filename
  410.     MOV    A,M        ; 1st Character
  411.     CPI    '?'        ; Is it "?"
  412.     JNZ    INIT        ; No, Continue
  413.     INX    H        ; Yes, Next Char
  414.     MOV    A,M        ; 2nd Character
  415.     CPI    ' '        ; Is it " "
  416.     JNZ    INIT        ; If not, did not want help guide
  417.     LDA    FCB+9        ; Check for any extent
  418.     CPI    ' '
  419.     JZ    HELPME        ; If none, wanted help
  420. ;
  421. ; Zero out the entire initialization data area
  422. ;
  423. INIT:    LXI    H,DATA0        ; Point to start of initialized data area
  424.     PUSH    H        ; Save for non-zero filling later
  425.     MVI    C,DATA1-DATA0    ; Data area length
  426.     XRA    A        ; Clear the "A" register
  427.  
  428. ZFILL:    MOV    M,A        ; Null the address
  429.     INX    H        ; Pointer+1
  430.     DCR    C        ; One less to go
  431.     JNZ    ZFILL
  432.  
  433.      IF    SHOPUB        ; In order for the Public Directories
  434.     MVI    A,0FFH        ; To be displayed, Option 'R' must be
  435.     STA    ROPFLG        ; Forced true.
  436.      ENDIF            ; SHOPUB
  437. ;
  438. ; Now copy non-zero initialization data from the template area
  439. ;
  440.     POP    H        ; Load A(DATA0)
  441.     LXI    D,TMPLT0    ; Load A(TMPLT0)
  442.     MVI    C,TMPLT1-TMPLT0    ; Template area length
  443.  
  444. NZFILL:    LDAX    D        ; Load template byte
  445.     MOV    M,A        ; Move to data area
  446.     INX    D        ; Next location to store data
  447.     INX    H        ; Next location to get data
  448.     DCR    C        ; One less to go
  449.     JNZ    NZFILL
  450.  
  451.     LXI    H,0        ; Clear HL
  452.  
  453.      IF    ZRDOS
  454.     MVI    C,ZRDVER    ; Get ZRDOS version
  455.     CALL    BDOS
  456.     MOV    A,L        ; ZRDOS Version #
  457.     STA    ZRDFLG        ; Save it
  458.      ENDIF            ; ZRDOS
  459.  
  460.     MVI    C,CPMVER    ; Get CP/M  version
  461.     CALL    BDOS
  462.     MOV    A,L        ; CP/M Version number
  463.     STA    VERFLG        ; Save it
  464.     STA    SOHFLG        ; Prevents initial unwanted CRLF
  465.     CPI    20H        ; Set carry if CP/M 1.4
  466.     PUSH    PSW        ; Save for BYE test
  467.     MVI    E,0FFH        ; Load current user number if CP/M 2
  468.     MVI    C,STUSER    ; Fall through with A=0 if not
  469.     CNC    CPM        ; Only if CP/M 2.0 or ZRDOS
  470.     STA    OLDUSR        ; Initial user number
  471.     STA    NEWUSR        ; New user = Initial user
  472.     STA    BASUSR        ; Directories
  473.     POP    PSW        ; Recover Version Flag
  474.     MVI    E,241        ; Special BYE5xx Call
  475.     MVI    C,STUSER    ; Returns 77 if BYE5xx active
  476.     CNC    CPM        ; BYE5nn not on CP/M 1.4 system
  477.     SUI    77        ; Return code expected
  478.     STA    BYEACT        ; BYEACT = 0, BYE5nn active
  479.  
  480.      IF    TIMEON
  481.     CALL    TIME
  482.      ENDIF            ; TIMEON
  483.  
  484.      IF    ZCPR3
  485.     LDA    FCB+13
  486.     STA    NEWUSR
  487.      ENDIF            ; ZCPR3
  488.  
  489.      IF    NOT ZCPR3
  490.     LXI    H,TBUF+1    ; Point to command line buffer (CLB)
  491.     MOV    A,M        ; CLB Character
  492.     CPI    '['        ; CP/M 3.0 style delimiter
  493.     JZ    CLOK        ; (may follow command in CP/M 3.0)
  494.     INX    H        ; CLB pointer +1
  495.     ORA    A        ; Terminator?
  496.     JNZ    CLOK        ; No, continue
  497.     MOV    M,A        ; Yes, set 2nd terminator
  498.  
  499. CLOK:    LXI    D,FCB        ; A(file control block)
  500.     CALL    FNAME        ; Process filename.typ
  501.     MOV    A,B        ; Disk specification
  502.     CPI    0FFH        ; Current?
  503.     JZ    CLUS        ; Yes
  504.     STAX    D        ; No, set disk specification
  505.  
  506. CLUS:    MOV    A,C        ; User specification
  507.     CPI    0FFH        ; Current?
  508.     JZ    CLNON        ; Yes
  509.     STA    NEWUSR        ; No, set user specification
  510.     STA    BASUSR
  511.      ENDIF            ; NOT ZCPR3
  512.  
  513. CLNON:    MVI    C,CURDSK
  514.     CALL    CPM        ; Load current disk number
  515.     STA    OLDDSK        ; Save for reset if needed
  516.     INR    A        ; Adjust
  517.     STA    OUTFCB        ; Save directory file drive
  518.     LXI    H,FCB        ; A(file control block)
  519.     MOV    A,M        ; Load directory search drive
  520.     ORA    A        ; Any specified?
  521.     JNZ    START1        ; Yes, skip next routine
  522.     LDA    OLDDSK        ; Otherwise, get default disk
  523.     INR    A        ; Adjust
  524.     JMP    START2
  525.  
  526. START1:    PUSH    PSW        ; Save status
  527.     MVI    A,1
  528.     STA    DRVFLG        ; Set DRVFLG = 1
  529.     POP    PSW        ; Load status
  530.  
  531. START2:    MOV    M,A        ; Absolute drive code in directory FCB
  532. ;
  533. ; If at least one option is allowed,  scan command line for the option
  534. ; field delimiter. The option field delimiter is considered valid only
  535. ; if it is preceded by at least 1 space  (otherwise may be part of the
  536. ; directory filename).     Any unrecognized options/illegal user numbers
  537. ; will be flagged.(We scan the command line buffer rather than the 2nd
  538. ; default FCB because all 8 options + 2 digit user number will not fit
  539. ; in the 2nd FCB name field).
  540. ;
  541.     LXI    H,TBUF        ; CLB pointer
  542.     MOV    B,M        ; CLB length
  543. ;
  544. ; Search for valid command line delimiter, if not found, assume no
  545. ; options.  Show help menu if single "?" entered.
  546. ;
  547. SCNDOL:    INX    H        ; CLB PTR+1
  548.     DCR    B        ; CLB LEN-1
  549.     JM    DOPTN        ; Exit if command line buffer empty
  550.     MOV    A,M        ; CLB Character
  551.     CPI    '['        ; CPM+ style delimiter?
  552.     JZ    OPTDLM        ; Yes
  553.     CPI    '$'        ; CPM2 style delimiter?
  554.     JZ    SPB4        ; Yes
  555.     CPI    '/'        ; ZCPR style delimiter?
  556.     JNZ    SCNDOL        ; No
  557.  
  558. SPB4:    DCX    H        ; '$' found, space must precede
  559.     MOV    A,M        ; Previous character
  560.     INX    H
  561.     CPI    ' '
  562.     JNZ    SCNDOL        ; No space, ignore '$'
  563. ;
  564. ; Valid delimiter found.  Scan the rest of the buffer for options.
  565. ; Errors past this point cause an abort.
  566. ;
  567. OPTDLM:    XCHG            ; DE = CLB pointer (swap pointers)
  568.  
  569. SCNOPT:    INX    D        ; CLB PRT+1
  570.     DCR    B        ; CLB LEN-1
  571.     JM    DOPTN        ; If option field exhausted, exit
  572.  
  573. SCNAGN:    LDAX    D        ; Load option character
  574.     CPI    ' '        ; Is it " "?
  575.     JZ    SCNOPT        ; Yes, Ignore it
  576.     CPI    ']'        ; CPM+ style terminator?
  577.     JZ    SCNOPT        ; Options may follow terminator
  578.     LXI    H,OTBL-1    ; OTBL pointer
  579.     MVI    C,OEND-OTBL+1    ; OTLB length
  580.  
  581. NOMACH:    INX    H        ; OTLB pointer+1
  582.     DCR    C        ; OTLB length-1
  583.     JZ    CLERR        ; Error if option table end
  584.  
  585.      IF    WHEEL        ; ZCMD/ZCPR2/ZCPR3?
  586.     PUSH    PSW        ; Save "A" value
  587.     LDA    WHLOC        ; Load wheel byte
  588.     ORA    A        ; Set Flags
  589.     JZ    NOMAC1        ; Not set, so forget it
  590.     MOV    A,M        ; Load the table option
  591.     ANI    5FH        ; Allow the option
  592.     MOV    M,A        ; Stuff back in table
  593.  
  594. NOMAC1:    POP    PSW        ; Restore "A" value
  595.      ENDIF            ; WHEEL
  596.  
  597.     CMP    M        ; Compare with table entry
  598.     JNZ    NOMACH        ; If no match, check next
  599.     MVI    M,0        ; Else, activate the option
  600.     JMP    SCNOPT        ; Continue scan
  601. ;.....
  602. ;
  603. ; Playback the command line up to the character that stopped the scan
  604. ; and exit
  605. ;
  606. CLERR:    XRA    A        ; Clear "A" register
  607.     INX    D        ; Tag end of CLB
  608.     STAX    D        ; With terminator
  609.     CALL    CRLF        ; New line
  610.     LXI    D,ERRMS2    ; 'Error'
  611.     CALL    PUTS
  612.     LXI    D,ERRTAG    ; '->'
  613.     CALL    PUTS
  614.     LXI    H,TBUF+1    ; Playback CLB to error point
  615.  
  616. CLELP:    MOV    A,M        ; Character
  617.     ORA    A        ; Zero?
  618.     JZ    CLEX        ; Yes, exit
  619.     CALL    PUTCHR        ; No, output to console
  620.     INX    H        ; CLB pointer+1
  621.     JMP    CLELP        ; Continue
  622.  
  623. CLEX:    MVI    A,'?'        ; Tag line with a '?' field
  624.     CALL    PUTCHR
  625.     CALL    CRLF        ; New Line
  626.  
  627.      IF    SHOPUB
  628.     CALL    RSTPUB
  629.      ENDIF            ; SHOPUB
  630.  
  631. ;;;;;    JMP    0000H        ; And reset CCP, all finished
  632.     JMP    EXIT2
  633. ;.....
  634. ;
  635. ; Options input or not specified, and associated flags set.
  636. ;
  637. ; If D-option, swap error vectors, then start at drive A if no
  638. ; drive specified on command line.
  639. ;
  640. DOPTN:    LDA    DOPFLG        ; If multi-disk flag set,
  641.     ORA    A        ; Need to set error traps
  642.     JNZ    AOPTN        ; If not, go check A-option
  643.     CALL    SWAPEM        ; Swap BDOS error vector tables
  644.     LDA    DRVFLG        ; Directory drive specified?
  645.     ORA    A
  646.     JNZ    AOPTN        ; No, don't reset
  647.     MVI    A,1        ; Yes, Set FCB to A:
  648.     STA    FCB
  649. ;
  650. ; Start user at 0 if A-option selected without U-option
  651. ;
  652. AOPTN:    LDA    AOPFLG        ; Check All-users option
  653.     ORA    A
  654.     JNZ    COPTN        ; Jump if not
  655.     LDA    HOPFLG        ; Asking to show all from current?
  656.     ORA    A
  657.     JZ    COPTN        ; If yes, do not reset "A" to zero
  658.     XRA    A        ; No, Start at user 0
  659.     STA    NEWUSR
  660.     STA    BASUSR
  661. ;
  662. ; Test if C-option and set indicator character 'r', else 'k'
  663. ;
  664. COPTN:    LDA    COPFLG        ; File sizes wanted in records?
  665.     ORA    A
  666.     MVI    A,'k'
  667.     JNZ    COPTN1        ; Jump if not
  668.     MVI    A,'r'
  669.  
  670. COPTN1:    STA    FSIZEC        ; Indicator char after size
  671. ;
  672. ; Determine whether horizontal or vertical alphabetization.
  673. ; If X-option selected, use alternate format.
  674. ; Set flag and fence character accordingly.
  675. ;
  676.     LDA    XOPFLG        ; Check for X option
  677.     ORA    A
  678.     LDA    VFLAG        ; Get vertical flag
  679.     JNZ    XOPTN1        ; Jump if no X option
  680.     CMA            ; Else swap vertical/horizontal indicator
  681.     STA    VFLAG        ; And change VFLAG other way
  682.  
  683. XOPTN1:    DS    0
  684. ;
  685. ; The following optionally resets the disk system.  The reset must
  686. ; be done OUTSIDE of the multiple drive loop if the $F option is
  687. ; enabled because CP/M 1.4 will clobber the DMA buffer on reset.
  688. ;
  689.     LDA    ROPFLG        ; Reset Disk?
  690.     ORA    A
  691.     JNZ    NOOPT
  692. ;
  693. ; Disk reset if R option entered on command line
  694. ;
  695.     MVI    C,RESET
  696.     CALL    CPM
  697. ;
  698. ; Validate drive code and user area numbers from the drive table
  699. ;
  700. NOOPT:    LXI    D,DRUMSG    ; Get drive/user error message
  701.     PUSH    D
  702.     LDA    FCB        ; Get directory drive code
  703.     DCR    A        ; Normalize to range of 0-31
  704.     CPI    HIDRV-LODRV    ; Compare with max drives on-line
  705.     JNC    ERXIT        ; Drive error exit if out of range
  706.  
  707.      IF    MAXDRV        ; Look for MXDRV
  708.     LXI    H,MXDRV        ; A(MXDRV) to HL
  709.     MOV    L,M        ; (MXDRV) to L
  710.      ENDIF            ; MAXDRV
  711.  
  712.      IF    MAXDRV
  713.     INX    H        ; +1
  714.     CMP    L        ; Check it
  715.     JNC    ERXIT        ; Oops if not bigger
  716.      ENDIF            ; MAXDRV
  717. ;
  718. ; Skips any drives marked 0FFh, some computers do not have contiguous
  719. ; drives, such as Heath H89, etc.
  720. ;
  721.     MOV    E,A        ; Drive code = table index
  722.     MVI    D,0
  723.     LXI    H,LODRV        ; DUTBL Pointer
  724.     DAD    D        ; DUTBL Pointer+INDEX
  725.     MOV    A,M        ; User Number
  726.     ORA    A        ; Set Status
  727.     JM    NDSK        ; If negative, ignore drive
  728.  
  729.      IF    WHEEL
  730.     LDA    WHLOC        ; Get wheel byte
  731.     ORA    A        ; Check it
  732.     JZ    USRCK        ; If reset, restrict user
  733.     MVI    A,MXZUSR    ; If set, max user = MXZUSR
  734.     JMP    USRCK1
  735.      ENDIF            ; WHEEL
  736.  
  737. USRCK:    LXI    H,LODRV        ; DUTBL PTR
  738.     DAD    D        ; DUTLB PTR+INDEX
  739.     MOV    A,M        ; Load max user for this drive
  740.  
  741.      IF    MAXUR        ; Use low memory values if smaller
  742.     MOV    H,A        ; Current value of MAXUSR
  743.     LDA    MXUSR        ; Alternate value
  744.      ENDIF            ; MAXUR
  745.  
  746.      IF    MAXUR AND NOT ZCPR3
  747.     SBI    1        ; MAXUSR is really maximum user+1
  748.      ENDIF            ; MAXUR AND NOT ZCPR3
  749.  
  750.      IF    MAXUR
  751.     CMP    H        ; Compare the two
  752.     JNC    USRCK1        ; OK if MAXU <= table value
  753.     STA    MAXUSR        ; Else replace it
  754.      ENDIF            ; MAXUR
  755.  
  756. USRCK1:    MOV    B,A        ; Save max user for later testing
  757.     ANI    1FH        ; Insure in range 0-31
  758.     STA    MAXUSR        ; Save it for later
  759.     LXI    H,NEWUSR    ; Point to directory user area
  760.     CMP    M        ; Compare with the maximum
  761.     JC    ERXIT        ; User number illegal, error exit
  762.     POP    D        ; Destroy error message pointer
  763.     MOV    A,B        ; Check to see if this drive
  764.     ORA    A        ; Has been mapped out
  765.     JM    NDSK        ; Yes, skip this drive
  766.     LXI    H,FCB+1        ; No, point to name
  767.     MOV    A,M        ; Any name specified?
  768.     CPI    '$'        ; Delimiter?
  769.     JZ    WCD        ; Yes, All files
  770.     CPI    '/'        ; Unix/ZCPR3 delimiter?
  771.     JZ    WCD        ; Yes, All files
  772.     CPI    '['        ; CP/M+ delimiter?
  773.     JZ    WCD
  774.     CPI    ' '        ; No, Filename specified
  775.     JNZ    GOTFCB
  776. ;
  777. ; No FCB - make FCB all '?'
  778. ;
  779. WCD:    MVI    B,11        ; Filename+typ length
  780.  
  781. QLOOP:    MVI    M,'?'        ; Store "?" in FCB
  782.     INX    H        ; FCB pointer+1
  783.     DCR    B        ; FCB length-1
  784.     JNZ    QLOOP        ; Continue
  785.  
  786. GOTFCB:    MVI    A,'?'        ; Force wild extent
  787.     STA    FCB+12
  788.     CALL    SETSRC        ; Set DMA for BDOS media change check
  789.     LXI    H,FCB        ; Point to FCB drive code for directory
  790.     MOV    E,M        ; Load drive code from FCB
  791.     DCR    E        ; Normalize drive code for select
  792.     MVI    C,SELDSK    ; Select directory drive to retrieve
  793.     CALL    CPM        ; The proper allocation vector
  794.     CALL    CKVER        ; Check version
  795.     JC    V14        ; Pre-2.x...get parameters the 1.4 way
  796.     MVI    C,DSKPAR    ; If 2.2 or MP/M...request DPB
  797.     CALL    BDOS
  798.     INX    H
  799.     INX    H
  800.     MOV    A,M        ; Load block shift
  801.     STA    BLKSHF        ; Block Shift
  802.     INX    H        ; Bump to block mask
  803.     MOV    A,M        ; Load block mask
  804.     STA    BLKMSK        ; Block Mask
  805.     INX    H
  806.     INX    H
  807.     MOV    E,M        ; Get maximum block #
  808.     INX    H
  809.     MOV    D,M
  810.     XCHG
  811.     SHLD    BLKMAX        ; Maximum Block #
  812.     XCHG
  813.     INX    H
  814.     MOV    E,M        ; Load directory size
  815.     INX    H
  816.     MOV    D,M
  817.     XCHG
  818.     JMP    FREE
  819.  
  820. V14:    LHLD    BDOS+1        ; Get parameters 1.4 style
  821.     MVI    L,3BH        ; Point to directory size
  822.     MOV    E,M        ; Get it
  823.     MVI    D,0        ; Force high order to 0
  824.     PUSH    D        ; Save for later
  825.     INX    H        ; Point to block shift
  826.     MOV    A,M        ; Fetch
  827.     STA    BLKSHF        ; Save
  828.     INX    H        ; Point to block mask
  829.     MOV    A,M        ; Fetch it
  830.     STA    BLKMSK        ; And save it
  831.     INX    H
  832.     MOV    E,M        ; Get maximum block #
  833.     MVI    D,0
  834.     XCHG
  835.     SHLD    BLKMAX        ; Save it
  836.     POP    H        ; Restore directory size
  837.     JMP    FREE20        ; Calculate free space from alloc vector
  838. ;
  839. ; Calculate number of K free on selected drive now so the FREE figure
  840. ; will not reflect either creation or additions to the DISK.DIR file.
  841. ; Note: This routine will not always function correctly as coded.  To
  842. ; insure the proper calculation when the $F option is specified and
  843. ; cataloging multiple disks on a single drive, you should do a CTL-C
  844. ; AFTER the disk to be cataloged has been readied.
  845. ;
  846. FREE:    SHLD    DIRMAX        ; Save max number of directory entries
  847.     LDA    VERFLG        ; Check version number
  848.     CPI    30H        ; CP/M 3.0?
  849.     JC    FREE20        ; No, Use old method
  850.     LDA    FCB        ; Load drive number
  851.     DCR    A        ; Normalize
  852.     MOV    E,A        ; Use compute free space BDOS call
  853.     MVI    C,46        ; Calculate free space
  854.     CALL    CPM
  855.     MVI    C,3        ; Answer is a 24-bit integer
  856.  
  857. FRE3L1:    LXI    H,TBUF+2    ; Answer in 1st 3 bytes of TBUF
  858.     MVI    B,3        ; Convert from records to k
  859.     ORA    A        ; By dividing by 8
  860.  
  861. FRE3L2:    MOV    A,M        ; LS byte record count
  862.     RAR            ; /2
  863.     MOV    M,A        ; Replace
  864.     DCX    H        ; Next byte record count
  865.     DCR    B        ;
  866.     JNZ    FRE3L2        ; Loop for 3 bytes
  867.     DCR    C
  868.     JNZ    FRE3L1        ; Shift 3 times
  869.     LHLD    TBUF        ; Now get result in k
  870.     JMP    SAVFRE        ; Save Free Space
  871.  
  872. FREE20:    MVI    C,DSKALL    ; Allocation vector address
  873.     CALL    BDOS
  874.     XCHG
  875.     LHLD    BLKMAX        ; Max Block Number
  876.     INX    H
  877.     LXI    B,0        ; Init block count = 0
  878.  
  879. GSPBYT:    PUSH    D        ; Save allocation address
  880.     LDAX    D
  881.     MVI    E,8        ; Set to process 8 blocks
  882.  
  883. GSPLUP:    RAL            ; Test bit
  884.     JC    NOTFRE
  885.     INX    B
  886.  
  887. NOTFRE:    MOV    D,A        ; Save bits
  888.     DCX    H        ; Count down blocks
  889.     MOV    A,L
  890.     ORA    H
  891.     JZ    ENDALC        ; Quit if out of blocks
  892.     MOV    A,D        ; Restore bits
  893.     DCR    E        ; Count down 8 bits
  894.     JNZ    GSPLUP        ; Do another bit
  895.     POP    D        ; Bump to next byte of allocation vector
  896.     INX    D
  897.     JMP    GSPBYT        ; Process it
  898.  
  899. ENDALC:    POP    D        ; Clear stack of allocation vector pointer
  900.     MOV    L,C        ; Copy blocks to HL
  901.     MOV    H,B
  902.     LDA    BLKSHF        ; Load block shift factor
  903.     SUI    3        ; Convert from records to k
  904.     JZ    SAVFRE        ; Skip shifts if 1k blocks return free in HL
  905.  
  906. FREKLP:    DAD    H        ; Multiply blocks by k/block
  907.     DCR    A
  908.     JNZ    FREKLP
  909. ;
  910. SAVFRE:    SHLD    FREEBY        ; Save free space for output later
  911. ;
  912. ; Reenter here on subsequent passes while in the all-users mode
  913. ;
  914. SETTBL:    LHLD    DIRMAX        ; Load directory maximum size
  915.     INX    H        ; Directory size is DIRMAX+1
  916.     DAD    H        ; Double directory size
  917.     LXI    D,ORDER        ; Too get order table size
  918.     DAD    D        ; Allocate order table
  919.     SHLD    TBLOC        ; Name tbl begins where order tbl ends
  920.     SHLD    NEXTT
  921.     XCHG
  922.     LHLD    BDOS+1        ; Insure we have room to continue
  923.     MOV    A,E
  924.     SUB    L
  925.     MOV    A,D
  926.     SBB    H
  927.     JNC    OUTMEM
  928.     CALL    CKVER        ; Set carry if pre-CP/M 2
  929.     LDA    NEWUSR        ; Load directory user area
  930.     MOV    E,A
  931.     MVI    C,STUSER    ; Get the user function
  932.     CNC    CPM        ; Set new user number if CP/M 2
  933. ;
  934. ; Look up the FCB in the directory
  935. ;
  936.     MVI    A,'?'        ; Check for wild FCB extent
  937.     LXI    H,FCB+12
  938.     MOV    M,A        ; Match all extents
  939.     INX    H
  940.     MOV    M,A        ; Match all S1 bytes
  941.     INX    H
  942.     MOV    M,A        ; Match all S2 bytes
  943.     LXI    H,0
  944.     SHLD    COUNT        ; Initialize match counter
  945.     SHLD    TOTFIL        ; "  total file counter
  946.     SHLD    TOTSIZ        ; "  total size counter
  947.     CALL    SETSRC        ; Set DMA for directory search
  948.     MVI    C,SRCHF        ; Load 'search first' function
  949.     JMP    LOOK        ; Go search for 1st match
  950. ;
  951. ; Read more directory entries
  952. ;
  953. MORDIR:    MVI    C,SRCHN        ; Search next function
  954.  
  955. LOOK:    LXI    D,FCB        ; A(file control block)
  956.     CALL    CPM        ; Read directory entry
  957.     INR    A        ; End (0FFH)?
  958.     JZ    SPRINT        ; Yes, sort & print what we have
  959. ;
  960. ; Point to directory entry
  961. ;
  962.     DCR    A        ; Undo previous INR A
  963.     ANI    3        ; Make modulus 4
  964.     ADD    A        ; Multiply
  965.     ADD    A        ; By 32 because
  966.     ADD    A        ; Each directory
  967.     ADD    A        ; Entry is 32
  968.     ADD    A        ; Bytes long
  969.     LXI    H,TBUF+1    ; Point to buffer (skip to FN/FT)
  970.     ADD    L        ; Point to entry
  971.     ADI    9        ; Point to sys byte
  972.     MOV    L,A        ; Save (can't carry to H)
  973.     LDA    QOPFLG        ; Find only non-$ARC files?
  974.     ORA    A
  975.     JNZ    OSYS        ; No, check for only $SYS files
  976.     INX    H        ; Yes, get the archive byte
  977.     MOV    A,M
  978.     DCX    H
  979.     ORA    A        ; Check bit 7 for $ARC file
  980.     JM    MORDIR        ; If set, ignore this filename
  981.  
  982. OSYS:    LDA    OOPFLG        ; Find only $SYS files?
  983.     ORA    A
  984.     JNZ    CKSYS
  985.     MOV    A,M        ; Yes, get system byte
  986.     ORA    A        ; Check bit 7 for $SYS file
  987.     JP    MORDIR        ; If not set, ignore this filename
  988.     JMP    SYSFOK        ; Else check for a match
  989.  
  990. CKSYS:    LDA    SOPFLG        ; Did user request $SYS files?
  991.     ORA    A
  992.     JZ    SYSFOK        ; If yes, exit
  993.     MOV    A,M        ; Get system byte back
  994.     ORA    A        ; Check bit 7 for $SYS file
  995.     JM    MORDIR        ; Skip that file
  996.  
  997. SYSFOK:    MOV    A,L        ; Go back now
  998.     SUI    10        ; Back to user number (allocation flag)
  999.     MOV    L,A        ; HL points to entry now
  1000.     LDA    NEWUSR        ; Get current user
  1001.     CMP    M
  1002.     JNZ    MORDIR        ; Ignore if different
  1003.     INX    H
  1004. ;
  1005. ; Move entry to table
  1006. ;
  1007.     XCHG            ; Entry to DE
  1008.     LHLD    NEXTT        ; Next table entry to HL
  1009.     MVI    B,11        ; Entry length (name, type, extent)
  1010.  
  1011. TMOVE:    LDAX    D        ; Get entry character
  1012.  
  1013.      IF    NOT (USELC OR REVID)
  1014.     ANI    7FH        ; Remove attributes
  1015.      ENDIF            ; NOT (USELC OR REVID)
  1016.  
  1017.     MOV    M,A        ; Store in table
  1018.     INX    D
  1019.     INX    H
  1020.     DCR    B        ; More?
  1021.     JNZ    TMOVE
  1022.     INX    D        ; DE->> S1
  1023.     INX    D        ; DE->> S2
  1024.     LDAX    D        ; Get S2 byte, oflo=int(extents/32)
  1025.     PUSH    H        ; Save HL
  1026.     MOV    L,A        ; Set up 16-bit multiply
  1027.     MVI    H,0
  1028.     MVI    B,5
  1029.     CALL    SHLL        ; HL is now # of oflo extents
  1030.     DCX    D        ; DE->> S1
  1031.     DCX    D        ; DE->> extent
  1032.     LDAX    D        ; Get extent
  1033.     ADD    L
  1034.     MOV    L,A
  1035.     MOV    A,H
  1036.     ACI    0
  1037.     MOV    H,A        ; HL has total extents
  1038.     MVI    B,7
  1039.     CALL    SHLL        ; HL has total records less last ext
  1040.     INX    D        ; DE->> S1
  1041.     INX    D        ; DE->> S2
  1042.     INX    D        ; Point to sector count
  1043.     LDAX    D        ; Get it
  1044.     ADD    L
  1045.     MOV    L,A
  1046.     MOV    A,H
  1047.     ACI    0
  1048.     MOV    H,A        ; HL has total records
  1049.     XTHL            ; Do some fancy shuffling
  1050.     XCHG
  1051.     XTHL
  1052.     XCHG
  1053.     MOV    M,D
  1054.     INX    H
  1055.     MOV    M,E
  1056.     POP    D        ; All back to normal
  1057.     INX    H
  1058.     SHLD    NEXTT        ; Save updated table address
  1059.     XCHG
  1060.     LHLD    COUNT        ; Bump the # of matches made
  1061.     INX    H
  1062.     SHLD    COUNT
  1063.     LXI    H,13        ; Size of next entry
  1064.     DAD    D
  1065.     XCHG            ; Future NEXTT is in DE
  1066.     LHLD    BDOS+1        ; Pick up TPA end
  1067.     MOV    A,E
  1068.     SUB    L        ; Compare NEXTT-TPA end
  1069.     MOV    A,D
  1070.     SBB    H
  1071.     JC    MORDIR        ; If TPA end > NEXTT, loop back for more
  1072.  
  1073. OUTMEM:    CALL    ERXIT        ; Exit if directory too large
  1074.     DB    'Memory',0
  1075. ;
  1076. ; Shift HL left by B bits
  1077. ;
  1078. SHLL:    DAD    H
  1079.     DCR    B
  1080.     RZ
  1081.     JMP    SHLL
  1082. ;
  1083. ; Sort and print
  1084. ;
  1085. SPRINT:    CALL    SETFOP        ; Return to file output DMA & user #
  1086.     LHLD    COUNT        ; Get file name count
  1087.     MOV    A,L
  1088.     ORA    H        ; Any found?
  1089.     JZ    PRTOTL        ; Exit if no files found
  1090.     PUSH    H        ; Save file count
  1091.     STA    SUPSPC        ; Enable leading zero suppression
  1092. ;
  1093. ; Initialize the order table
  1094. ;
  1095.     LHLD    TBLOC        ; Get start of name table
  1096.     XCHG            ; Into DE
  1097.     LXI    H,ORDER        ; Point to order table
  1098.     LXI    B,13        ; Entry length
  1099.  
  1100. BLDORD:    MOV    M,E        ; Save low order address
  1101.     INX    H
  1102.     MOV    M,D        ; Save high order address
  1103.     INX    H
  1104.     XCHG            ; Table address to HL
  1105.     DAD    B        ; Point to next entry
  1106.     XCHG
  1107.     XTHL            ; Save table address, load loop counter
  1108.     DCX    H        ; Count down loop
  1109.     MOV    A,L
  1110.     ORA    H        ; More?
  1111.     XTHL            ; Load table address, save loop counter
  1112.     JNZ    BLDORD        ; Yes, go do another one
  1113.     POP    H        ; Clean loop counter off stack
  1114.     LHLD    COUNT        ; Get count
  1115.     SHLD    SCOUNT        ; Save as # to sort
  1116.     DCX    H        ; Only 1 entry?
  1117.     MOV    A,L
  1118.     ORA    H
  1119.     JZ    DONE        ; Yes, so skip sort
  1120. ;
  1121. ; This sort routine is adapted from SOFTWARE TOOLS
  1122. ;
  1123.     LHLD    SCOUNT        ; Number of entries
  1124.  
  1125. L1:    ORA    A        ; Clear carry
  1126.     MOV    A,H        ; GAP=GAP/2
  1127.     RAR
  1128.     MOV    H,A
  1129.     MOV    A,L
  1130.     RAR
  1131.     MOV    L,A
  1132.     ORA    H        ; Is it zero?
  1133.     JZ    DONE        ; Then none left
  1134.     MOV    A,L        ; Make gap odd
  1135.     ORI    1
  1136.     MOV    L,A
  1137.     SHLD    GAP
  1138.     INX    H        ; I=GAP+1
  1139.  
  1140. L2:    SHLD    I
  1141.     XCHG
  1142.     LHLD    GAP
  1143.     MOV    A,E        ; J=I-GAP
  1144.     SUB    L
  1145.     MOV    L,A
  1146.     MOV    A,D
  1147.     SBB    H
  1148.     MOV    H,A
  1149.  
  1150. L3:    SHLD    J
  1151.     XCHG
  1152.     LHLD    GAP        ; JG=J+GAP
  1153.     DAD    D
  1154.     SHLD    JG
  1155.     CALL    COMPARE        ; Compare (J) and (JG)
  1156.     JP    L4        ; If A(J)<=A(JG)
  1157.     LHLD    J
  1158.     XCHG
  1159.     LHLD    JG
  1160.     CALL    SWAP        ; Exchange a(J) and a(JG)
  1161.     LHLD    J        ; J=J-GAP
  1162.     XCHG
  1163.     LHLD    GAP
  1164.     MOV    A,E
  1165.     SUB    L
  1166.     MOV    L,A
  1167.     MOV    A,D
  1168.     SBB    H
  1169.     MOV    H,A
  1170.     JM    L4        ; If J>0 go to l3
  1171.     ORA    L        ; Check for zero
  1172.     JZ    L4
  1173.     JMP    L3
  1174.  
  1175. L4:    LHLD    SCOUNT        ; For later
  1176.     XCHG
  1177.     LHLD    I        ; I=I+1
  1178.     INX    H
  1179.     MOV    A,E        ; If I<=n go to l2
  1180.     SUB    L
  1181.     MOV    A,D
  1182.     SBB    H
  1183.     JP    L2
  1184.     LHLD    GAP
  1185.     JMP    L1
  1186. ;
  1187. ; Sort is all done - print entries
  1188. ;
  1189. DONE:    LDA    FOPFLG        ; File output flag
  1190.     ORA    A        ; Set?
  1191.     JNZ    NOOUT        ; No, skip open
  1192. ;
  1193. ; If all user option enabled, and we're not on the first pass, then the
  1194. ; output file is already open and positioned, so we can skip the open.
  1195. ;
  1196.     LXI    H,OPNFLG    ; Output file open flag
  1197.     CMP    M        ; A=0,set Z if OPNFLG=0 also
  1198.     JNZ    NOOUT        ; If OPNFLG not zero, skip open
  1199.     DCR    M        ; Else, set OPNFLG for next user #
  1200. ;
  1201. ; First pass on file append - prepare DISK.DIR to receive new
  1202. ; or appended output.
  1203. ;
  1204.     LXI    D,OUTFCB    ; Does output file exist?
  1205.     MVI    C,SRCHF
  1206.     CALL    CPM
  1207.     INR    A
  1208.     JNZ    OPENIT        ; Yes, open for processing
  1209.     MVI    C,MAKE        ; Else, create output file
  1210.     CALL    CPM
  1211.     INR    A        ; Successful?
  1212.     JNZ    NOOUT        ; Yes, Continue
  1213. ;
  1214. ; If make or open fails, declare error
  1215. ;
  1216. OPNERR:    CALL    ERXIT
  1217.     DB    'Open',0
  1218. ;
  1219. WRTERR:    CALL    ERXIT
  1220.     DB    'Write',0
  1221. ;
  1222. ; Output file already exists - open it and position
  1223. ; it to the last record of the last extent.
  1224. ;
  1225. OPENIT:    MVI    C,OPEN        ; Open 1st extent of output file
  1226.     CALL    CPM
  1227.     INR    A
  1228.     JZ    OPNERR        ; Bad deal if 1st won't open
  1229.  
  1230. OPNMOR:    LDA    OUTFCB+15    ; Record count (RC)
  1231.     CPI    128
  1232.     JC    LSTEXT        ; If RC<128, this is last extent
  1233.     LXI    H,OUTFCB+12
  1234.     INR    M        ; Else, increment to next extent
  1235.     MVI    C,OPEN        ; Try to open it
  1236.     CALL    CPM
  1237.     INR    A
  1238.     JNZ    OPNMOR        ; Continue opening extents to end
  1239.     DCR    M        ; Then, reopen preceding extent
  1240.     MVI    C,OPEN
  1241.     CALL    CPM
  1242.     LDA    OUTFCB+15    ; Get RC for the last extent
  1243. ;
  1244. ; At this point, OUTFCB is opened to the last extent of the file, so
  1245. ; read in the last record in the last extent.
  1246. ;
  1247. LSTEXT:    ORA    A        ; Is this extent empty?
  1248.     JZ    NOOUT        ; Yes, starting a clean slate
  1249.     DCR    A        ; Normalize record count
  1250.     STA    OUTFCB+32    ; Set record number to read
  1251.     MVI    C,READ        ; Read last record of file
  1252.     CALL    CPM
  1253.     ORA    A        ; Successful read?
  1254.     JZ    RDOK        ; Yes, scan for EOF mark
  1255.  
  1256. APERR:    CALL    ERXIT
  1257.     DB    'Append',0
  1258. ;
  1259. ; We now have the last record in the file in the buffer. Scan the last
  1260. ; record for the EOF mark, indicate where we can start adding data.
  1261. ;
  1262. RDOK:    LXI    H,OUTBUF    ; Point to output buffer start
  1263.     MVI    B,128        ; Output buffer length
  1264.  
  1265. SCAN:    MOV    A,M        ; Character
  1266.     CPI    'Z'-40H        ; End of file?
  1267.     JZ    RESCR        ; Yes, save pointers and reset CR
  1268.     INX    H        ; Pointer+1
  1269.     DCR    B        ; Length-1
  1270.     JNZ    SCAN        ; Continue to end of buffer
  1271. ;
  1272. ; If an explicit EOF mark or an implied EOF (last record is full) in
  1273. ; the last buffer, move the FCB record and extent pointer back to cor-
  1274. ; rect for the read operation so the first write operation will replace
  1275. ; the last record of the DISK.DIR file.
  1276. ;
  1277. RESCR:    PUSH    H        ; Save EOF buffer pointer
  1278.     PUSH    B        ; Save EOF buffer remaining
  1279.     LXI    H,OUTFCB+32    ; Load current record again
  1280.     DCR    M        ; Record-1
  1281.     JP    SAMEXT        ; If CR>=0, still in same extent
  1282.     LXI    H,OUTFCB+12    ; Else, move to previous extent
  1283.     DCR    M
  1284.     MVI    C,OPEN        ; Then, reopen previous extent
  1285.     CALL    CPM
  1286.     INR    A
  1287.     JZ    APERR        ; Append error if can not reopen
  1288.     LDA    OUTFCB+15    ; Else,
  1289.     DCR    A        ; Position to last record of
  1290.     STA    OUTFCB+32    ; The extent
  1291.  
  1292. SAMEXT:    POP    PSW        ; Recall EOF location in buffer
  1293.     STA    BUFCNT        ; Set buffer counter
  1294.     POP    H        ; Recall next buffer pointer
  1295.     SHLD    BUFPNT        ; Set pointer for first addition
  1296.  
  1297. NOOUT:    LDA    FIRSTT        ; First time through?
  1298.     ORA    A
  1299.     JNZ    NOVOPT        ; No, we've been here before
  1300.     MVI    A,0FFH        ; Yes,
  1301.     STA    FIRSTT        ; Set first time flag
  1302.     LDA    VOPFLG        ; Version display flag
  1303.     ORA    A        ; Set?
  1304.     JNZ    NOVOPT        ; No, skip version print
  1305.     LXI    D,VERNAME    ; Yes, print version
  1306.     CALL    PUTS        ; Print the string
  1307.     CALL    CRLF
  1308.  
  1309. NOVOPT:    LHLD    COUNT
  1310.     SHLD    LCOUNT
  1311.     LXI    H,0
  1312.     SHLD    LBTOTL
  1313.     SHLD    LMTOTL
  1314.     LXI    H,ORDER        ; Initialize order table pointer
  1315.     SHLD    NEXTL
  1316.     SHLD    NEXTT
  1317.     LDA    VFLAG        ; Check display form
  1318.     ORA    A
  1319.     JNZ    NEWLIN        ; Jump if not vertical
  1320.     LHLD    COUNT        ; Code computes end of name table
  1321.     CALL    MULT13        ; (or start of second table
  1322.     XCHG            ; Where files to be stored after
  1323.     LHLD    TBLOC        ; Redundant extents removed)
  1324.     DAD    D
  1325.     SHLD    NEWPTR        ; Save it twice
  1326.     SHLD    XPOINT        ; For later
  1327. ;
  1328. ; Output the directory files we've matched
  1329. ;
  1330. ENTRY:    LHLD    COUNT        ; Files matched count
  1331.     DCX    H        ; Count-1
  1332.     SHLD    COUNT
  1333.     MOV    A,H        ; Is this the last file?
  1334.     ORA    L
  1335.     JZ    OKPRNT        ; Yes, last file so skip compare
  1336. ;
  1337. ; Compare each entry to make sure that it isn't part of a multiple
  1338. ; extent file.    Go only when we have the last extent of the file.
  1339. ;
  1340.     PUSH    B        ; Save number of columns
  1341.     LDA    VFLAG        ; Check display form
  1342.     ORA    A
  1343.     CNZ    CKABRT        ; If horiz, check for abort from keyboard
  1344.     LHLD    NEXTT
  1345.     MVI    A,11
  1346.     CALL    COMPR        ; Does this entry match next one?
  1347.     POP    B        ; Restore number of columns
  1348.     JNZ    OKPRNT        ; No, print it
  1349.     INX    H
  1350.     INX    H        ; Skip, highest extent last in list
  1351.     SHLD    NEXTT
  1352.     JMP    ENTRY        ; Loop back for next lowest extent
  1353. ;
  1354. ; VLIST substitution. If VLIST option chosen, OKPRINT moves unique
  1355. ; filenames and sizes in "k" to a second table above the first for
  1356. ; use later.
  1357. ;
  1358. OKPRNT:    LHLD    NEXTT        ; Get order table pointer
  1359.     MOV    E,M        ; Get low order address
  1360.     INX    H
  1361.     MOV    D,M        ; Get high order address
  1362.     INX    H
  1363.     SHLD    NEXTT        ; Save updated table pointer
  1364.     XCHG            ; Table entry to HL
  1365.     LDA    VFLAG        ; Check display form
  1366.     ORA    A
  1367.     JNZ    OKPR1        ; Jump if not vertical
  1368.     PUSH    H        ; Save address of byte to be moved
  1369.     LHLD    NEWPTR        ; Address in new table to put byte
  1370.     PUSH    H        ; Save address
  1371.     LXI    D,13        ; Update address
  1372.     DAD    D
  1373.     SHLD    NEWPTR        ; Save for later (end of table)
  1374.     POP    H        ; Set current move  to    address
  1375.     XCHG            ; Swap pointers
  1376.     POP    H        ; Set current move from address
  1377.     MVI    B,11        ; Filename.typ length
  1378.     CALL    MOVE        ; Move it
  1379.     PUSH    D
  1380.     JMP    OKPR2
  1381.  
  1382. OKPR1:    MVI    B,8        ; Filename length
  1383.     CALL    PUTSB        ; Output
  1384.     MVI    A,'.'        ; Period after filename
  1385.     CALL    PUTCHR        ; Output
  1386.     MVI    B,3        ; Filetype length
  1387.     CALL    PUTSB        ; Output
  1388.  
  1389. OKPR2:    CALL    SIZEFL
  1390.     LHLD    TOTSIZ        ; DE = rounded size in K
  1391.     DAD    D        ; Add to total used
  1392.     SHLD    TOTSIZ
  1393.     LHLD    TOTFIL        ; Increment filecount
  1394.     INX    H
  1395.     SHLD    TOTFIL
  1396.     XCHG
  1397.     LDA    COPFLG        ; Size wanted in records?
  1398.     ORA    A
  1399.     JNZ    OKPR3        ; Jump if not
  1400.     LHLD    FILERC        ; Else get record count
  1401.  
  1402. OKPR3:    LDA    VFLAG        ; Check display form
  1403.     ORA    A
  1404.     JNZ    OKPR4        ; Jump if not vertical
  1405.     POP    D        ; A(size to go)
  1406.     MOV    A,H        ; Move size to table two
  1407.     STAX    D
  1408.     INX    D
  1409.     MOV    A,L
  1410.     STAX    D
  1411. ;
  1412. ; One File Moved - Test to see if we have to move another
  1413. ;
  1414.     LHLD    COUNT        ; Current file counter
  1415.     MOV    A,H
  1416.     ORA    L
  1417.     JZ    PRTOTL        ; Zero, output summary
  1418.     JMP    ENTRY
  1419. ;
  1420. ; Output the size of the individual file
  1421. ;
  1422. OKPR4:    CALL    DECPRT        ; Print it
  1423.     LDA    FSIZEC        ; Follow with 'k' or 'r'
  1424.     CALL    PUTCHR
  1425. ;
  1426. ; One file output - test to see if we have to output another one.
  1427. ;
  1428.     LHLD    COUNT        ; Current file counter
  1429.     MOV    A,H
  1430.     ORA    L        ; Zero?
  1431.     JZ    PRTOTL        ; Yes, exit to summary output
  1432. ;
  1433. ; At least one more file to output,
  1434. ; can we put it on the current line?
  1435. ;
  1436.     DCR    C
  1437.     PUSH    PSW
  1438.     CNZ    FENCE        ; If room left output fence character
  1439.     POP    PSW
  1440.     JNZ    ENTRY        ; Output another file
  1441. ;
  1442. ; Current line full, start a new one
  1443. ;
  1444. NEWLIN:    MVI    C,4        ; Reset names per line counter
  1445.     CALL    CRLF        ; Space down to next line
  1446.     JMP    ENTRY        ; Output another file
  1447. ;.....
  1448. ;
  1449. ; Compute the size of the file/library and update our summary datum.
  1450. ; This has been changed into a subroutine so that both the file size
  1451. ; computation and a library size (when printing out library members)
  1452. ; can be computed in K.
  1453. ;
  1454. SIZEFL:    MOV    D,M
  1455.     INX    H
  1456.     MOV    E,M        ; Size in DE (records)
  1457.     XCHG
  1458.     SHLD    FILERC        ; Save record count
  1459.     XCHG
  1460.     LDA    BLKMSK
  1461.     PUSH    PSW
  1462.     ADD    E
  1463.     MOV    E,A
  1464.     MOV    A,D
  1465.     ACI    0
  1466.     MOV    D,A
  1467.     POP    PSW
  1468.     CMA
  1469.     ANA    E
  1470.     MOV    E,A
  1471.     MVI    B,3
  1472.  
  1473. SHRR:    MOV    A,D
  1474.     ORA    A
  1475.     RAR
  1476.     MOV    D,A
  1477.     MOV    A,E
  1478.     RAR
  1479.     MOV    E,A
  1480.     DCR    B
  1481.     JNZ    SHRR
  1482.     RET
  1483. ;
  1484. ; Print HL in decimal with leading zero suppression
  1485. ;
  1486. DECPRT:    XRA    A        ; Clear leading zero flag
  1487.     STA    LZFLG
  1488.     LXI    D,-10000
  1489.     LDA    SUPSPC
  1490.     PUSH    PSW
  1491.     XRA    A
  1492.     STA    SUPSPC
  1493.     CALL    DIGIT
  1494.     POP    PSW
  1495.     STA    SUPSPC
  1496.     LXI    D,-1000        ; Print 1000's digit
  1497.     CALL    DIGIT
  1498.     LXI    D,-100        ; Etc.
  1499.     CALL    DIGIT
  1500.     LXI    D,-10
  1501.     CALL    DIGIT
  1502.     MVI    A,'0'        ; Get 1's digit
  1503.     ADD    L
  1504.     JMP    PUTCHR
  1505.  
  1506. DIGIT:    MVI    B,'0'        ; Start off with ASCII 0
  1507.  
  1508. DIGLP:    PUSH    H        ; Save current remainder
  1509.     DAD    D        ; Subtract
  1510.     JNC    DIGEX        ; Quit on overflow
  1511.     POP    PSW        ; Throw away remainder
  1512.     INR    B        ; Bump digit
  1513.     JMP    DIGLP        ; Loop back
  1514.  
  1515. DIGEX:    POP    H        ; Restore pointer
  1516.     MOV    A,B
  1517.     CPI    '0'        ; Zero digit?
  1518.     JNZ    DIGNZ        ; No, type it
  1519.     LDA    LZFLG        ; Leading zero?
  1520.     ORA    A
  1521.     MVI    A,'0'
  1522.     JNZ    PUTCHR        ; Print digit
  1523.     LDA    SUPSPC        ; Get space suppression flag
  1524.     ORA    A        ; See if printing file totals
  1525.     RZ            ; Yes, don't give leading spaces
  1526.     JMP    SPACE        ; Leading zero..print space
  1527. ;
  1528. DIGNZ:    STA    LZFLG        ; Leading zero flag set
  1529.     JMP    PUTCHR        ; Print leading zero & digit
  1530. ;.....
  1531. ;
  1532. ;-----------------------------------------------------------------------
  1533. ;          VLIST subroutines begin here
  1534. ;
  1535. ;Multiply contents of HL register by 13
  1536. ;
  1537. MULT13:    MOV    D,H
  1538.     MOV    E,L
  1539.     DAD    H
  1540.     DAD    D
  1541.     DAD    H
  1542.     DAD    H
  1543.     DAD    D
  1544.     RET
  1545. ;.....
  1546. ;
  1547. ; Main VLIST subroutine to output a filename and column delimiter
  1548. ;
  1549. VENTRY:    CALL    PFILE1        ; Routine to print a filename
  1550.     RZ            ; If at end of line return with zero set
  1551.     CC    FENCE        ; Print column delimiter if more
  1552.     LHLD    JUMPER        ; Put the jumper back in DE
  1553.     XCHG
  1554.     ORI    1        ; Insure non zero return
  1555.     RET
  1556. ;.....
  1557. ;
  1558. PFILE1:    MOV    A,M        ; Let's see what we have
  1559.     CPI    0FEH
  1560.     RNC
  1561.     ANI    7FH        ; Strip parity bit
  1562.     PUSH    B        ; Save number of columns
  1563.     MVI    B,8        ; Print filename and type
  1564.     CALL    PUTSB
  1565.     MVI    A,'.'
  1566.     CALL    PUTCHR
  1567.     MVI    B,3
  1568.     CALL    PUTSB
  1569.     MOV    D,M        ; Get it into DE
  1570.     INX    H
  1571.     MOV    E,M
  1572.     XCHG            ; HL <-> DE
  1573.     CALL    DECPRT        ; Print it out
  1574.     LDA    FSIZEC        ; Follow with 'k' or 'r'
  1575.     CALL    PUTCHR
  1576.     POP    B        ; Load number of columns
  1577.     LHLD    TOTFIL        ; Load number of files left
  1578.     DCX    H        ; # files-1
  1579.     SHLD    TOTFIL        ; Resave it
  1580.     MOV    A,H
  1581.     ORA    L        ; Zero yet?
  1582.     RZ            ; Yes, no more files
  1583.     DCR    C        ; No, decrement it
  1584.     STC            ; Force carry on
  1585.     RET            ; This return
  1586. ;.....
  1587. ;
  1588. ;              End of VLIST routines
  1589. ;-----------------------------------------------------------------------
  1590. ;
  1591. ; Show total space and files used
  1592. ;
  1593. PRTOTL:    LDA    VFLAG        ; Check display form
  1594.     ORA    A
  1595.     JZ    PRTOT1        ; Jump if vertical
  1596.     LDA    LOPFLG
  1597.     ORA    A
  1598.     JNZ    PRTOT1
  1599.     LHLD    TOTFIL        ; How many files matched?
  1600.     MOV    A,H
  1601.     ORA    L
  1602.     CNZ    PRTLMEM        ; Skip .LBR check if none found
  1603.  
  1604. PRTOT1:    XRA    A        ; Get a zero to
  1605.     STA    SUPSPC        ; Suppress leading spaces in totals
  1606.     LHLD    TOTFIL        ; How many files matched?
  1607.     MOV    A,H
  1608.     ORA    L
  1609.     JZ    NXTUSR        ; Skip summary if none found
  1610.     PUSH    H        ; Save TOTFIL
  1611.     STA    FNDFLG        ; Set file found flag
  1612.     LDA    VFLAG        ; Check display form
  1613.     ORA    A
  1614.     JNZ    PRTOT3        ; Horizontal = 0FFh, exit if not zero
  1615.     LDA    SOHFLG
  1616.     ORA    A
  1617.     JZ    PRTOT2
  1618.     XRA    A
  1619.     STA    SOHFLG
  1620.     JMP    PRTOT3
  1621.  
  1622. PRTOT2:    CALL    CRLF
  1623.  
  1624. PRTOT3:    LXI    D,TOTMS1    ; Print "13,10,' Drive'"
  1625.     CALL    PUTS
  1626.     LDA    FCB
  1627.     ADI    'A'-1
  1628.     CALL    PUTCHR        ; Output the drive code
  1629.     CALL    CKVER
  1630.     JC    NOUSER
  1631.     CALL    PUTUSR        ; Output user number
  1632.  
  1633.      IF    NDIRS
  1634.     MVI    A,' '
  1635.     CALL    PUTCHR
  1636.     CALL    NAMDIR
  1637.      ENDIF            ; NDIRS
  1638.  
  1639.     LDA    USRNR
  1640.     CPI    10
  1641.     LXI    D,NOFMS2
  1642.     JC    $+6
  1643.     LXI    D,NOFMS2+1    ; Print some spaces
  1644.     CALL    PUTS
  1645.     LDA    BYEACT        ; BYE active?
  1646.     ORA    A
  1647.     JZ    NOUSER        ; Yes, skip ulcode
  1648.  
  1649.      IF    ULINE
  1650.     LXI    D,ULON        ; Turn on underline
  1651.     CALL    COUTS        ; If not null
  1652.      ENDIF            ; ULINE
  1653.  
  1654. NOUSER:    LXI    D,TOTMS6    ; Print " Files: "
  1655.     CALL    PUTS
  1656.     POP    H        ; Recall TOTFIL
  1657.     CALL    DECPRT        ; Print # of files matched
  1658.     LXI    D,TOTMS4    ; No CRLF needed, display > 40
  1659.     CALL    PUTS
  1660.     LHLD    TOTSIZ        ; Total k used by matched files
  1661.     CALL    DECPRT        ; Print file size
  1662.     LXI    D,TOTMS5    ; Print "k"
  1663.     CALL    PUTS
  1664.     CALL    PRTFRE        ; Print free space remaining
  1665.  
  1666.      IF    ULINE
  1667.     LDA    BYEACT        ; Bye active?
  1668.     ORA    A        ;
  1669.     JZ    NPRNT        ; Yes, skip ULINE off
  1670.     LXI    D,ULOFF        ; Turn off underline
  1671.     CALL    COUTS        ; If not null
  1672.      ENDIF            ; ULINE
  1673. ;
  1674. ; Summary line printed, now print detail files, first compute total
  1675. ; printout lines.
  1676. ;
  1677. NPRNT:    LDA    VFLAG        ; Check display form
  1678.     ORA    A
  1679.     JNZ    NXTUSR        ; Jump if horizontal
  1680.     LXI    B,3
  1681.     MOV    A,C        ; Get number of names per line
  1682.     CMA            ; Negative of number of columns
  1683.     MOV    E,A        ; Into DE
  1684.     MVI    D,0FFH
  1685.     LHLD    TOTFIL        ; Load total number of files
  1686.     DAD    B        ; Round up to a full line
  1687.     MVI    C,0FFH
  1688.  
  1689. NPRNT1:    INR    C        ; C-reg will hold number of
  1690.     DAD    D        ; Lines to be displayed
  1691.     JC    NPRNT1
  1692.     MOV    A,C
  1693.     STA    LINES        ; Done, save it for later
  1694.     STA    SUPSPC        ; Allow spaces preceding file sizes
  1695. ;
  1696. ; Number lines times entry size = the number of bytes to skip in the
  1697. ; second table when outputting files in vertical order.
  1698. ;
  1699.     MOV    L,A        ; Put number of lines into HL
  1700.     MVI    H,0
  1701.     CALL    MULT13
  1702.     SHLD    JUMPER        ; Put it away
  1703. ;
  1704. ; Fill a record with FF at the end of table 2
  1705. ;
  1706.     LHLD    NEWPTR        ; Now points to end of table 2
  1707.     MVI    B,128
  1708.     MVI    A,0FFH
  1709.  
  1710. NPRNT2:    MOV    M,A
  1711.     INX    H
  1712.     DCR    B
  1713.     JNZ    NPRNT2
  1714. ;
  1715. ; Increment the number of files for use later in VENTRY.  This insures
  1716. ; that a column delimiter will be printed after the last filename, if
  1717. ; the file appears in other than the last column of the display.
  1718. ;
  1719.     LXI    H,TOTFIL
  1720.     INR    M
  1721. ;
  1722. ; Print out a line of files
  1723. ;
  1724. NPRNT3:    MVI    C,4        ; Reset number of columns
  1725.     CALL    CRLF        ; Start a new line
  1726. ;
  1727. ; Print first filename
  1728. ;
  1729.     LHLD    XPOINT        ; XPOINT = to start of second table
  1730.     CALL    VENTRY        ; At entry. Below, it is incremented
  1731.                 ; For additional lines of printout
  1732.     JZ    NLINE        ; Either out of columns or out of files
  1733. ;
  1734. ; Print second filename
  1735. ;
  1736.     LHLD    XPOINT
  1737.     DAD    D
  1738.     CALL    VENTRY
  1739.     JZ    NLINE
  1740. ;
  1741. ; Print third filename
  1742. ;
  1743.     LHLD    XPOINT
  1744.     DAD    D
  1745.     DAD    D
  1746.     CALL    VENTRY
  1747.     JZ    NLINE
  1748. ;
  1749. ; Print fourth filename
  1750. ;
  1751.     LHLD    XPOINT
  1752.     DAD    D
  1753.     DAD    D
  1754.     DAD    D
  1755.     CALL    VENTRY
  1756.  
  1757. NLINE:    LHLD    XPOINT        ; Increment XPOINT to next file
  1758.     LXI    D,13
  1759.     DAD    D
  1760.     SHLD    XPOINT
  1761.     LHLD    TOTFIL        ; Out of files?
  1762.     MOV    A,H
  1763.     ORA    L
  1764.     JZ    DOLIB        ; Yes, Check for libraries
  1765.     LXI    H,LINES        ; No, just need a new line
  1766.     DCR    M
  1767.     JNZ    NPRNT3
  1768.  
  1769. DOLIB:    LDA    LOPFLG
  1770.     ORA    A
  1771.     JNZ    NXTUSR
  1772.     LHLD    TOTFIL        ; How many files matched?
  1773.     MOV    A,H
  1774.     ORA    L
  1775.     CNZ    PRTLMEM        ; Skip library check if none found
  1776. ;
  1777. ; Directory for one user area completed.  If all users option is select-
  1778. ; ed, then go do another directory on the next user number until we ex-
  1779. ; ceed the maximum user # for the selected drive.
  1780. ;
  1781. NXTUSR:    LDA    AOPFLG        ; All user flag
  1782.     ORA    A        ; Set?
  1783.     JZ    NXTUSU        ; Set if zero, show all user areas
  1784.     LDA    HOPFLG        ; "H" flag to show remaining areas
  1785.     ORA    A
  1786.     JNZ    GOCLZ        ; Non-zero, not set, exit
  1787.  
  1788. NXTUSU:    CALL    CKVER        ; Running CP/M 2?
  1789.     JC    GOCLZ        ; No, Skip user increment
  1790.     CALL    CKABRT        ; Yes, Check for user abort
  1791.     LDA    MAXUSR        ; No abort - get maximum user #
  1792.     LXI    H,NEWUSR    ; Increment directory user number
  1793.     INR    M
  1794.     CMP    M        ; Next user # exceed maximum?
  1795.     JNC    SETTBL        ; No, more user areas to go
  1796.     LDA    BASUSR        ; Reset base user number for
  1797.     MOV    M,A        ; The next directory search
  1798. ;
  1799. ; We've finished all of our outputting. Flush the remainder of the out-
  1800. ; put buffer and close the file before going to exit routine.
  1801. ;
  1802. GOCLZ:    LXI    H,OPNFLG    ; Get file open status, reset flag
  1803.     MOV    A,M        ; To force reopen on next pass
  1804.     MVI    M,0
  1805.     ORA    A        ; File open?
  1806.     JZ    NXTDSK        ; No, Skip closing DISK.DIR
  1807.     LXI    H,BUFCNT
  1808.     MOV    A,M        ; Load # of unflushed characters in
  1809.     MVI    M,128        ; Buffer, force BUFCNT to empty status
  1810.     ORA    A        ; If BUFCNT=128, buffer empty set sign
  1811.     JM    DDCLOS        ; Close DISK.DIR if buffer is empty
  1812.     JZ    FLUSH        ; Write last record to DISK.DIR if full
  1813.     LHLD    BUFPNT        ; Else pad unused buffer with CTL-Z
  1814.  
  1815. PUTAGN:    MVI    M,'Z'-40H    ; EOF marker
  1816.     INX    H        ; Next buffer location
  1817.     DCR    A        ; Count-1
  1818.     JNZ    PUTAGN        ; Continue buffer padding fill
  1819.  
  1820. FLUSH:    LXI    D,OUTFCB    ; Flush the last output buffer
  1821.     MVI    C,WRITE
  1822.     CALL    CPM
  1823.     ORA    A
  1824.     JNZ    WRTERR
  1825.  
  1826. DDCLOS:    LXI    D,OUTFCB    ; Close DISK.DIR output file
  1827.     MVI    C,CLOSE
  1828.     CALL    CPM
  1829. ;
  1830. ; Directory for all user areas finished.  If the multi-disk option is
  1831. ; enabled and selected, reset to the base user area and repeat the
  1832. ; directory for next drive on-line until we either exceed the drives in
  1833. ; our LODRV-HIDRV table, or the BDOS shuts us down with a select or bad
  1834. ; record error, which will be intercepted back to the EXIT module.
  1835. ;
  1836. NXTDSK:    LXI    H,FNDFLG    ; Load file found flag
  1837.     MOV    A,M
  1838.     MVI    M,0        ; Clear found flag for next drive
  1839.     ORA    A
  1840.     JNZ    NDSK        ; Continue if at least 1 file found
  1841.     LXI    H,FOPFLG
  1842.     DCR    M
  1843.     PUSH    H
  1844.     LXI    D,NOFMS1    ; Print 1st part of no files message
  1845.     CALL    PUTS        ; Print it
  1846.     LXI    D,NOFLM
  1847.     CALL    PUTS        ; Print message
  1848.     LDA    FCB
  1849.     ADI    'A'-1
  1850.     CALL    PUTCHR        ; Output the drive
  1851.     CALL    CKVER
  1852.     JC    NOUSR1
  1853.     CALL    PUTUSR        ; Output the user number
  1854.  
  1855. NOUSR1:    LXI    D,NOFMS3    ; Print divider
  1856.     CALL    PUTS
  1857.     CALL    PRTFRE        ; Tag with free message
  1858.     LDA    VFLAG        ; Check display form
  1859.     ORA    A
  1860.     CNZ    CRLF        ; Need another CRLF in horizontal mode
  1861.     POP    H
  1862.     INR    M
  1863.  
  1864. NDSK:    LDA    DOPFLG        ; Multi-disk selected?
  1865.     ORA    A
  1866.     JNZ    NPRT        ; No, skip next check
  1867.     CALL    CKABRT        ; Check for user abort
  1868.     MVI    A,HIDRV-LODRV    ; Load max drive code to search
  1869.     LXI    H,FCB        ; Increment directory FCB drive code
  1870.     INR    M
  1871.     CMP    M        ; Does next disk exceed maximum?
  1872.     JC    NPRT
  1873.  
  1874.      IF    MAXDRV
  1875.     LDA    MXDRV        ; Look at another value limit
  1876.     INR    A
  1877.     CMP    M        ; Is it lower?
  1878.     JC    NPRT        ; Bail out if too low
  1879.     JMP    NOOPT        ; Search next disk
  1880.      ENDIF            ; MAXDRV
  1881.  
  1882.     JNC    NOOPT        ; Search next disk if maxdr not true
  1883. ;
  1884. ; If no printer, fall through to EXIT
  1885. ;
  1886. NPRT:    LDA    POPFLG
  1887.     ORA    A        ; Printer active?
  1888.     JNZ    EXIT        ; No, just exit
  1889.     MVI    C,LIST
  1890.     MVI    E,13        ; Print a CRLF
  1891.     CALL    CPM
  1892.     MVI    E,10        ; Line feed
  1893.     CALL    CPM
  1894.     JMP    EXIT        ; All done - exit to CCP
  1895. ;.....
  1896. ;
  1897. ; Output the user number of the directory in decimal
  1898. ;
  1899. PUTUSR:    LDA    NEWUSR
  1900.     CPI    10        ; User no. < 10?
  1901.     JC    DUX        ; Yes, skip 10's digit
  1902.     STA    USRNR
  1903.     PUSH    B        ; No, process 10's digit
  1904.     MVI    C,'0'-1
  1905.  
  1906. DUY:    INR    C        ; Get tens digit
  1907.     SUI    10
  1908.     JNC    DUY        ; Loop until we've gone too far
  1909.     ADI    10
  1910.     MOV    B,A        ; Save units digit
  1911.     MOV    A,C        ; Print tens digit
  1912.     CALL    PUTCHR
  1913.     MOV    A,B        ; Recall units digit
  1914.     POP    B
  1915.  
  1916. DUX:    ADI    '0'        ; Make it ASCII
  1917.     JMP    PUTCHR
  1918.  
  1919. ;.....
  1920. ;
  1921. ; Force new line on output and check for page pause
  1922. ;
  1923. CRLF:    MVI    A,13        ; Send CR
  1924.     CALL    PUTCHR
  1925.     MVI    A,10        ; Send LF
  1926.     JMP    PUTCHR
  1927. ;.....
  1928. ;
  1929. ; Separate the directory output on a line with a space,
  1930. ; the delimiter, followed by another space.
  1931. ;
  1932. FENCE:    CALL    SPACE
  1933.     MVI    A,':'        ; Fence character
  1934.     CALL    PUTCHR        ; Print it, then a space character
  1935.  
  1936. SPACE:    MVI    A,' '
  1937. ;
  1938. ; Output character in A to console, and optionally to printer
  1939. ; and/or the output file.  Detects user abort request.
  1940. ;
  1941. PUTCHR:    PUSH    B
  1942.     PUSH    D
  1943.     PUSH    H
  1944.     PUSH    PSW        ; Save the character to output
  1945.     CALL    HITYPE        ; Send it to console
  1946.     POP    PSW        ; Restore the output character
  1947.     ANI    7FH        ; Strip parity bit on character
  1948. ;
  1949. ; Test file output mode and skip to page pause test if not active
  1950. ;
  1951.     MOV    B,A        ; Save stripped character to B
  1952.     CPI    10        ; At end of line?
  1953.     CZ    CKABRT        ; Check for user abort request
  1954.     LDA    FOPFLG        ; Is file output active?
  1955.     ORA    A
  1956.     JNZ    NOWRIT        ; Go check for page pause if not
  1957. ;
  1958. ; File output mode active - make sure we have room in buffer to add
  1959. ; the next character. If buffer full, write out current record first
  1960. ; and then start a new record with current character.
  1961. ;
  1962.     LHLD    BUFPNT        ; Load current buffer pointer
  1963.     LDA    BUFCNT        ; Load buffer capacity remaining
  1964.     ORA    A        ; Buffer full?
  1965.     JNZ    PUTBUF        ; No, Continue
  1966.     CALL    SETFOP        ; Yes, Set the DMA address
  1967.     LXI    D,OUTFCB    ; Else, write current buffer out
  1968.     MVI    C,WRITE
  1969.     CALL    CPM        ; (call must save character in B)
  1970.     ORA    A        ; Error?
  1971.     JNZ    WRTERR        ; Yes, exit if disk full or R/O
  1972.     LXI    H,OUTBUF    ; Reset buffer pointer
  1973.     MVI    A,128        ; Reset buffer capacity
  1974.  
  1975. PUTBUF:    MOV    M,B        ; Move char to next buffer position
  1976.     INX    H        ; Bump buffer pointer
  1977.     SHLD    BUFPNT        ; And save it
  1978.     DCR    A        ; Buffer char count-1
  1979.     STA    BUFCNT        ; And save it
  1980.  
  1981. NOWRIT:    MOV    A,B        ; Recall stripped character
  1982.     ANI    7FH        ; Strip parity bit on character
  1983.     MOV    E,A        ; Setup list output call
  1984.     MVI    C,LIST
  1985.     LDA    POPFLG        ; Load printer flag
  1986.     ORA    A        ; Set?
  1987.     CZ    CPM        ; Yes, print character
  1988.     MOV    A,E        ; Recall character
  1989.     CPI    10        ; Do we have a line feed?
  1990.     JNZ    PUTRET        ; Exit if not
  1991.     LDA    NOPFLG        ; Page pause function disabled?
  1992.     ORA    A
  1993.     JZ    PUTRET        ; Yes, exit
  1994.     LDA    POPFLG        ; Load, printer flag
  1995.     ORA    A        ; Set?
  1996.     JZ    PUTRET        ; Yes, skip page pause
  1997.     LDA    FOPFLG        ; File output flag
  1998.     ORA    A        ; Set?
  1999.     JZ    PUTRET        ; Yes, skip page pause
  2000.  
  2001.     LDA    LINCNT        ; Load line count
  2002.     INR    A        ; Bump it
  2003.     STA    LINCNT
  2004.     MVI    L,23        ; Allows use of [more] to finish display
  2005.     CMP    L        ; End of the screen?
  2006.     JC    PUTRET
  2007.  
  2008.     LXI    D,EOSMSG    ; Else, display pause message
  2009.     MVI    C,PRINT        ; Without checking for line feeds
  2010.     CALL    BDOS
  2011.     CALL    GETCH        ; Wait for character
  2012.     CPI    'C'-40H        ; Abort on CTL-C
  2013.     JZ    EXIT1
  2014.     CPI    'K'-40H        ; Or CTL-K
  2015.     JZ    EXIT1
  2016.     CPI    'X'-40H        ; Or CTL-X
  2017.     JZ    EXIT1
  2018.     CPI    ' '        ; See if printing character
  2019.     JC    NOTEOS        ; Exit if not
  2020.     JZ    NOTEOS1        ; If a space, exit to different place
  2021.     ANI    5FH        ; Change to upper-case
  2022.     CPI    'C'        ; Can abort with c, C
  2023.     JZ    EXIT1
  2024.     CPI    'K'        ; Can abort with k, K
  2025.     JZ    EXIT1
  2026.     CPI    'X'        ; Can abort with x, X
  2027.     JZ    EXIT1
  2028.  
  2029. NOTEOS:    XRA    A        ; Reset line count
  2030.  
  2031. NOTEOS1:STA    LINCNT
  2032.     LXI    D,MORERA    ; Overwrite the [more] display
  2033.     MVI    C,PRINT
  2034.     CALL    BDOS
  2035.     XRA    A        ; Reset the 'A' register
  2036.  
  2037. PUTRET:    POP    H        ; Exit from PUTCHR
  2038.     POP    D
  2039.     POP    B
  2040.     RET
  2041. ;.....
  2042. ;
  2043. ; Output character, with low-case or reverse-video highlighting if high
  2044. ; bit set and conditionals enabled.
  2045. ;
  2046. HITYPE:    DS    0
  2047.  
  2048.      IF    USELC OR REVID
  2049.     ORA    A        ; Check for attributes not set
  2050.     JP    CONOUT        ; No attribute..ignore this one
  2051.     ANI    7FH        ; Attribute set, delete now
  2052.      ENDIF            ; USELC OR REVID
  2053.  
  2054.      IF    NOT USELCW AND WHEEL
  2055.     MOV    E,A        ; Save the character for later
  2056.     LDA    WHLOC        ; If wheel byte not set then
  2057.     ORA    A        ; Don't use lower case or REVID
  2058.     MOV    A,E        ; Get back the character to display
  2059.     JZ    CONOUT
  2060.      ENDIF            ; NOT USELCW AND WHEEL
  2061.  
  2062.      IF    REVID
  2063.     PUSH    PSW        ; Save character
  2064.     LXI    D,RVON        ; Turn on reverse video
  2065.     CALL    COUTS        ; If not null
  2066.     POP    PSW        ; Restore character
  2067.      ENDIF            ; REVID
  2068.  
  2069.      IF    USELC
  2070.     CPI    'A'        ; Change only from A-Z
  2071.     JC    TYPEC
  2072.     CPI    'Z'+1
  2073.     JNC    TYPEC        ; Punctuation can change so leave it
  2074.     ORI    20H        ; If attribute, make lower case
  2075.      ENDIF            ; USELC
  2076.  
  2077.      IF    USELC OR REVID
  2078. TYPEC:    CALL    CONOUT        ; Send the processed character
  2079.      ENDIF            ; USELC OR REVID
  2080.  
  2081.      IF    REVID
  2082.     LXI    D,RVOFF        ; Turn off reverse video
  2083.     CALL    COUTS        ; If not null
  2084.      ENDIF            ; REVID
  2085.  
  2086.      IF    USELC OR REVID
  2087.     RET
  2088.      ENDIF            ; USELC OR REVID
  2089. ;.....
  2090. ;
  2091. ; Output character in A to console
  2092. ;
  2093. CONOUT:    MOV    E,A        ; Get character for BDOS entry
  2094.     MVI    C,WRCON
  2095.     JMP    BDOS        ; Console Output
  2096. ;.....
  2097. ;
  2098. ; Output (raw) null-terminated string at (DE) to console.
  2099. ;
  2100.  
  2101. COUTS:    LDAX    D        ; Get byte of string
  2102.     ORA    A        ; Null?
  2103.     RZ            ; Return if so
  2104.     PUSH    D
  2105.     CALL    CONOUT
  2106.     POP    D
  2107.     INX    D        ; Next byte
  2108.     JMP    COUTS
  2109. ;.....
  2110. ;
  2111. ; Output bytes at HL of length B to console/printer/file
  2112. ;
  2113. PUTSB:    MOV    A,M
  2114.     CALL    PUTCHR
  2115.     INX    H
  2116.     DCR    B
  2117.     JNZ    PUTSB
  2118.     RET
  2119. ;.....
  2120. ;
  2121. ; Output null-terminated string to console/printer/file
  2122. ;
  2123. PUTS:    LDAX    D        ; Load character from DE string
  2124.     ANI    7FH        ; Strip off parity
  2125.     ORA    A        ; Is a 0?
  2126.     RZ            ; Yes, Terminate
  2127.     CALL    PUTCHR        ; Display character
  2128.     INX    D        ; Next string position
  2129.     JMP    PUTS        ; Continue
  2130. ;.....
  2131. ;
  2132. ; Fetch character from console (without echo)
  2133. ;
  2134. GETCH:    LHLD    0000H+1        ; Warm Boot Address
  2135.     MVI    L,9        ; Direct Console
  2136.     CALL    GOHL        ; Get Character
  2137.     ANI    7FH        ; Strip off any parity
  2138.     RET
  2139. ;.....
  2140. ;
  2141. ; Check for a CTL-C or CTL-S entered from the keyboard.  Jump to EXIT if
  2142. ; CTL-C, pause on CTL-S.
  2143. ;
  2144. CKABRT:    PUSH    H
  2145.     PUSH    D
  2146.     PUSH    B
  2147.     MVI    C,CONST
  2148.     CALL    BDOS
  2149.     ORA    A
  2150.     JZ    CKAB3        ; No character, exit
  2151.     MVI    C,RDCON
  2152.     CALL    BDOS
  2153.     ANI    5FH
  2154.     CPI    'S'-40H
  2155.     JZ    CKAB0
  2156.     CPI    'S'
  2157.     JNZ    CKAB1
  2158.     CALL    CKAB4
  2159.  
  2160. CKAB0:    MVI    C,RDCON
  2161.     CALL    BDOS
  2162.     ANI    5FH
  2163.  
  2164. CKAB1:    CPI    'C'-40H        ; CTL-C?
  2165.     JZ    CKAB2        ; Yes, quit
  2166.     CPI    'K'-40H
  2167.     JZ    CKAB2
  2168.     CPI    'X'-40H
  2169.     JZ    CKAB2
  2170.     CPI    ' '        ; Any other CTL-character, abort
  2171.     JC    CKAB3
  2172.     CALL    CKAB4        ; Clear the character from screen
  2173.     CPI    'C'
  2174.     JZ    CKAB2
  2175.     CPI    'K'
  2176.     JZ    CKAB2
  2177.     CPI    'X'
  2178.     JNZ    CKAB3
  2179.  
  2180. CKAB2:    LXI    D,CKMS1
  2181.     CALL    PUTS
  2182.     POP    B
  2183.     POP    D
  2184.     POP    H
  2185.     JMP    EX0        ; All done
  2186.  
  2187. CKAB3:    POP    B
  2188.     POP    D
  2189.     POP    H
  2190.     RET
  2191.  
  2192. CKAB4:    PUSH    PSW
  2193.     LXI    D,CKMS2
  2194.     CALL    PUTS
  2195.     POP    PSW
  2196.     RET
  2197. ;.....
  2198. ;
  2199. ; Call here to call address in HL
  2200. ;
  2201. GOHL:    PCHL
  2202. ;
  2203. ; Enter BDOS, save all extended registers
  2204. ;
  2205. CPM:    PUSH    B        ; Save Registers
  2206.     PUSH    D
  2207.     PUSH    H
  2208.  
  2209.      IF    ZRDOS
  2210.     LDA    ZRDFLG        ; ZRDOS running?
  2211.     ORA    A
  2212.     JNZ    ZRD        ; ZRDOS error trap and DOSs call
  2213.      ENDIF            ; ZRDOS
  2214.  
  2215.     CALL    BDOS
  2216.     MOV    B,A        ; Save return code
  2217.     LDA    VERFLG        ; Is this 3.0?
  2218.     CPI    30H
  2219.     MOV    A,B
  2220.     JC    CPM20        ; No, exit normally
  2221.     CPI    0FFH        ; Yes, was return code FF?
  2222.     JNZ    CPM20        ; No, exit normally
  2223.     MOV    A,H        ; Yes, check for error code
  2224.     ORA    A
  2225.     JNZ    DSKERR        ; Exit if physical error
  2226.     MOV    A,B        ; Else, continue normally
  2227.  
  2228. CPM20:    POP    H
  2229.     POP    D
  2230.     POP    B
  2231.     RET
  2232. ;.....
  2233. ;
  2234. ; ZRDOS Error Trap and System Call exits to CPM20
  2235. ;
  2236.      IF    ZRDOS
  2237. ZRD:    CALL    SETTRAP        ; Set the warm boot trap
  2238.     CALL    BDOS        ; Do what we're told
  2239.     CALL    RESTRAP        ; Reset the trap
  2240.     JMP    CPM20        ; Error free exit
  2241. ;.....
  2242. ;
  2243. ; Set Warm Boot Trap in ZRDOS
  2244. ;
  2245. SETTRAP:PUSH    H
  2246.     PUSH    D
  2247.     PUSH    B
  2248.     MVI    C,SETWBT    ; Set warm boot trap to come here
  2249.     LXI    D,WBTRAP
  2250.     CALL    BDOS
  2251.     POP    B
  2252.     POP    D
  2253.     POP    H
  2254.     RET
  2255. ;.....
  2256. ;
  2257. ; WBTRAP is where the ZRDOS returns control on warm boot (error)
  2258. ;
  2259. WBTRAP:    LXI    H,DSKERR    ; Return here after trap reset
  2260.     PUSH    H        ; Save DSKERR on stack
  2261. ;
  2262. ; Reset Warm Boot Trap in ZRDOS
  2263. ;
  2264. RESTRAP:PUSH    H
  2265.     PUSH    D
  2266.     PUSH    B
  2267.     PUSH    PSW
  2268.     MVI    C,RESWBT    ; Reset warm boot trap
  2269.     CALL    BDOS
  2270.     POP    PSW
  2271.     POP    B
  2272.     POP    D
  2273.     POP    H
  2274.     RET
  2275.      ENDIF            ; ZRDOS
  2276. ;.....
  2277. ;
  2278. ; For file output mode, return to old user area and set DMA for the file
  2279. ; output buffer.
  2280. ;
  2281. SETFOP:    CALL    CKVER        ; Clear carry if CP/M 2 or later
  2282.     LDA    OLDUSR        ; Get user number at startup
  2283.     MOV    E,A
  2284.     MVI    C,STUSER
  2285.     CNC    CPM        ; Reset old user number if CP/M 2
  2286.     LXI    D,OUTBUF    ; Move DMA from search buffer into
  2287.     JMP    SET2        ; Output buffer
  2288.     RET
  2289. ;.....
  2290. ;
  2291. ; Move disk buffer DMA to default buffer for directory search operations
  2292. ; and BDOS media change routines (required for pre-CP/M 2 systems while
  2293. ; in file output mode with active buffer).
  2294. ;
  2295. SETSRC:    LXI    D,TBUF        ; Default DMA Address
  2296.  
  2297. SET2:    MVI    C,STDMA        ; Set DMA Address
  2298.     JMP    CPM
  2299. ;.....
  2300. ;
  2301. ; Print amount of free space remaining on selected drive
  2302. ;
  2303. PRTFRE:    LXI    D,TOTMS7    ; Print " Free: '
  2304.     CALL    PUTS
  2305.     LHLD    FREEBY
  2306.     CALL    DECPRT        ; Print k free
  2307.     LXI    D,TOTMS8    ; Print "k "
  2308.     CALL    PUTS
  2309.     LDA    VFLAG        ; Alphabetizing vertically?
  2310.     ORA    A
  2311.     RZ            ; If yes, finished
  2312.     JMP    CRLF        ; Else turn up an extra line
  2313. ;.....
  2314. ;
  2315. ; Show string on the console
  2316. ;
  2317. SHOW:    LDAX    D        ; Get character from DE string
  2318.     ANI    7FH        ; Strip off parity
  2319.     ORA    A        ; Is it a 0?
  2320.     RZ            ; Yes, terminate
  2321.     PUSH    B        ; Save registers
  2322.     PUSH    D
  2323.     PUSH    H
  2324.     CALL    CONOUT        ; Show character on console
  2325.     POP    H        ; Load registers
  2326.     POP    D
  2327.     POP    B
  2328.     INX    D        ; Next string position
  2329.     JMP    SHOW        ; Continue
  2330. ;.....
  2331. ;
  2332. ; Compare routine for last extent of file search
  2333. ;
  2334. COMPR:    PUSH    H        ; Save table address
  2335.     MOV    E,M        ; Load low order
  2336.     INX    H
  2337.     MOV    D,M        ; Load high order
  2338.     INX    H
  2339.     MOV    C,M
  2340.     INX    H
  2341.     MOV    B,M
  2342. ;
  2343. ; BC, DE now point to entries to be compared
  2344. ;
  2345.     XCHG
  2346.     MOV    E,A        ; Get count
  2347.  
  2348. CMPLP:    LDAX    B
  2349.     XRA    M        ; Copy bit 7 of M
  2350.     ANI    7FH        ; Into bit 7 of A
  2351.     XRA    M
  2352.     CMP    M        ; Then compare
  2353.     INX    H
  2354.     INX    B
  2355.     JNZ    NOTEQL        ; Quit on mismatch
  2356.     DCR    E        ; Or end of count
  2357.     JNZ    CMPLP
  2358. ;
  2359. NOTEQL:    POP    H
  2360.     RET            ; Condition code tells all
  2361. ;.....
  2362. ;
  2363. ; Swap entries in the order table
  2364. ;
  2365. SWAP:    LXI    B,ORDER-2    ; Table base
  2366.     DAD    H        ; *2
  2367.     DAD    B        ; + base
  2368.     XCHG
  2369.     DAD    H        ; *2
  2370.     DAD    B        ; + base
  2371.     MOV    C,M
  2372.     LDAX    D
  2373.     XCHG
  2374.     MOV    M,C
  2375.     STAX    D
  2376.     INX    H
  2377.     INX    D
  2378.     MOV    C,M
  2379.     LDAX    D
  2380.     XCHG
  2381.     MOV    M,C
  2382.     STAX    D
  2383.     RET
  2384. ;.....
  2385. ;
  2386. ; New compare routine for sorting
  2387. ;
  2388. COMPARE:LXI    B,ORDER-2
  2389.     DAD    H
  2390.     DAD    B
  2391.     XCHG
  2392.     DAD    H
  2393.     DAD    B
  2394.     XCHG
  2395.     MOV    C,M
  2396.     INX    H
  2397.     MOV    B,M
  2398.     XCHG
  2399.     MOV    E,C
  2400.     MOV    D,B
  2401.     MOV    C,M
  2402.     INX    H
  2403.     MOV    H,M
  2404.     MOV    L,C
  2405.     MVI    B,13        ; Count for normal sort
  2406.     LDA    TOPFLG        ; Check for sort by type
  2407.     ORA    A
  2408.     JNZ    CMPLPE        ; Jump if normal sort
  2409.     PUSH    H        ; Save name pointers for later
  2410.     PUSH    D
  2411.     LXI    B,8        ; Point to file types
  2412.     DAD    B
  2413.     XCHG
  2414.     DAD    B
  2415.     XCHG
  2416.     MVI    B,3        ; Count for type compare
  2417.     CALL    CMPLPE
  2418.     POP    D        ; Retrieve name pointers
  2419.     POP    H        ;
  2420.     RNZ
  2421.     MVI    B,8        ; Count for name compare
  2422.     CALL    CMPLPE
  2423.     RNZ
  2424.     INX    D        ; Point to extent
  2425.     INX    D
  2426.     INX    D
  2427.     INX    H
  2428.     INX    H
  2429.     INX    H
  2430.     MVI    B,2        ; Count for extent compare
  2431.  
  2432. CMPLPE:    LDAX    D        ;
  2433.     XRA    M        ; Copy bit 7 of M
  2434.     ANI    7FH        ; Into bit 7 of A
  2435.     XRA    M        ;
  2436.     CMP    M        ; Then compare
  2437.     INX    D
  2438.     INX    H
  2439.     RNZ
  2440.     DCR    B
  2441.     JNZ    CMPLPE
  2442.     RET
  2443. ;.....
  2444. ;
  2445. ; Error exit
  2446. ;
  2447. ERXIT:    MVI    A,0FFH        ; Error Flag
  2448.     STA    FOPFLG        ; Disable file output on error
  2449.     CALL    CRLF        ; Space down
  2450.     POP    D        ; Load message string pointer
  2451.     CALL    PUTS        ; Print message
  2452.     LXI    D,ERRMS1    ; " Error"
  2453.     CALL    PUTS        ; Print message
  2454.     CALL    CRLF        ; Space down
  2455. ;
  2456. ; Exit - all done, restore stack
  2457. ;
  2458. EXIT:    LDA    DOPFLG        ; Multi-disk selected?
  2459.     ORA    A
  2460.     JNZ    EX0        ; No, skip next
  2461.     CALL    CKABRT        ; Check for user abort
  2462.     MVI    A,HIDRV-LODRV    ; Maximum drive code to search
  2463.     LXI    H,FCB        ; Increment directory FCB drive code
  2464.     INR    M
  2465.     CMP    M        ; Does next disk exceed maximum?
  2466.     JC    EX0
  2467.  
  2468.      IF    MAXDRV
  2469.     LDA    MXDRV        ; Look at another value limit
  2470.     INR    A
  2471.     CMP    M        ; Is it lower?
  2472.     JC    EX0        ; Bail out if too low
  2473.     JMP    NOOPT        ; Search next disk
  2474.      ENDIF            ; MAXDRV
  2475.  
  2476.     JNC    NOOPT        ; Search next disk if MAXDR not true
  2477.  
  2478. EX0:    LDA    VFLAG        ; Check display form
  2479.     ORA    A
  2480.     CZ    CRLF        ; Turn up a blank line at end if vertical
  2481.     MVI    C,CONST        ; Check console status
  2482.     CALL    CPM
  2483.     ORA    A        ; Character waiting?
  2484.     MVI    C,RDCON
  2485.     CNZ    CPM        ; Gobble up character
  2486.  
  2487.      IF    ZRDOS
  2488.     LDA    ZRDFLG        ; ZRDOS running?
  2489.     ORA    A
  2490.     JNZ    EXIT2        ; Yes
  2491.      ENDIF            ; ZRDOS
  2492.  
  2493.     LDA    VERFLG        ; Version flag
  2494.     CPI    30H        ; CP/M 3.0?
  2495.     JC    EXIT1        ; No
  2496.     MVI    C,2DH        ; Yes,
  2497.     MVI    E,0        ; Reset error mode to default
  2498.     CALL    CPM
  2499.     JMP    EXIT2        ; Quit
  2500.  
  2501. EXIT1:    LDA    DOPFLG        ; If they were swapped
  2502.     ORA    A
  2503.     CZ    SWAPEM
  2504.  
  2505. EXIT2    EQU    $
  2506.  
  2507.      IF    SHOPUB
  2508.     CALL    RSTPUB
  2509.      ENDIF            ; SHOPUB
  2510.  
  2511.      IF    WMBOOT
  2512.     JMP    0000H
  2513.      ENDIF            ; WMBOOT
  2514.  
  2515.     LDA    OLDDSK        ; Restore original drive
  2516.     MOV    E,A
  2517.     MVI    C,14
  2518.     CALL    CPM
  2519.     LDA    OLDUSR        ; Restore original user area
  2520.     MOV    E,A
  2521.     MVI    C,32
  2522.     CALL    CPM
  2523.  
  2524. EXIT3:    LHLD    STACK        ; Get old stack pointer
  2525.     SPHL            ; Move back to old stack
  2526.     RET            ; And return to CCP
  2527. ;.....
  2528. ;
  2529. ; Restore Public areas if they were changed
  2530. ;
  2531.      IF    SHOPUB
  2532. RSTPUB:    LHLD    0109H
  2533.     MVI    D,0
  2534.     MVI    E,07EH
  2535.     DAD    D
  2536.     LDA    PUBDRV
  2537.     MOV    M,A
  2538.     INX    H
  2539.     LDA    PUBUSR
  2540.     MOV    M,A
  2541.     RET
  2542.      ENDIF            ; SHOPUB
  2543. ;.....
  2544. ;
  2545.      IF    NDIRS
  2546. NAMDIR:    MVI    A,0
  2547.     STA    CURDIR        ; Initial check count
  2548.  
  2549. NAMDR1:    LHLD    NAMADR        ; Named directory buffer address
  2550.  
  2551. NAMDR2:    LDA    FCB        ; Get current Drive
  2552.     CMP    M        ; Does NDR entry match current drive?
  2553.     JNZ    NXTDIR        ; No, check next
  2554.     LDA    NEWUSR        ; Get current user
  2555.     INX    H
  2556.     CMP    M        ; Does NDR entry match current user?
  2557.     JNZ    NXTDIR        ; No, check next
  2558.     MVI    A,'['        ; Frame the name in brackets
  2559.     CALL    PUTCHR
  2560.     MVI    C,8        ; Number of Characters in entry
  2561.  
  2562. DIRCHR:    INX    H        ; Match, Point to Directory Name
  2563.     MOV    A,M        ; Get Character
  2564.     CPI    20H        ; End of entry?
  2565.     JNZ    DIRCH1        ; No
  2566.  
  2567. DIRCH0:    PUSH    PSW
  2568.     MVI    A,']'        ; Print closing bracket
  2569.     CALL    PUTCHR
  2570.     POP    PSW
  2571.     JMP    DIRCH2
  2572.  
  2573. DIRCH1:    CALL    PUTCHR
  2574.     DCR    C
  2575.     JNZ    DIRCHR        ; Output Eight characters
  2576.     JMP    DIRCH0
  2577.     RET            ; Done
  2578. DIRCH2:    MOV    A,C
  2579.     ORA    A
  2580.     RZ
  2581.     MVI    A,20H        ; Fill with spaces for neatness sake
  2582.     CALL    PUTCHR
  2583.     DCR    C
  2584.     JNZ    DIRCH2
  2585.     RET
  2586.  
  2587. NXTDIR:    LDA    CURDIR
  2588.     ADI    1        ; Increment Directory pointer
  2589.     STA    CURDIR
  2590.     LXI    H,NUMDIR
  2591.     CMP    M        ; Exceeded Max Entry?
  2592.     JZ    NODIR        ; Yes, there is no entry for this DU
  2593.     LHLD    NAMADR        ; Get base NDR address
  2594.     MVI    D,0
  2595.     MVI    E,18        ; Increment to next entry
  2596.  
  2597. NXTD:    DAD    D
  2598.     DCR    A        ; Decrement count
  2599.     JNZ    NXTD        ; Until current Offset reached
  2600.     JMP    NAMDR2        ; And check the entry for a match
  2601. NODIR:    MVI    C,10        ; No match, output ten spaces
  2602.  
  2603. NODIR1:    MVI    A,20H
  2604.     CALL    PUTCHR
  2605.     DCR    C
  2606.     JNZ    NODIR1
  2607.     RET
  2608.      ENDIF            ; NDIRS
  2609. ;.....
  2610. ;
  2611. ; Trap BDOS select and sector error vectors to our own intercept routine
  2612. ; so we can catch a reference to an illegal drive.
  2613. ;
  2614. SWAPEM:    DS    0
  2615.  
  2616.      IF    ZRDOS
  2617.     LDA    ZRDFLG        ; See if ZRDOS running
  2618.     ORA    A
  2619.     RNZ            ; Yes, quit this
  2620.      ENDIF            ; ZRDOS
  2621.  
  2622.     LDA    VERFLG        ; Version flag
  2623.     CPI    30H        ; Error mode call available?
  2624.     JC    SWAP20        ; No, use BDOS error vectors
  2625.     MVI    C,2DH        ; Yes, use error mode call
  2626.     MVI    E,0FFH        ;
  2627.     CALL    CPM        ; Set "return code only" mode
  2628.     RET
  2629.  
  2630. SWAP20:    LHLD    BDOS+1        ; Load pointer to base of BDOS
  2631.     INX    H        ; Swap new pointer if running a
  2632.     MOV    E,M        ; Program below the CCP
  2633.     INX    H
  2634.     MOV    D,M
  2635.     XCHG            ; HL points to the proper vector
  2636.     MVI    L,9        ; Point to record error vector
  2637.     LXI    D,VECTBL    ; Exchange with our vector table
  2638.     MVI    A,4        ; 4 bytes to swap
  2639.  
  2640. SWAPLP:    MOV    B,M        ; Load byte from HL
  2641.     XCHG
  2642.     MOV    C,M        ; Load byte from DE
  2643.     MOV    M,B        ; Save byte from HL
  2644.     XCHG
  2645.     MOV    M,C        ; Save byte from DE
  2646.     INX    H        ; Increment exchange pointers
  2647.     INX    D
  2648.     DCR    A        ; Counter-1
  2649.     JNZ    SWAPLP        ; Continue swapping
  2650.     RET
  2651. ;.....
  2652. ;
  2653. ; Check CP/M version number. Return carry flag set if pre-CP/M 2.  If
  2654. ; CP/M 2 or later or MP/M (any version), return carry clear.
  2655. ;
  2656. CKVER:    LDA    VERFLG        ; Version Flag
  2657.     CPI    20H        ; CP/M 2.0?
  2658.     RET
  2659. ;.....
  2660. ;
  2661. ; Return point from intercepted BDOS select and bad record errors.
  2662. ;
  2663. DSKERR:    LXI    SP,STACK    ; Get out of BDOS' stack
  2664.     JMP    EXIT        ; And exit back to CCP
  2665. ;.....
  2666. ;
  2667. ;-----------------------------------------------------------------------
  2668. ;             Start of FNAME routine
  2669. ;
  2670. ; Main module
  2671. ;    on entry, DE points to FCB to be filled, HL points to first
  2672. ;        byte of target string, RFCB is 36 bytes long
  2673. ;    on exit, B=disk number (1 for A, etc.) and C=user number
  2674. ;        HL points to terminating character
  2675. ;        A=0 and Z set if error in disk or user numbers
  2676. ;        A=0FFH and NZ if ok
  2677. ;
  2678. MAXDISK    EQU    16        ; Maximum number of disks
  2679. MAXUSER    EQU    31        ; Maximum user number
  2680.  
  2681. FNAME:    PUSH    D        ; Save DE
  2682.     MVI    A,0FFH        ; Set default disk and user
  2683.     STA    DISKNO
  2684.     STA    USERNO
  2685.     MVI    B,36        ; Initialize FCB
  2686.     PUSH    D        ; Save pointer
  2687.     XRA    A        ; A=0
  2688.  
  2689. FNINI:    STAX    D        ; Store zero
  2690.     INX    D        ; Point to next
  2691.     DCR    B        ; Count down
  2692.     JNZ    FNINI
  2693.     POP    D        ; Get pointer back
  2694.     PUSH    H        ; Save pointer
  2695. ;
  2696. ; Scan for colon, comma, or space in string
  2697. ;
  2698. COLON:    MOV    A,M        ; Scan for colon or space
  2699.     INX    H        ; Point to next
  2700.     CPI    ':'        ; Colon found?
  2701.     JZ    COLON1
  2702.     CPI    ','        ; Comma found?
  2703.     JZ    GETF1
  2704.     CPI    ' '+1        ; Delimiter?
  2705.     JC    GETF1
  2706.     JMP    COLON        ; Continue if not EOL
  2707. ;
  2708. COLON1:    POP    H        ; Clear stack
  2709.     MOV    A,M        ; Save possible drive specification
  2710.     CALL    CAPS        ; Capitalize
  2711.     CPI    'A'        ; Digit if less than "A"
  2712.     JC    USERCK        ; Process user number
  2713.     SUI    'A'        ; Change from ASCII to binary
  2714.     CPI    MAXDISK        ; Within bounds?
  2715.     JC    SVDISK
  2716. ;
  2717. ERREXIT:XRA    A        ; Error indicator
  2718.     POP    D        ; Restore DE
  2719.     RET
  2720. ;.....
  2721. ;
  2722. ; Log in specified disk
  2723. ;
  2724. SVDISK:    INR    A        ; Adjust to 1 for "A"
  2725.     STA    DISKNO        ; Save flag
  2726.     INX    H        ; Point to next character
  2727. ;
  2728. ; Check for user
  2729. ;
  2730. USERCK:    MOV    A,M        ; Get possible user #
  2731.     CPI    ':'        ; No user number
  2732.     JZ    GETFILE
  2733.     CPI    '?'        ; All user numbers?
  2734.     JNZ    USERC1
  2735.     STA    USERNO        ; Set value
  2736.     INX    H        ; Point to after
  2737.     MOV    A,M        ; Must be colon
  2738.     CPI    ':'
  2739.     JZ    GETFILE
  2740.     JMP    ERREXIT        ; Fatal error if not colon after ?
  2741.  
  2742. USERC1:    XRA    A        ; Zero user number
  2743.     MOV    B,A        ; B = A for user number
  2744.  
  2745. USRLOOP:MOV    A,M        ; Get digit
  2746.     INX    H        ; Point to next
  2747.     CPI    ':'        ; Done?
  2748.     JZ    USRDN
  2749.     SUI    '0'        ; Convert to binary
  2750.     JC    ERREXIT        ; User number error?
  2751.     CPI    10
  2752.     JNC    ERREXIT
  2753.     MOV    C,A        ; Next digit in C
  2754.     MOV    A,B        ; Old number in A
  2755.     ADD    A        ; *2
  2756.     ADD    A        ; *4
  2757.     ADD    B        ; *5
  2758.     ADD    A        ; *10
  2759.     ADD    C        ; *10+new digit
  2760.     MOV    B,A        ; Result in B
  2761.     JMP    USRLOOP
  2762.  
  2763. USRDN:    MOV    A,B        ; Get newer user number
  2764.     CPI    MAXUSER+1    ; Within range?
  2765.     JNC    ERREXIT
  2766.     STA    USERNO        ; Save in flag
  2767.     JMP    GETFILE
  2768. ;
  2769. ; Extract file name
  2770. ;
  2771. GETF1:    POP    H        ; Get pointer to byte
  2772. ;
  2773. GETFILE:MOV    A,M        ; Pointing to colon?
  2774.     CPI    ':'
  2775.     JNZ    GFILE1
  2776.     INX    H        ; Skip over colon
  2777.  
  2778. GFILE1:    MOV    A,M        ; Get next character
  2779.     CPI    ','        ; Delimiter?
  2780.     JZ    GFQUES
  2781.     CPI    ' '+1        ; Not a delimiter?
  2782.     JNC    GFILE2
  2783.  
  2784. GFQUES:    INX    D        ; Fill with ???
  2785.     MVI    B,11        ; 11 bytes
  2786.     MVI    A,'?'
  2787.  
  2788. GFFILL:    STAX    D        ; Put?
  2789.     INX    D        ; Point to next
  2790.     DCR    B        ; Count down
  2791.     JNZ    GFFILL
  2792.  
  2793. FNDONE:    LDA    DISKNO        ; Get disk number
  2794.     MOV    B,A        ; In 'B'
  2795.     LDA    USERNO        ; Get user number
  2796.     MOV    C,A        ; In 'C'
  2797.     POP    D        ; Restore registers
  2798.     MVI    A,0FFH        ; No error
  2799.     ORA    A        ; Set flags
  2800.     RET
  2801. ;
  2802. ; Get file name fields
  2803. ;
  2804. GFILE2:    MVI    B,8        ; At most, 8 byte filename
  2805.     CALL    SCANF        ; Scan and fill
  2806.     MVI    B,3        ; At most, 3 byte filetype
  2807.     MOV    A,M        ; Get delimiter
  2808.     CPI    '.'        ; Filename ending in "."?
  2809.     JNZ    GFILE3
  2810.     INX    H        ; Point to character after "."
  2811.     CALL    SCANF        ; Scan and fill
  2812.     JMP    FNDONE        ; Done, return to "args"
  2813.  
  2814. GFILE3:    CALL    SCANF4        ; Fill with spaces
  2815.     JMP    FNDONE
  2816. ;
  2817. ; Scanner routine
  2818. ;
  2819. SCANF:    CALL    DELCK        ; Check for delimiter
  2820.     JZ    SCANF4        ; Fill with spaces if found
  2821.     INX    D        ; Next byte in filename
  2822.     CPI    '*'        ; Question mark fill ?
  2823.     JNZ    SCANF1
  2824.     MVI    A,'?'        ; Place "?"
  2825.     STAX    D
  2826.     JMP    SCANF2
  2827.  
  2828. SCANF1:    STAX    D        ; Place character
  2829.     INX    H        ; Next position
  2830.  
  2831. SCANF2:    DCR    B        ; Count down
  2832.     JNZ    SCANF        ; Continue loop
  2833.  
  2834. SCANF3:    CALL    DELCK        ; Skip to delimiter
  2835.     RZ
  2836.     INX    H        ; Point to next
  2837.     JMP    SCANF3
  2838.  
  2839. SCANF4:    INX    D        ; Next filename or filetype
  2840.     MVI    A,' '        ; Fill with spaces
  2841.     STAX    D
  2842.     DCR    B        ; Count down
  2843.     JNZ    SCANF4
  2844.     RET
  2845. ;.....
  2846. ;
  2847. ; Check character pointed to by HL for a delimiter,
  2848. ; return with Zero flag set if the character is a delimiter
  2849. ;
  2850. DELCK:    MOV    A,M        ; Get the character
  2851.     CALL    CAPS        ; Capitalize
  2852.     ORA    A        ; 0=delimiter
  2853.     RZ
  2854.     CPI    ' '+1        ; Space character+1
  2855.     JC    DELCK1        ; Space character or less
  2856.     CPI    '='
  2857.     RZ
  2858.     CPI    5FH        ; Underscore
  2859.     RZ
  2860.     CPI    '.'
  2861.     RZ
  2862.     CPI    ':'
  2863.     RZ
  2864.     CPI    ';'
  2865.     RZ
  2866.     CPI    ','
  2867.     RZ
  2868.     CPI    '<'
  2869.     RZ
  2870.     CPI    '>'
  2871.     RET
  2872. ;
  2873. DELCK1:    CMP    M        ; Compare with self for OK
  2874.     RET
  2875. ;.....
  2876. ;
  2877. CAPS:    CPI    'a'
  2878.     RC
  2879.     CPI    'z'+1
  2880.     RNC
  2881.     SUI    20H
  2882.     RET
  2883. ;.....
  2884. ;              End of FNAME routine
  2885. ;-----------------------------------------------------------------------
  2886. ;
  2887. ; Subroutines to read library file directory
  2888. ;
  2889. PRTLMEM:LXI    H,ORDER        ; Initialize order table pointer
  2890.     SHLD    NEXTL
  2891.     XRA    A
  2892.     STA    LNCNT
  2893.  
  2894. ENTRYL:    LHLD    LCOUNT        ; Get FCB count
  2895.     DCX    H        ; Decrement it
  2896.     SHLD    LCOUNT
  2897.     MOV    A,H        ; Is this the last file?
  2898.     ORA    L
  2899.     JZ    LBRTST        ; Yes, skip compare
  2900.     PUSH    B
  2901.     CALL    CKABRT        ; Keyboard abort?
  2902.     LHLD    NEXTL
  2903.     MVI    A,11
  2904.     CALL    COMPR        ; This entry match next one?
  2905.     POP    B
  2906.     JNZ    LBRTST        ; No, print it
  2907.     INX    H
  2908.     INX    H        ; Skip, highest extent last in list
  2909.     SHLD    NEXTL
  2910.     JMP    ENTRYL        ; Loop back for next lowest extent
  2911. ;.....
  2912. ;
  2913. ; Exit Library member printing
  2914. ;
  2915. LBEXIT:    LHLD    LMTOTL
  2916.     MOV    A,H
  2917.     ORA    L
  2918.     RZ
  2919.     PUSH    H        ; Save member count
  2920.     XRA    A        ; Get a zero to
  2921.     STA    SUPSPC        ; Suppress leading spaces in totals
  2922.     LDA    LNCNT
  2923.     MVI    L,4        ; If last line is full, don't turn
  2924.     CMP    L        ; Up extra line
  2925.     CNZ    CRLF        ; If partial line, extra line needed
  2926.     LXI    D,CONTM1    ; Print "There are "
  2927.     CALL    PUTS
  2928.     POP    H        ; Get total member count back
  2929.     CALL    DECPRT
  2930.     LXI    D,MFILES    ; Print "Members in "
  2931.     CALL    PUTS
  2932.     LHLD    LBTOTL
  2933.     CALL    DECPRT
  2934.     LXI    D,LIBR
  2935.     JMP    PUTS
  2936. ;
  2937. ; Valid entry obtained - spit it out
  2938. ;
  2939. LBRTST:    MVI    A,1        ; Turn off .ARC/ARK
  2940.     STA    ISARC
  2941.     LHLD    NEXTL        ; Load order table pointer
  2942.     MOV    E,M        ; Low order address
  2943.     INX    H
  2944.     MOV    D,M        ; High order address
  2945.     INX    H
  2946.     SHLD    NEXTL        ; Save updated table pointer
  2947.     LXI    H,8
  2948.     DAD    D
  2949.     CALL    CKLBR
  2950.     JZ    LBRSET
  2951.     CALL    CKARC
  2952.     JNZ    LBRNEX
  2953.     XRA    A
  2954.     STA    ISARC
  2955.  
  2956. LBRSET:    PUSH    D
  2957.     LDA    LNCNT
  2958.     MVI    L,4
  2959.     CMP    L
  2960.     CNZ    CRLF
  2961.     PUSH    PSW        ; Just in case
  2962.     LXI    D,LFMSP1    ; Long Library directory message
  2963.     LDA    ISARC
  2964.     ORA    A
  2965.     JNZ    SARCM1
  2966.     LXI    D,AFMSP1
  2967.  
  2968. SARCM1:    CALL    PUTS        ; Print it
  2969.     POP    PSW        ; Put it back
  2970.     LDA    FCB        ; Load current drive
  2971.     ADI    'A'-1        ; Convert to ASCII
  2972.     CALL    PUTCHR        ; Print it
  2973.     CALL    PUTUSR        ; Print user # after it
  2974.     MVI    A,':'        ; And colon
  2975.     CALL    PUTCHR
  2976.     POP    H
  2977.     PUSH    H
  2978.     MVI    B,8        ; Filename length
  2979.     CALL    PUTSB
  2980.     MVI    A,'.'        ; Period after filename
  2981.     CALL    PUTCHR
  2982.     MVI    B,3        ; 3 characters of filetype
  2983.     CALL    PUTSB
  2984.     CALL    SIZEFL        ; Compute size of library in k
  2985.     XCHG
  2986.     CALL    DECPRT
  2987.     LXI    D,LFMSP3
  2988.     CALL    PUTS
  2989.     POP    H
  2990. ;
  2991. ; Saves the library file name into LBRFCB
  2992. ;
  2993.     LDA    FCB
  2994.     LXI    D,LBRFCB    ; To
  2995.     STAX    D
  2996.     INX    D
  2997.     MVI    B,11        ; Length
  2998.     CALL    MOVE        ; Do the move
  2999.     XCHG
  3000.     MVI    B,25
  3001.  
  3002. CLMFCB:    MVI    M,0
  3003.     INX    H
  3004.     DCR    B
  3005.     JNZ    CLMFCB
  3006.     CALL    SETLDMA
  3007.     LXI    D,LBRFCB    ; Point to file
  3008.     MVI    C,OPEN        ; Get function
  3009.     CALL    CPM        ; Open it
  3010.     MVI    C,READ
  3011.     LXI    D,LBRFCB
  3012.     CALL    CPM
  3013.     CALL    SETFOP
  3014.     LXI    H,LBBUF
  3015.     MOV    A,M
  3016.     ORA    A
  3017.     JZ    CKLDIR        ; Check directory present?
  3018.  
  3019.     LDA    ISARC
  3020.     ORA    A
  3021.     JNZ    BADLBR
  3022.     MOV    A,M
  3023.     CPI    ARCMAR
  3024.     JZ    CKADIR
  3025.  
  3026. BADLBR:    LXI    H,NLBRF
  3027.     LDA    ISARC
  3028.     ORA    A
  3029.     JNZ    NBARC
  3030.     LXI    H,NARCF
  3031.  
  3032. NBARC:    MVI    B,25
  3033.     CALL    PUTSB
  3034. ;
  3035. LMLEXI:    CALL    LBCLOS
  3036. ;
  3037. ; Do next library file
  3038. ;
  3039. LBRNEX:    LHLD    LCOUNT        ; Check count
  3040.     MOV    A,H
  3041.     ORA    L
  3042.     JZ    LBEXIT        ; No more, all done
  3043.     JMP    ENTRYL        ; Else, get next .LBR file
  3044. ;.....
  3045. ;
  3046. ; Close the library file
  3047. ;
  3048. LBCLOS:    LXI    D,LBRFCB
  3049.     MVI    C,CLOSE
  3050.     CALL    CPM
  3051.     RET
  3052. ;.....
  3053. ;
  3054. ; Set the Library file DMA address
  3055. ;
  3056. SETLDMA:CALL    CKVER        ; Set carry if pre-CP/M 2
  3057.     LDA    NEWUSR        ; Get user area for directory
  3058.     MOV    E,A
  3059.     MVI    C,STUSER    ; Get the user function
  3060.     CNC    CPM        ; And set new user number if CP/M 2
  3061.     LXI    D,LBBUF
  3062.     MVI    C,STDMA
  3063.     CALL    CPM
  3064.     RET
  3065. ;.....
  3066. ;
  3067. ; Check to see if there indeed is a LBR file directory
  3068. ;
  3069. CKLDIR:    MVI    B,11        ; Length of file name
  3070.     MVI    A,' '        ; Space
  3071.     INX    H
  3072.  
  3073. CKDLP:    CMP    M
  3074.     JNZ    BADLBR
  3075.     DCR    B
  3076.     INX    H
  3077.     JNZ    CKDLP
  3078. ;
  3079. ; The first entry in the LBR directory is indeed blank.  Now see if the
  3080. ; directory size is > 0
  3081. ;
  3082.     MOV    E,M        ; File starting location low
  3083.     INX    H        ; Must be zero here
  3084.     MOV    A,M        ; File starting location high
  3085.     ORA    E        ; Must be zero here also
  3086.     JNZ    BADLBR
  3087.     INX    H
  3088.     MOV    E,M        ; Get library size low
  3089.     INX    H        ; Point to library size high
  3090.     MOV    D,M        ; Get library size high
  3091.     MOV    A,D
  3092.     ORA    E        ; Library must have some size
  3093.     JZ    BADLBR
  3094.     DCX    D
  3095.     XCHG
  3096.     SHLD    SLFILE
  3097.     LHLD    LBTOTL
  3098.     INX    H
  3099.     SHLD    LBTOTL
  3100.     MVI    A,4
  3101.     STA    LNCNT        ; Reset names per line counter
  3102.     MVI    B,3
  3103.     LXI    H,17
  3104.     DAD    D
  3105.     JMP    LMTEST
  3106.  
  3107. LFMLOP:    LHLD    SLFILE        ; Get next buffer if more
  3108.     MOV    A,L
  3109.     ORA    H
  3110.     JZ    LMLEXI
  3111.     DCX    H
  3112.     SHLD    SLFILE
  3113.     CALL    SETLDMA
  3114.     MVI    C,READ
  3115.     LXI    D,LBRFCB
  3116.     CALL    CPM
  3117.     CALL    SETFOP
  3118.     MVI    B,4        ; Get file count per record
  3119.     LXI    H,LBBUF        ; Get buffer starting address
  3120.  
  3121. LMTEST:    MOV    A,M        ; Get member open flag
  3122.     ORA    A        ; Test for open
  3123.     JZ    PRMNAM
  3124.  
  3125. LMTESA:    LDA    ISARC
  3126.     ORA    A
  3127.     RZ
  3128.     LXI    D,32        ; Member not open get offset
  3129.     DAD    D        ; To next and add it in
  3130.     DCR    B        ; Is buffer empty ?
  3131.     JNZ    LMTEST        ; No so test next entry
  3132.     JMP    LFMLOP        ; Yes, get next buffer
  3133. ;
  3134. PRMNAM:    PUSH    H        ; Print member name and size
  3135.     PUSH    B
  3136.     CALL    CKABRT        ; Keyboard abort?
  3137.     LXI    H,LNCNT
  3138.     MVI    A,4
  3139.     CMP    M
  3140.     JNZ    PRMNA1
  3141.  
  3142.      IF    PRBRDR
  3143.     MVI    A,'*'        ; Load "A" with border character
  3144.     CALL    PUTCHR        ; Print it
  3145.     MVI    A,' '        ;
  3146.     CALL    PUTCHR        ; Space between border and text
  3147.      ENDIF            ; PRBRDR
  3148.  
  3149.     JMP    PRMNA2
  3150.  
  3151. PRMNA1:    CALL    SPACE
  3152.     MVI    A,':'
  3153.     CALL    PUTCHR
  3154.     CALL    SPACE
  3155.  
  3156. PRMNA2:    POP    B
  3157.     POP    H
  3158.     PUSH    H
  3159.     PUSH    B
  3160.     INX    H
  3161.     MVI    B,8        ; Filename length
  3162.     CALL    PUTSB
  3163.     MVI    A,'.'        ; Period after filename
  3164.     CALL    PUTCHR
  3165.     MVI    B,3        ; 3 characters of filetype
  3166.     CALL    PUTSB
  3167.     INX    H
  3168.     INX    H
  3169.     MOV    E,M
  3170.     INX    H
  3171.     MOV    D,M
  3172.     XCHG
  3173. ;
  3174. ; Output the size of the individual file
  3175. ;
  3176.     PUSH    D
  3177.     PUSH    H
  3178.     XCHG
  3179.     LHLD    LLENLOC
  3180.     XCHG
  3181.     DAD    D
  3182.     SHLD    LLENLOC
  3183.     POP    H
  3184. ;
  3185. ; New code added to convert lib members from records to 'k'.  Upon entry
  3186. ; member's size in records is in HL.
  3187. ;
  3188.     LDA    COPFLG        ; File sizes wanted in records?
  3189.     ORA    A
  3190.     JZ    PRMNA3        ; Jump if so
  3191.     LXI    D,7        ; Round up to nearest 1k
  3192.     DAD    D
  3193.     XCHG
  3194.     LXI    H,0
  3195.     MOV    A,E        ; Low byte of record count in A
  3196.     RRC
  3197.     RRC
  3198.     RRC
  3199.     ANI    1FH
  3200.     MOV    E,A        ; And put it back
  3201.     MOV    L,D        ; Get the high byte if any
  3202.     MVI    D,0        ; Clean out the old resting place
  3203.     DAD    H        ; Multiply it by 32 to convert to
  3204.     DAD    H        ; Number of k bytes
  3205.     DAD    H
  3206.     DAD    H
  3207.     DAD    H
  3208.     DAD    D        ; And add in the low byte
  3209.  
  3210. PRMNA3:    POP    D
  3211.     CALL    DECPRT        ; Go print it
  3212.     LDA    FSIZEC        ; Follow with 'k' or 'r'
  3213.     CALL    PUTCHR
  3214. ;
  3215. ; Update library member total and name counter
  3216. ;
  3217.     LHLD    LMTOTL
  3218.     INX    H
  3219.     SHLD    LMTOTL
  3220.     LDA    LNCNT
  3221.     DCR    A
  3222.     STA    LNCNT
  3223.     POP    B
  3224.     POP    H
  3225.     JNZ    LMTESA        ; And go output another file
  3226. ;
  3227. ; Current line full, start a new one
  3228. ;
  3229.     MVI    A,4
  3230.     STA    LNCNT        ; Reset names per line counter
  3231.     CALL    CRLF        ; Space down to next line
  3232.     JMP    LMTESA
  3233. ;.....
  3234. ;
  3235. ; Move characters from "HL" to "DE" length in "B"
  3236. ;
  3237. MOVE:    MOV    A,M        ; Get a character
  3238.     STAX    D        ; Store it
  3239.     INX    H        ; To next "from"
  3240.     INX    D        ; To next "to"
  3241.     DCR    B        ; More?
  3242.     JNZ    MOVE        ; Yes, loop
  3243.     RET            ; No, return
  3244. ;.....
  3245. ;
  3246. ; Archive file subroutines
  3247. ;
  3248. CKADIR:    XRA    A
  3249.     DCR    A
  3250.     STA    GETABL        ; Say buffer is full (first read by lbr test)
  3251.     LHLD    LBTOTL        ; Bump library count total
  3252.     INX    H
  3253.     SHLD    LBTOTL
  3254.     MVI    A,4        ; LDA     MNPL
  3255.     STA    LNCNT        ; Reset names per line counter
  3256.  
  3257. ARCLP:    CALL    GET        ; Get the next character from buffer
  3258.     CPI    ARCMAR        ; Is it archive header marker?
  3259.     JNZ    BADLBR        ; And abort if not
  3260.     CALL    GET        ; Get header version
  3261.     ORA    A        ; If zero, that's logical end of file,
  3262.     JZ    LMLEXI        ; And we're done
  3263.     LXI    D,ANAME        ; Set to fill header buffer
  3264.     MVI    B,HDRSIZ    ; Setup normal header size less file name
  3265.     CPI    1        ; But test if version 1
  3266.     JNZ    GETHD1        ; Skip if not version 1
  3267.     LXI    B,HDRSIZ-4    ; Else, header is 4 bytes less
  3268.  
  3269. GETHD1:    CALL    GET        ; Get header byte
  3270.     STAX    D        ; Store in buffer
  3271.     INX    D
  3272.     DCR    B
  3273.     JNZ    GETHD1        ; Loop for all bytes
  3274.     LXI    H,ARCFIL    ; Prefill dummy arc FCB name with spaces
  3275.     MVI    B,11
  3276.  
  3277. FIXAN:    MVI    M,' '
  3278.     INX    H
  3279.     DCR    B
  3280.     JNZ    FIXAN
  3281.     MVI    B,5        ; Prefill rest of dummy FCB with zero
  3282.  
  3283. FIXAE:    MVI    M,0
  3284.     INX    H
  3285.     DCR    B
  3286.     JNZ    FIXAE
  3287.     LXI    H,ANAME        ; Get pointer to archive header buffer
  3288.     LXI    D,ARCFIL    ; Point to our dummy FCB
  3289.     MVI    B,8        ; Get name length
  3290.  
  3291. MANAME:    MOV    A,M        ; Get character from header
  3292.     INX    H
  3293.     ORA    A
  3294.     JZ    AEDONE        ; Nothing in buffer so we're done
  3295.     CPI    02EH        ; Is the char a point
  3296.     JZ    DAEXT        ; DO FILE EXTENT
  3297.     STAX    D
  3298.     INX    D
  3299.     DCR    B
  3300.     JNZ    MANAME
  3301.  
  3302. DAEXT:    LXI    D,ARCFIL+8    ; Get dummy file extent address
  3303.     MVI    B,3
  3304.     MOV    A,M
  3305.     CPI    2EH
  3306.     JNZ    AELOP
  3307.     INX    H
  3308.  
  3309. AELOP:    MOV    A,M        ; Fill in the file extent
  3310.     ORA    A
  3311.     JZ    AEDONE
  3312.     STAX    D
  3313.     INX    H
  3314.     INX    D
  3315.     DCR    B
  3316.     JNZ    AELOP
  3317.  
  3318. AEDONE:    LXI    H,ASIZE
  3319.     MOV    E,M        ; Fetch BCDE from (HL)
  3320.     INX    H
  3321.     MOV    D,M
  3322.     INX    H
  3323.     MOV    C,M
  3324.     XRA    A        ; Clear flags
  3325.     MOV    A,E        ; Convert file length count in bytes
  3326.     RAL            ; To length in records for output
  3327.     MOV    A,D
  3328.     RAL
  3329.     MOV    E,A
  3330.     MOV    A,C
  3331.     RAL
  3332.     MOV    D,A
  3333.     XCHG
  3334.     SHLD    ARCFIL+13    ; Save file length
  3335.     LXI    H,ARCFIL-1    ; Point to dummy FCB
  3336.     CALL    PRMNAM        ; List the file info
  3337.     LXI    H,ASIZE        ; Get remaining file size
  3338.     MOV    A,M
  3339.     ANI    7FH
  3340.     LHLD    ARCFIL+13    ; Save file length
  3341.     XCHG            ; Save record offset
  3342.     LXI    H,GETABL    ; Point to offset of last byte read
  3343.     ADD    M        ; Add byte offsets
  3344.     CPI    80H        ; Does it overflow current record?
  3345.     JC    NRAD
  3346.     SUI    80H        ; Adjust pointer
  3347.     INX    D        ; Bump record number
  3348.  
  3349. NRAD:    MOV    M,A        ; Update buffer pointer for new position
  3350.     MOV    A,D        ; Check record offset
  3351.     ORA    E
  3352.     JZ    LEXIT        ; Return if none (still in same record)
  3353.     PUSH    D        ; Save record offset
  3354.     LXI    D,LBRFCB
  3355.     MVI    C,RECORD    ; Compute current "random" record no.
  3356.     CALL    CPM        ; (I.e. next sequential record to read)
  3357.     LHLD    LBRFCB+FRN    ; Get result
  3358.     DCX    H        ; Adjust next record to current record
  3359.     POP    D        ; Restore record offset
  3360.     DAD    D        ; Compute new record no.
  3361.     JC    BADLBR        ; If >64k, it's past largest (8 Mb) file
  3362.     SHLD    LBRFCB+FRN    ; Save new record no.
  3363.     MVI    C,READRN    ; Read the random record
  3364.     CALL    GETREC
  3365.     ORA    A
  3366.     JNZ    BADLBR        ; File read error
  3367.     LXI    H,LBRFCB+FCR    ; Point to current record in extent
  3368.     INR    M        ; Bump for subsequent sequential read
  3369.  
  3370. LEXIT:    JMP    ARCLP        ; Loop for next file
  3371. ;.....
  3372. ;
  3373. ; Get next sequential byte from archive file
  3374. ;
  3375. GET:    PUSH    B        ; Save registers
  3376.     PUSH    D
  3377.     PUSH    H
  3378.     LDA    GETABL        ; Point to last byte read
  3379.     INR    A        ; At end of buffer?
  3380.     CPI    80H
  3381.     CNC    GETNXT        ; Yes, read next record and reset pointer
  3382.     STA    GETABL        ; Save new buffer pointer
  3383.     MOV    L,A
  3384.     MVI    H,0
  3385.     LXI    D,LBBUF
  3386.     DAD    D
  3387.     MOV    A,M        ; Fetch byte from there
  3388.     POP    H        ; Restore registers
  3389.     POP    D
  3390.     POP    B
  3391.     RET            ; Return
  3392. ;
  3393. ; Get next sequential record from archive file
  3394. ;
  3395. GETNXT:    MVI    C,READ        ; Setup read-sequential function code
  3396.     CALL    GETREC
  3397.     ORA    A
  3398.     JNZ    RDERR
  3399.     PUSH    PSW
  3400.     XRA    A
  3401.     DCR    A
  3402.     STA    GETABL
  3403.     POP    PSW
  3404.     RET
  3405. ;
  3406. RDERR:    POP    H        ; Strip GETNXT return
  3407.     POP    H        ; Clean up the get stack
  3408.     POP    D
  3409.     POP    B
  3410.     POP    H        ; Strip get calling address
  3411.     JMP    BADLBR        ; Show error
  3412. ;
  3413. ; Get record (sequential or random) from archive file
  3414. ;
  3415. GETREC:    PUSH    H
  3416.     PUSH    B
  3417.     CALL    SETLDMA        ; Set library DMA address
  3418.     LXI    D,LBRFCB    ; Setup FCB address
  3419.     POP    B        ; Restore read function
  3420.     CALL    CPM        ; Do it
  3421.     PUSH    PSW        ; Save read status
  3422.     CALL    SETFOP        ; Reset Print file DMA address
  3423.     POP    PSW        ; Restore read status
  3424.     POP    H        ; Restore buffer pointer
  3425.     RET
  3426. ;.....
  3427. ;
  3428. ; Test file extent for ARC/ARK
  3429. ;
  3430. CKARC:    PUSH    H
  3431.     PUSH    D
  3432.     PUSH    B
  3433.     XCHG
  3434.     LXI    H,ARCTYP
  3435.     MVI    C,2        ; Number for the loop to test
  3436. ;
  3437. CKARL:    LDAX    D
  3438.     ANI    7FH
  3439.     CMP    M
  3440.     JNZ    CKARX
  3441.     INX    H
  3442.     INX    D
  3443.     DCR    C
  3444.     JNZ    CKARL
  3445. ;
  3446. ; The first 2 match now see if C or K for .ARC or .ARK
  3447. ;
  3448.     LDAX    D
  3449.     ANI    7FH
  3450.     CPI    'C'        ; See if "C"
  3451.     JZ    CKARX
  3452.     CPI    'K'        ; See if "K"
  3453.  
  3454. CKARX:    POP    B
  3455.     POP    D
  3456.     POP    H
  3457.     RET
  3458. ;.....
  3459. ;
  3460. ; Test file extent for LBR
  3461. ;
  3462. CKLBR:    PUSH    H
  3463.     PUSH    D
  3464.     PUSH    B
  3465.     XCHG
  3466.     LXI    H,LBRTYP
  3467.     MVI    C,3
  3468.  
  3469. CKLBL:    LDAX    D
  3470.     ANI    7FH
  3471.     CMP    M
  3472.     JNZ    CKLBX
  3473.     INX    H
  3474.     INX    D
  3475.     DCR    C
  3476.     JNZ    CKLBL
  3477.  
  3478. CKLBX:    POP    B
  3479.     POP    D
  3480.     POP    H
  3481.     RET
  3482. ;
  3483. ; TIMEON routine
  3484. ;
  3485. ; Go through a search to see if BYE is active
  3486. ;
  3487.      IF    TIMEON
  3488. TIME:    LHLD    0001H        ; Point to warm boot again
  3489.     DCX    H        ; If BYE active,
  3490.     MOV    D,M        ; Pick up pointer to BYE variables
  3491.     DCX    H        ; (COVECT) followed by "BYE"
  3492.     MOV    E,M
  3493.     LXI    H,15        ; Calculate address of BYE variable
  3494.     DAD    D        ; Where ptr to orig BIOS vector stored
  3495.     MOV    E,M        ; Load that address into DE
  3496.     INX    H        ; If BIOS active, DE now points to
  3497.     MOV    D,M        ; Original BIOS console output vector
  3498.     INX    H        ; Point to BYE signon message
  3499.     MOV    A,M        ; Get letter
  3500.     ANI    05FH        ; Convert to upper case if needed
  3501.     CPI    'B'        ; Try to match "BYE"
  3502.     RNZ            ; Out if BYE not active
  3503.     INX    H
  3504.     MOV    A,M
  3505.     ANI    05FH        ; Convert to u-case if needed
  3506.     CPI    'Y'
  3507.     RNZ
  3508.     INX    H
  3509.     MOV    A,M
  3510.     ANI    05FH        ; Convert to u-case if needed
  3511.     CPI    'E'
  3512.     RNZ
  3513.  
  3514.     LXI    D,6        ; Bye running, point to RTCBUF
  3515.     DAD    D
  3516.     MOV    E,M        ; Get RTCBUF address
  3517.     INX    H        ; And copy
  3518.     MOV    D,M        ; In DE
  3519.     XCHG            ; Put in HL
  3520.     LXI    D,7        ; Offset to
  3521.     DAD    D        ; Time-on-system byte
  3522.     MOV    A,M        ; Load TOS byte
  3523.     LXI    H,TONMS1    ; Where to store in ASCII
  3524.     CALL    DEC8        ; Convert binary to ASCII
  3525.     LXI    D,TONMSG
  3526.     CALL    PUTS        ; Print the message
  3527.     RET            ; And return
  3528. ;.....
  3529. ;
  3530. ; DEC8 will convert an 8 bit binary number in A to 3 ASCII
  3531. ; bytes. HL points to the MSB location where the ASCII bytes
  3532. ; will be stored. Leading zeros are suppressed, store spaces
  3533. ; in your buffer before calling.
  3534. ;
  3535. DEC8:    PUSH    B
  3536.     PUSH    D
  3537.     MVI    E,0        ; Leading zero flag
  3538.     MVI    D,100
  3539.  
  3540. DEC81:    MVI    C,'0'-1
  3541.  
  3542. DEC82:    INR    C
  3543.     SUB    D        ; 100 or 10
  3544.     JNC    DEC82        ; Still +
  3545.     ADD    D        ; Now add it back
  3546.     MOV    B,A        ; Remainder
  3547.     MOV    A,C        ; Get 100/10
  3548.     CPI    '1'        ; Zero?
  3549.     JNC    DEC83        ; Yes
  3550.     MOV    A,E        ; Check flag
  3551.     ORA    A        ; Reset?
  3552.     MOV    A,C        ; Restore byte
  3553.     JZ    DEC84        ; Leading zeros are skipped
  3554.  
  3555. DEC83:    MOV    M,A        ; Store in buffer
  3556.     INX    H        ; Increment storage location
  3557.     MVI    E,0FFH        ; Set zero flag
  3558.  
  3559. DEC84:    MOV    A,D
  3560.     SUI    90        ; 100 to 10
  3561.     MOV    D,A
  3562.     MOV    A,B        ; Remainder
  3563.     JNC    DEC81        ; Do it again
  3564.     ADI    '0'        ; Make ASCII
  3565.     MOV    M,A        ; And store it
  3566.     POP    D
  3567.     POP    B
  3568.     RET
  3569.  
  3570. TONMSG:    DB    13,10,'Minutes on System: '
  3571. TONMS1:    DB    '    ',0
  3572.      ENDIF            ; TIMEON
  3573. ;
  3574. ;              end of TIMEON routine
  3575. ;-----------------------------------------------------------------------
  3576. ;               help routine
  3577. ;
  3578. ; Help menu if ? is typed, using a fancy ZCMD or ZCPR system
  3579. ;
  3580.      IF    WHEEL
  3581. HELPME:    LXI    D,OPTMSG    ; Point at message
  3582.     CALL    SHOW
  3583.     LDA    WHLOC        ; Check wheel
  3584.     ORA    A        ; If set, help out poor SYSOP
  3585.     JZ    EXIT3        ; No - exit
  3586.     LXI    D,SYSOP1    ; Point at message
  3587.     CALL    SHOW
  3588.     JMP    EXIT3        ; And exit
  3589. ;
  3590. ; This menu of options will appear to normal users (WHEEL not set).
  3591. ; Modify the menus to accommodate your system requirements.
  3592. ;
  3593. OPTMSG:    DB    13,10,13,10
  3594.     DB    '  Available Options (start with a  $  or  /  or'
  3595.     DB    '  [ character):',13,10,13,10
  3596.     DB    '  A - all user areas               N - no page pause'
  3597.     DB    ' [more]',13,10
  3598.     DB    '  C - file sizes in records        Q - show non-$ARCHived'
  3599.     DB    ' files',13,10
  3600.     DB    '  D - all drives                   T - order files'
  3601.     DB    ' by EXT type',13,10
  3602.     DB    '  H - Current area to highest      V - show version'
  3603.     DB    ' number',13,10
  3604.     DB    '  L - list LBR/ARC/ARK members     X - aux. format'
  3605.     DB    ' (horiz/vert)',13,10,13,10
  3606.     DB    '  Example - to list all drives and user areas,'
  3607.     DB    ' no pauses:',13,10,13,10
  3608.     DB    '                     B0>SD $AND <ret>'
  3609.     DB    13,10,13,10,0
  3610. ;
  3611. ; This menu of options appears only when the WHEEL is set.
  3612. ;
  3613. SYSOP1:    DB    13,10,'  * * * Special SYSOP Options (WHEEL SET) * * *'
  3614.     DB    13,10,13,10
  3615.     DB    '  F - file output (DISK.DIR)       R - reset disk'
  3616.     DB    ' system',13,10
  3617.     DB    '  O - show $SYS files only         S - include'
  3618.     DB    ' $SYS files',13,10
  3619.     DB    '  P - printer output',13,10,13,10
  3620.     DB    0
  3621.      ENDIF            ; WHEEL
  3622. ;
  3623. ; Help menu if ? is typed, NOT using any fancy ZCMD or ZCPR system
  3624. ;
  3625.      IF    NOT WHEEL
  3626. HELPME:    LXI    D,OPTMSG    ; Point at message
  3627.     CALL    SHOW
  3628.     JMP    EXIT3        ; And exit
  3629. ;
  3630. OPTMSG:    DB    13,10,13,10
  3631.     DB    '  Available Options (start with a  $  or  /  or'
  3632.     DB    '  [  character):',13,10
  3633.     DB    13,10
  3634.     DB    '  A - all user areas               P - printer output'
  3635.     DB    13,10
  3636.     DB    '  C - file sizes in records        Q - show non $ARChived'
  3637.     DB    ' files',13,10
  3638.     DB    '  D - all drives                   R - reset disk system'
  3639.     DB    13,10
  3640.     DB    '  F - file output (DISK.DIR)       S - include $SYS'
  3641.     DB    ' files',13,10
  3642.     DB    '  H - Current area to highest      T - order files'
  3643.     DB    ' by EXT type',13,10
  3644.     DB    '  L - list LBR/ARC/ARK members     V - show version'
  3645.     DB    ' number',13,10
  3646.     DB    '  N - no page pause [more]         X - aux. format'
  3647.     DB    ' (horiz/vert)',13,10
  3648.     DB    '  O - show $SYS files only',13,10,13,10
  3649.     DB    '  Example - to list all drives and user areas,'
  3650.     DB    ' no pauses:',13,10,13,10
  3651.     DB    '                     B0>SD $AND <ret>'
  3652.     DB    13,10,13,10,13,10,13,10,13,10,13,10,13,10
  3653.     DB    0
  3654.      ENDIF            ; NOT WHEEL
  3655. ;
  3656. ; Messages and Error statements
  3657. ;
  3658. CKMS1:    DB    13,10,'++ ABORTED ++',0
  3659. CKMS2:    DB    8,' ',8,0
  3660. DRUMSG:    DB    'Drive/User',0
  3661. EOSMSG:    DB    '[more] ','$'
  3662. MORERA:    DB    13,'        ',13,'$'
  3663. ERRMS1:    DB    ' '
  3664. ERRMS2:    DB    'Error',0
  3665. ERRTAG:    DB    ' ->',0
  3666. NOFLM:    DB    '>> No detectable file(s) on ',0
  3667. NOFMS1:    DB    13,10,13,10,' ',0
  3668. NOFMS2:    DB    '  ',0
  3669. NOFMS3:    DB    ':  ',0
  3670. SOHFLG:    DB    0
  3671. TOTMS1:    DB    13,10,'         Drive ',0
  3672. TOTMS4:    DB    '/',0
  3673. TOTMS5:    DB    'k  ',0
  3674. TOTMS6:    DB    ' Files: ',0
  3675. TOTMS7:    DB    ' Free: ',0
  3676. TOTMS8:    DB    'k ',0
  3677.  
  3678.      IF    PRBRDR
  3679. CONTM1:    DB    13,10,'** There are ',0
  3680. MFILES:    DB    ' member files in ',0
  3681. LIBR:    DB    ' library(s) and/or archive(s) **',0
  3682. AFMSP1:    DB    13,10,'** Archive directory for ',0
  3683. LFMSP1:    DB    13,10,'** Library directory for ',0
  3684. LFMSP3:    DB    'k'
  3685.     DB    ' **'
  3686.     DB    13,10,0
  3687.      ENDIF            ; PRBRDR
  3688.  
  3689.      IF    NOT PRBRDR
  3690. CONTM1:    DB    13,10,'There are ',0
  3691. MFILES:    DB    ' member files in ',0
  3692. LIBR:    DB    ' library(s) and/or archive(s)',0
  3693. AFMSP1:    DB    13,10,'Archive directory for ',0
  3694. LFMSP1:    DB    13,10,'Library directory for ',0
  3695. LFMSP3:    DB    'k'
  3696.     DB    13,10,0
  3697.      ENDIF            ; Not PRBRDR
  3698.  
  3699. NLBRF:    DB    '++ Not a library file ++',13,10
  3700. NARCF:    DB    '++ Not an archive file ++',13,10
  3701. LBRTYP:    DB    'LBR'
  3702. ARCTYP:    DB    'AR'        ; We only test the first 2 in the loop.
  3703.                 ; The C or K are tested separately.
  3704. ;
  3705. ; Permanently initialized data area
  3706. ;
  3707. VECTBL:    DW    DSKERR        ; BDOS record error intercept vector
  3708.     DW    DSKERR        ; BDOS select error intercept vector
  3709. ;
  3710. ; End of code that must be stored on disk in the .COM file
  3711. ;
  3712. ; Data area reinitialized by code when SD is run or rerun
  3713. ;
  3714. DATA0    EQU    $        ; Start of area to initialize
  3715.  
  3716. OTBL    EQU    $        ; Mark start of option table
  3717. VFLAG:    DS    1
  3718. AOPFLG:    DS    1
  3719. COPFLG:    DS    1
  3720. DOPFLG:    DS    1
  3721. FOPFLG:    DS    1
  3722. HOPFLG:    DS    1
  3723. LOPFLG:    DS    1
  3724. NOPFLG:    DS    1
  3725. OOPFLG:    DS    1
  3726. POPFLG:    DS    1
  3727. QOPFLG:    DS    1
  3728. ROPFLG:    DS    1
  3729. SOPFLG:    DS    1
  3730. TOPFLG:    DS    1
  3731. VOPFLG:    DS    1
  3732. XOPFLG:    DS    1
  3733.  
  3734. OEND    EQU    $        ; End of option table
  3735. ;
  3736. ; End of option lookup table
  3737. ;
  3738. BUFPNT:    DS    2        ; Next location in output buffer
  3739. BUFCNT:    DS    1        ; Number of bytes left in output buffer
  3740. OUTFCB:    DS    1+8+3        ; User number, filename, and filetype
  3741. ;
  3742. ; Beginning of area reinitialized to zero each time SD.COM is run
  3743. ;
  3744.     DS    21        ; Rest of DISK.DIR FCB
  3745. DISKNO:    DS    1        ; Disk number
  3746. USERNO:    DS    1        ; User number
  3747. OPNFLG:    DS    1        ; File open flag
  3748. DRVFLG:    DS    1        ; D option check for prior drive specificaton
  3749. FNDFLG:    DS    1        ; Files Matched Flag
  3750. BYEACT:    DS    1        ; BYE Active Flag
  3751.  
  3752. LINCNT:    DS    1        ; # lines printed on screen
  3753. LLENLOC:DS    2        ; Running total of .LBR length
  3754. LMTOTL:    DS    2
  3755. LBTOTL:    DS    2
  3756. LNCNT:    DS    1
  3757. LCOUNT:    DS    2
  3758. NEXTL:    DS    2
  3759. SLFILE:    DS    2
  3760. LINES:    DS    1        ; Number of lines to be printed
  3761. FIRSTT:    DS    1        ; First time flag for version number
  3762. ISARC:    DS    1
  3763. ;
  3764. ; Uninitialized data area
  3765. ;
  3766. BASUSR:    DS    1        ; Copy of original directory user #
  3767. BLKMAX:    DS    2        ; Highest block # on drive
  3768. BLKMSK:    DS    1        ; Records/block - 1
  3769. BLKSHF:    DS    1        ; Number shifts to mult by sec/blk
  3770. COUNT:    DS    2        ; Entry count
  3771. DIRMAX:    DS    2        ; Highest file # in directory
  3772. FILERC:    DS    2        ; File size in records
  3773. FREEBY:    DS    2        ; Number of k left on dir. drive
  3774. FSIZEC:    DS    1        ; File size character ('k' or 'r')
  3775. GAP:    DS    2        ; Sort routine storage
  3776. I:    DS    2        ; Sort routine storage
  3777. J:    DS    2        ; Sort routine storage
  3778. JG:    DS    2        ; Sort routine storage
  3779. LZFLG:    DS    1        ; 0 when printing leading zeros
  3780. MAXUSR:    DS    1        ; Max user # for drive
  3781. NEWUSR:    DS    1        ; User # selected by "$U" option
  3782. NEXTT:    DS    2        ; Next table entry
  3783. OLDDSK:    DS    1        ; Currently logged-in drive
  3784. OLDUSR:    DS    1        ; User number upon invocation
  3785. SCOUNT:    DS    2        ; # to sort
  3786. SUPSPC:    DS    1        ; Leading space flag
  3787. TBLOC:    DS    2        ; Start of name table
  3788. TOTFIL:    DS    2        ; Total number of files
  3789. TOTSIZ:    DS    2        ; Total size of all files
  3790. USRNR:    DS    1        ; User number
  3791. VERFLG:    DS    1        ; CP/M version number (0=pre-CP/M 2)
  3792. ZRDFLG:    DS    1        ; ZRDOS version number
  3793.  
  3794. DATA1    EQU    $        ; End of area to initialize
  3795.  
  3796.      IF    NDIRS
  3797. NAMADR:    DS    2        ; Named Directory Buffer Address
  3798. NUMDIR:    DS    1        ; Number of entries
  3799. CURDIR:    DS    1        ; NDR Check counter
  3800.      ENDIF            ; NDIRS
  3801.  
  3802.      IF    SHOPUB
  3803. PUBDRV:    DS    1        ; Storage for Public Drive byte
  3804. PUBUSR:    DS    1        ; "    "    "      User     "
  3805.      ENDIF            ; SHOPUB
  3806.  
  3807. GETABL:    DS    1
  3808. LBRFCB:    DS    36
  3809. LBBUF:    DS    128
  3810.  
  3811. ANAME:    DS    13
  3812. ASIZE:    DS    14
  3813. ARCFIL:    DS    16
  3814.  
  3815. NEWPTR:    DS    2        ; Start of second table
  3816. XPOINT:    DS    2
  3817. JUMPER:    DS    2        ; Increment for second table to
  3818.  
  3819. OUTBUF:    DS    128        ; Output file buffer
  3820. ;
  3821. ; BDOS equates
  3822. ;
  3823. BDOS    EQU    0005H        ; Entry Point for BDOS calls
  3824. FCB    EQU    005CH        ; Default FCB Address
  3825. TBUF    EQU    0080H        ; Default DMA Address
  3826.  
  3827. RDCON    EQU    1        ; Console input
  3828. WRCON    EQU    2        ; Console output
  3829. LIST    EQU    5        ; List output
  3830. PRINT    EQU    9        ; Print string
  3831. CONST    EQU    11        ; Get console status
  3832. CPMVER    EQU    12        ; Return CP/M version
  3833. RESET    EQU    13        ; Reset disk system
  3834. SELDSK    EQU    14        ; Select disk
  3835. OPEN    EQU    15        ; Open file
  3836. CLOSE    EQU    16        ; Close file
  3837. SRCHF    EQU    17        ; Search for first
  3838. SRCHN    EQU    18        ; Search for next
  3839. READ    EQU    20        ; Read sequential
  3840. WRITE    EQU    21        ; Write sequential
  3841. MAKE    EQU    22        ; Make file
  3842. CURDSK    EQU    25        ; Return current disk
  3843. STDMA    EQU    26        ; Set DMA Address
  3844. DSKALL    EQU    27        ; Get address of allocation vector
  3845. DSKPAR    EQU    31        ; Get address of disk parameters
  3846. STUSER    EQU    32        ; Set/get user number
  3847.  
  3848.      IF    ZRDOS
  3849. ZRDVER    EQU    48        ; Return version (ZRDOS)
  3850. SETWBT    EQU    50        ; Set warm boot trap (ZRDOS)
  3851. RESWBT    EQU    52        ; Reset warm boot trap (ZRDOS)
  3852.      ENDIF            ; ZRDOS
  3853.  
  3854.     DS    60        ; Stack area
  3855. STACK:    DS    2        ; Old stack pointer
  3856.  
  3857. ORDER    EQU    $        ; Order table starts here
  3858.  
  3859.     END
  3860.