;PRTCOL.Z80 Multiple-column printer formatter/driver --CHR$(13)09JUL86 -#- ; ; FALSE equ 0 TRUE equ NOT FALSE ; ;DEBUG equ FALSE ;CPM equ TRUE ; BDOS equ 5 LF equ 10 CR equ 13 EOF equ 1Ah ESC equ 1Bh FCB equ 5Ch DFDMA equ 80h FX equ 0FFh ; org 100h ; jp BEGIN ; ;Programmatic variables in this program are put down here in ; the first record so the program can program itself. ; ; -----MAGIC BYTES------ ; ; TABSPC: db 8 ;column count for tab expansion LOFSET: db 8 ;left margin from print-head start COLPRT: db 2 ;copy is split into this many columns GUTBYT: db 5 ;inter-copy midpage margin (gutter) COLBYT: db 35 ;width of each text column in characters ; ;The following variable is meaningless in v1.0: ; PAGLEN: db 65 ;lines that will fit on a page ; LINES: db 55 ;lines of copy per page HEDRUM: db 2 ;header margin in lines FUTRUM: db 4 ;copy-to-footing margin in lines ; LFEED: db 0FFh ;0 = no perfskip. ;0FFh = use ^L for TOF. ;Else, = PRFSKP in linefeeds ;(In future editions, 0FEh = ; calculate it from PAGLEN.) BSCHAR: db 8 ; FFDMAP: db LF ;^L is mapped to this char for CON:. ; SETUP$: db 1,CR ; db 3,ESC,'B',3 ;printer set-up string, w/BYCT, for Gemini ; org SETUP$+16 ; PDONE$: db 1,CR ; db 3,ESC,'B',2 ;normal settings string for Gemini 15X ; org PDONE$+16 ; FLOPPY: db 0FFh ;true if floppy-based HOMDSK: db 'B'-'A' HOMUSR: db 0 HOMNAM: db 'PRTCOL COM' ; ;These two aren't operative in v1.0: ; BUFENA: db 0FFh ;true if dot-buffers are enabled DOTENA: db 0FFh ;true if dot-commands are enabled ; ; ;Down here where they're patchable (if there's room)... ;ECHOSW may be patched to 'call' opcode for print-echo. ; CONOUT: ld e,a ld c,2 ECHOSW: jp BDOS ; pop af push af LSTOUT: ld e,a ld c,5 jp BDOS ; SPARE: equ $ ; ;------------------ ; ; org 180h ; ; BEGIN: ld (STAKS),sp ld sp,STAKS ld c,19h ;get current disk call BDOS ld (CURDSK),a ld e,0FFh ld c,20h ;get/set user code call BDOS ld (CURUSR),a call START ;call into program proper. ; EXIT: ld c,20h ;get/set user code ld a,(CURUSR) ld e,a ;On the way home from a normal call BDOS ;operation, reset to original site. ; ld c,0Eh ;select disk ld a,(CURDSK) ld e,a call BDOS ; QUIT: ld sp,(STAKS) ;here we drop our toys and run. ret ; START: call ILPRT db 1Dh,LF dm 1Dh,1Fh,7,'***----PRTCOL.COM' db 'v1.0-----***',1Dh,1Fh,7,'*',1Fh,28,'*' dm 1Dh,1Fh,7,'*',1Fh,3,'Multicolumnar' dm 'text' dm 'file' dm ' *',1Dh,1Fh,7,'*' dm 'formatter/printer' dm 'to' dm 'CON:,' dm '*',1Dh,1Fh,7,'*' dm 'LST:' dm 'and' dm 'DU:,' dm 'with' dm 'dynamic' dm '*',1Dh,1Fh,7,'*' dm 'parameter' db 'alteration.',1Fh,6,'*',1Dh,1Fh,7,'*',1Fh,28,'*' dm 1Dh,1Fh,7,'***--' db '--CHR$(13)09JUL86----***',1Dh,LF,0 ; ;Parsing: ; If command-line has ' ?' tail, enter CHGPRT first. Then ; peel off the ' ?' and continue. If now empty, leave. ; If command-line is empty, show-and-tell, then offer to ; run CHGPRT. Then leave. ; If command line has only '//' tail, show-and-tell and then ; leave. ; If command-line has ' v' switch, that suppresses LST: ; output. (View-only.) ; If command-line has ' q' switch, that suppresses CON: ; output. (Quietly.) ; If command-line has a second filename.typ (including *.*), ; output will also be sent to disk under that name. This ; will NOT suppress LST: output by itself. ; ;A new-format file-action-only command-line with pre-tweak, then, is: ; ;A0>prt du:infile.typ du:outfile.typ q v ? ; ; ld a,(DFDMA) or a jr z,XPLAIN ld a,(FCB+1) cp ' ' jr z,XPLAIN cp '?' jr z,XPLAIN cp '/' jp nz,BIZNES ld a,(FCB+2) cp '/' jp nz,BIZNES ; XPLAIN: call ILPRT db 'Invocation:' dm 1Dh,LF,'>colprt' dm '[du:]infile.typ[' dm 'du:outfile.typ][' dm 'q][' dm 'v][' dm '?]',1Dh,LF,'OUTFILE.TYP' dm 'must' dm 'be' dm 'specified' dm 'if' dm 'wanted.' dm 'If' dm 'it''s' dm 'only' dm 1Dh,'named' dm 'as' dm '*.*,' dm 'INFILE' dm 'becomes' dm 'INFILE.BAK.',1Dh,LF,'"' dm 'q"' dm '(Quietly):' dm 'suppress' dm 'CON:' dm 'output',1Dh,'"' dm 'v"' dm '(View-only):' dm 'suppress' dm 'LST:' dm 'output',1Dh,'All' dm 'of' dm 'COLPRT''s' dm 'critical' dm 'parameters' dm 'are' dm 'based' dm 'on' dm 'variables',1Dh,'stored' dm 'in' dm 'the' dm 'first' dm 'record' dm 'of' dm 'the' dm 'program.' dm 'Add' dm 'a' dm '"' dm '?"' dm 'tail',1Dh,'to' dm 'the' dm 'command' dm 'line' dm 'to' dm 'alter' dm 'these' dm 'before' dm 'running,' dm 'and',1Dh,'optionally' dm 'save' dm 'the' dm 'changes' dm 'to' dm 'disk' dm 'as' dm 'new' db 'defaults.',1Dh,0 ret ; ; BIZNES: ld hl,0FFFFh ld (INDSK),hl ld (OUTDSK),hl ;put some defaults out there ld hl,DFDMA ld c,(hl) ld b,0 add hl,bc dec c ;we DON'T want to see the starting space. ld b,c SWILUP: dec hl ld a,(hl) inc hl cp ' ' jp nz,COLUP ;no more space-bounded switches? ld a,(hl) cp ' ' jp z,NOCO ;a little bit of format tolerance dec b dec b dec hl dec hl cp '?' ;it's a switch. Which? jp nz,SWIV ld (EDITRQ),a jp SWILUP ; SWIV: cp 'V' jp nz,SWIQ ld a,(LISTON) ;command-tail switches toggle defaults. cpl ld (LISTON),a ;view-only jp SWILUP ; SWIQ: cp 'Q' jp nz,COLUP ld a,(TYPEON) cpl ld (TYPEON),a jp SWILUP ; COLUP: ld a,(hl) ;Loop-top. We're decrementing hl. If cp ' ' ; we find a space before we find a jr nz,NOTSPC ; given colon, the DU: there must be ld (FILFLG),a ; for the input file. jp NOCO NOTSPC: cp ':' jr nz,NOCO call COLON ld a,(FILFLG) or a jr nz,ISOUT ld a,b ;Of course, if it's that close to cp 3 ; the start... jr c,ISIN ISOUT: ld (OUTDSK),de ;(OUTDSK)=e,(OUTUSR)=d jr NOCO ; ISIN: ld (INDSK),de ;guess. NOCO: dec hl djnz COLUP ; ; ;Any fish? ; ;OUTFILE's defaults come from INFILE. INFILE's defaults come from ; CURRENT, the DU: in effect at invocation. A blank is FX. ; ; NEFISH: ld a,(INDSK) inc a jr nz,GOTIDK ld a,(CURDSK) ld (INDSK),a GOTIDK: ld a,(OUTDSK) inc a jr nz,GOTODK ld a,(INDSK) ld (OUTDSK),a GOTODK: ld a,(INUSR) inc a jr nz,GOTIUS ld a,(CURUSR) ld (INUSR),a GOTIUS: ld a,(OUTUSR) inc a jr nz,GOTOUS ld a,(INUSR) ld (OUTUSR),a ; ;Copy the filenames up into their FCBs. First, the source. ; GOTOUS: xor a ld (DIFFLG),a ;DIFFerence FLaG. ; ld hl,FCB+1 ld de,INFCB+1 ld bc,11 ldir ; ;If there isn't to be an output file, never mind this next. ; ld a,(FILFLG) or a jp z,OKDIF ; ;Write verbatim values into the output FCB. ; ld hl,FCB+17 ld de,OUTFCB+1 ld bc,11 ldir ; ;Now overlay any OUTFILE.TYP ambiguities. CCP has turned '*' into '??'. ;Sense also for any difference between infile.typ and outfile.typ. ; ld hl,INFCB+1 ld de,OUTFCB+1 ld b,11 INLDLP: ld a,(de) cp '?' jp nz,NTWILD ld a,(hl) ld (de),a jr INLDIN NTWILD: cp (hl) ;same as INFILE? Then we can't jr z,INLDIN ;say they're different. ld (DIFFLG),a ;any char is non-null INLDIN: inc hl inc de djnz INLDLP ; ;Are infile and outfile DU:s different? ; ld a,(DIFFLG) or a jr nz,OKDIF ld hl,INDSK ld a,(OUTDSK) cp (hl) jr nz,SETDIF ; inc hl ld a,(OUTUSR) cp (hl) jr nz,SETDIF ; ld hl,2424h ;*.$$$ filetype. In and out files ld (OUTFCB+9),hl ;have same name, so we'll go through ld (OUTFCB+10),hl ;the old file-rename routine. jp OKDIF ; ; SETDIF: ld a,0FFh ld (DIFFLG),a ;...or a DU: difference. ; ;We have FCBs filled out. Now go there, after altering parameters if ; so requested. ; OKDIF: call ILPRT dm 1Dh,1Fh,8,'Input: ' db 0 ld a,(INDSK) add 'A' call ILPCHR ; ld a,(INUSR) call PNIB ; ld a,':' call ILPCHR ld hl,INFCB+1 call HLPRT ld a,(FILFLG) or a jr z,GETEDT ; call ILPRT dm 1Dh,1Fh,8,'Output:' db 0 ld a,(OUTDSK) add 'A' call ILPCHR ; ld a,(OUTUSR) call PNIB ; ld a,':' call ILPCHR ld hl,OUTFCB+1 call HLPRT ; GETEDT: call CRLF ld a,(EDITRQ) or a call nz,ACCESS ; ld a,(FLOPPY) or a jr z,GTG ld c,0Dh ;reset disk system call BDOS ; GTG: call GOIN ;go to input DU:. ; ld de,INFCB ld c,0Fh ;open file call BDOS inc a jr nz,OPENOK call ILPRT dm 1Dh,9,7,'+++' dm 'No' dm 'Such' dm 'File' db '+++',1Dh,0 ; ret ; ;Input file opened ok. ; OPENOK: ld a,(FILFLG) or a jp z,NOYT ld a,(DIFFLG) or a call nz,GOOUT ; ld de,OUTFCB ld c,13h ;delete file call BDOS ; sub a ld (OUTFCB+12),a ld (OUTFCB+32),a ld de,OUTFCB ld c,16h ;make file call BDOS inc a jr nz,MAKOK call ILPRT dm 1Dh,9,7,'+++' dm 'Directory' dm 'Full' db '+++',1Dh,0 jp QUIT MAKOK: ld a,(DIFFLG) or a call nz,GOIN ;to input DU: ; ;Read in the first record. ; NOYT: ld de,INFCB ld c,14h ;read sequential call BDOS or a jr z,OKFRST call ILPRT dm 1Dh,7,1Fh,8,'++' dm 'Empty' dm 'File' db '++',0 jp QUIT ; OKFRST: ld hl,DFDMA ld (RCURSR),hl ; ; ;3. Calculate virtual page parameters, slice up memory. ; ld hl,(BDOS+1) ld de,880h or a sbc hl,de ;leave room for CCP push hl pop ix ;create the pushback stack ld (TOSIX),hl ;and record it ld (hl),0 ;and put a null there. ld de,800h ;LOTSA room for pushback stack. or a sbc hl,de ;make room for that stack. push hl ;save a copy ; ;full_line = lofset + (colbyt * colprt) + (gutbyt * colprt-1) ;fulpag = full_line * lines ; call CLRMUL ;clear the multiplier's registers ld a,(COLPRT) ;RPN style: first the tail of the dec a ; equation. ld (MULTER),a ;16-bit multiplier. ld a,(GUTBYT) ld (ACCUM),a call MULTD ;run the multiplier ld hl,(ACCUM) push hl call CLRMUL ;clear it for another goround ld a,(COLPRT) ld (MULTER),a ld a,(COLBYT) ld (ACCUM),a call MULTD ;the middle part ld hl,(ACCUM) ld de,(LOFSET) ;8-bit variable, but this way is ld d,0 ;easier. add hl,de pop de ;now add in the rest. add hl,de ;full bytecount per line. ld (BYLIN),hl push hl call CLRMUL pop hl ld (ACCUM),hl ld a,(LINES) ld (MULTER),a call MULTD ld hl,(ACCUM) ;byct of text section of virtual page. ld (FULPAG),hl ld de,BUFFER ;Where does the file buffer start? add hl,de ;here's the address. ld (TXTBUF),hl ;permanent copy ld (WCURSR),hl ;moving copy push hl pop de ;...as pushed from hl. pop hl ;get back the ceiling address or a sbc hl,de ;how much room in the file buffer? ld a,l and 80h ;in whole records, that is... ld l,a ld (TXTRUM),hl ;bytecount. Permanent copy. ld (WCOUND),hl ;decrementing copy. add hl,hl ;shift left. Now h=recnt. ld l,h ld a,0 rla ;pick up the carry ld h,a ld (RECNT),hl ; ;Now build the default header and footing. ; xor a ld (HEDSID),a ;zero its byct. Nothing waiting. ; ;Default header: ; ;File: A0:FILENAME.TYP ; ld a,(INUSR) cp 0Ah ld a,21 jr c,LOUNUM inc a LOUNUM: ld (HEDBUF),a ;byct ld hl,FILE$ ld de,HEDBUF+1 ld bc,6 ldir ld a,(INDSK) add 'A' ld (de),a inc de ld a,(INUSR) cp 0Ah jr c,STLOUN push af ld a,'1' ld (de),a ;user 15 maximum inc de pop af sub 0Ah STLOUN: add '0' ld (de),a inc de ld a,':' ld (de),a inc de ld hl,FCB+1 ld bc,8 ldir ld a,'.' ld (de),a inc de ld bc,3 ldir ex de,hl ld (hl),0 ;null-term ; ;Default footing: ; ;Page number at center point, provided that's less than 7Fh. ; DOFOOT: ld hl,(BYLIN) ;relax and enjoy your shoes! ld bc,(LOFSET) ;they are very stylish. ld b,0 or a sbc hl,bc ld b,h ld c,l ;margin is added at showtime. or a ;reset carry ld a,b rra ld b,a ld a,c rra ld c,a ld b,0 ;hard-set. 8bit BYCT. ld (FUTBUF),a dec bc dec bc ld hl,FUTBUF+1 ld de,FUTBUF+2 ld (hl),' ' ldir ex de,hl ld (hl),'#' inc hl ld (hl),0 ;null-term ; ;Set up the printer. ; SETPRT: ld hl,SETUP$ ld a,(LISTON) or a call nz,SNPDUN ; ; ;Superb (high-class, expensive) caterer: ; Gai Klass ; (213) 559-6777 ;Nudge her to make you some cookies. ;That, according to Harlan Ellison on Hour 25. ; ; ;Is there one waiting...? A header, that is, not a cookie. ; call GETBYT cp '.' jr nz,NOHDT call FILDOT call HEDCPY jr SETPRT ; NOHDT: cp ' ' jr nc,OKIX cp 9 jr nz,SETPRT OKIX: dec ix ld (ix),a ;4. Until EOF, do the loop. ; ; ;Southland Corporation ;7-11 West Pacific Division ;1240 So State College Blvd Suite #100 ;pob 6520 ;Anaheim CA 92806 ; ;Handy address to have, if you're not entirely happy about the ; precedent they set in caving in to Ed Meese's McCarthyesque ; tactics when he told 'em to stop selling Playboy... Funny, I ; coulda sworn we still had a Constitution! I don't recall our ; voting it down... ; ;Loop: ; ;1. Fill up virtual page ;2. Send header. ;3. Send main text. ;4. Send footing. ;5. Goto 1. ; MAINLP: call FILPAG ;build it. call PPAGE ;print it. ld a,(DUNFLG) ;^Z when EOF. or a jp nz,CLOSAL ld a,(HEDSID) ;new header waiting in the siding? or a call nz,HEDCPY ;at 300wpm, you use pencil? jp MAINLP ; ;5. Flush out last page to LST:, CON:, DSK:. ;6. If, flush printer to top of next form. ;7. If, flush disk buffer to disk and close file. ;8. If same filename.typ, do $$$-rename. ;9. Go home. ; CLOSAL: call CRLF ld a,(FILFLG) or a call nz,WEDUN ; ld hl,PDONE$ ld a,(LISTON) or a ret z SNPDUN: ld a,(hl) inc hl ld b,a or a ret z ;no string? SHUT UP!! SNPDUL: ld a,(hl) inc hl push hl push bc call LSTOUT ;only the printer. pop bc pop hl djnz SNPDUL ret ; ;;; ; HEDCPY: ld b,0 ld hl,HEDSID push hl ld c,(hl) ;grab bytecount ld de,HEDBUF inc bc ;and include it. ldir pop hl ld (hl),0 ;null the byct... it's our flag. ret ; ;;; ; ;Fill in a virtual page. ;Fill in a virtual line. Pay attention to the last full word that ; will fit into the line... leave the pointer at the beginning of ; the next word, fill the line in with spaces up to the right ; margin of the text column, and reloop until all the lines are ; filled in. ;Is handed a byte-count-per-line and an offset from start of page ; line (terms could be better). ;Is the line a ".he" or ".fo" exception? Then call that exception ; handler to dispense with it. ; ;As each page is shown/printed, if file output is chosen, it's ; copied ONCE up into 16KBOX buffer. That copier ignores nulls ; after turning first one into . ;One virtual page is constructed, then, its landmarks dynamically ;allocated at runtime start, and its real-estate subtracted from ;BUFFER, below FILBUF. ;Still better than making two files and then integrating 'em ;into one, and lots better than running in MBASIC. ; ;;; ; ; ;LOFSET: quantity of spaces in left margin ;COLPRT: quantity of text columns on each page ;BYLIN: quantity of bytes in each full line of page text ;COLBYT: characters per line in each column of text ;LINES: quantity of lines in the main text section of page ;GUTBYT: quantity of spaces in each intercolumn gutter ; ; FILPAG: ld a,(COLPRT) ;how many text columns dec a ld c,a ld a,(LINES) ;how many lines in this first column ld b,a ld hl,(TEXPAG) ;hl->start of virtual page text area push hl ;save start-pointer on stack for next column. FSTCOL: push bc ;save the damn linecounter push hl ;save that pointer during margin & line ld a,(LOFSET) ld b,a ;unlike gutter, I don't think or a ;left-offset is intrinsic to jp z,NOFSET ;this kind of thing. ld a,(DUNFLG) or a ld a,0 jp nz,WMARGN ld a,' ' WMARGN: ld (hl),a inc hl djnz WMARGN NOFSET: ld a,(COLBYT) ;load b for this column line ld b,a call FILLIN ; and continue with the column text. ld a,(DOTFLG) or a call nz,FILDOT pop hl ;get back start-of-line... ld de,(BYLIN) ;and repoint to start of next line. add hl,de pop bc ;get back the linecounter djnz FSTCOL ; pop hl ;here's (TEXPAG) again ld a,(LOFSET) ;LOFSET instead of GUTBYT dec c jp INXCOL ; NXTCOL: dec c ld a,(GUTBYT) INXCOL: ld e,a ld d,0 add hl,de ;hl->start of present column ld a,(COLBYT) ld e,a add hl,de ;hl->start of next gutter, ready to go. push hl ld a,(LINES) ld b,a push bc jp INCOL ;skip over the next-line adder ; SAMCLP: push bc ;save linecounter ld de,(BYLIN) ;inc hl to start of next line's column add hl,de INCOL: push hl ;FILLIN & WGUTTR use a copy of hl. ld a,(GUTBYT) ;...at least one byte. ld b,a ld a,(DUNFLG) ;is null if false, or ^Z if true. or a ld a,0 jp nz,WGUTTR ;fill out the last virtual page with nulls. ld a,' ' WGUTTR: ld (hl),a inc hl djnz WGUTTR ;First write the intercolumn spaces... ld a,(COLBYT) ;load b for this column line ld b,a call FILLIN ; and continue with the column text. ld a,(DOTFLG) or a call nz,FILDOT pop hl pop bc ;get back the linecounter djnz SAMCLP pop hl ;get back top-of-column ld a,c ;was that the last text column? or a jp nz,NXTCOL ret ; ;;; ; ;DOTFLG was set when an EOL was followed by a dot on the ; input stream. See if it's one of ours. ; FILDOT: ld hl,HEDSID ld b,0 push hl ;leave .HE firstbyte pointer on stack inc hl ld (hl),'.' inc hl inc b call GETBYT ld (hl),a inc hl inc b call GETBYT ld (hl),a inc hl inc b and 5Fh cp 'E' jp z,ISITHE cp 'O' jp z,ISITFO NODOTC: dec ix ;not our kind of dot. ld a,(hl) ;push back 2nd char... ld (ix),a dec hl dec ix ld a,(hl) ;...first char... ld (ix),a dec hl dec ix ld a,(hl) ;...and dot. ld (hl),a xor a ld (DOTFLG),a pop hl ;flush the pointer. ret ; ISITHE: ld a,(HEDSID+2) and 5Fh cp 'H' jp nz,NODOTC ld hl,HEDSID jp GETDOT ; ISITFO: ld a,(HEDSID+2) and 5Fh cp 'F' jp nz,NODOTC pop hl ld hl,FUTBUF push hl GETDOT: ld b,0 inc hl call GETBYT cp ' ' jp nz,INDTLP GDOTLP: call GETBYT INDTLP: or a jp z,DOTNUL cp EOF jp z,DOTEOF cp CR jp z,DOTEOL cp 9 jp z,DOTTAB ld (hl),a inc hl inc b jp GDOTLP ; DOTNUL: DOTEOL: call GETBYT cp EOF jp z,DOTEOF cp LF jp z,DOTDUN cp ' ' jp c,DOTEOL dec ix ld (ix),a DOTDUN: ld (hl),0 ;null-term pop hl ld (hl),b xor a ld (DOTFLG),a ret ; DOTEOF: ld (DUNFLG),a push hl ld hl,(TOSIX) ld (hl),a pop hl jp DOTDUN ; DOTTAB: ld (hl),' ' inc hl inc b ld a,(TABSPC) dec a and b jp nz,DOTTAB jp GDOTLP ; ; ;;; ; ; ;Fetch characters from GETBYT to fill in a line. At call, ;hl->fbad of line to fill, b=byct. ix is UNGET pointer. ;c = block number. If 0, this is last char line in text ; line. Fill out any with nulls. Else, fill out with ; spaces. ;IX points to a pushback stack, predecrementing, that holds ; any already-fetched fragment of a word that won't fully fit ; into the text column. When the pushback stack is empty, it ; points to a null (which changes to an EOF when that's received). ; ; FILLIN: ld de,0 ;linpos, used by TABBER and desperation. FILNLP: ld a,(ix) ;anything on the push-back stack? or a ;null-terminated at rest. jp z,FETCH cp EOF jp z,EOFL ;if no more text, null fill. ;get it and step the pointer. inc ix ;at least this stuff is already filtered. cp 9 jp nz,NOPTAB ld a,(TABSPC) ITABLP: ld (hl),' ' inc hl inc de dec a jp z,ITABDN djnz ITABLP ;did that fill out the line? ret ; NOPTAB: ld (hl),a inc hl inc de ITABDN: djnz FILNLP ld a,(ix) ;Check next stack entry. Cleanly-done line? cp ' ' ;no EOL on stack. Space not likely at this ret z ;point, but... or a ret z ;No? Put back some. Don't check input jr UNGTBL ;stream-- we're not ready for that yet. ; FETCH: call GETBYT INFTCH: or a jp z,NEOL ;go fill out the line with spaces. cp EOF jp z,FEOFL ;Fill out page with . Set ; DUNFLG. Set top of IX stack to ^Z. cp CR jp z,FEOL cp LF jp z,FEOL cp 9 jp z,TABBER cp ' ' jp c,FETCH ld (hl),a inc hl inc de FATCH: djnz FETCH ; cp ' ' ;Was that a space? If so, this was ret z ;a cleanly done line segment. ; ;(fall through) ; ;Do lookahead (GETBYT, then pushback) to see if next char is a ; word-terminator. If so, line is cleanly done. Otherwise... ;Test backwards to , putting characters on the pushback stack ; and blanking out the place where they were. ;By definition, the pushback stack can't be required to hold more ; than a line of text, so it fits comfortably below CCP. ; UNGET: call GETBYT cp EOF jp z,FEOFL or a ret z cp 9 ;if so, we drop this tab. ret z cp ' ' ;if so, we drop this space. ret z cp CR jp z,FEOL ;flush the stream EOL. cp LF jp z,FEOL dec ix ;push it back. ld (ix),a UNGTBL: dec hl dec de inc b ld a,(hl) cp ' ' ;Pointers are refreshed by caller, ret z ; so it's okay to abandon this one. dec ix ;Copy first part of unusable word ld (ix),a ; onto pushback stack, replacing ld (hl),' ' ; with spaces. ld a,e or d jr nz,UNGTBL ; ;My 'eof' logo-string, amongst other things, is indigestible ; to this program (one word, usually about 40 characters long). ;Here we copy that word into the footing and hope for the best. ; ld hl,FUTBUF push hl ld b,0 inc hl BIGMOV: ld a,(ix) or a jp z,BIGDUN cp EOF jp z,BIGDUN inc ix ld (hl),a inc hl inc b jp BIGMOV BIGDUN: ld (hl),' ' inc hl inc b ld (hl),'#' inc b pop hl ld (hl),b ret ; ;Pull all the bells 'n' whistles that signal quitting time. ; FEOFL: ld (DUNFLG),a push hl push de ld hl,(TOSIX) ;up until now, a null. ld (hl),a ;now, until the page is finished, pop de ;we'll fill out the lines with nulls. pop hl EOFL: ld a,b or a ret z xor a jp FEOLP ; ;Pull in the EOL (don't pushback), then fill out the line. ;If c (block-counter) = 0, use nulls. If not, use spaces. ; LFEOLS: cp LF ;Linefeed here? Call it quits and jp nz,NEOL ; leave any other for next time. FEOL: call GETBYT cp EOF jp z,FEOFL cp 9 jp z,FEPBAK cp '.' jp nz,NOTDOT ld (DOTFLG),a jp NEOL ;we know what it is, now, thank you. ; NOTDOT: cp ' ' jp c,LFEOLS ;flushes out any control bytes except tab, lf FEPBAK: dec ix ld (ix),a ; NEOL: ld a,b or a ret z ;no 256 extras, please. ld a,c or a jp z,FEOLP ld a,' ' FEOLP: ld (hl),a inc hl inc de djnz FEOLP ret ; ; TABBER: ld (hl),' ' inc hl inc de ld a,(TABSPC) ;how many positions? dec a and e jp z,FATCH djnz TABBER ret ; ; ;; ; ;Print a virtual page, including header, footing and perfskip. ; Call with hl -> page start. Printer is assumed to be at TOF. ;Checks variable LFEED after the page is sent. If zero, sends ; nothing. If 0FFh, sends ^L. Otherwise, sends that many LF. ;Uses PCHAR, which chains (sometimes) to LCHAR. PCHAR pushes/pops ; nothing it doesn't need, so BDOS trashing WILL show through. ;PCHAR must have a programmable intercept for ^L, for the sake ; of INFOTON/INFORMER terminals that CLEAR on that (map to ^J). ; PPAGE: call PHEADR ld a,(LINES) ld l,a ld h,0 ld (LINLFT),hl ld hl,(TEXPAG) PPGLUP: ld bc,(BYLIN) push hl call PLINE ; NOTNUL: ld hl,LINLFT dec (hl) pop hl jp z,PDN ld de,(BYLIN) add hl,de jp PPGLUP ; PDN: ld (OLDPAG),hl call PFOOTG ; ld a,(LFEED) or a ret z cp 0FFh jr z,FORFED ld b,a FFDLUP: push bc call PCRLF pop bc djnz FFDLUP ret ; FORFED: ld a,0Ch ;formfeed jp PCHAR ; ;; ; PLINLP: inc hl PLINE: ld a,(hl) and 7Fh jp z,PEOL ;on null, do EOL cp CR jp z,PEOL cp LF jp z,PEOL cp 7Fh ;no deletes, thanks. jp z,PLINLP cp ' ' ;tabs were expanded in layout phase jp c,PLINLP push hl push bc call PCHAR pop bc pop hl dec bc ld a,c or b jp nz,PLINLP ; ;(fall through) ; PEOL: push hl push bc call PCRLF ;give image a CP/M EOL pop bc pop hl ld a,(hl) ;what was that, anyway? cp LF ;step past solitary jp z,LFRET or a ;null? XNULL will take care of it. ret z cp CR ;(not used here:) if not cr, libyct=0. ret nz ;then we're up to start of next line. inc hl ;it's . Solo, or in ? ld a,(hl) cp LF ret nz ;solo. Next, please. LFRET: inc hl ;. Step to start of next line. ret ; ;; ; PHEADR: ld hl,(HEDRAD) ;address of header buffer, null-term'd. call PBUFFR ld a,(HEDRUM) ;header margin ld b,a HDRMLP: push bc call PCRLF pop bc djnz HDRMLP ret ; PFOOTG: call PCRLF ld a,(FUTRUM) ;footing margin ld b,a FTRMLP: push bc call PCRLF pop bc djnz FTRMLP ld hl,(FOOTAD) ;address of footing buffer, null-term'd. call PBUFFR call INCDEC ret ; PBUFFR: ld b,(hl) push bc inc hl push hl ld a,(LOFSET) or a jp z,BNOFST BMARLP: ex af,af' ;keep the loopcounter in the prime. ld a,' ' ;betcha thought I forgot to include call PCHAR ; the left margin in the header and ex af,af' ; footing! dec a jp nz,BMARLP BNOFST: pop hl pop bc PBUFFL: ld a,(hl) inc hl or a ret z push hl cp '#' jp z,PRPANM push bc call PCHAR pop bc POURLP: pop hl djnz PBUFFL call PCRLF ret ; ;Print the page-number string instead of the pound symbol. ; PRPANM: ld hl,PGNM$ PPNMIN: ld a,(hl) inc hl cp '0' ;omit leading zeros jp z,PPNMIN push hl push bc call PCHAR pop bc pop hl PPNMLP: ld a,(hl) or a jp z,POURLP inc hl push hl push bc call PCHAR pop bc pop hl jp PPNMLP ; ;; ; PCRLF: ld a,CR call PCHAR ld a,LF PCHAR: and 7Fh ld (PSTASH),a ; ld a,(FILFLG) or a ld a,(PSTASH) call nz,WRFILE ; ld a,(PSTASH) cp EOF ret z ld a,(LISTON) or a ld a,(PSTASH) call nz,LSTOUT ;bios hook or patchable BDOS/CDOS call ; ld a,(TYPEON) or a ret z ld a,(PSTASH) cp 'L'-40h jp nz,PNTFFD ld a,(FFDMAP) ;if okay, is ^L. If not, is ^J (LF). PNTFFD: call CONOUT ;bios hook or patchable BDOS/CDOS call ret ; ;;; ; ; ;DU: decoder. ;Call with hl -> colon, b holding command-line countdown. ;Returns with hl -> below the DU:, b decremented to match, ; d = usr: ; e = drv: (A: = 0h) ;0FFh in either means no value was found for it. ; COLON: dec hl ;units digit, or letter dec b ld de,0FFFFh ;set up default values ld a,(hl) cp '0' jr c,NOWLET cp '9'+1 jr nc,NOWLET sub '0' ld d,a dec hl dec b ld a,(hl) cp '0' jr c,NOWLET cp '9'+1 jr nc,NOWLET sub '0' push de ;save the units value ld d,a ;tens value * 10 add a,a add a,a add a,d add a,a pop de add a,d ;add 'em together. ld d,a dec hl dec b ld a,(hl) NOWLET: cp 'a' jr c,UPPER cp 'z'+1 ret c and 5Fh UPPER: cp 'A' ret c cp 'Z'+1 ret nc sub 'A' ld e,a ;move usr: into position ret ; ;;; ; ; ;Close the files and head home. If input and output files ; have the same intended DU:FILENAME.TYP, we don't have to ; change DU:, but that's when we have to do some renaming. ;First we have to cap and flush the output file. ; WEDUN: ld a,EOF call WRFILE ld a,(WCOUND) ;lower half and 7Fh ;whole record count jp nz,WEDUN ld a,EOF call WRFILE ; ;Update the Record Count to reflect how much text we have to stash. ; ld hl,(WCURSR) ld de,(TXTBUF) or a sbc hl,de add hl,hl ;left-shift ld l,h ld a,0 rla ld h,a ld (RECNT),hl ; ld a,h ;just in case we triggered a write or l call nz,OUTWRF ;write out the outfile. ; ld a,(DIFFLG) or a call nz,GOIN ; ld de,INFCB ld c,10h ;close file call BDOS ; ld a,(DIFFLG) or a call nz,GOOUT ; ; ld de,OUTFCB ld c,10h ;close file call BDOS ; ld a,(DIFFLG) or a ret nz ; ;We've got some renaming to do before we can head for home. ; Blind-delete INFILE.BAK ...then ; INFILE.TYP becomes INFILE.BAK; ; OUTFILE.$$$ becomes OUTFILE.TYP. ; ld hl,INFCB+9 ld de,OUTFCB+25 ld bc,3 ldir ; ld hl,BAK$ ld de,INFCB+25 ld bc,3 ldir ; ld hl,INFCB+1 ld de,INFCB+17 ld bc,8 ldir ; ld hl,OUTFCB+1 ld de,OUTFCB+17 ld bc,8 ldir ; ; ld hl,INFCB+1 ld de,KILFCB+1 ld bc,8 ldir ; ld de,KILFCB ld c,13h ;delete file call BDOS ; ld de,INFCB ld c,17h ;rename file call BDOS ; ld de,OUTFCB ld c,17h ;rename file call BDOS ; ret ; BAK$: db 'BAK' ; ; ;Go to input DU:. ; GOIN: ld a,(INDSK) ld e,a ld c,0Eh ;select disk call BDOS ; ld a,(INUSR) ld e,a ld c,20h ;get/set user call BDOS ret ; ; ;Go to output DU:. ; GOOUT: ld a,(OUTDSK) ld e,a ld c,0Eh ;select disk call BDOS ; ld a,(OUTUSR) ld e,a ld c,20h ;get/set user call BDOS ret ; ; ;;; ; ;Fetcher from the DFDMA record buffer. ; Tends the buffer. ;If read error, gives back a 1Ah to ; the caller, and that should be that. ; ;This part's a WordStar Document-mode filler filter. ; GETBYT: call GBYT cp 1Fh ; jp z,GETBYT cp 1Eh ;both. jp z,GETBYT ;flush soft hyphens cp 80h res 7,a ;affects only the N flag ret c cp ' ' ;throw away soft spaces jp z,GETBYT ;gimme nuther byte. cp CR ret nz call GBYT ;flush the LF jp GETBYT ; GBYT: push hl ld hl,(RCURSR) ;loaded to 80h by an unknown hand... ld a,(hl) inc hl ld (RCURSR),hl ld (STASH),a ;and insert this one. ld hl,(RCURSR) ld a,l or a ;RCURSR reached 100h? jr nz,GOTBYT ;nope. push de ;yup. Go get another record. push bc ld de,INFCB ld c,14h ;read sequential call BDOS pop bc pop de or a ;set the flags on the result code. ld a,EOF ;if error, say "eof". That's for jr z,RELOAD ;text files without ^Z. ld (STASH),a ;Will also bite the last char off. RELOAD: ld hl,DFDMA ;reset the RCURSR to 80h ld (RCURSR),hl GOTBYT: ld a,(STASH) ;if no error, no 1Ah, unless it's pop hl ;written in the text file itself. cp EOF ret nz ld (DUNFLG),a push de ld de,(TOSIX) ld (de),a pop de ret ; RCURSR: dw 80h ;Text reading cursor. Never let out of ;the DFDMA region 80h-0FFh. ; ;;; ; ; WRFILE: push hl push bc ld hl,(WCURSR) ld bc,(WCOUND) ld (hl),a inc hl dec bc ld (WCURSR),hl ld (WCOUND),bc ld a,c ;countdown reached zero? or b call z,OUTWRF WRFRET: pop bc pop hl ret ; ;goto OUTUSR, OUTDSK... the code's from PRETTY. ; OUTWRF: ld a,(DIFFLG) or a call nz,GOOUT ld bc,(RECNT) ;until EOF time, has count of ;recordspace in buffer ld de,(TXTBUF) WRFLUP: ld hl,80h add hl,de ld (DMADDR),hl push bc ld c,1Ah ;set DMA address call BDOS ld de,OUTFCB ld c,15h ;write sequential call BDOS or a jp nz,WRFERR pop bc dec bc ld a,b or c ld de,(DMADDR) jp nz,WRFLUP WRFDUN: ld a,(DIFFLG) or a call nz,GOIN ; ; goto INUSR, INDSK... the code's from PRETTY. ; ld hl,(TXTBUF) ;repoint to start of text buffer ld (WCURSR),hl ld hl,(TXTRUM) ld (WCOUND),hl ;write countdown ld de,DFDMA ld c,1Ah ;set DMA back for GETBYT call BDOS ret ; ; ; WRFERR: call ILPRT dm 1Dh,7,9,'++' dm 'Write' dm 'Error' db '++',0 jp QUIT ; ; ;;; ; ; ;At call, hl -> ASCII units digit. ;Increment the multidigit ASCII number. ; INCDEC: ld hl,PAGNUM INDCLP: ld a,(hl) inc a ld (hl),a cp '9'+1 ret c ld (hl),'0' dec hl jr INDCLP ; ;------ ; ;Clear the multibyte registers used in the following multiply. ; CLRMUL: xor a ld hl,MULTER ld de,MULTER+1 ld bc,9 ld (hl),a ldir ret ; ;Based on MORSETXT, a 32-bit by 16-bit unsigned multiply. ; MULTD: push iy push hl push de push bc ld iy,ACCUM ld hl,ACCUM ld de,MULTND ld bc,4 ldir ld b,16 ;bitcount ; MLDLP: rl (iy+0) rl (iy+1) rl (iy+2) rl (iy+3) ld hl,(MULTER) add hl,hl ;shift left into carry ld (MULTER),hl jp nc,NOADD ld hl,(ACCUM) ld de,(MULTND) add hl,de ld (ACCUM),hl ld hl,(ACCUM+2) ld de,(MULTND+2) adc hl,de ld (ACCUM+2),hl NOADD: djnz MLDLP pop bc pop de pop hl pop iy ret ; MULTER: ds 2 ;b0,b1 MULTND: ds 4 ;b0,b1,b2,b3 ACCUM: ds 4 ;b0,b1,b2,b3 ; ; ;-------- ; ; ;String-packer's version of ILPRT. ; ; FUNC is BDOS character-output call. ; 2 CONout ; 4 PUNout ; 5 LSTout ; 6 DIRECT CONOUT ; ; d7 set: Trailing space ; 1Fh: Next byte is space-count ; 1Dh: ; ; ILPRT: ex (sp),hl call HLPRT ex (sp),hl ret ; HLPRT: push de push bc push af ILLUP: ld a,(hl) inc hl cp 80h push af ;save the flags call NOTRAI pop af jr c,ILLUP ;resume ld a,' ' call SHIPIT jr ILLUP ; NOTRAI: and 7Fh or a jr z,ILDUN cp 1Fh jr z,TABBIE cp 1Dh jr nz,SHIPIT ld a,0Dh call ILPCHR ld a,0Ah SHIPIT: call ILPCHR ret ; ILDUN: pop af ;get that extra off pop af ;and the extra call layer pop af pop bc pop de ret ; TABBIE: ld b,(hl) dec b TABLUP: ld a,' ' call ILPCHR djnz TABLUP inc hl ld a,' ' jp SHIPIT ; CRLF: push hl push de push bc push af ld a,CR call ILPCHR ;recursive, so we get filtering and nulls. ld a,LF call ILPCHR pop af pop bc pop de pop hl ret ; ; ; ;;; ; ; ;========== TRACER PACKAGE ======================START ; IF FALSE ; ILPRT: ex (sp),hl push af ILLUP: ld a,(hl) inc hl or a jr z,ILDUN call TRACER jr ILLUP ILDUN: pop af ex (sp),hl ret ; ENDIF ;FALSE ; ; DMPCTR: db 0 DMPTIC: db 0 DUMPHL: dw 0 ; DUMPR: push bc push de DUMPIN: ld (DUMPHL),hl call PHL call ILPRT db ': ',0 ld hl,(DUMPHL) ld e,16 DUMPHX: ld a,(hl) inc hl push hl push de call PHEX ld a,' ' call TRACER pop de pop hl dec e jr nz,DUMPHX ld hl,(DUMPHL) ld e,16 DUMPAS: ld a,(hl) inc hl push hl push de and 7Fh cp ' ' jr nc,ASOK ld a,'.' ASOK: call TRACER pop de pop hl dec e jr nz,DUMPAS ld a,CR call TRACER ld a,LF call TRACER ; ld de,16 ld hl,(DUMPHL) add hl,de ld (DUMPHL),hl ld a,(DMPCTR) inc a ld (DMPCTR),a and 0Fh jr z,DUMPUP cp 8 jr nz,DUMPIN ld a,CR call TRACER ld a,LF call TRACER jr DUMPIN DUMPUP: pop de pop bc xor a ld (DMPCTR),a ld (DMPTIC),a ret ; PHL: push hl ld a,h call PHEX pop hl ld a,l PHEX: push af rrca rrca rrca rrca call PNIB pop af PNIB: and 0Fh add a,90h daa adc a,40h daa ILPCHR: TRACER: push bc push de push hl push af call CONOUT ;BDOS(2) hook with possible print-echo. ld c,0Bh call BDOS or a jr z,NOCSN CSN: ld c,1 call BDOS cp 'S'-40h jr z,CSN cp 'C'-40h jp z,0 NOCSN: pop af pop hl pop de pop bc ret ; SAK: push hl push de push bc push af call ILPRT dm 1Dh,'[waiting:' dm 'strike' dm 'almost' dm 'any' dm 'key]' db 0 ld c,1 call BDOS call ILPRT db CR,1Fh,33,1Dh,0 pop af pop bc pop de pop hl ret ; ; ;======= TRACER PACKAGE ============================END ; ; ;;; ; ; FILE$: db 'File: ',0 PGNM$: db '0000000' PAGNUM: db '1',0 ; ; DUNFLG: db 0 ; When true (1Ah), EOF has been fetched LISTON: db 0FFh ; True: send output to LST: TYPEON: db 0FFh ; True: send output to CON: FILFLG: db 0 ; True: send output to disk. EDITRQ: db 0 ; True: do variables edit before running PSTASH: db 0 ;Output stash STASH: db 0 ;Input stash TEXPAG: dw BUFFER ;start of virtual page FOOTAD: dw FUTBUF HEDRAD: dw HEDBUF ; DIFFLG: db 0 ;true if drive, user, name or type specified ; for OUTFILE is different from INFILE. DOTFLG: db 0 ;if nonzero, a possible dot-command awaits. ; ;------------------- ; INFCB: db 0,' ',' ',0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0 ; OUTFCB: db 0,' ','$$$',0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0 ; 12345678 KILFCB: db 0,' ','BAK',0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0 ; ; db 'STAK:' ds 80h STAKS: ds 2 STASHW: ds 2 ; ; CURDSK: ds 1 CURUSR: ds 1 INDSK: ds 1 INUSR: ds 1 OUTDSK: ds 1 OUTUSR: ds 1 ; ; BYLIN: ds 2 FULPAG: ds 2 LINLFT: ds 2 TOSIX: ds 2 WCURSR: ds 2 WCOUND: ds 2 DMADDR: ds 2 TXTBUF: ds 2 TXTRUM: ds 2 RECNT: ds 2 CURPAG: ds 2 OLDPAG: ds 2 ; LINBUF: db 80h,0 ds 82h ; ;The following puts the pre-tweak module in the buffers. It'll ; be overwritten when the program begins formatting, so it doesn't ; occupy operating space, but it can be called if wanted before the ; real process starts. ACCESS is in there. ; *INCLUDE CHGPRT12.Z80 ; HEDSID: equ LINBUF+84h ;BYCT, then string. HEDBUF: equ HEDSID+84h ;BYCT, then string. FUTBUF: equ HEDBUF+84h ;BYCT, then string. BUFFER: equ FUTBUF+84h ; end ; ; ; eof PRT.Z80/Ampro[midivrb.991]--CHR$(13)27MAY86