0001 ;=============================================================== 0002 ; program CDUMP (filename) 0003 ; 0004 ; Takes the (explicit) name of a file and displays it at the 0005 ; console in 128-byte physical records. Each record is shown as 0006 ; two lines with the record number appended to the right of the 0007 ; first one. 0008 ; 0009 ; Where a control character appears it is displayed as its 0010 ; matching printable character, but in reverse video. A DEL 0011 ; character (which has no paired letter) displays as tilde (~). 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 Switch db 0 ; Normal/Reverse switch 0028 UsedNormal equ 00h ; values that may be in Switch. 0029 UsedRevers equ 80h 0030 ; 0031 ; The following constants are terminal-hardware-dependent. 0032 ; Substitute the sequence of characters that makes your 0033 ; terminal go reverse-video to normal-video and vice versa. 0034 ; End each sequence with '$', for writing via TypeMessage. 0035 ; 0036 NormalSeq: ; sequence that cancels reverse video 0037 db AsciiESC,'q','$' ; Heath H19, Zenith Z19 0038 ReversSeq: ; sequence that starts reverse video 0039 db AsciiESC,'p','$' ; Heath H19, Zenith Z19 0040 ;=============================================================== 0041 ; the main program -- initialization 0042 Main: 0043 SERVICE BdosOpen,CpmFcb 0044 inr a ; error code FFh becomes 00h 0045 jz Nofile ; no file -- error code at end. 0046 SERVICE BdosSetBuffer,Buffer ; input to our Buffer 0047 mvi a,128 0048 sta Index ; Index := 128 (Buffer is empty) 0049 lxi h,1 0050 shld Record ; Record := 1 0051 mvi a,UsedNormal 0052 sta Switch ; Switch := UsedNormal 0053 ;=============================================================== 0054 ; the main program -- main loop 0055 ; 0056 call Getchar ; C := next byte, A := flag 0057 MainWhile: 0058 ora a ; check end-of-file flag in A 0059 jnz MainEnd 0060 ; 0061 call TypeCRLF; type a blank line 0062 mvi b,64 ; do 64 times (count in B) 0063 Main4: 0064 mov a,c ; put data byte in A, 0065 call Output ; ..write it. 0066 call Getchar ; C := next byte, A := flag 0067 DJNZ Main4 ; end do. 0068 ; 0069 call ShowRecord ; show the record number, 0070 call TypeCRLF; ..end the first line. 0071 ; 0072 mvi b,64 ; set up for 2nd line. 0073 Main5: 0074 mov a,c ; get data byte, 0075 call Output ; ..write it. 0076 call Getchar ; flag gets set on the 128th call 0077 DJNZ Main5 ; end do. 0078 ; 0079 call TypeCRLF; end the 2nd line, 0080 lhld Record 0081 inx h 0082 shld Record ; Record := Record + 1 0083 jmp MainWhile ; end while. 0084 ; 0085 MainEnd: 0086 call GoToNormal ; return terminal to normal, 0087 ret ; back to prolog, do warm start. 0088 ;--------------------------------------------------------------- 0089 ; Getchar: return the next byte from the file in register C, 0090 ; and an end of file flag in register A. If the current 0091 ; record is exhausted, read another record into the buffer. 0092 ; 0093 ; Assumes: that Buffer is on a page boundary. 0094 ; Output: byte in C. End-of-file flag in A. 0095 ; Preserves: all but A, C, flags. 0096 ;--------------------------------------------------------------- 0097 Getchar: 0098 lda Index 0099 ora a ; Index > 127? 0100 jp Getchar2 ; ..no, continue 0101 ; ...the buffer is empty, read a record into it. 0102 SERVICE BdosRead,CpmFcb 0103 ora a ; non-zero if physical end of file. 0104 rnz ; quit, A nonzero, if true. 0105 ; otherwise continue, A=Index=00 0106 Getchar2: 0107 push h ; save caller's HL, form address 0108 mvi h,HIGH(Buffer) ; ..of data from page 0109 mov l,a ; ..plus Index (in A). 0110 mov c,m ; C := the byte 0111 inr a 0112 sta Index ; Index := Index + 1 0113 xra a ; return zero flag 0114 pop h 0115 ret ; end Getchar. 0116 ;--------------------------------------------------------------- 0117 ; Output sends the byte in A to the console. Begin by setting 0118 ; off the high bit, because some word processors set Bit 7 in 0119 ; special-purpose carriage returns, etc. Then if the input is: 0120 ; 0121 ; a printable character, set normal video and type it. 0122 ; a control character, translate it to a printable one, 0123 ; set reverse video, and type it. 0124 ; 0125 ; Preserves: all. 0126 ;--------------------------------------------------------------- 0127 Output: 0128 push psw 0129 ani AsciiDEL ; turn off the high bit. 0130 cpi AsciiBlank ; if A<' ' (carry set), control. 0131 JRC Control 0132 cpi AsciiDEL ; likewise if it's a DEL 0133 JRZ Control 0134 ; ...printable, get into normal video 0135 call GoToNormal 0136 JMPR Output2 0137 Control:; ...fix control character, set up reverse video 0138 adi 40h ; make, e.g., SUB into Z 0139 jp Control2 ; ..but DEL+40 is over 127 0140 mvi a,'~' ; ..make DEL into a tilde. 0141 Control2: 0142 call GoToReverse 0143 Output2: 0144 call Typechar ; type the character 0145 pop psw 0146 ret ; end Output. 0147 ;--------------------------------------------------------------- 0148 ; GoToNormal: Get the terminal into normal video if it isn't. 0149 ; Preserves: all. 0150 ;--------------------------------------------------------------- 0151 GoToNormal: 0152 push psw 0153 push d 0154 mvi a,UsedNormal 0155 lxi d,NormalSeq 0156 JMPR GoToEither 0157 ;--------------------------------------------------------------- 0158 ; GoToReverse: Get the terminal into reverse video if it isn't. 0159 ; Preserves: all. 0160 ;--------------------------------------------------------------- 0161 GoToReverse: 0162 push psw 0163 push d 0164 mvi a,UsedRevers 0165 lxi d,ReversSeq 0166 ;--------------------------------------------------------------- 0167 ; common conclusion of GoToNormal/Reverse: change the terminal 0168 ; mode, but only if it needs changing. 0169 ;--------------------------------------------------------------- 0170 GoToEither: 0171 push h 0172 lxi h,Switch 0173 cmp m ; is it how we want it? 0174 mov m,a ; (it is now) 0175 pop h 0176 cnz TypeMessage; send DE-->sequence if it wasn't 0177 pop d 0178 pop psw 0179 ret 0180 ;--------------------------------------------------------------- 0181 ; ShowRecord: Finish the first line with two spaces and the 0182 ; record number in hex -- in normal video, of course. 0183 ; Preserves: all. 0184 ;--------------------------------------------------------------- 0185 ShowRecord: 0186 push h 0187 call GoToNormal 0188 call TypeBlank 0189 call TypeBlank 0190 lhld Record 0191 call TypeXXXX ; TypeXXXX(Record) 0192 pop h 0193 ret 0194 ;--------------------------------------------------------------- 0195 ; Nofile: the input file doesn't exist. Abort with the 0196 ; message No File, avoiding the problems we had in FDUMP. 0197 ;--------------------------------------------------------------- 0198 Nofile: 0199 ABORT NoFileMsg 0200 NoFileMsg: db 'No File','$' 0201 ;=============================================================== 0202 ; the included subroutines... 0203 ; #include TypeSubs.Inc,TypeCommon -- TypeChar, -CRLF, etc. 0204 ; #include TypeSubs.Inc,TypeXXXX 0205 ;=============================================================== 0206 ; The record buffer, at the end to make the .COM file smaller. 0207 ; Also on a page boundary, don't forget. 0208 ORGPAGE 0209 Buffer: ds 128 0210 ; 0211 ; For MP/M, the .HEX file should account for the full size of 0212 ; the program, so enable the next instruction: 0213 ; db 0 0214 END * CROSS-REFERENCE * def. val. symbol and uses * ---- 0020 ASCIIBLANK CPI-130 * ---- 007F ASCIIDEL ANI-129 CPI-132 * ---- 001B ASCIIESC DB-37 -39 * ---- 000F BDOSOPEN SERVICE-43 * ---- 0014 BDOSREAD SERVICE-102 * ---- 001A BDOSSETBUFFER SERVICE-46 * 0209 0300 BUFFER SERVICE-46 MVI-108 * 0137 0201 CONTROL JRC-131 JRZ-133 * 0141 0208 CONTROL2 JP-139 * ---- 005C CPMFCB SERVICE-43 -102 * 0097 01CB GETCHAR CALL-56 -66 -76 * 0106 01E2 GETCHAR2 JP-100 * 0170 0221 GOTOEITHER JMPR-156 * 0151 0210 GOTONORMAL CALL-86 -135 -187 * 0161 021A GOTOREVERSE CALL-142 * 0026 0158 INDEX STA-48 LDA-98 STA-112 * 0042 0160 MAIN * 0063 019C MAIN4 DJNZ-67 * 0073 01AF MAIN5 DJNZ-77 * 0085 01C7 MAINEND JNZ-59 * 0057 0193 MAINWHILE JMP-83 * 0198 0240 NOFILE JZ-45 * 0200 0248 NOFILEMSG ABORT-199 * 0036 015A NORMALSEQ LXI-155 * 0127 01EE OUTPUT CALL-65 -75 * 0143 020B OUTPUT2 JMPR-136 * 0025 0156 RECORD SHLD-50 LHLD-80 SHLD-82 LHLD-190 * 0038 015D REVERSSEQ LXI-165 * 0185 022E SHOWRECORD CALL-69 * 0027 0159 SWITCH STA-52 LXI-172 * ---- 0250 TYPEBLANK CALL-188 -189 * ---- 026F TYPECHAR CALL-144 * ---- 0256 TYPECRLF CALL-61 -70 -79 * ---- 0266 TYPEMESSAGE CNZ-176 * ---- 027E TYPEXXXX CALL-191 * 0028 0000 USEDNORMAL MVI-51 -154 * 0029 0080 USEDREVERS MVI-164 * CENSUS OF OPCODE USAGE * * ABORT 1 ADI 1 ANI 1 * CALL 17 CMP 1 CNZ 1 * CPI 2 DB 5 DJNZ 2 * DS 1 DW 1 END 1 * EQU 2 INR 2 INX 1 * JMP 1 JMPR 2 JNZ 1 * JP 2 JRC 1 JRZ 1 * JZ 1 LDA 1 LHLD 2 * LXI 4 MACLIB 2 MOV 5 * MVI 8 ORA 3 ORGPAGE 1 * POP 6 PROLOG 1 PUSH 8 * RET 5 RNZ 1 SERVICE 3 * SHLD 2 STA 3 XRA 1