home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / dskutl / archive.aqm / ARCHIVE.ASM
Encoding:
Assembly Source File  |  1985-02-10  |  26.6 KB  |  878 lines

  1. ;               ARCHIVE - File Archive/Backup Utility
  2. ;               Version 1.0, 6-June-82 by Kelly Smith
  3. ;      ARCHIVE  is  a  user oriented disk maintenance  utility  for 
  4. ; archival  storage and file backup.   User facilities include  the 
  5. ; ability to selectively 'tag' files for archival (or non-archival) 
  6. ; attributes,  display  file  archive attributes,  or  backup  non-
  7. ; archive files to a selected disk.  Wild-card filenames (using '*' 
  8. ; and/or  '?')  may be used freely,  to select some or  all  (i.e., 
  9. ; '*.*') files for archiving.
  10. ;                      - Theory of Operation -
  11. ;      Digital  Research's  MP/M-II and CP/M-86  Operating  Systems 
  12. ; utilize a file attribute for archival backup of any file addition 
  13. ; or update to the disk directory.   This attribute is 'reset' when 
  14. ; an  application  program is required to write a file to  a  disk.  
  15. ; The  actual 'mechanism' for this archive function is realized  by 
  16. ; controlling  the  most significant bit of the third character  of 
  17. ; the FCB (File Control Block) directory entry (i.e.,  position 11, 
  18. ; identified  as byte position T3,  with the Archive attribute  bit 
  19. ; (bit  7  of byte T3) identified as T3').   It is  then  a  simple 
  20. ; matter to identify a file as archived (e.g.,  backed-up) when T3' 
  21. ; is a 'one',  and non-archived (e.g.,  needs to be backed-up) when 
  22. ; T3'  is  a  'zero'.   The 'not-so-simple' part,  is  the  utility 
  23. ; required   to  keep  track  of  the  archive  attributes   on   a 
  24. ; disk...thats where ARCHIVE comes in, and works with CP/M-80 (with 
  25. ; the help of a little 'patch'),  as well as with MP/M-II and CP/M-
  26. ; 86 (when translated for 8086 CPU operation).    
  27. ;                       - Examples of Usage -
  28. ;      At  the CP/M user command prompt,  (usually 'A>'),  the user 
  29. ; has the option for four single letter ARCHIVE command directives, 
  30. ; as follows:
  31. ;                S - Set file archive attribute.
  32. ;                R - Reset file archive attribute.
  33. ;                D - Display file arcive attribute.
  34. ;                B - Backup non-archived files.
  35. ;      ARCHIVE  is  invoked by the user at the CP/M  command  level 
  36. ; therefore, as follows,
  37. ;                    A>ARCHIVE FN.FT OPTION<cr>
  38. ; ...where,  'FN.FT' is an amibiguous or un-ambiguous filename  and 
  39. ; filetype,  followed  by one of the single character options,  and 
  40. ; then a keyboard RETURN entry.  An actual example then might be:
  41. ;                       A>archive b:*.* b<cr>
  42. ; ...then,  we  are executing ARCHIVE from the 'A' disk drive,  for 
  43. ; all  filenames and filetypes on disk 'B' whose archive  attribute 
  44. ; has   been  'reset',   to  be  'backed-up'  to  some   (as   yet) 
  45. ; indeterminate destination disk.
  46. ;      Options  'S',  'R' and 'D' (Set,  Reset,  and Display)  when 
  47. ; invoked,  will  cause each file found in the directory 'match' to 
  48. ; be  displayed by 'multiple extension'...that is,  each  directory 
  49. ; entry will be displayed,  with its 'extent' number,  followed  by 
  50. ; the archive attribute action/status as 'S' or 'R' (Set or Reset).
  51. ;      Option  'B'  (Backup)  will  request the  user  to  enter  a 
  52. ; destination disk letter (A to P), then proceed to scan the source 
  53. ; disk  directory for 'reset' archive file  entries.   Any  'reset' 
  54. ; entries  will  then be 'set' (indicating that the file  has  been 
  55. ; archived)  and then these files will be copied to the destination 
  56. ; disk  (Note  however,  that  these  files  will  not  retain  any 
  57. ; previously  set  attributes of 'Read Only' or 'System'  had  they 
  58. ; been  set...all  files  copied to the destination  disk  will  be 
  59. ; 'tagged'  as archived only).   If a disk becomes full,  the  user 
  60. ; will  be requested to remove the disk from the destination  drive 
  61. ; and  insert another for completion of the  backup  process.   Any 
  62. ; file  that has not been completely copied to the destination disk 
  63. ; at the time that disk is detected as 'full', will be deleted from 
  64. ; that disk,  and the file copy will resume intact on the next disk 
  65. ; installed in the destination drive.
  66. ;      Users of MP/M-II can use ARCHIVE immediately, with no system 
  67. ; modification  required  because it "knows" about file  archiving.  
  68. ; However,  for  CP/M-80 users,  they must patch there system  BDOS 
  69. ; (Basic Disk Operating System) to "teach" CP/M-80 file  archiving.  
  70. ; The following code must be edited and assembled,  then loaded (as 
  71. ; a  '.HEX'  file)  with DDT (Dynamic Debugging  Tool)  using  your 
  72. ; normal  system  installation  procedure for  merging  your  'Boot 
  73. ; Loader'  and  BIOS (Basic Input/Output System) into  your  system 
  74. ; "image"  for eventual SYSGEN'ing (this code assumes the  standard 
  75. ; SYSGEN position of address 980H for the start of the CCP (Console 
  76. ; Command   Processor,   with   a  CP/M-80  system  'size'  of   56 
  77. ; Kilobytes...change the value at label MSIZE to suit your needs).
  78. ;                           *+*+*+*+*+*+*
  79. ;                           *+         +*
  80. ;                           *+ WARNING +*
  81. ;                           *+         +*
  82. ;                           *+*+*+*+*+*+*
  83. ;      You  must incorporate this 'archive patch' in an  unmodified 
  84. ; CP/M-80   (version   2.2)   BDOS   O-N-L-Y...any   other    prior 
  85. ; modifications  will (no doubt) be overlayed by this one,  causing 
  86. ; unpredictable results...'nuf said.
  87. ;                                              - KS -
  88. ;
  89. ;
  90. ;
  91. ; msize        equ    56        ; size of this CP/M 2.2 system
  92. ; ;
  93. ; bdos$loc    equ    (msize-20)*1024+3c00h    ; base address of BDOS
  94. ; wrsec        equ    bdos$loc+03b8h    ; address of write sector routine
  95. ; pntdir    equ    bdos$loc+055eh    ; address of directory pointer routine
  96. ; reset$archive    equ    bdos$loc+0df0h    ; address of reset archive bit patch
  97. ; ;
  98. ; ccp$base    equ    0980h        ; sysgen ccp base position
  99. ; bdos$entry    equ    ccp$base+0806h    ; sysgen bdos entry position
  100. ; wrt$dir    equ    bdos$entry+05c8h; 'wrsec' call location, in DIR write routine
  101. ; scratch    equ    bdos$entry+0deah; scratch RAM inside bdos for patch
  102. ;     org    wrt$dir            ; patch 'call wrsec'
  103. ; ;
  104. ;     call    reset$archive        ; call patch in scratch RAM
  105. ; ;
  106. ;     org    scratch            ; patch area for 'archive bit reset'
  107. ; ;
  108. ;     call    pntdir            ; point to directory entry in buffer
  109. ;     lxi    d,11            ; make offset to 't3' in FCB
  110. ;     dad    d
  111. ;     mov    a,m            ; get 't3' character from FCB
  112. ;     ani    07fh            ; kill archive bit position
  113. ;     mov    m,a            ; return reset archive bit to FCB
  114. ;     call    wrsec            ; write directory sector
  115. ;     ret                ; return to 'wrt$dir' routine
  116. ; ;
  117. ; ;
  118. ; ;
  119. ;     end
  120. ;
  121. ;
  122. ;
  123. ; *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
  124. ; *+                                                                     +*
  125. ; *+  ARCHIVE.ASM Utility Version 1.0,  as of 6-June-82, by Kelly Smith  +*
  126. ; *+                                                                     +*
  127. ; *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
  128. ;
  129. ;
  130. true    equ    -1        ; define true
  131. false    equ    not true    ; define false
  132. ;
  133. mpm    equ    not true    ; conditional assembly for MP/M
  134. ;
  135. bdos    equ    5        ; CP/M entry point
  136. exit    equ    0        ; CP/M exit point
  137. dfcb    equ    5ch        ; CP/M default fcb
  138. fcbext    equ    dfcb+12        ; fcb extent byte
  139. fcbrno    equ    dfcb+32        ; fcb record number byte
  140. dbuff    equ    80h        ; default disk buffer
  141. coninp    equ    1        ; console character input function
  142. pchar    equ    2        ; print character function
  143. dircon    equ    6        ; direct console i/o function
  144. pmessg    equ    9        ; print message function
  145. constat    equ    11        ; console status function
  146. version    equ    12        ; return version number function
  147. rsetdsk    equ    13        ; reset disk system function
  148. seldsk    equ    14        ; select drive function
  149. open    equ    15        ; open file function
  150. close    equ    16        ; close file function
  151. srchfst    equ    17        ; search for first file match function
  152. srchnxt    equ    18        ; search for next file match function
  153. delete    equ    19        ; delete file function
  154. read    equ    20        ; read record function
  155. write    equ    21        ; write record function
  156. make    equ    22        ; make file function
  157. currdsk    equ    25        ; return current logged disk function
  158. stdma    equ    26        ; set dma address function
  159. attrib    equ    30        ; set file attributes function
  160. tab    equ    09h        ; tab character
  161. lf    equ    0ah        ; line feed character
  162. cr    equ    0dh        ; carriage return character
  163.  
  164.     org    100h
  165.  
  166. ;
  167. ; jump over authorship notice
  168. ;
  169.     jmp    over
  170. ;
  171.     db    cr,lf,'ARCHIVE Ver.1.0, 6-Jun-82:  Kelly Smith'
  172.     db    cr,lf,'3055 Waco Avenue, Simi Valley, CA 93063'
  173.     db    cr,lf,'Z'-40h    ; force end-of-file for display
  174. ;
  175. ; make a new stack pointer at CP/M serial number
  176. ;
  177. over:    lhld    bdos+1        ; set up a stack
  178.     sphl            ; at top of tpa
  179. ;
  180. ; get curent logged disk, and save it
  181. ;
  182.     mvi    c,currdsk    ; return curent disk
  183.     call    bdos
  184.     sta    logdsk        ; save as logged disk
  185. ;
  186. ; reset disk system in case someone swapped in new disk on the system
  187. ;
  188.     mvi    c,rsetdsk    ; reset disk system function
  189.     call    bdos
  190. ;
  191. ; now return to original login disk
  192. ;
  193.     lda    logdsk        ; get logged in disk number
  194.     mov    e,a        ; do disk select
  195.     mvi    c,seldsk
  196.     call    bdos    
  197. ;
  198. ; announcing, the new and improved ARCHIVE...it beats as it sweeps, as it cleans
  199.     lxi    d,signon    ; point to signon message
  200.     mvi    c,pmessg    ; print string fuction
  201.     call    bdos        ; print it
  202. ;
  203. ; check for proper environment, we only live for CP/M 2.2
  204. ;
  205.     mvi    c,version    ; check version number, must be 2.2
  206.     call    bdos
  207.     cpi    022h        ; version number correct?
  208.     lxi    d,bad$ver$num    ; set-up bad version message, in case its not
  209.     jnz    arcexit        ; bail-out now, if wrong version number
  210. ;
  211.     if    not mpm        ; CP/M-80 does not know about archiving...
  212.     lhld    bdos+1        ; see if archiving installed in CP/M
  213.     lxi    d,05c9h        ; add offset to archive patch address
  214.     dad    d
  215.     shld    arch$addr    ; save address for later
  216.     mov    a,m        ; get low byte content
  217.     cpi    0b8h        ; is this address for write sector routine?
  218.     jnz    patch$bdos    ; if not, patch it back into bdos
  219.     lxi    d,noarch    ; tell user that archive is not installed
  220.     jmp    arcexit        ; exit via CP/M warm boot
  221. ;
  222. patch$bdos:
  223. ;
  224.     lhld    bdos+1        ; patch write sector address back to bdos
  225.     lxi    d,03b2h        ; add offset address of 'wrsec'
  226.     dad    d
  227.     xchg            ; address patch info to [DE]
  228.     lhld    arch$addr    ; get address to patch in [HL]
  229.     mov    m,e        ; low byte address patched first
  230.     inx    h        ; bump pointer
  231.     mov    m,d        ; high byte address patched second
  232.     endif            ; endif MP/M
  233. ;
  234. ; check if filename specified, abort if not
  235. ;
  236.     lda    dfcb+1        ; this will be a space, if no filename
  237.     cpi    ' '
  238.     jnz    gotname        ; if not space, probably filename
  239.     lxi    d,no$file$nam    ; inform user of error of their way...
  240.     mvi    c,pmessg
  241.     call    bdos
  242.     lxi    d,opts        ; tell'em about backup options also
  243.     jmp    arcexit        ; bail-out now, no filename
  244. ;
  245. ; got a name, now check to see which (if any) disk specified
  246. gotname:lda    dfcb        ; check for specific drive
  247.     dcr    a
  248.     mov    e,a        ; set up for select disk call
  249.     mvi    c,seldsk
  250.     inr    a        ; if no specified drive, skip call
  251.     sta    src$dsk$num    ; save drive specifier for later check
  252.     cnz    bdos
  253.     xra    a        ; now zap out drive specifier
  254.     sta    dfcb
  255.     mvi    a,'?'        ; force extent number wild
  256.     sta    dfcb+12
  257.     lda    dfcb+17        ; get "B", "S", "R" or "D" option
  258.     sta    option
  259.     cpi    'B'        ; backup operation?
  260.     jz    okopt
  261.     cpi    'S'        ; set archive operation?
  262.     jz    okopt
  263.     cpi    'R'        ; reset archive operation?
  264.     jz    okopt
  265.     cpi    'D'        ; just display?
  266.     jz    okopt
  267. badopt:    lxi    d,ilgopt    ; let'em know it was an illegal option
  268. arcexit:mvi    c,pmessg    ; bitch, bitch, bitch... 
  269.     call    bdos
  270.     jmp    exit
  271. ; findout now, if operation is for backup or general lobotomy
  272. ;
  273. okopt:    lda    option        ; get option specifier
  274.     cpi    'B'
  275.     jnz    arc$s$r        ; if not backup, must be set/reset archive
  276. dest:    lxi    d,req$dest    ; request destination disk for backup files
  277.     mvi    c,pmessg
  278.     call    bdos
  279.     mvi    c,coninp    ; get console input character
  280.     call    bdos
  281.     ani    05fh        ; force upper case
  282.     sbi    'A'        ; force binary digit
  283.     cpi    16        ; disk >P?
  284.     jnc    dest        ; must satisfy ourselves with 16 disks maximum
  285.     lxi    h,logdsk    ; is this jerk backing up to the same disk?
  286.     ani    0fh        ; strip high nibble for match to logged disk
  287.     cmp    m
  288.     push    psw        ; save flags
  289.     inr    a        ; save re-adjusted disk number
  290.     sta    dest$dsk$num
  291.     pop    psw        ; get flags
  292.     jz    dsksame        ; if same, tell'em so now
  293.     inx    h        ; bump pointer to destination disk
  294.     mov    a,m        ; get disk number
  295.     inx    h        ; bump pointer to source disk number
  296.     cmp    m        ; any chance he specified destination as source
  297.     jnz    backup        ; if not, we can (finally) proceed with backup
  298. dsksame:lxi    d,same$dsk    ; sob...(read this anyway you want)
  299.     mvi    c,pmessg
  300.     call    bdos
  301.     jmp    dest        ; computers never lose their patience...
  302. ;
  303. ; ready for directory write operations now...do archive set/reset
  304. ;
  305. arc$s$r:call    crlf        ; tidy up display
  306.     xra    a        ; zero out file count
  307.     sta    filcnt
  308.     lxi    d,dfcb        ; find the first file and get its block map
  309.     mvi    c,srchfst
  310.     call    bdos
  311.     inr    a        ; search successful?
  312.     jnz    gotfile        ; yes, go process rest
  313.     lxi    d,no$file$fnd    ; oops, no file found
  314.     jmp    arcexit        ; exit via CP/M warm boot
  315. gotfile:dcr    a        ; compensate for 'inr' above
  316.     rrc            ; file offset to bits 5 and 6
  317.     rrc
  318.     rrc
  319.     ani    60h
  320.     lxi    h,dbuff        ; point to base of buffer
  321.     mov    c,a
  322.     mvi    b,0
  323.     dad    b        ; index by file offset
  324.     push    h        ; save directory entry, for the moment
  325.     lxi    b,filetable    ; point to base of file table
  326.     call    filepoint    ; get table pointer to [HL]
  327.     xchg            ; [DE] now points to place in table
  328.     lda    filcnt        ; keep track of number of files in table
  329.     inr    a
  330.     sta    filcnt        ; bump file count
  331.     pop    h        ; [HL] points to directory entry
  332.     mvi    b,32
  333.     call    blkmov        ; copy entry into table
  334. getnext:mvi    c,srchnxt    ; search for another entry
  335.     lxi    d,dfcb
  336.     call    bdos
  337.     inr    a        ; returns 0ffh at end of search
  338.     jnz    gotfile        ; got another one, go save it
  339. ;  end of directory encountered, now process them
  340. tagfile:call    abort        ; check for user abort of process
  341.     lxi    b,filetable-32    ; allow for file count one greater than desired
  342.     call    filepoint
  343.     push    h
  344.     lxi    d,dfcb        ; copy next name to default fcb
  345.     mvi    b,32
  346.     call    blkmov        ; someday I will grow up to be a Z80...
  347.     xra    a
  348.     sta    dfcb        ; clear drive number
  349.     lxi    d,-20        ; point back to extent field
  350.     dad    d
  351.     mvi    m,'$'        ; tag end of print here
  352.     pop    d        ; get back pointer to start of entry
  353.     inx    d        ; bump forward to name
  354.     mvi    c,pmessg
  355.     call    bdos        ; say what we're working on
  356.     mvi    e,' '        ; make space between filename.typ and extent
  357.     mvi    c,pchar
  358.     call    bdos
  359.     lda    dfcb+12        ; get extent number
  360.     push    psw        ; save it
  361.     adi    '0'        ; convert to ascii
  362.     mov    e,a
  363.     mvi    c,pchar        ; display extent number
  364.     pop    psw
  365.     call    bdos
  366.     lda    option        ; get B, S, R, or D
  367.     cpi    'D'        ; display only?
  368.     jz    nextfile
  369.     rrc            ; bit 7 = 0 for B, R, and D, 1 for S
  370.     ani    80h
  371.     mov    b,a        ; save mask
  372.     lxi    d,dfcb+11    ; point to t3
  373.     ldax    d        ; get it
  374.     ani    7fh        ; strip t3'
  375.     ora    b        ; set bit if option was S
  376.     stax    d        ; put it back
  377.     lxi    d,dfcb        ; point to start of fcb
  378.     xra    a        ; zap out drive field
  379.     stax    d
  380.     mvi    c,attrib    ; do set attributes function
  381.     call    bdos
  382. nextfile:
  383.     lda    dfcb+11        ; get t3
  384.     rlc            ; isolate t3'
  385.     ani    1
  386.     adi    'R'        ; make an R or S
  387.     sta    donmsg+1
  388.     lxi    d,donmsg
  389.     mvi    c,pmessg    ; print completion message for this file
  390.     call    bdos
  391.     call    crlf        ; tidy up display
  392.     lxi    h,filcnt    ; point to file counter
  393.     dcr    m        ; count it down
  394.     jz    exit        ; exit if done
  395.     jmp    tagfile        ; tag next file
  396. ;
  397. ; backup routine - does multiple file search and copy
  398. ;
  399. backup:    call    crlf        ; tidy up display
  400. noback:    call    abort        ; check for user abort of process
  401.     call    mfname        ; set-up multi-file search (seek and ye shall find?)
  402.     jnc    movname        ; file found, if no carry
  403.     lda    mfflg1        ; check if anything ever found...
  404.     ora    a
  405.     lxi    d,bakup$done    ; set-up backup done message
  406.     jnz    nofile        ; if not...indicate, no file found
  407.     lda    got$arc        ; check archive found flag
  408.     ora    a
  409.     jnz    arcexit        ; if not zero, must have found one (or more)
  410.     lxi    d,narcs        ; indicate no archive files found
  411.     jmp    arcexit
  412. nofile:    lxi    d,no$file$fnd    ; oops, no file found
  413.     jmp    arcexit        ; exit with perturbed message
  414. movname:lxi    h,dfcb+11    ; point to t3 in filetype
  415.     mov    a,m        ; get t3 byte
  416.     rlc            ; archive bit set?
  417.     jc    noback        ; if so, no backup required
  418.     rrc            ; adjust back to normal
  419.     sta    got$arc        ; set archive file found flag with non-zero
  420.     ori    080h        ; set 'archived' status back
  421.     mov    m,a        ; put it back
  422.     push    h        ; save pointer
  423.     lxi    d,dfcb        ; point to start of fcb
  424.     mvi    c,attrib    ; do set attributes function
  425.     call    bdos
  426.     pop    h        ; restore pointer
  427.     dcx    h        ; point to t2 in filetype
  428.     mov    a,m        ; get t2 byte
  429.     ani    07fh        ; strip-off t2'
  430.     mov    m,a        ; put it back
  431.     dcx    h        ; point to t1 in filetype
  432.     mov    a,m        ; get t1 byte
  433.     ani    07fh        ; strip-off t1'
  434.     mov    m,a        ; put it back
  435.     lxi    h,dfcb+1    ; point to filename for move and display
  436.     lxi    d,fname        ; display destination for filename
  437.     mvi    b,8        ; set-up to move 8 characters in filename
  438.     call    blkmov        ; too bad that 8080 is defacto standard
  439.     lxi    h,dfcb+9    ; point to filetype for move and display
  440.     lxi    d,fname+9    ; display destination for filetype
  441.     mvi    b,3        ; set-up to move 3 characters in filetype
  442.     call    blkmov        ; LDIR is so nifty...
  443. dspname:lxi    d,fname        ; display filename and filetype
  444.     mvi    c,pmessg
  445.     call    bdos
  446. ; save first fcb for use later as destination file name
  447.     mvi    b,11           ; number of characters to move
  448.     lxi    h,dfcb+1    ; from default fcb
  449.     lxi    d,destfcb+1     ; to destfcb
  450.     call    blkmov        ; round'em up and head'em out
  451. ; open the source file
  452.     lda    logdsk        ; select disk, in case of disk full status
  453.     mov    e,a
  454.     mvi    c,seldsk    ; select disk function
  455.     call    bdos    
  456.     lxi    d,dfcb        ; point to source fcb
  457.     mvi    c,open        ; attempt open
  458.     call    bdos
  459.     cpi    0ffh        ; file not found?
  460.     jnz    openok
  461.     lxi    d,src$open$err    ; oops, source file open error
  462.     jmp    arcexit        ; exit via CP/M warm boot
  463. ; open the destination file
  464. openok:    lxi    d,destfcb    ; point to destination fcb
  465.     lda    dest$dsk$num    ; get destination disk number
  466.     stax    d        ; set-up destination disk fcb disk number
  467.     mvi    c,delete    ; erase any old file
  468.     call    bdos
  469.     lxi    d,destfcb
  470.     mvi    c,make        ; make the new one
  471.     call    bdos
  472.     cpi    0ffh        ; succesfully created?
  473.     jz    full        ; oops, disk full...time for a new one
  474. ; read source file to buffer, write to destination as copy
  475. ;
  476. copy:    lxi    h,(table$end-filetable)/128    ; save buffer size
  477.     shld    bufmax
  478.     xra    a        ; clear eof flag
  479.     sta    eof$flg
  480. copy1:    call    abort        ; check for user abort on ctrl-c
  481.     lxi    h,0        ; set current buffer counter to zero
  482.     shld    bufcnt
  483.     lxi    h,filetable    ; set buffer start pointer to begin
  484.     shld    bufpnt
  485. ; file source reading loop to read all of buffer full or stop on eof
  486. copy2:    lhld    bufpnt        ; set dma address to buffer pointer
  487.     xchg
  488.     mvi    c,stdma
  489.     call    bdos
  490.     lxi    d,dfcb        ; point at default fcb for reading
  491.     mvi    c,read        ; function set for record read
  492.     call    bdos
  493.     ora    a        ; check if read was o.k., or eof
  494.     jnz    copy3        ; end of file so set eof flag
  495.     lhld    bufpnt        ; set buffer pointer up one sector
  496.     lxi    d,128
  497.     dad    d
  498.     shld    bufpnt
  499.     lhld    bufcnt        ; increase buffer sector count
  500.     inx    h
  501.     shld    bufcnt
  502.     xchg            ; check to see if memory is full
  503.     lhld    bufmax        ; maximum sector count
  504.     call    cdehl        ; compare
  505.     jnz    copy2        ; if not full go get next sector
  506.     jmp    copy4        ; go handle write operation
  507. ; here if read operation indicates that the file is at its end on read
  508. copy3:    mvi    a,0ffh        ; set eof flag
  509.     sta    eof$flg
  510. ; write output file processing loop to send memory buffer to destination disk file
  511. copy4:    lxi    h,filetable    ; set buffer pointer to start
  512.     shld    bufpnt
  513. copy5:    call    abort        ; check for user abort on ctrl-c
  514.     lhld    bufcnt        ; see if buffer is empty yet
  515.     mov    a,h
  516.     ora    l
  517.     jz    copy6        ; buffer empty so check eof flag
  518.     dcx    h        ; dec buffer sector count for each write
  519.     shld    bufcnt
  520.     lhld    bufpnt        ; set up dma address
  521.     push    h        ; save for size bump
  522.     xchg
  523.     mvi    c,stdma
  524.     call    bdos
  525.     pop    h
  526.     lxi    d,128        ; increase address for sector size
  527.     dad    d
  528.     shld    bufpnt
  529.     lxi    d,destfcb    ; point to output file fcb
  530.     mvi    c,write        ; write record function code
  531.     call    bdos        ; go write
  532.     ora    a           ; check if any error
  533.     jz    copy5        ; o.k., so do next record
  534.     jmp    full        ; oops...disk full, time for a new one
  535. ;
  536. copy6:    lda    eof$flg        ; buffer all written so go check eof
  537.     ora    a
  538.     jz    copy1        ; go to read next buffer full
  539.     lxi    d,destfcb    ; point at fcb for file close
  540.     mvi    c,close        ; close file function code
  541.     call    bdos
  542.     cpi    0ffh        ; check if close error
  543.     jnz    backup        ; if not, backup more files
  544.     lxi    d,src$close$err    ; oops, close error on destination disk
  545.     jmp    arcexit        ; exit with error message
  546. ;
  547. ; subroutine to compare [DE] to [HL], [Z] set if equal
  548. ;
  549. cdehl:    mov    a,d        ; high bytes equal?
  550.     cmp    h
  551.     rnz
  552.     mov    a,e        ; yes, how'bout low bytes?
  553.     cmp    l
  554.     ret            ; set zero, if equal
  555. ;
  556. ; subroutine to allow disk change, to continue backup process
  557. ;
  558. full:    lxi    d,destfcb    ; delete partial file on destination disk
  559.     mvi    c,delete
  560.     call    bdos
  561.     lxi    d,dsk$full    ; indicate that disk (or dir) is full
  562.     mvi    c,pmessg
  563.     call    bdos
  564.     lda    dest$dsk$num    ; get destination disk number
  565.     adi    040h        ; ASCII'ize it
  566.     mov    e,a        ; display it
  567.     mvi    c,pchar
  568.     call    bdos
  569.     lxi    d,now$full    ; display remaining portion of full message
  570.     mvi    c,pmessg
  571.     call    bdos
  572. req$cnt:lxi    d,enter$ret    ; tell'em to remove/insert disk, hit return
  573.     mvi    c,pmessg
  574.     call    bdos
  575.     mvi    c,coninp    ; wait for user response
  576.     call    bdos
  577.     cpi    cr        ; carriage return?
  578.     jnz    req$cnt        ; if not, leave reminder on what to do
  579.     call    crlf        ; tidy up screen
  580.     mvi    c,rsetdsk    ; reset disk system for newcomer
  581.     call    bdos
  582.     call    rset$fcb    ; reset fcb for retry of previous file
  583.     jmp    dspname        ; continue on new disk, with last file
  584. ;
  585. ; Multi-file  access  subroutine.   Allows processing  of  multiple 
  586. ; files (i.e.  *.*) from disk.  This routine builds the proper name 
  587. ; in the fcb each time it is called.  Carry is set if no more names
  588. ; can be found. 
  589. ;
  590. mfname:    mvi    c,stdma        ; set dma address
  591.     lxi    d,dbuff
  592.     call    bdos
  593.     xra     a        ; clear fcb extension and  record number
  594.     sta    fcbext
  595.     sta    fcbrno
  596.     lda    mfflg1        ; get multi-file flag
  597.     ora    a
  598.     jz    mfile1        ; if zero, not 1st time flag
  599.     lxi    h,dfcb        ; save filename as requested name
  600.     lxi    d,mfreq
  601.     mvi    b,12
  602.     call    blkmov
  603.     lda    dfcb
  604.     sta    mfcur        ; save disk in current fcb
  605.     lxi    h,mfreq        ; set-up for filename search
  606.     lxi    d,dfcb
  607.     mvi    b,12
  608.     call    blkmov
  609.     mvi    c,srchfst    ; do search first
  610.     lxi    d,dfcb
  611.     call    bdos
  612.     jmp    mfile2        ; check if file found
  613. ;
  614. mfile1:    lxi    h,mfcur        ; do search first on current filename
  615.     lxi    d,dfcb
  616.     mvi    b,12
  617.     call    blkmov
  618.     mvi    c,srchfst
  619.     lxi    d,dfcb
  620.     call    bdos
  621.     lxi    h,mfreq        ; do search next on requested filename
  622.     lxi    d,dfcb
  623.     mvi    b,12
  624.     call    blkmov
  625.     mvi    c,srchnxt
  626.     lxi    d,dfcb
  627.     call    bdos
  628. mfile2:    inr    a        ; return carry set, if file not found
  629.     stc
  630.     rz
  631. ;
  632. ; move name found to current filename
  633. ;
  634.     dcr    a        ; adjust location found
  635.     ani    3
  636.     add    a
  637.     add    a
  638.     add    a
  639.     add    a
  640.     add    a
  641.     adi    81h
  642.     mov    l,a        ; make filename pointer
  643.     mvi    h,0
  644.     push    h        ; save filename pointer
  645.     lxi    d,mfcur+1
  646.     mvi    b,11
  647.     call    blkmov        ; move filename to current filename
  648. ;
  649. ; move filename found to fcb
  650. ;
  651.     pop    h        ; get filename pointer
  652.     lxi    d,dfcb+1
  653.     mvi    b,11
  654.     call    blkmov        ; move filename to fcb
  655. ;
  656. ; setup fcb for subsequent file write operation
  657. ;
  658. rset$fcb:
  659. ;
  660.     lxi    d,dfcb        ; point to source fcb
  661.     lda    src$dsk$num    ; force disk number, in case not logged disk
  662.     stax    d
  663.     xra    a        ; clean-up for new file backup
  664.     sta    fcbext
  665.     sta    fcbrno
  666.     sta    destfcb
  667.     sta    destfcb+12
  668.     sta    destfcb+32
  669.     sta    mfflg1        ; turn off 1st time flag
  670.     ret
  671. ;
  672. ;  subroutine to do block moves
  673. ;
  674. blkmov:    mov    a,m        ; copy byte from [HL] to [DE]
  675.     stax    d
  676.     inx    h        ; bump pointers
  677.     inx    d
  678.     dcr    b        ; loop for count in [B]
  679.     jnz    blkmov
  680.     ret
  681. ;  subroutine to index [BC] by file counter
  682. ;
  683. filepoint:
  684. ;
  685.     lhld    filcnt        ; get file counter
  686.     mvi    h,0        ; force hi ord to 0
  687.     dad    h        ; multiply by 32
  688.     dad    h
  689.     dad    h
  690.     dad    h
  691.     dad    h
  692.     dad    b        ; use as index to file table
  693.     ret
  694. ;
  695. ; subroutine to check for user abort (any key pressed)
  696. ;
  697. abort:    push    h        ; save all registers
  698.     push    d
  699.     push    b
  700.     push    psw
  701.     mvi    c,dircon    ; check direct console i/o (status)
  702.     mvi    e,0ffh        ; input only
  703.     call    bdos
  704.     ora    a        ; set flags
  705.     jz    abortx        ; return, if zero result
  706.     cpi    'C'-40h        ; control-c for abort?
  707.     jnz    abortx        ; just return, if not
  708.     lxi    d,abort$process    ; indicate we are aborting process
  709.     mvi    c,pmessg
  710.     call    bdos
  711.     jmp    exit        ; exit via CP/M warm boot
  712. abortx:    pop    psw        ; restore all registers
  713.     pop    b
  714.     pop    d
  715.     pop    h
  716.     ret
  717. ;
  718. ; subroutine to do carriage return/line feed
  719. ;
  720. crlf:    lxi    d,crlf$msg
  721.     mvi    c,pmessg
  722.     call    bdos
  723.     ret
  724. signon:        db    cr,lf,'ARCHIVE (CTRL-C to Abort) - Ver.1.0'
  725.         db    cr,lf,cr,lf,'$'
  726. ilgopt:        db    'Invalid or Unspecified Option - Must Be Specified As:'
  727.         db    cr,lf,cr,lf
  728. opts:        db    tab,'B - Backup File Archive or,'
  729.         db    cr,lf
  730.         db    tab,'S - Set File Archive or,'
  731.         db    cr,lf
  732.         db    tab,'R - Reset File Archive or,'
  733.         db    cr,lf
  734.         db    tab,'D - Display File Archive'
  735.         db    cr,lf,'$'
  736. no$file$fnd:    db    cr,lf,'File Not Found, Aborting$'
  737. donmsg:        db    '  ','$'
  738. crlf$msg:    db    cr,lf,'$'
  739. bad$ver$num:    db    'Must be CP/M Version 2.2 to Archive, Aborting$'
  740. ;
  741.     if    not mpm        ; archive must be 'installed' in CP/M-80
  742. noarch:        db    'Archiving Not Installed, Aborting$'
  743.     endif            ; endif MP/M    
  744. ;
  745. req$dest:    db    'Destination Disk for BACKUP Files (A to P)? $'
  746. ;
  747. same$dsk:    db    cr,lf,'Can''t BACKUP to Source Disk You TWIT!',cr,lf,'$'
  748. ;
  749. abort$process:    db    cr,lf,'User Abort of ARCHIVE Process$'
  750. ;
  751. narcs:        db    cr,lf,'No ARCHIVE Files Found to BACKUP$' 
  752. ;
  753. no$file$nam:    db    'No Filename or Option Specified - '
  754.         db    'ARCHIVE must be invoked as:'
  755.         db    cr,lf,cr,lf
  756.         db    tab,'ARCHIVE FN.FT OPTION<cr>'
  757.         db    cr,lf,cr,lf
  758.         db    'Where;',tab,'FN.FT is Filename and Filetype '
  759.         db    '(? and * allowed)'
  760.         db    cr,lf,cr,lf
  761.         db    'And;',tab,'OPTION is specified as:'
  762.         db    cr,lf,cr,lf,'$'
  763. src$open$err:    db    cr,lf,'Oops, Can''t Open File on Source Disk$'
  764. dsk$full:    db    cr,lf,'Destination BACKUP Disk $'
  765. ;
  766. now$full:    db    ': is now FULL - Remove, insert NEW Disk$'
  767. ;
  768. enter$ret:    db    cr,lf,'Enter RETURN when ready to continue BACKUP process: $'
  769. src$read$err:    db    cr,lf,'Oops, Read Error on Source Disk$'
  770. src$close$err:    db    cr,lf,'Oops, Bad Close on Destination Disk$'
  771. ;
  772. bakup$done:    db    cr,lf,'BACKUP Complete',cr,lf,'$'
  773. ;
  774. fname:        db    '            $'    ; 11 spaces for filename.typ
  775. ;
  776. got$arc:    db    0    ; archive file found flag (1 = found)
  777. ;
  778. mfflg1:        db    1    ; 1st time flag for multi-file access
  779. ;
  780. mfreq:        ds    12    ; multi-file requested filename
  781. ;
  782. mfcur:        ds    12    ; multi-file current filename
  783. ;
  784. arch$addr:    ds    2    ; archive patch address
  785. ;
  786. logdsk:        ds    1    ; current logged-in disk number
  787. dest$dsk$num:    ds    1    ; destination disk number
  788. ;
  789. src$dsk$num:    ds    1    ; source disk number
  790. ;
  791. filcnt:        ds    1    ; count of files in filetable
  792. ;
  793. option:        ds    1    ; storage for B, S, R or D option letter
  794. ;
  795. destfcb:    ds    33    ; destination disk file control block
  796. ;
  797. bufmax:        ds    2    ; buffer maximum size
  798. ;
  799. bufcnt:        ds    2    ; buffer sector count
  800. ;
  801. bufpnt:        ds    2    ; buffer pointer
  802. ;
  803. eof$flg:    ds    1    ; end-of-file flag
  804. ;
  805. filetable    equ    $        ; file table/buffer starts here
  806.         ds    4*4096        ; 16k buffer
  807. table$end    equ    $        ; file table/buffer ends here
  808. ;
  809. ;
  810.     end
  811.