home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / dirutl / wherfind.lbr / WHERFIND.MQC / WHERFIND.MAC
Text File  |  1986-07-13  |  58KB  |  2,015 lines

  1.     .Z80
  2.     TITLE    WHERFIND Version 3.01 - 07/02/86 - 20:07
  3.     PAGE
  4. ;************************************************************************
  5. ;*                                    *
  6. ;*  Written    by G.B. Shaffstall, SYSOP Lakewood RCP/M        *
  7. ;*                                      *
  8. ;*  Modified for use with ZCPR3 by R.T. Hilgert SYSOP XEROX RCP/M    *
  9. ;*                                      *
  10. ;*  Modified  for two column output,  pagination, combined WHEREIS    *
  11. ;*   with FIND and added extensive annotation  7/2/86  by        *
  12. ;*   Gil Shultz Sysop the REALM - (313) 349-3408  Novi Michigan.    *
  13. ;*                                    *
  14. ;*  This  program  allows  full wildcard searches of the directories    *
  15. ;*  and ALL LIBRARY files on a CP/M system  for  a  requested  file,    *
  16. ;*  starting  on  drive A, user 0, working its way up and across all    *
  17. ;*  drive/user areas until a trapped I/O error causes exit or  CTL-C    *
  18. ;*  or  CTL-X  is  hit  at  the  keyboard.  Optionally, the user can    *
  19. ;*  specify a single drive to be searched  by  including  the  drive    *
  20. ;*  name as a prefix to the search file.  This is based on SD-81, so    *
  21. ;*  credit is given to the MANY people that have worked on it in the    *
  22. ;*  past.                                *
  23. ;*                                      *
  24. ;*  Entering WHEREIS<cr> will display a brief help message.        *
  25. ;*                                      *
  26. ;*  The USER AREA PATCH  TABLE  is  the  same  as  in  SD  with  two    *
  27. ;*  exceptions:  [1] if 0FFH is placed in a user location that drive    *
  28. ;*  will be skipped, and [2] If using with ZCPR all  entries  should    *
  29. ;*  be  set to 0FFH in the source file, as the ZCPR conditional code    *
  30. ;*  will re-load the table on entry based  on  ZCPR's  MAXDRIVE  and    *
  31. ;*  MAXUSER values.                            *
  32. ;*                                      *
  33. ;*  Users of this program with hard disks will want to set the QUIET    *
  34. ;*  equate to 0 to provide the message "Searching <dn>: User  <num>"    *
  35. ;*  so  the  user will know that the program is still running.  With    *
  36. ;*  any other value, the message "+++ NO  FILE  ON  <dn>:"  will  be    *
  37. ;*  printed as the program switches drives and no files are found.    *
  38. ;*                                      *
  39. ;*  There is no page pause capability, but unless something like    *
  40. ;*      WHEREIS *.*    is used this should be no problem.        *
  41. ;*                                    *
  42. ;************************************************************************
  43.  
  44.     SUBTTL    EQUATES
  45.     PAGE
  46. USRMSK    EQU    00001111B    ; Mask for maximum user number
  47. CR    EQU    0DH        ; carriage return character
  48. LF    EQU    0AH        ; line feed character
  49. ESC    EQU    1BH        ; escape character
  50. YES    EQU    0FFH        ; true
  51. NO    EQU    0        ; NOT YES
  52.  
  53. ;************************************************************************
  54. ;*                                    *
  55. ;*    If running with ZCPR3 with NDRS ste ZCPR3 true to display    *
  56. ;*    named directory information.                    *
  57. ;*                                    *
  58. ZCPR3    EQU    NO    ; YES                        *
  59. ;*                                    *
  60. ;*    Set the following equate true if using ZCPR to limit Drive    *
  61. ;*    user number searching.                        *
  62. ;*                                    *
  63. ZCPR    EQU    YES    ; YES                        *
  64. ;*                                    *
  65. ;*                                    *
  66. ;*    Set one and only one of the following equates true for the    *
  67. ;*    program you want. The programs generated will be        *
  68. ;*                                    *
  69. ;*        WHEREIS    or     FIND                    *
  70. ;*                                    *
  71. WHERE    EQU    NO        ; set to yes for WHEREIS        *
  72. FIND    EQU    YES        ; set to yes for FIND            *
  73. ;*                                    *
  74. ;*    Set the following equate true for two column output.        *
  75. ;*                                    *
  76. TWOCOL    EQU    YES        ; set to yes for two columns.        *
  77. ;*                                    *
  78. ;*    Set the following equate true for pagination.            *
  79. ;*                                    *
  80. PAGNAT    EQU    YES        ; set true for pagination.        *
  81. ;*                                    *
  82. ;************************************************************************
  83.  
  84. QFLAG    EQU    0    ; set to <> 0 for silent mode
  85. MDRIV    EQU    03DH    ; ZCPR Max drive storage location
  86. MUSR    EQU    03FH    ; ZCPR Max user storage location
  87. RDCHR    EQU    1    ; read char from console
  88. WRCHR    EQU    2    ; write char to console
  89. PRINTS    EQU    9    ; print string
  90. CONST    EQU    11    ; check cons stat
  91. RESET    EQU    13    ; reset disk system
  92. SELDSK    EQU    14    ; select    disk
  93. OPEN    EQU    15    ; 0ffh=not found
  94. CLOSE    EQU    16    ;   "    "
  95. SEARCH    EQU    17    ;   "    "
  96. NEXT    EQU    18    ;   "    "
  97. READ    EQU    20    ; not 0 = eof
  98. WRITE    EQU    21    ; not 0 = disk full
  99. MAKE    EQU    22    ; 0ffh =    directory full
  100. CURDSK    EQU    25    ; get currently logged disk name
  101. SETDMA    EQU    26    ; set current dma
  102. GALLOC    EQU    27    ; get address of allocation vector
  103. CURDPB    EQU    31    ; get current disk parameters
  104. CURUSR    EQU    32    ; get currently logged user number (2.x only)
  105. BASE    EQU    0    ; default to 0
  106. FCB    EQU    BASE+5CH ; force relocatable code to 5CH
  107. BDOS    EQU    BASE+5     ; force relocatable code to 05H
  108.  
  109.     COND    ZCPR3
  110.     PAGE
  111.     .8080
  112.     INCLUDE    Z3BASE.LIB
  113.     .Z80
  114.     PAGE
  115.     ENDC    ; ZCPR3
  116.  
  117. ;************************************************************************
  118. ;*                                    *
  119. ;*             BEGIN EXECUTABLE PROGRAM CODE            *
  120. ;*                                    *
  121. ;************************************************************************
  122.  
  123.     JP    START            ; goto entry point
  124.     SUBTTL    DRIVE / USER TABLE
  125.     PAGE
  126.  
  127. ;************************************************************************
  128. ;*                                    *
  129. ;*            Drive code/user area lookup table        *
  130. ;*                                    *
  131. ;*    Note  that  the  lodrv-hidrv  table  is included here fully     *
  132. ;*    configured. For your own use, you should change the maximum     *
  133. ;*    user  areas as  appropriate for  each drive on your system.      *
  134. ;*    Note that there are only 16 user areas available under cp/m     *
  135. ;*    2,  so  the  highest  legal user area you can specify is 15     *
  136. ;*    (range 0-15 = 16 areas).  The program will convert anything     *
  137. ;*    over  15 into mod 15.  Enter an 0ffh to cause a drive to be     *
  138. ;*    skipped on search. NOTE: set to 0FFH for ZCPR use.        *
  139. ;*                                    *
  140. ;************************************************************************
  141.  
  142. LODRV:                ; mark beginning of drive/user table
  143.  
  144.     DEFB    0FFH        ; maximum user area for drive A
  145.     DEFB    0FFH        ;   "      "    "    "     "    B
  146.     DEFB    0FFH        ;   "      "    "    "     "    C
  147.     DEFB    0FFH        ;---"-----"----"----"----"----D
  148.     DEFB    0FFH        ;   "      "    "    "     "    E
  149.     DEFB    0FFH        ;   "      "    "    "     "    F
  150.     DEFB    0FFH        ;   "      "    "    "     "    G
  151.     DEFB    0FFH        ;---"-----"----"----"----"----H
  152.     DEFB    0FFH        ;   "      "    "    "     "    I
  153.     DEFB    0FFH        ;   "      "    "    "     "    J
  154.     DEFB    0FFH        ;   "      "    "    "     "    K
  155.     DEFB    0FFH        ;---"-----"----"----"----"----L
  156.     DEFB    0FFH        ;   "      "    "    "     "    M
  157.     DEFB    0FFH        ;   "      "    "    "     "    N
  158.     DEFB    0FFH        ;   "      "    "    "     "    O
  159.     DEFB    0FFH        ;---"-----"----"----"----"----P
  160.  
  161. HIDRV:                ; mark end of drive/user table
  162.     SUBTTL    LOCAL STORAGE, MESSAGES ETC.
  163.     PAGE
  164. QUIET:    DEFB    QFLAG        ; patch to non zero for quiet mode
  165.  
  166. BDOLOC:    DEFW 0
  167.  
  168.     COND    WHERE
  169. VERNAME:
  170.     DEFB    CR,LF,'WHEREIS v 3.01 for the REALM - 07/02/86 - 20:07',CR,LF
  171.     DEFB    CR,LF,'A Total Wild-Card FILE including Libraries.',CR,LF
  172.     DEFB    CR,LF,'Syntax to search all drives and user areas'
  173.     DEFB    CR,LF,'is WHEREIS <Filename.type>',CR,LF
  174.     DEFB    CR,LF,'Examples:'
  175.     DEFB    CR,LF,'A0>WHEREIS *.AQ6     or    A0>WHEREIS MBOOT*.*',CR,LF
  176.     DEFB    CR,LF,'To search a single drive and all user areas'
  177.     DEFB    CR,LF,'Use WHEREIS <Drivename:Filename.type>',CR,LF
  178.     DEFB    CR,LF,'Examples:'
  179.     DEFB    CR,LF,'A0>WHEREIS B:MDM???.*  or  A0>WHEREIS D:KP*.*',CR,LF
  180.     DEFB    CR,LF,'Pagination is '
  181.     COND    PAGNAT
  182.     DEFB    'on'
  183.     ENDC
  184.     COND    (NOT PAGNAT AND 0FFH)
  185.     DEFB    'off'
  186.     ENDC
  187.     DEFB    CR,LF,'Two column output is '
  188.     COND    TWOCOL
  189.     DEFB    'on'
  190.     ENDC
  191.     COND    (NOT TWOCOL AND 0FFH)
  192.     DEFB    'off'
  193.     ENDC
  194.     DEFB    CR,LF,CR,LF+80H
  195.  
  196. PROCES:    DEFB    CR,LF,'  Searching '
  197. PROC1:    DEFB    ' : User',' '+80H
  198. SIGNON:    DEFB    CR,LF,'WHEREIS v 3.01 for the REALM - 07/02/86 - 20:07',CR,LF
  199.     DEFB    ' ^X or ^C to abort',CR,LF,CR,LF+80H
  200.     ENDC
  201.  
  202.     COND    FIND
  203.  
  204. VERNAME:
  205.     DEFB    CR,LF,'FIND v 3.01 for the REALM - 07/03/86 - 20:07',CR,LF
  206.     DEFB    CR,LF,'A Total Wild-Card FILE Search Utility.',CR,LF
  207.     DEFB    CR,LF,'Syntax to search all drives and user areas'
  208.     DEFB    CR,LF,'is FIND <Filename.type>',CR,LF
  209.     DEFB    CR,LF,'Examples:'
  210.     DEFB    CR,LF,'A0>FIND *.AQ6     or    A0>FIND MBOOT*.*',CR,LF
  211.     DEFB    CR,LF,'To search a single drive and all user areas'
  212.     DEFB    CR,LF,'Use FIND <Drivename:Filename.type>',CR,LF
  213.     DEFB    CR,LF,'Examples:'
  214.     DEFB    CR,LF,'A0>FIND B:MDM???.*  or  A0>FIND D:KP*.*',CR,LF
  215.     DEFB    CR,LF,'Pagination is '
  216.     COND    PAGNAT
  217.     DEFB    'on'
  218.     ENDC
  219.     COND    (NOT PAGNAT AND 0FFH)
  220.     DEFB    'off'
  221.     ENDC
  222.     DEFB    CR,LF,'Two column output is '
  223.     COND    TWOCOL
  224.     DEFB    'on'
  225.     ENDC
  226.     COND    (NOT TWOCOL AND 0FFH)
  227.     DEFB    'off'
  228.     ENDC
  229.     DEFB    CR,LF,CR,LF+80H
  230. PROCES:    DEFB    CR,LF,'  Searching '
  231. PROC1:    DEFB    ' : User',' '+80H
  232. SIGNON:    DEFB    CR,LF,'FIND v 3.01 for the REALM - 07/03/86 - 20:07',CR,LF
  233.     DEFB    ' ^X or ^C to abort',CR,LF,CR,LF,+80H
  234.     ENDC
  235.  
  236. ;********************************
  237. ;*                *
  238. ;*    Initialized data area    *
  239. ;*                *
  240. ;********************************
  241.  
  242.     COND    WHERE
  243. LBRTYP:    DEFB    'LBR'
  244.     ENDC
  245. VERBAD:    DEFB    '+++ Needs CP/M 2.0 or Newer to RU','N'+80H
  246. DREMSG:    DEFB    '+++ Driv','e' OR 80H
  247. ERRMS1:    DEFB    ' '
  248. ERRMS2:    DEFB    'Erro','r' OR 80H
  249. USRMSG:    DEFB    'User ','#' OR 80H
  250. NOFMS1:    DEFB    '+++ NO FILE ON '
  251. NOFMS2:    DEFB    ' ',':' OR 80H
  252.  
  253. VECTBL:    DEFW    DSKERR        ; bdos sector error intercept vector
  254.     DEFW    DSKERR        ; bdos select error intercept vector
  255. DOPFLG:    DEFB    0
  256.     SUBTTL    UNITIALIZED STORAGE AREA
  257.     PAGE
  258. BASUSR:    DEFB    0        ; dupe of original dir. user # to search
  259. BLKMAX:    DEFW    0        ; highest block # on drive
  260. BLKMSK:    DEFB    0        ; sec/blk - 1
  261. BLKSHF:    DEFB    0        ; # shifts to mult by sec/blk
  262. COUNT:    DEFW    0        ; entry count
  263. DIRMAX:    DEFW    0        ; highest file # in directory
  264. GAP:    DEFW    0        ; sort routine storage
  265. HITRAP:    DEFB    0        ; highlight trap (previously typed char)
  266. I:    DEFW    0        ; sort routine storage
  267. J:    DEFW    0        ; sort routine storage
  268. JG:    DEFW    0        ; sort routine storage
  269. LZFLG:    DEFB    0        ; 0 when printing leading zeros
  270. MAXUSR:    DEFB    0        ; max user # for drive from lookup table
  271. NEWUSR:    DEFB    0        ; contains user # selected by "$u" option
  272. NEXTT:    DEFW    0        ; next table entry
  273. OLDDSK:    DEFB    0        ; holder for currently logged-in drive
  274. OLDUSR:    DEFB    0        ; contains user number upon invocation
  275. SCOUNT:    DEFW    0        ; # to sort
  276. SUPSPC:    DEFB    0        ; leading space flag for decimal routine
  277. TBLOC:    DEFW    0        ; pointer to start of name table
  278. TEMP:    DEFW    0        ; save dir entry
  279. VERFLG:    DEFB    0        ; cp/m version number (0=pre-cp/m 2)
  280. FNDFLG:    DEFB    0        ; file found flag
  281. LLENLOC:
  282.     DEFW    0        ; running total of .lbr length
  283. LCOUNT:    DEFW    0
  284. NEXTL:    DEFW    0
  285. SLFILE:    DEFW    0
  286. SEARN:    DEFS    11        ; holding area for search name
  287.     COND    WHERE
  288. LBRFCB:    DEFS    36        ; library FCB
  289. LBBUF:    DEFS    80H        ; library buffer
  290.     ENDC
  291.     SUBTTL    MAIN PROGRAM CODE
  292.     PAGE
  293.  
  294. ;****************************************
  295. ;*                    *
  296. ;*    Main program starts here.    *
  297. ;*                    *
  298. ;****************************************
  299.  
  300. START:    LD    HL,0        ; clear HL
  301.     ADD    HL,SP        ; hl=old stack
  302.     LD    (STACK),HL    ; save it
  303.     LD    SP,STACK    ; get new stack
  304.  
  305.     COND    ZCPR
  306.     LD    HL,LODRV    ; point at drive user table
  307.     PUSH    HL        ; and get it to DE
  308.     POP    DE        ; got it
  309.     INC    DE        ; up bye one (setup for LDIR)
  310.     LD    A,(MUSR)    ; get maximum user
  311. ;    DEC    A        ; adjust it
  312.     LD    (LODRV),A    ; stuff maximum user in table
  313.     LD    B,0        ; clear hi byte
  314.     LD    A,(MDRIV)    ; get maximum drive
  315.     OR    A        ; test for drive A
  316.     JP    Z,NOMOVE    ; yep, only drive so move nothing
  317.     DEC    A        ; adjust drive number (gfs)
  318.     JP    Z,NOMOVE    ; nope, exit
  319.     LD    C,A        ; set up counter
  320.     DEFB    0EDH,0B0H    ; LDIR
  321. NOMOVE:
  322.     ENDC
  323.  
  324.     XOR    A        ; get a zero
  325.     LD    (FNDFLG),A    ; clear file found flag
  326.     LD    (NEWUSR),A    ; make new user = 0
  327.     LD    (BASUSR),A    ; duplicate it if multi-disk mode
  328.     LD    C,12        ; get and save the cp/m version #
  329.     CALL    BDOS        ; get version from system
  330.     LD    A,L        ; get it
  331.     LD    (VERFLG),A    ; and save it
  332.     LD    (DOPFLG),A    ; do not allow multi-drive yet
  333.     CP    20H        ; set carry if cp/m 1.4
  334.     JP    C,VERERR    ; exit on earlier than 2.0
  335.     LD    HL,FCB+1    ; point to name
  336.     LD    A,(HL)        ; any specified?
  337.     CP    ' '        ; test
  338.     JP    Z,NONERR    ; so print help info
  339.     PUSH    HL        ; save fcb address
  340.     LD    DE,SEARN    ; point to search name holding area
  341.     LD    B,11        ; size of file name, type
  342.     CALL    MOVE        ; move it
  343.     POP    HL        ; restore fcb address
  344.     LD    E,0FFH        ; get current user number
  345.     LD    C,CURUSR    ; set it up
  346.     CALL    CPM        ; and do it
  347.     LD    (OLDUSR),A    ; initialize startup user number
  348.  
  349. CLNON:    LD    C,CURDSK    ; set it up
  350.     CALL    CPM        ; get current disk nr
  351.     LD    (OLDDSK),A    ; save for reset if needed
  352.     LD    HL,FCB        ; set up pointer
  353.     LD    A,(HL)        ; get drive name for directory search
  354.     OR    A        ; any specified?
  355.     JP    NZ,START2    ; yes skip next routine
  356.     XOR    A
  357.     LD    (DOPFLG),A    ; ok let multi-drive in
  358.     LD    A,1        ; otherwise, get disk "a"
  359. START2:    LD    (HL),A        ; put the absolute drive code in
  360.                 ; ..directory fcb
  361. CKREST:    LD    DE,SIGNON    ; point to hello message
  362.     CALL    PRINT        ; and say hello
  363.     LD    A,(DOPFLG)    ; get flag
  364.     OR    A        ; and test it
  365.     CALL    Z,SWAPEM    ; swap bdos error vector tables
  366.  
  367. ;********************************************************
  368. ;*                            *
  369. ;*    Validate drive code and user area numbers    *
  370. ;*    from the drive table.                *
  371. ;*                            *
  372. ;********************************************************
  373.  
  374. NOOPT:    LD    DE,DREMSG    ; get the drive/user error message
  375.     PUSH    DE        ; save on stack
  376.     LD    A,(FCB)        ; get directory drive code
  377.     DEC    A        ; normalize to range of 0-15
  378.     CP    HIDRV-LODRV    ; compare with maximum drives on-line
  379.     JP    NC,ERXIT    ; take drive error exit if out of range
  380.     LD    HL,USRMSG    ; switch to user # error message
  381.     EX    (SP),HL
  382.     LD    E,A        ; use drive code as index into table
  383.     LD    D,0        ; clear hi byte so offset is ok
  384.  
  385. USRCK:    LD    HL,LODRV    ; point to base of drive/user table
  386.     ADD    HL,DE        ; add offset into table
  387.     LD    A,(HL)        ; get the maximum user # for this drive
  388.     CP    0FFH        ; check for skip drive
  389.     JP    Z,ERXIT        ; exit if not wanted
  390.  
  391. USRCK2:    AND    USRMSK        ; make sure its in range 0 - 15 (gfs)
  392.     LD    (MAXUSR),A    ; save it for later
  393.     LD    HL,NEWUSR    ; point to the directory user area
  394.     CP    (HL)        ; compare it with the maximum
  395.     JP    C,ERXIT        ; take error exit if user number illegal
  396.     POP    DE        ; destroy error message pointer
  397.     LD    HL,FCB+1    ; point to name
  398.  
  399. ;********************************************************
  400. ;*                            *
  401. ;*    Make fcb all '?' to search for every file    *
  402. ;*                            *
  403. ;********************************************************
  404.  
  405. WCD:    LD    B,11        ; fn+ft count
  406. QLOOP:    LD    (HL),'?'    ; store '?' in fcb
  407.     INC    HL        ; bump FCB pointer
  408.     DEC    B        ; count off
  409.     JP    NZ,QLOOP    ; and loop till finished
  410.  
  411. GOTFCB:    LD    A,'?'        ; force wild extent
  412.     LD    (FCB+12),A
  413.     CALL    SETSRC        ; set dma for bdos media change check
  414.     LD    HL,FCB        ; point to fcb drive code for directory
  415.     LD    E,(HL)        ; get the drive code out of the fcb
  416.     DEC    E        ; normalize drive code for select
  417.     LD    C,SELDSK    ; select the directory drive to retrieve
  418.     CALL    CPM        ; ..the proper allocation vector
  419.     LD    C,CURDPB    ; it is 2.x or mp/m...request dpb
  420.     CALL    BDOS        ; put the system to work
  421.     INC    HL        ; bump pointer to
  422.     INC    HL        ; block shift location
  423.     LD    A,(HL)        ; get block shift
  424.     LD    (BLKSHF),A    ; save block shift factor
  425.     INC    HL        ; bump to block mask
  426.     LD    A,(HL)        ; get block mask
  427.     LD    (BLKMSK),A    ; get it saved
  428.     INC    HL        ; bump pointer to max block
  429.     INC    HL        ; there
  430.     LD    E,(HL)        ; get max block #
  431.     INC    HL        ; bump pointer
  432.     LD    D,(HL)        ; get mask
  433.     EX    DE,HL        ; swap pointers
  434.     LD    (BLKMAX),HL    ; save it
  435.     EX    DE,HL        ; and back, we saved it
  436.     INC    HL        ; bump pointer
  437.     LD    E,(HL)        ; get directory size
  438.     INC    HL        ; and bump again
  439.     LD    D,(HL)        ; get size
  440.     EX    DE,HL        ; swap pointers
  441.     LD    (DIRMAX),HL    ; save max # of entries in directory
  442.  
  443. ;************************************************************************
  444. ;*                                    *
  445. ;*    Reenter here on subsequent passes while in the all-users mode    *
  446. ;*                                    *
  447. ;************************************************************************
  448.  
  449. SETTBL:    LD    A,(QUIET)    ; check if in quiet mode
  450.     OR    A        ; test
  451.     JP    NZ,SETTB1    ; yes so skip printout
  452.     LD    A,(FCB)        ; get drive
  453.     ADD    A,'A'-1        ; ASCIFY it
  454.     LD    (PROC1),A    ; and stuff it away
  455.     LD    DE,PROCES    ; show the user what area is being
  456.     CALL    PRINT        ; worked on.
  457.     CALL    TYPUSR        ; now display user number
  458.  
  459.     COND    ZCPR3
  460.     LD    A,' '        ; get a space
  461.     CALL    TYPE        ; and send it
  462.     CALL    SHONDR        ; now show drive
  463.     ENDC    ; ZCPR3
  464.  
  465. SETTB1:    LD    HL,(DIRMAX)    ; get directory maximum again
  466.     INC    HL        ; directory size is dirmax+1
  467.     ADD    HL,HL        ; double directory size
  468.     LD    DE,ORDER    ; to get size of order table
  469.     ADD    HL,DE        ; allocate order table
  470.     LD    (TBLOC),HL    ; name tbl begins where order tbl ends
  471.     LD    (NEXTT),HL    ; save in both places
  472.     EX    DE,HL        ; swap pointers
  473.     LD    HL,(BDOS+1)    ; make sure we have room to continue
  474.     LD    A,E        ; get low
  475.     SUB    L        ; and subtract
  476.     LD    A,D        ; now get hi
  477.     SBC    A,H        ; and subtract, carry = ok
  478.     JP    NC,OUTMEM    ; tell not enough memory
  479.     LD    A,(NEWUSR)    ; get user area for directory
  480.     LD    E,A        ; save it
  481.     LD    C,CURUSR    ; get the user function
  482.     CALL    CPM        ; ..and set new user number
  483.  
  484. ;************************************************
  485. ;*                        *
  486. ;*    Look up the fcb in the directory    *
  487. ;*                        *
  488. ;************************************************
  489.  
  490.     LD    A,'?'        ; get a question mark
  491.     LD    HL,FCB+12    ; set pointer
  492.     LD    (HL),A        ; match all extents
  493.     INC    HL        ; up pointer
  494.     LD    (HL),A        ; match all s1 bytes
  495.     INC    HL        ; up pointer
  496.     LD    (HL),A        ; match all s2 bytes
  497.     LD    HL,0        ; now clear match counter
  498.     LD    (COUNT),HL    ; initialize match counter
  499.     CALL    SETSRC        ; set dma for directory search
  500.     LD    C,SEARCH    ; get 'SEARCH FIRST' function
  501.     JP    LOOK        ; ..and go search for 1st match
  502.  
  503. ;****************************************
  504. ;*                    *
  505. ;*    Read more directory entries    *
  506. ;*                    *
  507. ;****************************************
  508.  
  509. MORDIR:    LD    C,NEXT        ; search next
  510.  
  511. LOOK:    LD    DE,FCB        ; point to FCB
  512.     CALL    CPM        ; read directory entry
  513.     INC    A        ; check for end (0ffh)
  514.     JP    Z,SPRINT    ; if no more, sort & print what we have
  515.  
  516. ;****************************************
  517. ;*                    *
  518. ;*    Point to directory entry    *
  519. ;*                    *
  520. ;****************************************
  521.  
  522. SOME:    DEC    A        ; undo previous 'INR A'
  523.     AND    3        ; make modulus 4
  524.     ADD    A,A        ; multiply...
  525.     ADD    A,A        ; ..by 32 because
  526.     ADD    A,A        ; ..each    directory
  527.     ADD    A,A        ; ..entry is 32
  528.     ADD    A,A        ; ..bytes long
  529.     LD    HL,BASE+81H    ; point to buffer (skip to fn/ft)
  530.     ADD    A,L        ; point to entry
  531.     ADD    A,9        ; point to system byte
  532.     LD    L,A        ; save (can't carry to h)
  533.     LD    A,(HL)        ; get system byte
  534.     OR    A        ; check bit 7
  535.     JP    M,MORDIR    ; skip that file
  536.  
  537. SYSFOK:    LD    A,L        ; go back now
  538.     SUB    10        ; back to user number (alloc flag)
  539.     LD    L,A        ; hl points to entry now
  540.     LD    A,(NEWUSR)    ; get current user
  541.     CP    (HL)        ; test it
  542.     JP    NZ,MORDIR    ; ignore if different
  543.     INC    HL
  544.  
  545. ;********************************
  546. ;*                *
  547. ;*    Move entry to table    *
  548. ;*                *
  549. ;********************************
  550.  
  551.     EX    DE,HL        ; entry to de
  552.     LD    HL,(NEXTT)    ; next table entry to hl
  553.     LD    B,11        ; entry length (name, type, extent)
  554.  
  555. TMOVE:    LD    A,(DE)        ; get entry char
  556.     AND    7FH        ; remove attributes
  557.     LD    (HL),A        ; store in table
  558.     INC    DE        ; bump pointers
  559.     INC    HL        ; both of them
  560.     DEC    B        ; more?
  561.     JP    NZ,TMOVE    ; yep, move it
  562.     INC    DE        ; de->> s1
  563.     INC    DE        ; de->> s2
  564.     LD    A,(DE)        ; get s2 byte, overflow=int(extents/32)
  565.     PUSH    HL        ; save hl
  566.     LD    L,A        ; set up 16-bit multiply
  567.     LD    H,0        ; clear hi
  568.     LD    B,5        ; set up shift factor
  569.     CALL    SHLL        ; hl is now # of overflow extents
  570.     DEC    DE        ; de->> s1
  571.     DEC    DE        ; de->> extent
  572.     LD    A,(DE)        ; get extent
  573.     ADD    A,L        ; add it in
  574.     LD    L,A        ; save in L
  575.     LD    A,H        ; get HI
  576.     ADC    A,0        ; add in carry
  577.     LD    H,A        ; hl now has total extents
  578.     LD    B,7        ; get shift factor
  579.     CALL    SHLL        ; hl now has total sectors less last ext
  580.     INC    DE        ; de->> s1
  581.     INC    DE        ; de->> s2
  582.     INC    DE        ; point to sector count
  583.     LD    A,(DE)        ; get it
  584.     ADD    A,L        ; add it
  585.     LD    L,A        ; save in L
  586.     LD    A,H        ; get HI
  587.     ADC    A,0        ; and add in carry
  588.     LD    H,A        ; hl now has total sectors
  589.     EX    (SP),HL        ; do some fancy shuffling
  590.     EX    DE,HL        ; swap pointers
  591.     EX    (SP),HL        ; and swap with top of stack
  592.     EX    DE,HL        ; swap them back
  593.     LD    (HL),D        ; get value
  594.     INC    HL        ; and bump pointer
  595.     LD    (HL),E        ; now stuff it
  596.     POP    DE        ; all back to normal...
  597.     INC    HL        ; up pointer
  598.     LD    (NEXTT),HL    ; save updated table address
  599.     EX    DE,HL        ; swap it
  600.     LD    HL,(COUNT)    ; bump the # of matches made
  601.     INC    HL        ; up counter
  602.     LD    (COUNT),HL    ; and save count
  603.     LD    HL,13        ; size of next entry
  604.     ADD    HL,DE        ; add offset
  605.     EX    DE,HL        ; future nextt is in de
  606.     LD    HL,(BDOS+1)    ; pick up tpa end
  607.     LD    A,E        ; get low
  608.     SUB    L        ; compare nextt-tpa end
  609.     LD    A,D        ; now get hi
  610.     SBC    A,H        ; now set flag
  611.     JP    C,MORDIR    ; if tpa end > nextt, loop back for more
  612.  
  613. OUTMEM:    CALL    ERXIT        ; exit if directory too large
  614.     DEFB    'Memor','y' OR 80H
  615.  
  616. ;************************************************
  617. ;*                        *
  618. ;*    Shift    HL left by n bits (in B)    *
  619. ;*                        *
  620. ;************************************************
  621.  
  622. SHLL:    ADD    HL,HL        ; shift left by one
  623.     DEC    B        ; count down shift count
  624.     RET    Z        ; return if finished
  625.     JP    SHLL        ; else shift again
  626.  
  627. ;****************
  628. ;*        *
  629. ;*    Sort    *
  630. ;*        *
  631. ;****************
  632.  
  633. SPRINT:    CALL    SETFOP        ; return to file output dma & user #
  634.     LD    HL,(COUNT)    ; get file name count
  635.     LD    A,L        ; do 16 bit test
  636.     OR    H        ; any found?
  637.     JP    Z,PRTOTL    ; exit if no files found
  638.     PUSH    HL        ; save file count
  639.     LD    (SUPSPC),A    ; enable leading zero suppression
  640.  
  641. ;****************************************
  642. ;*                    *
  643. ;*    Initialize the order table    *
  644. ;*                    *
  645. ;****************************************
  646.  
  647.     LD    HL,(TBLOC)    ; get start of name table
  648.     EX    DE,HL        ; into de
  649.     LD    HL,ORDER    ; point to order table
  650.     LD    BC,13        ; entry length
  651.  
  652. BLDORD:    LD    (HL),E        ; save low order address
  653.     INC    HL        ; bump pointer
  654.     LD    (HL),D        ; save high order address
  655.     INC    HL        ; bump pointer
  656.     EX    DE,HL        ; table address to hl
  657.     ADD    HL,BC        ; point to next entry
  658.     EX    DE,HL        ; swap
  659.     EX    (SP),HL        ; save tbl address, fetch loop counter
  660.     DEC    HL        ; count down loop
  661.     LD    A,L        ; do 16 bit test
  662.     OR    H        ; more?
  663.     EX    (SP),HL        ; (restore tbl address, save counter)
  664.     JP    NZ,BLDORD    ; yes, go do another one
  665.     POP    HL        ; clean loop counter off stack
  666.     LD    HL,(COUNT)    ; get count
  667.     LD    (SCOUNT),HL    ; save as # to sort
  668.     DEC    HL        ; only 1 entry?
  669.     LD    A,L        ; do test
  670.     OR    H        ; for all 16 bits
  671.     JP    Z,NOOUT        ; yes, so skip sort
  672.  
  673. ;********************************************************
  674. ;*                            *
  675. ;*    This sort routine is adapted from Software    *
  676. ;*    Tools by Kernigan and Plaugher.            *
  677. ;*                            *
  678. ;********************************************************
  679.  
  680. SORT:    LD    HL,(SCOUNT)    ; number of entries
  681. L0:    OR    A        ; clear carry
  682.     LD    A,H        ; gap=gap/2
  683.     RRA
  684.     LD    H,A
  685.     LD    A,L
  686.     RRA
  687.     LD    L,A
  688.     OR    H        ; is it zero?
  689.     JP    Z,NOOUT        ; then none left
  690.     LD    A,L        ; make gap odd
  691.     OR    1
  692.     LD    L,A
  693.     LD    (GAP),HL
  694.     INC    HL        ; i=gap+1
  695.  
  696. L2:    LD    (I),HL
  697.     EX    DE,HL
  698.     LD    HL,(GAP)
  699.     LD    A,E        ; j=i-gap
  700.     SUB    L
  701.     LD    L,A
  702.     LD    A,D
  703.     SBC    A,H
  704.     LD    H,A
  705.  
  706. L3:    LD    (J),HL
  707.     EX    DE,HL
  708.     LD    HL,(GAP)    ; jg=j+gap
  709.     ADD    HL,DE
  710.     LD    (JG),HL
  711.     LD    A,13        ; compare 13 characters    {sfk}
  712.     CALL    COMPARE        ; compare (j) and (jg)
  713.     JP    P,L5        ; if a(j)<=a(jg)
  714.     LD    HL,(J)
  715.     EX    DE,HL
  716.     LD    HL,(JG)
  717.     CALL    SWAP        ; exchange a(j) and a(jg)
  718.     LD    HL,(J)        ; j=j-gap
  719.     EX    DE,HL
  720.     LD    HL,(GAP)
  721.     LD    A,E
  722.     SUB    L
  723.     LD    L,A
  724.     LD    A,D
  725.     SBC    A,H
  726.     LD    H,A
  727.     JP    M,L5        ; if j>0 goto l3
  728.     OR    L        ; check for zero
  729.     JP    Z,L5
  730.     JP    L3
  731.  
  732. L5:    LD    HL,(SCOUNT)    ; for later
  733.     EX    DE,HL
  734.     LD    HL,(I)        ; i=i+1
  735.     INC    HL
  736.     LD    A,E        ; if i<=n goto l2
  737.     SUB    L
  738.     LD    A,D
  739.     SBC    A,H
  740.     JP    P,L2
  741.     LD    HL,(GAP)
  742.     JP    L0
  743.  
  744. ;********************************************************
  745. ;*                            *
  746. ;*    Sort is all done - print entries that compare    *
  747. ;*                            *
  748. ;********************************************************
  749.  
  750. NOOUT:    LD    HL,(COUNT)    ; get count
  751.     LD    (LCOUNT),HL    ; and save it
  752.     LD    HL,ORDER    ; initialize order table pointer
  753.     LD    (NEXTL),HL    ; get pointer
  754.     LD    (NEXTT),HL    ; and save it
  755.  
  756. ;********************************************************
  757. ;*                            *
  758. ;*    Output the directory files we've matched.    *
  759. ;*                            *
  760. ;********************************************************
  761.  
  762. ENTRY:    LD    HL,(COUNT)    ; get count
  763.     DEC    HL        ; dock file count
  764.     LD    (COUNT),HL    ; and save it
  765.     LD    A,H        ; is this the last file?
  766.     OR    L        ; test all 16 bits
  767.     JP    Z,OKPRNT    ; if count=0, last file so skip compare
  768.  
  769. ;****************************************************************
  770. ;*                                *
  771. ;*    Compare each entry to make sure that it isn't part    *
  772. ;*    of a multiple extent file. Go only when we have the    *
  773. ;*    last extent of the file.                *
  774. ;*                                *
  775. ;****************************************************************
  776.  
  777.     CALL    CKABRT        ; check for abort code from keyboard
  778.     LD    HL,(NEXTT)    ; get pointer
  779.     LD    A,11        ; set up length of filename.ext
  780.     CALL    COMPR        ; does this entry match next one?
  781.     JP    NZ,OKPRNT    ; no, print it
  782.     INC    HL        ; bump pointer
  783.     INC    HL        ; skip since highest extent last in list
  784.     LD    (NEXTT),HL    ; save it
  785.     JP    ENTRY        ; loop back for next lowest extent
  786.  
  787. OKPRNT:    LD    HL,(NEXTT)    ; get order table pointer
  788.     LD    E,(HL)        ; get low order address
  789.     INC    HL        ; bump pointer
  790.     LD    D,(HL)        ; get high order address
  791.     INC    HL        ; bump pointer
  792.     LD    (NEXTT),HL    ; save updated table pointer
  793.     EX    DE,HL        ; table entry to hl
  794.  
  795. ;************************************************
  796. ;*                        *
  797. ;*    Put in user & drive printout here.    *
  798. ;*                        *
  799. ;************************************************
  800.  
  801.     PUSH    HL        ; save pointer on stack
  802.     LD    HL,(TFILES)    ; get count
  803.     INC    HL        ; bump it up by one
  804.     LD    (TFILES),HL    ; and update count
  805.     POP    HL        ; restore original pointer
  806.     CALL    COMPS        ; match what we are looking for ?
  807.     JP    NZ,OKEXIT    ; no, so don't print it
  808.     PUSH    HL        ; save pointer on stack
  809.     LD    HL,(TMATCH)    ; get match count
  810.     INC    HL        ; add one to it
  811.     LD    (TMATCH),HL    ; and save match count
  812.     POP    HL        ; restore pointer from stack
  813.  
  814.     CALL    GCRLF        ; space it out
  815.     LD    A,(FCB)        ; ..precede new line with drive name
  816.     ADD    A,'A'-1        ; ascify it
  817.     CALL    TYPE        ; and display drive
  818.     CALL    TYPUSR        ; now display user number
  819.     LD    A,':'        ; tag header with a colon and a space
  820.     CALL    TYPE        ; ..and exit back to entry
  821.  
  822.     COND    ZCPR3
  823.     CALL    SHONDR
  824.     ENDC    ; ZCPR3
  825.  
  826.     LD    A,' '        ; get a space
  827.     CALL    TYPE        ; and display it
  828.     LD    B,8        ; file name length
  829.     CALL    TYPEIT        ; type filename
  830.     LD    A,'.'        ; period after fn
  831.     CALL    TYPE        ; display dot
  832.     LD    B,3        ; display 3 characters of filetype
  833.     CALL    TYPEIT        ; now display file extension
  834.     LD    D,(HL)        ; now calculate size of file
  835.     INC    HL        ; bump pointer
  836.     LD    E,(HL)        ; size in de (sectors)
  837.     LD    A,(BLKMSK)    ; get block mask
  838.     PUSH    AF        ; save on stack
  839.     ADD    A,E        ; add to sectors
  840.     LD    E,A        ; and put back in E
  841.     LD    A,D        ; now get hi
  842.     ADC    A,0        ; add in carry bit
  843.     LD    D,A        ; and put it back
  844.     POP    AF        ; restore block mask
  845.     CPL            ; and test it
  846.     AND    E        ; mask it
  847.     LD    E,A        ; size in de (sectors rounded to blocksize)
  848.     LD    B,3        ; set up shift factor
  849.  
  850. SHRR:    LD    A,D        ; get value
  851.     OR    A        ; clear carry
  852.     RRA            ; rotate (shift) i
  853.     LD    D,A        ; put it back
  854.     LD    A,E        ; get HI
  855.     RRA            ; shift it with carry
  856.     LD    E,A        ; and put it back
  857.     DEC    B        ; test to see if shift is finished
  858.     JP    NZ,SHRR        ; no, do it again
  859.     EX    DE,HL        ; get file size
  860.  
  861. ;********************************************************
  862. ;*                            *
  863. ;*    Output the size of the individual file.        *
  864. ;*                            *
  865. ;********************************************************
  866.  
  867.     CALL    DECPRT        ; ..go print it
  868.     LD    A,'K'        ; ..and follow with k size
  869.     CALL    TYPE        ; terminate file size with a 'K'
  870.     LD    A,0FFH        ; get flag value
  871.     LD    (FNDFLG),A    ; set file found flag
  872.  
  873. ;********************************************************
  874. ;*                            *
  875. ;*    One file output - test to see if we have to    *
  876. ;*    output another one.                *
  877. ;*                            *
  878. ;********************************************************
  879.  
  880. OKEXIT:    LD    HL,(COUNT)    ; get current file counter and test it
  881.     LD    A,H        ; take hi byte
  882.     OR    L        ; and test with low
  883.     JP    Z,PRTOTL    ; if no more files exit to summary output
  884.     JP    ENTRY        ; else do next
  885.  
  886. ;********************************************************
  887. ;*                            *
  888. ;*    Compute the size of the file/library and     *
  889. ;*    update our summary datum. This has been changed    *
  890. ;*    into a    subroutine so that both the file size    *
  891. ;*    computation and a library size (when printing    *
  892. ;*    out library members) can be computed in K.    *
  893. ;*                            *
  894. ;********************************************************
  895.  
  896. DOIT:    LD    E,(HL)        ; get extent #
  897.     LD    D,0        ; clear hi
  898.     INC    HL        ; up pointer
  899.     LD    A,(HL)        ; get sector count of last extent
  900.     EX    DE,HL
  901.     ADD    HL,HL        ; # of extents times 16k
  902.     ADD    HL,HL
  903.     ADD    HL,HL
  904.     ADD    HL,HL
  905.     EX    DE,HL        ; save in de
  906.     LD    HL,BLKMSK    ; get block mask
  907.     ADD    A,(HL)        ; round last extent to block size
  908.     RRCA            ; adjust it
  909.     RRCA            ; convert from sectors to k
  910.     RRCA            ; adjusted
  911.     AND    1FH        ; now mask it
  912.     LD    L,A        ; add to total k
  913.     LD    H,0        ; clear hi
  914.     ADD    HL,DE        ; add it in
  915.     LD    A,(BLKMSK)    ; get sectors/blk-1
  916.     RRCA            ; adjust it
  917.     RRCA            ; convert to k/blk
  918.     RRCA            ; adjusted
  919.     AND    1FH        ; now mask it
  920.     CPL            ; use to finish rounding
  921.     AND    L        ; mask it
  922.     LD    L,A        ; and all finished
  923.     RET            ; return, were finished
  924.  
  925. ;****************************************************************
  926. ;*                                *
  927. ;*    Print HL in decimal with leading zero suppression.    *
  928. ;*                                *
  929. ;****************************************************************
  930.  
  931. DECPRT:    XOR    A        ; clear leading zero flag
  932.     LD    (LZFLG),A    ; flag cleared
  933.     LD    DE,-1000    ; print 1000'S DIGIT
  934.     CALL    DIGIT        ; print digit
  935.     LD    DE,-100        ; etc.
  936.     CALL    DIGIT        ; print digit
  937.     LD    DE,-10        ; print 100's digit
  938.     CALL    DIGIT        ; do it
  939.     LD    A,'0'        ; get 1'S DIGIT
  940.     ADD    A,L        ; add just it
  941.     JP    TYPE        ; and print it
  942.  
  943. DIGIT:    LD    B,'0'        ; start off with ascii 0
  944.  
  945. DIGLP:    PUSH    HL        ; save current remainder
  946.     ADD    HL,DE        ; subtract
  947.     JP    NC,DIGEX    ; quit on overflow
  948.     POP    AF        ; throw away remainder
  949.     INC    B        ; bump digit
  950.     JP    DIGLP        ; loop back
  951.  
  952. DIGEX:    POP    HL        ; restore pointer
  953.     LD    A,B        ; get data
  954.     CP    '0'        ; zero digit?
  955.     JP    NZ,DIGNZ    ; no, type it
  956.     LD    A,(LZFLG)    ; leading zero?
  957.     OR    A        ; test it
  958.     LD    A,'0'        ; get ascii zero
  959.     JP    NZ,TYPE        ; print digit
  960.     LD    A,(SUPSPC)    ; get space suppression flag
  961.     OR    A        ; see if printing file totals
  962.     RET    Z        ; yes, don't give leading spaces
  963.     LD    A,' '        ; get a space
  964.     JP    TYPE        ; leading zero...print space
  965.  
  966. DIGNZ:    LD    (LZFLG),A    ; leading zero flag so next zero prints
  967.     JP    TYPE        ; and print digit
  968.  
  969. ;****************************************
  970. ;*                    *
  971. ;*    Now check for libraries        *
  972. ;*                    *
  973. ;****************************************
  974.  
  975.     COND    WHERE
  976. PRTOTL:    LD    HL,(LCOUNT)    ; how many files did we see?
  977.     LD    A,H        ; get hi byte
  978.     OR    L        ; and do 16 bit test with low
  979.     CALL    NZ,PRTLMEM    ; skip the .lbr check if none found
  980.     XOR    A        ; get a zero to...
  981.     LD    (SUPSPC),A    ; suppress leading spaces in totals
  982.     ENDC
  983.     COND    FIND
  984. PRTOTL:    
  985.     XOR    A        ;get a zero to...
  986.     LD    (SUPSPC),A        ;suppress leading spaces in totals
  987.     ENDC
  988.  
  989. ;****************************************************************
  990. ;*                                *
  991. ;*    Directory for one user area completed.  If 'ALL USERS'    *
  992. ;*    option is selected, then go do another directory on    *
  993. ;*    the next user number until we exceed the maximum user    *
  994. ;*    # for the selected drive.                *
  995. ;*                                *
  996. ;****************************************************************
  997.  
  998. NXTUSR:    CALL    CKABRT        ; check for user abort first
  999.     LD    A,(MAXUSR)    ; no abort - get maximum user number
  1000.     LD    HL,NEWUSR    ; bump directory user number
  1001.     INC    (HL)
  1002.     CP    (HL)        ; does next user # exceed maximum?
  1003.     JP    NC,SETTBL    ; continue if more user areas to go
  1004.     LD    A,(BASUSR)    ; reset base user number for the
  1005.     LD    (HL),A        ; ..next directory search
  1006.  
  1007. ;****************************************************************
  1008. ;*                                *
  1009. ;*    Directory for all user areas completed.  If the        *
  1010. ;*    multi-disk option is enabled and selected, reset to    *
  1011. ;*    the base user area and repeat the directory for next    *
  1012. ;*    drive on-line until we either exceed the drives in our    *
  1013. ;*    lodrv-hidrv table, or the BDOS shuts us down with a    *
  1014. ;*    select or bad sector error, which will be intercepted    *
  1015. ;*    back to the exit module.                *
  1016. ;*                                *
  1017. ;****************************************************************
  1018.  
  1019. NXTDSK:    LD    HL,FNDFLG    ; get file found flag
  1020.     LD    A,(HL)        ; get flag
  1021.     LD    (HL),0        ; clear file found flag for next drive
  1022.     OR    A        ; test old flag
  1023.     JP    NZ,NDSK        ; continue if at least 1 file found
  1024.     LD    A,(QUIET)    ; check output mode
  1025.     OR    A        ; test it
  1026.     JP    Z,NDSK        ; if zero, next
  1027.     CALL    CRLF        ; clean up lint
  1028.     LD    A,(FCB)        ; stash ascii dir. drive in no file msg
  1029.     ADD    A,'A'-1        ; ascify it
  1030.     LD    (NOFMS2),A    ; and stuff it
  1031.     LD    DE,NOFMS1    ; print "no file on ? - "
  1032.     CALL    PRINT        ; display it
  1033.  
  1034. NDSK:    LD    A,(DOPFLG)    ; get flag
  1035.     OR    A        ; and test it
  1036.     JP    NZ,EXIT        ; ok, exit
  1037.     CALL    CKABRT        ; check for user abort first
  1038.     LD    A,HIDRV-LODRV    ; get maximum drive code to search
  1039.     LD    HL,FCB        ; bump directory fcb drive code
  1040.     INC    (HL)        ; up pointer
  1041.     CP    (HL)        ; does next disk exceed maximum?
  1042.     JP    C,EXIT        ; if so, exit
  1043.     LD    E,(HL)        ; get value
  1044.     LD    D,0        ; clear hi
  1045.     DEC    E        ; count down
  1046.     LD    HL,LODRV    ; get it
  1047.     ADD    HL,DE        ; add offset
  1048.     LD    A,(HL)        ; pick up value from table
  1049.     CP    0FFH        ; and test it
  1050.     JP    Z,NDSK        ; search next disk if maxdr not true
  1051.     JP    NOOPT        ; onward
  1052.  
  1053. ;****************************************************************
  1054. ;*                                *
  1055. ;*    Print the user number of the directory in decimal.    *
  1056. ;*                                *
  1057. ;****************************************************************
  1058.  
  1059. TYPUSR:    LD    A,(NEWUSR)    ; get user number
  1060.     CP    10        ; if user no. > 9 print leading 1
  1061.     JP    C,DUX        ; ok, print
  1062.     LD    A,'1'        ; else set leading user number
  1063.     CALL    TYPE        ; display it
  1064.     LD    A,(NEWUSR)    ; print low digit of user #
  1065.     SUB    10        ; adjust it
  1066.  
  1067. DUX:    ADD    A,'0'        ; ascify it
  1068.     JP    TYPE        ; and display it
  1069.  
  1070.     COND    TWOCOL
  1071. GCRLF:    LD    A,(HCOUNT)    ; get count
  1072.     CP    5        ; see if at start
  1073.     RET    C        ; yep, exit
  1074.     LD    A,' '        ; get a space
  1075.     CALL    TYPE        ; send a space
  1076.     LD    A,(HCOUNT)    ; get count
  1077.     CP    5        ; see if at start
  1078.     RET    C        ; yep, exit
  1079.     CP    30        ; see if library displayed
  1080.     JP    C,SPACXX    ; space it out
  1081.     CP    50        ; test line length
  1082.     JP    NC,CRLF        ; else space line out
  1083.  
  1084. SEPCRL:    LD    A,(NEWUSR)    ; get user number
  1085.     CP    10        ; test it
  1086.     JP    NC,SEPLNG    ; space for < 10
  1087.     LD    A,' '        ; get a space
  1088.     CALL    TYPE        ; and send space
  1089.  
  1090. SEPLNG:    LD    A,'|'        ; get fence character
  1091.     CALL    TYPE        ; and display it
  1092.     LD    A,' '        ; get a space
  1093.     CALL    TYPE        ; now display it
  1094.     RET            ; return were finished
  1095.  
  1096. SPACXX:    PUSH    HL        ; save the world
  1097.     PUSH    DE
  1098.     PUSH    BC
  1099.     PUSH    AF
  1100.     LD    B,15        ; number of columns to move
  1101.     LD    HL,XXFIL    ; space filled string
  1102.     CALL    TYPEIT        ; send spaces
  1103.     POP    AF        ; and restore the world
  1104.     POP    BC
  1105.     POP    DE
  1106.     POP    HL
  1107.     JP    SEPCRL        ; send separator
  1108.  
  1109. XXFIL:    DEFB    '                    '
  1110.     ENDC
  1111.     COND    (NOT TWOCOL AND 0FFH)
  1112. GCRLF:
  1113.     ENDC
  1114.  
  1115. ;********************************************************
  1116. ;*                            *
  1117. ;*    Send a carriage return line feed to console.    *
  1118. ;*                            *
  1119. ;********************************************************
  1120.  
  1121. CRLF:    LD    A,CR        ; send cr
  1122.     CALL    TYPE        ; display it
  1123.     LD    A,LF        ; send lf
  1124.     JP    TYPE        ; exit to caller from type
  1125.  
  1126. ;****************************************************************
  1127. ;*                                *
  1128. ;*    Output character in a to console, and optionally    *
  1129. ;*    to printer and/or the output file.            *
  1130. ;*                                *
  1131. ;****************************************************************
  1132.  
  1133. TYPE:    PUSH    BC        ; save the world
  1134.     PUSH    DE
  1135.     PUSH    HL
  1136.     PUSH    AF        ; save the character to output
  1137.     CALL    TYPE1        ; send it to console
  1138.     COND    PAGNAT
  1139.     LD    A,(HCOUNT)    ; get hor count
  1140.     INC    A        ; up count
  1141.     LD    (HCOUNT),A    ; and save updated count
  1142.     POP    AF        ; get character
  1143.     PUSH    AF        ; and save on stack
  1144.     AND    01111111B    ; kill parity bit
  1145.     CP    LF        ; test if at end
  1146.     JP    NZ,TYPRET    ; do exit
  1147.     LD    A,0        ; get a zero
  1148.     LD    (HCOUNT),A    ; and update counter
  1149.     LD    A,(VCOUNT)    ; get vertical count
  1150.     INC    A        ; up count
  1151.     LD    (VCOUNT),A    ; save new count
  1152.     CP    60        ; 60 lines per page
  1153.     JP    C,TYPRET    ; not at end, onward
  1154.     LD    B,6        ; 6 blank lines
  1155.  
  1156. FRMFED:    PUSH    BC        ; save it
  1157.     LD    A,CR        ; we go around the normal
  1158.     CALL    TYPE1        ; output routine so we
  1159.     LD    A,LF        ; don't get trapped in
  1160.     CALL    TYPE1        ; a loop
  1161. ;    CALL    CRLF        ; clean line
  1162.     POP    BC        ; get count
  1163.     DJNZ    FRMFED        ; count it down
  1164.     LD    A,0        ; get a zero
  1165.     LD    (VCOUNT),A    ; up count
  1166.     ENDC            ; pagnat
  1167.  
  1168. TYPRET:    POP    AF        ; restore the output character
  1169.     POP    HL        ; exit from type
  1170.     POP    DE
  1171.     POP    BC
  1172.     RET            ; back, were finished
  1173.  
  1174. ;********************************
  1175. ;*                *
  1176. ;*    Output character    *
  1177. ;*                *
  1178. ;********************************
  1179.  
  1180. TYPE1:    LD    E,A        ; get character into bdos entry register
  1181.     LD    C,WRCHR        ; set up function
  1182.     JP    BDOS        ; call conout via the bdos
  1183.  
  1184. ;************************************************
  1185. ;*                        *
  1186. ;*    Print a string at HL of length B    *
  1187. ;*                        *
  1188. ;************************************************
  1189.  
  1190. TYPEIT:    LD    A,(HL)        ; pick up character
  1191.     AND    07FH        ; mask parity bit off
  1192.     CALL    TYPE        ; go display it
  1193.     INC    HL        ; point to next character
  1194.     DEC    B        ; and count down characters
  1195.     JP    NZ,TYPEIT    ; to display
  1196.     RET            ; return if none left
  1197.  
  1198. ;************************************************
  1199. ;*                        *
  1200. ;*    Print string terminated with last    *
  1201. ;*    byte high on console            *
  1202. ;*                        *
  1203. ;************************************************
  1204.  
  1205. PRINT:    LD    A,(DE)        ; pick up character
  1206.     PUSH    AF        ; save on stack
  1207.     AND    7FH        ; mask it (no 8th bit)
  1208.     CALL    TYPE        ; send to console
  1209.     POP    AF        ; get original back
  1210.     OR    A        ; test it
  1211.     RET    M        ; back if MSB set
  1212.     INC    DE        ; else bump pointer
  1213.     JP    PRINT        ; and do next
  1214.  
  1215. ;********************************************************
  1216. ;*                            *
  1217. ;*    Fetch character from console (without echo)    *
  1218. ;*                            *
  1219. ;********************************************************
  1220.  
  1221. CINPUT:    LD    HL,(BASE+1)    ; get warm boot vector
  1222.     LD    L,9        ; get input offset
  1223.     CALL    GOHL        ; go to conin routine in bios
  1224.     AND    7FH        ; mask any parity bit
  1225.     RET            ; and back to caller, we have it
  1226.  
  1227. ;****************************************************************
  1228. ;*                                *
  1229. ;*    Check for a CTL-C or CTL-S entered from the keyboard.    *
  1230. ;*    Jump to exit if CTL-C, pause on CTL-S.            *
  1231. ;*                                *
  1232. ;****************************************************************
  1233.  
  1234. CKABRT:    LD    HL,(BASE+1)    ; get warm boot vector
  1235.     LD    L,6        ; check status of keyboard
  1236.     CALL    GOHL        ; any key pressed?
  1237.     OR    A        ; test
  1238.     RET    Z        ; no, return to caller
  1239.     CALL    CINPUT        ; get character
  1240.     CP    'C'-40H        ; ctl-c?
  1241.     JP    Z,EX0        ; if ctl-c then quit
  1242.     CP    'X'-40H        ; ctl-x?
  1243.     JP    Z,EX0        ; if ctl-x then quit
  1244.     CP    'S'-40H        ; ctl-s?
  1245.     RET    NZ        ; no, return to caller
  1246.     CALL    CINPUT        ; yes, wait for another char.
  1247.     CP    'C'-40H        ; might be ctl-c
  1248.     JP    Z,EX0        ; if ctl-c then quit
  1249.     CP    'X'-40H        ; might be ctl-x
  1250.     JP    Z,EX0        ; if ctl-x, else fall thru and continue
  1251.     RET            ; all finished, exit
  1252.  
  1253. ;************************************************
  1254. ;*                        *
  1255. ;*    Kludge to allow call to address in HL    *
  1256. ;*                        *
  1257. ;************************************************
  1258.  
  1259. GOHL:    JP    (HL)
  1260.  
  1261. ;********************************************************
  1262. ;*                            *
  1263. ;*    Entry    to BDOS saving all extended registers    *
  1264. ;*                            *
  1265. ;********************************************************
  1266.  
  1267. CPM:    PUSH    BC        ; save them registers
  1268.     PUSH    DE
  1269.     PUSH    HL
  1270.     CALL    BDOS        ;
  1271.     LD    B,A        ; save return code
  1272.     LD    A,(VERFLG)    ; is this 3.0?
  1273.     CP    30H        ; see if a zero
  1274.     LD    A,B        ; get value
  1275.     JP    C,CPM20        ; no, exit normally
  1276.     CP    0FFH        ; it is 3.0 - was return code 0FFH?
  1277.     JP    NZ,CPM20    ; no, exit normally
  1278.     LD    A,H        ; 3.0 and a=0FFH - check for error code
  1279.     OR    A        ; test it
  1280.     JP    NZ,DSKERR    ; trap out if we got a physical error
  1281.     LD    A,B        ;  else continue normally
  1282.  
  1283. CPM20:    POP    HL        ; restore the world
  1284.     POP    DE
  1285.     POP    BC
  1286.     RET            ; and back to caller, were finished
  1287.  
  1288. ;
  1289. ;****************************************************************
  1290. ;*                                *
  1291. ;*    For file output mode, return to old user area and    *
  1292. ;*    set dma for the file output buffer.            *
  1293. ;*                                *
  1294. ;****************************************************************
  1295.  
  1296. SETFOP:    LD    A,(OLDUSR)    ; get user number at startup
  1297.     LD    E,A        ; set it up
  1298.     LD    C,CURUSR    ; set up function
  1299.     CALL    CPM        ; reset the old user number
  1300.     RET            ; and back, were finished
  1301.  
  1302. ;****************************************************************
  1303. ;*                                *
  1304. ;*    Move disk buffer dma to default buffer for directory    *
  1305. ;*    search operations and bdos media change routines    *
  1306. ;*    (necessary for pre-cp/m 2 systems while in file output    *
  1307. ;*    mode with an active buffer).                *
  1308. ;*                                *
  1309. ;****************************************************************
  1310.  
  1311. SETSRC:    LD    DE,BASE+80H    ; point to default DMA address
  1312.  
  1313. SET2:    LD    C,SETDMA    ; set up function call
  1314.     JP    CPM        ; and set dma address
  1315.  
  1316. ;****************************************
  1317. ;*                    *
  1318. ;*    Compare routine for sort.    *
  1319. ;*                    *
  1320. ;****************************************
  1321.  
  1322. COMPR:    PUSH    HL        ; save table address
  1323.     LD    E,(HL)        ; load low order
  1324.     INC    HL        ; bump pointer
  1325.     LD    D,(HL)        ; load high order
  1326.     INC    HL        ; bump it again
  1327.     LD    C,(HL)        ; pick up data
  1328.     INC    HL        ; bump pointer
  1329.     LD    B,(HL)        ; and last piece of information
  1330.  
  1331. ;********************************************************
  1332. ;*                            *
  1333. ;*    BC, DE now point to entries to be compared.    *
  1334. ;*                            *
  1335. ;********************************************************
  1336.  
  1337.     EX    DE,HL        ; swap pointers
  1338.     LD    E,A        ; get count
  1339.  
  1340. CMPLP:    LD    A,(HL)        ; get character
  1341.     AND    7FH        ; mask parity bit
  1342.     LD    D,A        ; save it in D
  1343.     LD    A,(BC)        ; get next character
  1344.     AND    7FH        ; mask parity bit
  1345.     CP    D        ; test for match
  1346.     INC    HL        ; up source pointer
  1347.     INC    BC        ; up compare pointer
  1348.     JP    NZ,NOTEQL    ; quit on mismatch
  1349.     DEC    E        ; or end of count
  1350.     JP    NZ,CMPLP    ; loop till end of string
  1351.  
  1352. NOTEQL:    POP    HL        ; restore pointer
  1353.     RET            ; cond code tells all
  1354.  
  1355. ;************************************************
  1356. ;*                        *
  1357. ;*    Swap entries in the order table.    *
  1358. ;*                        *
  1359. ;************************************************
  1360.  
  1361. SWAP:    LD    BC,ORDER-2    ; table base
  1362.     ADD    HL,HL        ; *2
  1363.     ADD    HL,BC        ; + base
  1364.     EX    DE,HL
  1365.     ADD    HL,HL        ; *2
  1366.     ADD    HL,BC        ; + base
  1367.     LD    C,(HL)        ; get low address of pointer
  1368.     LD    A,(DE)        ; and do it for other pointer
  1369.     EX    DE,HL        ; swap pointers
  1370.     LD    (HL),C        ; swap low pointer value
  1371.     LD    (DE),A        ; swaped
  1372.     INC    HL        ; bump pointer
  1373.     INC    DE        ; bump pointers, both of them
  1374.     LD    C,(HL)        ; get hi address
  1375.     LD    A,(DE)        ; and the other
  1376.     EX    DE,HL        ; swap pointers
  1377.     LD    (HL),C        ; swap hi pointer value
  1378.     LD    (DE),A        ; swaped
  1379.     RET            ; and back, were finished
  1380.  
  1381. ;********************************
  1382. ;*                *
  1383. ;*    New compare routine.    *
  1384. ;*                *
  1385. ;********************************
  1386.  
  1387. COMPARE:
  1388.     LD    BC,ORDER-2    ; table base
  1389.     ADD    HL,HL        ; *2
  1390.     ADD    HL,BC        ; + base
  1391.     EX    DE,HL
  1392.     ADD    HL,HL        ; *2
  1393.     ADD    HL,BC        ; + base
  1394.     EX    DE,HL        ; swap pointers
  1395.     LD    C,(HL)        ; get low value
  1396.     INC    HL        ; bump pointer
  1397.     LD    B,(HL)        ; get low test value
  1398.     EX    DE,HL        ; bump pointer
  1399.     LD    E,(HL)        ; get hi value
  1400.     INC    HL        ; bump pointer
  1401.     LD    D,(HL)        ; get it
  1402.     EX    DE,HL        ; swap pointers
  1403.     LD    E,A        ; count
  1404.  
  1405. CMPLPE:    LD    A,(HL)        ; get character
  1406.     AND    7FH        ; mask out 8th bit
  1407.     LD    D,A        ; save it in D
  1408.     LD    A,(BC)        ; get test character
  1409.     AND    7FH        ; mask out 8th bit
  1410.     CP    D        ; see if match (z flag)
  1411.     INC    BC        ; up pointers
  1412.     INC    HL        ; both of them
  1413.     RET    NZ        ; no match, exit
  1414.     DEC    E        ; else count down string length
  1415.     JP    NZ,CMPLPE    ; and loop till all match
  1416.     RET            ; if we get here, they matched
  1417.  
  1418. ;********************************
  1419. ;*                *
  1420. ;*    --- Error exit ---    *
  1421. ;*                *
  1422. ;********************************
  1423.  
  1424. ERXIT:    CALL    CRLF        ; space down
  1425.     POP    DE        ; get pointer to message string
  1426.     CALL    PRINT        ; print it
  1427.     LD    DE,ERRMS1    ; print " error"
  1428.     CALL    PRINT        ; send message
  1429.     CALL    CRLF        ; space down
  1430.  
  1431. ;************************************************
  1432. ;*                        *
  1433. ;*    --- Exit - all done restore stack ---    *
  1434. ;*                        *
  1435. ;************************************************
  1436.  
  1437. EXIT:    LD    A,(DOPFLG)    ; check multi disk mode
  1438.     OR    A        ; set cpu flag
  1439.     JP    NZ,EX0        ; onward
  1440.     CALL    CKABRT        ; check for user abort first
  1441.     LD    A,HIDRV-LODRV    ; get maximum drive code to search
  1442.     LD    HL,FCB        ; bump directory fcb drive code
  1443.     INC    (HL)        ; up pointer
  1444.     CP    (HL)        ; does next disk exceed maximum?
  1445.     JP    C,EX0        ; onward
  1446.     JP    NOOPT        ; search next disk if maxdr not true
  1447.  
  1448. TMMSG:    DEFB    CR,LF,LF,'Files Matched -',' '+80H
  1449. TCMSG:    DEFB    CR,LF,'Files Checked -',' '+80H
  1450. TLMSG:    DEFB    CR,LF,'Libraries Searched -',' '+80H
  1451. TFILES:    DEFW    0
  1452. TLIBRA:    DEFW    0
  1453. TMATCH:    DEFW    0
  1454.  
  1455. EX0:    LD    DE,TMMSG    ; point to matched message
  1456.     CALL    PRINT        ; display it
  1457.     LD    HL,(TMATCH)    ; get count
  1458.     CALL    DECPRT        ; and tell how many matched
  1459.     LD    DE,TCMSG    ; point to checked message
  1460.     CALL    PRINT        ; display it
  1461.     LD    HL,(TFILES)    ; get checked count
  1462.     CALL    DECPRT        ; and tell him how many
  1463.     LD    DE,TLMSG    ; point to library message
  1464.     CALL    PRINT        ; display it
  1465.     LD    HL,(TLIBRA)    ; get count
  1466.     CALL    DECPRT        ; and tell how many libraries checked
  1467.     LD    C,CONST        ; check console status
  1468.     CALL    CPM        ; get status
  1469.     OR    A        ; char waiting?
  1470.     LD    C,RDCHR        ; assume one waiting
  1471.     CALL    NZ,CPM        ; gobble up char
  1472.     LD    A,(VERFLG)    ; or error mode, depending on version
  1473.     CP    30H        ; test for match
  1474.     JP    C,EXIT0        ; nope, cpm 2.xx
  1475.     LD    C,45        ; get value
  1476.     LD    E,0        ; set error mode back to default
  1477.     CALL    CPM        ; go do it
  1478.     JP    EXIT1        ; onward
  1479.  
  1480. EXIT0:    LD    A,(DOPFLG)    ; ..if they were swapped
  1481.     OR    A        ; test flag
  1482.     CALL    Z,SWAPEM    ; reverse them if so
  1483.  
  1484. EXIT1:    LD    A,'L'-'@'    ;  form feed character
  1485.     CALL    TYPE1        ;  go send to top of page
  1486.     LD    HL,(STACK)    ; get old stack pointer
  1487.     LD    SP,HL        ; move back to old stack
  1488.     RET            ; ..and return to ccp
  1489.  
  1490. VERERR:    LD    DE,VERBAD    ; abort cp/m is version 1.?
  1491. VERER1:    CALL    PRINT        ; display message
  1492.     JP    EXIT1        ; and abort
  1493.  
  1494. NONERR:    LD    DE,VERNAME    ; print help info
  1495.     JP    VERER1        ; tell him
  1496.  
  1497. ;********************************************************
  1498. ;*                            *
  1499. ;*    Trap BDOS select and sector error vectors to    *
  1500. ;*    our own intercept routine so we    can catch a    *
  1501. ;*    reference to an illegal drive.            *
  1502. ;*                            *
  1503. ;********************************************************
  1504.  
  1505. SWAPEM:    LD    A,(VERFLG)    ; check version
  1506.     CP    30H        ; see if error mode call is available
  1507.     JP    C,SWAP20    ; if not, use bdos error vectors
  1508.     LD    C,45
  1509.     LD    E,0FFH        ; use set error mode call
  1510.     CALL    CPM        ; set "return code only" mode
  1511.     RET            ; and back, were done
  1512.  
  1513. SWAP20:    LD    HL,(BDOLOC)    ; get pointer to base of bios
  1514.     LD    A,L        ; get low value
  1515.     OR    H        ; test with hi
  1516.     JP    NZ,SWAPO0    ; yep, onward
  1517.     LD    HL,BASE+6    ; get bdos address
  1518. SWAPO0:    LD    L,9        ; set pointer to error vectors
  1519.  
  1520. SWAPOK:    LD    DE,VECTBL    ; exchanging with our own vector table
  1521.     LD    A,4        ; 4 bytes to swap
  1522.  
  1523. SWAPLP:    LD    B,(HL)        ; get byte from hl
  1524.     EX    DE,HL
  1525.     LD    C,(HL)        ; get byte from de
  1526.     LD    (HL),B        ; put byte from hl
  1527.     EX    DE,HL
  1528.     LD    (HL),C        ; put byte from de
  1529.     INC    HL        ; bump exchange pointers
  1530.     INC    DE
  1531.     DEC    A        ; dock counter
  1532.     JP    NZ,SWAPLP    ; continue swapping till done
  1533.     RET
  1534.  
  1535. ;************************************************
  1536. ;*                        *
  1537. ;*    Recovery point from intercepted BDOS    *
  1538. ;*    select and bad sector errors.        *
  1539. ;*                        *
  1540. ;************************************************
  1541.  
  1542. DSKERR:    LD    SP,STACK    ; get out of bdos' STACK
  1543.     JP    EXIT        ; ..and exit back to ccp
  1544.  
  1545.     COND    WHERE
  1546. ;================================================================
  1547. ;=                                =
  1548. ;=         SUBROUTINES TO READ LIBRARY FILE DIRECTORY        =
  1549. ;=                                =
  1550. ;================================================================
  1551.  
  1552. PRTLMEM:
  1553.     LD    HL,SEARN+8    ; get value
  1554.     CALL    CKLBR        ; see if library entry
  1555.     RET    Z        ; nope, exit
  1556.     LD    HL,ORDER    ; initialize order table pointer
  1557.     LD    (NEXTL),HL    ; save pointer
  1558.  
  1559. ENTRYL:    LD    HL,(LCOUNT)    ; get fcb count
  1560.     DEC    HL        ; decrement it
  1561.     LD    (LCOUNT),HL    ; and update counter
  1562.     LD    A,H        ; is this the last file?
  1563.     OR    L        ; see if count = 0
  1564.     JP    Z,LBRTST    ; if count=0, last file skip compare
  1565.     PUSH    BC        ; save it
  1566.     CALL    CKABRT        ; check for abort code from keyboard
  1567.     LD    HL,(NEXTL)    ; get value
  1568.     LD    A,11        ; set up length of filename
  1569.     CALL    COMPR        ; does this entry match next one?
  1570.     POP    BC        ; restore it
  1571.     JP    NZ,LBRTST    ; no, print it
  1572.     INC    HL        ; up pointer
  1573.     INC    HL        ; skip, highest extent comes last in list
  1574.     LD    (NEXTL),HL    ; and save new pointer
  1575.     JP    ENTRYL        ; loop back for next lowest extent
  1576.  
  1577. ;****************************************
  1578. ;*                    *
  1579. ;*    Exit library member printing    *
  1580. ;*                    *
  1581. ;****************************************
  1582.  
  1583. LBEXIT:    XOR    A        ; get a zero to...
  1584.     LD    (SUPSPC),A    ; suppress leading spaces in totals
  1585.     RET            ; back, were finished
  1586.  
  1587. ;************************************************
  1588. ;*                        *
  1589. ;*    Valid entry obtained - spit it out.    *
  1590. ;*                        *
  1591. ;************************************************
  1592.  
  1593. LBRTST:    LD    HL,(NEXTL)    ; get order table pointer
  1594.     LD    E,(HL)        ; get low order address
  1595.     INC    HL        ; up pointer
  1596.     LD    D,(HL)        ; get high order address
  1597.     INC    HL        ; and up it again
  1598.     LD    (NEXTL),HL    ; save updated table pointer
  1599.     LD    HL,8        ; set up offset
  1600.     ADD    HL,DE        ; add offset
  1601.     CALL    CKLBR        ; go test it
  1602.     JP    NZ,LBRNEX    ; onward
  1603.     PUSH    DE        ; now put DE into HL
  1604.     POP    HL        ; done
  1605.  
  1606. ;************************************************
  1607. ;*                        *
  1608. ;*    Saves the library file name into lbrfcb    *
  1609. ;*                        *
  1610. ;************************************************
  1611.  
  1612.     LD    A,(FCB)
  1613.     LD    DE,LBRFCB    ; to
  1614.     LD    (DE),A
  1615.     INC    DE
  1616.     LD    B,11        ; length
  1617.     CALL    MOVE        ; do the move
  1618.     EX    DE,HL
  1619.     LD    B,25
  1620.  
  1621. CLMFCB:    LD    (HL),0        ; clear memory <- HL
  1622.     INC    HL        ; up it by 1
  1623.     DEC    B        ; count down
  1624.     JP    NZ,CLMFCB    ; and clear rest of FCB
  1625.     CALL    SETLDMA        ; set up xfer address
  1626.     LD    DE,LBRFCB    ; point to file
  1627.     LD    C,OPEN        ; get function
  1628.     CALL    CPM        ; open it
  1629.     LD    C,READ        ; set up read function
  1630.     LD    DE,LBRFCB    ; point to FCB
  1631.     CALL    CPM        ; read a record
  1632.     CALL    SETFOP        ; set it up
  1633.     LD    HL,LBBUF    ; set up pointer
  1634.     LD    A,(HL)        ; get byte
  1635.     OR    A        ; and see if zero
  1636.     JP    Z,CKLDIR    ; check directory present?
  1637.  
  1638. LMLEXI:    CALL    LBCLOSE
  1639.  
  1640. ;********************************
  1641. ;*                *
  1642. ;*    Do next library file    *
  1643. ;*                *
  1644. ;********************************
  1645.  
  1646. LBRNEX:    LD    HL,(LCOUNT)    ; check count
  1647.     LD    A,H        ; do a 16 bit test
  1648.     OR    L        ; tested
  1649.     JP    Z,LBEXIT    ; no more, all done
  1650.     JP    ENTRYL        ; else, get next .lbr file
  1651.  
  1652. ;********************************
  1653. ;*                *
  1654. ;*    Close the library file.    *
  1655. ;*                *
  1656. ;********************************
  1657.  
  1658. LBCLOSE:
  1659.     LD    DE,LBRFCB    ; point to FCB
  1660.     LD    C,CLOSE        ; set up function
  1661.     CALL    CPM        ; have the system close it
  1662.     RET            ; and back to caller, were finished
  1663.  
  1664. ;************************************************
  1665. ;*                        *
  1666. ;*    Set the library file dma address.    *
  1667. ;*                        *
  1668. ;************************************************
  1669.  
  1670. SETLDMA:
  1671.     LD    A,(NEWUSR)    ; get user area for directory
  1672.     LD    E,A        ; set user up
  1673.     LD    C,CURUSR    ; get the user function
  1674.     CALL    CPM        ; ..and set new user number
  1675.     LD    DE,LBBUF    ; point to buffer
  1676.     LD    C,SETDMA    ; set up xfer address function
  1677.     CALL    CPM        ; set xfer address
  1678.     RET            ; and back to caller, were finished
  1679.  
  1680. ;********************************************************
  1681. ;*                            *
  1682. ;*    Check to see if there indeed is a lbr file    *
  1683. ;*    directory and barf if not!            *
  1684. ;*                            *
  1685. ;********************************************************
  1686.  
  1687. CKLDIR:    LD    B,11        ; length of file name
  1688.     LD    A,' '        ; space
  1689.     INC    HL        ; up pointer
  1690.  
  1691. CKDLP:    CP    (HL)        ; see if we match
  1692.     JP    NZ,LMLEXI    ; nope, onward
  1693.     DEC    B        ; else count down
  1694.     INC    HL        ; up pointer
  1695.     JP    NZ,CKDLP    ; and loop back
  1696.  
  1697. ;********************************************************
  1698. ;*                            *
  1699. ;*    The first entry in the LBR directory is indeed    *
  1700. ;*    blank.  Now see if the directory size is >0.    *
  1701. ;*                            *
  1702. ;********************************************************
  1703.  
  1704.     LD    E,(HL)        ; file starting location low
  1705.     INC    HL        ; must be zero here
  1706.     LD    A,(HL)        ; file starting location high
  1707.     OR    E        ; must be zero here also
  1708.     JP    NZ,LMLEXI    ; nope, onward
  1709.     INC    HL        ; yep, bump pointer
  1710.     LD    E,(HL)        ; get library size low
  1711.     INC    HL        ; point to library size high
  1712.     LD    D,(HL)        ; get library size high
  1713.     LD    A,D        ; set it up
  1714.     OR    E        ; library must have some size
  1715.     JP    Z,LMLEXI    ; yep, onward
  1716.     DEC    DE        ; back it down
  1717.     EX    DE,HL        ; swap pointers
  1718.     LD    (SLFILE),HL    ; save pointer
  1719.     LD    B,3        ;
  1720.     LD    HL,17        ; set up offset
  1721.     ADD    HL,DE        ; add offset
  1722.     PUSH    HL        ; save on stack
  1723.     LD    HL,(TLIBRA)    ; get count
  1724.     INC    HL        ; increment it
  1725.     LD    (TLIBRA),HL    ; and save it
  1726.     POP    HL        ; restore value
  1727.     JP    LMTEST        ; onward
  1728.  
  1729. LFMLOP:    LD    HL,(SLFILE)    ; get count
  1730.     LD    A,L        ; get low
  1731.     OR    H        ; and do 16 bit test
  1732.     JP    Z,LMLEXI    ; zero, exit
  1733.     DEC    HL        ; count down
  1734.     LD    (SLFILE),HL    ; and save new count
  1735.     CALL    SETLDMA        ; set up the xfer address
  1736.     LD    C,READ        ; read a block of data function
  1737.     LD    DE,LBRFCB    ; point to library FCB
  1738.     CALL    CPM        ; read the block in
  1739.     CALL    SETFOP
  1740.     LD    B,4        ; get file count per sector
  1741.     LD    HL,LBBUF    ; get buffer starting address
  1742.  
  1743. LMTEST:    LD    A,(HL)        ; get member open flag
  1744.     OR    A        ; test for open
  1745.     JP    Z,PRMNAM    ; if zero, onward
  1746.  
  1747. LMTESA:    LD    DE,32        ; member not open get offset
  1748.     ADD    HL,DE        ; to next and add it in.
  1749.     DEC    B        ; is buffer empty ?
  1750.     JP    NZ,LMTEST    ; no so test next entry
  1751.     JP    LFMLOP        ; yes get next buffer...
  1752.  
  1753. PRMNAM:    PUSH    HL        ; print member name and size
  1754.     PUSH    BC
  1755.     CALL    CKABRT        ; check for abort code from keyboard
  1756.  
  1757. PRMNA1:    POP    BC        ; now we swap HL
  1758.     POP    HL        ; and BC
  1759.     PUSH    HL        ; save on the stack
  1760.     PUSH    BC        ; for later
  1761.     INC    HL        ; bump pointer
  1762.     PUSH    HL        ; save as we update count
  1763.     LD    HL,(TFILES)    ; get count
  1764.     INC    HL        ; bump it by one
  1765.     LD    (TFILES),HL    ; and save count
  1766.     POP    HL        ; now restore the pointer
  1767.     CALL    COMPS        ; match what we are looking for ?
  1768.     JP    NZ,LBGNXT    ; nope, onward
  1769.     PUSH    HL        ; save it on the stack
  1770.     LD    HL,(TMATCH)    ; get match count
  1771.     INC    HL        ; up it by one
  1772.     LD    (TMATCH),HL    ; and save it for later
  1773.     POP    HL        ; get pointer back from stack
  1774.     CALL    GCRLF        ;  changed for two column output
  1775.     LD    A,(FCB)        ; ..precede new line with drive name
  1776.     ADD    A,'A'-1        ; ascify it
  1777.     CALL    TYPE        ; and display drive
  1778.     CALL    TYPUSR        ; now display user
  1779.     LD    A,':'        ; tag header with a colon and a space
  1780.     CALL    TYPE        ; ..and exit back to entry
  1781.  
  1782.     COND    ZCPR3
  1783.     CALL    SHONDR
  1784.     ENDC    ; ZCPR3
  1785.  
  1786.     LD    A,' '        ; get a space
  1787.     CALL    TYPE        ; and display it after drive-user-:
  1788.     LD    B,8        ; file name length
  1789.     CALL    TYPEIT        ; display file name
  1790.     LD    A,'.'        ; period after fn
  1791.     CALL    TYPE        ; display the dot
  1792.     LD    B,3        ; display 3 characters of filetype
  1793.     CALL    TYPEIT        ; display the extension
  1794.     INC    HL        ; bump the pointer by 2
  1795.     INC    HL
  1796.     LD    E,(HL)        ; get value
  1797.     INC    HL        ; bump pointer
  1798.     LD    D,(HL)        ; we have the 16 bit value
  1799.     EX    DE,HL
  1800.  
  1801. ;********************************************************
  1802. ;*                            *
  1803. ;*    Output the size of the individual file.        *
  1804. ;*                            *
  1805. ;********************************************************
  1806.  
  1807.     PUSH    DE        ; save on stack
  1808.     PUSH    HL
  1809.     PUSH    HL
  1810.     LD    HL,(LLENLOC)    ; get pointer
  1811.     PUSH    HL        ; switch around on stack
  1812.     POP    DE        ; swapping
  1813.     POP    HL        ; swapped
  1814.     ADD    HL,DE        ; add offset and form pointer
  1815.     LD    (LLENLOC),HL    ; save new pointer
  1816.     POP    HL        ; and restore old pointer
  1817.  
  1818. ;********************************************************
  1819. ;*                            *
  1820. ;*    New code added to convert lib members from    *
  1821. ;*    sectors to 'K'.                    *
  1822. ;*                            *
  1823. ;*    Upon entry member's size in sectors is in HL.    *
  1824. ;*                            *
  1825. ;********************************************************
  1826.  
  1827.     EX    DE,HL        ; put it in de
  1828.     LD    HL,0        ; zero out hl
  1829.     LD    A,E        ; put low byte of sector count in a
  1830.     ADD    A,7        ; add seven to always round up 1k
  1831.     RRCA            ; convert it to k
  1832.     RRCA
  1833.     RRCA
  1834.     AND    1FH        ; mask it
  1835.     LD    E,A        ; and put it back
  1836.     LD    L,D        ; get the high byte if any
  1837.     LD    D,0        ; clean out the old resting place
  1838.     ADD    HL,HL        ; multiply it by 32 to convert to
  1839.     ADD    HL,HL        ; number
  1840.     ADD    HL,HL        ; of
  1841.     ADD    HL,HL        ; k
  1842.     ADD    HL,HL        ; bytes
  1843.     ADD    HL,DE        ; and add in the low byte
  1844.     POP    DE
  1845.     CALL    DECPRT        ; ..go print it
  1846.     LD    A,'K'        ; ..and follow with size
  1847.     CALL    TYPE        ; display the 'K'
  1848.     LD    HL,INLBF    ; set pointer
  1849.     LD    B,3        ;  gfs spacing
  1850.     CALL    TYPEIT        ; and display it
  1851.     LD    HL,LBRFCB+1    ; point to filename
  1852.     LD    B,8        ; file name length
  1853.     CALL    TYPEIT        ; display file name
  1854.     LD    A,'.'        ; period after fn
  1855.     CALL    TYPE        ; display dot
  1856.     LD    B,3        ; display 3 characters of filetype
  1857.     CALL    TYPEIT        ; display extension
  1858.     LD    A,0FFH        ; get flag value
  1859.     LD    (FNDFLG),A    ; set file found flag
  1860.  
  1861. ;********************************************************
  1862. ;*                            *
  1863. ;*    At least one more file to output - can we    *
  1864. ;*    put it on the current line?            *
  1865. ;*                            *
  1866. ;********************************************************
  1867.  
  1868. LBGNXT:    POP    BC        ; restore the pointers
  1869.     POP    HL        ; from the stack
  1870.     JP    LMTESA        ; .. and go output another file
  1871.  
  1872.     ENDC            ; whereis
  1873.  
  1874. COMPS:    PUSH    HL        ; save the world
  1875.     PUSH    DE
  1876.     PUSH    BC
  1877.     LD    BC,SEARN    ; set pointer
  1878.     LD    E,11        ; set count to filename.ext length
  1879.  
  1880. COMPS1:    LD    A,(HL)        ; get character
  1881.     AND    7FH        ; mask parity bit
  1882.     LD    D,A        ; and save it in D
  1883.     LD    A,(BC)        ; get test character
  1884.     INC    BC        ; up pointers
  1885.     INC    HL        ; both of them
  1886.     AND    7FH        ; mask parity from test character
  1887.     CP    '?'        ; see if ambiguous character
  1888.     JP    Z,COMPS2    ; yep, onward
  1889.     CP    D        ; else see if match
  1890.     JP    NZ,COMPS3    ; nope, onward
  1891.  
  1892. COMPS2:    DEC    E        ; count down filename.ext length
  1893.     JP    NZ,COMPS1    ; loop back till finished
  1894.  
  1895. COMPS3:    POP    BC        ; now we restore the world
  1896.     POP    DE
  1897.     POP    HL
  1898.     RET            ; and back to caller, were finished
  1899.  
  1900. INLBF:    DEFB    ' > '
  1901.  
  1902. ;********************************************************
  1903. ;*                            *
  1904. ;*    Move characters from 'HL' to 'DE' length in 'B'    *
  1905. ;*                            *
  1906. ;********************************************************
  1907.  
  1908. MOVE:    LD    A,(HL)        ; get a character
  1909.     LD    (DE),A        ; store it
  1910.     INC    HL        ; to next 'FROM'
  1911.     INC    DE        ; to next 'TO'
  1912.     DEC    B        ; more?
  1913.     JP    NZ,MOVE        ; yes, loop
  1914.     RET            ; no, return
  1915.  
  1916.     COND    ZCPR3
  1917. SHONDR:
  1918.     PUSH    AF
  1919.     PUSH    BC
  1920.     PUSH    DE
  1921.     PUSH    HL
  1922.     PUSH    IX
  1923.     LD    IX,Z3NDIR-18
  1924.     LD    BC,18
  1925.     LD    A,(FCB)
  1926.     LD    D,A
  1927.     LD    A,(NEWUSR)
  1928.     LD    E,A
  1929.  
  1930. SHONDR1:
  1931.     ADD    IX,BC
  1932.     LD    A,(IX+0)
  1933.     OR    A
  1934.     JR    Z,SHONDR6
  1935.     LD    H,(IX+0)
  1936.     LD    L,(IX+1)
  1937.     XOR    A
  1938.     SBC    HL,DE
  1939.     JR    NZ,SHONDR1
  1940.     LD    B,8
  1941.     INC    IX
  1942.     LD    A,'<'
  1943.     CALL    TYPE
  1944.  
  1945. SHONDR2:
  1946.     INC    IX
  1947.     LD    A,(IX+0)
  1948.     CP    ' '
  1949.     JR    Z,SHONDR3
  1950.     CALL    TYPE
  1951.     DJNZ    SHONDR2
  1952.  
  1953. SHONDR3:
  1954.     LD    A,'>'
  1955.     CALL    TYPE
  1956.     LD    A,B
  1957.     OR    A
  1958.     JR    Z,SHONDR5
  1959.  
  1960. SHONDR4:
  1961.     LD    A,' '
  1962.     CALL    TYPE
  1963.     DJNZ    SHONDR4
  1964.  
  1965. SHONDR5:
  1966.     POP    IX
  1967.     POP    HL
  1968.     POP    DE
  1969.     POP    BC
  1970.     POP    AF
  1971.     RET
  1972.  
  1973. SHONDR6:
  1974.     LD    B,10
  1975.     JR    SHONDR4
  1976.     ENDC    ; ZCPR3
  1977.  
  1978.     COND    WHERE
  1979. ;****************************************
  1980. ;*                    *
  1981. ;*    Test file extent for LBR.    *
  1982. ;*                    *
  1983. ;****************************************
  1984.  
  1985. CKLBR:    PUSH    HL        ; save the world
  1986.     PUSH    DE
  1987.     PUSH    BC        ;
  1988.     EX    DE,HL        ; swap pointers
  1989.     LD    HL,LBRTYP    ; set up pointer for test
  1990.     LD    C,3        ; set up extension length
  1991.  
  1992. CKLBL:    LD    A,(DE)        ; get character
  1993.     AND    7FH        ; mask MSB
  1994.     CP    (HL)        ; see if a match
  1995.     JP    NZ,CKLBX    ; nope, not .LBR so exit
  1996.     INC    HL        ; yep, up pointers
  1997.     INC    DE        ; both source and test
  1998.     DEC    C        ; count down length
  1999.     JP    NZ,CKLBL    ; and loop to all matched
  2000.  
  2001. CKLBX:    POP    BC        ; restore the world
  2002.     POP    DE
  2003.     POP    HL
  2004.     RET            ; and back to caller, were finished
  2005.     ENDC
  2006.  
  2007. HCOUNT:    DEFB    0        ;  horizontal count
  2008. VCOUNT:    DEFB    0        ;  vertical count
  2009.  
  2010. PROGEND:
  2011. STACK    EQU    PROGEND+82H
  2012. ORDER    EQU    PROGEND+84H
  2013.     SUBTTL    SYMBOL TABLE
  2014.     END
  2015.