; ; PROGRAM: PRINT III (PRINT3) ; VERSION: 1.2 ; DATE: 26 Apr 83 ; AUTHOR: RICHARD CONN ; PREVIOUS VERSIONS: 1.1 (26 Apr 83), 1.0 (22 Apr 83) ; VERS equ 12 FALSE equ 0 TRUE equ NOT FALSE timeok equ FALSE ;TRUE to enable TIME feature, FALSE to disable ; ; PRINT3 is THE file print utility for ZCPR2. Installable by GENINS, ; PRINT3 provides a wide range of options for the user. First, PRINT3 allows ; the user to employ wild cards and file name lists (lists of files separated ; by commas, like: file1,file2,file3,...). Second, PRINT3 provides the ; following options: ; E Exact Mode ; No heading appears, no line numbering, ; no page numbering, tab expansion, form ; feeds ; F File Name Toggle ; The Heading Line can optionally contain ; the name of the file ; H@head@ Heading Text ; The user may specify the text of the heading ; to appear at the top of every page ; I Inspect Files ; The user approves each file to be printed ; before the printing process begins ; L Toggle Line Numbering ; Each line may or may not begin with a line ; number ; M Multiple Runs Toggle ; The user may or may not be prompted to set ; the Top of Form on his printer; Multiple Runs ; ON means that he will not be prompted ; N Toggle Page Numbering ; The numbering of each page is turned on or ; off ; Snnnn Skip to Specified Page ; Printing begins on the indicated page ; T Toggle Time Display ; Time/Date information is optionally included ; in the page header ; ; ; This program is Copyright (c) 1982, 1983 by Richard Conn ; All Rights Reserved ; ; ZCPR2 and its utilities, including this one, are released ; to the public domain. Anyone who wishes to USE them may do so with ; no strings attached. The author assumes no responsibility or ; liability for the use of ZCPR2 and its utilities. ; ; The author, Richard Conn, has sole rights to this program. ; ZCPR2 and its utilities may not be sold without the express, ; written permission of the author. ; ; ; BASIC SYSLIB ROUTINES NEEDED BY TEMPLATE ; ESIZE EQU 16 ; SIZE OF DIR ENTRY (FROM SYSLIB DIRF ROUTINE) EXT DIRFS ; DIRECTORY PROCESSOR EXT DIRPACK ; PACK DIRECTORY EXT ZGPINS ; INIT BUFFERS EXT ZFNAME ; FILE NAME PROCESSOR EXT INITFCB ; INIT FCB EXT RETUD ; RETURN CURRENT USER/DISK EXT PUTUD ; SAVE CURRENT USER/DISK EXT GETUD ; RESTORE CURRENT USER/DISK EXT LOGUD ; LOG INTO USER/DISK EXT PRINT ; PRINT STRING PTED TO BY RET ADR EXT PADC ; PRINT A IN DEC EXT COUT ; CONSOLE OUTPUT ROUTINE EXT CONDIN ; CONDITIONAL INPUT ROUTINE EXT CIN ; CONSOLE INPUT ROUTINE EXT CAPS ; CAPITALIZE ROUTINE EXT CRLF ; NEW LINE ROUTINE EXT CLINE ; COMMAND LINE STRING SAVE ROUTINE EXT CODEND ; CODE END COMPUTATION ROUTINE EXT F$OPEN ; FILE OPEN EXT F$READ ; BLOCK READ EXT F$CLOSE ; FILE CLOSE EXT EVAL10 ; STRING TO BINARY CONVERSION EXT LHLDC ; LST: HL AS DEC OUTPUT EXT LPSTR ; LST: (HL) STRING OUTPUT EXT LPRINT ; LST: STRING OUTPUT EXT LCRLF ; LST: NEW LINE EXT LOUT ; LST: OUTPUT EXT MOVEB ; MOVEB ROUTINE if timeok EXT TIME ; TIME Library Module Routine endif ; ; CP/M EQUATES ; CPM EQU 0 ; WARM BOOT BDOSE EQU CPM+5 ; BDOS ENTRY FCB EQU CPM+5CH ; FCB TBUFF EQU CPM+80H ; INPUT LINE BUFFER DEL EQU 7FH ; CR EQU 13 ; FF EQU 12 ; LF EQU 10 ; CTRLC EQU 'C'-'@' ; ^C CTRLG EQU 'G'-'@' CTRLH EQU 'H'-'@' CTRLI EQU 'I'-'@' CTRLX EQU 'X'-'@' CTRLZ EQU 'Z'-'@' ; ; OTHER EQUATES ; EOLD EQU 0FFH ; END OF LOAD DELIMITER ; ; Branch to Start of Program ; JMP START ; ;****************************************************************** ; ; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format ; ; This data block precisely defines the data format for ; initial features of a ZCPR2 system which are required for proper ; initialization of the ZCPR2-Specific Routines in SYSLIB. ; ; ; EXTERNAL PATH DATA ; EPAVAIL: DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES) EPADR: DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE ; ; INTERNAL PATH DATA ; INTPATH: DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT ; DISK = 1 FOR A, '$' FOR CURRENT ; USER = NUMBER, '$' FOR CURRENT DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT DB 0 ; END OF PATH ; ; MULTIPLE COMMAND LINE BUFFER DATA ; MCAVAIL: DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE? MCADR: DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE ; ; DISK/USER LIMITS ; MDISK: DB 4 ; MAXIMUM NUMBER OF DISKS MUSER: DB 31 ; MAXIMUM USER NUMBER ; ; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK ; DOK: DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES) UOK: DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES) ; ; PRIVILEGED USER DATA ; PUSER: DB 10 ; BEGINNING OF PRIVILEGED USER AREAS PPASS: DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL ; ; CURRENT USER/DISK INDICATOR ; CINDIC: DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS) ; ; DMA ADDRESS FOR DISK TRANSFERS ; DMADR: DW 80H ; TBUFF AREA ; ; NAMED DIRECTORY INFORMATION ; NDRADR: DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY NDNAMES: DB 64 ; MAX NUMBER OF DIRECTORY NAMES DNFILE: DB 'NAMES ' ; NAME OF DISK NAME FILE DB 'DIR' ; TYPE OF DISK NAME FILE ; ; REQUIREMENTS FLAGS ; EPREQD: DB 0FFH ; EXTERNAL PATH? MCREQD: DB 000H ; MULTIPLE COMMAND LINE? MXREQD: DB 0FFH ; MAX USER/DISK? UDREQD: DB 000H ; ALLOW USER/DISK CHANGE? PUREQD: DB 000H ; PRIVILEGED USER? CDREQD: DB 0FFH ; CURRENT INDIC AND DMA? NDREQD: DB 0FFH ; NAMED DIRECTORIES? Z2CLASS: DB 11 ; CLASS 11 DB 'ZCPR2' DS 10 ; RESERVED ; ; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA ; ;****************************************************************** ; ; ; **** Special Initial Value Area for GENINS ; LWIDTH: DB 132 ; WIDTH OF LINE LTPP: DB 44 ; LINES OF TEXT PER PAGE LSPP: DB 5 ; LINES TO SKIP PER PAGE CWIDTH: DB 80 ; WIDTH OF SCREEN CTPP: DB 22 ; LINES OF TEXT PER SCREEN CSPP: DB 1 ; LINES TO SKIP PER SCREEN ; ; NOTE: LTPP + LSPP + 2 (HEADER SIZE) = TOTAL LINES PER PAGE ON PRINTER ; NOTE: CTPP + CSPP + 1 (FOOTER SIZE) = TOTAL LINES PER SCREEN ON CONSOLE ; DLNUMFL: DB 0 ; LINE NUMBER FLAG (DEFAULT TO NO) DPNUMFL: DB 0FFH ; PAGE NUMBER FLAG (DEFAULT TO YES) DEXACT: DB 0 ; EXACT PRINT FLAG (DEFAULT TO NO) DFNPFL: DB 0FFH ; FILE NAME PRINT FLAG (DEFAULT TO YES) DTIMEPFL: DB 0FFH ; TIME PRINT FLAG (DEFAULT TO YES) DMULTFL: DB 0FFH ; MULTIPLE RUN FLAG (DEFAULT TO YES) DINSPECT: DB 0 ; INSPECT FILES (DEFAULT TO NO) ; ; OTHER BUFFERS ; SKIPFL: DB 0 ; SKIP FLAG (DEFAULT TO NO) SKIPNUM: DS 2 ; PAGE NUMBER TO SKIP TO LNUM: DS 2 ; CURRENT LINE NUMBER PNUM: DS 2 ; CURRENT PAGE NUMBER HBUF: DS 100 ; BUFFER FOR HEADING ; if timeok TIMEBF: DS 100 ; BUFFER FOR TIME STAMP endif ; LNUMFL: DB 0 ; LINE NUMBER FLAG (DEFAULT TO NO) PNUMFL: DB 0FFH ; PAGE NUMBER FLAG (DEFAULT TO YES) EXACT: DB 0 ; EXACT PRINT FLAG (DEFAULT TO NO) FNPFL: DB 0FFH ; FILE NAME PRINT FLAG (DEFAULT TO YES) TIMEPFL: DB 0FFH ; TIME PRINT FLAG (DEFAULT TO YES) MULTFL: DB 0FFH ; MULTIPLE RUN FLAG (DEFAULT TO YES) INSPECT: DB 0 ; INSPECT FILES (DEFAULT TO NO) ; ; Start of Program ; START: LXI H,0 ; GET STACK PTR DAD SP SHLD STACK ; SAVE IT LXI SP,STACK ; SET SP CALL PUTUD ; SAVE CURRENT USER/DISK AWAY CALL RETUD ; GET CURRENT USER/DISK MOV A,B ; SAVE DISK STA DISK MOV A,C ; SAVE USER STA USER CALL ZGPINS ; INIT BUFFERS LXI H,TBUFF ; SAVE COMMAND LINE CALL CLINE SHLD CMDLNE ; SAVE PTR ; ; **** Banner of Program ; CALL PRINT DB 'PRINT III, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0',0 ; ; Check for Help Request ; LDA FCB+1 ; GET FIRST CHAR OF FILE NAME CPI ' ' ; NO FILE SPEC? JZ HELP CPI '/' ; OPTION CAUGHT? JNZ ECONT ; ; **** Print Help Information ; HELP: CALL PRINT DB CR,LF,'PRINT III Command --' db cr,lf,' PRINT III is invoked by the following command line:' db cr,lf,' PRINT file1,file2,...,filen o...' db cr,lf,'where each "filen" is an ambiguous file name and type' db cr,lf,'and "o" is zero or more of the following options:' db cr,lf,' E Exact Print (expand tabs, form feed, no line' db cr,lf,' or page numbers, no heading)' db cr,lf,' F Toggle File Name Display' db cr,lf,' H@head@ Specify Page Heading (@ is any printing char)' db cr,lf,' I Inspect and Select Files First' db cr,lf,' L Toggle Numbering of Each Line' db cr,lf,' M Toggle Multiple Runs (MR=No TOF Msg)' db cr,lf,' N Toggle Numbering of Each Page' db cr,lf,' Snnnn Skip to Specified Page before Printing' ; if timeok db cr,lf,' T Toggle Time Display (if available) in header' endif ; db cr,lf,'Examples:' db cr,lf,' PRINT MYFILE.TXT,*.MAC LH''SAMPLE''' db cr,lf,' -- Number Lines, SAMPLE is Heading' db cr,lf,' PRINT MYFILE.* S25E' db cr,lf,' -- Skip to Page 25, Exact Print' db cr,lf,' At any time, ^C aborts PRINT III and ^X skips to next ' db 'file' DB CR,LF,0 ; ; RETURN TO OS ; RETURN: LHLD STACK ; GET OLD STACK SPHL ; SET IT RET ; ; PROGRAM'S INIT ROUTINE ; ECONT: CALL INIT ; PROG INIT ROUTINE ; ; EXTRACT FLAGS IF PRESENT ; LXI H,0 ; SET FILE COUNT SHLD FILECNT LHLD CMDLNE ; PT TO BUFFER ; ; SKIP TO FILE NAME STRING ; CALL SBLANK ; SKIP OVER BLANKS ; ; SKIP TO END OF FILE NAME STRING ; CALL SNBLANK ; SKIP OVER NON-BLANKS ; ; CHECK FOR LEADING SLASH ON OPTION AND SKIP IT IF SO ; OPT: CPI '/' ; OPTION CHAR? JNZ OPTION INX H ; SKIP SLASH ; ; PROCESS LIST OF OPTIONS ; OPTION: MOV A,M ; GET BYTE ORA A ; DONE? JZ DSPEC INX H ; PT TO NEXT CHAR CPI ' ' ; SKIP OVER SPACES JZ OPTION MOV C,A ; COMMAND IN C LXI D,OPTAB ; PT TO OPTION TABLE OPTL: LDAX D ; GET OPTION LETTER ORA A ; END OF TABLE? JZ HELP ; HELP IF SO CMP C ; MATCH? JZ OPTM ; PROCESS IF SO INX D ; PT TO NEXT ENTRY INX D INX D JMP OPTL ; ; PROCESS OPTION ; OPTM: PUSH H ; SAVE HL ON STACK LXI H,OPTION ; GET RETURN ADDRESS XTHL ; ... ON STACK AND RESTORE HL INX D ; PT TO ADDRESS LDAX D ; GET ADDRESS LOW MOV B,A ; ... IN B INX D LDAX D ; GET ADDRESS HIGH MOV D,A ; ... IN D MOV E,B ; LOW IN E PUSH D ; PUT ADDRESS ON STACK MOV A,C ; COMMAND IN A RET ; "CALL" OPTION ROUTINE ; ; **** PROGRAM INIT ROUTINE ; THIS ROUTINE IS USED BY THE PROGRAM TO PERFORM ANY INITS ; INIT: lxi h,dlnumfl ;copy defaults into buffers lxi d,lnumfl mvi b,7 ;7 bytes call moveb ;do copy xra a ;A=0 sta skipfl ;set no skip sta hbuf ;set no heading ; if timeok call time ;get time string lxi d,timebf ;store in buffer initt: mov a,m ;get byte stax d ;put byte inx h ;pt to next inx d ora a ;done? jnz initt endif ; RET ; ; **** OPTION TABLE ; EACH OPTION IS A CAPITAL LETTER OR SPECIAL CHAR FOLLOWED BY ; AN ADDRESS; THE TABLE IS TERMINATED BY A BINARY ZERO ; OPTAB: db 'E' dw optexact db 'F' dw optfn db 'H' dw opthd db 'I' dw optinsp db 'L' dw optln db 'M' dw optmult db 'N' dw optpn db 'S' dw optskip ; if timeok db 'T' dw opttime endif ; DB 0 ; END OF TABLE ; ; Option: E (Toggle exact mode) ; optexact: lda exact ;get flag cma ;flip it sta exact ;put flag ret ; ; Option: F (Toggle file name display) ; optfn: lda fnpfl ;get flag cma ;flip it sta fnpfl ;put flag ret ; ; Option: H (Set Heading) ; opthd: lxi d,hbuf ;pt to heading buffer mov a,m ;get delim ora a ;none? rz mov b,a ;delim in B inx h ;pt to next char opthd1: mov a,m ;get next char ora a ;done? jz opthd3 cmp b ;done by trailing delim? jz opthd2 stax d ;save char inx h ;pt to next inx d jmp opthd1 opthd2: inx h ;skip over delim opthd3: xra a ;store ending 0 stax d ret ; ; Toggle Inspect Option ; optinsp: lda inspect ;flip flag cma sta inspect ret ; ; Set Line Number Flag ; optln: lda lnumfl ;flip flag cma sta lnumfl ret ; ; Set Multiple Run Flag ; optmult: lda multfl ;flip flag cma sta multfl ret ; ; Set Page Numbering Flag ; optpn: lda pnumfl ;flip flag cma sta pnumfl ret ; ; Set Skip Flag and get number ; optskip: mvi a,0ffh ;set flag sta skipfl call eval10 ;get number xchg shld skipnum ;set page number to skip to xchg ;HL pts to next char mov a,d ;see if page number was zero ora e jnz option xra a ;if zero, just turn off skip flag sta skipfl ret ; if timeok ; ; Set Time Flag ; opttime: lda timepfl ;flip flag cma sta timepfl ret ; endif ; ; BEGIN MOVING THROUGH FILE NAMES, SEPARATED BY COMMAS ; DSPEC: LHLD CMDLNE ; PT TO FIRST BYTE CALL SBLANK ; SKIP TO NON-BLANK ; ; MAJOR REENTRY POINT WHEN FILE SPECS ARE SEPARATED BY COMMAS ; HL PTS TO FIRST BYTE OF NEXT FILE SPEC ; DSPEC1: LXI SP,STACK ; RESET STACK CALL GETUD ; RESET USER IF NECESSARY LXI D,NTFCB ; PT TO FCB IN DE, PT TO FIRST CHAR OF FILE NAME IN HL CALL ZFNAME ; EXTRACT FILE NAME INTO FCB, AND GET DISK AND USER JZ DERR ; ERROR HANDLER SHLD NEXTCH ; SAVE PTR TO DELIMITER WHICH ENDED SCAN MOV A,B ; SAVE POSSIBLE DRIVE SPEC CPI 0FFH ; CURRENT DISK? JZ DSPEC2 LDA MDISK ; GET MAX DISK NUMBER DCR B ; ADJUST TO WITHIN BOUNDS 0-15 CMP B ; WITHIN BOUNDS? MOV A,B ; GET DISK NUMBER IN A JNC USPEC DERR: CALL PRINT DB CR,LF,'Invalid Disk Specification',0 JMP DRETURN ; ; SET CURRENT DISK ; DSPEC2: LDA DISK ;GET CURRENT DISK MOV B,A ;... IN B ; CHECK FOR USER NUMBER USPEC: MOV A,C ; GET NEW USER NUMBER CPI 0FFH ; DEFAULT USER? JZ USPEC1 CPI '?' ; ALL USERS NOT ALLOWED? JZ UERR LDA MUSER ; GET MAX USER NUMBER CMP C MOV A,C ; USER NUMBER IN A JNC FCT UERR: CALL PRINT DB CR,LF,'Invalid User Number',0 JMP DRETURN USPEC1: LDA USER ;GET CURRENT USER MOV C,A ;... IN C ; ; LOAD DIRECTORY AND PERFORM FUNCTION ; FCT: MOV A,B ; SAVE NEW DISK/USER AWAY STA CDISK ; CURRENT DISK MOV A,C STA CUSER ; CURRENT USER CALL LOGUD ; LOG INTO ACCOUNT CALL CODEND ; PT TO END OF CODE CALL RETUD ; GET USER NUMBER FOR DIRFS MVI A,11000000B ; SELECT SYS AND NON-SYS FILES ORA C ; OR IN USER NUMBER LXI D,NTFCB ; PT TO FCB CALL INITFCB ; INIT THE FCB CALL DIRFS ; LOAD DIR, SELECT FILES, PACK, AND ALPHABETIZE ; ; DETERMINE BEGINNING OF SCRATCH AREA (SCRATCH) AND SZIE IN PAGES (BCNT) ; PUSH H ; SAVE PTR AND COUNT PUSH B LXI D,ESIZE ; SET PTR TO NEXT FREE BLOCK FCTFRE: MOV A,B ; DONE? ORA C JZ FCTFR1 DAD D ; PT TO NEXT DCX B ; COUNT DOWN JMP FCTFRE FCTFR1: INR H ; NEXT PAGE MVI L,0 SHLD SCRATCH ; SET PTR TO SCRATCH AREA XCHG ; PTR IN DE LHLD BDOSE+1 ; COMPUTE BLOCK BUFFER SIZE MOV A,H ; ADJUST FOR ZCPR2 SUI 10 SUB D ; A=SIZE IN BLOCKS STA BCNT ; SET BLOCK COUNT POP B ; RESTORE AND SAVE REGS POP H ; ; ALLOW USER TO INSPECT FILES ; PUSH H PUSH B CALL ICHECK ; CHECK FOR INSPECT OPTION AND INSPECT IF SET POP B ; RESTORE COUNT AND PTR POP H ; ; PERFORM FUNCTION; HL PTS TO FILE AND BC CONTAINS NUMBER OF FILES ; FCTL: MOV A,B ; CHECK FOR COMPLETION (COUNT = 0) ORA C JZ FCTL1 DCX B ; COUNT DOWN LXI SP,STACK ; RESET STACK PUSH B ; SAVE COUNT AND POINTER PUSH H CALL FUNCTION ; PERFORM FUNCTION FCTLNXT: LXI SP,STACK-4 ; RESTORE STACK POP H ; GET PTR AND COUNT POP B LXI D,ESIZE ; PT TO NEXT ENTRY DAD D JMP FCTL ; ; CHECK FOR NEXT FILE SPEC ; FCTL1: CALL GETUD ; RETURN TO HOME USER/DISK LHLD NEXTCH ; GET PTR MOV A,M ; GET DELIM CPI ',' ; ANOTHER FILE? JNZ DRETURN INX H ; PT TO CHAR AFTER COMMA JMP DSPEC1 ; CONTINUE PROCESSING ; ; **** EMERGENCY ABORT ; ABORT: CALL PRINT DB CR,LF,'** PRINT III Abort **',CR,LF,0 CALL GETUD ; RETURN HOME AND FALL THRU TO DRETURN ; ; **** FUNCTION COMPLETE -- CLEANUP AND EXIT ; FILL THIS IN WITH CLEANUP CODE FOR EXIT ; DRETURN: JMP RETURN ; ; **** INSPECT FILES -- THIS ROUTINE IS TO PERFORM A FILE INSPECTION ; ON INPUT, HL PTS TO FIRST 16-BYTE ENTRY AND BC=NUMBER OF ENTRIES ; ICHECK: mov a,b ;any files? ora c rz push h ;save ptrs push b lxi d,esize ;size of entry ichk1: mvi m,0 ;clear MSBytes dad d ;pt to next dcx b ;count down mov a,b ;done? ora c jnz ichk1 pop b ;restore ptrs pop h lda inspect ;inspect? ora a ;0=no rz call print db cr,lf,'PRINT III File Inspect Mode',0 ichk2: call print db cr,lf,'Select ',0 call prfn ;print file name call print db ' -- (Y/N/Q=Select Rest/S=Skip Rest/other=Y)? ' db 0 call cin ;get response call caps ;capitalize call cout ;echo cpi 'Q' ;select rest? jz ichkyr cpi 'S' ;skip rest jz ichknr cpi 'N' ;no to this one? jnz ichk3 mvi m,0ffh ;set NO flag in file FCB ichk3: dad d ;pt to next one dcx b ;count down mov a,b ;done? ora c jnz ichk2 RET ; Check Rest of Files as Selected ichkyr: call print db cr,lf,' Rest of Files Selected',0 ret ; Check Rest of Files as NOT Selected ichknr: mvi m,0ffh ;set NO flag dad d ;pt to next dcx b ;count down mov a,b ;done? ora c jnz ichknr call print db cr,lf,' Rest of Files NOT Selected',0 ret ; ; **** FUNCTION -- MAIN FUNCTION OF TEMPLATE ; ON ENTRY, HL PTS TO NAME OF FILE (16 BYTES) AND USER IS LOGGED INTO ; DIRECTORY CONTAINING INDICATED FILE ; FUNCTION: ; ; FILE PRINT Routine -- Print the File Whose Name is Pointed to by ; HL; we are already logged into the correct directory ; mov a,m ;file selected? ora a ;0=yes rnz lda multfl ;multiple runs? ora a ;0=no jnz fprint ;go right into function call print db cr,lf,'File: ',0 call prfn ;print file name call print db ' -- Please Set Top of Form' db cr,lf,' Strike Any Key When Ready ',0 call cin ;get response cpi ctrlc ;abort? jz abort cpi ctrlx rz fprint: call prinit ;init print buffers call fload ;load buffer initially call prhead ;print heading line lhld scratch ;pt to first char in file shld nxtln ;set pointer to next line fprloop: call prline ;print line of file jnz fprloop ;done if EOF call page ;advance to top of next page ret ; ; Init Print Buffers and Print File Name ; prinit: lxi d,tfcb ;set up FCB mvi b,12 ;12 bytes call moveb lxi h,0 ;HL=0 shld lnum ;set line number inx h ;HL=1 shld pnum ;set page number lda ltpp ;set line count sta lcount call print db cr,lf,'Printing File ',0 lxi h,tfcb ;pt to FCB call prfn ;print file name ret ; ; FILE LOAD (FLOAD) Routine -- Initial Load of memory buffer ; fload: lxi d,tfcb ;pt to file fcb call initfcb ;init file's fcb call f$open ;open file for input jz fload1 ;open was OK call print db cr,lf,'File ',0 xchg ;HL pts to FCB call prfn ;print file name call print db ' NOT Found',0 pop d ;clear return address ret ;abort printout of this file ; ; This is an entry point for further memory loads of the file ; fload1: lda bcnt ;get number of blocks to load mov c,a ;... in C lhld scratch ;get address of first block to load into shld nxtblk ;set pointer to next block to load fload2: call rdblk ;read a block (128 bytes) jnz eof ;eof encountered? call rdblk ;read another block (128 bytes) jnz eof ;eof encountered? dcr c ;count down jnz fload2 lhld nxtblk ;pt to next byte to load mvi m,eold ;mark end of load ret eof: lxi d,tfcb ;close file call f$close lhld nxtblk ;ensure ^Z mvi m,ctrlz ret rdblk: lxi d,tfcb ;pt to FCB call f$read ;read next block ora a ;error? rnz lhld nxtblk ;get ptr to next block xchg ; as dest lxi h,tbuff ;ptr to DMA address mvi b,128 ;copy 128 bytes rdblk1: mov a,m ;get byte ani 7fh ;mask out msb stax d ;put byte inx h ;pt to next inx d dcr b ;count down jnz rdblk1 xchg ;new nxtblock shld nxtblk ret ; ; Line Print Routine ; Print Next Line with Optional Disk Load ; Input Parameter is NXTLN, which is the address of the first char ; on the next line ; Output Parameter is Zero Flag, with Z meaning done with print, NZ ; meaning more yet to print ; prline: lhld lnum ;increment line number inx h shld lnum lhld nxtln ;pt to first char of next line mvi c,0 ;init char count mov a,m ;get first char of line cpi ctrlz ;EOF? cnz prlnum ;print line number (optional) prl1: mov a,m ;get char cpi eold ;end of load? jz prload cpi ctrlz ;eof? jz prexit inx h ;pt to next char cpi ctrli ;tab? jz prtab cpi cr ;? jz prcr cpi ff ;form feed? jz prff cpi lf ;end of line? jz prldn cpi ctrlh ;back space? jz prbs cpi ctrlg ;ring bell? jz prbell cpi del ;delete char? jz prl1 ;skip it cpi ' ' ;other control char? jc prl1 ;skip if other control char call prout ;print char inr c ;increment char count call eoltest ;check to see if at end of line and newline if so jmp prl1 ; ; End of Load Reached -- Load More of File from Disk ; prload: push b ;save char count call fload1 ;use load routine pop b ;get char count lhld scratch ;next byte is here jmp prl1 ;continue processing ; ; Tabulate ; prtab: mvi a,' ' ;space call prout inr c ;new char call eoltest ;process EOL mov a,c ;done? ani 7 jnz prtab ;continue tabulation jmp prl1 ;continue processing ; ; Exit with Zero Flag Set if Done ; prexit: xra a ;set zero flag ret ; ; Carriage Return -- Reset Character Count and Continue ; prcr: call prout ;send CR to printer mvi c,0 ;reset char count jmp prl1 ;continue processing ; ; Form Feed -- Advance to Top of Next Page ; prff: call page ;page eject with heading mvi c,0 ;reset char count jmp prl1 ;continue processing ; ; Line Feed -- End of Routine ; prldn: call prout ;echo LF to printer shld nxtln ;set ptr to first char of next line mvi a,0ffh ;set not done ora a ;set flags ret ; ; Backspace on Printer ; prbs: mov a,c ;check for beginning of line ora a jz prl1 ;continue if at BOL mvi a,ctrlh ;backspace call prout dcr c ;back up char position jmp prl1 ;continue ; ; Ring Bell on Printer ; prbell: call prout ;ring the bell jmp prl1 ;continue without advancing char position ; ; Test for End of Line and Process if so ; eoltest: lda lwidth ;get line width sui 4 ;4 chars less for continuation mark mov b,a ;result in B lda lnumfl ;line numbering (lines are 7 chars shorter if so) ora a ;0=no jz eolt1 mov a,b ;reduce by 7 for line numbers sui 7 mov b,a eolt1: mov a,b ;get line width cmp c ;there? rnz ;continue if not mov a,m ;get next char cpi cr ;new line next? rz ;continue if so cpi ctrlh ;backspace next? rz ;continue if so mvi a,' ' ;print continuation chars call prout mvi a,'<' call prout mvi a,'<' call prout mvi a,cr ;new line call prout mvi a,lf call prout mvi c,0 ;reset char position lda skipfl ;skipping? ora a ;0=no rnz lda lnumfl ;printing line numbers? ora a ;0=no rz call lprint db ' : ',0 ret ; ; Output a character to the printer ; A = Character ; prout: mov b,a ;char in B call condin ;check for abort jz prout1 cpi ctrlc ;abort? jz abort cpi ctrlx ;abort this one file? jz cxabort prout1: lda skipfl ;skipping? ora a ;set flags (Z=no skip=print char) mov a,b ;restore char cz lout ;send character to printer cpi lf ;special tests if it is a line feed rnz ;done if non-LF char lda lcount ;decrement line counter dcr a sta lcount rnz ; ; Paging Required ; Skip to top of next page; reset LCOUNT (Lines Left on Page Count); ; print header ; prout0: lda ltpp ;get number of text lines per page sta lcount ;set as new line count push h ;save ptr lhld pnum ;increment page number inx h shld pnum lda lspp ;get number of lines to skip per page call lineskp ;skip lines pop h ;restore ptr mov a,m ;check next character cpi ctrlz ;EOF? cnz prhead ;print 2-line heading if NOT EOF ret ; ; Abort current file with final page eject ; cxabort: lda lcount ;get count of remaining lines call lineskp ;skip lines lda lspp ;number of lines to skip per page call lineskp ;skip lines jmp fctlnxt ;continue with next file ; ; Skip out rest of page ; Form Feed Function ; page: lda lcount ;get count of remaining lines call lineskp ;skip lines jmp prout0 ;process top of new page ; ; Skip out lines on page ; A = number of lines to skip ; lineskp: mov b,a ;line count in B ora a ;any? rz lda skipfl ;skipping? ora a rnz lines1: mvi a,cr ;output new line to printer call lout mvi a,lf call lout dcr b ;count down jnz lines1 ret ; ; Print Line Number (optional) ; prlnum: lda skipfl ;skipping? ora a ;0=no rnz lda lnumfl ;get flag ora a ;0=don't number lines rz push h ;save ptr lhld lnum ;get line number call lhldc ;print line number call lprint ;print separator db ': ',0 pop h ;restore ptr ret ; ; Print 2-line heading and control skipping ; prhead: push h ;save ptr lda skipfl ;currently skipping? ora a ;0=no cnz skiptst ;test for shut off lda exact ;exact says no heading ora a ;0FFH=yes jnz prhead1 lda pnumfl ;number pages? ora a ;0=no cnz prpnum ;print page heading and number lda fnpfl ;print file name? ora a ;0=no cnz prfname ;print file name ; if timeok ;time available? lda timepfl ;print time? ora a ;0=no cnz prtime ;print time endif ; lda hbuf ;print heading? ora a ;0=no cnz prhdg ;print heading prhead1: pop h ;restore ptr lda skipfl ;skipping? ora a rnz call lcrlf ;new line jmp lcrlf ; ; Test for completion of skipping ; skiptst: lhld pnum ;get page number xchg ;... in DE lhld skipnum ;get page to skip to mov a,h ;compare them cmp d rnz mov a,l cmp e rnz xra a ;A=0 to stop skipping sta skipfl ;set flag ret ; ; Print Page Number ; prpnum: lda skipfl ;skipping? ora a rnz call lprint ;print header db 'Page ',0 lhld pnum ;print current page number call lhldc ;print as decimal ret ; ; Print File Name ; prfname: lda skipfl ;skipping? ora a rnz call prdash ;print separator lxi h,tfcb+1 ;pt to first char mvi b,8 ;8 chars call lfn1 mvi a,'.' call lout mvi b,3 ;3 chars call lfn1 ret lfn1: mov a,m ;get char ani 7fh ;mask call lout ;send to printer inx h ;pt to next dcr b ;count down jnz lfn1 ret ; ; Print Separator ; prdash: call lprint db ' -- ',0 ret ; if timeok ; ; Print Time ; prtime: lda skipfl ;skipping? ora a rnz call prdash ;print separator lxi h,timebf ;pt to time stamp call lpstr ;print ret ; endif ; ; Print Header ; prhdg: lda skipfl ;skipping? ora a rnz call prdash ;print separator lxi h,hbuf ;pt to heading call lpstr ;print ret ; ; UTILITIES ; SBLANK -- SKIP BLANKS PTED TO BY HL UNTIL NON-BLANK ENCOUNTERED; HL ; SNBLANK -- SKIP NON-BLANKS PTED TO BY HL UNTIL BLANK OR EOL; HL ; PRFN -- PRINT FILE NAME PTED TO BY HL; AFFECT NOTHING ; ; ; SKIP UNTIL NON-BLANK ; SBLANK: MOV A,M ; LOOK FOR BLANK INX H ; PT TO NEXT CPI ' ' ; BLANK? JZ SBLANK DCX H ; BACK UP RET ; ; SKIP UNTIL BLANK OR EOL ; SNBLANK: MOV A,M ; GET CHAR INX H ; PT TO NEXT CPI ' ' ; BLANK? JZ SNB1 ORA A ; EOL? JNZ SNBLANK SNB1: DCX H ; BACK UP RET ; ; PRINT FILE NAME PTED TO BY HL ; OUTPUT TO CON: ; PRFN: PUSH H ; SAVE REGS PUSH B CALL RETUD ; GET CURRENT USER/DISK MOV A,B ; PRINT DISK ADI 'A' ; LETTER CALL COUT MOV A,C ; PRINT USER CALL PADC CALL PRINT DB ': ',0 INX H ; PT TO FILE NAME MVI B,8 ; PRINT NAME CALL PRNT MVI A,'.' ; DECIMAL CALL COUT MVI B,3 ; PRINT TYPE CALL PRNT POP B ; GET REGS POP H RET ; ; PRINT CHARS PTED TO BY HL FOR B BYTES ; OUTPUT TO CON: ; PRNT: MOV A,M ; GET CHAR CALL COUT INX H ; PT TO NEXT DCR B ; COUNT DOWN JNZ PRNT RET ; ; BUFFERS ; DISK: DS 1 ; HOME DISK NUMBER USER: DS 1 ; HOME USER NUMBER CDISK: DS 1 ; CURRENT DISK NUMBER CUSER: DS 1 ; CURRENT USER NUMBER CMDLNE: DS 2 ; PTR TO COMMAND LINE STRING NEXTCH: DS 2 ; PTR TO NEXT CHAR IN MULTIFILE COMMAND LINE FILECNT: DS 2 ; COUNT OF NUMBER OF FILES RENAMED SCRATCH: DS 2 ; ADDRESS OF FIRST FREE BYTE BCNT: DS 1 ; NUMBER OF PAGES IN SCRATCH AREA NTFCB: DS 36 ; FCB FOR NEW FILE ; ; PRINT3 Buffers ; tfcb: ds 36 ; FCB for current file nxtblk: ds 2 ; pointer to next block to load nxtln: ds 2 ; pointer to next line to read lcount: ds 1 ; count of text lines left on page ; ; Stack ; DS 100 ; STACK AREA STACK: DS 2 ; OLD STACK PTR END