home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / lambda / soundpot / a / cfa03.lbr / CFA03.AZM / CFA03.ASM
Encoding:
Assembly Source File  |  1993-10-26  |  36.9 KB  |  1,433 lines

  1. ; This program is derived from MAKE26.ASM
  2.  
  3. ; See file CFA03.HIS for upgrade notes and programmer credits.
  4. ; See file CFA03.DOC for full instructions, usage notes, warnings, etc.
  5.  
  6. ;=============================================================================
  7.  
  8. ;        P R O G R A M    E Q U A T E S
  9.  
  10. ;=============================================================================
  11.  
  12. VERSION    EQU    03        ; a preliminary release
  13.  
  14. FALSE    EQU    0
  15. TRUE    EQU    NOT FALSE
  16.  
  17. ZCPR3    EQU    FALSE        ;true for ZCPR3 version, false for plain CP/M
  18.                 ; MAKE SURE TO SET THIS CORRECTLY.
  19.  
  20. WHEEL    EQU    FALSE        ;true to test wheel byte before running
  21. WHLADR    EQU    3EH        ;wheel byte location
  22.  
  23. TAGS    EQU    TRUE        ; true to set filename bytes 1-4 (ldr)
  24. SPLIT    EQU    FALSE        ; true for experimental file splitter (ldr)
  25. SEGSIZ    EQU    3        ; size (in extents) for split segments
  26.                 ; 1=16k, 2=32k, 3=48k, etc... (ldr)
  27.  
  28. BDOS    EQU    0005H        ;BDOS entry address
  29. DMAADDR    EQU    0080H        ;default CP/M file buffer
  30. FCB    EQU    005CH        ;default CP/M FCB
  31. TFCB    EQU    006CH        ;temporary FCB
  32. Z3ENV    EQU    00000H        ;ZCPR3 environment address filled in by Z3INS
  33. CR    EQU    0DH        ;(z3env not presently needed anyway)
  34. LF    EQU    0AH
  35. TAB    EQU    09H
  36. BELL    EQU    07H
  37.  
  38. ;=============================================================================
  39.  
  40. ;        M A I N    P R O G R A M    C O D E
  41.  
  42. ;-----------------------------------------------------------------------------
  43.  
  44.     ORG    0100H
  45.  
  46. CFA:
  47.  
  48.      IF    ZCPR3
  49.  
  50.         ;ZCPR3 initialization (not actually needed here, but if one
  51.         ;runs the install program it will not report a bad utility)
  52.  
  53.     JMP    START
  54.     DB    'Z3ENV'
  55.     DB    1        ;external environment
  56.     DW    Z3ENV        ;environment address (value is not used here)
  57.  
  58.      ENDIF    ;ZCPR3
  59.  
  60. START:        ;set up local stack pointer
  61.  
  62.     LXI    H,0        ;get CP/M stack pointer
  63.     DAD    SP
  64.     SHLD    OLDSTK        ;save it for later return
  65.     LXI    SP,NEWSTK    ;set up new local stack
  66.  
  67.         ;perform setup tasks
  68.  
  69.      IF    WHEEL
  70.     LDA    WHLADR        ;get wheel byte
  71.     ORA    A        ;is it set?
  72.     JZ    EREXIT        ;no/don't run
  73.      ENDIF            ;wheel
  74.  
  75.     CALL    SIGNON        ;print signon message
  76.     CALL    CHKHLP        ;see if help requested and go there if so
  77.  
  78.     CALL    INIT        ;set up data areas
  79.     CALL    SETDU        ;handle current and specified DU areas
  80.     CALL    GETOPT        ;get option from command line (abort if bad)
  81.     CALL    CHKRO        ;abort if destination drive is R/O and option
  82.                 ;..requests change in files
  83.  
  84.         ;begin main work of program
  85.  
  86.     CALL    SRCHF        ;locate first directory entry (abort if none)
  87.  
  88. LOOP:    CALL    SETPTR        ;set DMAPTR to point to disk directory FCB
  89.     CALL    CHKFIL        ;check for applicable file
  90.     CNC    CALLOPT        ;if applicable file, process option
  91.  
  92. NEXTFIL:    ;go on to next file
  93.  
  94.     LXI    H,DIRCODE     ;point to the directory code
  95.     INR    M        ;increase it one
  96.     MOV    A,M        ;get new value
  97.     CPI    04        ;check for four FCB entries completed
  98.     JNZ    LOOP        ;if not, go back and continue
  99.  
  100.         ;process this group of four files and go on to next
  101.  
  102.     LXI    H,CHGFLAG    ;point to change flag
  103.     MOV    A,M        ;get it into A
  104.     MVI    M,0        ;reset it
  105.     ORA    A        ;set flags from original value
  106.     CNZ    WRTDE        ;if changes were made, write the buffer back
  107.  
  108.         ;sequence through files to get new buffer-full of FCB's
  109.  
  110. SRNXT:    LXI    D,AMBFIL    ;point to any-match FCB
  111.     MVI    C,12H        ;BDOS search-next function
  112.     CALL    BDOS
  113.     CPI    0FFH        ;see if end of entries
  114.     JZ    QUIT        ;quit if no more files
  115.     CPI    0        ;loop until buffer is updated by BDOS
  116.     JNZ    SRNXT        ;jump until dircode is zero
  117.     STA    DIRCODE     ;save the 0 in dircode
  118.     JMP    LOOP        ; and loop again
  119.  
  120. ;=============================================================================
  121.  
  122. ;    O P T I O N    P R O C E S S I N G    R O U T I N E S
  123.  
  124. ;-----------------------------------------------------------------------------
  125.  
  126.      IF    TAGS    ; code for setting file tags (ldr)
  127.  
  128. ; Selects tag 1 to set high.
  129.  
  130. TAG1:
  131.     LHLD    DMAPTR        ;point to disk directory FCB entry
  132.     LXI    D,1        ;offset to tag 1
  133.     CALL    SETHI        ; set control bit HIGH (ldr)
  134.     RET
  135.  
  136. ;-----------------------------------------------------------------------------
  137.  
  138. ; Selects tag 1 to set low.
  139.  
  140. UNTAG1:
  141.     LHLD    DMAPTR        ;point to disk directory FCB entry
  142.     LXI    D,1        ;offset to tag 1
  143.     CALL    SETLO        ; set control bit LOW (ldr)
  144.     RET
  145.  
  146. ;-----------------------------------------------------------------------------
  147.  
  148. ; Selects tag 2 to set high.
  149.  
  150. TAG2:
  151.     LHLD    DMAPTR        ;point to disk directory FCB entry
  152.     LXI    D,2        ;offset to tag 2
  153.     CALL    SETHI        ; set control bit HIGH (ldr)
  154.     RET
  155.  
  156. ;-----------------------------------------------------------------------------
  157.  
  158. ; Selects tag 2 to set low.
  159.  
  160. UNTAG2:
  161.     LHLD    DMAPTR        ;point to disk directory FCB entry
  162.     LXI    D,2        ;offset to tag 2
  163.     CALL    SETLO        ; set control bit LOW (ldr)
  164.     RET
  165. ;-----------------------------------------------------------------------------
  166.  
  167. ; Selects tag 3 to set high.
  168.  
  169. TAG3:
  170.     LHLD    DMAPTR        ;point to disk directory FCB entry
  171.     LXI    D,3        ;offset to tag 3
  172.     CALL    SETHI        ; set control bit HIGH (ldr)
  173.     RET
  174.  
  175. ;-----------------------------------------------------------------------------
  176.  
  177. ; Selects tag 3 to set low.
  178.  
  179. UNTAG3:
  180.     LHLD    DMAPTR        ;point to disk directory FCB entry
  181.     LXI    D,3        ;offset to tag 3
  182.     CALL    SETLO        ; set control bit LOW (ldr)
  183.     RET
  184. ;-----------------------------------------------------------------------------
  185.  
  186. ; Selects tag 4 to set high.
  187.  
  188. TAG4:
  189.     LHLD    DMAPTR        ;point to disk directory FCB entry
  190.     LXI    D,4        ;offset to tag 4
  191.     CALL    SETHI        ; set control bit HIGH (ldr)
  192.     RET
  193.  
  194. ;-----------------------------------------------------------------------------
  195.  
  196. ; Selects tag 4 to set low.
  197.  
  198. UNTAG4:
  199.     LHLD    DMAPTR        ;point to disk directory FCB entry
  200.     LXI    D,4        ;offset to tag 4
  201.     CALL    SETLO        ; set control bit LOW (ldr)
  202.     RET
  203.  
  204.      ENDIF    ; TAGS    end of code for 1-4 tags (ldr)
  205.  
  206. ;------------------------------------------------------------------------------
  207.  
  208. ; Selects SYS file attribute.
  209.  
  210. SETSYS:
  211.     LHLD    DMAPTR        ;point to disk directory FCB entry
  212.     LXI    D,10        ;offset 10 to DIR/SYS byte
  213.     CALL    SETHI        ; set control bit HIGH (ldr)
  214.     RET
  215.  
  216. ;-----------------------------------------------------------------------------
  217.  
  218. ; Selects DIR file attribute.
  219.  
  220. SETDIR:
  221.     LHLD    DMAPTR        ;point to disk directory FCB entry
  222.     LXI    D,10        ;offset 10 to SYS/DIR byte
  223.     CALL    SETLO        ; set control bit LOW (ldr)
  224.     RET
  225.  
  226. ;-----------------------------------------------------------------------------
  227.  
  228. ; Selects R/O file attribute.
  229.  
  230. SETRO:
  231.     LHLD    DMAPTR        ;point to disk directory FCB entry
  232.     LXI    D,9        ;offset 9 to R/O-R/W byte
  233.     CALL    SETHI        ; set control bit HIGH (ldr)
  234.     RET
  235.  
  236. ;-----------------------------------------------------------------------------
  237.  
  238. ; Selects R/W file attribute
  239.  
  240. SETRW:
  241.     LHLD    DMAPTR        ;point to disk directory FCB entry
  242.     LXI    D,9        ;offset 9 to R/O-R/W byte
  243.     CALL    SETLO        ; set control bit LOW (ldr)
  244.     RET
  245.  
  246. ;-----------------------------------------------------------------------------
  247. ; Selects ARC file attribute.
  248.  
  249. SETARC:
  250.     LHLD    DMAPTR        ;point to disk directory FCB entry
  251.     LXI    D,11        ;offset 10 to ARCHIVE byte
  252.     CALL    SETHI        ; set control bit HIGH (ldr)
  253.     RET
  254.  
  255. ;-----------------------------------------------------------------------------
  256.  
  257. ; Selects Non-ARC file attribute.
  258.  
  259. SETNRC:
  260.     LHLD    DMAPTR        ;point to disk directory FCB entry
  261.     LXI    D,11        ;offset 10 to ARCHIVE byte
  262.     CALL    SETLO        ; set control bit LOW (ldr)
  263.     RET
  264.  
  265. ;-----------------------------------------------------------------------------
  266.  
  267. ; Erase the file by writing E5 as the user number tag.  We know that the file
  268. ; is not already erased because of the work of subroutine CHKFIL earlier.
  269. ; Therefore, we must set the change flag to show the need to write the sector
  270. ; back out to disk.
  271.  
  272. ERASE:
  273.     LHLD    DMAPTR
  274.     MVI    M,0E5H
  275.     CALL    SETCHGFL    ;show need to write sector back to disk
  276.     CALL    REPORT        ;report the new file status
  277.     RET
  278.  
  279. ;-----------------------------------------------------------------------------
  280.  
  281. ; Unerase the file by writing the current user number into the tag byte in
  282. ; place of the E5.  The comments under ERASE apply here, too.
  283.  
  284. UNERA:
  285.     LDA    DEFUSR        ;get logged in user number
  286.     LHLD    DMAPTR
  287.     MOV    M,A        ;put it into disk directory user # tag
  288.     CALL    SETCHGFL    ;show need to write sector back to disk
  289.     CALL    REPORT        ;report the new file status
  290.     RET
  291.  
  292. ;-----------------------------------------------------------------------------
  293. ;  This routine sets selected attribute or tag byte HIGH.  If the file
  294. ;  was not already set this way, the CHGFLAG is set to indicate the
  295. ;  necessity of writing the modified sector out to disk.  (ldr)
  296.  
  297. SETHI:    DAD    D
  298.     MOV    A,M        ; get selected byte
  299.         ORA    A        ; test current state of control bit
  300.     CP    SETCHGFL    ; if not already high, set change flag
  301.     ORI    80H        ; make sure it is set
  302.     MOV    M,A        ; write modified byte back out
  303.     CALL    REPORT        ; report the new file status
  304.     RET
  305.  
  306. ;-----------------------------------------------------------------------------
  307. ;  This routine sets selected attribute or tag byte LOW.  If the file
  308. ;  was not already set this way, the CHGFLAG is set to indicate the
  309. ;  necessity of writing the modified sector out to disk.  (ldr)
  310.  
  311. SETLO:    DAD    D
  312.     MOV    A,M        ; get selected byte
  313.     ORA    A        ; sign flag shows state of SYS bit
  314.     CM    SETCHGFL    ; if not already low, set change flag
  315.     ANI    7FH        ; clear the high bit
  316.     MOV    M,A        ; write modified byte back to buffer
  317.     CALL    REPORT        ; report the new file status
  318.     RET
  319.  
  320. ;-----------------------------------------------------------------------------
  321.  
  322. ; Change the user number of the file.
  323.  
  324. CHUSER:    LDA    OPTION        ;get user number
  325.     LHLD    DMAPTR        ;point to place to put it
  326.     MOV    M,A        ;put new user number in directory
  327.     CALL    SETCHGFL    ;show need to write sector back out to disk
  328.     CALL    REPORT        ;report the new file status
  329.     RET
  330.  
  331. ;-----------------------------------------------------------------------------
  332.      IF    SPLIT    ; (ldr)
  333.  
  334. ;  EXPERIMENTAL FEATURE enabled with SPLIT EQU TRUE.  Use at your own risk.
  335. ;  Chops a file into little pieces.  CHGFLAG is set regardless. (ldr)
  336.  
  337. CHOP:
  338.     LHLD    DMAPTR        ; point to disk directory FCB entry
  339.     LXI    D,9        ; offset first byte in filetype
  340.     DAD    D
  341.     LDA    EXTLTR
  342.     MOV    M,A        ; change first letter of filetype
  343.  
  344.     LHLD    DMAPTR        ; point to disk directory FCB entry
  345.     LXI    D,12        ; offset to extent byte
  346.     DAD    D
  347.     LDA    MRKSEG
  348.     MOV    M,A        ; change extent number
  349.  
  350.     INR    A        ; bump the extent counter
  351.     STA    MRKSEG        ; and store it
  352.     CPI    SEGSIZ        ; see if we've reached the limit
  353.     JNZ    CHOPX        ; if not, keep it as is
  354.     SUB    A        ;  otherwise zero it out
  355.     STA    MRKSEG        ;   store extent counter (again)
  356.     LDA    EXTLTR        ;    load letter for filename
  357.     INR    A        ;     increment it
  358.     STA    EXTLTR        ;      and store it, too
  359.  
  360. CHOPX:    CALL    SETCHGFL    ; set change flag
  361.     CALL    REPORT        ; report the new file status
  362.     RET
  363.  
  364. ;-----------------------------------------------------------------------------
  365.  
  366. ;  EXPERIMENTAL FEATURE enabled with SPLIT EQU TRUE.  Use at your own risk.
  367. ;  Join hacked little pieces into one file.  CHGFLAG is set regardless.
  368. ;  Reverse of CHOP operation.  Renames files with character '-' as first
  369. ;  byte of filetype.  (ldr)
  370.  
  371. BIND:
  372.     LHLD    DMAPTR        ; point to disk directory FCB entry
  373.     LXI    D,12        ; offset to extent
  374.     DAD    D
  375.     LDA    MRKSEG        ; get current extent number
  376.     MOV    M,A        ; restore original extent
  377.     INR    A        ; increment it
  378.     STA    MRKSEG        ; and store for next round
  379.  
  380.     LHLD    DMAPTR        ; point to disk directory FCB entry
  381.     LXI    D,9        ; first byte of filetype
  382.     DAD    D
  383.     MVI    A,'-'        ; arbitrary code to mark Bind
  384.     MOV    M,A        ; write modified byte back to buffer
  385.  
  386.     CALL    SETCHGFL    ; set change flag
  387.     CALL    REPORT        ; report the new file status
  388.     RET
  389.  
  390.      ENDIF    ; SPLIT (ldr)
  391.  
  392. ;-----------------------------------------------------------------------------
  393.  
  394. ; This code reports the attributes of the files acted on and, if required,
  395. ; the erased or unerased status.  This code is called directly by the blank
  396. ; option and indirectly by all the other option processors after they have
  397. ; finished performing their changes on the files.
  398.  
  399. REPORT:    CALL    PRTFN        ;print the file name
  400.     CALL    ILPRT        ;print spacer and equal sign
  401.     DB    ' = ',0
  402.     CALL    PRTOPT        ;print the option letter or number
  403.     MVI    C,3        ;put in three more blank spaces
  404.     CALL    PRTBLK
  405.     CALL    PRTATTR        ;print file attributes
  406.     LDA    OPTION        ;see if files erased
  407.     CPI    'E'
  408.     CZ    PRTERA        ;if so, print erased message
  409.     LDA    OPTION
  410.     CPI    'U'        ;see if files unerased
  411.     CZ    PRTUNE        ;if so, print unerased message
  412.     RET
  413.  
  414. ;=============================================================================
  415.  
  416. ;        P R O G R A M    F L O W    R O U T I N E S
  417.  
  418. ;-----------------------------------------------------------------------------
  419.  
  420. ;                CALLOPT
  421.  
  422. ; This routine uses the value of OPTION to look up the processing routine
  423. ; to which to branch.
  424.  
  425. CALLOPT:
  426.     LXI    H,JMPTBL    ;point to jump table
  427.     LDA    OPTION        ;get user number or option letter
  428.     MOV    B,A        ;save it in B
  429.  
  430. LOOKUP:    MOV    A,M        ;get option letter from table
  431.     INX    H        ;point to jump address
  432.     ORA    A        ;end of table?
  433.     JZ    JMPOPT2        ;if so, jump
  434.     CMP    B        ;do we match a table entry
  435.     JZ    JMPOPT1        ;if so, go to code to get jump address
  436.     INX    H        ;else jump over jump address to
  437.     INX    H        ;..next option character
  438.     JMP    LOOKUP        ;and try again
  439.  
  440. JMPOPT1:
  441.     MOV    A,M        ;get low part of jump address into A
  442.     INX    H        ;point to high part of address
  443.     MOV    H,M        ;get it into H
  444.     MOV    L,A        ;jump address is in HL
  445.     PCHL            ;jump to it
  446.  
  447. JMPOPT2:
  448.     LXI    H,CHUSER    ;default to change user routine
  449.     PCHL            ;jump to it
  450.  
  451. JMPTBL:    DB    ' '
  452.     DW    REPORT
  453.  
  454.      IF    TAGS    ; (ldr)
  455.  
  456.     DB    'F'
  457.     DW    TAG1
  458.  
  459.     DB    'G'
  460.     DW    UNTAG1
  461.  
  462.     DB    'H'
  463.     DW    TAG2
  464.  
  465.     DB    'I'
  466.     DW    UNTAG2
  467.  
  468.     DB    'J'
  469.     DW    TAG3
  470.  
  471.     DB    'K'
  472.     DW    UNTAG3
  473.  
  474.     DB    'L'
  475.     DW    TAG4
  476.  
  477.     DB    'M'
  478.     DW    UNTAG4
  479.  
  480.      ENDIF    ; TAGS (ldr)
  481.  
  482.     DB    'S'
  483.     DW    SETSYS
  484.  
  485.     DB    'D'
  486.     DW    SETDIR
  487.  
  488.     DB    'R'
  489.     DW    SETRO
  490.  
  491.     DB    'W'
  492.     DW    SETRW
  493.  
  494.     DB    'A'
  495.     DW    SETARC
  496.  
  497.     DB    'N'
  498.     DW    SETNRC
  499.  
  500.     DB    'E'
  501.     DW    ERASE
  502.  
  503.     DB    'U'
  504.     DW    UNERA
  505.  
  506.      IF    SPLIT    ; (ldr)
  507.  
  508.     DB    'C'
  509.     DW    CHOP
  510.  
  511.     DB    'B'
  512.     DW    BIND
  513.  
  514.      ENDIF    ;SPLIT (ldr)
  515.  
  516.     DB    0        ;end of table mark
  517.  
  518. ;-----------------------------------------------------------------------------
  519.  
  520. ;                QUIT
  521.  
  522. ; Restores the original CP/M stack, and returns to CP/M.  If indicated by the
  523. ; reset flag, it resets the disk system.  The logged DU area when the program
  524. ; was invoked is restored.  The entry point QUIT2 is used by code CHKHL
  525. ; which that doesn't change the logged in directory.
  526.  
  527. QUIT:    LDA    DEFDRV        ;get original default drive
  528.     CALL    LOGDRV        ;log it in
  529.     LDA    DEFUSR        ;get original default user
  530.     CALL    LOGUSR        ;log it in
  531.  
  532.         ;see if we need to reset the disk system
  533.  
  534. QUIT1:    LDA    RSTFLAG
  535.     ORA    A        ;if reset flag is clear
  536.     JZ    QUIT2        ;..we can skip disk system reset
  537.  
  538.         ;reset the disk system
  539.  
  540.     MVI    C,0DH
  541.     CALL    BDOS
  542.  
  543.         ;restore the original stack
  544.  
  545. QUIT2:    LHLD    OLDSTK        ;get original stack pointer
  546.     SPHL            ;set it up
  547.  
  548.     CALL    CRLF        ;one last blank line
  549.     RET            ;back to CP/M
  550.  
  551.      IF    WHEEL
  552. EREXIT:                ;if using wheel byte and wheel not set
  553.     CALL    ILPRT        ;we pretend the program doesn't exist
  554.     DB    'CFA?',0    ;by printing phony CCP error.
  555.     JMP    QUIT2
  556.      ENDIF            ;wheel
  557.  
  558. ;=============================================================================
  559.  
  560. ;    F I L E    S E L E C T I O N    S U B R O U T I N E S
  561.  
  562. ;-----------------------------------------------------------------------------
  563.  
  564. ;                CHKFIL
  565.  
  566. ; This subroutine checks to see whether or not the FCB pointed to in the
  567. ; DMA buffer is one that should be acted on.  If not, the routine returns
  568. ; with the zero flag set.
  569.  
  570. CHKFIL:    CALL    CHKUN        ;check user number and erased status of file
  571.     RC            ;return with carry set to skip file
  572.     CALL    CHKFN        ;next check the file name for a match
  573.     RET            ;return showing status of name match
  574.  
  575. ;-----------------------------------------------------------------------------
  576.  
  577. ;                CHKUN
  578.  
  579. ; This subroutine checks the user number status of a file and sets the carry
  580. ; flag if the file should be skipped over.  If the option is UNERASE and the
  581. ; file is not an erased file, it should be skipped.  If the option is not
  582. ; unerase and the file is an erased file, then likewise it should be skipped.
  583. ; Finally, if the file is in a user number other than the logged in user, it
  584. ; should also be skipped.
  585.  
  586. CHKUN:        ;test file erased status
  587.  
  588.     LHLD    DMAPTR        ;point to user number tag of file
  589.     MOV    A,M        ;get the tag
  590.     CPI    0E5H        ;carry flag set if not erased
  591.     PUSH    PSW        ;save flag
  592.     
  593.         ;test program option status
  594.  
  595.     LDA    OPTION        ;get the option
  596.     CPI    'U'        ;is it unerase?
  597.     JNZ    CHKUN1        ;if not, skip to CHKUN1
  598.  
  599.         ;case of unerase option
  600.  
  601.     POP    PSW        ;carry flag set if not erased
  602.     RET            ;file not erased will be skipped
  603.  
  604.         ;case of option other than unerase
  605.  
  606. CHKUN1:    POP    PSW
  607.     CMC            ;carry flag set if file erased
  608.     RC            ;erased file will be skipped
  609.  
  610.         ;now check for user number in source area
  611.  
  612.     LDA    ALLUSR        ;see if "all users" was requested
  613.     CPI    '#'        ;
  614.     JZ    CHKUN2        ;if so, skip over compare...
  615.     LDA    SRCUSR        ;get source user number
  616.     CMP    M        ;compare to file tag
  617.     RZ            ;if OK, return (carry is clear)
  618.     STC            ;else set carry
  619. CHKUN2:
  620.     RET            ;..and return
  621.  
  622. ;-----------------------------------------------------------------------------
  623.  
  624. ;                CHKFN
  625.  
  626. ; This subroutine compares the name of the file in the FCB in the DMA buffer
  627. ; with the specification from the command line.
  628.  
  629. CHKFN:        ;set up pointers and character count
  630.  
  631.     LHLD    DMAPTR        ;get pointer to FCB in DMA buffer
  632.     INX    H        ;point to first character in the name
  633.     LXI    D,FCB+1     ;set DE to name in FCB from command line
  634.     MVI    C,0BH        ;load count for compare
  635.  
  636. CP1:    LDAX    D        ;get fcb command line character
  637.     CPI    '?'        ;see if anything matches
  638.     JZ    MATCH        ;if it is '?', consider it a match
  639.     SUB    M        ;get difference (see next instruction)
  640.     ANI    7FH        ;clear attribute bit
  641.     JZ    MATCH        ;if zero, characters match
  642.     STC            ;else set carry
  643.     RET            ;..and return
  644.  
  645. MATCH:    INX    D        ;point to next characters
  646.     INX    H
  647.     DCR    C        ;decrease count of characters
  648.     JNZ    CP1        ;loop until zero
  649.     RET            ;carry is clear showing names match
  650.  
  651. ;=============================================================================
  652.  
  653. ;    D I S K    O P E R A T I O N    S U B R O U T I N E S
  654.  
  655. ;-----------------------------------------------------------------------------
  656.  
  657. ;                SRCHF
  658.  
  659. ; This subroutine uses the fully ambiguous file spec at AMBFIL to locate the
  660. ; first directory entry on the disk.  The directory code (0-3) is saved. If
  661. ; no directory entry is found, then the program gives a message and branches
  662. ; to QUIT for a prompt return.
  663.  
  664. SRCHF:    LXI    D,AMBFIL    ;point to match any filename.typ
  665.     MVI    C,11H        ;bdos search first function
  666.     CALL    BDOS        ;do it
  667.     STA    DIRCODE     ;save directory code
  668.     CPI    0FFH        ;see if end of entries
  669.     RNZ            ;if something found, return
  670.     CALL    ILPRT        ;else give a message
  671.     DB    BELL
  672.     DB    'Empty disk?',0
  673.     JMP    QUIT
  674.  
  675. ;-----------------------------------------------------------------------------
  676.  
  677. ;                WRTDE
  678.  
  679. ; This routine writes the directory buffer back to the disk.  I also sets the
  680. ; reset flag so that the disk system will be reset on program termination.
  681.  
  682. WRTDE:    LXI    H,RSTFLAG    ;point to the flag
  683.     MVI    M,0FFH        ;set the flag
  684.     MVI    C,1H        ;set BIOS write to directory
  685.                 ; C = 0   write to allocated
  686.                 ; C = 1   write to directory
  687.                 ; C = 2   write to unallocated
  688.     CALL    WRITE        ;do the write
  689.     ORA    A        ;check for error
  690.     RZ            ;if none, return
  691.  
  692.     CALL    ILPRT
  693.     DB    BELL
  694.     DB    'Bad Sector Write Error',0
  695.  
  696.     JMP    QUIT
  697.  
  698. ;-----------------------------------------------------------------------------
  699.     
  700. ;                WRITE
  701.  
  702. ; This routine is filled in during the operation of the program and performs
  703. ; a direct BIOS sector write operation on the currently selected track and
  704. ; sector.
  705.  
  706. WRITE:    JMP    0000        ;vector to bios write routine
  707.  
  708. ;=============================================================================
  709.  
  710. ;        P R I N T I N G    R O U T I N E S
  711.  
  712. ;-----------------------------------------------------------------------------
  713.  
  714. ;                PRTFN
  715.  
  716. ; This subroutine displays (at the beginning of the next line of the screen)
  717. ; the name of the file pointed to in the DMA buffer.
  718.  
  719. PRTFN:    CALL    CRLF        ;print cr/lf
  720.     LHLD    DMAPTR        ;address of file fcb
  721.     INX    H        ;skip to file name
  722.     LXI    D,BLNKCNT    ;point to blanks counter
  723.     XCHG            ;exchange pointers
  724.     MVI    M,0        ;preset blank count to zero
  725.  
  726.     MVI    C,8        ;length of file name
  727.     CALL    PRTSTR        ;print the name first
  728.  
  729.     MVI    A,'.'        ;print the period
  730.     CALL    CHAROUT
  731.  
  732.     MVI    C,3        ;now print the file type
  733.     CALL    PRTSTR
  734.  
  735.     MOV    C,M        ;get number of blanks needed for fill
  736.     CALL    PRTBLK        ;print the blanks
  737.     RET
  738.  
  739. ;-----------------------------------------------------------------------------
  740.  
  741. ;                PRTOPT
  742.  
  743. ; This subroutine prints out the option as a letter or as a number as
  744. ; appropriate.
  745.  
  746. PRTOPT:    LDA    OPTION        ;get the option value
  747.     CPI    20H        ;if it's a user number, carry will be set
  748.     JNC    CHAROUT        ;if not number, just print the character
  749.     MVI    B,'0'-1        ;preset for two-digit calculation later
  750.     CPI    10        ;see if single digit
  751.     JNC    TWODIG        ;if not, print two digits
  752.     ADI    '0'        ;else convert to ASCII
  753.     JMP    CHAROUT        ;and print it
  754. TWODIG:    INR    B        ;count tens digit in B
  755.     SUI    10        ;keep subtracting 10 until carry is set
  756.     JNC    TWODIG
  757.     ADI    10        ;get remainder (units digit) back
  758.     MOV    C,A        ;save it in C
  759.     MOV    A,B        ;print tens digit
  760.     CALL    CHAROUT
  761.     MOV    A,C        ;print units digit
  762.     ADI    '0'
  763.     JMP    CHAROUT
  764.  
  765. ;-----------------------------------------------------------------------------
  766.  
  767. ;                PRTATTR
  768.  
  769. ; This subroutine prints the attribute status (SYS or DIR and R/O or R/W)
  770. ; of the file currently being worked on.
  771.  
  772. PRTATTR:
  773.     LHLD    DMAPTR        ;point to file FCB
  774.     LXI    D,9        ;offset to R/O-R/W byte
  775.     DAD    D
  776.     PUSH    H        ;save pointer for reuse below
  777.     MOV    A,M
  778.     RAL            ;move R/O bit into carry
  779.     PUSH    PSW        ;save flags
  780.     CC    PRTRO        ;if carry, print read-only
  781.     POP    PSW        ;get flags back to test again
  782.     CNC    PRTRW        ;if not carry, print read-write
  783.  
  784.     POP    H        ;get pointer back
  785.     INX    H        ;point to SYS/DIR byte
  786.     PUSH    H        ;save pointer for reuse below
  787.     MOV    A,M
  788.     RAL            ;move SYS/DIR bit into carry
  789.     PUSH    PSW        ;save flags
  790.     CC    PRTSYS        ;if carry, print SYS
  791.     POP    PSW        ;get them back
  792.     CNC    PRTDIR        ;if not carry, print DIR
  793.     POP    H
  794.     INX    H
  795.     MOV    A,M
  796.     RAL            ;move ARCHIVE bit into carry
  797.     PUSH    PSW        ;save flags
  798.     CC    PRTARC        ;if carry, print ARC
  799.     POP    PSW        ;get them back
  800.     CNC    PRTNRC        ;if not carry, print Non-ARC
  801.     RET
  802.     
  803. ;-----------------------------------------------------------------------------
  804.  
  805. ;    MESSAGE PRINTING ROUTINES
  806.  
  807. PRTRO:    CALL    ILPRT        ;file is read-only
  808.     DB    '  R/O',0
  809.     RET
  810.  
  811. PRTRW:    CALL    ILPRT        ;file is read-write
  812.     DB    '  R/W',0
  813.     RET
  814.  
  815. PRTSYS:    CALL    ILPRT        ;file has SYS attribute
  816.     DB    '  SYS',0
  817.     RET
  818.  
  819. PRTDIR:    CALL    ILPRT        ;file has DIR attribute
  820.     DB    '  DIR',0
  821.     RET
  822.  
  823. PRTARC:    CALL    ILPRT        ;file has ARC attribute
  824.     DB    '  ARCHIVE',0
  825.     RET
  826.  
  827. PRTNRC:    CALL    ILPRT        ;file has NO ARC attribute
  828.     DB    '  Non-ARC',0
  829.     RET
  830.  
  831. PRTERA:    CALL    ILPRT        ;file erased
  832.     DB    '  <ERASED>',0
  833.     RET
  834.  
  835. PRTUNE:    CALL    ILPRT        ;file unerased
  836.     DB    '  <UNERASED>',0
  837.     RET
  838.  
  839. ;-----------------------------------------------------------------------------
  840.  
  841. ;                HELP
  842.  
  843. ; This code displays the built in help screen and then jumps to QUIT to
  844. ; return to CP/M.  Entire menu re-written for this version.  (ldr)
  845.  
  846. HELP:    CALL    ILPRT
  847.     DB    'Usage:',TAB
  848.  
  849.      IF    ZCPR3
  850.     DB    'CFA [dir:]filename.typ X[#]',CR,LF,LF
  851.     DB    ' where dir: is optional directory specifier in DU:',CR,LF
  852.     DB    ' or named directory form,'
  853.      ENDIF    ;ZCPR3
  854.  
  855.      IF    NOT ZCPR3
  856.     DB    'CFA [d:]filename.typ X[#]',CR,LF,LF
  857.     DB    ' where d: is optional drive specifier,'
  858.      ENDIF    ;NOT ZCPR3
  859.  
  860.     DB    ' and X may be ONE of these:',CR,LF,LF
  861.  
  862.     DB    'Number 0-31',CR,LF
  863.     DB    '  Moves file to user area X',CR,LF,LF
  864.  
  865.      IF    TAGS    ; (ldr)
  866.     DB    'File tags:',TAB,TAB,TAB
  867.      ENDIF    ;TAGS (ldr)
  868.  
  869.     DB    'File attributes:',CR,LF
  870.      IF    TAGS    ; (ldr)
  871.     DB    '  F or G  Tag 1, on/off',TAB,TAB
  872.      ENDIF    ;TAGS (ldr)
  873.     DB    '  R or W:  $R/O or $R/W',CR,LF
  874.  
  875.      IF    TAGS    ; (ldr)
  876.     DB    '  H or I  Tag 2, on/off',TAB,TAB
  877.      ENDIF    ;TAGS (ldr)
  878.     DB    '  S or D:  $SYS or $DIR',CR,LF
  879.  
  880.      IF    TAGS    ;(ldr)
  881.     DB    '  J or K  Tag 3, on/off',TAB,TAB
  882.      ENDIF    ;TAGS (ldr)
  883.     DB    '  A or N:  $ARC or $Non-ARC',CR,LF
  884.  
  885.      IF    TAGS    ;(ldr)
  886.     DB    '  L or M  Tag 4, on/off',CR,LF
  887.      ENDIF    ;TAGS (ldr)
  888.     DB    LF    ; end of usual file tags and attributes
  889.  
  890.     DB    'File erase or unerase:',CR,LF
  891.     DB    '  E or U:  Erase or Unerase (into current user)'
  892.     DB    CR,LF,LF
  893.  
  894.      IF    SPLIT ; (ldr)
  895.     DB    'File splitting (handle with care):',CR,LF
  896.     DB    '  C:  Cut file into segments, each '
  897.     DB    SEGSIZ+48, ' extents long',CR,LF
  898.     DB    '  B:  Bind files previously Cut'
  899.     DB    CR,LF,LF
  900.      ENDIF    ;SPLIT (ldr)
  901.  
  902.     DB    'Add "#" after any letter option to work in ALL user areas'
  903.     DB    0    ; end of help text
  904.  
  905.     JMP    QUIT2
  906.  
  907. ;=============================================================================
  908.  
  909. ;    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
  910.  
  911. ;-----------------------------------------------------------------------------
  912.  
  913. ;                CRTOUT
  914.  
  915. ; This subroutine sends the character in register A to the console.  Registers
  916. ; BC, DE, and HL are preserved.
  917.  
  918. CHAROUT:
  919.  
  920.     PUSH    H        ;save registers
  921.     PUSH    D
  922.     PUSH    B
  923.     MOV    E,A        ;get character into E
  924.     MVI    C,06        ;BDOS direct console I/O
  925.     CALL    BDOS
  926.     POP    B        ;restore registers
  927.     POP    D
  928.     POP    H
  929.     RET
  930.  
  931. ;-----------------------------------------------------------------------------
  932.  
  933. ;                CRLF
  934.  
  935. ; This routine sends a carriage return and linefeed to the console.
  936.  
  937. CRLF:    CALL    ILPRT
  938.     DB    CR,LF,0
  939.     RET
  940.  
  941. ;-----------------------------------------------------------------------------
  942.  
  943. ;                FILL
  944.  
  945. ; This subroutine fills memory starting at HL for a length B with the byte
  946. ; in A.
  947.  
  948. FILL:
  949.     MOV    M,A
  950.     INX    H
  951.     DCR    B
  952.     JNZ    FILL
  953.     RET
  954.  
  955. ;-----------------------------------------------------------------------------
  956.  
  957. ;                ILPRT
  958.  
  959. ; This subroutine prints the string that follows its call.  The string must
  960. ; be terminated with a null (0).
  961.  
  962. ILPRT:    POP    H    ;get address following call into HL
  963.  
  964. ILPRT1:    MOV    A,M    ;get character from message
  965.     INX    H    ;point to next character
  966.     ORA    A    ;test for null indicating end of message
  967.     JZ    ILPRT2    ;if end, fix up return address
  968.     MOV    E,A    ;have BDOS send character it to console
  969.     MVI    C,2
  970.     PUSH    H    ;save pointer to string
  971.     CALL    BDOS
  972.     POP    H    ;restore pointer
  973.     JMP    ILPRT1    ;process it
  974.  
  975. ILPRT2:    PUSH    H    ;set up return address to just past message
  976.     RET
  977.  
  978. ;-----------------------------------------------------------------------------
  979.  
  980. ;                PRTSTR
  981.  
  982. ; This subroutine prints a string of characters pointed to by DE.  The number
  983. ; of characters is in the C register.  Blanks are not printed; instead, the
  984. ; blanks counter pointed to by HL is incremented.
  985.  
  986. PRTSTR:    LDAX    D        ;get character
  987.     CPI    ' '        ;see if it is a blank
  988.     CZ    UPCOUNT        ;if so, up the count
  989.     CNZ    CHAROUT        ;if not, output the character
  990.     INX    D
  991.     DCR    C        ;check count
  992.     JNZ    PRTSTR
  993.     RET
  994.  
  995. UPCOUNT:
  996.     PUSH    PSW        ;save flags
  997.     INR    M        ;increase the blank counter
  998.     POP    PSW        ;restore flags
  999.     RET
  1000.  
  1001. ;-----------------------------------------------------------------------------
  1002.  
  1003. ;                PRTBLK
  1004.  
  1005. ; This subroutine prints blank spaces given by the count in C.  The routine
  1006. ; will work even for a count of zero.
  1007.  
  1008. PRTBLK:    INR    C        ;turn 0 into 1
  1009. PRTBL1:    DCR    C        ;check count
  1010.     RZ            ;return if count exhausted
  1011.     MVI    A,' '        ;set character to print
  1012.     CALL    CHAROUT
  1013.     JMP    PRTBL1
  1014.  
  1015. ;=============================================================================
  1016.  
  1017. ;        S E T U P    S U B R O U T I N E S
  1018.  
  1019. ;-----------------------------------------------------------------------------
  1020.  
  1021. ;                SIGNON
  1022.  
  1023. ; This subroutine displays the program signon message.
  1024.  
  1025. SIGNON:    CALL    ILPRT
  1026.     DB    CR,LF,'CFA - v'
  1027.     DB    VERSION / 10 + '0'
  1028.     DB    '.'
  1029.     DB    VERSION MOD 10 + '0'
  1030.  
  1031.      IF    ZCPR3
  1032.     DB    ' for ZCPR3'
  1033.      ENDIF    ;ZCPR3
  1034.  
  1035.     DB    CR,LF,0
  1036.     RET
  1037.  
  1038. ;-----------------------------------------------------------------------------
  1039.  
  1040. ;                CHKHLP
  1041.  
  1042. ; This subroutine checks to see if the user has invoked the program in a
  1043. ; way to request the built-in help screen.  The help screen is shown if the
  1044. ; command has no tail or if the tail begins with a slash.
  1045.  
  1046. CHKHLP:    LDA    FCB+1        ;get first character of first parameter
  1047.     CPI    ' '        ;no name?
  1048.     JZ    HELP        ;if so, go to HELP
  1049.     CPI    '/'        ;parameter starts with slash?
  1050.     JZ    HELP        ;if so, go to HELP
  1051.     RET            ;return with flag set appropriately
  1052.  
  1053. ;-----------------------------------------------------------------------------
  1054.  
  1055. ;                INIT
  1056.  
  1057. ; This subroutine initializes the data areas in the program so that GO
  1058. ; command will re-run the program correctly.
  1059.  
  1060. INIT:    XRA    A        ;zero the accumulator
  1061.     STA    CHGFLAG        ;preset control flags
  1062.     STA    RSTFLAG
  1063.     STA    DIRCODE
  1064.  
  1065.      IF    SPLIT    ;(ldr)
  1066.     STA    MRKSEG        ; zero extent counter    
  1067.     MVI    A,'A'
  1068.     STA    EXTLTR        ; set first letter for segment rename
  1069.      ENDIF    ;SPLIT
  1070.     
  1071.     LXI    H,AMBFIL2
  1072.     MVI    B,16
  1073.     CALL    FILL        ;clear the fcb
  1074.  
  1075.     MVI    A,'?'
  1076.     MVI    B,16
  1077.     LXI    H,AMBFIL
  1078.     CALL    FILL
  1079.  
  1080.     LHLD    0001        ;get warmboot address (base of bios + 3)
  1081.     LXI    D,27H        ;offset for jump to bios write
  1082.     DAD    D        ;compute address for write routine
  1083.     SHLD    WRITE + 1    ;load our vector with this address
  1084.  
  1085.     RET
  1086.  
  1087. ;-----------------------------------------------------------------------------
  1088.  
  1089. ;                SETDU
  1090.  
  1091. ; This subroutine gets and saves the values of the currently logged in drive
  1092. ; and user area and the drive and user specified (if any) on the command line
  1093. ; for the files to be operated on.
  1094.  
  1095. SETDU:        ;get currently logged in user number
  1096.  
  1097.     MVI    C,20H        ;BDOS get/set user number function
  1098.     MVI    E,0FFH        ;get user flag
  1099.     CALL    BDOS
  1100.     STA    DEFUSR
  1101.     STA    SRCUSR        ;save for now as source user also
  1102.  
  1103.         ;get the currently logged in drive
  1104.  
  1105.     MVI    C,19H        ;bdos get drive number function
  1106.     CALL    BDOS        ;get drive number
  1107.     STA    DEFDRV
  1108.     INR    A        ;change range 1-16 and
  1109.     STA    SRCDRV        ;..save for now as source drive also
  1110.     
  1111.         ;now log in the drive and user in file spec
  1112.  
  1113.     LDA    FCB        ;get drive spec from FCB
  1114.     ORA    A        ;see if default specified
  1115.     JZ    SETDU1
  1116.     STA    SRCDRV        ;save source drive
  1117.     SUI    1        ;get in range 0-15
  1118.     CALL    LOGDRV        ;log in the drive
  1119.     XRA    A        ;and change FCB to show default drive
  1120.     STA    FCB
  1121.  
  1122. SETDU1:
  1123.  
  1124.      IF    ZCPR3
  1125.     LDA    FCB+13        ;get user number from S1 byte
  1126.     STA    SRCUSR        ;save as source user area
  1127.     CALL    LOGUSR        ;log in the user number
  1128.      ENDIF    ;ZCPR3
  1129.  
  1130.     RET
  1131.  
  1132. ;-----------------------------------------------------------------------------
  1133.  
  1134. ; These two routines log in the drive or user number given in the A register.
  1135. ; No registers are preserved.
  1136.  
  1137. LOGDRV:    MOV    E,A
  1138.     MVI    C,0EH
  1139.     CALL    BDOS
  1140.     RET
  1141.  
  1142. LOGUSR:    MOV    E,A
  1143.     MVI    C,20H
  1144.     CALL    BDOS
  1145.     RET
  1146.  
  1147. ;-----------------------------------------------------------------------------
  1148.  
  1149. ;                GETOPT
  1150.  
  1151. ; Process option specified on the command line.  If there is an error, the
  1152. ; routine jumps to HELP which in turn jumps to QUIT.  If a named directory
  1153. ; is specified for the destination on the command line, then its user number
  1154. ; is obtained from address TFCB+13.  The drive is checked to make sure that
  1155. ; the destination is on the same drive.
  1156.  
  1157. GETOPT:
  1158.  
  1159.      IF    ZCPR3
  1160.  
  1161.         ;check for destination specified using named directory
  1162.  
  1163.     LDA    TFCB        ;check for drive number
  1164.     ORA    A        ;if zero, no DIR: or DU: given
  1165.     JZ    GETOPT1
  1166.  
  1167.         ;check for correct drive spec
  1168.  
  1169.     LXI    H,SRCDRV    ;point to source drive value
  1170.     CMP    M
  1171.     JNZ    BADDRV        ;if not the same, jump to bad drive message
  1172.  
  1173.         ;get the user number
  1174.  
  1175.     LDA    TFCB + 13
  1176.     STA    OPTION        ;store user number as option
  1177.     JMP    CHKNUM        ;check for valid user number
  1178.  
  1179. BADDRV:    CALL    ILPRT        ;destination and source drives not same
  1180.     DB    BELL
  1181.     DB    'Source and Destination Drives must be same',0
  1182.     JMP    QUIT
  1183.  
  1184.      ENDIF    ;ZCPR3
  1185.  
  1186. GETOPT1:
  1187.     LXI    H,TFCB        ;point to parsed second parameter
  1188.     MOV    A,M        ;make sure it wasn't of form 'D:'
  1189.     ORA    A        ;drive byte should be zero
  1190.     JNZ    BADOPT
  1191.     INX    H        ;now look at data entered
  1192.  
  1193.     MOV    A,M        ;get the first character
  1194.     CALL    GETNUM        ;try to read it as a number
  1195.     JC    LETTER        ;if not, must be a letter or bad
  1196.     MOV    B,A        ;save digit in B
  1197.     STA    OPTION        ;..and as interim option
  1198.     INX    H        ;try next character
  1199.     MOV    A,M
  1200.     CPI    ' '        ;if it is a blank
  1201.     JZ    CHKNUM        ;..go to test user number value
  1202.  
  1203.     CALL    GETNUM        ;see if second character is a number
  1204.     JC    BADOPT        ;if not, we have a bad option spec
  1205.  
  1206.     MOV    C,A        ;save second digit
  1207.     MOV    A,B        ;get first digit back
  1208.     ADD    A        ;double it three times to make 8x
  1209.     ADD    A
  1210.     ADD    A
  1211.     ADD    B        ;now add original in twice to make 10x
  1212.     ADD    B
  1213.     ADD    C        ;finally, add in second digit
  1214.     STA    OPTION        ;..and save the final result
  1215.  
  1216.         ;check for valid user number (in range and not same
  1217.         ;as logged in user number)
  1218.  
  1219. CHKNUM:    LDA    OPTION        ;make sure we have the user number
  1220.     CPI    32        ;test for valid user number range
  1221.     JNC    BADNUM
  1222.     LXI    H,SRCUSR    ;see if same as source user
  1223.     CMP    M
  1224.     JZ    SAMENUM        ;if so, give message
  1225.     RET
  1226.  
  1227. LETTER:        ;check for valid letter option
  1228.     PUSH    PSW        ;save option letter
  1229.     INX    H        ;check whether option followed by '#'
  1230.     MOV    A,M        
  1231.     CPI    '#'
  1232.     JNZ    LETTER0        ;not "all users" switch, don't save it
  1233.     STA    ALLUSR
  1234. LETTER0:
  1235.     POP    PSW        ;get option character back
  1236.     LXI    H,OPTLIST    ;point to list of valid options
  1237.     MOV    C,M        ;get number of options in list
  1238. LETTER1:            ;loop through them checking
  1239.     INX    H
  1240.     CMP    M        ;compare to list entry
  1241.     JZ    GOODOPT        ;if it matches, we have a good option
  1242.     DCR    C        ;else, count down
  1243.     JNZ    LETTER1        ;..and try again
  1244.     JMP    HELP        ;we get here if option is not valid
  1245.  
  1246. GOODOPT:    ;we have a good option letter
  1247.     STA    OPTION
  1248.     RET
  1249.  
  1250. BADOPT:        ;we have a bad option specifier
  1251.     CALL    ILPRT
  1252.     DB    BELL,0    ; if bad option, just a bell, then menu
  1253.     JMP    HELP
  1254.  
  1255. BADNUM:        ;we have an illegal user number
  1256.     CALL    ILPRT
  1257.     DB    BELL
  1258.     DB    'User number must be 0-31',0
  1259.     JMP    QUIT
  1260.  
  1261. SAMENUM:    ;give message about already in that user area
  1262.     CALL    ILPRT
  1263.     DB    BELL
  1264.     DB    'Destination/Source user numbers must be different',0
  1265.     JMP    QUIT
  1266.  
  1267.         ;subroutine to check for number character
  1268.         ;returns with carry set if not a number
  1269.  
  1270. GETNUM:    CPI    '0'        ;see if less than '0'
  1271.     RC            ;if so, set carry flag as signal
  1272.     CPI    '9'+1        ;see if more than '9'
  1273.     CMC            ;reverse sense of carry flag
  1274.     RC            ;if >9, return with carry set
  1275.     SUI    '0'        ;convert to number value
  1276.     RET            ;carry is clear
  1277.  
  1278.         ;list of valid options
  1279.  
  1280. OPTLIST:
  1281.     DB    ENDLIST-OPTLIST    ;number of options in list
  1282.     DB    ' SDRWANEU'    ;valid options
  1283.  
  1284.      IF    TAGS        ; include options for tags
  1285.     DB    'FGHIJKLM'    ; (ldr)
  1286.      ENDIF    ; TAGS
  1287.  
  1288.      IF    SPLIT        ; include options for file splitting
  1289.     DB    'CB'        ; (ldr)
  1290.      ENDIF    ; SPLIT
  1291.  
  1292. ENDLIST:    ; just a marker, no code.
  1293.  
  1294. ;-----------------------------------------------------------------------------
  1295.  
  1296. ;                CHKRO
  1297.  
  1298. ; This routine checks to see if the destination drive is read-only.  If it
  1299. ; is, an appropriate error message is displayed and the program aborts with
  1300. ; a jump to QUIT.  If the option is display only (option = space char), then
  1301. ; this test is skipped.
  1302.  
  1303. CHKRO:    LDA    OPTION        ;see if display option is in effect
  1304.     CPI    ' '
  1305.     RZ            ;if so, skip rest of test
  1306.  
  1307.     MVI    C,1DH        ;get R/O vector from BDOS
  1308.     CALL    BDOS
  1309.  
  1310.         ;calculate number of left-shifts needed
  1311.  
  1312.     LDA    SRCDRV        ;get the target drive number
  1313.     CMA            ;complement it (makes 255-SRCDRV)
  1314.     ADI    17        ;makes A = 16 - SRCDRV (value 1-16)
  1315.  
  1316.         ;shift word in HL to put bit of R/O vector for
  1317.         ;specified drive into high bit position
  1318.  
  1319. CHKRO1:    DCR    A        ;test for done
  1320.     JZ    CHKRO2        ;if so, jump
  1321.     DAD    H        ;shift HL to left
  1322.     JMP    CHKRO1        ;and loop
  1323.  
  1324. CHKRO2:    DAD    H        ;move high bit into carry flag
  1325.     RNC            ;if not R/O, return
  1326.     CALL    ILPRT        ;else print R/O error message
  1327.     DB    BELL
  1328.     DB    'Drive is R/O',0
  1329.  
  1330.     JMP    QUIT        ;abort program
  1331.  
  1332. ;=============================================================================
  1333.  
  1334. ;        M I S C E L L A N E O U S    R O U T I N E S
  1335.  
  1336. ;-----------------------------------------------------------------------------
  1337.  
  1338. ;                SETPTR
  1339.  
  1340. ; This subroutine uses the value of the directory code to calculate a pointer
  1341. ; to the FCB in the DMA buffer.  This is done by multiplying the directory code
  1342. ; by 32 and adding it to the DMA address (DMAADDR).  The result is saved in
  1343. ; DMAPTR.
  1344.  
  1345. SETPTR:
  1346.     LDA    DIRCODE     ;get the directory code
  1347.     ADD    A        ;offset by 32 bytes per entry
  1348.     ADD    A
  1349.     ADD    A
  1350.     ADD    A
  1351.     ADD    A
  1352.     MOV    E,A        ;move value into DE
  1353.     MVI    D,0
  1354.     LXI    H,DMAADDR    ;get buffer address
  1355.     DAD    D        ;compute offset into buffer
  1356.     SHLD    DMAPTR        ;save the address into the buffer
  1357.     RET
  1358.  
  1359. ;-----------------------------------------------------------------------------
  1360.  
  1361. ;                SETCHGFL
  1362.  
  1363. ; This subroutine sets the change-flag to show that the directory sector
  1364. ; has been modified and needs to be written out to disk.
  1365.  
  1366. SETCHGFL:
  1367.     PUSH    PSW
  1368.     MVI    A,0FFH        ;set the sector change flag
  1369.     STA    CHGFLAG
  1370.     POP    PSW
  1371.     RET
  1372.  
  1373. ;=============================================================================
  1374.  
  1375. ;            D A T A    A R E A
  1376.  
  1377. ;-----------------------------------------------------------------------------
  1378.  
  1379. OLDSTK:                ;place to keep old stack pointer
  1380.     DS    2
  1381.  
  1382. BLNKCNT:            ;count of blank characters in file name
  1383.     DS    1
  1384.  
  1385. CHGFLAG:            ;flag for change requiring write
  1386.     DS    1
  1387.  
  1388. RSTFLAG:            ;flag for need to reset disk system
  1389.     DS    1
  1390.  
  1391. AMBFIL:                ;working fcb
  1392.     DS    16
  1393.  
  1394. AMBFIL2:            ;space for rest of FCB
  1395.     DS    19
  1396.  
  1397. OPTION:                ;storage for new user number or option
  1398.     DS    1
  1399.  
  1400. ALLUSR:                ;storage for "all users" switch
  1401.     DS    1
  1402.  
  1403. DIRCODE:            ;storage for directory code (0-3)
  1404.     DS    1
  1405.  
  1406. DMAPTR:                ;address of FCB in DMA buffer
  1407.     DS    2
  1408.  
  1409. DEFDRV:                ;current default drive
  1410.     DS    1
  1411.  
  1412. SRCDRV:                 ;source drive
  1413.     DS    1
  1414.  
  1415. DEFUSR:                ;current default user number
  1416.     DS    1
  1417.  
  1418. SRCUSR:                ;source user area from file spec
  1419.     DS    1
  1420.  
  1421.      IF    SPLIT        ; (ldr)
  1422. MRKSEG:
  1423.     DS    1        ; extent counter for split segments
  1424.  
  1425. EXTLTR:
  1426.     DS    1        ; letter code for renamed segments
  1427.      ENDIF    ;SPLIT
  1428.  
  1429.     DS    60        ;room for local stack
  1430.  
  1431. NEWSTK:
  1432.     END
  1433.