;*********************************************************** ; QLIST.ASM Copyright (C) 1985 by UCS, inc. ;*********************************************************** VER EQU 15 ; Version 1.5 January 03/87 ; Version 1.5 January 03/87 ; Fixed bug with tab expansion; margin offset spaces ; should not count when calculating next mod 8 tab ; stop. ; - IC ; ; Version 1.4 March 19/86 ; Fixed several bugs with headers under different ; combinations of compressed print/expanded header. ; Added code to allow header message to show total ; space availabe for header with all combinations of ; compressed/expanded. Made REVO a flag that can be ; changed with DDT. ; - IC ; Version 1.3 Feb 18/86 ; Changed string print subroutine to use high bit set ; as end of string marker instead of '0'. This allows ; strings containing a zero to be sent to printer. ; Since I found that I used the $O options most of the ; time, I also added a switch to allow all options to ; be the default and $O to signify no options. Moved ; the expanded and compressed print strings to 103H and ; added spare bytes so that they could be changed ; without having to re-assemble the entire program. ; - IC ; Version 1.2 Jan 22/86 ; Added compressed print and expanded title options. ; Minor (mostly cosmetic) changes to other code. ; - Ian Cottrell ; Sysop, ICBBS ; Ottawa, Ont, Canada ; (613)-990-9774 ; ; Version 1.1 11/30/1985 ; Fixed nasty bug when printing files on other than the ; default drive. ; - JG ; ; Version 1.0 10/02/1985 by Jim Gronek ; ; ; QLIST is a file lister that will automatically unsqueeze ; files before listing. QLIST allows you to select ; formatting options for the listing, including; left margin ; setting, line feed recognition, page headers, compressed ; print for body of listing and expanded print for the ; headers (if your printer supports these features), and ; page to start/stop printing. ; ; QLIST is based on KPLISTER, but lacks the Okidata 92 ; printer options selection feature, and Kaypro video codes ; of KPLISTER. QLIST is a generic file lister for use with ; ANY Z-80 based, CP/M 2.2 or 3.0 system and any printer. ; NOTE - If you desire expanded print headings or ; compressed print in the body, you must provide your ; printer equates before assembly. The source code is set ; to support a Fujitsu DX2200 printer. ; ; QLIST combines the functions of LISTT16 ((C) Irv Hoff) and ; USQB.REL ((C) Dave Rand) to provide greater flexibility ; for the user. ; ; QLIST must be executed with a filename.typ argument. The ; syntax is as follows: ; ; QLIST filename.typ [$o] ; where: $ is the options menu flag ; $O toggles the formatting options for ; the listing (see below) ; $S sends output to the CRT only ; ; The byte stored at REVO allows you to select the default ; setting for the formatting options switch, $O. If REVO is ; true (non-zero), then QLIST assumes that you always want ; the formatting options and will prompt you for all allowed ; options if no options menu flag is entered. In this case, ; entering $O on the command line will cause options to be ; suppressed. If REVO is false (zero), then the operation ; of the $O switch is reversed (i.e. $O means use options, ; no $O means no options). ; ; If executed without a filename argument, QLIST will exit ; to CP/M with a warm boot. ; ; If you wish to patch QLIST without recompiling, the REVO ; flag is at 104H. Set to 0 for normal ($O required for ; options) or 0FFH for reverse options (no $O required). ; The compressed print on string starts at 104H to 109H, ; compressed off at 10AH to 10FH, expanded on at 110H to ; 115H and expanded off at 116H to 11CH. Remember that the ; last byte of each of these strings must have the high bit ; set. ; ; QLIST may be assembled with ASM ((C) DRI), LASM or MAC ; ((C) DRI). ORG 100H ;-------------------- configuration -------------------- FALSE EQU 00H TRUE EQU NOT FALSE CTLC EQU 'C'-40H ; Control-c to terminate BELL EQU 'G'-40H ; Control-g for bell BS EQU 'H'-40H ; Control-h for backspace TAB EQU 'I'-40H ; Control-i for tab LF EQU 'J'-40H ; Control-j for linefeed FFD EQU 'L'-40H ; Control-l for formfeed CR EQU 'M'-40H ; Control-m for carriage return SI EQU 'V'-40H ; Control-v for synch idle CTLX EQU 'X'-40H ; Control-x to terminate EOF EQU 'Z'-40H ; Control-z for end-of-file FCB1 EQU 05CH ; Location of file control block TBUFF EQU 080H ; Buffer for file control block TEXT EQU 054 ; Number of lines of text per page PAGENM EQU 3 ESC EQU 1BH ; Escape character ; BDOS equates BDOS EQU 05H ; System call entry point CONIN EQU 01H ; Get keyboard character CONOUT EQU 02H ; Crt output routine LIST EQU 05H ; List device output PSTRING EQU 09H ; Console output string CINPUT EQU 0AH ; Console input line STATUS EQU 0BH ; Console status ; print format options table ; set the following equates as desired: OPTS EQU TRUE ; True to allow any options RPOPT EQU FALSE ; True to allow roll paper option MGNOPT EQU TRUE ; True to allow margin option FFOPT EQU TRUE ; True to allow forms feed option HDGOPT EQU TRUE ; True to allow heading option SSPGOPT EQU TRUE ; True to allow start/stop page option CMPOPT EQU TRUE ; True to use compressed print for body ; Be sure to set CMPON and CMPOF below EXPOPT EQU TRUE ; True to use expanded print for titles ; Be sure to set EXPON and EXPOF below NWIDTH EQU 78 ; Paper width for normal print NPGCOL EQU 68 ; Start column of page number for normal print CWIDTH EQU 130 ; Paper width for compressed print CPGCOL EQU 120 ; Start column of page number for compressed ; end of print options table BEGIN: JMP OKPRNT ; Jump around signon message REVO DB 0FFH ; Reverse options flag IF CMPOPT ; NOTE: Last character of these strings ; must have the high bit set (i.e. '+80H') CMPON: DB 15+80H ; Enter compressed print for Fujitsu DX2200 DB 0,0,0,0,0 ; Spares to allow change without re-assemble CMPOF: DB 18+80H ; Return to normal print for Fujitsu DX2200 DB 0,0,0,0,0 ; Spares ENDIF IF EXPOPT EXPON: DB 14+80H ; Enter expanded print for Fujitsu DX2200 DB 0,0,0,0,0 ; Spares EXPOF: DB 20+80H ; Cancel expanded print for Fujitsu DX2200 DB 0,0,0,0,0 ; Spares ENDIF TTABN: DB NWIDTH-1 ; Default - adjust later if necessary PAGCOL: DB NPGCOL ; Default - adjust later if necessary FLAG: DB ' ' ; misc storage locations SAVSTK: DW 0 ; Storage for user's stack CCP: DB 0 ; MSB of CCP address COLMN: DB 0 ; Current column count LCNT: DB 0 ; Current line count FRMFD: DB 0 ; Form feed flag NOTAB: DB 0 ; Tear tab flag START: DB 0 ; Start indicator PAGIND: DB 0 ; New page indicator COMPRS: DB 0 ; Compressed print flag EXPAND: DB 0 ; Expanded title flag MARGIN: DB 0 ; Number of spaces to indent FLEN: DB 0 ; Length of filename in header HLEN: DB 0 ; Max length of header message ; file handling data BUFADR: DW $-$ FILEADR:DW $-$ FILELEN:DB 0,0 FILEPTR:DB 0,0 FILESIZ:DB 0,0 FCB: DB 0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0 ; heading line for hard copy HEAD1: DB SI,SI,SI,SI,SI,SI,SI,SI,SI,SI,SI,SI,' ' HEAD2: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0 HEAD3: DB 'Page ' HEAD4: DB SI,SI,'1',CR,LF,LF,LF+80H PAGES: DB SI,SI,'1 ' PAGEQ: DB SI,SI,' ' QUIT: DB CR,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF+80H QUITR: DB CR,LF,LF,LF,LF+80H TURNUP: DB CR,LF,LF,LF,LF,LF,LF,LF,LF,LF,CR,LF+80H MSG1: DB CR,LF DB ' QLIST v' DB VER/10+'0','.',VER MOD 10+'0' DB ' File Listing Utility (Unsqueezes) ' DB CR,LF DB ' Copyright (C) 1985 by UCS, inc. ' DB CR,LF,LF+80H MERRR: DB ' == No filename was specified == ' DB BELL,CR,LF DB ' (use $S after filename.typ for CRT only) ' DB BELL,CR,LF DB ' (use $O after filename.typ for options) ' DB BELL,CR,LF DB '( ^X or ^C aborts at end of current line)' DB CR,LF+80H MERRN: DB ' == No file by that name on this disk == ' DB CR,LF+80H MERRW: DB '== No ambiguous filenames (*/?) please ==' DB CR,LF+80H MSG1B: DB ' Do you want tear tabs to use roll paper? (Y/N): ',' '+80H MSG1C: DB ' Number of spaces for left margin (0-99): ',' '+80H MSG1D: DB ' Accept Form Feed Characters? (Y/N): ',' '+80H MSG1E: DB ' Heading/date or title (055 character limit) is: ' DB CR,LF,LF,'---> ',' '+80H MSG1F: DB CR,LF DB ' Start printing at page # (Default = 1) : ',' '+80H MSG1G: DB ' Quit printing at page # (Default = End): ',' '+80H MSG1H: DB ' Do you want to use compressed print? (Y/N): ',' '+80H MSG1J: DB ' Use expanded print for title? (Y/N): ',' '+80H MSG2: DB ' Highest page is: ',' '+80H MSG3: DB CR,LF+80H OKPRNT: LXI H,0 ; Save ccp's stack DAD SP ; SHLD SAVSTK ; ; sign-on message LXI H,MSG1 CALL STRNGC ; see if any file was requested TITL: LXI H,TBUFF ; Get ptr to command line tail MOV A,M ; And get # chars in buffer ORA A ; Check for none JZ ERRORR ; Xfr - no command line tail LHLD MEMRY ; Force to mod 256 address LXI D,257 ; DAD D ; MVI A,0 ; MOV L,A ; SHLD MEMRY ; LXI D,128 ; Compute adr of local stack DAD D ; [ 128 bytes above end of program ] SPHL ; Load stack register ; calculate maximum available buffer size LHLD MEMRY ; Get adr of first available byte ; [stored by link or l80] LXI D,256+1032 ; Compensate for stack and table DAD D ; SHLD BUFADR ; Save adr of beginning of buffer SHLD FILEADR ; XCHG ; Buffer adr to de LDA BDOS+2 ; Get msb of bdos adr to a SUI 8 ; And decr by 8 [2k] for ccp MOV H,A ; And move to h STA CCP ; Also save as ccp adr msb XRA A ; Zero-set a ; calculate the difference to get space available SUB E ; Subtract buffer adr [de] from ccp MOV L,A ; Adr to get buffer length MOV A,H ; Result in hl SBB D ; MOV H,A ; ; free space available now in 'hl', so store for buffer size SHLD FILESIZ ; Save buffer length ; move file name into heading buffer ; check for any 'wild card' characters and if present show error LXI H,FCB1 ; Get ptr to default fcb MVI B,11 ; And char count for file name TITL1: INX H ; Incr fcb ptr and MOV A,M ; Fetch byte CPI '?' ; Check for '?' - 'wild card' JZ ERRORW ; Xfr - got '?' - illegal DCR B ; Decr char count JNZ TITL1 ; Xfr - not through with name ; open requested file to read the data to list LXI H,FCB1 ; Move file name from default fcb LXI D,FCB ; Get ptr to internal fcb MVI C,12 ; And length of disk, name, & type CALL STORE ; And move to internal fcb XRA A ; Zero set extent and record count fields STA FCB+12 ; Of fcb for bdos STA FCB+32 ; LHLD FILESIZ ; Initialize read routine values SHLD FILELEN ; SHLD FILEPTR ; LXI D,FCB ; Get fcb pointer for bdos MVI C,15 ; Cp/m 'open file' code CALL BDOS ; INR A ; Check for open error JZ ERRORN ; Xfr - had open error ; if yes, see if a drive was mentioned, do not print that LXI H,TBUFF+3 ; Get ptr to 2nd data char MOV A,M ; And fetch it CPI ':' ; Check for disk separator JZ TITL2 ; Xfr - have disk specification LXI H,TBUFF ; Reset ptr to beginning of data INX H ; Incr past first blank ; move the file name and heading/date into the buffer TITL2: LXI D,HEAD1 ; Get ptr to heading buffer MVI B,0 ; Zero counter TITL2A: INX H ; Incr command line ptr and MOV A,M ; fetch byte ORA A ; Check for terminator JZ TITL2B ; Xfr - got terminator - end of line CPI ' ' ; Check for end of file name JZ TITL2B ; Xfr - got blank - end of file name STAX D ; Store byte in heading buffer INX D ; and incr buffer ptr INR B ; and counter JMP TITL2A ; Go do next TITL2B: IF NOT OPTS OR NOT HDGOPT DCX D ; Point to last char in heading buffer LDAX D ; Get it ORI 80H ; Set high bit for printer output routine STAX D ; Put it back ENDIF ; NOT OPTS OR NOT HDGOPT TITL2C: MOV A,B ; Store length of STA FLEN ; filename in header MOV A,M ; Loop til end of line or option flag ORA A JZ NOOPT ; No options INX H CPI '$' ; Check for command line options JNZ TITL2C ; Xfr - no command line options DCX H ; Back-up to prior char position MVI M,0 ; And store line terminator INX H ; Incr back to option byte, MOV A,M ; Fetch it, STA FLAG ; And store it for later CPI 'S' ; Check for 'screen only' JNZ THEAD ; If not, continue DCX D ; Else, point to last char in heading buffer LDAX D ; Get it ORI 80H ; Set high bit for printer output routine STAX D ; Put it back JMP GOPT6 ; Now skip options - 'screen only' THEAD: LDA REVO ; Get reverse options flag ORA A ; Is set? JZ GOPT0 ; If no, skip XRA A ; Else, reverse options, so clear 'O' STA FLAG DCX D ; Point to last char in heading buffer LDAX D ; Get it ORI 80H ; Set high bit for printer output routine STAX D ; Put it back JMP GOPT6 EOL: IF NOT OPTS OR NOT HDGOPT DCX D ; Point to last char in heading buffer LDAX D ; Get it ORI 80H ; Set high bit for printer output routine STAX D ; Put it back ENDIF ; NOT OPTS OR NOT HDGOPT NOOPT: LDA REVO ; Get reverse options flag ORA A ; Is set? JZ GOPT6 ; If not, skip options MVI A,'O' ; Else, reverse options, so store 'O' STA FLAG ; get options from user GOPT0: ; Get 'tear tabs' option IF OPTS AND RPOPT LXI H,MSG1B ; Output 'tear tabs' message CALL STRNGC ; CALL INPUT ; Get user's reply ANI 5FH ; Force upper case CPI 'Y' ; And check for 'yes' JNZ GOPT0A ; Xfr - not 'yes' - assume 'no' INR A STA NOTAB GOPT0A: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and rpopt ; get left margin option GOPT1: IF OPTS AND MGNOPT LXI H,MSG1C ; Output left margin message CALL STRNGC ; CALL DECINP ; Get decimal number from user MOV A,H ; And check range ORA A ; JNZ PRHC2 ; Xfr - too big MOV A,L ; CPI 100 ; JNC PRHC2 ; Xfr - too big STA MARGIN ; Save value MOV B,A ; Temporarily save in B LDA EXPAND ; Using expanded title? ORA A JZ PRHC1 RAR ; If so, divide by 2 MOV B,A ; New value to B PRHC1: LDA PAGCOL ; Get column for page SUB B ; Adjust for indent STA PAGCOL ; Now restore CALL NEWLINE ; Do cr, lf on console JMP GOPT2 PRHC2: MVI A,BELL ; Ring bell on error CALL COUT ; JMP GOPT1 ; Go try again ENDIF ; Opts and mgnopt ; get form feed option GOPT2: IF OPTS AND FFOPT LXI H,MSG1D ; Output form feed message CALL STRNGC ; CALL INPUT ; Get user's reply ANI 5FH ; Force upper case CPI 'Y' ; And check for 'yes' JNZ GOPT2A ; Xfr - not 'yes' - assume 'no' STA FRMFD ; Set form feed switch GOPT2A: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and ffdopt GOPT3: IF OPTS AND CMPOPT LDA FLAG ; Check for 'o' option CPI 'O' ; JNZ GOPT4 ; Xfr - not 'o' option LXI H,MSG1H ; Output compressed print message CALL STRNGC CALL INPUT ; Get user's reply ANI 5FH ; Force upper case CPI 'Y' ; And check for 'yes' JNZ GOPT3A ; Xfr - not 'yes' - assume 'no' STA COMPRS ; Set compressed print flag MVI A,CWIDTH ; Get width for compressed STA TTABN ; Store it for tear tabs MVI A,CPGCOL ; Get page number column for expanded STA PAGCOL ; Store it GOPT3A: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and cmpopt GOPT4: IF OPTS AND EXPOPT LDA FLAG ; Check for 'o' option CPI 'O' ; JNZ GOPT5 ; Xfr - not 'o' option LXI H,MSG1J ; Output expanded title message CALL STRNGC CALL INPUT ; Get user's reply ANI 5FH ; Force upper case CPI 'Y' ; And check for 'yes' JNZ GOPT4A ; Xfr - not 'yes' - assume 'no' STA EXPAND ; Set form feed switch GOPT4A: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and expopt ; get heading option GOPT5: IF OPTS AND HDGOPT LDA FLEN ; Get length of filename in header ADI 3 ; Extra blanks MOV B,A ; Store in B LDA EXPAND ; Expanded header? ORA A JZ GOPT5A ; If not, skip MOV A,B ; Else, get length of filename + blanks RLC ; Double it MOV B,A ; Store it again GOPT5A: LDA MARGIN ; Get number of indent spaces ADD B ; Add 'em MOV B,A ; Put it back LDA PAGCOL ; Get start column for page number SUB B ; Calculate max length available for header MOV B,A ; Save it LDA EXPAND ; Expanded header ORA A JZ GOPT5B ; If not, skip MOV A,B ; Else, get available length RRC ; Divide by 2 MOV B,A ; Put it back STA HLEN ; Store for later GOPT5B: CALL CONV ; Convert to BCD for printing LXI H,MSG1E+24 ; Point to # of chars in header MOV A,D ; Get first digit ADI '0' ; Add ASCII bias MOV M,A ; Insert it into message INX H ; Point next MOV A,E ; Get last 2 digits ANI 0F0H ; Mask off low nibble RRC ; Move to low nibble RRC RRC RRC ADI '0' ; Add ASCII bias MOV M,A ; Into message INX H ; Point next MOV A,E ; Get digits again ANI 0FH ; Mask off high nibble ADI '0' ; ASCII bias MOV M,A ; Last one LXI H,MSG1E ; Output heading message CALL STRNGC LDA HLEN ; Get max length of input CALL GETSTR ; Get input from console ORA A ; Check for no input JZ GOPT5C ; Xfr - no input MOV C,A ; Move input count to C for move LXI D,HEAD2 ; And get pointer to destination CALL STORE ; Move input to heading buffer DCX D ; Point to last char in heading buffer LDAX D ; Get it ORI 80H ; Set high bit for printer output routine STAX D ; Put it back GOPT5C: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and hdgopt ; get start and stop page GOPT6: IF OPTS AND SSPGOPT LXI H,MSG1F ; Output start page message CALL STRNGC ; MVI A,4 ; Get max length of input CALL GETSTR ; Get input data from console ORA A ; Check for no input JZ GOPT6A ; Return - no input MOV C,A ; Move input count to c for move LXI D,PAGES+2 ; And get destination ptr CALL STORE ; Move input to page number GOPT6A: CALL NEWLINE ; Do cr, lf on console ; get stop page GOPT7: LXI H,MSG1G ; Output stop page message CALL STRNGC ; MVI A,4 ; Get max length of input CALL GETSTR ; Get input data ORA A ; Check for no input JZ GOPT7A ; Return - no input MOV C,A ; Move input count to c for move LXI D,PAGEQ+2 ; And destination pointer CALL STORE ; Move input to quit page number GOPT7A: CALL NEWLINE ; Do cr, lf on console ENDIF ; Opts and ssgopt ; check for squeezed file CHKSQ: CALL NEWPG ; Begin on a new page LXI D,FCB ; Read 1st record in random mode MVI C,21H ; Cp/m 'read random' code CALL BDOS ; LDA 80H ; Fetch 1st byte of file and CPI 76H ; Check for 'squeezed' signature JNZ MAIN ; Xfr - not 'squeezed' LDA 81H ; Now check 2nd byte for CPI 0FFH ; 'squeezed' signature JNZ MAIN ; Xfr - not 'squeezed' LHLD MEMRY ; Compute address of table LXI D,128 ; DAD D ; PUSH H ; And move it to bc for uinit POP B ; LHLD BUFADR ; Get address of usq buffer to hl LDA CCP ; Get msb of ccp adr as end of buffer MOV D,A ; And put in d for uinit CALL UINIT ; Initialize unsqueeze routine CALL USQ ; Now unsqueeze and print it CALL BUFULL ; Output final buffer full JMP ROLL MAIN: CALL GETCH ; Get a byte from the file CPI EOF ; Was if eof? JZ ROLL ; Xfr - end of file CALL PCHR ; Output the byte JMP MAIN ; main print loop for squeezed files BUFULL: PUSH H ; Save all registers for usq PUSH D ; PUSH B ; PUSH PSW ; LHLD BUFADR ; Initialize buffer ptr BUFLP: MOV A,M ; Get byte from buffer CPI EOF ; And check for eof JZ BUFEX ; Xfr - got eof - prepare to return PUSH H ; Save buffer ptr CALL PCHR ; Ouptut byte POP H ; Restore buffer ptr and INX H ; Incr to next byte LDA CCP ; Check for end of buffer CMP H ; JNZ BUFLP ; Xfr - not at end of buffer yet BUFEX: POP PSW ; Restore usq's registers POP B ; POP D ; POP H ; RET ; error routine for usq EREXT: CALL PRINT DB CR,LF,' Unsqueeze error ',BELL,CR,LF+80H JMP 0 ; routine to output characters for both types of input file PCHR: CPI ' ' ; Check for control chars JC PCH4 ; Xfr - got control char PCH3: CALL WRITE2 ; Output char to con and lst XRA A ; Set zero for return STA PAGIND ; And turn off top of page indic. RET PCH4: CPI CR ; Check for cr JZ PCH5 ; Xfr - got cr CPI FFD ; Check for form feed JZ PCH6 ; Xfr - got form feed CPI LF ; Check for line feed JZ PCH7 ; Xfr got line feed CPI TAB ; Check for tab JZ PCH8 ; Xfr got tab JMP PCH9 ; handle 'cr' char. PCH5: LDA PAGIND ; Skip cr at top of new page ORA A ; RNZ ; Xfr - at top CALL ABORT ; Check for operator abort MVI A,CR ; Output a cr to con and lst JMP PCH3 ; handle form feed char. PCH6: LDA PAGIND ; Skip form feeds at top of new page ORA A ; RNZ ; Return - at top CALL ABORT ; Check for operator abort LDA FRMFD ; Check for normal form feed wanted ORA A ; RZ ; Return - ignore form feeds JMP PCH71 ; Go do new page ; handle 'lf' chars. PCH7: LDA PAGIND ; Skip line feeds at top of new page ORA A ; RNZ ; Return - at top LDA LCNT ; Incr line count INR A ; STA LCNT ; And store updated value CPI TEXT ; Check for max lines per page JNC PCH71 ; Xfr - max exceeded MVI A,LF ; Output a line feed to con and lst CALL WRITE3 ; CALL INDENT ; Do left margin indent XRA A ; Set zero for return RET ; 'lf' and lines/page exceeded so start a new page PCH71: CALL ABORT ; Check for operator abort PUSH PSW ; Save byte CALL TTABS ; Output 'tear tabs' if wanted CALL NMBR ; Incr page number CALL CKSP ; Check for 'end page' CALL INDENT ; Do left margin LDA EXPAND ; Expanded print for title? ORA A JZ PCH72 ; If not, carry on LXI H,EXPON ; Else, set printer to expanded print CALL STRNGP PCH72: LXI H,HEAD1 ; Output page heading to con and lst CALL STRNGB CALL PAGNO ; Output page number to con and lst LDA EXPAND ; Were we expanded? ORA A JZ PCH73 LXI H,EXPOF ; If so, printer back to normal CALL STRNGP PCH73: CALL NEWPG ; Initial for new page POP PSW ; Restore original byte RET ; handle tab characters PCH8: PUSH B ; Create some work space LDA (MARGIN) ; Get margin offset MOV B,A ; Save in B PCH81: MVI A,' ' ; Output blanks to next mod 8 column CALL WRITE2 ; To con and lst LDA COLMN ; Check for mod 8 column SUB B ; Margin spaces don't count ANI 7 ; JNZ PCH81 ; Xfr - not mod 8 yet XRA A ; Set zero for return POP B ; Restore BC RET ; display control-characters PCH9: PUSH PSW ; Save byte MVI A,'^' ; Output a '^' as control indicator CALL WRITE2 ; To con and lst POP PSW ; Restore byte ADI 40H ; And shift to alphabetic CALL WRITE2 ; And output to con and lst RET ;-----> getstr get a string from the console. uses BDOS bufferd console ; input and the BDOS default i/o buffer [80h]. ; max. length of input in a GETSTR: STA TBUFF ; Store max length in buffer for bdos LXI D,TBUFF ; Get ptr to buffer for bdos MVI C,0AH ; Cp/m 'buffered console input' code CALL BDOS ; LDA TBUFF+1 ; Get count of input chars LXI H,TBUFF+2 ; Get pointer to input data RET ;-----< getstr ;-----> decinp get decimal input from console and convert to binary ; binary value returned in hl. max 5 char input ; destroys b and de. DECINP: MVI A,6 ; Get max length of input CALL GETSTR ; Get input from console XCHG ; Input data ptr to de LXI H,0 ; Initialize result to zero ORA A ; Check for no input RZ ; Return - nothing input MOV B,A ; Move count to b DI1: LDAX D ; Get input byte, INX D ; Decr pointer, PUSH D ; And save pointer SUI '0' ; Convert char to binary JC DI2 ; Xfr - char not numeric - ignore CPI 10 ; Check other end of numeric range JNC DI2 ; Xfr - char not numeric - ignore DAD H ; Multiply accumulated result by ten PUSH H ; [ 8 x result + 2 x result] DAD H ; DAD H ; POP D ; Restore 2 x result value DAD D ; ORA A ; Add current digit to result ADD L ; MOV L,A ; MVI A,0 ; ADD H ; MOV H,A ; DI2: POP D ; Restore pointer to ascii input DCR B ; Decr input count JNZ DI1 ; Xfr - not through RET ; console buffer for decinp TEMP: DB 5 ; Buffer length [5 bytes] DB 0 ; Input count [set by bdos] DB 0,0,0,0,0 ; Actual buffer ;-----> conv convert hex number in B to BCD in DE ; destroys B and DE CONV: LXI D,0 ; Ready to receive number MOV A,B ; Hex number now in A SUI 100 JC CONV1 INR D MOV B,A JMP CONV+3 CONV1: MOV A,B SUI 10 JC CONV2 INR E MOV B,A JMP CONV1+1 CONV2: MOV A,E RLC RLC RLC RLC ORA B MOV E,A RET ;-----> abort check for operator abort - ctl-c or ctl-x ABORT: MVI C,STATUS ; Check console status CALL BDOS ; RAR ; Check for data present RNC ; Return - no data input MVI C,CONIN ; Read con CALL BDOS ; CPI CTLC ; Check for control-c JZ ABORT1 ; Xfr - got ctl-c - abort program CPI CTLX ; Check for control-x JNZ ABORT ; Xfr - not ctl-x - ignore input ABORT1: LDA NOTAB ; Check for 'tear tabs' wanted ORA A ; JZ EXIT ; Xfr - no - return to cp/m ; add 'tear tabs' for roll paper LXI H,TURNUP ; Print 10 blank lines CALL STRNGP ; LXI H,QUITR-7 ; Print 6 blank lines CALL STRNGP ; JMP EXIT ; Return to ccp - no warm boot ABORT2: LXI H,QUITR-3 ; Print 2 blank lines CALL STRNGC ; JMP EXIT ; Return to ccp - no warm boot ; check to see if ready to stop printing yet CKSP: PUSH H PUSH D PUSH B LXI H,PAGEQ+2 CKSP1: INX H MOV A,M CPI ' ' JNZ CKSP1 DCX H LXI D,HEAD4+2 MVI C,PAGENM CKSP2: LDAX D CMP M JNZ CKSP3 DCX D DCX H DCR C JNZ CKSP2 JMP ABORT1 CKSP3: POP B POP D POP H RET ; check to see if ready to start printing yet CKST: PUSH H PUSH D PUSH B LXI H,PAGES+2 CKST1: INX H MOV A,M CPI ' ' JNZ CKST1 DCX H LXI D,HEAD4+2 MVI C,PAGENM CKST2: LDAX D CMP M JNZ CKST4 DCX D DCX H DCR C JNZ CKST2 STA START MVI A,CR CALL WRITEP LDA NOTAB ORA A CNZ TTABS LDA COMPRS ; Test for compressed print ORA A JZ NOCOMP LXI H,CMPON ; Set printer to compress print CALL STRNGP NOCOMP: CALL INDENT LDA EXPAND ; Test for expanded print in title ORA A JZ CKST3 LXI H,EXPON ; Expanded print for title CALL STRNGP CKST3: LXI H,HEAD1 CALL STRNGB CALL PAGNO LDA EXPAND ; Test for expanded print in title ORA A JZ CKST4 LXI H,EXPOF ; Now turn off expanded print CALL STRNGP CKST4: POP B POP D POP H RET ; see if anything already in the buffer DISK1: LHLD FILELEN XCHG LHLD FILEPTR MOV A,L SUB E MOV A,H SBB D JC DISK5 ; if empty, fill buffer LXI H,0 SHLD FILEPTR ; get next disk sector, check for end-of-file marker DISK2: XCHG LHLD FILELEN MOV A,E SUB L MOV A,D SBB H JNC DISK4 ; otherwise get next sector LHLD FILEADR DAD D XCHG MVI C,26 CALL BDOS LXI D,FCB MVI C,20 CALL BDOS ORA A JNZ DISK3 LXI D,TBUFF LHLD FILEPTR DAD D SHLD FILEPTR JMP DISK2 ; reset for end-of-file marker location DISK3: LHLD FILEPTR SHLD FILELEN ; set for buffer full DISK4: LXI D,TBUFF MVI C,26 CALL BDOS LXI H,0 SHLD FILEPTR ; get the next character from the buffer DISK5: XCHG LHLD FILEADR DAD D XCHG LHLD FILELEN MOV A,L ORA H MVI A,EOF RZ LDAX D LHLD FILEPTR INX H SHLD FILEPTR RET ; exit if having a problem opening a file ERROR: CALL STRNGC JMP EXIT ERRORR: LXI H,MERRR JMP ERROR ERRORN: LXI H,MERRN JMP ERROR ERRORW: LXI H,MERRW JMP ERROR ; exit routine EXIT: XRA A LDA COMPRS ; See if printer was in compressed mode ORA A JZ EXIT1 LXI H,CMPOF ; Restore printer to normal print CALL STRNGP EXIT1: LHLD SAVSTK SPHL JMP 0 ; ouptut a cr, lf pair to the console NEWLINE:LXI H,MSG3 ; Get pointer to cr, lf CALL STRNGC ; Now output it RET ; get a character from the buffer GETCH: CALL DISK1 ANI 7FH RET ; indent for new left margin, if requested INDENT: PUSH PSW PUSH B ; Save user's bc LDA MARGIN ; Get count of margin chars INR A ; And compensate for test before use MOV B,A ; And move to b ID1: DCR B ; Decr margin count JZ IDEX ; Xfr - through MVI A,' ' ; Output a blank CALL WRITEP ; JMP ID1 ; Go do next IDEX: LDA MARGIN ; Compensate for margin in other calculations STA COLMN POP B ; Restore user's BC POP PSW RET ; get a character from the keyboard INPUT: PUSH H PUSH B MVI C,CONIN CALL BDOS ANI 7FH POP B POP H CPI CTLC JZ ABORT2 CPI CTLX JZ ABORT2 RET ; set parameters for a new page NEWPG: XRA A ; Zero-set line count and STA LCNT ; Print column STA COLMN ; MVI A,0FFH ; Turn on new page indicator STA PAGIND ; LDA START ORA A CZ CKST JMP INDENT ; increment the page number for hard copy NMBR: LXI H,HEAD4+2 MVI C,PAGENM NMBR1: MOV A,M CPI ' ' JZ NMBR2 CPI SI JNZ NMBR3 NMBR2: MVI A,'0' NMBR3: INR A MOV M,A CPI '9'+1 JNZ NMBR4 MVI M,'0' DCX H DCR C JNZ NMBR1 NMBR4: RET ; if no print, tell what maximum page was NOPNT: LXI H,MSG3 CALL STRNGC LXI H,MSG2 CALL STRNGC LXI H,HEAD4 CALL STRNGC JMP EXIT ; to start a new page NUPAGE: LXI H,TURNUP JMP STRNGB ; display and print the page number PAGNO: LDA PAGCOL MOV B,A LDA EXPAND ; See if expanded print is wanted ORA A JZ PAGNO1 ; If no, carry on MOV A,B ; Else, divide page # column RAR ; by 2 MOV B,A PAGNO1: MVI A,' ' CALL WRITE2 LDA COLMN ADI 1 SUB B JC PAGNO1 LXI H,HEAD3 JMP STRNGB ; roll up page to terminate ROLL: LDA START ORA A JZ NOPNT MVI A,CR CALL WRITEP ROLL1: LDA LCNT INR A STA LCNT CPI TEXT JNC ROLL2 MVI A,LF CALL WRITEP JMP ROLL1 ROLL2: CALL TTABS LDA NOTAB ORA A JZ EXIT LXI H,QUIT CALL STRNGP JMP EXIT ; ignore cr, lf, ffd or eof at top of any new page SKIP: CALL GETCH CPI CR JZ SKIP CPI LF JZ SKIP CPI EOF JZ ROLL CPI FFD JZ SKIP RET ; transfer a string of chars. from one area to another STORE: MOV A,M STAX D INX H INX D DCR C JNZ STORE RET ; print and display a string of characters STRNGB: MOV A,M PUSH PSW ; Save for later ANI 7FH ; Remove any high bits CALL WRITE2 POP PSW ; Now restore RLC ; Test for high bit set RC ; If so, all done INX H ; Else, continue JMP STRNGB ; write ascii string to crt only STRNGC: MOV A,M PUSH PSW ; Save for later ANI 7FH ; Remove any high bits CALL COUT POP PSW ; Now restore RLC ; Test for high bit set RC ; If so, all done INX H JMP STRNGC ; print an in-line message PRINT: XTHL ; Retrieve message address from stack CALL STRNGC ; Print string INX H ; Incr past terminator XTHL ; Restore return address to stack RET ; print a string of characters STRNGP: MOV A,M PUSH PSW ; Save for later ANI 7FH ; Remove any high bits CALL WRITEP POP PSW ; Now restore RLC ; Test for high bit set RC ; If so, all done INX H ; Else, continue JMP STRNGP ; adds tear tabs for roll paper TTABS: LDA NOTAB ORA A JZ NUPAGE LXI H,QUITR CALL STRNGB MVI A,'-' CALL WRITE3 LDA TTABN MOV B,A TTABS1: MVI A,' ' CALL WRITE3 DCR B JNZ TTABS1 MVI A,'-' CALL WRITE2 LXI H,QUITR CALL STRNGB XRA A STA COLMN RET ; write char. to crt WRITE2: CPI SI RZ CPI CR JZ WRITE3 CPI LF JZ WRITE3 PUSH PSW LDA COLMN INR A STA COLMN POP PSW WRITE3: CALL WRITEC ; write char. to printer WRITE1: CALL WRITEP RET ; write ascii character to crt WRITEC: MOV E,A LDA START ORA A MOV A,E RZ COUT: PUSH H PUSH D PUSH B PUSH PSW MOV E,A MVI C,CONOUT CALL BDOS POP PSW POP B POP D POP H RET ; write ascii character to printer WRITEP: CPI SI RZ MOV E,A LDA FLAG CPI 'S' RZ LDA START ORA A RZ PUSH H PUSH B MVI C,LIST CALL BDOS POP B POP H RET DLE EQU 090H ;-----> uinit initialize the unsqueeze routine with values from the ; user; hl = address of usq buffer, de = adr of top of buffer, ; bc = adr of 1032 byte table UINIT: SHLD BUFF ; Store buffer address SHLD NEXTADR ; MOV A,D ; Store high order byte of top adr STA TOPRAM ; PUSH B ; Store adr of table POP H ; SHLD TABLE ; RET ;-----< uinit ;this is start of baseline usq code USQ: XRA A ; Force init char read STA NUMLFT STA RCNT ; And zero repeats LHLD LASTMEM SHLD SOB SHLD EOB CALL GETW USQ1: CALL GETW ; Get cksum, and store SHLD FILECRC USQ2: CALL GET1 JNZ EREXT ORA A JNZ USQ2 USQ3A: CALL GETW SHLD NUMVALS LXI D,258 CALL CMPDEHL JC USQ3B CALL ERREXT DB CR,LF,' File has illegal decode size. Aborting. ' DB BELL,CR,LF+80H USQ3B: XCHG LHLD TABLE XCHG USQ4: SHLD MAX MOV A,H ORA L JZ USQ5 PUSH D CALL GETW POP D XCHG MOV M,E INX H MOV M,D INX H PUSH H CALL GETW XCHG POP H MOV M,E INX H MOV M,D INX H XCHG LHLD MAX DCX H JMP USQ4 USQ5: LXI H,0 USQ6: PUSH H CALL GETNXT POP H JNZ USQ8 MOV E,A MVI D,0 DAD D PUSH H PUSH PSW LHLD NEXTADR ; Point to load address LDA TOPRAM ; Check against end page of tpa CMP H ; If at same page, yes JNZ NOFULL ; Buffer is not full yet CALL BUFULL ; Buffer full, process buffer LHLD BUFF ; Reset buffer pointer NOFULL: POP PSW MOV M,A INX H SHLD NEXTADR POP H JMP USQ6 USQ8: XCHG LHLD FILECRC CALL CMPDEHL USQ9: RZ CALL PRINT DB CR,LF,' ERROR - Checksum error in file ' DB BELL+80H JMP EREXT ERREXT: POP H MOV A,M ORA A JZ EREXT INX H PUSH H CALL COUT JMP ERREXT CMPDEHL:MOV A,H CMP D RNZ MOV A,L CMP E RET GET1: LHLD EOB XCHG LHLD SOB CALL CMPDEHL JZ GET1R MOV A,M INX H SHLD SOB CMP A RET GET1R: LHLD LASTMEM SHLD SOB SHLD EOB GET1R1: PUSH H XCHG MVI C,26 CALL BDOS LXI D,FCB MVI C,20 CALL BDOS POP H ORA A JNZ GET1R2 LXI D,128 DAD D XCHG LHLD ENDMEM CALL CMPDEHL XCHG JNC GET1R1 GET1R2: SHLD EOB XCHG LHLD SOB CALL CMPDEHL JNZ GET1 MVI A,255 ORA A RET GETW: CALL GET1 JNZ BADR PUSH PSW CALL GET1 JNZ BADR MOV H,A POP PSW MOV L,A RET BADR: CALL PRINT DB CR,LF,'Premature EOF on file... aborted.' DB BELL+80H JMP 0 GETNXT: LDA RCNT ; See if in the middle of ORA A ; Repeat sequence... JZ GETN7 DCR A STA RCNT LDA LAST CMP A RET GETN7: CALL GETN4 CPI DLE JNZ GETN5 CALL GETN4 ORA A JNZ GETN6 MVI A,DLE ; Dle is encoded as dle,0 CMP A RET GETN6: DCR A DCR A STA RCNT LDA LAST CMP A RET GETN5: STA LAST CMP A RET GETN4: LXI D,0 ; Pointer @ sot LDA CHAR MOV C,A GETN1: LDA NUMLFT ORA A JNZ GETN2 PUSH D CALL GET1 JNZ BADR POP D MOV C,A MVI A,8 GETN2: DCR A STA NUMLFT MOV A,C RRC MOV C,A LHLD TABLE JNC GETN3 INX H INX H ; Add 2 to point to right node GETN3: DAD D DAD D DAD D DAD D ; Ok.. pointing close to right plc.. MOV E,M INX H MOV D,M MOV A,D ANI 128 JZ GETN1 MOV A,C STA CHAR MOV A,D CPI 254 ; Is special eof? MVI A,EOF JZ GETEOF ; Yup MOV A,E CMA CMP A RET GETEOF: POP H ORA A RET ;end of baseline usq code LASTMEM:DW 80H ENDMEM: DW 80H+127 SOB: DW 80H EOB: DW 80H ; the following values are initialized by uinit with values ; supplied by the user BUFF: DW $-$ TOPRAM: DB 0 TABLE: DW $-$ NEXTADR:DW $-$ NUMLFT: DS 1 RCNT: DS 1 FILECRC:DS 2 LAST: DS 1 CHAR: DS 1 NUMVALS:DS 2 MAX: DS 2 MEMRY: DW PRGEND PRGEND EQU $ END