home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
KAYPRO
/
KBSHW321.LBR
/
KBSHW321.AQM
/
KBSHW321.ASM
Wrap
Assembly Source File
|
2000-06-30
|
40KB
|
1,483 lines
; Kaypro BISHOW v3.21 - buffered bi-directional file scroll utility
;
; KPBISHOW is now completely compatible with standard Wordstar control
; keys and uses the Kaypro arrow keys for +/- scrolling and right and
; left margin control
;
; Ver 3.21, 8 Dec 84, Steve Sanders, Tampa, FL
; - Oops, my mistake with the filename printing twice.
; Removed (sic) code that I had added (it was late folks).
; Call status line in one shot now like it should be.
; Future rev planned to display current memory page number
; and allow going directly to any given page number with
; a CTRL-G nn command. Also go all the way to the back
; of the file.
;
; Ver 3.20, 8 Dec 84, Steve Sanders, Tampa, FL
; - Added the name of file being displayed on 25th line
;
; Ver 3.10, 5 Dec 84, Steve Sanders, Tampa, Fl
; - Added 25th line display of program name, vers #, and
; "enter ? for help menu". Stripped out all non-Kaypro
; equates and short version code.
;
; Ver 3.00kp, 2 Dec 84, Steve Sanders, Tampa, Fl
; - This version is for video-able Kaypros only
; Made command structure the same as Wordstar for scrolling
; forward and backward and also for advancing one line forward
; or backward. Text scroll is completely controlled by the
; Kaypro cursor keys now - up, down, left, and right.
; Changed help menu accordingly, added commands to menu that
; were always in the old code but not documented. Removed the
; GRAF toggles as there are no line drawing routines for the
; Kaypro used and other graphics don't need the GRAF byte toggled.
;
; Ver 2.09KP, 25 Sep 84, Jim Gronek, Phoenix, Arizona
; - Added equates for Kaypro 2/4/10, reverse video codes on help
; command (?), modified exit routines to re-enable cursor
; even if filename not specified to BISHOW, added automatic
; toggle for GRAF byte with ZCPR2/3 on K10's
;
; Ver 2.09, 7 Jan 84, Frans van Duinen, Toronto, Ont
; - Modified USQ routines for higher speed (+10%) and
; less memory usage.
; - made USQ code optional through conditional assembly
; - fixed a bug introduced with 2.08 and SHORT=TRUE
; (resulted from ASM's inability to nest IF/ENDIF)
; - fixed a bug that reset FCBEX after open, whenever
; sector 0 was read, (this resulted in BDOS assuming that
; the current extent, whose allocation group nos were still
; in the FCB, was the correct one.
; - Changed exit to clear screen only on Q or ^C exit,
; to leave any messages visible
; - Made wait after clear screen a cond assembly option
;
; Ver 2.08, 2 Jan 84, Frans van Duinen, Toronto, Ont
; - added squeezed file capability
; - added sidewise scrolling on ^I, ^L, steps of 8
; - Osborne support for cursor keys, clr scr & scr size
; - Changed FILBAK rtn to recognize top of file
; - Set up flag to avoid unnecessary re-reading of
; top of file
;
; The unsqueeze code was lifted from the USQ base code
; by Dave Rand (Edmonton, Alberta) as adapted for LTYPE1
; by S.Kluger (El Paso,Texas)
; The code was lifted to allow continued use of ASM.COM
;
; ** Original program code written by Phil Cary 23 Aug 82
;
; BISHOW is a buffered, bidirectional version of SHOW.ASM
; which first appeared in Interface Age, November, 1981. That
; program could only scroll forward in a file, and read
; sectors from disk one at a time as they were sent to the
; console. I used SHOW frequently to take a quick look at a
; file without loading a big text editor, and to examine
; another file with the RUN command while in Wordstar. TYPE
; does not work since it is not a file that Wordstar can load
; and run.
;
; It was annoying when I went past the point I was looking for
; in a file with SHOW, and could not go backwards. Thus, this
; bidirectional version which uses random access reads. In
; addition, buffering was added so that the number of disk
; reads would be reduced, and moving back and forth in a
; moderate sized file would be speeded up. There is a trade
; off between the size of the buffer and the length of time it
; takes to refill the buffer which should be set to the user's
; preference.
;
; There are several customizing items in this program. One is
; the equate "maxsec" which sets the buffer size. Another is
; the string in the subroutine "clrscr" just after the org
; statement. This should be changed to erase the screen and
; home the cursor for the user's terminal. The program, as
; written, requires a terminal with an erase screen and home
; cursor function. Some terminals do not allow the 80th
; column to be filled without going to the next line. For
; this reason, the screen width ("maxchr") initially is set to
; 79. The screen sizes can be changed using the "S" (screen)
; command. The parameters that can be changed are the maximum
; column displayed ("maxchr"), the minimum column displayed
; (allowing you to "window" the output), and the number of
; lines ("scroln"). A zero for the maximum column displayed
; will give and unlimited screen width. The maximum column
; displayed and the number of lines can be set when calling
; BISHOW, e.g., "BISHOW file.nam 79 24" will give 79 columns
; and 24 lines, and "BISHOW file.nam 79" will give 79 columns
; with the default number of lines. The last customizing item
; is the "short" equate. If this is chosen, the multiplicity
; of command forms is not allowed (see the beginning to change
; the commands used), and certain messages are shortened.
; This will allow BISHOW to fit into a 1K area. If "short" is
; false, the program is slightly over 1K. Finally, direct I/O
; to the console is used to avoid echoing the commands to the
; console as the CP/M write console function does.
;
; Just a small contribution to the public domain software as
; partial payment for the many fine and educational programs
; the system has given me. Phil Cary.
;.........
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
; this code is now for Kaypro only -
;
KAYPRO EQU TRUE ;assemble for Kaypro 2/4/10
;
SQUEEZE EQU TRUE ;Generate code to handle squeezed files
NOWAIT EQU TRUE ;Do not wait after clear screen
;
; Operational equates
;
MAXSEC EQU 32 ;number of sectors in buffer
SIGNAT EQU 0FF76H ;Signature for SQ files
DLE EQU 090H ;Char flag for run compression (SQ)
;
;
IF KAYPRO
SCROLN EQU 24 ;number of lines per scroll
MAXCHR EQU 79 ;number of characters per line
ARWLFT EQU 08H ;Cursor left key (backspace)
ARWUP EQU 0BH ;Cursor up key (vert tab)
arwdwn equ 0ah ;cursor down key (linefeed)
ARWRT EQU 0CH ;Cursor right key (formfeed)
ENDIF
;
;
BASE EQU 0 ;standard zero base CP/M
;
; BDOS functions
;
CONOUT EQU 2 ;console write
OPEN EQU 15 ;open file
CLOSE EQU 16 ;close file
READR EQU 33 ;read file random access
STDMA EQU 26 ;set dma address
;
; Page zero equates
;
WBOOT EQU BASE ;warm boot entry point
BDOS EQU WBOOT+5 ;BDOS entry point
FCB EQU WBOOT+5CH ;default fcb drive number
CMDTAIL EQU WBOOT+80H ;location of command tail
FCBFN EQU FCB+1 ;start of filename
FCBFT EQU FCB+9 ;start of filetype
FCBEX EQU FCB+12 ;current extent number
FCBCRR EQU FCB+33 ;current record number, random access
TPA EQU WBOOT+100H ;transient program area
;
; ASCII equates
;
ENDMSG EQU 0 ;null
BELL EQU 7 ;bell
BS EQU 8 ;Backspace
TAB EQU 9 ;tab
LF EQU 0AH ;line feed
CR EQU 0DH ;carriage return
EOF EQU 1AH ;end of file
ESC EQU 1BH ;escape
SPACE EQU 20H ;space
;
;
ORG TPA
;
JMP START ;skip over next subroutine
;
CLRSCR: CALL CDISP ;command to home cursor and clear to
DB 1EH,17H,ENDMSG ;end of screen for Kaypro 2/4/10
;
IF NOWAIT
;
WAIT: MVI B,0 ;waste time (may or may not be necessary)
;
WAIT1: XTHL ;good time gobbeler!
XTHL
DCR B
JNZ WAIT1
RET ;return from clrscr
;
ENDIF
;
HELP2: ; very fancy graphical help menu for the Kaypro
CALL CDISP
DB cr,lf
DB ESC,'B0'
db ' KPBISHOW v 3.21 Available Commands (same as Wordstar) '
db ' ',cr,lf,' ',esc,'B1'
db ' ^C,Space bar,F, or C/R=forward a page ^R or B=back 1 page '
DB esc,'C1',' ',cr,lf,' ',esc,'B1'
DB ' ^Z,+,arrow-down=forward 1 line ^W,-,arrow-up=back 1 line '
db esc,'C1',' ',cr,lf,' ',esc,'B1'
db ' ^L or arrow-right=8 cols right ^H or arrow-left=8 cols left '
db esc,'C1',' ',cr,lf,' ',esc,'B1'
db ' ^S or S=set the screen parameters Q or X=exits program '
DB ESC,'C1',' ',cr,lf,' ',esc,'B1'
db ' Any other keys pressed will display this help menu '
db esc,'C1',' ',cr,lf
db ' Steven L. Sanders 08 Dec 84 '
db ' '
DB esc,'C0',CR,LF,ENDMSG
JMP GETCMD
;
STATUS: ; status line display for the Kaypro
CALL CDISP
DB ESC,'C7',1AH ;disable status line and clear screen
DB ESC,'B6' ;save cursor position
DB ESC,'B7' ;enable status line
DB ESC,'=8 ' ;position cursor to 25,0
DB ESC,'B0' ;inverse video mode
DB ESC,'B1' ;dim mode
DB ' *KPBISHOW* '
DB ESC,'C1' ;dim off
DB ' Viewing file:'
DB endmsg
; print filename routine
;
lxi h,cmdtail ;get filename from command tail
mov b,m ;get number of chrs
inx h ;point at first chr
inr b
prtfn1: mov a,m ;get the chr
call co ;output it
inx h ;move pointer
dcr b ;decrement the b reg
jnz prtfn1 ;if not 0 then loop till done
;
call cdisp ;now finish rest of status line
db ' '
db esc,'B1' ;dim mode
db esc,'B2' ;blink on
db ' ? for help '
db esc,'C2' ;blink off
db ' S. Sanders 12/08/84 '
db esc,'C1' ;dim off
DB ESC,'C0' ;inverse video off
DB ESC,'C6' ;recall cursor position
DB ENDMSG
ret
;
; start of program (finally)
;
START: LXI H,0 ;get ccp's stack
DAD SP
SHLD STACK ;save old stack for later
LXI SP,STACK ;set new stack
LXI H,CMDTAIL ;point to command tail
MOV B,M ;get number of char in tail
INX H ;point to first character
INR B
;
EATSP: MOV A,M ;get character if there is one
INX H
DCR B ;b=number of characters left
JZ OPENF ;no more characters
CPI SPACE ;ignore spaces
JZ EATSP
;
FILNAM: MOV A,M ;get characters in file name
INX H
DCR B ;b=number of characters left
JZ OPENF ;only file name in tail
CPI SPACE ;wait for next space
JNZ FILNAM
LXI D,CHRMAX ;point to chr/line
CALL GETNBR ;get number of characters/line
JC HELP ;invalid number
LXI D,LINMAX ;point to number of lines
CNZ GETNBR ;call only if characters still in
;__command tail
JC HELP ;invalid number
;
OPENF: CALL OPNFIL ;open file in default fcb
;
CALL STATUS ;display status line if file open ok
;
OPENF1:
IF SQUEEZE
;
CALL CHKSQ ;Check for squeezed, init if
;
ENDIF
;
WRTFWD: XRA A ;get a 0
STA LINCNT ;store in line count
STA CHRCNT ;store in character count
; Do not reset the current extent!!!
; BDOS will switch extents only if the no
; specified ( <FCBEX> ) does NOT agree with
; the wanted no <FCBCRR>.
STA FCBCRR ;zero current record
STA FCBCRR+1 ;__both bytes
STA FCBCRR+2 ;__and the overflow
CALL CLRSCR ;erase the screen
;
WRTFW0: CALL FILBUF ;fill the disk buffer
WRTFW3:
LXI H,DSKBUF ;point to beginning of buffer
;
WRTFW1:
MOV A,M ;get a character
CPI EOF ;see if eof
JZ GETCMD ;yes, wait for command
INX H ;bump pointer
ANI 7FH ;strip high bit
CPI 'L'-40H ;filter form-feeds
JZ FILTER ;__commonly found in .PRN files
CALL CO1 ;put it on console
CPI CR ;see if end of line
JZ FWDCNT ;yes, adjust line count
;
WRTFW2: LXI D,ENDBUF ;get end of buffer address
CALL cmphlde ;Is HL> gt DE> (end of buff)
; ; Note test is LT now, not NE (v1.81)
JNC WRTFW0 ;refill buffer and start over
JMP WRTFW1 ;else, continue with next character
;
HELP: CALL CDISP
DB 1ah,ESC,'B0'
DB ' Kaypro BISHOW vers 3.21 '
DB ESC,'C0',CR,LF,LF
DB 'Usage: BISHOW d:filename.typ [cols [lines]]',CR,LF,cr,lf
DB 'Specify entire filename.typ - no wildcards allowed',cr,lf,lf
DB 'Columns default to 79',cr,lf
DB 'Lines per screen to 24',cr,lf
DB ENDMSG
JMP EXIT1
;
FILTER: PUSH PSW ;save status
MVI A,'^' ;print '^' in front
CALL CO1 ;__of control character
POP PSW ;restore status
ADI 40H ;mask into displayable char
CALL CO1 ;display filtered control char
;
FWDCNT: LDA LINCNT ;get number of lines displayed
INR A ;bump it
STA LINCNT ;__and store it
MOV D,A ;save lincnt
LDA LINMAX ;get max number of line
CMP D ;compare with line count
JNZ WRTFW2 ;if not there, continue, else get command
XRA A ;zero the
STA LINCNT ;__line count
;
GETCMD: PUSH H
PUSH D
PUSH B
;
IF KAYPRO
CALL CDISP
DB ESC,'C4',ENDMSG ;disable cursor
ENDIF
;
GETCM1: MVI C,6 ;direct console I/O
MVI E,0FFH ;__set up for input
CALL BDOS
ORA A ;loop till char avail
JZ GETCM1
POP B
POP D
POP H
CPI 'a' ;change command to
JC GETCM2 ;__upper case
CPI 'z'+1
JNC GETCM2
XRI 20H ;is lower case, make upper case
;
GETCM2: ; get the command from keyboard
;
; go to top of the file?
;
CPI '1' ; 1 means goto 1st line
JZ WRTTOP ;Test if top in buffer
;
; help?
;
CPI '?' ;help request
JZ HELP2
;
; forward a page ( Space bar, F, ^C, or C/R )
;
CPI ' ' ;more use space
JZ WRTFW1
CPI 'F' ;scroll forward?
JZ WRTFW1 ;br if yes
CPI 'C'-40H ;wordstar uses ^C
JZ WRTFW1
cpi cr ;also c/r goes forward a page
jz wrtfw1
;
; back a page ( B or ^R )
;
CPI 'B' ;scroll backward?
JZ WRTBAK
CPI 'R'-40H ;wordstar uses ^R
JZ WRTBAK
;
; next line forward ( +, ^Z, or Arrow-down key )
;
cpi '+' ;1 for 1 more line?
jz wrtnxt
cpi 'Z'-40H ;wordstar uses ^Z
JZ WRTNXT
cpi arwdwn ;cursor down?
jz wrtnxt
;
; back a line ( -, ^W, or Arrow-up key )
;
cpi '-' ;minus key?
jz wrtprv
CPI 'W'-40H ;scroll prev line?
JZ WRTPRV
CPI ARWUP ;Cursor up?
JZ WRTPRV ;yes, back-up a line
;
;
; exit program, clear screen ( Q or X )
;
CPI 'Q' ;Q for quit?
JZ EXITCL
cpi 'X' ;was it an X
jz exitcl
;
; set new screen paramaters ( S or ^S )
;
CPI 'S' ;set screen parameters
JZ SETSCR
cpi 'S'-40H
jz setscr
;
; adjust margins ( Arrow-left, Arrow-right, or M )
;
CPI ARWLFT ;Cursor left?
JZ ADJMM
CPI ARWRT ;Cursor right?
JZ ADJMM
cpi 'M' ; m for margins?
jz adjmm
;
JMP HELP2 ;if none of these, display built-in help menu
;
;...........
; Go to top of file
WRTTOP:
LDA TOPBUF ;Get top in buffer flag
ORA A
JNZ WRTFWD ;No - the hard way
CALL CLRSCR ;erase the screen
WRTTO1:
XRA A
STA LINCNT ;Clear lines put so far
JMP WRTFW3 ;Buffer contains top sectors
;
; Write one more line
WRTNXT: LDA LINMAX
DCR A ;fool wrtfw1 to only write one line
STA LINCNT
JMP WRTFW1
; Back up one line
WRTPRV: LDA LINMAX ;back up one screen + 1 line
INR A
JMP WRTBK0
; Back up full screen
WRTBAK: LDA LINMAX ;get screen line count
ADD A ;__multiply by 2
;
WRTBK0: INR A ;__and add 1
STA LINCNT ;__to backup to previous page
CALL CLRSCR ;clear the screen
;
WRTBK1: LXI D,DSKBUF ;get address of start of buffer start
CALL cmphlde ;Is HL> LT DE> (start of buff)
; ; Note test is LT now, not NE (v1.81)
JC FILBAK ;Go refill buffer
;
WRTBK2: MOV A,M ;get a character
ANI 7FH ;strip high bit
DCX H ;decrement buffer
CPI CR ;see if end of line
JZ BAKCNT ;__or form-feed
CPI 'L'-40H ;__and adjust line count if so
JNZ WRTBK1 ;else, loop if not
;
BAKCNT: LDA LINCNT ;else, get number of lines to move back
DCR A ;__and decrement it
STA LINCNT ;__store it
JNZ WRTBK1 ;__and loop if not there
INX H ;else bump pointer
INX H ;__to account for dcx
JMP WRTFW1 ;and go write a screen
;
FILBAK:
; Test for top of file
LDA TOPBUF ;Get top in buffer flag
ORA A
JZ WRTTO1 ;Yes - start of file in buffer
; Start of file not in buffer, step back
LHLD SECCNT ;Get no of sectors last read
LXI D,MAXSEC ;get the buffer size
DAD D ;add them
XCHG ;__and put them in DE
LDA FCBCRR ;subtract low order byte
SUB E ;__from current record count
STA FCBCRR ;__and store in current record count
LDA FCBCRR+1 ;same with high order byte
SBB D ;__but with borrow
JM WRTFWD ;if beyond beginning of file, start over
STA FCBCRR+1 ;else, store high order byte
CALL FILBUF ;fill the buffer
LXI H,ENDBUF ;__and point to end of buffer
CALL CLRSCR ;clear the screen
JMP WRTBK2 ;continue moving back in file
;
; ;Fill buffer from spec'd sector
FILBUF:
MVI B,MAXSEC ;number of sectors to resd
FILB1S:
LXI D,DSKBUF ;load start of disk buffer
LXI H,0 ;zero out the
SHLD SECCNT ;__number of sectors in buffer
LHLD FCBCRR ;Is this top of file?
MOV A,H
ORA L
STA TOPBUF ;Set top of file in buffer flag
; ; Z - top, NZ - not top
IF SQUEEZE
LDA SQFLG ;Is this a squeezed file
ORA A
JNZ FILSQ ;Yes -
ENDIF
;
FILBU1: PUSH H ;save all
PUSH D ;__registers from
PUSH B ;__BDOS clobber
MVI C,STDMA ;set dma to
CALL BDOS ;__disk buffer
LXI D,FCB ;set up to read
MVI C,READR ;__a record
CALL BDOS ;do it
ORA A ;read OK?
LHLD FCBCRR ;get current record number
INX H ;__bump it
SHLD FCBCRR ;__and save it
LHLD SECCNT ;get sectors in buffer
INX H ;bump it
SHLD SECCNT ;store it
POP B
POP D
POP H
JNZ RDERR ;no, last sector read
DCR B ;decrement it
RZ ;if done return
LXI H,128 ;else, add 128 to
DAD D ;__dma address
XCHG ;put it in de
JMP FILBU1 ;read another sector
;
IF SQUEEZE
;
; Fill buffer from squeezed file
; This rtn handles mapping from unsq sector #
; to sector, byte & bit in sq stream
; on input FCBCRR contains wanted sector no,
; ( no allowance made for sectors # over 65535)
; <B> contains no of sectors wanted
; DE> buffer where sectors wanted,
; ignored in this version, always full DSKBUF
FILSQ:
LHLD FCBCRR ;Get # for 1st sector wanted
XCHG
PUSH D ;Save to restore after unsq
LHLD NXTSEC ; & 1st sector after buffered ones
CALL cmphlde ;Consecutive?
JZ USQNXT ;Yes - fine
JNC USQBAK ;No - lower
; ;Next sect after latest but not consec
CALL CDISP
DB CR,LF,'Program failure, non-contiguous sectors requested'
DB CR,LF,'from unsqueeze rtn',CR,LF,0
JMP EXIT ;Should never happen
USQBAK: ;Going backward
MOV A,D ;All the way?
ORA E
JNZ USQNO1 ;No - MUST be prev!!!
LXI H,SQMAP+2+8 ;Yes - reset SQMAP index to #3
SHLD SQMAP
USQNO1:
LHLD SQMAP ;Get index into mapping table
LXI D,-8 ;Step back from next, past current to prev
DAD D
SHLD SQMAP ; & save updated index for next
MOV E,M ;Get SQ sector no
INX H
MOV D,M
INX H
MOV C,M ;Get byte offset
INX H
MOV A,M ; & bit offset
STA bitlft
XRA A
STA rcnt ;No runs in progress
; (assumption)
STA SQBYT+1 ;Set offset 1st data byte
MOV A,C
STA SQBYT ;For now offset within sector only
LHLD SQBSC1 ;Get no of first SQ sector now in buffer
XCHG ;<HL> wanted 1st sector, <DE> actual 1st
CALL cmphlde ;Is 1st buffer sector low/equal 1st data sect?
JNC USQ1OK ;Yes - first wanted sector SQ in buffer
; Max header 1035 bytes + file name)
; Force reload of SQ buffer
SHLD NXTSQS ;No - 1st data sector b/4 1st buffer sect
; (note is probab not sector 0
; because of header, eg decoding tree)
MVI A,1 ;Set rewind with I/O
STA SQREWD ;Set rewind flag
; SQBYT contains offset of 1st data byte
XRA A
STA SQEOF ;Reset end of file on SQ
; Leave current extent alone. This is how
; BDOS knows how to switch extents. It checks
; if the current extent no agrees with
; the wanted record.
STA FCBCRR+2 ; & count overflow, should not be necessary
MOV D,A
JMP USQNX1 ;Go adj buffer pointer
; (NOP since <DE>=0
; ;SQ text still in buffer
USQ1OK:
; <DE> # of 1st sector in SQ buf
; <HL> # of wanted SQ sector
; (Max 100H SQ sectors in buffer)
MOV A,L
SUB E
RAR ;Convert to pages (100H)
; Know Cy=0 in
; leaves Cy if odd no of sects
MOV D,A
MVI A,0 ;Do not disturb Cy
RAR ;Pu carry (now 80H or 00H)
USQNX1:
MOV E,A
LHLD SQBYT ;Get offset of 1st data byte in wanted sect
DAD D ; --> offset in buffer
LXI D,SQBUF
DAD D ;Convert to absolute addr
SHLD inbufs ;& set as next byte to unsqueeze
;
USQNXT: ;Next sector consecutive
LHLD NXTSQS ;Get no of next SQ sector
; (in case read reqd)
SHLD FCBCRR
; Build mapping table entry
LHLD inbufs ;Calc offset in buffer
LXI D,-SQBUF
DAD D
MOV C,L ;Keep offset within sector
LDA bitlft ;Get bit offset
MOV B,A
ORA A ;On byte boundary?
MOV A,C
JNZ NOTBBY ;No -
INR A ;Yes - no adj reqd
NOTBBY:
ANI 7FH ;Ensure sector relative
DAD H ;Convert to sector no
ORA A ;Is next byte at start of sect?
JNZ SECTOK
DCR H ;Yes - step back one sector
SECTOK:
DCR A
ANI 7FH ;& adj byte index
MOV E,H
MVI D,0
LHLD SQBSC1 ;# of 1st sector in buffer
DAD D
XCHG ;<D> absolute SQ sector no
LHLD SQMAP ;Get index
MOV M,E ;Save abs SQ sector no
INX H
MOV M,D
INX H
MOV M,A ;Save sector relative byte offset
INX H
MOV M,B ;Save bitlft
INX H
SHLD SQMAP ;Save new index
CALL CDISP ;Show msg where is
DB '>>> Unsqueezing text <<<',ENDMSG
; Corrupts display if aft CR but b/4 LF
CALL filusq ;Fill unsq buffer
; returns NZ on EOF
; SQEOF set as well then
CALL CDISP ;Remove msg just displayed,
; assumes BS across start of line if reqd
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB ' '
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,0
LHLD FCBCRR ;Get no of next SQ sector
SHLD NXTSQS
LHLD nxtadr ;Calc # of unsq sectors in buf
LXI D,-DSKBUF ;(as neg no)
DAD D ;Calc length
DAD H ; & convert to sectors in <H>
MOV L,H
MVI H,0
SHLD SECCNT ;Save # of sectors in DSKBUF
POP D ;Get FCBCRR as passed by calling rtn
DAD D ; & calc new one
SHLD FCBCRR
SHLD NXTSEC
RET
;
ENDIF
;
;
;We only get here if end of file
;
RDERR: MVI A,EOF ;get bogus eof
STAX D ;save at buffer end in case no eof in file
XRA A ;get a zero to direct to start of buffer
RET ;__on ret
;
OPNFIL: LDA FCBFN ;point to first letter of filename
CPI ' ' ;anything there?
JZ HELP ;no, give help message
XRA A ;get a 0
STA FCBEX ;zero current extent
; MUST open file on extent zero
LXI D,FCB ;file name in default fcb
MVI C,OPEN ;set up to open
CALL BDOS ;do it
INR A ;open OK?
RNZ ;yes
CALL CDISP ;else, give error msg and quit
DB cr,lf,'File not found - check the DIR',7,cr,lf,ENDMSG
JMP EXIT1 ;leave msg on screen on exit
;
GETNBR: MOV A,M ;get first digit
INX H
DCR B ;b=number of characters left in buffer
RZ ;no digit
CPI SPACE
JZ GETNBR ;wait until next non-space
PUSH D ;save location to save number
MVI D,0 ;initialize number
;
GNUM1: SUI 30H ;change ASCII to number
JC INVNUM ;not a number
CPI 10
CMC
JC INVNUM ;not a number
PUSH PSW ;save number
MOV A,D ;multiply old number by 10
ADD A ;*2
ADD A ;*4
ADD A ;*8
ADD D ;*9
ADD D ;*10
MOV D,A
POP PSW ;restore new digit
ADD D
MOV D,A
MOV A,M ;get next digit
INX H
DCR B
JZ ENDNUM ;end of number
CPI SPACE
JNZ GNUM1
;
ENDNUM: MOV A,D ;save number
DCR A ;correct number for co routines
XCHG ;set to restore save location
POP H ;restore save location
MOV M,A ;save digit
XCHG ;put buffer location where it belongs
MOV A,B ;see if any characters left in buffer
ORA A ;zero if no characters in buffer
RET
;
INVNUM: POP D ;correct stack
RET
;
ASCIIN: MVI B,100 ;divide by 100, then change
CALL DIVIDE ;__digit to ASCII and store at hl
MVI B,10 ;divide by 10, then change
CALL DIVIDE ;__digit to ASCII and store at hl+1
MVI B,30H ;change ones place number
ADD B ;__to ASCII and store at hl+2
MOV M,A
;
CDISP: XTHL ;exchange top of stack and HL
;
CDIS1: MOV A,M ;HL now pointing to db message
ORA A ;see if 0 at end of message
INX H
JZ CDIS2 ;yes, restore stack and return
CALL CO ;no, print the character
JMP CDIS1 ;__and loop
;
CDIS2: XTHL ;get return address on top of stack
RET ;__and return
;
CO: PUSH B ;Save the registers
PUSH D ;__from bdos
PUSH H ;__clobber
CO2: PUSH PSW
CO4: MOV E,A ;set up character
MVI C,CONOUT ;__to send to console
CALL BDOS ;do it
CO3: POP PSW
CO5: POP H ;restore
POP D ;__the registers
POP B
RET
;
CO1: PUSH B ;Save the registers
PUSH D
PUSH H
PUSH PSW
LXI H,CHRCNT ;Get address of character count
CPI CR ;see if end of line
JZ ENDLIN ;update line information
CPI LF ;ignore linefeed
JZ CO4
LDA CHRMAX ;get maximum characters per line
CMP M ;see if too many char
JC CO3 ;don't print character
POP PSW ;__and print character
CPI TAB ;fix chrcnt for tabs
JZ TABFIX
INR M ;increment character count
MOV E,A
LDA CHRMIN ;see if up to minimum display yet
CMP M
MOV A,E ;restore character
JNC CO5 ;do not display character
JMP CO2 ;finally, display character
;
ENDLIN: MVI M,0 ;reset character count
JMP CO4 ;print cr
;
TABFIX: MVI A,08H ;fix chrcnt for tabs
ADD M ;increment to next 8-count
ANI 0F8H ;make into multiple of 8
;
TAB2: SUB M ;get number of space to go
MOV B,A
;
TAB1: MVI A,SPACE ;expand tab
CALL CO1
DCR B
JNZ TAB1 ;still more spaces
JMP CO5 ;exit routine
;
SETSCR: PUSH H
PUSH D
PUSH B
;
GETMAX: LDA CHRMAX ;get maximum number of characters
INR A
LXI H,HUNS
CALL ASCIIN ;put ASCII number in message
;
DB CR,LF,'Maximum Column: '
;
HUNS: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ;read input from console
LXI D,CHRMAX ;set new chrmax in memory
CALL GETNBR
JC GETMAX ;if error, repeat last message
;
GETMIN: LDA CHRMIN ;get minimum character display
INR A
LXI H,HUN
CALL ASCIIN ;put ASCII number in message
;
DB LF,'Minimum Column: '
;
HUN: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ;read input from console
LXI D,CHRMIN ;set new chrmax in memory
CALL GETNBR
JC GETMIN ;if error, repeat last message
;
GETLIN: LDA LINMAX ;get number of lines per display
LXI H,HUND
CALL ASCIIN ;put ASCII number in message
DB LF,'Lines Displayed: '
;
HUND: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ;read input from console
LXI D,LINMAX ;set new chrmax in memory
CALL GETNBR
JC GETLIN ;if error, repeat last message
POP B
POP D
POP H
;
WRTSAM: LDA LINMAX ;write the same screen
JMP WRTBK0
;
;
GETINP: MVI A,5 ;get set to read new maximum column
STA CMDTAIL
MVI C,0AH
LXI D,CMDTAIL
CALL BDOS ;get maximum column
LXI H,CMDTAIL+1 ;now, change to ASCII
MOV B,M
INX H
INR B
RET ;return with input in buffer
;
; Adjust char min/max on cursor left/rt
ADJMM:
PUSH H
CPI ARWLFT ;Move left (decrease)?
; set flag
LDA CHRMAX ;What is last char on line t/b displ
MOV H,A
LDA CHRMIN ; & 1st char to display
MVI L,8 ;Scroll by 8
JZ ADJMMD ;Yes - adjust down
ADD L ;No - increase min, no limit
PUSH PSW
MOV A,L
ADD H ; & max
JMP ADJMMS
ADJMMD:
SUB L ;Display more to the left
PUSH PSW
MOV A,H
SUB L
ADJMMS:
MOV H,A ;<H> max
POP PSW ;<A> min
CMP H ;Wrap, (max< min)
JNC ADJMMX ;Yes - leave unchanged
STA CHRMIN
MOV A,H
STA CHRMAX
ADJMMX:
POP H
JMP WRTSAM ;Go write same screen
;
;
DIVIDE: MVI C,'0'-1 ;extract dividend of a div c
;
DIV1: INR C ;__and store in location pointed
SUB B ;__to by hl
JNC DIV1
ADD B
MOV M,C ;save ASCII digit
INX H ;bump pointer to next location
RET
;
EXITCL:
; Clear screen only on reg exit
CALL CLRSCR ;clear the screen
;
EXIT: MVI E,0FFH ;clear console of characters
MVI C,6 ;direct console I/O
CALL BDOS ;__get any waiting characters
;
IF KAYPRO
CALL CDISP
DB ESC,'C7' ;disable status line
DB ESC,'B4',ENDMSG ;enable cursor display
CALL CLRSCR ;now clear whole screen
ENDIF
;
LXI D,FCB ;close file
MVI C,CLOSE ;--in case this is MP/M
CALL BDOS
;
EXIT1:
IF KAYPRO
CALL CDISP ;re-enable cursor even if no file
DB ESC,'B4',ENDMSG ;specified to BISHOW
ENDIF
;
LHLD STACK ;get old stack
SPHL
RET ;return to CCP
;
;
; Compare <HL> to <DE>
; Z - equal; C - <HL> less than <DE>
cmphlde:
mov a,h
cmp d
rnz
mov a,l
cmp e
ret
;
IF SQUEEZE
*******************************************************
* USQ support code *
* 10/12/83 by Dave Rand *
*******************************************************
;
; Check for SQ file, init tree if so
CHKSQ:
; Initialize
xra a
mov l,a
mov h,l ;clear <hl>
STA SQFLG ;Make sure not set as squeezed yet
sta SQEOF ; end of file on SQ
sta SQREWD ;Clear "rewinding" SQ file
sta bitlft ;force init char read
sta rcnt ;and zero repeats
shld FCBCRR ;Clear next record
sta FCBCRR+2 ; and overflow
shld numvals ;Clear # nodes
;
lxi h,SQBUF ;Set to input (squeezed) buffer
shld inbufs
shld inbufu
lxi d,128
dad d
shld SQBUFE ;Force exit on full buff aft 1 sect
; causes the SQ buffer to contain
; sectors 1+ only (not zero),
; normally fine since sector 0 contains only
; header info. Sector 0 will be reread
; if contains data and needed
call usqsig ;Read & val signature word
RNZ ;Not SQ
STA SQFLG ;Yes - set flag
lhld 0006 ;Get top of memory
lxi d,sqbuf+100H*128 ;Limit buffer to max 100H
call cmphlde ; sectors (FILBUF uses 8 bit count <B>)
JC toplow ;use top
xchg ;use limit
toplow:
shld SQBUFE ;& store as full address
call namlp ;Skip past name
call usqtbl ;Validate & load decoding tree
jz oak ;tree ok
call CDISP
db cr,lf,'Invalid decode tree size',cr,lf,0
jmp EXIT
oak:
lxi h,SQMAP+2 ;Point to 1st entry
shld SQMAP ;Set to 1at entry in SQ mapper
ret
; Read and validate signature word
usqsig:
call getw ;Read 1st word in file
lxi d,signat ;Get expected value
call cmphlde
mvi a,1 ;Set code in case of error
ret ;Exit with Z/NZ
;
; Read & save checksum
rdchks:
call getw ;get cksum, and store
shld filchks
ret
; Read & skip name
namlp: call getc ;Loop to skip name
jnz erext ;I/O error or unexpected EOF
ora a
jnz namlp ;Not yet end of name
ret
;
; Load decoding tree
; This version uses 1 byte abslute node indices
; (1-ffH) and is thus limited to 255 nodes and 255
; characters represented in the squeezed file.
; (All different characters present in the original
; file as well as any added through run encoding.
; Runs of 3 or more consecutive identical characters
; are encoded as char, DLE, count, where count
; is a one byte field 00 - FFH)
;
usqtbl:
call getw ;Get no of nodes
mov a,h
ora l
jz nzexit ;Null tree
shld numvals
mov a,h ;Max 257, 256 char & spec eof
; in this version allow for only 256
; diff codes, every ASCII and non-ASCII
; char would have to be present, or
; run repeat counts 128-255 (every one)
ora a ;H/o byte should be zero
jnz nzexit
lxi d,SQTREE ;Set to decoding tree
nodelp: shld nxtadr ;Save no of nodes
mov a,h
ora l
rz ;Done all nodes
call cvnode ;get node, falg byte in <H>,
; index/char in <L>
push h
call cvnode ;get second child/char
pop b
mov a,b
ral ;Shift flags to 8, 4 posns
ora h ;Combine in 1st child flags
xchg ;HL> SQTREE, <A>,<C>,<E> node
mov m,a ;Store flags in table
inx h
mov m,c
inx h
mov m,e
inx h
xchg ;DE> SQTREE
lhld nxtadr ;Nodes remaining
dcx h
jmp nodelp
; Get encoded node
; Our nodes contain 3 bytes:
; - flag byte,
; - left child index/char
; - right child index/char
; Nodes on input are 4 bytes,
; with each half containing
; an index (1-100h) or character,
; where characters are encoded as
; negative values -(char+1)
; Eof is encoded as -(100h+1)
cvnode:
push d
call getw ;Get word, chld ptr or char
pop d
mov a,h
ora a
rz ;Child index, <H>=0,<L>=index
mov a,l
cma
mov l,a ;convert char to reg form
mov a,h ;get h/o byte again
cma
inr a ;Conv to 1 if char, 2 if EOF
mov h,a
cpi 1 ;Was that reg char?
rz ;Yes - complete
adi 3 ;No convert EOF flag to 0100
mov h,a
ret
; Exit with NZ flag
nzexit:
mvi a,2 ;tree error
ora a ;Set NZ flag
ret
;
;
; Fill output buffer (unsqueezed char)
;
filusq:
lda SQREWD ;Rewinding SQ input?
ora a
jz norewd ;No
; Reload SQ buffer
lhld inbufs
push h ;getrf resets
call getrf ;Yes - reload buffer & get 1st 8 bits
pop h
shld inbufs ;Set to first data byte to use
badj:
mov c,a
lda bitlft ;Get preset 1st wanted bit no
mov c,a
mvi a,8
sub b ; Calc adjmt reqd
badjlp:
dcr a
jz badjfn ; bit adjust finished
mov b,a
mov a,c
rrc
mov c,a
mov a,b
jmp badjlp
badjfn:
sta bitbuf
xra a
sta SQREWD ; & clear rewind flag
norewd:
lxi h,DSKBUF ;reset buffer pointer
xra a
buflp:
shld nxtadr ;Save as next byte in buffer
rnz ;End of file (NZ flag)
; as set by GETNXT rtn below
lxi d,SQTREE ;Get end of input
call cmphlde ;buffer full (de < hl - not full)
jnc full ;buffer is full
call getnxt ;Get next decoded char
;No checksum taken
lhld nxtadr ;Next out buffer posn
mov m,a ;Store char returned, may be EOF char
inx h
jmp buflp
;
full:
xra a ;Ensure Z
ret ;Return on full buffer
;
;
; Get next decoded character
;
getnxt: lda rcnt ;see if in the middle of
ora a ;repeat sequence...
jz norpt
dcr a ;Yes - reduce repeat remaining
sta rcnt
lda last ;Get latest char again
cmp a
ret ;Return with Z for ok
norpt: call decode
rnz ;EOF? <A>=1AH
cpi dle ;Run encoding flag?
jnz norun
; Handle DLE
call decode ;get count
rnz ;EOF? (is really error after DLE)
ora a
jnz run ;Non-zero, real run
mvi a,dle ;dle is encoded as dle,0
cmp a
ret
; ;Run encoding found
run: dcr a ;Allow for char already retnd
dcr a ; & this one
sta rcnt ;Keep count yet to be retd
lda last ;return second time
cmp a
ret
; ;Normal char, no run active
norun: sta last ;This may be the start
cmp a
ret
;
;
; Read bits and decode to char
; note this version uses 3 bytes per node
; not 4.
; The first byte in each node is a flag byte
; .... x... - left node contains EOF marker
; .... .x.. - right node contains EOF marker
; .... ..x. - left node contains char
; .... ...x - right node contains char
;
decode: lxi d,0 ;Set to node zero in table
lda bitbuf ;Get bits from bit buffer
mov c,a
bitlp: lda bitlft ;Any bits remaining?
ora a
jnz nxtbit ;Yes - go use
push d
call getc ;No - replenish bit buffer
jnz badr ;Unexpected eof
pop d
mov c,a
mvi a,8 ;Set as 8 bits inbuffer
nxtbit: dcr a
sta bitlft ;Save no of bit remaining
lxi h,SQTREE ;Set to node 0, left child ptr
dad d
dad d
dad d ;Add in node no (4 bytes/node)
mov b,m ;Get flag byte
inx h ;Step to left child pointer
mov a,c ;Get input bits
rrc ;Shuffle LOW-ORDER bit to Carry
mov c,a
mov a,b ;Get flag byte
jnc getn3 ;Zero input bit,leave at left
inx h ;add 1 to point to right child pointer
add b ;Normalize wanted flags to .... x.x.
getn3:
mov e,m ;Pick up child or char
; <D> should always remain zero
ani 1010B ;Mask unwanted bits
jz bitlp ;Reg child pointer
; Got to char or eof
ani 1000B ;End of file marker?
jnz goteof ;Yes - get out with eof
mov a,c
sta bitbuf ;Save bit buffer
mov a,e ;Get decoded char (neg)
ret
;
; Exit on reg eof
goteof:
mvi a,eof
ora a
ret
;
; ;Get input word (lo/hi, unencoded)
getw: call getc
jnz badr ;Unexpected eof
push psw
call getc
jnz badr ;Unexpected eof
mov h,a
pop psw
mov l,a
ret
;
erext:
badr: call CDISP
db cr,lf,'Unexpected EOF on squeezed file',cr,lf,0
jmp EXIT
;
; Get single (unencoded) char
getc: lhld inbufu
xchg
lhld inbufs
call cmphlde ;End of input buffer?
jz getrf ;Yes
getc1:
mov a,m ;No get next byte
inx h
shld inbufs ;Save addr of next byte
cmp a
ret
;
; Refill input buffer
;
getrf:
lda SQEOF ;Is there anything else?
ora a
jz getok
call CDISP
db cr,lf,'Read past EOF on SQ file',cr,lf,0
jmp EXIT
getok:
lhld SECCNT ;Save sector count (decoded buffer only)
push h
lxi h,SQBUF ;Set input buffer as empty,
shld inbufs ;_and start of buffer
xchg ;DE> buffer, next sector locn
lhld SQBUFE ;End of input buffer
shld inbufu ;Assume no end of file for now
mov a,l
sub e
mov l,a
mov a,h
sbb d ;Calc buffer size
mov h,a
dad h ;Convert to no of sectors
mov b,h ;No of sectors to read
; # sectors limited to 100 max (<B>=0)
lhld FCBCRR ;No of 1st sector to read
shld SQBSC1
call FILBU1 ;Read sector into SQBUF
; <B> no of sectors not read if eof
; HL> 128
; DE> last sector read, or after if eof
lhld FCBCRR ;Get next SQ sector no
shld NXTSQS
mov a,b ;Did we fill buffer?
ora a
jz getrf2 ;yes - no eof
xchg ;Eof, adjust buffer end marker
shld inbufu ;Mark end of buffer used
sta SQEOF ;& flag eof
;
; Input buffer re-filled
getrf2:
pop h
shld SECCNT ;Restore sector count (decoded buffer only)
lhld inbufu ;Get end of buffer
xchg
lhld inbufs ;Get start of buffer
call cmphlde ;Something there?
jc getc1 ;Yes - go for char
jmp erext ;No - read past eof or empty file
;
;end of baseline USQ code
;
otbufe: dw 0 ;End of decoded char buffer
inbufs: dw 0 ;Start of input buffer
inbufu: dw 0 ;End of used part input buffer
SQBUFE: dw 0 ;End of input buffer
;
nxtadr: dw DSKBUF ;Next byte in output buffer
; also used when loading tree
bitlft: ds 1 ;No of bits left in bit buffer
rcnt: ds 1 ;Run count remaining (DLE)
filchks:ds 2 ;Checksum read from file
last: ds 1 ;Last reg char decoded
bitbuf: ds 1 ;Latest 8 bits (encoded) from input file
numvals:ds 2 ;No of nodes in encodng tree
;
ENDIF
;
; Memory allocation
;
SECCNT: DW 0 ;number of sectors read into buffer
LINMAX: DB SCROLN ;number of to write lines on console
CHRMAX: DB MAXCHR-1 ;number of characters to display per line
CHRMIN: DB 0 ;character to start displaying on line
CHRCNT: DS 1 ;character number in line
LINCNT: DS 1 ;line number on write or move back in buffer
TOPBUF: DB 0 ;Top of file is now in buffer
; Z - yes, NZ - no
;
IF SQUEEZE
;
NXTSEC: DW 0 ;Next (unsqueezed) sector not yet in BSKBUF
; set (and used) only by FILSQ
SQFLG: DB 0 ;File is squeezed
SQEOF: DB 0 ;End of file on squeezed file
SQREWD: DB 0 ;Flag the SQ input file is being re-read
; buffer refill rtn (getrf) to set inbufs
; as per offset in SQBYT, and pre-load
; bit buffer. Bit buffer to be adj
; as per Bitlft
SQBYT: DW 0 ;Offset of first data byte in SQ buffer
SQBSC1: DW 0 ;No of 1st sector in SQ buffer
NXTSQS: DW 0 ;No of last sector in SQ buffer
;
ENDIF
;
DS 60 ;stack area
STACK: DS 2 ;old stack saved here
DSKBUF: EQU $ ;disk buffer area above the program
;
ENDBUF EQU DSKBUF+MAXSEC*128
;
IF SQUEEZE
;
SQTREE EQU ENDBUF ;Space for SQ decoding tree
SQMAP EQU SQTREE+257*3
; Space for SQ buffer mapping table
; contains sq sect #, sq byte & bit offset
; for every time DSKBUF was filled
; 1st entry contains index to latest mapping
; triplet
; To handle run compr straddling buffer end,
; should also store rcnt & last
SQBUF EQU SQMAP+100*4 ;(allows for 100 8k buffers)
; Input (squeezed) buffer
; Runs up to top of free mem
ENDIF
;
END TPA