; ******************************************************************** ; * * ; * 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 rboot equ 0 ; RE-BOOT CP/M bdos equ 5 ; BDOS CALL ENTRY fcb equ 5ch ; DEFAULT FILE CONTROL BLOCK fcbn equ fcb+32 ; RECORD COUNT type equ fcb+9 ; FILE TVPE qty equ fcb+17 ; NUMBER OF COPIES inbuf equ 80h ; DEFAULT DMA ADDRESS ;* CP/M BDOS FUNCTIONS readf equ 1 ; READ CONSOLE INTO (A) typef equ 2 ; WRITE CONSOLE FROM (E) listf equ 5 ; WRITE LIST DEUICE FROM (E) intrf equ 11 ; TEST CONSOLE INTERRUPT open equ 15 ; OPEN FILE find equ 17 ; FIND FILE IN DIRECTORY read equ 20 ; READ FILE ;* CONTROL CHARACTERS AND CODES rub equ 7fh ; RUBOUT CHARACTER eof equ 1ah ; END OF FILE IN BUFFER tab equ 9 ; TAB CHARACTER ffeed equ 0ch ; FORM FEED CHARACTER org 0100h ; TPA PROGRAM START ADDRESS jp start ; GO TO PROGRAM START ;* CONSOLE I/O THROUGH BDOS CALL ci: push hl ; SAVE REGISTERS push de push bc ld c,readf ; READ FUNCTION call bdos ; RETURN CHAR IN (A) pop bc ; RESTORE OTHER REGISTERS pop de pop hl ret co: push hl push de push bc ld e,a ; PRINT CHAR TO (E) ld c,typef call bdos pop bc pop de pop hl ret lo: push hl push de push bc ld e,a ld c,listf call bdos ld c,intrf ; LOOK FOR OPERATOR call bdos ; INTERRUPT and 1 ; IN LS BIT jp z,lox call ci ; IS IT A RUBOUT? cp rub jp z,exit ; YES. QUIT lox: pop bc pop de pop hl ret ccrlf: ld a,0dh ; CR LF TO CONSOLE call co ld a,0ah jp co lcrlf: ld a,0dh ; CR LF TO LIST DEUICE call lo ld a,0ah jp lo msgxp: pop hl ; OUTPUT MESSAGE AND RETURN msgx1: ld a,(hl) ; THROUGH (H,L) cp 0 ; TEXT TERMINATOR = 0 jp z,msgex call co inc hl jp msgx1 msgex: inc hl ; POINT TO TEXT + 1 jp (hl) ; AND RETURN THERE ;* PRINT UTILITY CONSOLE MESSAGE SUBROUTINES rdmsg: call ccrlf ; PROMPT FOR READ DISC call msgxp db 'READ DISC IN DRIVE. THEN CR ' db 0 rdms1: call ci ; GET RESPONSE cp 'X' ; ALLOW EXIT jp z,rboot ; BACK TO CP/M cp 0dh ; ACCEPT CR ONLY jp nz,rdms1 call ccrlf ; ACKNOWLEDGE ret ; AND RETURN rderr: call ccrlf ; SHOW READ ERROR call msgxp db 'REAO ERROR! ENTER X TO ABORT ' db 0dh,0ah db ' CR TO IGNORE ' db 0 rder1: call ci ; ACCEPT CR OR X cp 'X' jp z,exit cp 0dh ret z ; RETURN MEANS IGNORE jp rder1 ; READ ERROR exit: call msgxp db 0dh,0ah db 'BACK TO CP/M?' db 0 exit1: call ci ; WAIT FOR CR OR X cp 0dh jp z,rboot cp 'X' jp z,rboot jp nz,exit1 ; AS ONLY LEGAL RESPONSE start: xor a ; CLEAR CONTINUATION AND ld (contd),a ; RELOAD FLAGS ld (relod),a inc a ; DEFAULT PRINT QTY = 1 ld (count),a ld hl,type ; SET FILE TYPE TO .PRN ld a,(hl) ; IF NOT SPECIFIED cp ' ' jp nz,start ld (hl),'P' inc hl ld (hl),'R' inc hl ld (hl),'N' star1: ld hl,qty ; GET PRINT QUANTITY ld a,(hl) ; IF ANY cp ' ' jp z,prnin ; ELSE CONTINUE sub 30h ; STRIP ASCII ld (count),a ; AND SAVE QUANTITY inc hl ld a,(hl) ; ANOTHER DIGIT? cp ' ' jp z,prnin ; NO. CONTINUE call multi ; YES. COUNT * 10 > (C) ld a,(hl) ; ADD NEW LS DIGIT sub 30h add a,c ld (count),a ; FOR TOTAL inc hl ld a,(hl) ; GET LAST DIGIT cp ' ' ; IF ANY jp z,prnin call multi ld a,(hl) sub 30h add a,c ld (count),a ;* INPUT THE PRINT FILE prnin: call ccrlf ; SIGN ON MESSAGE call msgxp db 'CP/M PRINT UTILITYV V80.0 6 MAR 80' db 0dh,0ah db 0 call rdmsg ; PROMPT FOR READ DISC ld de,fcb ; LOOK FOR FILE ld c,find ; BEFORE GOING AHEAD call bdos cp 255 ; DOES FILE EXIST? jp nz,prni1 ; YES. READ IT call ccrlf ; NO. GIVE UP call msgxp db 'FILE DOES NOT EXIST! ' db 0 jp exit prni1: ld hl,0 ; ZERO LINE AND ld (dsave),hl ; CHAR COUNTERS ld hl,buffr ; INITIALIZE POINTER ld (hsave),hl ; INTO BUFFER ld de,fcb ; USE FILE CONTROL BLOCK ld c,open ; AND OPEN THE FILE call bdos cp 255 ; ERROR? jp nz,prni2 call ccrlf ; YES. SHOW IT db 'UNABLE TO OPEN FILE! ' db 0 jp exit ; AND ABORT prni2: ld de,fcb ; READ A RECORD ld c,read call bdos cp 0 ; GOOD READ? jp z,prni3 ; YES. STORE IT cp 1 ; OR END OF FILE? jp z,rdend ; YES call rderr ; NO, SHOW ERROR prni3: ld hl,(hsave) ; STORE THE RECORD ld de,inbuf ld c,80h prni4: ld a,(de) ld (hl),a inc hl inc de dec c jp nz,prni4 ld (hsave),hl ; AND NEXT ADDRESS ld a,(7) ; ANY MEMORY LEFT? dec a cp h jp nz,prni2 ; YES, KEEP READING xor a ; NO. SET FLAGS cpl ld (contd),a ; AND ld (relod),a jp rden1 ; PRINT PARTIAL FILE rdend: xor a ; CLEAR CONTINUED ld (contd),a ; FLAG ld (fcbn),a ; REWIND THE FILE rden1: ld hl,(hsave) ; FLAG END OF FILE ld (hl),eof ;* PRINT THE FILE prnou: ld hl,(dsave) ; (E) = POSITION ON LINE ex de,hl ; (D) = LINE COUMT ON PAGE ld hl,buffr ; OUTPUT THE BUFFER prno1: ld a,(hl) ; GET A CHARACTER inc hl ; AND POINT TO NEXT cp eof ; ALL DONE? jp z,prnex cp 0ah ; IGNORE LINE FEEDS jp z,prno1 cp 0dh ; CARRIAGE RETURN? jp z,nxtln cp tab ; TAB CHARACTER? jp z,tabbr ; YES, SKIP AHEAD cp 1fh ; NON-PRINTING? jp c,prno2 ; YES. DONT COUNT IT inc e ; NO. COUNT prno2: call lo ; WRITE THE CHARAACTER jp prno1 nxtln: call lcrlf ; CR AND LF ld e,0 ; ZERO CHAR COUNTER inc d ; COUNT LINE ld a,d ; TO END OF PAGE cp 60 call z,formo ; THEN FORM FEED jp prno1 ; AND CONTINUE prnex: ex de,hl ; SAVE COUNTERS ld (dsave),hl ld a,(contd) ; FILE CONTINUED? or a jp z,prne1 ; NO, COUNT IT ld hl,buffr ; YES. READ MORE ld (hsave),hl jp prni2 prne1: ld a,ffeed ; FEED OUT LAST PAGE call lo ld hl,0 ; AND ZERO COUNTERS ld (dsave),hl ld a,(count) ; COUNT THIS PRINTOUT dec a ld (count),a jp nz,prne2 ; AND DO MORE TIL call msgxp ; ALL DONE db 'ALL DOME! ' db 0 jp exit prne2: ld a,(relod) ; HAUE TO RELOAD FILE? or a jp z,prnou ; NO, PRINT IT AS IS xor a ; YES. CLEAR THE FLAG ld (relod),a jp prni1 ; AND RE-OPEN THE FILE tabbr: ld a,e ; GET POSITION and 07 ; MASK 3 LS BITS ld c,a ; FOR TAB SPACING tabb1: ld a,c ; DONE? and 8 jp nz,prno1 ; YES. NEXT CHARACTER ld a,' ' call lo ; NO. OUTPUT A SPACE inc e ; COUNT IT inc c jp tabb1 ; AND LOOP formo: ld a,ffeed ; OUTPUT A FORM FEED call lo ld d,0 ; ZERO LINE COUNT ret multi: ld a,(count) ; COUNT TIMES TEN ld c,a rlca rlca rlca add a,c add a,c ld c,a ; INTO (C) ret ;* RAM BUFFERS hsave: ds 2 ; BUFFER ADDRESS STORE dsave: ds 2 ; COUNTERS STORE contd: ds 1 ; CONTINUED FLAG relod: ds 1 ; RELOAD FILE FLAG count: ds 1 ; NUMBER TO PRINT buffr: ds 1 ; START OF RAM BUFFER end