0001 ;=============================================================== 0002 ; 0003 ; program FDUMP (filename) 0004 ; 0005 ; FDUMP takes the (explicit) name of any file, and dumps the 0006 ; file to the console in physical, 128-byte records. 0007 ; 0008 ; Each record is displayed as two lines, with the record number 0009 ; in hex appended to the first line. Control characters are 0010 ; shown as dots, except for CR and LF which are shown as 0011 ; back-slash characters to reveal the end of an ASCII line. 0012 ; ***************************************************** 0013 ; * This program was originally published in * 0014 ; * A PROGRAMMER'S NOTEBOOK * 0015 ; * Utilities for CP/M-80 * 0016 ; * by David E. Cortesi * 0017 ; * Copyright (C) Reston Publishing Company Inc. 1983 * 0018 ; ***************************************************** 0019 ;=============================================================== 0020 MACLIB CPMEQU ; standard equate-names 0021 MACLIB PROG ; important macros 0022 PROLOG ; enter, set up stack, go to Main 0023 ;=============================================================== 0024 ; the global variables... 0025 Record dw 0 ; record count 0026 Index db 0 ; index to next byte in Buffer 0027 ;=============================================================== 0028 ; the main program -- initialization 0029 Main: 0030 SERVICE BdosOpen,CpmFcb 0031 inr a ; error code FFh becomes 00h 0032 jz Nofile ; no file -- error code at end. 0033 ; 0034 SERVICE BdosSetBuffer,Buffer ; input to our Buffer 0035 mvi a,128 0036 sta Index ; Index := 128 (Buffer is empty) 0037 lxi h,0 0038 shld Record ; Record := 0 0039 ;=============================================================== 0040 ; the main program -- main loop 0041 ; 0042 call Getchar ; C := Getchar, and set flag in A. 0043 MainWhile: 0044 ora a ; while not EOF... 0045 jnz MainEnd ; (it is EOF) 0046 call TypeCRLF; type a blank line 0047 mvi b,64 ; do 64 times (count in B) 0048 Main4: 0049 mov a,c ; put data byte in A, 0050 call Output ; ..write it. 0051 call Getchar ; C := next byte, A := flag 0052 DJNZ Main4 ; dcr b, jnz Main4 0053 ; 0054 call ShowRecord ; show the record number, 0055 call TypeCRLF; ..end the first line. 0056 ; 0057 mvi b,64 ; set up for 2nd line. 0058 Main5: 0059 mov a,c ; get data byte, 0060 call Output ; ..write it. 0061 call Getchar ; flag gets set on the 128th call 0062 DJNZ Main5 ; end do. 0063 ; 0064 call TypeCRLF; end the 2nd line, 0065 lhld Record 0066 inx h 0067 shld Record ; Record := Record + 1 0068 jmp MainWhile ; end while. 0069 ; 0070 MainEnd: 0071 ret ; back to prolog, do warm start. 0072 ;--------------------------------------------------------------- 0073 ; Getchar: return the next byte from the file in register C, 0074 ; and an end of file flag in register A. If the current 0075 ; record is exhausted, read another record into the buffer. 0076 ; 0077 ; Assumes: that Buffer is on a page boundary. 0078 ; Output: byte in C. End-of-file flag in A. 0079 ; Preserves: all but A, C, flags. 0080 ;--------------------------------------------------------------- 0081 Getchar: 0082 lda Index 0083 ora a ; Index > 127? 0084 jp Getchar2 ; ..no, continue 0085 ; 0086 ; ...the buffer is empty, read a record into it. 0087 ; 0088 SERVICE BdosRead,CpmFcb 0089 ora a ; non-zero if physical end of file. 0090 rnz ; quit, A nonzero, if true. 0091 ; otherwise continue, A=Index=00 0092 Getchar2: 0093 push h ; save HL, then form address 0094 mvi h,HIGH(Buffer) ; ..of data using Buffer page 0095 mov l,a ; ..and Index (in A). 0096 mov c,m ; C := the byte 0097 inr a 0098 sta Index ; Index := Index + 1 0099 xra a ; not EOF, return zero flag 0100 pop h 0101 ret ; end Getchar. 0102 ;--------------------------------------------------------------- 0103 ; Output: send the byte in A to the console. Begin by setting 0104 ; off the high bit, because some word processors set Bit 7 in 0105 ; special-purpose carriage returns, etc. Then if the byte is 0106 ; printable just type it. If it's a control character let the 0107 ; Control routine translate it first. 0108 ; preserves: all registers. 0109 ;--------------------------------------------------------------- 0110 Output: 0111 push psw 0112 ani AsciiDEL ; turn off the high bit. 0113 cpi AsciiBlank ; if A<" " (carry is set), 0114 cc Control ; A := Control(A) 0115 cpi AsciiDEL ; ..or if A is a DEL, 0116 cz Control ; A := Control(A) 0117 call TypeChar ; TypeChar(A) 0118 pop psw 0119 ret 0120 ;--------------------------------------------------------------- 0121 ; Control: translate a control character to printable form. 0122 ; Change most controls to dots. Change CR to and LF to 0123 ; back-slashes so that the end of a normal line stands out. 0124 ; preserves: all but A, flags. 0125 ; output: printable byte in A 0126 ;--------------------------------------------------------------- 0127 Control: 0128 cpi AsciiCR 0129 JRZ Control2 0130 cpi AsciiLF 0131 JRZ Control2 0132 mvi A,'.' 0133 ret 0134 Control2: 0135 mvi A,'\' 0136 ret 0137 ;--------------------------------------------------------------- 0138 ; ShowRecord: display the record number. Type two spaces, then 0139 ; the four hex digits of "Record". 0140 ; preserves: all. 0141 ;--------------------------------------------------------------- 0142 ShowRecord: 0143 push h 0144 call TypeBlank 0145 call TypeBlank 0146 lhld Record 0147 call TypeXXXX ; TypeXXXX(Record) 0148 pop h 0149 ret 0150 ;--------------------------------------------------------------- 0151 ; Nofile: the input file doesn't exist. At this point the 0152 ; command tail at location 80h looks like this: 0153 ; 0154 ; nn space filename 00 0155 ; 0156 ; where nn is the length and 00 is a null byte. Turn it into 0157 ; a message string like this: 0158 ; 0159 ; nn space filename?$ 0160 ; 0161 ; and abort with the message ' filename?' that results. This 0162 ; code has two bugs (see text), none serious. 0163 ;--------------------------------------------------------------- 0164 Nofile: 0165 lda CpmTail ; A := length of the "tail" 0166 mov e,a ; make that a 16-bit integer 0167 mvi d,0 0168 lxi h,CpmTail+1 ; HL->start of "tail" 0169 dad d ; HL->null byte at end of "tail" 0170 mvi m,'?' ; complete the message: "filename?" 0171 inx h 0172 mvi m,'$' ; terminator for message string 0173 ABORT CpmTail+1 ; 0174 ;=============================================================== 0175 ; the included subroutines... 0176 ; #include TypeSubs.Inc,TypeCommon -- TypeChar, -CRLF, etc. 0177 ; #include TypeSubs.Inc,TypeXXXX 0178 ;=============================================================== 0179 ; The record buffer, at the end to make the .COM file smaller. 0180 ; Also on a page boundary, don't forget. 0181 ORGPAGE 0182 Buffer: ds 128 0183 ; 0184 ; For MP/M, the .HEX file should account for the full size of 0185 ; the program, so enable the next instruction: 0186 ; db 0 0187 END * CROSS-REFERENCE * def. val. symbol and uses * ---- 0020 ASCIIBLANK CPI-113 * ---- 000D ASCIICR CPI-128 * ---- 007F ASCIIDEL ANI-112 CPI-115 * ---- 000A ASCIILF CPI-130 * ---- 000F BDOSOPEN SERVICE-30 * ---- 0014 BDOSREAD SERVICE-88 * ---- 001A BDOSSETBUFFER SERVICE-34 * 0182 0300 BUFFER SERVICE-34 MVI-94 * 0127 01F1 CONTROL CC-114 CZ-116 * 0134 01FE CONTROL2 JRZ-129 -131 * ---- 005C CPMFCB SERVICE-30 -88 * ---- 0080 CPMTAIL LDA-165 LXI-168 ABORT-173 * 0081 01BC GETCHAR CALL-42 -51 -61 * 0092 01D3 GETCHAR2 JP-84 * 0026 0158 INDEX STA-36 LDA-82 STA-98 * 0029 0159 MAIN * 0048 0190 MAIN4 DJNZ-52 * 0058 01A3 MAIN5 DJNZ-62 * 0070 01BB MAINEND JNZ-45 * 0043 0187 MAINWHILE JMP-68 * 0164 0210 NOFILE JZ-32 * 0110 01DF OUTPUT CALL-50 -60 * 0025 0156 RECORD SHLD-38 LHLD-65 SHLD-67 LHLD-146 * 0142 0201 SHOWRECORD CALL-54 * ---- 0227 TYPEBLANK CALL-144 -145 * ---- 0246 TYPECHAR CALL-117 * ---- 022D TYPECRLF CALL-46 -55 -64 * ---- 0255 TYPEXXXX CALL-147 * CENSUS OF OPCODE USAGE * * ABORT 1 ANI 1 CALL 13 * CC 1 CPI 4 CZ 1 * DAD 1 DB 1 DJNZ 2 * DS 1 DW 1 END 1 * INR 2 INX 2 JMP 1 * JNZ 1 JP 1 JRZ 2 * JZ 1 LDA 2 LHLD 2 * LXI 2 MACLIB 2 MOV 5 * MVI 9 ORA 3 ORGPAGE 1 * POP 3 PROLOG 1 PUSH 3 * RET 6 RNZ 1 SERVICE 3 * SHLD 2 STA 2 XRA 1