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 / F / MAKE27.ARK / MAKE27.ASM next >
Assembly Source File  |  1990-04-13  |  49KB  |  1,850 lines

  1.  
  2. ; BE SURE TO CHECK ZCPR3 EQUATE BELOW BEFORE ASSEMBLING
  3. ;
  4. ;    ********************************************
  5. ;    *                       *
  6. ;    *    MAKE USER NUMBER CHANGE           *
  7. ;    *                       *
  8. ;    *       SYNTAX: MAKE D:AFN O  /O  (ALL)       *
  9. ;    *            MAKE DU:AFN O /O  (ALL)       *
  10. ;    *        MAKE DIR:AFN O /O (ZCPR3)  *
  11. ;    *                       *
  12. ;    *    where the drive, drive/user, and      *
  13. ;    *    named directory forms (where          *
  14. ;    *    appropriate) are optional            *
  15. ;    *                       *
  16. ;    *        and               *
  17. ;    *                       *
  18. ;    *    where O is one of the options:       *
  19. ;    *                       *
  20. ;    *    DIR:    new DIR for files (ZCPR3)  *
  21. ;    *       DU:    new DU for files       *
  22. ;    *    U:    new DU for files       *
  23. ;    *    nn    new user # for files       *
  24. ;    *    R    set files to R/O       *
  25. ;    *    W    set files to R/W       *
  26. ;    *    S    set files to SYS       *
  27. ;    *    D    set files to DIR       *
  28. ;    *    A    set files to ARCHIVE       *
  29. ;    *    N    set files to Non-ARCHIVE   *
  30. ;    *    E    erase files           *
  31. ;    *    U    unerase files           *
  32. ;    *    blank    show status of files       *
  33. ;    *                       *
  34. ;    *    /O    auto delete of dest file   *
  35. ;    *                       *
  36. ;    *  for built-in help screen enter       *
  37. ;    *         MAKE //               *
  38. ;    *                       *
  39. ;    ********************************************
  40.  
  41.  
  42. ; This primary purpose of this program is to allow one to change the user
  43. ; number of designated files on a designated drive to a different user number.
  44. ; This is carried out without copying the files and then deleting the original
  45. ; files; rather, the user number tag in the disk directory is simply changed
  46. ; to reflect the new user number.  The program also has options to set files
  47. ; attributes of read-only, read-write, system, and directory.  Files can also
  48. ; be erased or unerased.
  49.  
  50. ; The code assumes that the track and sector are set by the BDOS search
  51. ; functions and uses a simple BIOS write to update the directory.  Before using
  52. ; this program, test it on a garbage disk to make sure that it works with your
  53. ; system.
  54.                        
  55. ;  VERSION 1.0        -     07/05/81   R.E.D. 
  56. ;       1.1        -     07/15/81   R.E.D. 
  57. ;                       
  58. ;       1.2 - 8/1/82            
  59. ;        ENHANCED FILE NAME DISPLAY.
  60. ;             KEN LOVETT       
  61. ;       1.3 - 8/6/83            
  62. ;        FIXED BUG WHICH CAUSED LAST CHAR IN FILE SPEC TO  
  63. ;        BE NON-SIGNIFICANT.       
  64. ;             KEN LOVETT       
  65. ;       2.0 - 8/7/83            
  66. ;        ADDED OPTIONS TO SET R/O, R/W, SYS, DIR FLAGS. ALSO  
  67. ;        ERASE AND UNERASE FILES.   
  68. ;             KEN LOVETT       
  69. ;                       
  70. ;       2.1 - 6/20/85           
  71. ;        Added (actually, just enabled - it was always there)
  72. ;        full 32 (0-31) area capability, extended display routine
  73. ;        to handle the higher user numbers, added a four-byte kludge
  74. ;        of a display fix required by late-model Kaypros and merely
  75. ;        harmless otherwise, other minor display stuff.           
  76. ;            Bruce Morgen       
  77. ;
  78. ;       2.2 - 07/02/85
  79. ;        Major cleanup of the code (which was highly unstructured and
  80. ;        thus hard to read).  Added check on user number of files so
  81. ;        that the code will act only on files in the logged in area.
  82. ;        There is still no checking to make sure that there is not
  83. ;        already a file in the destination user area of the same name
  84. ;        as the file that is being moved in.
  85. ;            Jay Sage
  86. ;
  87. ;       2.3 - 07/14/85
  88. ;        In ZCPR3 systems the CCP processes the DU: and named directory
  89. ;        forms of directory specification.  The drive value is returned
  90. ;        in the usual way in the FCB, and the user number is placed in
  91. ;        the S1 byte.  Version 22Z of MAKE allows the syntax:
  92. ;
  93. ;                MAKE DIR:AFN OPTION
  94. ;
  95. ;        The files to be operated on can be specified using the full
  96. ;        ZCPR3 format.  The option can even take the DIR: form with a
  97. ;        named directory.  The ZCPR3 equate determines whether a
  98. ;        ZCPR3 version or a standard version will be assembled.
  99. ;        For some reason, even though there is no change in allocation,
  100. ;        performing any write to the directory sets the disk to R/O
  101. ;        status.  I have changed the code I originally put it to
  102. ;        reset the disk system whenever any write has occurred.  I had
  103. ;        not noticed this problem because I use the ZRDOS replacement
  104. ;        for the BDOS, and it automatically relogs changed disks.
  105. ;            Jay Sage
  106. ;
  107. ;       2.4 - 06/15/86
  108. ;        Added ability to SET or RESET the ARCHIVE bit, and added
  109. ;        the WHEEL conditional, which makes MAKE disappear 
  110. ;        (echoes: MAKE?) unless the wheel byte is set.
  111. ;            Michael Conley
  112. ;
  113. ;       2.5 - (an obsolete version # observed in the Chicago area dated
  114. ;         1984 - skipped to avoid confusion.
  115. ;
  116. ;       2.6 - 07/22/86
  117. ;        Added "All users" switch for any options not involving a
  118. ;        user number.  A number sign after the selected option
  119. ;        makes it operate on ALL user areas, not just the current
  120. ;        one. (e.g.,  MAKE *.BAK E# -- would erase all .BAK files
  121. ;        in all user areas.) 
  122. ;            Michael Conley
  123. ;
  124. ;       2.7 - 04/10/88
  125. ;        Added DU: support for both source and destination while
  126. ;        not needing ZCPR3. Added destination existence checking
  127. ;        and auto erasure/manual prompting for erasure of destination
  128. ;        file of same name. (will abort processing if other than
  129. ;        a Y/y answer to delete file on destination. UNERASE now
  130. ;        works on specified user(if supplied before filename)
  131. ;            Eugene Nolan
  132. ;
  133. ;=============================================================================
  134.  
  135. ;        P R O G R A M    E Q U A T E S
  136.  
  137. ;=============================================================================
  138.  
  139.  
  140. VERSION    EQU    27
  141.  
  142. FALSE    EQU    0
  143. TRUE    EQU    NOT FALSE
  144.  
  145. ZCPR3    EQU    FALSE        ;true for ZCPR3 version, false for general CP/M
  146.  
  147. WHEEL    EQU    FALSE        ;true to test wheel byte before running
  148. WHLADR    EQU    3EH        ;wheel byte location
  149.  
  150. BDOS    EQU    0005H        ;BDOS entry address
  151. DMAADDR    EQU    0080H        ;default CP/M file buffer
  152. FCB    EQU    005CH        ;default CP/M FCB
  153. TFCB    EQU    006CH        ;temporary FCB
  154. Z3ENV    EQU    00000H        ;ZCPR3 environment address filled in by Z3INS
  155. CR    EQU    0DH            ;(z3env not presently needed anyway)
  156. LF    EQU    0AH
  157. TAB    EQU    09H
  158. BELL    EQU    07H
  159.  
  160. ;
  161. ;
  162. ;
  163. ;=============================================================================
  164.  
  165. ;        M A I N    P R O G R A M    C O D E
  166.  
  167. ;-----------------------------------------------------------------------------
  168.  
  169.  
  170.     ORG    0100H
  171.  
  172. MAKE:
  173.  
  174.     IF    ZCPR3
  175.  
  176.         ;ZCPR3 initialization (not actually needed here, but if one
  177.         ;runs the install program it will not report a bad utility)
  178.  
  179.     JMP    START
  180.     DB    'Z3ENV'
  181.     DB    1        ;external enviroment
  182.     DW    Z3ENV        ;environment address (value is not used here)
  183. START:
  184.  
  185.     ENDIF    ;ZCPR3
  186.  
  187.         ;set up local stack pointer
  188.  
  189.     LXI    H,0        ;get CP/M stack pointer
  190.     DAD    SP
  191.     SHLD    OLDSTK        ;save it for later return
  192.     LXI    SP,NEWSTK    ;set up new local stack
  193.  
  194.         ;perform setup tasks
  195.  
  196.      IF    WHEEL
  197.     LDA    WHLADR        ;get wheel byte
  198.     ORA    A        ;is it set? 
  199.     JZ    EREXIT        ;no/don't run
  200.      ENDIF            ;wheel
  201.  
  202.     CALL    SIGNON        ;print signon message
  203.  
  204.  
  205.     CALL    CHKHLP        ;see if help requested and go there if so
  206.  
  207.     IF    NOT ZCPR3    ;if ZCPR2, we assume correct version of CP/M
  208.     CALL    CHKVER        ;abort if not CP/M version 2.0 or later
  209.     ENDIF    ;NOT ZCPR3
  210.  
  211.     CALL    INIT        ;set up data areas
  212.  
  213.  
  214.     CALL    SETDU        ;handle current and specified DU areas
  215.     CALL    GETOPT        ;get option from command line (abort if bad)
  216.     CALL    CHKRO        ;abort if destination drive is R/O and option
  217.                 ;..requests change in files
  218.  
  219.         ;begin main work of program
  220.  
  221.     CALL    SRCHF        ;locate first directory entry (abort if none)
  222.  
  223. LOOP:    CALL    SETPTR        ;set DMAPTR to point to disk directory FCB
  224.     CALL    CHKFIL        ;check for applicable file
  225.     CNC    CALLOPT        ;if applicable file, process option
  226.  
  227. NEXTFIL:    ;go on to next file
  228.  
  229.     LXI    H,DIRCODE     ;point to the directory code
  230.     INR    M        ;increase it one
  231.     MOV    A,M        ;get new value
  232.     CPI    04        ;check for four FCB entries completed
  233.     JNZ    LOOP        ;if not, go back and continue
  234.  
  235.         ;process this group of four files and go on to next
  236.  
  237.     LXI    H,CHGFLAG    ;point to change flag
  238.     MOV    A,M        ;get it into A
  239.     MVI    M,0        ;reset it
  240.     ORA    A        ;set flags from original value
  241.     CNZ    WRTDE        ;if changes were made, write the buffer back
  242.  
  243.         ;sequence through files to get new buffer-full of FCB's
  244.  
  245. SRNXT:    LXI    D,AMBFIL    ;point to any-match FCB
  246.     MVI    C,12H        ;BDOS search-next function
  247.     CALL    BDOS
  248.     CPI    0FFH        ;see if end of entries
  249.     JZ    QUIT        ;quit if no more files
  250.     CPI    0        ;loop until buffer is updated by BDOS
  251.     JNZ    SRNXT        ;jump until dircode is zero
  252.     STA    DIRCODE     ;save the 0 in dircode
  253.     JMP    LOOP        ; and loop again
  254.  
  255. ;=============================================================================
  256.  
  257. ;    O P T I O N    P R O C E S S I N G    R O U T I N E S
  258.  
  259. ;-----------------------------------------------------------------------------
  260.  
  261. ; Set the file attribute to SYS.  If the file was not already SYS, then the
  262. ; CHGFLAG is set to indicate the need later to write the modified sector out
  263. ; to disk.
  264.  
  265. SETSYS:
  266.     LHLD    DMAPTR        ;point to disk directory FCB entry
  267.     LXI    D,10        ;offset 10 to DIR/SYS byte
  268.     DAD    D
  269.     MOV    A,M        ;get the SYS/DIR byte
  270.     ORA    A        ;test current state of SYS bit
  271.     CP    SETCHGFL    ;if not already SYS, set the change flag
  272.     ORI    80H        ;make sure it is set
  273.     MOV    M,A        ;write modified byte back out
  274.     CALL    REPORT        ;report the new file status
  275.     RET
  276.  
  277. ;-----------------------------------------------------------------------------
  278.  
  279. ; Set the file attribute to DIR.  If the file was not already DIR, then the
  280. ; CHGFLAG is set to indicate the need later to write the modified sector out
  281. ; to disk.
  282.  
  283. SETDIR:
  284.     LHLD    DMAPTR        ;point to disk directory FCB entry
  285.     LXI    D,10        ;offset 10 to SYS/DIR byte
  286.     DAD    D
  287.     MOV    A,M
  288.     ORA    A        ;sign flag shows state of SYS bit
  289.     CM    SETCHGFL    ;if not already DIR, set change flag
  290.     ANI    7FH        ;clear the DIR bit
  291.     MOV    M,A        ;write modified byte back to buffer
  292.     CALL    REPORT        ;report the new file status
  293.     RET
  294.  
  295. ;-----------------------------------------------------------------------------
  296.  
  297. ; Set the file attribute to R/O.  If the file was not already R/O, then the
  298. ; CHGFLAG is set to indicate the need later to write the modified sector out
  299. ; to disk.
  300.  
  301. SETRO:
  302.     LHLD    DMAPTR        ;point to disk directory FCB entry
  303.     LXI    D,9        ;offset 9 to R/O-R/W byte
  304.     DAD    D
  305.     MOV    A,M
  306.     ORA    A        ;test current state of R/O bit
  307.     CP    SETCHGFL    ;if not already R/O, set the change flag
  308.     ORI    80H        ;make sure it is set
  309.     MOV    M,A        ;write modified byte back out
  310.     CALL    REPORT        ;report the new file status
  311.     RET
  312.  
  313. ;-----------------------------------------------------------------------------
  314.  
  315. ; Set the file attribute to R/W.  If the file was not already R/W, then the
  316. ; CHGFLAG is set to indicate the need later to write the modified sector out
  317. ; to disk.
  318.  
  319. SETRW:
  320.     LHLD    DMAPTR        ;point to disk directory FCB entry
  321.     LXI    D,9        ;offset 9 to R/O-R/W byte
  322.     DAD    D
  323.     MOV    A,M
  324.     ORA    A        ;sign flag shows state of R/O-R/W bit
  325.     CM    SETCHGFL    ;if not already R/W, set change flag
  326.     ANI    7FH        ;clear the R/O bit
  327.     MOV    M,A        ;write modified byte back to buffer
  328.     CALL    REPORT        ;report the new file status
  329.     RET
  330. ;-----------------------------------------------------------------------------
  331. ; Set the file attribute to ARC.  If the file was not already ARC, then the
  332. ; CHGFLAG is set to indicate the need later to write the modified sector out
  333. ; to disk.
  334.  
  335. SETARC:
  336.     LHLD    DMAPTR        ;point to disk directory FCB entry
  337.     LXI    D,11        ;offset 10 to ARCHIVE byte
  338.     DAD    D
  339.     MOV    A,M        ;get the ARCHIVE byte
  340.     ORA    A        ;test current state of ARC bit
  341.     CP    SETCHGFL    ;if not already ARC, set the change flag
  342.     ORI    80H        ;make sure it is set
  343.     MOV    M,A        ;write modified byte back out
  344.     CALL    REPORT        ;report the new file status
  345.     RET
  346.  
  347. ;-----------------------------------------------------------------------------
  348.  
  349. ; RESET the ARCHIVE file attribute.  If the file was already ARC, then the
  350. ; CHGFLAG is set to indicate the need later to write the modified sector out
  351. ; to disk.
  352.  
  353. SETNRC:
  354.     LHLD    DMAPTR        ;point to disk directory FCB entry
  355.     LXI    D,11        ;offset 10 to ARCHIVE byte
  356.     DAD    D
  357.     MOV    A,M
  358.     ORA    A        ;sign flag shows state of ARC bit
  359.     CM    SETCHGFL    ;if it was ARC, set change flag
  360.     ANI    7FH        ;clear the ARC bit
  361.     MOV    M,A        ;write modified byte back to buffer
  362.     CALL    REPORT        ;report the new file status
  363.     RET
  364.  
  365. ;-----------------------------------------------------------------------------
  366.  
  367. ; Erase the file by writing E5 as the user number tag.  We know that the file
  368. ; is not already erased because of the work of subroutine CHKFIL earlier.
  369. ; Therefore, we must set the change flag to show the need to write the sector
  370. ; back out to disk.
  371.  
  372. ERASE:
  373.     LHLD    DMAPTR
  374.     MVI    M,0E5H
  375.     CALL    SETCHGFL    ;show need to write sector back to disk
  376.     CALL    REPORT        ;report the new file status
  377.     RET
  378.  
  379. ;-----------------------------------------------------------------------------
  380.  
  381. ; Unerase the file by writing the current user number into the tag byte in
  382. ; place of the E5.  The comments under ERASE apply here, too.
  383.  
  384. UNERA:
  385.     LDA    SRCUSR        ;get logged/specified in user number
  386.     LHLD    DMAPTR
  387.     MOV    M,A        ;put it into disk directory user # tag
  388.     CALL    SETCHGFL    ;show need to write sector back to disk
  389.     CALL    REPORT        ;report the new file status
  390.     RET
  391.  
  392. ;-----------------------------------------------------------------------------
  393.  
  394. ; Change the user number of the file.
  395.  
  396. CHUSER:    LDA    OPTION        ;get user number
  397.     LHLD    DMAPTR        ;point to place to put it
  398.     MOV    M,A        ;put new user number in directory
  399.     CALL    SETCHGFL    ;show need to write sector back out to disk
  400.     CALL    REPORT        ;report the new file status
  401.     RET
  402.  
  403. ;-----------------------------------------------------------------------------
  404.  
  405. ; This code reports the attributes of the files acted on and, if required,
  406. ; the erased or unerased status.  This code is called directly by the blank
  407. ; option and indirectly by all the other option processors after they have
  408. ; finished performing their changes on the files.
  409.  
  410. REPORT:    CALL    PRTFN        ;print the file name
  411.     CALL    ILPRT        ;print spacer and equal sign
  412.     DB    ' = ',0
  413.     CALL    PRTOPT        ;print the option letter or number
  414.     MVI    C,3        ;put in three more blank spaces
  415.     CALL    PRTBLK
  416.     CALL    PRTATTR        ;print file attributes
  417.     LDA    OPTION        ;see if files erased
  418.     CPI    'E'
  419.     CZ    PRTERA        ;if so, print erased message
  420.     LDA    OPTION
  421.     CPI    'U'        ;see if files unerased
  422.     CZ    PRTUNE        ;if so, print unerased message
  423.     RET
  424.  
  425.  
  426. ;=============================================================================
  427.  
  428. ;        P R O G R A M    F L O W    R O U T I N E S
  429.  
  430. ;-----------------------------------------------------------------------------
  431.  
  432. ;                CALLOPT
  433.  
  434. ; This routine uses the value of OPTION to look up the processing routine
  435. ; to which to branch.
  436.  
  437. CALLOPT:
  438.     LXI    H,JMPTBL    ;point to jump table
  439.     LDA    OPTION        ;get user number or option letter
  440.     MOV    B,A        ;save it in B
  441.  
  442. LOOKUP:    MOV    A,M        ;get option letter from table
  443.     INX    H        ;point to jump address
  444.     ORA    A        ;end of table?
  445.     JZ    JMPOPT2        ;if so, jump
  446.     CMP    B        ;do we match a table entry
  447.     JZ    JMPOPT1        ;if so, go to code to get jump address
  448.     INX    H        ;else jump over jump address to
  449.     INX    H        ;..next option character
  450.     JMP    LOOKUP        ;and try again
  451.  
  452. JMPOPT1:
  453.     MOV    A,M        ;get low part of jump address into A
  454.     INX    H        ;point to high part of address
  455.     MOV    H,M        ;get it into H
  456.     MOV    L,A        ;jump address is in HL
  457.     PCHL            ;jump to it
  458.  
  459. JMPOPT2:
  460.     LXI    H,CHUSER    ;default to change user routine
  461.     PCHL            ;jump to it
  462.  
  463. JMPTBL:    DB    ' '
  464.     DW    REPORT
  465.  
  466.     DB    'S'
  467.     DW    SETSYS
  468.  
  469.     DB    'D'
  470.     DW    SETDIR
  471.  
  472.     DB    'R'
  473.     DW    SETRO
  474.  
  475.     DB    'W'
  476.     DW    SETRW
  477.  
  478.     DB    'A'
  479.     DW    SETARC
  480.  
  481.     DB    'N'
  482.     DW    SETNRC
  483.  
  484.     DB    'E'
  485.     DW    ERASE
  486.  
  487.     DB    'U'
  488.     DW    UNERA
  489.  
  490.     DB    0        ;end of table mark
  491.  
  492. ;-----------------------------------------------------------------------------
  493.  
  494. ;                QUIT
  495.  
  496. ; This code sends a CRLF to the console, restores the original CP/M stack,
  497. ; and returns to CP/M.  If indicated by the reset flag, it resets the disk
  498. ; system.  The logged DU area when the program was invoked is restored.  The
  499. ; entry point QUIT2 is used by code (CHKHLP and CHKVER) that have not changed
  500. ; the logged in directory.
  501.  
  502. QUIT:    CALL    CRLF
  503.  
  504.         ;log in the original drive/user
  505.  
  506.     LDA    DEFDRV        ;get original default drive
  507.     CALL    LOGDRV        ;log it in
  508.     LDA    DEFUSR        ;get original default user
  509.     CALL    LOGUSR        ;log it in
  510.  
  511.         ;see if we need to reset the disk system
  512.  
  513. QUIT1:    LDA    RSTFLAG
  514.     ORA    A        ;if reset flag is clear
  515.     JZ    QUIT2        ;..we can skip disk system reset
  516.  
  517.         ;reset the disk system
  518.  
  519.     MVI    C,0DH
  520.     CALL    BDOS
  521.  
  522.         ;restore the original stack
  523.  
  524. QUIT2:    LHLD    OLDSTK        ;get original stack pointer
  525.     SPHL            ;set it up
  526.     RET            ;back to CP/M
  527.  
  528.      IF    WHEEL
  529. EREXIT:                ;if using wheel byte and wheel not set
  530.     CALL    ILPRT        ;we pretend the program doesn't exist
  531.     DB    'MAKE?',0    ;by printing phony CCP error.
  532.     JMP    QUIT2
  533.      ENDIF            ;wheel
  534.  
  535. ;=============================================================================
  536.  
  537. ;    F I L E    S E L E C T I O N    S U B R O U T I N E S
  538.  
  539. ;-----------------------------------------------------------------------------
  540.  
  541. ;                CHKFIL
  542.  
  543. ; This subroutine checks to see whether or not the FCB pointed to in the
  544. ; DMA buffer is one that should be acted on.  If not, the routine returns
  545. ; with the zero flag set.
  546.  
  547. CHKFIL:    CALL    CHKUN        ;check user number and erased status of file
  548.     RC            ;return with carry set to skip file
  549.     CALL    CHKFN        ;next check the file name for a match
  550.     RET            ;return showing status of name match
  551.  
  552. ;-----------------------------------------------------------------------------
  553.  
  554. ;                CHKUN
  555.  
  556. ; This subroutine checks the user number status of a file and sets the carry
  557. ; flag if the file should be skipped over.  If the option is UNERASE and the
  558. ; file is not an erased file, it should be skipped.  If the option is not
  559. ; unerase and the file is an erased file, then likewise it should be skipped.
  560. ; Finally, if the file is in a user number other than the logged in user, it
  561. ; should also be skipped.
  562.  
  563. CHKUN:        ;test file erased status
  564.  
  565.     LHLD    DMAPTR        ;point to user number tag of file
  566.     MOV    A,M        ;get the tag
  567.     CPI    0E5H        ;carry flag set if not erased
  568.     PUSH    PSW        ;save flag
  569.     
  570.         ;test program option status
  571.  
  572.     LDA    OPTION        ;get the option
  573.     CPI    'U'        ;is it unerase?
  574.     JNZ    CHKUN1        ;if not, skip to CHKUN1
  575.  
  576.         ;case of unerase option
  577.  
  578.     POP    PSW        ;carry flag set if not erased
  579.     RET            ;file not erased will be skipped
  580.  
  581.         ;case of option other than unerase
  582.  
  583. CHKUN1:    POP    PSW
  584.     CMC            ;carry flag set if file erased
  585.     RC            ;erased file will be skipped
  586.  
  587.         ;now check for user number in source area
  588.  
  589.     LDA    ALLUSR        ;see if "all users" was requested
  590.     CPI    '#'        ;
  591.     JZ    CHKUN2        ;if so, skip over compare...
  592.     LDA    SRCUSR        ;get source user number
  593.     CMP    M        ;compare to file tag
  594.     RZ            ;if OK, return (carry is clear)
  595.     STC            ;else set carry
  596. CHKUN2:
  597.     RET            ;..and return
  598.  
  599. ;-----------------------------------------------------------------------------
  600.  
  601. ;                CHKFN
  602.  
  603. ; This subroutine compares the name of the file in the FCB in the DMA buffer
  604. ; with the specification from the command line.
  605.  
  606. CHKFN:        ;set up pointers and character count
  607.  
  608.     LHLD    DMAPTR        ;get pointer to FCB in DMA buffer
  609.     INX    H        ;point to first character in the name
  610.     LXI    D,FCB+1     ;set DE to name in FCB from command line
  611.     MVI    C,0BH        ;load count for compare
  612.  
  613. CP1:    LDAX    D        ;get fcb command line character
  614.     CPI    '?'        ;see if anything matches
  615.     JZ    MATCH        ;if it is '?', consider it a match
  616.     SUB    M        ;get difference (see next instruction)
  617.     ANI    7FH        ;clear attribute bit
  618.     JZ    MATCH        ;if zero, characters match
  619.     STC            ;else set carry
  620.     RET            ;..and return
  621.  
  622. MATCH:    INX    D        ;point to next characters
  623.     INX    H
  624.     DCR    C        ;decrease count of characters
  625.     JNZ    CP1        ;loop until zero
  626.     RET            ;carry is clear showing names match
  627.  
  628.  
  629.  
  630. ;=============================================================================
  631.  
  632. ;    D I S K    O P E R A T I O N    S U B R O U T I N E S
  633.  
  634. ;-----------------------------------------------------------------------------
  635.  
  636. ;                SRCHF
  637.  
  638. ; This subroutine uses the fully ambiguous file spec at AMBFIL to locate the
  639. ; first directory entry on the disk.  The directory code (0-3) is saved. If
  640. ; no directory entry is found, then the program gives a message and branches
  641. ; to QUIT for a prompt return.
  642.  
  643. SRCHF:    LXI    D,AMBFIL    ;point to match any filename.typ
  644.     MVI    C,11H        ;bdos search first function
  645.     CALL    BDOS        ;do it
  646.     STA    DIRCODE     ;save directory code
  647.     CPI    0FFH        ;see if end of entries
  648.     RNZ            ;if something found, return
  649.     CALL    ILPRT        ;else give a message
  650.     DB    BELL,CR,LF
  651.     DB    'No Files On Disk',CR,LF,0
  652.     JMP    QUIT
  653.  
  654. ;-----------------------------------------------------------------------------
  655.  
  656. ;                WRTDE
  657.  
  658. ; This routine writes the directory buffer back to the disk.  I also sets the
  659. ; reset flag so that the disk system will be reset on program termination.
  660.  
  661. WRTDE:    LXI    H,RSTFLAG    ;point to the flag
  662.     MVI    M,0FFH        ;set the flag
  663.     MVI    C,1H        ;set BIOS write to directory
  664.                 ; C = 0   write to allocated
  665.                 ; C = 1   write to directory
  666.                 ; C = 2   write to unallocated
  667.     CALL    WRITE        ;do the write
  668.     ORA    A        ;check for error
  669.     RZ            ;if none, return
  670.  
  671.     CALL    ILPRT
  672.     DB    BELL
  673.     DB    CR,LF
  674.     DB    'Bad Sector Write Error',CR,LF,0
  675.  
  676.     JMP    QUIT
  677.  
  678. ;-----------------------------------------------------------------------------
  679.     
  680. ;                WRITE
  681.  
  682. ; This routine is filled in during the operation of the program and performs
  683. ; a direct BIOS sector write operation on the currently selected track and
  684. ; sector.
  685.  
  686. WRITE:    JMP    0000        ;vector to bios write routine
  687.  
  688.  
  689. ;=============================================================================
  690.  
  691. ;        P R I N T I N G    R O U T I N E S
  692.  
  693. ;-----------------------------------------------------------------------------
  694.  
  695. ;                PRTFN
  696.  
  697. ; This subroutine displays (at the beginning of the next line of the screen)
  698. ; the name of the file pointed to in the DMA buffer.
  699.  
  700. PRTFN:    CALL    CRLF        ;print cr/lf
  701.     LHLD    DMAPTR        ;address of file fcb
  702.     INX    H        ;skip to file name
  703.     LXI    D,BLNKCNT    ;point to blanks counter
  704.     XCHG            ;exchange pointers
  705.     MVI    M,0        ;preset blank count to zero
  706.  
  707.     MVI    C,8        ;length of file name
  708.     CALL    PRTSTR        ;print the name first
  709.  
  710.     MVI    A,'.'        ;print the period
  711.     CALL    CHAROUT
  712.  
  713.     MVI    C,3        ;now print the file type
  714.     CALL    PRTSTR
  715.  
  716.     MOV    C,M        ;get number of blanks needed for fill
  717.     CALL    PRTBLK        ;print the blanks
  718.     RET
  719.  
  720. ;-----------------------------------------------------------------------------
  721.  
  722. ;                PRTOPT
  723.  
  724. ; This subroutine prints out the option as a letter or as a number as
  725. ; appropriate.
  726.  
  727. PRTOPT:    LDA    OPTION        ;get the option value
  728.     CPI    20H        ;if it's a user number, carry will be set
  729.     JNC    CHAROUT        ;if not number, just print the character
  730.     MVI    B,'0'-1        ;preset for two-digit calculation later
  731.     CPI    10        ;see if single digit
  732.     JNC    TWODIG        ;if not, print two digits
  733.     ADI    '0'        ;else convert to ASCII
  734.     JMP    CHAROUT        ;and print it
  735. TWODIG:    INR    B        ;count tens digit in B
  736.     SUI    10        ;keep subtracting 10 until carry is set
  737.     JNC    TWODIG
  738.     ADI    10        ;get remainder (units digit) back
  739.     MOV    C,A        ;save it in C
  740.     MOV    A,B        ;print tens digit
  741.     CALL    CHAROUT
  742.     MOV    A,C        ;print units digit
  743.     ADI    '0'
  744.     JMP    CHAROUT
  745.  
  746. ;-----------------------------------------------------------------------------
  747.  
  748. ;                PRTATTR
  749.  
  750. ; This subroutine prints the attribute status (SYS or DIR and R/O or R/W)
  751. ; of the file currently being worked on.
  752.  
  753. PRTATTR:
  754.     LHLD    DMAPTR        ;point to file FCB
  755.     LXI    D,9        ;offset to R/O-R/W byte
  756.     DAD    D
  757.     PUSH    H        ;save pointer for reuse below
  758.     MOV    A,M
  759.     RAL            ;move R/O bit into carry
  760.     PUSH    PSW        ;save flags
  761.     CC    PRTRO        ;if carry, print read-only
  762.     POP    PSW        ;get flags back to test again
  763.     CNC    PRTRW        ;if not carry, print read-write
  764.  
  765.     POP    H        ;get pointer back
  766.     INX    H        ;point to SYS/DIR byte
  767.     PUSH    H        ;save pointer for reuse below
  768.     MOV    A,M
  769.     RAL            ;move SYS/DIR bit into carry
  770.     PUSH    PSW        ;save flags
  771.     CC    PRTSYS        ;if carry, print SYS
  772.     POP    PSW        ;get them back
  773.     CNC    PRTDIR        ;if not carry, print DIR
  774.     POP    H
  775.     INX    H
  776.     MOV    A,M
  777.     RAL            ;move ARCHIVE bit into carry
  778.     PUSH    PSW        ;save flags
  779.     CC    PRTARC        ;if carry, print ARC
  780.     POP    PSW        ;get them back
  781.     CNC    PRTNRC        ;if not carry, print Non-ARC
  782.     RET
  783.     
  784. ;-----------------------------------------------------------------------------
  785.  
  786. ;    MESSAGE PRINTING ROUTINES
  787.  
  788. PRTRO:    CALL    ILPRT        ;file is read-only
  789.     DB    '  R/O',0
  790.     RET
  791.  
  792. PRTRW:    CALL    ILPRT        ;file is read-write
  793.     DB    '  R/W',0
  794.     RET
  795.  
  796. PRTSYS:    CALL    ILPRT        ;file has SYS attribute
  797.     DB    '  SYS',0
  798.     RET
  799.  
  800. PRTDIR:    CALL    ILPRT        ;file has DIR attribute
  801.     DB    '  DIR',0
  802.     RET
  803.  
  804. PRTARC:    CALL    ILPRT        ;file has ARC attribute
  805.     DB    '  ARCHIVE',0
  806.     RET
  807.  
  808. PRTNRC:    CALL    ILPRT        ;file has NO ARC attribute
  809.     DB    '  Non-ARC',0
  810.     RET
  811.  
  812. PRTERA:    CALL    ILPRT        ;file erased
  813.     DB    '   *** ERASED ***',0
  814.     RET
  815.  
  816. PRTUNE:    CALL    ILPRT        ;file unerased
  817.     DB    '   *** UNERASED ***',0
  818.     RET
  819.  
  820. ;-----------------------------------------------------------------------------
  821.  
  822. ;                HELP
  823.  
  824. ; This code displays the built in help screen and then jumps to QUIT to
  825. ; return to CP/M.
  826.  
  827. HELP:    CALL    ILPRT
  828.     DB    CR,LF 
  829.     DB    TAB,'Syntax:  '
  830.  
  831.     IF    ZCPR3
  832.     DB    'MAKE [DIR:]AMBIG.FIL X[#]',CR,LF,LF
  833.     DB    '* where DIR: is an optional directory specifier',CR,LF
  834.     DB    '  using either the DU: or named directory format',CR,LF,LF
  835.     ENDIF    ;ZCPR3
  836.  
  837.     IF    NOT ZCPR3
  838.     DB    'MAKE [DU:][D:][U:]AMBIG.FIL [X][#][ /O]',CR,LF,LF
  839.     DB    '* where DU: is an optional drive-user,drive,user specifier'
  840.     db    CR,LF
  841.     DB    '  and /O cause auto delete of file on destination',cr,lf
  842.     ENDIF    ;NOT ZCPR3
  843.  
  844.     DB    '* and where `X'' may be ONE of the options:',CR,LF,LF
  845.  
  846.     IF    ZCPR3
  847.     DB    TAB,'DIR:',TAB,'Moves files to named directory DIR',CR,LF
  848.     ENDIF    ;ZCPR3
  849.  
  850.     DB    TAB,'U ,U:, DU:   ','Moves files to user # U (0-31)',CR,LF,LF
  851.     DB    'The following operate in the current user area.',CR,LF
  852.     DB    'Add a  #  to act on ALL user areas at once.',CR,LF,LF
  853.     DB    TAB,'S',TAB,'Sets file attribute(s) to SYSTEM',CR,LF
  854.     DB    TAB,'D',TAB,'Sets file attribute(s) to DIRECTORY',CR,LF
  855.     DB    TAB,'R',TAB,'Sets file attribute(s) to READ/ONLY',CR,LF
  856.     DB    TAB,'W',TAB,'Sets file attribute(s) to READ/WRITE',CR,LF
  857.     DB    TAB,'A',TAB,'Sets file attribute(s) to ARCHIVE',CR,LF
  858.     DB    TAB,'N',TAB,'Sets file attribute(s) to NON-ARCHIVE',CR,LF
  859.     DB    TAB,'E',TAB,'Erases the specified files',CR,LF
  860.     DB    TAB,'U',TAB,'Unerases the specified files',CR,LF,0
  861.  
  862.     JMP    QUIT2
  863.  
  864.  
  865. ;=============================================================================
  866.  
  867. ;    G E N E R A L - P U R P O S E   S U B R O U T I N E S
  868.  
  869. ;-----------------------------------------------------------------------------
  870.  
  871. ;                CRTOUT
  872.  
  873. ; This subroutine sends the character in register A to the console.  Registers
  874. ; BC, DE, and HL are preserved.
  875.  
  876. CHAROUT:
  877.  
  878.     PUSH    H        ;save registers
  879.     PUSH    D
  880.     PUSH    B
  881.     MOV    E,A        ;get character into E
  882.     MVI    C,06        ;BDOS direct console I/O
  883.     CALL    BDOS
  884.     POP    B        ;restore registers
  885.     POP    D
  886.     POP    H
  887.     RET
  888.  
  889. ;-----------------------------------------------------------------------------
  890.  
  891. ;                CRLF
  892.  
  893. ; This routine sends a carriage return and linefeed to the console.
  894.  
  895. CRLF:    CALL    ILPRT
  896.     DB    CR,LF,0
  897.     RET
  898.  
  899.  
  900. ;-----------------------------------------------------------------------------
  901.  
  902. ;                FILL
  903.  
  904. ; This subroutine fills memory starting at HL for a length B with the byte
  905. ; in A.
  906.  
  907. FILL:
  908.     MOV    M,A
  909.     INX    H
  910.     DCR    B
  911.     JNZ    FILL
  912.     RET
  913.  
  914. ;-----------------------------------------------------------------------------
  915.  
  916. ;                ILPRT
  917.  
  918. ; This subroutine prints the string that follows its call.  The string must
  919. ; be terminated with a null (0).
  920.  
  921. ILPRT:    POP    H    ;get address following call into HL
  922.  
  923. ILPRT1:    MOV    A,M    ;get character from message
  924.     INX    H    ;point to next character
  925.     ORA    A    ;test for null indicating end of message
  926.     JZ    ILPRT2    ;if end, fix up return address
  927.     MOV    E,A    ;have BDOS send character it to console
  928.     MVI    C,2
  929.     PUSH    H    ;save pointer to string
  930.     CALL    BDOS
  931.     POP    H    ;restore pointer
  932.     JMP    ILPRT1    ;process it
  933.  
  934. ILPRT2:    PUSH    H    ;set up return address to just past message
  935.     RET
  936.  
  937. ;-----------------------------------------------------------------------------
  938.  
  939. ;                PRTSTR
  940.  
  941. ; This subroutine prints a string of characters pointed to by DE.  The number
  942. ; of characters is in the C register.  Blanks are not printed; instead, the
  943. ; blanks counter pointed to by HL is incremented.
  944.  
  945. PRTSTR:    LDAX    D        ;get character
  946.     CPI    ' '        ;see if it is a blank
  947.     CZ    UPCOUNT        ;if so, up the count
  948.     CNZ    CHAROUT        ;if not, output the character
  949.     INX    D
  950.     DCR    C        ;check count
  951.     JNZ    PRTSTR
  952.     RET
  953.  
  954. UPCOUNT:
  955.     PUSH    PSW        ;save flags
  956.     INR    M        ;increase the blank counter
  957.     POP    PSW        ;restore flags
  958.     RET
  959.  
  960. ;-----------------------------------------------------------------------------
  961.  
  962. ;                PRTBLK
  963.  
  964. ; This subroutine prints blank spaces given by the count in C.  The routine
  965. ; will work even for a count of zero.
  966.  
  967. PRTBLK:    INR    C        ;turn 0 into 1
  968. PRTBL1:    DCR    C        ;check count
  969.     RZ            ;return if count exhausted
  970.     MVI    A,' '        ;set character to print
  971.     CALL    CHAROUT
  972.     JMP    PRTBL1
  973.  
  974.  
  975. ;=============================================================================
  976.  
  977. ;        S E T U P    S U B R O U T I N E S
  978.  
  979. ;-----------------------------------------------------------------------------
  980.  
  981. ;                SIGNON
  982.  
  983. ; This subroutine displays the program signon message.
  984.  
  985. SIGNON:    CALL    ILPRT
  986.     DB    CR,LF,'MAKE  -  Version '
  987.     DB    VERSION / 10 + '0'
  988.     DB    '.'
  989.     DB    VERSION MOD 10 + '0'
  990.  
  991.     IF    ZCPR3
  992.     DB    ' for ZCPR3'
  993.     ENDIF    ;ZCPR3
  994.  
  995.     DB    CR,LF,0
  996.     RET
  997.  
  998. ;-----------------------------------------------------------------------------
  999.  
  1000. ;                CHKHLP
  1001.  
  1002. ; This subroutine checks to see if the user has invoked the program in a
  1003. ; way to request the built-in help screen.  The help screen is shown if the
  1004. ; command has no tail or if the tail begins with a slash.
  1005.  
  1006. CHKHLP:    LDA    FCB+1        ;get first character of first parameter
  1007.     CPI    ' '        ;no name?
  1008.     JZ    HELP        ;if so, go to HELP
  1009.     CPI    '/'        ;parameter starts with slash?
  1010.     JZ    HELP        ;if so, go to HELP
  1011.     RET            ;return with flag set appropriately
  1012.  
  1013. ;-----------------------------------------------------------------------------
  1014.  
  1015. ;                CHKVER
  1016.  
  1017. ; This subroutine checks for a valid version number (one that supports user
  1018. ; numbers).  If it is not valid, then this routine displays and error message
  1019. ; and jumps to QUIT2.
  1020.  
  1021.     IF    NOT ZCPR3
  1022.  
  1023. CHKVER:    MVI    C,0CH        ;bdos version number function
  1024.     CALL    BDOS
  1025.     CPI    20H        ;make sure 2.0 or more
  1026.     RNC            ;return if OK
  1027.     CALL    ILPRT        ;else print error message
  1028.     DB    BELL,CR,LF
  1029.     DB    'Requires CP/M version 2.0 or higher.',CR,LF,0
  1030.     JMP    QUIT2        ;terminate program
  1031.  
  1032.     ENDIF    ;NOT ZCPR3
  1033.  
  1034. ;-----------------------------------------------------------------------------
  1035.  
  1036. ;                INIT
  1037.  
  1038. ; This subroutine initializes the data areas in the program so that GO
  1039. ; command will re-run the program correctly.
  1040.  
  1041. INIT:    XRA    A        ;zero the accumulator
  1042.     STA    CHGFLAG        ;preset control flags
  1043.     STA    RSTFLAG
  1044.     STA    DIRCODE
  1045.  
  1046.     LXI    H,AMBFIL2
  1047.     MVI    B,16
  1048.     CALL    FILL        ;clear the fcb
  1049.  
  1050.     MVI    A,'?'
  1051.     MVI    B,16
  1052.     LXI    H,AMBFIL
  1053.     CALL    FILL
  1054.  
  1055.     LHLD    0001        ;get warmboot address (base of bios + 3)
  1056.     LXI    D,27H        ;offset for jump to bios write
  1057.     DAD    D        ;compute address for write routine
  1058.     SHLD    WRITE + 1    ;load our vector with this address
  1059.  
  1060.     RET
  1061.  
  1062. ;-----------------------------------------------------------------------------
  1063.  
  1064. ;                SETDU
  1065.  
  1066. ; This subroutine gets and saves the values of the currently logged in drive
  1067. ; and user area and the drive and user specified (if any) on the command line
  1068. ; for the files to be operated on.
  1069.  
  1070. SETDU:        ;get currently logged in user number
  1071.  
  1072.     MVI    C,20H        ;BDOS get/set user number function
  1073.     MVI    E,0FFH        ;get user flag
  1074.     CALL    BDOS
  1075.     STA    DEFUSR
  1076.     STA    SRCUSR        ;save for now as source user also
  1077.  
  1078.         ;get the currently logged in drive
  1079.  
  1080.     MVI    C,19H        ;bdos get drive number function
  1081.     CALL    BDOS        ;get drive number
  1082.     STA    DEFDRV
  1083.     INR    A        ;change range 1-16 and
  1084.     STA    SRCDRV        ;..save for now as source drive also
  1085.     
  1086.  
  1087.     CALL    PARSEM        ;parse command tail to FCB's
  1088.                 ;(only look for /O if ZCPR3)
  1089.  
  1090.         ;now log in the drive and user in file spec
  1091.  
  1092.     LDA    FCB        ;get drive spec from FCB
  1093.     ORA    A        ;see if default specified
  1094.     JZ    SETDU1
  1095.     STA    SRCDRV        ;save source drive
  1096.     SUI    1        ;get in range 0-15
  1097.     CALL    LOGDRV        ;log in the drive
  1098.     XRA    A        ;and change FCB to show default drive
  1099.     STA    FCB
  1100.  
  1101.  
  1102.     LDA    FCB+13        ;get user number from S1 byte
  1103.     STA    SRCUSR        ;save as source user area
  1104.     CALL    LOGUSR        ;log in the user number
  1105. SETDU1:
  1106.  
  1107.     RET
  1108.  
  1109. ;-----------------------------------------------------------------------------
  1110.  
  1111. ; These two routines log in the drive or user number given in the A register.
  1112. ; No registers are preserved.
  1113.  
  1114.  
  1115. LOGDRV:    MOV    E,A
  1116.     MVI    C,0EH
  1117.     CALL    BDOS
  1118.     RET
  1119.  
  1120. LOGUSR:    MOV    E,A
  1121.     MVI    C,20H
  1122.     CALL    BDOS
  1123.     RET
  1124.  
  1125. ;-----------------------------------------------------------------------------
  1126.  
  1127. ;                GETOPT
  1128.  
  1129. ; Process option specified on the command line.  If there is an error, the
  1130. ; routine jumps to HELP which in turn jumps to QUIT.  If a named directory
  1131. ; is specified for the destination on the command line, then its user number
  1132. ; is obtained from address TFCB+13.  The drive is checked to make sure that
  1133. ; the destination is on the same drive.
  1134.  
  1135. GETOPT:
  1136.  
  1137.  
  1138.         ;check for destination specified using DU/named directory
  1139.  
  1140.     LDA    TFCB        ;check for drive number
  1141.     ORA    A        ;if zero, no DIR: or DU: given
  1142.     JZ    GETOPT1
  1143.  
  1144.         ;check for correct drive spec
  1145.  
  1146.     LXI    H,SRCDRV    ;point to source drive value
  1147.     CMP    M
  1148.     JNZ    BADDRV        ;if not the same, jump to bad drive message
  1149.  
  1150.         ;get the user number
  1151.  
  1152.     LDA    TFCB + 13
  1153.     STA    OPTION        ;store user number as option
  1154.     JMP    CHKNUM        ;check for valid user number
  1155.  
  1156. BADDRV:    CALL    ILPRT        ;destination and source drives not same
  1157.     DB    BELL
  1158.     DB    CR,LF,LF
  1159.     DB    'Source and Destination Drives',CR,LF
  1160.     DB    'Must be the Same'
  1161.     DB    CR,LF
  1162.     DB    0
  1163.     JMP    QUIT
  1164.  
  1165.  
  1166. GETOPT1:
  1167.     LXI    H,TFCB        ;point to parsed second parameter
  1168.     MOV    A,M        ;make sure it wasn't of form 'D:'
  1169.     ORA    A        ;drive byte should be zero
  1170.     JNZ    BADOPT
  1171.     INX    H        ;now look at data entered
  1172.  
  1173.     MOV    A,M        ;get the first character
  1174.     CALL    GETNUM        ;try to read it as a number
  1175.     JC    LETTER        ;if not, must be a letter or bad
  1176.     MOV    B,A        ;save digit in B
  1177.     STA    OPTION        ;..and as interim option
  1178.     INX    H        ;try next character
  1179.     MOV    A,M
  1180.     CPI    ' '        ;if it is a blank
  1181.     JZ    CHKNUM        ;..go to test user number value
  1182.  
  1183.     CALL    GETNUM        ;see if second character is a number
  1184.     JC    BADOPT        ;if not, we have a bad option spec
  1185.  
  1186.     MOV    C,A        ;save second digit
  1187.     MOV    A,B        ;get first digit back
  1188.     ADD    A        ;double it three times to make 8x
  1189.     ADD    A
  1190.     ADD    A
  1191.     ADD    B        ;now add original in twice to make 10x
  1192.     ADD    B
  1193.     ADD    C        ;finally, add in second digit
  1194.     STA    OPTION        ;..and save the final result
  1195.  
  1196.         ;check for valid user number (in range and not same
  1197.         ;as logged in user number)
  1198.  
  1199. CHKNUM:    LDA    OPTION        ;make sure we have the user number
  1200.     CPI    32        ;test for valid user number range
  1201.     JNC    BADNUM
  1202.     LXI    H,SRCUSR    ;see if same as source user
  1203.     CMP    M
  1204.     JZ    SAMENUM        ;if so, give message
  1205.     CALL    LOGUSR
  1206.     LXI    D,FCB        ;See if file exists on destination
  1207.     MVI    C,11H
  1208.     CALL    BDOS
  1209.     CPI    0FFH
  1210.     JNZ    FNDDES        ;NZ=yes
  1211.     LDA    SRCUSR        ;no, relog user
  1212.     CALL    LOGUSR
  1213.     RET
  1214. FNDDES:
  1215.     CALL    ILPRT
  1216.     DB    BELL,CR,LF,"EXISTS ON DESTINATION",0
  1217.     LDA    OVRWRT        ;Auto overwrite?(/O)
  1218.     ORA    A
  1219.     JZ    NFNDOV        ;Z=no
  1220. FNDOVR:
  1221.     LXI    D,FCB        ;Delete file on destination user
  1222.     MVI    C,19
  1223.     CALL    BDOS
  1224.     CALL    ILPRT
  1225.     DB    " - DELETED",CR,LF,0
  1226.     RET
  1227. NFNDOV:
  1228.     CALL    ILPRT
  1229.     DB    " >>DELETE(Y/N)? ",0
  1230.     MVI    C,1        ;Query operator as to what to do
  1231.     CALL    BDOS
  1232.     CPI    "Y"
  1233.     JZ    FNDOVR
  1234.     CPI    "y"
  1235.     JZ    FNDOVR
  1236.     JMP    QUIT2        ;abort if not a yes answer
  1237.  
  1238. LETTER:        ;check for valid letter option
  1239.     PUSH    PSW        ;save option letter
  1240.     INX    H        ;check whether option followed by '#'
  1241.     MOV    A,M        
  1242.     CPI    '#'
  1243.     JNZ    LETTER0        ;not "all users" switch, don't save it
  1244.     STA    ALLUSR
  1245. LETTER0:
  1246.     POP    PSW        ;get option character back
  1247.     LXI    H,OPTLIST    ;point to list of valid options
  1248.     MOV    C,M        ;get number of options in list
  1249. LETTER1:            ;loop through them checking
  1250.     INX    H
  1251.     CMP    M        ;compare to list entry
  1252.     JZ    GOODOPT        ;if it matches, we have a good option
  1253.     DCR    C        ;else, count down
  1254.     JNZ    LETTER1        ;..and try again
  1255.     JMP    HELP        ;we get here if option is not valid
  1256.  
  1257. GOODOPT:    ;we have a good option letter
  1258.     STA    OPTION
  1259.     RET
  1260.  
  1261. BADOPT:        ;we have a bad option specifier
  1262.     CALL    ILPRT
  1263.     DB    BELL,CR,LF
  1264.     DB    TAB,'****  BAD OPTION SPECIFIER  ****',CR,LF,0
  1265.     JMP    HELP
  1266.  
  1267. BADNUM:        ;we have an illegal user number
  1268.     CALL    ILPRT
  1269.     DB    BELL,CR,LF
  1270.     DB    TAB,'****  ILLEGAL USER NUMBER  ****',CR,LF,0
  1271.     JMP    HELP
  1272.  
  1273. SAMENUM:    ;give message about already in that user area
  1274.     CALL    ILPRT
  1275.     DB    BELL,CR,LF
  1276.     DB    'Destination User Number is the',CR,LF
  1277.     DB    'Same as the Source User Number'
  1278.     DB    CR,LF,0
  1279.     JMP    QUIT
  1280.  
  1281.         ;subroutine to check for number character
  1282.         ;returns with carry set if not a number
  1283.  
  1284. GETNUM:    CPI    '0'        ;see if less than '0'
  1285.     RC            ;if so, set carry flag as signal
  1286.     CPI    '9'+1        ;see if more than '9'
  1287.     CMC            ;reverse sense of carry flag
  1288.     RC            ;if >9, return with carry set
  1289.     SUI    '0'        ;convert to number value
  1290.     RET            ;carry is clear
  1291.  
  1292.         ;list of valid options
  1293.  
  1294. OPTLIST:
  1295.     DB    ENDLIST-OPTLIST    ;number of options in list
  1296.     DB    ' SDRWANEU'    ;valid options
  1297. ENDLIST:
  1298.  
  1299. ;-----------------------------------------------------------------------------
  1300.  
  1301. ;                CHKRO
  1302.  
  1303. ; This routine checks to see if the destination drive is read-only.  If it
  1304. ; is, an appropriate error message is displayed and the program aborts with
  1305. ; a jump to QUIT.  If the option is display only (option = space char), then
  1306. ; this test is skipped.
  1307.  
  1308.  
  1309. CHKRO:    LDA    OPTION        ;see if display option is in effect
  1310.     CPI    ' '
  1311.     RZ            ;if so, skip rest of test
  1312.  
  1313.     MVI    C,1DH        ;get R/O vector from BDOS
  1314.     CALL    BDOS
  1315.  
  1316.         ;calculate number of left-shifts needed
  1317.  
  1318.     LDA    SRCDRV        ;get the target drive number
  1319.     CMA            ;complement it (makes 255-SRCDRV)
  1320.     ADI    17        ;makes A = 16 - SRCDRV (value 1-16)
  1321.  
  1322.         ;shift word in HL to put bit of R/O vector for
  1323.         ;specified drive into high bit position
  1324.  
  1325. CHKRO1:    DCR    A        ;test for done
  1326.     JZ    CHKRO2        ;if so, jump
  1327.     DAD    H        ;shift HL to left
  1328.     JMP    CHKRO1        ;and loop
  1329.  
  1330. CHKRO2:    DAD    H        ;move high bit into carry flag
  1331.     RNC            ;if not R/O, return
  1332.     CALL    ILPRT        ;else print R/O error message
  1333.     DB    BELL,CR,LF
  1334.     DB    'Drive is set to R/O',CR,LF,0
  1335.  
  1336.     JMP    QUIT        ;abort program
  1337.  
  1338.  
  1339. ;=============================================================================
  1340.  
  1341. ;        M I S C E L L A N E O U S    R O U T I N E S
  1342.  
  1343. ;-----------------------------------------------------------------------------
  1344.  
  1345. ;                SETPTR
  1346.  
  1347. ; This subroutine uses the value of the directory code to calculate a pointer
  1348. ; to the FCB in the DMA buffer.  This is done by multiplying the directory code
  1349. ; by 32 and adding it to the DMA address (DMAADDR).  The result is saved in
  1350. ; DMAPTR.
  1351.  
  1352. SETPTR:
  1353.     LDA    DIRCODE     ;get the directory code
  1354.     ADD    A        ;offset by 32 bytes per entry
  1355.     ADD    A
  1356.     ADD    A
  1357.     ADD    A
  1358.     ADD    A
  1359.     MOV    E,A        ;move value into DE
  1360.     MVI    D,0
  1361.     LXI    H,DMAADDR    ;get buffer address
  1362.     DAD    D        ;compute offset into buffer
  1363.     SHLD    DMAPTR        ;save the address into the buffer
  1364.     RET
  1365.  
  1366. ;-----------------------------------------------------------------------------
  1367.  
  1368. ;                SETCHGFL
  1369.  
  1370. ; This subroutine sets the change-flag to show that the directory sector
  1371. ; has been modified and needs to be written out to disk.
  1372.  
  1373. SETCHGFL:
  1374.     PUSH    PSW
  1375.     MVI    A,0FFH        ;set the sector change flag
  1376.     STA    CHGFLAG
  1377.     POP    PSW
  1378.     RET
  1379.  
  1380. ;
  1381. ;
  1382. ;
  1383. ;This section adds complete parseing of command line tail held at
  1384. ; 80h in to the FCB's into a form compatible with ZCPR3's DU: form.
  1385.  
  1386. CHRCNT    EQU    80H
  1387.  
  1388. PARSEM:
  1389.  
  1390.     LXI    H,CHRCNT    ; Point to character count
  1391.     MOV    A,M        ; Get character count
  1392.     INX    H        ; Pt to first character of command line
  1393.     CALL    ADDAH        ; Pt to after last char of command line
  1394.     MVI    M,0        ; Store ending zero
  1395.     LXI    H,CHRCNT+1    ; First char of command line
  1396.     SHLD    NXTCHR
  1397.     XCHG
  1398.  
  1399. IF ZCPR3
  1400.  
  1401. CHKSLSH:
  1402.     CALL    ADVAN        ;move thru Tail until end or '/' found
  1403.     LDAX    D
  1404.     ORA    A
  1405.     JZ    FSLH1        ;z=end, no '/'
  1406.     CPI    "/"
  1407.     JNZ    CHKSLSH    
  1408.     INX    D
  1409.     LDAX    D
  1410.     CPI    'O'        ;overwrite option?
  1411.     JZ    FSLSH1        ;z=yes
  1412.     CPI    'o'
  1413.     JZ    FSLSH1
  1414.     XRA    A
  1415. FSLSH1:
  1416.     STA    OVRWRT
  1417.     RET
  1418. ENDIF    ;ZCPR3
  1419.  
  1420. IF NOT ZCPR3
  1421.     LDA    SRCDRV        ; Save drive BDSO says is default
  1422.     STA    TEMPDR
  1423.     CALL    SCANER        ; Search command line for next token
  1424.     LXI    H,TEMPDR    ; Save pointer to drive specification
  1425.     PUSH    H
  1426.     LDA    COLON        ; ':' found in token?
  1427.     ORA    A
  1428.     JZ    NPARUSR        ; Z=no
  1429.     MOV    A,M        ; Set drive specification
  1430.     STA    FCBDN
  1431.     LDA    TEMPUSR        ; Save user in 'S1' byte in FCB
  1432.     STA    FCBDN+13
  1433. NPARUSR:
  1434.     LXI    H,FCBDN+10H    ; Pt to 2nd file name
  1435.     LDA    SRCDRV
  1436.     STA    TEMPDR
  1437.     CALL    SCANX        ; Scan for it and load it into fcb+16
  1438.     POP    H        ; Set up drive specs
  1439.     LDA    COLON        ; DU form?
  1440.     ORA    A
  1441.     JZ    NPRUSR1        ; Z=no
  1442.     MOV    A,M
  1443.     STA    FCBDM        ; Yes ,save D
  1444.     LDA    TEMPUSR
  1445.     STA    FCBDM+13    ; And U
  1446. NPRUSR1:
  1447.     XRA    A        ; Zero current record number(not really needed)
  1448.     STA    FCBCR
  1449.     CALL    ADVAN        ; Skip over blanks in tail
  1450.     LDAX    D
  1451.     CPI    "/"        ; O overwrite option here?
  1452.     JNZ    NOOVR0
  1453.     INX    D
  1454.     LDAX    D
  1455.     CPI    'O'
  1456.     JZ    NOOVRW        ; Z=yes
  1457.     CPI    'o'
  1458.     JZ    NOOVRW
  1459. NOOVR0:    XRA    A
  1460. NOOVRW:
  1461.     STA    OVRWRT
  1462.     LXI    D,FCB        ; Copy to default FCB
  1463.     LXI    H,FCBDN        ; From FCBDN
  1464.     MVI    B,33        ; Set up default FCB
  1465.  
  1466. LDDIR:    MOV    A,M        ; Move parsed FCB's to CPM's default ones
  1467.     STAX    D
  1468.     INX    H
  1469.     INX    D
  1470.     DCR    B
  1471.     JNZ    LDDIR
  1472.  
  1473.     RET
  1474.  
  1475. SCANER:    LXI    H,FCBDN        ; Point to FCBDN
  1476. ;
  1477. SCANX:
  1478.     XRA    A        ; A=0
  1479.     MOV    M,A        ; Set first byte of FCBDN
  1480.     STA    COLON        ; Set no colon flag
  1481.     LDA    DEFUSR        ; Get current user
  1482.     STA    TEMPUSR        ; Set tempusr
  1483.     CALL    ADVAN        ; Skip to non-blank or end of line
  1484.     MVI    B,11        ; Prep for possible space fill
  1485.     JZ    SCAN4        ; Done if eol
  1486. ;
  1487. ;
  1488. ; Scan token for DU: form, which means we have a user/disk specification
  1489. ; DE points to next character in line, HL points to FCBDN.
  1490. ;
  1491.     PUSH    D        ; Save pointer to first character
  1492.     CALL    SDELM        ; Check for delimiter and get first char
  1493.     CPI    'A'        ; In letter range?
  1494.     JC    SCAN1
  1495.     CPI    'P'+1        ; In letter range?
  1496.     JC    SCAN1A
  1497. ;
  1498. SCAN1:    CPI    '0'        ; Check for digit range
  1499.     JC    SCAN2
  1500.     CPI    '9'+1        ; In digit range?
  1501.     JNC    SCAN2
  1502. ;
  1503. SCAN1A:    INX    D        ; Pt to next char
  1504.     CALL    SDELM        ; Check for delimiter, else digit
  1505.     JMP    SCAN1
  1506. ;
  1507. SCAN2:    POP    D        ; Restore ptr to first char
  1508.     CPI    ':'        ; Was delimiter a colon?
  1509.     JNZ    SCAN3        ; Done if no colon
  1510.     STA    COLON        ; Set colon found
  1511. ;
  1512. ;
  1513. ; Scan for and extract user/disk info - on entry, HL point to FCBDN, DE
  1514. ; points to first character and A-register contains the first character.
  1515. ;    
  1516.     LDAX    D        ; Get first character
  1517.     CPI    'A'        ; Convert possible drive spec to number
  1518.     JC    SUD1        ; If less than 'a', must be digit
  1519. ;
  1520. ;
  1521. ; Set disk number (A=1)
  1522. ;
  1523.     SUI    'A'-1
  1524. ;
  1525. ;     IF    DRVMAX
  1526. ;    PUSH    B        ; Save 'BC'
  1527. ;    PUSH    PSW        ; Save drive request
  1528. ;    LDA    DRVMAX        ; Get maximum legal drive
  1529. ;    ADI    2        ; Bump it two for the compare
  1530. ;    MOV    B,A        ; Save maximum drive in 'B'
  1531. ;    POP    PSW        ; Restore drive request
  1532. ;    CMP    B        ; See if illegal drive
  1533. ;    POP    B        ; Restore bc
  1534. ;     ENDIF            ; DRVMAX
  1535. ;;
  1536. ;     IF    NOT DRVMAX
  1537. ;    CPI    MAXDISK+1    ; Within range?
  1538. ;     ENDIF            ; NOT DRVMAX
  1539. ;
  1540.     JC    ERROR        ; Invalid disk number
  1541.     STA    TEMPDR        ; Set temporary drive number
  1542.     MOV    M,A        ; Set fcbdn
  1543.     INX    D        ; Pt to next char
  1544.     LDAX    D        ; See if it is a colon (:)
  1545.     CPI    ':'
  1546.     JZ    SUD2        ; Done if no user number (it is a colon)
  1547. ;
  1548. ;
  1549. ; Set user number
  1550. ;
  1551. SUD1:    PUSH    H        ; Save pointer to FCBDN
  1552.     XCHG            ; Hl pts to first digit
  1553.     CALL    NUM0A        ; Get number
  1554.     XCHG            ; De pts to terminating colon
  1555. ;
  1556. ;     IF    USRMAX
  1557. ;    LXI    H,USRMAX
  1558. ;    CMP    M
  1559. ;     ENDIF            ; USRMAX
  1560. ;
  1561. ;     IF    NOT USRMAX
  1562. ;    CPI    MAXUSR+1    ; Within limit?
  1563. ;     ENDIF            ; NOT USRMAX
  1564. ;
  1565.     POP    H        ; Get pointer to FCBDN
  1566.     JC    ERROR
  1567. ;
  1568.     STA    TEMPUSR        ; Save user number
  1569. ;
  1570. SUD2:    INX    D        ; Point to character after colon
  1571. ;
  1572. ;
  1573. ; Extract filename from possible FILENAME.TYP - DE points to next char-
  1574. ; acter to process, HL points tao FCBDN.
  1575. ;
  1576. SCAN3:    XRA    A        ; A=0
  1577.     STA    QMCNT        ; Init question mark count
  1578.     MVI    B,8        ; Max of 8 chars in file name
  1579.     CALL    SCANF        ; Fill FCB file name
  1580. ;
  1581. ;
  1582. ; Extract file type from possible FILENAME.TYP
  1583. ;
  1584.     MVI    B,3        ; Prepare to extract type
  1585.     LDAX    D        ; Get last char which stopped scan
  1586.     CPI    '.'        ; Have a type if de) delimiter is a '.'
  1587.     JNZ    SCAN4        ; Fill file type bytes with <sp>
  1588.     INX    D        ; Pt to char in command line after '.'
  1589.     CALL    SCANF        ; Fill fcb file type
  1590.     JMP    SCAN5        ; Skip to next processing
  1591. ;
  1592. SCAN4:    CALL    SCANF4        ; Space fill
  1593. ;
  1594. ;
  1595. ; Fill in EX, S1, S2, and RC with zeroes
  1596. ;
  1597. SCAN5:    MVI    B,4        ; 4 bytes
  1598.     XRA    A        ; A=0
  1599.     CALL    SCANF5        ; Fill with zeroes
  1600. ;
  1601. ;
  1602. ; Scan complete -- DE points to delimiter byte after token
  1603. ;
  1604.     XCHG
  1605.     SHLD    NXTCHR
  1606.     XCHG
  1607. ;
  1608. ;
  1609. ; Set zero flag to indicate presence of '?' in FILENAME.TYPE
  1610. ;
  1611. QMCNT    EQU    $+1        ; Pointer for in-the-code modification
  1612.     MVI    A,0        ; Number of question marks
  1613.     ORA    A        ; Set zero flag to indicate any '?'
  1614.     RET
  1615. ;.....
  1616. ;
  1617. ;
  1618. ; Scan token pointed to by DE for a max of B bytes; place it into file
  1619. ; name field pointed to by HL; expand and interpret wild cards of '*'
  1620. ; '?'; on exit, DE points to terminating delimiter.
  1621. ;
  1622. SCANF:    CALL    SDELM        ; Done if delimiter encountered
  1623.     JZ    SCANF4
  1624.     INX    H        ; Point to next byte in FCBDN
  1625.     CPI    '*'        ; Is (DE) a wild card?
  1626.     JNZ    SCANF1        ; Continue if not
  1627.     MVI    M,'?'        ; Place '?' in FCB
  1628.     CALL    SCQ        ; Scanner count question marks
  1629.     JMP    SCANF2
  1630. ;
  1631. SCANF1:    MOV    M,A        ; Store filename char in fcb
  1632.     INX    D        ; Pt to next char in command line
  1633.     CPI    '?'        ; Check for question mark (wild)
  1634.     CZ    SCQ        ; Scanner count question marks
  1635. ;
  1636. SCANF2:    DCR    B
  1637.     JNZ    SCANF
  1638. ;    DJNZ    SCANF        ; Decrement char count until 8 elapsed
  1639. ;
  1640. SCANF3:    CALL    SDELM        ; 8 chars or more - skip until delimiter
  1641.     RZ            ; Zero flag set if delimiter found
  1642.     INX    D        ; Pt to next char in command line
  1643.     JMP    SCANF3
  1644. ;
  1645. ;
  1646. ; Fill memory pointed to by HL with spaces for B bytes
  1647. ;
  1648. SCANF4:    MVI    A,' '        ; Fill with spaces
  1649. ;
  1650. SCANF5:    INX    H        ; Point to next byte in FCB
  1651.     MOV    M,A        ; Fill with byte in A-reg.
  1652.     DCR    B
  1653.     JNZ    SCANF5
  1654. ;    DJNZ    SCANF5
  1655.     RET
  1656. ;.....
  1657. ;
  1658. ;
  1659. ; Increment question mark count for scanner - this routine increments
  1660. ; the count of the number of question marks in the current FCB entry.
  1661. ;
  1662. SCQ:    PUSH    H        ; Save HL
  1663.     LXI    H,QMCNT        ; Get count
  1664.     INR    M        ; Increment
  1665.     POP    H        ; Get HL
  1666.     RET
  1667. ;.....
  1668. ;
  1669. ;
  1670.  
  1671. ;
  1672. ;
  1673. ; Check to see if DE points to delimiter, if so return with zero flag
  1674. ; set.
  1675. ;
  1676. SDELM:    LDAX    D
  1677.     ORA    A        ; 0=delimiter
  1678.     RZ
  1679.     CPI    ' '+1        ; Delim if <= <SP>
  1680.     JC    ZERO
  1681.     CPI    '='        ; '='=delimiter
  1682.     RZ
  1683.     CPI    5FH        ; Underscore=delimiter
  1684.     RZ
  1685.     CPI    '.'        ; '.'=delimiter
  1686.     RZ
  1687.     CPI    ':'        ; ':'=delimiter
  1688.     RZ
  1689.     CPI    ','        ; ','=delimiter
  1690.     RZ
  1691.     CPI    ';'        ; ';'=delimiter
  1692.     RZ
  1693.     CPI    '<'        ; '<'=delimiter
  1694.     RZ
  1695.     CPI    '>'        ; '>'=delimiter
  1696.     RET
  1697. ;
  1698. ZERO:    XRA    A        ; Set zero flag
  1699.     RET
  1700. ;.....
  1701. ;
  1702. ;
  1703. ; Advance input pointer to first non-blank and fall through to SBLANK
  1704. ;
  1705. ADVAN:    PUSH    H
  1706.     LHLD    NXTCHR
  1707.     XCHG
  1708.     POP    H
  1709. ;LDED    NXTCHR        ; Point to next character
  1710. ;
  1711. ;
  1712. ; Skip string pointed to by DE (string ends in 0 OR CMDSEP) until end of
  1713. ; string or non-delimited encounterd (beginning of token).
  1714. ;
  1715. SBLANK:
  1716.     LDAX    D        ; Get character
  1717.     ORA    A        ; Zero?
  1718.     RZ
  1719.     CALL    SDELM        ; Skip over delimiter
  1720.     RNZ
  1721.     INX    D        ; Advance to next char
  1722.     JMP    SBLANK
  1723. ;.....
  1724. ;
  1725. ;
  1726. ; Add A ro HL (HL=HL+A)
  1727. ;
  1728. ADDAH:    ADD    L
  1729.     MOV    L,A
  1730.     RNC
  1731.     INR    H
  1732.     RET
  1733.  
  1734.  
  1735. NUM0A:    LXI    B,1100H        ; C=accumulated value, b=char count
  1736. ;                ; (c=0, b=11)
  1737. NUM1:    MOV    A,M        ; Get character
  1738.     CPI    ' '        ; Done if <SP>
  1739.     JZ    NUM2
  1740.     CPI    ':'        ; Done if colon
  1741.     JZ    NUM2
  1742.     INX    H        ; Pt to next char
  1743.     SUI    '0'        ; Convert to binary
  1744.     CPI    10        ; Error if >= 10
  1745.     JNC    NUMERR
  1746.     MOV    D,A        ; Digit in d
  1747.     MOV    A,C        ; New value = old value * 10
  1748.     RLC            ; *2
  1749.     JC    NUMERR
  1750.     RLC            ; *4
  1751.     JC    NUMERR
  1752.     RLC            ; *8
  1753.     JC    NUMERR
  1754.     ADD    C        ; *9
  1755.     JC    NUMERR
  1756.     ADD    C        ; *10
  1757.     JC    NUMERR
  1758.     ADD    D        ; New value = old value * 10 + digit
  1759.     JC    NUMERR        ; Check for range error
  1760.     MOV    C,A        ; Set new value
  1761.     DCR    B
  1762.     JNZ    NUM1
  1763.  
  1764. ;    DJNZ    NUM1        ; Count down
  1765. ;
  1766. ;
  1767. ; Return from number
  1768. ;
  1769. NUM2:    MOV    A,C        ; Get accumulated value
  1770.     RET
  1771. ;.....
  1772. ;
  1773. ;
  1774. ; Number error routine for space conservation
  1775. ;
  1776. NUMERR:    JMP    BADNUM        ; Use error routine
  1777. ERROR:    JMP    BADNUM
  1778.  
  1779.  
  1780. FCBDN:    DB    0        ; Disk name
  1781. FCBFN:    DS    8        ; File name
  1782. FCBFT:    DS    3        ; File type
  1783.     DS    1        ; Extent number
  1784.     DS    2        ; S1 and S2
  1785.     DS    1        ; Record count
  1786. FCBDM:    DB    0
  1787.     DS    15        ; Disk group map
  1788. FCBCR:    DS    1        ; Current record number
  1789. TEMPDR    DS    2
  1790. NXTCHR    DS    2
  1791. TEMPUSR    DS    1
  1792. CURUSR    DS    1
  1793. COLON    DS    2
  1794. ENDIF    ;NOT ZCPR3
  1795.  
  1796. OVRWRT    DS    1
  1797.  
  1798. ;=============================================================================
  1799.  
  1800. ;            D A T A    A R E A
  1801.  
  1802. ;-----------------------------------------------------------------------------
  1803.  
  1804. OLDSTK:                ;place to keep old stack pointer
  1805.     DS    2
  1806.  
  1807. BLNKCNT:            ;count of blank characters in file name
  1808.     DS    1
  1809.  
  1810. CHGFLAG:            ;flag for change requiring write
  1811.     DS    1
  1812.  
  1813. RSTFLAG:            ;flag for need to reset disk system
  1814.     DS    1
  1815.  
  1816. AMBFIL:                ;working fcb
  1817.     DS    16
  1818.  
  1819. AMBFIL2:            ;space for rest of FCB
  1820.     DS    19
  1821.  
  1822. OPTION:                ;storage for new user number or option
  1823.     DS    1
  1824.  
  1825. ALLUSR:                ;storage for "all users" switch
  1826.     DS    1
  1827.  
  1828. DIRCODE:            ;storage for directory code (0-3)
  1829.     DS    1
  1830.  
  1831. DMAPTR:                ;address of FCB in DMA buffer
  1832.     DS    2
  1833.  
  1834. DEFDRV:                ;current default drive
  1835.     DS    1
  1836.  
  1837. SRCDRV:                 ;source drive
  1838.     DS    1
  1839.  
  1840. DEFUSR:                ;current default user number
  1841.     DS    1
  1842.  
  1843. SRCUSR:                ;source user area from file spec
  1844.     DS    1
  1845.  
  1846.     DS    60        ;room for local stack
  1847. NEWSTK:
  1848.  
  1849.     END
  1850.