home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
list
/
qlist15.lbr
/
QLIST15.AZM
/
QLIST15.ASM
Wrap
Assembly Source File
|
1987-01-05
|
37KB
|
1,633 lines
;***********************************************************
; 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