Listing 1. Assembly-language Print program ; ******************************************************************** ; * * ; * A PRINT UTILITY FOR CP/M 6 MARCH 80 * ; * * ; ******************************************************************** ; THIS PROGRAM PERMITS THE SIMPLE ENTRY OF "PRINT FILENAME N" ; TO PRODUCE N COPIES OF THE NAMED .PRN FILE. IF N IS NOT ; SPECIFIED. IT DEFAULTS TO 1. ; OTHER FILE TYPES MAY BE SPECIFIED IF DESIRED. TABS ARE ; EXPANDED TO 8 SPACES. AND A FORM FEED IS OUTPUT EACH 60 LINES ; AND AT THE END OF THE FILE. ;* CP/M BDOS ADDRESSES 0000 = RBOOT EQU 0 ; RE-BOOT CP/M 0005 = BDOS EQU 5 ; BDOS CALL ENTRY 005C = FCB EQU 5CH ; DEFAULT FILE CONTROL BLOCK 007C = FCBN EQU FCB+32 ; RECORD COUNT 0065 = TYPE EQU FCB+9 ; FILE TVPE 006D = QTY EQU FCB+17 ; NUMBER OF COPIES 0080 = INBUF EQU 80H ; DEFAULT DMA ADDRESS ;* CP/M BDOS FUNCTIONS 0001 = READF EQU 1 ; READ CONSOLE INTO (A) 0002 = TYPEF EQU 2 ; WRITE CONSOLE FROM (E) 0005 = LISTF EQU 5 ; WRITE LIST DEUICE FROM (E) 000B = INTRF EQU 11 ; TEST CONSOLE INTERRUPT 000F = OPEN EQU 15 ; OPEN FILE 0011 = FIND EQU 17 ; FIND FILE IN DIRECTORY 0014 = READ EQU 20 ; READ FILE ;* CONTROL CHARACTERS AND CODES 007F = RUB EQU 7FH ; RUBOUT CHARACTER 001A = EOF EQU 1AH ; END OF FILE IN BUFFER 0009 = TAB EQU 9 ; TAB CHARACTER 000C = FFEED EQU 0CH ; FORM FEED CHARACTER 0100 ORG 0100H ; TPA PROGRAM START ADDRESS 0100 C30B02 JMP START ; GO TO PROGRAM START ;* CONSOLE I/O THROUGH BDOS CALL 0103 E5 CI PUSH H ; SAVE REGISTERS 0104 D5 PUSH D 0105 C5 PUSH B 0106 0E01 MVI C,READF ; READ FUNCTION 0108 CD0500 CALL BDOS ; RETURN CHAR IN (A) 010B C1 POP B ; RESTORE OTHER REGISTERS 010C D1 POP D 010D E1 POP H 010E C9 RET 010F E5 CO PUSH H 0110 D5 PUSH D 0111 C5 PUSH B 0112 5F MOV E,A ; PRINT CHAR TO (E) 0113 0E02 MVI C,TYPEF 0115 CD0500 CALL BDOS 0118 C1 POP B 0119 D1 POP D 011A E1 POP H 011B C9 RET 011C E5 LO PUSH H 011D D5 PUSH D 011E C5 PUSH B 011F 5F MOV E,A 0120 0E05 MVI C,LISTF 0122 CD0500 CALL BDOS 0125 0E0B MVI C,INTRF ; LOOK FOR OPERATOR 0127 CD0500 CALL BDOS ; INTERRUPT 012A E601 ANI 1 ; IN LS BIT 012C CA3701 JZ LOX 012F CD0301 CALL CI ; IS IT A RUBOUT? 0132 FE7F CPI RUB 0134 CAE801 JZ EXIT ; YES. QUIT 0137 C1 LOX POP B 0138 D1 POP D 0139 E1 POP H 013A C9 RET 013B 3E0D CCRLF MVI A,0DH ; CR LF TO CONSOLE 013D CD0F01 CALL CO 0140 3E0A MVI A,0AH 0142 C30F01 JMP CO 0145 3E0D LCRLF MVI A,0DH ; CR LF TO LIST DEUICE 0147 CD1C01 CALL LO 014A 3E0A MVI A,0AH 014C C31C01 JMP LO 014F E1 MSGXP POP H ; OUTPUT MESSAGE AND RETURN 0150 7E MSGX1 MOV A,M ; THROUGH (H,L) 0151 FE00 CPI 0 ; TEXT TERMINATOR = 0 0153 CA5D01 JZ MSGEX 0156 CD0F01 CALL CO 0159 23 INX H 015A C35001 JMP MSGX1 015D 23 MSGEX INX H ; POINT TO TEXT + 1 015E E9 PCHL ; AND RETURN THERE ;* PRINT UTILITY CONSOLE MESSAGE SUBROUTINES 015F CD3B01 RDMSG CALL CCRLF ; PROMPT FOR READ DISC 0162 CD4F01 CALL MSGXP 0165 5245414420 DB 'READ DISC IN DRIVE. THEN CR ' 0181 00 DB 0 0182 CD0301 RDMS1 CALL CI ; GET RESPONSE 0185 FE58 CPI 'X' ; ALLOW EXIT 0187 CA0000 JZ RBOOT ; BACK TO CP/M 018A FE0D CPI 0DH ; ACCEPT CR ONLY 018C C28201 JNZ RDMS1 018F CD3B01 CALL CCRLF ; ACKNOWLEDGE 0192 C9 RET ; AND RETURN 0193 CD3B01 RDERR CALL CCRLF ; SHOW READ ERROR 0196 CD4F01 CALL MSGXP 0199 5245414F20 DB 'REAO ERROR! ENTER X TO ABORT ' 01B7 0D0A DB 0DH,0AH 01B9 2020202020 DB ' CR TO IGNORE ' 01D9 00 DB 0 01DA CD0301 RDER1 CALL CI ; ACCEPT CR OR X 01DD FE58 CPI 'X' 01DF CAE801 JZ EXIT 01E2 FE0D CPI 0DH 01E4 C8 RZ ; RETURN MEANS IGNORE 01E5 C3DA01 JMP RDER1 ; READ ERROR 01E8 CD4F01 EXIT CALL MSGXP 01EB 0D0A DB 0DH,0AH 01ED 4241434B20 DB 'BACK TO CP/M?' 01FA 00 DB 0 01FB CD0301 EXIT1 CALL CI ; WAIT FOR CR OR X 01FE FE0D CPI 0DH 0200 CA0000 JZ RBOOT 0203 FE58 CPI 'X' 0205 CA0000 JZ RBOOT 0208 C2FB01 JNZ EXIT1 ; AS ONLY LEGAL RESPONSE 020B AF START XRA A ; CLEAR CONTINUATION AND 020C 32DA03 STA CONTD ; RELOAD FLAGS 020F 32DB03 STA RELOD 0212 3C INR A ; DEFAULT PRINT QTY = 1 0213 32DC03 STA COUNT 0216 216500 LXI H,TYPE ; SET FILE TYPE TO .PRN 0219 7E MOV A,M ; IF NOT SPECIFIED 021A FE20 CPI ' ' 021C C20B02 JNZ START 021F 3650 MVI M,'P' 0221 23 INX H 0222 3652 MVI M,'R' 0224 23 INX H 0225 364E MVI M,'N' 0227 216D00 STAR1 LXI H,QTY ; GET PRINT QUANTITY 022A 7E MOV A,M ; IF ANY 022B FE20 CPI ' ' 022D CA5702 JZ PRNIN ; ELSE CONTINUE 0230 D630 SUI 30H ; STRIP ASCII 0232 32DC03 STA COUNT ; AND SAVE QUANTITY 0235 23 INX H 0236 7E MOV A,M ; ANOTHER DIGIT? 0237 FE20 CPI ' ' 0239 CA5702 JZ PRNIN ; NO. CONTINUE 023C CDCB03 CALL MULTI ; YES. COUNT * 10 > (C) 023F 7E MOV A,M ; ADD NEW LS DIGIT 0240 D630 SUI 30H 0242 81 ADD C 0243 32DC03 STA COUNT ; FOR TOTAL 0246 23 INX H 0247 7E MOV A,M ; GET LAST DIGIT 0248 FE20 CPI ' ' ; IF ANY 024A CA5702 JZ PRNIN 024D CDCB03 CALL MULTI 0250 7E MOV A,M 0251 D630 SUI 30H 0253 81 ADD C 0254 32DC03 STA COUNT ;* INPUT THE PRINT FILE 0257 CD3B01 PRNIN CALL CCRLF ; SIGN ON MESSAGE 025A CD4F01 CALL MSGXP 025D 43502F4D20 DB 'CP/M PRINT UTILITYV V80.0 6 MAR 80' 0281 0D0A DB 0DH,0AH 0283 00 DB 0 0284 CD5F01 CALL RDMSG ; PROMPT FOR READ DISC 0287 115C00 LXI D,FCB ; LOOK FOR FILE 028A 0E11 MVI C,FIND ; BEFORE GOING AHEAD 028C CD0500 CALL BDOS 028F FEFF CPI 255 ; DOES FILE EXIST? 0291 C2B302 JNZ PRNI1 ; YES. READ IT 0294 CD3B01 CALL CCRLF ; NO. GIVE UP 0297 CD4F01 CALL MSGXP 029A 46494C4520 DB 'FILE DOES NOT EXIST! ' 02AF 00 DB 0 02B0 C3E801 JMP EXIT 02B3 210000 PRNI1 LXI H,0 ; ZERO LINE AND 02B6 22D803 SHLD DSAVE ; CHAR COUNTERS 02B9 21DD03 LXI H,BUFFR ; INITIALIZE POINTER 02BC 22D603 SHLD HSAVE ; INTO BUFFER 02BF 115C00 LXI D,FCB ; USE FILE CONTROL BLOCK 02C2 0E0F MVI C,OPEN ; AND OPEN THE FILE 02C4 CD0500 CALL BDOS 02C7 FEFF CPI 255 ; ERROR? 02C9 C2E802 JNZ PRNI2 02CC CD3B01 CALL CCRLF ; YES. SHOW IT 02CF 554E41424C DB 'UNABLE TO OPEN FILE! ' 02E4 00 DB 0 02E5 C3E801 JMP EXIT ; AND ABORT 02E8 115C00 PRNI2 LXI D,FCB ; READ A RECORD 02EB 0E14 MVI C,READ 02ED CD0500 CALL BDOS 02F0 FE00 CPI 0 ; GOOD READ? 02F2 CAFD02 JZ PRNI3 ; YES. STORE IT 02F5 FE01 CPI 1 ; OR END OF FILE? 02F7 CA2303 JZ RDEND ; YES 02FA CD9301 CALL RDERR ; NO, SHOW ERROR 02FD 2AD603 PRNI3 LHLD HSAVE ; STORE THE RECORD 0300 118000 LXI D,INBUF 0303 0E80 MVI C,80H 0305 1A PRNI4 LDAX D 0306 77 MOV M,A 0307 23 INX H 0308 13 INX D 0309 0D DCR C 030A C20503 JNZ PRNI4 030D 22D603 SHLD HSAVE ; AND NEXT ADDRESS 0310 3A0700 LDA 7 ; ANY MEMORY LEFT? 0313 3D DCR A 0314 BC CMP H 0315 C2E802 JNZ PRNI2 ; YES, KEEP READING 0318 AF XRA A ; NO. SET FLAGS 0319 2F CMA 031A 32DA03 STA CONTD ; AND 031D 32DB03 STA RELOD 0320 C32A03 JMP RDEN1 ; PRINT PARTIAL FILE 0323 AF RDEND XRA A ; CLEAR CONTINUED 0324 32DA03 STA CONTD ; FLAG 0327 327C00 STA FCBN ; REWIND THE FILE 032A 2AD603 RDEN1 LHLD HSAVE ; FLAG END OF FILE 032D 361A MVI M,EOF ;* PRINT THE FILE 032F 2AD803 PRNOU LHLD DSAVE ; (E) = POSITION ON LINE 0332 EB XCHG ; (D) = LINE COUMT ON PAGE 0333 21DD03 LXI H,BUFFR ; OUTPUT THE BUFFER 0336 7E PRNO1 MOV A,M ; GET A CHARACTER 0337 23 INX H ; AND POINT TO NEXT 0338 FE1A CPI EOF ; ALL DONE? 033A CA6703 JZ PRNEX 033D FE0A CPI 0AH ; IGNORE LINE FEEDS 033F CA3603 JZ PRNO1 0342 FE0D CPI 0DH ; CARRIAGE RETURN? 0344 CA5803 JZ NXTLN 0347 FE09 CPI TAB ; TAB CHARACTER? 0349 CAAF03 JZ TABBR ; YES, SKIP AHEAD 034C FE1F CPI 1FH ; NON-PRINTING? 034E DA5203 JC PRNO2 ; YES. DONT COUNT IT 0351 1C INR E ; NO. COUNT 0352 CD1C01 PRNO2 CALL LO ; WRITE THE CHARAACTER 0355 C33603 JMP PRNO1 0358 CD4501 NXTLN CALL LCRLF ; CR AND LF 035B 1E00 MVI E,0 ; ZERO CHAR COUNTER 035D 14 INR D ; COUNT LINE 035E 7A MOV A,D ; TO END OF PAGE 035F FE3C CPI 60 0361 CCC303 CZ FORMO ; THEN FORM FEED 0364 C33603 JMP PRNO1 ; AND CONTINUE 0367 EB PRNEX XCHG ; SAVE COUNTERS 0368 22D803 SHLD DSAVE 036B 3ADA03 LDA CONTD ; FILE CONTINUED? 036E B7 ORA A 036F CA7B03 JZ PRNE1 ; NO, COUNT IT 0372 21DD03 LXI H,BUFFR ; YES. READ MORE 0375 22D603 SHLD HSAVE 0378 C3E802 JMP PRNI2 037B 3E0C PRNE1 MVI A,FFEED ; FEED OUT LAST PAGE 037D CD1C01 CALL LO 0380 210000 LXI H,0 ; AND ZERO COUNTERS 0383 22D803 SHLD DSAVE 0386 3ADC03 LDA COUNT ; COUNT THIS PRINTOUT 0389 3D DCR A 038A 32DC03 STA COUNT 038D C2A103 JNZ PRNE2 ; AND DO MORE TIL 0390 CD4F01 CALL MSGXP ; ALL DONE 0393 414C4C2044 DB 'ALL DOME! ' 039D 00 DB 0 039E C3E801 JMP EXIT 03A1 3ADB03 PRNE2 LDA RELOD ; HAUE TO RELOAD FILE? 03A4 B7 ORA A 03A5 CA2F03 JZ PRNOU ; NO, PRINT IT AS IS 03A8 AF XRA A ; YES. CLEAR THE FLAG 03A9 32DB03 STA RELOD 03AC C3B302 JMP PRNI1 ; AND RE-OPEN THE FILE 03AF 7B TABBR MOV A,E ; GET POSITION 03B0 E607 ANI 07 ; MASK 3 LS BITS 03B2 4F MOV C,A ; FOR TAB SPACING 03B3 79 TABB1 MOV A,C ; DONE? 03B4 E608 ANI 8 03B6 C23603 JNZ PRNO1 ; YES. NEXT CHARACTER 03B9 3E20 MVI A,' ' 03BB CD1C01 CALL LO ; NO. OUTPUT A SPACE 03BE 1C INR E ; COUNT IT 03BF 0C INR C 03C0 C3B303 JMP TABB1 ; AND LOOP 03C3 3E0C FORMO MVI A,FFEED ; OUTPUT A FORM FEED 03C5 CD1C01 CALL LO 03C8 1600 MVI D,0 ; ZERO LINE COUNT 03CA C9 RET 03CB 3ADC03 MULTI LDA COUNT ; COUNT TIMES TEN 03CE 4F MOV C,A 03CF 07 RLC 03D0 07 RLC 03D1 07 RLC 03D2 81 ADD C 03D3 81 ADD C 03D4 4F MOV C,A ; INTO (C) 03D5 C9 RET ;* RAM BUFFERS 03D6 HSAVE DS 2 ; BUFFER ADDRESS STORE 03D8 DSAVE DS 2 ; COUNTERS STORE 03DA CONTD DS 1 ; CONTINUED FLAG 03DB RELOD DS 1 ; RELOAD FILE FLAG 03DC COUNT DS 1 ; NUMBER TO PRINT 03DD BUFFR DS 1 ; START OF RAM BUFFER 03DE END