.cs 5 .mt 5 .mb 6 .pl 66 .ll 65 .po 10 .hm 2 .fm 2 .he .bp .tc 5.3 A Sample File-to-File Copy Program .he CP/M Operating System Manual 5.3 A Sample Copy Program .sh 5.3 A Sample File-to-File Copy Program .qs .pp The following program provides a relatively simple example of file operations. The program source file is created as COPY.ASM using the CP/M ED program and then assembled using ASM or MAC, resulting in a HEX file. The LOAD program is used to produce a COPY.COM file that executes directly under the CCP. The program begins by setting the stack pointer to a local area and proceeds to move the second name from the default area at 006CH to a 33-byte File Control Block called DFCB. The DFCB is then prepared for file operations by clearing the current record field. At this point, the source and destination FCBs are ready for processing, because the SFCB at 005CH is properly set up by the CCP upon entry to the COPY program. That is, the first name is placed into the default FCB, with the proper fields zeroed, including the current record field at 007CH. The program continues by opening the source file, deleting any existing destination file, and creating the destination file. If all this is successful, the program loops at the label COPY until each record is read from the source file and placed into the destination file. Upon completion of the data transfer, the destination file is closed and the program returns to the CCP command level by jumping to BOOT. .ll 75 .sp 3 .nf ; sample file-to-file copy program ; ; at the ccp level, the command ; ; copy a:x.y b:u.v ; ; copies the file named x.y from drive ; a to a file named u.v. on drive b. ; 0000 = boot equ 0000h ;system reboot 0005 = bdos equ 0005h ;bdos entry point 005c = fcbl equ 005ch ;first file name 005c = sfcb equ fcbl ;source fcb 006c = fcb2 equ 006ch ;second file name 0080 = dbuff equ 0080h ;default buffer 0100 = tpa equ 0100h ;beginning of tpa ; 0009 = printf equ 9 ;print buffer func# 000f = openf equ 15 ;open file func# 0010 = closef equ 16 ;close file func# 0013 = deletef equ 19 ;delete file func# 0014 = readf equ 20 ;sequential read 0015 = writef equ 21 ;sequential write 0016 = makef equ 22 ;make file func# ; 0100 org tpa ;beginning of tpa 0100 311b02 lxi sp,stack ;local stack ; ; move second file name to dfcb 0103 0e10 mvi c,16 ;half an fcb 0105 116c00 lxi d,fcb2 ;source of move 0108 21da01 lxi h,dfcb ;destination fcb 010b 1a mfcb: Idax d ;source fcb 010c 13 inx d ;ready next 010d 77 mov m,a ;dest fcb 010e 23 inx h ;ready next 010f 0d dcr c ;count 16...0 0110 c10b01 jnz mfcb ;loop 16 times ; ; name has been removed, zero cr 0113 af xra a ;a = 00h 0114 32fa01 sta dfcbcr ;current rec = 0 ; ; source and destination fcb's ready ; 0117 115c00 lxi d,sfcb ;source file 011a cd6901 call open ;error if 255 011d 118701 lxi d,nofile ;ready message 0120 3c inr a ;255 becomes 0 0121 cc6101 cz finis ;done if no file ; ; source file open, prep destination 0124 11da01 lxi d,dfcb ;destination 0127 cd7301 call delete ;remove if present ; 012a 11da01 lxi d,dfcb ;destination 012d cd8201 call make ;create the file 0130 119601 lxi d,nodir ;ready message 0133 3c inr a ;255 becomes 0 0134 cc6101 cz finis ;done if no dir space ; ; source file open, dest file open ; copy until end of file on source ; 0137 115c00 copy: lxi d,sfcb ;source 013a cd7801 call read ;read next record 013d b7 ora a ;end of file? 013e c25101 jnz eofile ;skip write if so ; ; not end of file, write the record 0141 11da01 lix d,dfcb ;destination 0144 cd7d01 call write ;write record 0147 11a901 lxi d,space ;ready message 014a b7 ora a ;00 if write ok 014b c46101 cnz finis ;end if so 014e c33701 jmp copy ;loop until eof ; eofile: ;end of file, close destination 0151 11da01 lxi d,dfcb ;destination 0154 cd6e01 call close ;255 if error 0157 21bb01 lxi h,wrprot ;ready message 015a 3c inr a ;255 becomes 00 015b cc6101 cz finis ;shouldn't happen ; ; copy operation complete, end 015e 11cc01 lxi d,normal ;ready message ; finis ;write message given by de, reboot 0161 0e09 mvi c,printf 0163 cd0500 call bdos ;write message 0166 c30000 jmp boot ;reboot system ; ; system interface subroutines ; (all return directly from bdos) ; 0169 0e0f open: mvi c,openf 016b c30500 jmp bdos ; 016e 0e10 close: mvi c,closef 0170 c30500 jmp bdos ; 0173 0e13 delete mvi c,deletef 0175 c30500 jmp bdos ; 0178 0e14 read: mvi c,readf 017a c30500 jmp bdos ; 017d 0e15 write: mvi c,writef 017f c30500 jmp bdos ; 0182 0e16 make: mvi c,makef 0184 c30500 jmp bdos ; ; console messages 0187 6e6f20f nofile: db 'no source file$' 0196 6e6f209 nodir: db 'no directory space$' 01a9 6f7574f space: db 'out of dat space$' 01bb 7772695 wrprot: db 'write protected?$' 01cc 636f700 normal: db 'copy complete$' ; ; data areas 01da dfcb: ds 33 ;destination fcb 01fa dfcbcr equ dfcb+32 ;current record ; 01fb ds 32 ;16 level stack stack: 021b end .ll 65 .fi .in 0 .sp 2 .pp Note that there are several simplifications in this particular program. First, there are no checks for invalid filenames that could contain ambiguous references. This situation could be detected by scanning the 32-byte default area starting at location 005CH for ASCII question marks. A check should also be make to ensure that the filenames have been included (check locations 005DH and 006DH for nonblank ASCII characters). Finally, a check should be made to ensure that the source and destination filenames are different. An improvement in speed could be obtained by buffering more data on each read operation. One could, for example, determine the size of memory by fetching FBASE from location 0006H and using the entire remaining portion of memory for a data buffer. In this case, the programmer simply resets the DMA address to the next successive 128-byte area before each read. Upon writing to the destination file, the DMA address is reset to the beginning of the buffer and incremented by 128 bytes to the end as each record is transferred to the destination file. .sp 2 .he CP/M Operating System Manual 5.4 A Sample File Dump Utility .tc 5.4 A Sample File Dump Utility .sh 5.4 A Sample File Dump Utility .qs .pp The following file dump program is slightly more complex than the simple copy program given in the previous section. The dump program reads an input file, specified in the CCP command line, and displays the content of each record in hexadecimal format at the console. Note that the dump program saves the CCP's stack upon entry, resets the stack to a local area, and restores the CCP's stack before returning directly to the CCP. Thus, the dump program does not perform and warm start at the end of processing. .ll 75 .sp 3 .nf x.in 5 ;DUMP program reads input file and displays hex data ; 0100 org 100h 0005 = bdos equ 0005h = ;bdos entry point 0001 = cons equ 1 ;read console 0002 = typef equ 2 ;type function 0009 = printf equ 9 ;buffer print entry 000b = brkf equ 11 ;break key function ;(true if char 000f = openf equ 15 ;file open 0014 = readf equ 20 ;read function ; 005c = fcb equ 5ch ;file control block ;address 0080 = buff equ 80h ;input disk buffer ;address ; ; non graphic characters 000d = cr equ 0dh ;carriage return 000a = If equ 0ah ;line feed ; ; file control block definitions 005c = fcbdn equ fcb+0 ;disk name 005d = fcbfn equ fcb+1 ;file name 0065 = fcbft equ fcb+9 ;disk file type (3 ;characters) 0068 = fcbrl equ fcb+12 ;file's current reel ;number 006b = fcbrc equ fcb+15 ;file's record count (0 to ;128)128) 007c = fcbcr' equ fcb+32 ;current (next) record ;number (0 007d = fcbin equ fcb+33 ;fcb length ; ; set up stack 0100 210000 lxi h,0 0103 39 dad sp ; entry stack pointer in hl from the ccp 0104 221502 shld oldsp ; set sp to local stack area (restored at ; finis) 0107 315702 lxi sp,stktop ; read and print successive buffers 010a cdc101 call setup ;set up input file 010d feff cpi 255 ;255 if file not present 010f c21b01 jnz openok ;skip if open is ok ; ; file not there, give error message and ; return 0112 11f301 lxi d,opnmsg 0115 cd9c01 call err 0118 c35101 jmp finis ;to return ; openok: ;open operation ok, set buffer index to ;end 011b 3e80 mvi a,80h 011d 321302 sta ibp ;set buffer pointer to 80h ; hl contains next address to print 0120 210000 lxi h,0 ;start with 0000 ; gloop: 0123 e5 push h ;save line position 0124 cda201 call gnb 0127 e1 pop h ;recall line position 0138 da5101 jc finis ;carry set by gnb if end ;file 012b 47 mov b,a ; print hex values ; check for line fold 012c 7d mov a,l 012d e60f ani 0fh ;check low 4 bits 012f c24401 jnz nonum ; print line number 0132 cd7201 call crlf ; ; check for break key 0135 cd5901 call break ; accum lsb = 1 if character ready 0138 0f rrc ;into carry 0139 da5101 jc finis ;don't print any more ; 013c 7c mov a,h 013d cd8f01 call phex 0140 7d mov a,l 0141 cd8f01 call phex nonum 0144 23 inx h ;to next line number 0145 3e20 mvi a,'' 0147 cd6501 call pchar 014a 78 mov a,b 014b cd8f01 call phex 014e c32301 jmp gloop ; finis ; end of dump, return to cco ; (note that a jmp to 0000h reboots) 0151 cd7201 call crif 0154 2a1502 lhld oldsp 0157 f9 sphl ; stack pointer contains ccp's stack ; location 0158 c9 ret ;to the ccp ; ; ; subroutines ; break: ;check break key (actually any key will ;do) 0159 e5d5c5 push h! push d! push b; environment ;saved 015c 0e0b mvi c,brkf 015e cd0500 call bdos 0161 c1d1e1 pop b! pop d! pop h; environment restored 0164 c9 ret ; pchar: ;print a character 0165 e5d5c5 push h! push d! push b; saved 0168 0e02 mvi c, typef 016a 5f mov e,a 016b cd0500 call bdos 016e c1d1e1 pop b! pop d! pop h; restored 0171 c9 ret ; crlf 0172 3e0d mvi a,cr 0174 cd6501 call pchar 0177 3e0a mvi a,lf 0179 cd6501 call pchar 017c c9 ret ; ; pnib: ;print nibble in reg a 017d e60f ani ofh ;low 4 bits 017f fe0a cpi 10 0181 d28901 jnc p10 ; less than or equal to 9 0184 c630 adi '0' 0186 c38b01 jmp prn ; ; greater or equal to 10 0189 c637 p10: adi 'a' - 10 018b cd6501 prn: call pchar 018e c9 ret ; phex ;print hex char in reg a 018f f5 pushpsw 0190 0f rrc 0191 0f rrc 0192 0f rrc 0193 0f rrc 0194 cd7d01 call pnib ;print nibble 0197 f1 pop psw 0198 cd7d01 call pnip 019b c9 ret ; err: ;print error message ; d,e addresses message ending with "$" 019c 0e09 mvi c,printf ;print buffer ;function 019e cd0500 call bdos 01a1 c9 ret ; ; gnb: ;get next byte 01a2 3a1302 lda ibp 01a5 fe80 cpi 80h 01a7 c2b301 jnz g0 ; read another buffer ; ; 01aa cdce01 call diskr 01ad b7 ora a ;zero value if read ok 01ae cab301 jz g0 ;for another byte ; end of data, return with carry set for eof 01b1 37 stc 01b2 c9 ret ; g0: ;read the byte at buff+reg a 01b3 5f mov e,a ;Is byte of buffer index 01b4 1600 mvi d,0 ;double precision ;index to de 01b6 3c inr a ;index=index+1 01b7 321302 sta ibp ;back to memory ; pointer is incremented ; save the current file address 01ba 218000 lxi h,buff 01bd 19 dad d ; absolute character address is in hl 01be 7e mov a,m ; byte is in the accumulator 01bf b7 ora a ;reset carry bit 01c0 c9 ret ; setup: ;set up file ; open the file for input 01c1 af xra a ;zero to accum 01c2 327c00 sta fcbcr ;clear current record ; 01c5 115c00 lxi d,fcb 01c8 0e0f mvi c,openf 01ca cd0500 call bdos ; 255 in accum if open error 01cd c9 ret ; diskr: ;read disk file record 01ce e5d5c5 push h! push d! push b 01d1 115c00 lxi d,fcb 01d4 0e14 mvi c,readf 01d6 cd0500 call bdos 01d9 c1d1e1 pop b! pop d! pop h 01dc c9 ret ; ; fixed message area 01dd 46494c0 signon: db 'file dump version 2.0$' 01f3 0d0a4e0 opnmsg: db cr,lf,'no input file present on disk$' ; variable area 0213 ibp: ds 2 ;input buffer pointer 0215 oldsp: ds 2 ;entry sp value from ccp ; ; stack area 0217 ; ds 64 ;reserve 32 level stack stktop: ; 0257 end .ll 65 .fi .in 0 .nx fived