; ARCHIVE - File Archive/Backup Utility ; Version 1.0, 6-June-82 by Kelly Smith ; ; ; ARCHIVE is a user oriented disk maintenance utility for ; archival storage and file backup. User facilities include the ; ability to selectively 'tag' files for archival (or non-archival) ; attributes, display file archive attributes, or backup non- ; archive files to a selected disk. Wild-card filenames (using '*' ; and/or '?') may be used freely, to select some or all (i.e., ; '*.*') files for archiving. ; ; ; - Theory of Operation - ; ; Digital Research's MP/M-II and CP/M-86 Operating Systems ; utilize a file attribute for archival backup of any file addition ; or update to the disk directory. This attribute is 'reset' when ; an application program is required to write a file to a disk. ; The actual 'mechanism' for this archive function is realized by ; controlling the most significant bit of the third character of ; the FCB (File Control Block) directory entry (i.e., position 11, ; identified as byte position T3, with the Archive attribute bit ; (bit 7 of byte T3) identified as T3'). It is then a simple ; matter to identify a file as archived (e.g., backed-up) when T3' ; is a 'one', and non-archived (e.g., needs to be backed-up) when ; T3' is a 'zero'. The 'not-so-simple' part, is the utility ; required to keep track of the archive attributes on a ; disk...thats where ARCHIVE comes in, and works with CP/M-80 (with ; the help of a little 'patch'), as well as with MP/M-II and CP/M- ; 86 (when translated for 8086 CPU operation). ; ; ; - Examples of Usage - ; ; At the CP/M user command prompt, (usually 'A>'), the user ; has the option for four single letter ARCHIVE command directives, ; as follows: ; ; S - Set file archive attribute. ; ; R - Reset file archive attribute. ; ; D - Display file arcive attribute. ; ; B - Backup non-archived files. ; ; ARCHIVE is invoked by the user at the CP/M command level ; therefore, as follows, ; ; A>ARCHIVE FN.FT OPTION ; ; ...where, 'FN.FT' is an amibiguous or un-ambiguous filename and ; filetype, followed by one of the single character options, and ; then a keyboard RETURN entry. An actual example then might be: ; ; A>archive b:*.* b ; ; ...then, we are executing ARCHIVE from the 'A' disk drive, for ; all filenames and filetypes on disk 'B' whose archive attribute ; has been 'reset', to be 'backed-up' to some (as yet) ; indeterminate destination disk. ; ; Options 'S', 'R' and 'D' (Set, Reset, and Display) when ; invoked, will cause each file found in the directory 'match' to ; be displayed by 'multiple extension'...that is, each directory ; entry will be displayed, with its 'extent' number, followed by ; the archive attribute action/status as 'S' or 'R' (Set or Reset). ; ; Option 'B' (Backup) will request the user to enter a ; destination disk letter (A to P), then proceed to scan the source ; disk directory for 'reset' archive file entries. Any 'reset' ; entries will then be 'set' (indicating that the file has been ; archived) and then these files will be copied to the destination ; disk (Note however, that these files will not retain any ; previously set attributes of 'Read Only' or 'System' had they ; been set...all files copied to the destination disk will be ; 'tagged' as archived only). If a disk becomes full, the user ; will be requested to remove the disk from the destination drive ; and insert another for completion of the backup process. Any ; file that has not been completely copied to the destination disk ; at the time that disk is detected as 'full', will be deleted from ; that disk, and the file copy will resume intact on the next disk ; installed in the destination drive. ; ; Users of MP/M-II can use ARCHIVE immediately, with no system ; modification required because it "knows" about file archiving. ; However, for CP/M-80 users, they must patch there system BDOS ; (Basic Disk Operating System) to "teach" CP/M-80 file archiving. ; The following code must be edited and assembled, then loaded (as ; a '.HEX' file) with DDT (Dynamic Debugging Tool) using your ; normal system installation procedure for merging your 'Boot ; Loader' and BIOS (Basic Input/Output System) into your system ; "image" for eventual SYSGEN'ing (this code assumes the standard ; SYSGEN position of address 980H for the start of the CCP (Console ; Command Processor, with a CP/M-80 system 'size' of 56 ; Kilobytes...change the value at label MSIZE to suit your needs). ; ; ; *+*+*+*+*+*+* ; *+ +* ; *+ WARNING +* ; *+ +* ; *+*+*+*+*+*+* ; ; You must incorporate this 'archive patch' in an unmodified ; CP/M-80 (version 2.2) BDOS O-N-L-Y...any other prior ; modifications will (no doubt) be overlayed by this one, causing ; unpredictable results...'nuf said. ; - KS - ; ; ; ; msize equ 56 ; size of this CP/M 2.2 system ; ; ; bdos$loc equ (msize-20)*1024+3c00h ; base address of BDOS ; wrsec equ bdos$loc+03b8h ; address of write sector routine ; pntdir equ bdos$loc+055eh ; address of directory pointer routine ; reset$archive equ bdos$loc+0df0h ; address of reset archive bit patch ; ; ; ccp$base equ 0980h ; sysgen ccp base position ; bdos$entry equ ccp$base+0806h ; sysgen bdos entry position ; wrt$dir equ bdos$entry+05c8h; 'wrsec' call location, in DIR write routine ; scratch equ bdos$entry+0deah; scratch RAM inside bdos for patch ; ; org wrt$dir ; patch 'call wrsec' ; ; ; call reset$archive ; call patch in scratch RAM ; ; ; org scratch ; patch area for 'archive bit reset' ; ; ; call pntdir ; point to directory entry in buffer ; lxi d,11 ; make offset to 't3' in FCB ; dad d ; mov a,m ; get 't3' character from FCB ; ani 07fh ; kill archive bit position ; mov m,a ; return reset archive bit to FCB ; call wrsec ; write directory sector ; ret ; return to 'wrt$dir' routine ; ; ; ; ; ; ; end ; ; ; ; *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* ; *+ +* ; *+ ARCHIVE.ASM Utility Version 1.0, as of 6-June-82, by Kelly Smith +* ; *+ +* ; *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* ; ; ; true equ -1 ; define true false equ not true ; define false ; mpm equ not true ; conditional assembly for MP/M ; bdos equ 5 ; CP/M entry point exit equ 0 ; CP/M exit point dfcb equ 5ch ; CP/M default fcb fcbext equ dfcb+12 ; fcb extent byte fcbrno equ dfcb+32 ; fcb record number byte dbuff equ 80h ; default disk buffer ; coninp equ 1 ; console character input function pchar equ 2 ; print character function dircon equ 6 ; direct console i/o function pmessg equ 9 ; print message function constat equ 11 ; console status function version equ 12 ; return version number function rsetdsk equ 13 ; reset disk system function seldsk equ 14 ; select drive function open equ 15 ; open file function close equ 16 ; close file function srchfst equ 17 ; search for first file match function srchnxt equ 18 ; search for next file match function delete equ 19 ; delete file function read equ 20 ; read record function write equ 21 ; write record function make equ 22 ; make file function currdsk equ 25 ; return current logged disk function stdma equ 26 ; set dma address function attrib equ 30 ; set file attributes function ; tab equ 09h ; tab character lf equ 0ah ; line feed character cr equ 0dh ; carriage return character ; org 100h ; ; jump over authorship notice ; jmp over ; db cr,lf,'ARCHIVE Ver.1.0, 6-Jun-82: Kelly Smith' db cr,lf,'3055 Waco Avenue, Simi Valley, CA 93063' db cr,lf,'Z'-40h ; force end-of-file for display ; ; make a new stack pointer at CP/M serial number ; over: lhld bdos+1 ; set up a stack sphl ; at top of tpa ; ; get curent logged disk, and save it ; mvi c,currdsk ; return curent disk call bdos sta logdsk ; save as logged disk ; ; reset disk system in case someone swapped in new disk on the system ; mvi c,rsetdsk ; reset disk system function call bdos ; ; now return to original login disk ; lda logdsk ; get logged in disk number mov e,a ; do disk select mvi c,seldsk call bdos ; ; announcing, the new and improved ARCHIVE...it beats as it sweeps, as it cleans ; lxi d,signon ; point to signon message mvi c,pmessg ; print string fuction call bdos ; print it ; ; check for proper environment, we only live for CP/M 2.2 ; mvi c,version ; check version number, must be 2.2 call bdos cpi 022h ; version number correct? lxi d,bad$ver$num ; set-up bad version message, in case its not jnz arcexit ; bail-out now, if wrong version number ; if not mpm ; CP/M-80 does not know about archiving... lhld bdos+1 ; see if archiving installed in CP/M lxi d,05c9h ; add offset to archive patch address dad d shld arch$addr ; save address for later mov a,m ; get low byte content cpi 0b8h ; is this address for write sector routine? jnz patch$bdos ; if not, patch it back into bdos lxi d,noarch ; tell user that archive is not installed jmp arcexit ; exit via CP/M warm boot ; patch$bdos: ; lhld bdos+1 ; patch write sector address back to bdos lxi d,03b2h ; add offset address of 'wrsec' dad d xchg ; address patch info to [DE] lhld arch$addr ; get address to patch in [HL] mov m,e ; low byte address patched first inx h ; bump pointer mov m,d ; high byte address patched second endif ; endif MP/M ; ; check if filename specified, abort if not ; lda dfcb+1 ; this will be a space, if no filename cpi ' ' jnz gotname ; if not space, probably filename lxi d,no$file$nam ; inform user of error of their way... mvi c,pmessg call bdos lxi d,opts ; tell'em about backup options also jmp arcexit ; bail-out now, no filename ; ; got a name, now check to see which (if any) disk specified ; gotname:lda dfcb ; check for specific drive dcr a mov e,a ; set up for select disk call mvi c,seldsk inr a ; if no specified drive, skip call sta src$dsk$num ; save drive specifier for later check cnz bdos xra a ; now zap out drive specifier sta dfcb mvi a,'?' ; force extent number wild sta dfcb+12 lda dfcb+17 ; get "B", "S", "R" or "D" option sta option cpi 'B' ; backup operation? jz okopt cpi 'S' ; set archive operation? jz okopt cpi 'R' ; reset archive operation? jz okopt cpi 'D' ; just display? jz okopt ; badopt: lxi d,ilgopt ; let'em know it was an illegal option arcexit:mvi c,pmessg ; bitch, bitch, bitch... call bdos jmp exit ; ; findout now, if operation is for backup or general lobotomy ; okopt: lda option ; get option specifier cpi 'B' jnz arc$s$r ; if not backup, must be set/reset archive dest: lxi d,req$dest ; request destination disk for backup files mvi c,pmessg call bdos mvi c,coninp ; get console input character call bdos ani 05fh ; force upper case sbi 'A' ; force binary digit cpi 16 ; disk >P? jnc dest ; must satisfy ourselves with 16 disks maximum lxi h,logdsk ; is this jerk backing up to the same disk? ani 0fh ; strip high nibble for match to logged disk cmp m push psw ; save flags inr a ; save re-adjusted disk number sta dest$dsk$num pop psw ; get flags jz dsksame ; if same, tell'em so now inx h ; bump pointer to destination disk mov a,m ; get disk number inx h ; bump pointer to source disk number cmp m ; any chance he specified destination as source jnz backup ; if not, we can (finally) proceed with backup dsksame:lxi d,same$dsk ; sob...(read this anyway you want) mvi c,pmessg call bdos jmp dest ; computers never lose their patience... ; ; ready for directory write operations now...do archive set/reset ; arc$s$r:call crlf ; tidy up display xra a ; zero out file count sta filcnt lxi d,dfcb ; find the first file and get its block map mvi c,srchfst call bdos inr a ; search successful? jnz gotfile ; yes, go process rest lxi d,no$file$fnd ; oops, no file found jmp arcexit ; exit via CP/M warm boot ; gotfile:dcr a ; compensate for 'inr' above rrc ; file offset to bits 5 and 6 rrc rrc ani 60h lxi h,dbuff ; point to base of buffer mov c,a mvi b,0 dad b ; index by file offset push h ; save directory entry, for the moment lxi b,filetable ; point to base of file table call filepoint ; get table pointer to [HL] xchg ; [DE] now points to place in table lda filcnt ; keep track of number of files in table inr a sta filcnt ; bump file count pop h ; [HL] points to directory entry mvi b,32 call blkmov ; copy entry into table getnext:mvi c,srchnxt ; search for another entry lxi d,dfcb call bdos inr a ; returns 0ffh at end of search jnz gotfile ; got another one, go save it ; ; end of directory encountered, now process them ; tagfile:call abort ; check for user abort of process lxi b,filetable-32 ; allow for file count one greater than desired call filepoint push h lxi d,dfcb ; copy next name to default fcb mvi b,32 call blkmov ; someday I will grow up to be a Z80... xra a sta dfcb ; clear drive number lxi d,-20 ; point back to extent field dad d mvi m,'$' ; tag end of print here pop d ; get back pointer to start of entry inx d ; bump forward to name mvi c,pmessg call bdos ; say what we're working on mvi e,' ' ; make space between filename.typ and extent mvi c,pchar call bdos lda dfcb+12 ; get extent number push psw ; save it adi '0' ; convert to ascii mov e,a mvi c,pchar ; display extent number pop psw call bdos lda option ; get B, S, R, or D cpi 'D' ; display only? jz nextfile rrc ; bit 7 = 0 for B, R, and D, 1 for S ani 80h mov b,a ; save mask lxi d,dfcb+11 ; point to t3 ldax d ; get it ani 7fh ; strip t3' ora b ; set bit if option was S stax d ; put it back lxi d,dfcb ; point to start of fcb xra a ; zap out drive field stax d mvi c,attrib ; do set attributes function call bdos ; nextfile: ; lda dfcb+11 ; get t3 rlc ; isolate t3' ani 1 adi 'R' ; make an R or S sta donmsg+1 lxi d,donmsg mvi c,pmessg ; print completion message for this file call bdos call crlf ; tidy up display lxi h,filcnt ; point to file counter dcr m ; count it down jz exit ; exit if done jmp tagfile ; tag next file ; ; backup routine - does multiple file search and copy ; backup: call crlf ; tidy up display noback: call abort ; check for user abort of process call mfname ; set-up multi-file search (seek and ye shall find?) jnc movname ; file found, if no carry lda mfflg1 ; check if anything ever found... ora a lxi d,bakup$done ; set-up backup done message jnz nofile ; if not...indicate, no file found lda got$arc ; check archive found flag ora a jnz arcexit ; if not zero, must have found one (or more) lxi d,narcs ; indicate no archive files found jmp arcexit nofile: lxi d,no$file$fnd ; oops, no file found jmp arcexit ; exit with perturbed message movname:lxi h,dfcb+11 ; point to t3 in filetype mov a,m ; get t3 byte rlc ; archive bit set? jc noback ; if so, no backup required rrc ; adjust back to normal sta got$arc ; set archive file found flag with non-zero ori 080h ; set 'archived' status back mov m,a ; put it back push h ; save pointer lxi d,dfcb ; point to start of fcb mvi c,attrib ; do set attributes function call bdos pop h ; restore pointer dcx h ; point to t2 in filetype mov a,m ; get t2 byte ani 07fh ; strip-off t2' mov m,a ; put it back dcx h ; point to t1 in filetype mov a,m ; get t1 byte ani 07fh ; strip-off t1' mov m,a ; put it back lxi h,dfcb+1 ; point to filename for move and display lxi d,fname ; display destination for filename mvi b,8 ; set-up to move 8 characters in filename call blkmov ; too bad that 8080 is defacto standard lxi h,dfcb+9 ; point to filetype for move and display lxi d,fname+9 ; display destination for filetype mvi b,3 ; set-up to move 3 characters in filetype call blkmov ; LDIR is so nifty... dspname:lxi d,fname ; display filename and filetype mvi c,pmessg call bdos ; ; save first fcb for use later as destination file name ; mvi b,11 ; number of characters to move lxi h,dfcb+1 ; from default fcb lxi d,destfcb+1 ; to destfcb call blkmov ; round'em up and head'em out ; ; open the source file ; lda logdsk ; select disk, in case of disk full status mov e,a mvi c,seldsk ; select disk function call bdos lxi d,dfcb ; point to source fcb mvi c,open ; attempt open call bdos cpi 0ffh ; file not found? jnz openok lxi d,src$open$err ; oops, source file open error jmp arcexit ; exit via CP/M warm boot ; ; open the destination file ; openok: lxi d,destfcb ; point to destination fcb lda dest$dsk$num ; get destination disk number stax d ; set-up destination disk fcb disk number mvi c,delete ; erase any old file call bdos lxi d,destfcb mvi c,make ; make the new one call bdos cpi 0ffh ; succesfully created? jz full ; oops, disk full...time for a new one ; ; read source file to buffer, write to destination as copy ; copy: lxi h,(table$end-filetable)/128 ; save buffer size shld bufmax xra a ; clear eof flag sta eof$flg copy1: call abort ; check for user abort on ctrl-c lxi h,0 ; set current buffer counter to zero shld bufcnt lxi h,filetable ; set buffer start pointer to begin shld bufpnt ; ; file source reading loop to read all of buffer full or stop on eof ; copy2: lhld bufpnt ; set dma address to buffer pointer xchg mvi c,stdma call bdos lxi d,dfcb ; point at default fcb for reading mvi c,read ; function set for record read call bdos ora a ; check if read was o.k., or eof jnz copy3 ; end of file so set eof flag lhld bufpnt ; set buffer pointer up one sector lxi d,128 dad d shld bufpnt lhld bufcnt ; increase buffer sector count inx h shld bufcnt xchg ; check to see if memory is full lhld bufmax ; maximum sector count call cdehl ; compare jnz copy2 ; if not full go get next sector jmp copy4 ; go handle write operation ; ; here if read operation indicates that the file is at its end on read ; copy3: mvi a,0ffh ; set eof flag sta eof$flg ; ; write output file processing loop to send memory buffer to destination disk file ; copy4: lxi h,filetable ; set buffer pointer to start shld bufpnt copy5: call abort ; check for user abort on ctrl-c lhld bufcnt ; see if buffer is empty yet mov a,h ora l jz copy6 ; buffer empty so check eof flag dcx h ; dec buffer sector count for each write shld bufcnt lhld bufpnt ; set up dma address push h ; save for size bump xchg mvi c,stdma call bdos pop h lxi d,128 ; increase address for sector size dad d shld bufpnt lxi d,destfcb ; point to output file fcb mvi c,write ; write record function code call bdos ; go write ora a ; check if any error jz copy5 ; o.k., so do next record jmp full ; oops...disk full, time for a new one ; copy6: lda eof$flg ; buffer all written so go check eof ora a jz copy1 ; go to read next buffer full lxi d,destfcb ; point at fcb for file close mvi c,close ; close file function code call bdos cpi 0ffh ; check if close error jnz backup ; if not, backup more files lxi d,src$close$err ; oops, close error on destination disk jmp arcexit ; exit with error message ; ; subroutine to compare [DE] to [HL], [Z] set if equal ; cdehl: mov a,d ; high bytes equal? cmp h rnz mov a,e ; yes, how'bout low bytes? cmp l ret ; set zero, if equal ; ; subroutine to allow disk change, to continue backup process ; full: lxi d,destfcb ; delete partial file on destination disk mvi c,delete call bdos lxi d,dsk$full ; indicate that disk (or dir) is full mvi c,pmessg call bdos lda dest$dsk$num ; get destination disk number adi 040h ; ASCII'ize it mov e,a ; display it mvi c,pchar call bdos lxi d,now$full ; display remaining portion of full message mvi c,pmessg call bdos req$cnt:lxi d,enter$ret ; tell'em to remove/insert disk, hit return mvi c,pmessg call bdos mvi c,coninp ; wait for user response call bdos cpi cr ; carriage return? jnz req$cnt ; if not, leave reminder on what to do call crlf ; tidy up screen mvi c,rsetdsk ; reset disk system for newcomer call bdos call rset$fcb ; reset fcb for retry of previous file jmp dspname ; continue on new disk, with last file ; ; Multi-file access subroutine. Allows processing of multiple ; files (i.e. *.*) from disk. This routine builds the proper name ; in the fcb each time it is called. Carry is set if no more names ; can be found. ; mfname: mvi c,stdma ; set dma address lxi d,dbuff call bdos xra a ; clear fcb extension and record number sta fcbext sta fcbrno lda mfflg1 ; get multi-file flag ora a jz mfile1 ; if zero, not 1st time flag lxi h,dfcb ; save filename as requested name lxi d,mfreq mvi b,12 call blkmov lda dfcb sta mfcur ; save disk in current fcb lxi h,mfreq ; set-up for filename search lxi d,dfcb mvi b,12 call blkmov mvi c,srchfst ; do search first lxi d,dfcb call bdos jmp mfile2 ; check if file found ; mfile1: lxi h,mfcur ; do search first on current filename lxi d,dfcb mvi b,12 call blkmov mvi c,srchfst lxi d,dfcb call bdos lxi h,mfreq ; do search next on requested filename lxi d,dfcb mvi b,12 call blkmov mvi c,srchnxt lxi d,dfcb call bdos mfile2: inr a ; return carry set, if file not found stc rz ; ; move name found to current filename ; dcr a ; adjust location found ani 3 add a add a add a add a add a adi 81h mov l,a ; make filename pointer mvi h,0 push h ; save filename pointer lxi d,mfcur+1 mvi b,11 call blkmov ; move filename to current filename ; ; move filename found to fcb ; pop h ; get filename pointer lxi d,dfcb+1 mvi b,11 call blkmov ; move filename to fcb ; ; setup fcb for subsequent file write operation ; rset$fcb: ; lxi d,dfcb ; point to source fcb lda src$dsk$num ; force disk number, in case not logged disk stax d xra a ; clean-up for new file backup sta fcbext sta fcbrno sta destfcb sta destfcb+12 sta destfcb+32 sta mfflg1 ; turn off 1st time flag ret ; ; ; ; subroutine to do block moves ; blkmov: mov a,m ; copy byte from [HL] to [DE] stax d inx h ; bump pointers inx d dcr b ; loop for count in [B] jnz blkmov ret ; ; subroutine to index [BC] by file counter ; filepoint: ; lhld filcnt ; get file counter mvi h,0 ; force hi ord to 0 dad h ; multiply by 32 dad h dad h dad h dad h dad b ; use as index to file table ret ; ; subroutine to check for user abort (any key pressed) ; abort: push h ; save all registers push d push b push psw mvi c,dircon ; check direct console i/o (status) mvi e,0ffh ; input only call bdos ora a ; set flags jz abortx ; return, if zero result cpi 'C'-40h ; control-c for abort? jnz abortx ; just return, if not lxi d,abort$process ; indicate we are aborting process mvi c,pmessg call bdos jmp exit ; exit via CP/M warm boot abortx: pop psw ; restore all registers pop b pop d pop h ret ; ; subroutine to do carriage return/line feed ; crlf: lxi d,crlf$msg mvi c,pmessg call bdos ret ; ; ; signon: db cr,lf,'ARCHIVE (CTRL-C to Abort) - Ver.1.0' db cr,lf,cr,lf,'$' ; ilgopt: db 'Invalid or Unspecified Option - Must Be Specified As:' db cr,lf,cr,lf opts: db tab,'B - Backup File Archive or,' db cr,lf db tab,'S - Set File Archive or,' db cr,lf db tab,'R - Reset File Archive or,' db cr,lf db tab,'D - Display File Archive' db cr,lf,'$' ; no$file$fnd: db cr,lf,'File Not Found, Aborting$' ; donmsg: db ' ','$' ; crlf$msg: db cr,lf,'$' ; bad$ver$num: db 'Must be CP/M Version 2.2 to Archive, Aborting$' ; if not mpm ; archive must be 'installed' in CP/M-80 noarch: db 'Archiving Not Installed, Aborting$' endif ; endif MP/M ; req$dest: db 'Destination Disk for BACKUP Files (A to P)? $' ; same$dsk: db cr,lf,'Can''t BACKUP to Source Disk You TWIT!',cr,lf,'$' ; abort$process: db cr,lf,'User Abort of ARCHIVE Process$' ; narcs: db cr,lf,'No ARCHIVE Files Found to BACKUP$' ; no$file$nam: db 'No Filename or Option Specified - ' db 'ARCHIVE must be invoked as:' db cr,lf,cr,lf db tab,'ARCHIVE FN.FT OPTION' db cr,lf,cr,lf db 'Where;',tab,'FN.FT is Filename and Filetype ' db '(? and * allowed)' db cr,lf,cr,lf db 'And;',tab,'OPTION is specified as:' db cr,lf,cr,lf,'$' ; src$open$err: db cr,lf,'Oops, Can''t Open File on Source Disk$' ; dsk$full: db cr,lf,'Destination BACKUP Disk $' ; now$full: db ': is now FULL - Remove, insert NEW Disk$' ; enter$ret: db cr,lf,'Enter RETURN when ready to continue BACKUP process: $' ; src$read$err: db cr,lf,'Oops, Read Error on Source Disk$' ; src$close$err: db cr,lf,'Oops, Bad Close on Destination Disk$' ; bakup$done: db cr,lf,'BACKUP Complete',cr,lf,'$' ; fname: db ' $' ; 11 spaces for filename.typ ; got$arc: db 0 ; archive file found flag (1 = found) ; mfflg1: db 1 ; 1st time flag for multi-file access ; mfreq: ds 12 ; multi-file requested filename ; mfcur: ds 12 ; multi-file current filename ; arch$addr: ds 2 ; archive patch address ; logdsk: ds 1 ; current logged-in disk number ; dest$dsk$num: ds 1 ; destination disk number ; src$dsk$num: ds 1 ; source disk number ; filcnt: ds 1 ; count of files in filetable ; option: ds 1 ; storage for B, S, R or D option letter ; destfcb: ds 33 ; destination disk file control block ; bufmax: ds 2 ; buffer maximum size ; bufcnt: ds 2 ; buffer sector count ; bufpnt: ds 2 ; buffer pointer ; eof$flg: ds 1 ; end-of-file flag ; filetable equ $ ; file table/buffer starts here ds 4*4096 ; 16k buffer table$end equ $ ; file table/buffer ends here ; ; ; end