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
/
ENTERPRS
/
CPM
/
UTILS
/
A
/
BSHOW32.LZH
/
BISHOW32.ASM
< prev
next >
Wrap
Assembly Source File
|
2000-06-30
|
49KB
|
1,931 lines
;
; title 'BISHOW v3.02 - buffered bidirectional file scroll utility'
;
; Ver 3.02, 3 Nov 85, Rod Clark, Seattle WA
; - added Wordstar cursor pad (^C now = page down).
; - ESC exits, clears screen. Q exits, leaves screen.
; - Wrong keys are ignored. H = brief help. ? = help.
; - SHORT + SQUEEZE + LIBRARY = .COM file < 2k.
; - SHORT, no SQUEEZE, no LIBRARY = .COM file < 1k.
; - SHORT disables setting each margin interactively
; (the command line still sets the right margin and
; the page length), but it does let you scroll back
; and forth horizontally by tab stops within a file.
; The SHORT version gives two sets of cursor keys
; (Wordstar and CR/SP etc), but no help display.
; - BISHOW (no filename) tells whether it works on .LBR
; or squeezed files, or both, or just on plain files.
; - and fixed jumbled multiple-line .LBR directory.
;
; Ver 3.01, 15 Jan 84, Frans van Duinen, Toronto, Ont
; - made unsqueeze message optional
; - added library capability
; - fixed bug in conditional assembly of CLRSCR
;
; 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
;
; Ver 1.07, 1 Aug 83, Ted H. Emigh ...!unc!tucc!emigh
; - added screen width specification
; - added screen definition commands (see notes below)
;
; Ver 1.06, 2 Jul 83, Chuck Forsberg
; - added commands for more, mince, vi familiarity.
; Bad cmd gives help
;
; Ver 1.051, 26 June 83, Dick Mead
; - added "?" for help on commands.
;
; Ver 1.05, 31 May 83, Bruce Ratoff
; - added 'N' (next line) and 'P' (previous line) cmds
; - decreased buffer from 8k to 4k (8k takes too long)
;
; Ver 1.04, 15 May 83, Keith Petersen, W8SDZ
; - fixed bug which caused display past end-of-file
; and added bogus eof in case none at file end
; - added strip of high-order bit in line count routine
; - added exit clear of any left-over keyboard character
;
; Ver 1.03, 11 May 83, Keith Petersen, W8SDZ
; - fixed to allow assembly with ASM.COM
; - fixed screen clear bug when crossing read boundries
; - added strip for high-order bit in character before
; printing (needed for WordStar files)
; - improved stack routines
; - fixed bug in console input routine
; - removed Z80 dependant code (now works on 8080 too)
;
; Ver 1.02, 06 May 83, Lucien Pan, Toronto, Canada
; - fixed some minor bugs
; - returns to ccp w/o warm boot
; - filters form-feeds (useful in .PRN files)
; - scrolls foward/backwards by same number of lines
; - disable/enable cursor during scroll for H-19
;
; Ver 1.01, 30 Mar 83 - added BDOS function 6. W.F.Mcgee
;
; Ver 1.00, 23 Aug 82 Phil Cary, 748 Kenilworth Parkway, Baton
; Rouge, LA 70808
;
; 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.
;
; This bidirectional version 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. 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.
;
;Define version number for help message
;
VERS EQU 3 ;Note current use in DB constrains VERS &
REVS EQU 02 ; REVS to be one and two digits respectively
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
; ASCII equates
;
ENDMSG EQU 0 ;null
BS EQU 8 ;Backspace
TAB EQU 9 ;tab
LF EQU 0AH ;line feed
FEED EQU 0CH ;form feed
CR EQU 0DH ;carriage return
EOF EQU 1AH ;end of file
ESC EQU 1BH ;escape
SPACE EQU 20H ;space
;
;------------------------------------------------------------------------------
; @@@@@
; ///////////////////// User settings ///////////////////////
;
HEATH EQU FALSE ;assemble for H-19 terminal
OSBORNE EQU FALSE ;assemble for 52-column screen
;
SHORT EQU TRUE ;no SQ or LBR = 1k / with SQ and LBR = 2k
LONG EQU NOT SHORT ;duplicate keys, includes help, margin set
SQUEEZE EQU TRUE ;Optional, to handle squeezed files
LIBRARY EQU TRUE ;Optional, to handle .LBR files
;
NOWAIT EQU TRUE ;true = no wait after screen clear
SILENT EQU TRUE ;true = no superfluous "unsqueezing text" msg
;
IF NOT OSBORNE
SCROLN EQU 24 ;number of lines per scroll
MAXCHR EQU 79 ;number of characters per line
ENDIF
;
IF OSBORNE
SCROLN EQU 24 ;number of lines per scroll
MAXCHR EQU 51 ;number of characters per line
ENDIF
;
; ///////// change the help tables if you change keys //////////
;
; command keys - short version
;
LINE EQU 'X'-40H
LINE2 EQU CR
PAGE EQU 'C'-40H
PAGE2 EQU SPACE
LINEUP EQU 'E'-40H
LINEUP2 EQU 'P'
PAGEUP EQU 'R'-40H
PAGEUP2 EQU 'B'
ARWLFT EQU 'S'-40H
ARWLFT2 EQU 'H'-40H
ARWRT EQU 'D'-40H
ARWRT2 EQU TAB
TOP EQU 'T'
TOP2 EQU '1'
QUIT EQU 'Q'
QUITCL EQU ESC
;
; additional command keys - long version
;
IF LONG
LINE3 EQU LF
LINE4 EQU '+'
LINE5 EQU 'Z'-40H
LINE6 EQU 'N'
PAGE3 EQU 'F'
PAGE4 EQU 'F'-40H
PAGE5 EQU 'V'-40H
LINEUP3 EQU 'K'-40H
LINEUP4 EQU '-'
LINEUP5 EQU 'W'-40H
PAGEUP3 EQU 'B'-40H
ARWLFT3 EQU 'A'-40H
ARWRT3 EQU 'L'-40H
SETKEY EQU 'S'
HUH EQU 'H'
HUH2 EQU '?'
ENDIF
;
; ////// check help and clrscr routines at @@@@@ below ////////
;
;------------------------------------------------------------------------------
;
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
;
; Operational equates
;
MAXSEC EQU 32 ;number of sectors in buffer
SQSIGN EQU 0FF76H ;Signature for SQ files
LBSIGN EQU 2000H ;Signature for library files
DLE EQU 090H ;Char flag for run compression (SQ)
;
ORG TPA
;
JMP START ;skip over next subroutines
;
;------------------------------------------------------------------------------
; @@@@@
; ///////// change help tables to reflect key changes /////////
;
IF LONG AND NOT OSBORNE
HELP3:
CALL CDISP
DB CR,LF,LF
DB ' ^E ^X ^R ^C T ^S ^D '
DB ' S H Q',CR,LF
DB 'up line next line up page next page top left right'
DB ' set help quit',CR,LF
DB ' P - cr + B F sp 1 bs tab '
DB ' S ? ESC',CR,LF
DB ' ^W ^K ^Z lf N ^B ^F ^V ^A ^L',CR,LF
DB ENDMSG
JMP GETCMD
ENDIF
;
IF LONG AND OSBORNE
HELP3: JMP HELP2
ENDIF
;
IF LONG AND NOT OSBORNE
HELP2:
CALL CDISP
DB CR,LF,LF
DB ' P ^E line up B ^R page up bs ^S left '
DB ' S set Q quit',CR,LF
DB ' cr ^X line sp ^C page tab ^D right'
DB ' T 1 top ESC clear',CR,LF
DB ENDMSG
JMP GETCMD
ENDIF
;
IF LONG AND OSBORNE
HELP2:
CALL CDISP
DB CR,LF,LF
DB '^E line up ^R page up ^S left T top Q quit',CR,LF
DB '^X line ^C page ^D right S set ESC clear',CR,LF
DB ENDMSG
JMP GETCMD
ENDIF
;
; ////////////////// check your clear code ///////////////////
;
CLRSCR:
CALL CDISP ;command to erase screen and home cursor
;
IF NOT (HEATH OR OSBORNE)
DB ESC,'+',ENDMSG ;put your screen clear string here
ENDIF
;
IF HEATH
DB ESC,'E',ENDMSG ;for H/Z-19 terminal -- Change as required
ENDIF
;
IF OSBORNE
DB 1AH,ENDMSG ;for Osborne (& Televideo?)
ENDIF
;
; /////////////////// end of user settings ////////////////////
;
;------------------------------------------------------------------------------
;
IF NOT NOWAIT
WAIT: MVI B,0 ;waste time (may or may not be necessary)
WAIT1: XTHL ;good time gobbeler!
XTHL
DCR B
JNZ WAIT1
ENDIF
;
RET ;return from clrscr
;
START:
IF HEATH
CALL CDISP
DB ESC,'x5',ENDMSG ;disable cursor
ENDIF
;
LXI H,0 ;get ccp's stack
DAD SP
SHLD STACK ;save old stack for reinstatement at exit
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
;
CALL EATSP ;Step to next non-bl in input
JZ OPENF ;no more characters
;
CALL FILNAM ;Skip file name, returns <B>=0 or <A>=20H
JZ OPENF ;only file name in tail
;
; Check if there is a member name
CALL EATSP ;Step to next non-bl in input
JZ OPENF ;no more characters
CPI '9'+1 ;Numeric?
;
IF LIBRARY
JNC MEMB ;No -
ENDIF
;
CPI '0'
JNC NUMBER ;Yes - must be width & height
;
;
IF LIBRARY ;Have member name (at FCB+11H)
MEMB:
STA MEMNAM ;No - have member name
PUSH H ;Posn in command line
PUSH B ;# of chars remaining
LXI H,FCB+11H ;Source
LXI D,MEMFCB+1 ;Destination
MVI B,11 ;Move name + type
CALL MOVE
; add LBR suffix if required
LXI H,FCB+9 ;Is there a suffix
MOV A,M
CPI SPACE
JNZ NUMBR2 ;Yes - leave
MVI M,'L'
INX H
MVI M,'B'
INX H
MVI M,'R'
NUMBR2:
POP B
POP H
CALL FILNAM ;Skip member name, returns <B>=0 or <A>=20H
JZ OPENF ;end
ENDIF ;above section included in library ver. only
;
; Handle screen width & height
NUMBER:
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
;
IF SQUEEZE
CALL CHKSQ ;Check for squeezed, init if
ENDIF ;Returns first word in file in <HL>
;
IF LIBRARY
CALL FILBF0 ;fill the disk buffer with start of file
CALL CHKLB ;Check for library file
CALL CLRSCR
JMP WRTFW0 ;Buffer contains top sectors
ENDIF
;
WRTFWD:
CALL CLRSCR ;erase the screen
CALL FILBF0 ;fill the disk buffer with start of file
WRTFW0:
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 FEED ;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)
JC WRTFW1 ;continue with next character
CALL FILBUF ;fill the disk buffer with next sectors
JMP WRTFW0 ;start over
;
HELP: CALL CDISP
DB CR,LF,'BISHOW '
DB (VERS MOD 10)+'0','.'
DB REVS/10+'0',(REVS MOD 10)+'0',CR,LF
;
IF LIBRARY AND SQUEEZE
DB 'bishow d:ANYsqFIL.lbr '
ENDIF
;
IF LIBRARY AND NOT SQUEEZE
DB 'bishow a:FILnotSQ.lbr '
ENDIF
;
IF SQUEEZE AND NOT LIBRARY
DB 'bishow a:SQZorNOT.fil '
ENDIF
;
IF (NOT SQUEEZE) AND (NOT LIBRARY)
DB 'bishow d:anyPLAIN.fil '
ENDIF
;
IF LIBRARY
DB '[member] '
ENDIF
;
DB '[cols [lines]]',CR,LF,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
;
GETCM1: CALL GETIN ;Get input char if any
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:
; /////////////// commands for short version /////////////////
;
CPI LINE ;scroll next line
JZ WRTNXT
CPI LINE2
JZ WRTNXT
CPI PAGE ;scroll next page
JZ WRTFW1
CPI PAGE2
JZ WRTFW1
CPI LINEUP ;scroll prev line
JZ WRTPRV
CPI LINEUP2
JZ WRTPRV
CPI PAGEUP ;scroll page backward
JZ WRTBAK
CPI PAGEUP2
JZ WRTBAK
CPI ARWLFT ;scroll left
JZ ADJMM
CPI ARWLFT2
JZ ADJMM
CPI ARWRT ;scroll right
JZ ADJMM
CPI ARWRT2
JZ ADJMM
CPI TOP ;go to 1st line of file
JZ WRTTOP
CPI TOP2
JZ WRTTOP
CPI QUIT ;does not clear screen
JZ EXIT
CPI QUITCL ;clears screen
JZ EXITCL
;
; //////////////// commands for long version /////////////////
;
IF LONG
;
CPI LINE3
JZ WRTNXT
CPI LINE4
JZ WRTNXT
CPI LINE5
JZ WRTNXT
CPI LINE6
JZ WRTNXT
;
CPI PAGE3
JZ WRTFW1
CPI PAGE4
JZ WRTFW1
CPI PAGE5
JZ WRTFW1
;
CPI LINEUP3
JZ WRTPRV
CPI LINEUP4
JZ WRTPRV
CPI LINEUP5
JZ WRTPRV
;
CPI PAGEUP3
JZ WRTBAK
;
CPI ARWLFT3
JZ ADJMM
;
CPI ARWRT3
JZ ADJMM
;
CPI SETKEY
JZ SETSCR
;
CPI HUH
JZ HELP2 ;brief table of commands
CPI HUH2
JZ HELP3 ;full table of commands
;
ENDIF
;
JMP GETCMD
;
;
; 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 WRTFW0 ;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 FEED ;__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 with top of file
FILBF0:
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 ;Reset to sector zero
;
IF NOT LIBRARY
STA FCBCRR+1 ;
STA FCBCRR+2 ;__and clear the overflow
ENDIF
;
IF LIBRARY
LHLD SCZERO ;Set to sector zero for file/member
SHLD FCBCRR
ENDIF
;
; ;Fill buffer from spec'd sector
FILBUF:
MVI B,MAXSEC ;number of sectors to resd
FILB1S:
;
IF LIBRARY
LHLD SCZERO ;Get top sector for member
XCHG
LHLD FCBCRR ;Is this top of file?
CALL cmphlde ;This it? (<A>=0 if equal)
ENDIF
;
IF NOT LIBRARY
LHLD FCBCRR ;Is this top of file?
MOV A,H
ORA L
ENDIF
;
STA TOPBUF ;Set top of file in buffer flag
LXI D,DSKBUF ;load start of disk buffer
LXI H,0 ;zero out the
SHLD SECCNT ;__number of sectors in buffer
; ; 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
;
IF LIBRARY
PUSH D ;Save sector buffer pointer
LHLD FCBCRR ;get current record number
XCHG
LHLD SCLAST ;& get last sector for member (or FFFF)
CALL cmphlde ;Are we within member
POP D
JC RDERR ;no, last sector read
ENDIF
;
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,'Disjoint sectors',CR,LF,0
JMP EXIT ;Should never happen
USQBAK: ;Going backward
ENDIF
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ;Get 1st sector for member
CALL cmphlde ;All the way back to start?
ENDIF
;
IF SQUEEZE AND NOT LIBRARY
MOV A,D ;All the way?
ORA E
ENDIF
;
IF SQUEEZE
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
ENDIF
;
IF SQUEEZE AND NOT SILENT
CALL CDISP ;Show msg where is
DB '>>> Unsqueezing Text <<<',ENDMSG
;Corrupts display if after CR but before LF
ENDIF
;
IF SQUEEZE
CALL FILUSQ ;fills unsq buffer
ENDIF ;SQEOF set as well then
;
IF SQUEEZE AND NOT SILENT
CALL CDISP ;Remove msg just displayed, assumes
;BS works 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
ENDIF
;
IF SQUEEZE
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 'No File',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
;
IF LONG
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
DCX H ;delete leading zeroes
DCX H ;__in the number
MVI C,SPACE ;__and replace with spaces
MOV A,B
CMP M ;check first digit for '0'
JNZ CDISP ;not zero
MOV M,C ;replace with space
INX H
CMP M ;check second digit for '0'
JNZ CDISP ;not zero
MOV M,C ;replace with space
ENDIF
;
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
MOV E,A ;set up character
MVI C,CONOUT ;__to send to console
CALL BDOS ;do it
POP PSW
CO5: POP H ;restore
POP D ;__the registers
POP B
RET
;
CO1: PUSH B ;Save the registers
PUSH D
PUSH H
MOV E,A
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 CO2
LDA CHRMAX ;get maximum characters per line
CMP M ;see if too many char
JC CO5 ;don't print character
MOV A,E ;restore and print character
CPI TAB ;fix chrcnt for tabs
JZ TABFIX
INR M ;increment character count
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 CO2 ;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
;
;
IF LONG
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,'Max 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,'Min 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 per Page: '
;
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
;
ENDIF ;above code (flying set) only if long
;
ADJMM: ;Adjust char min/max on cursor left/rt
PUSH H
CPI ARWLFT ;Move left (decrease)?
JZ ADJM1 ; set flag
CPI ARWLFT2
JZ ADJM1
;
IF LONG
CPI ARWLFT3
JZ ADJM1
ENDIF
;
ADJM1: LDA CHRMAX ;rightmost char to display
MOV H,A
LDA CHRMIN ;leftmost char to display
MVI L,8 ;Scroll by 8
JZ ADJMMD ;OK - adjust to left
ADD L ;No - increase min, no limit
PUSH PSW
MOV A,L
ADD H ;increase max
JMP ADJMMS ;OK - adjust to right
ADJMMD:
SUB L ;adjust to left
PUSH PSW
MOV A,H
SUB L
ADJMMS: ;adjust to right
MOV H,A ;<H> max
POP PSW ;<A> min
CMP H ;Wrap, (max< min)
JNC ADJMMX ;OK - leave unchanged
STA CHRMIN
MOV A,H
STA CHRMAX
ADJMMX:
POP H
LDA LINMAX ;write the same screen
JMP WRTBK0 ;same effect as WRTSAM above
;
;
IF LONG
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
;
ENDIF
;
EXITCL:
; Clear screen only on <ESC> exit
CALL CLRSCR ;clear the screen
;
EXIT:
; CALL GETIN ;__get any waiting character
; CALL GETIN ;and a possible second character
;
IF HEATH
CALL CDISP ;re-enable cursor
DB ESC,'y5',ENDMSG
ENDIF
;
LXI D,FCB ;close file
MVI C,CLOSE ;--in case this is MP/M
CALL BDOS
;
EXIT1:
LHLD STACK ;get old stack
SPHL
RET ;return to CCP
;
;
IF LIBRARY
CHKLB: ;Check for Library file
xra a
sta memfcb
sta lbflg ;Clear library flag
LHLD DSKBUF ;Get 1st word in file
lxi d,lbsign ;Get expected value
call cmphlde
jz islb
; Not library
;
lda memnam ;Was member specified
ora a
rz ;No - ok
call CDISP
db cr,lf,'Not LBR',cr,lf,0
jmp EXIT ;Get out to leave msg visible
;
; Is library
islb:
mvi a,1
sta LBFLG ;Yes - set library flag
LXI H,DSKBUF+14 ;Set to dir size (in sectors)
mov a,m ;Assume <255 entries
RAL
RAL ;Convert # sectors to # entries
DCR A ;Less 1 for file descriptor
sta dirsiz ;directory size in entries
mov b,a ;Save no of entries for loop
LXI H,DSKBUF+20H ;Set 1st member entry
CALL CDISP ;write a blank line before first dir line
DB CR,LF,0
;
; Loop through directory entries
dirlp:
push b ;Save no of entries remaining
MOV A,M ;Get entry status
ORA A ;Deleted?
JNZ nyet ;Yes - skp to next
LDA MEMNAM ;Do we have member name on command line?
ORA A
JZ DISPM ;No - display member name routine
;
; See if this is the requested member
;
mvi b,12 ;Length of names + 00H in front
lxi d,memfcb
call cpstr ;Compare names
jz found
jmp nyet
;
; Display rather than look for the member
;
DISPM: mvi b,11 ;Length of names
push h
inx h ;Step to actual name
DSPMLP:
mov a,m
call CO ;Display one char
inx h
dcr b ;Reduce count remaining
jz nmend ;end of name
;
ENDIF
;
IF LIBRARY AND NOT OSBORNE
; (Bypass for Ozzys narrow screen)
mov a,b
cpi 3 ;only 3 more?
jnz DSPMLP ;No -
mvi a,'.' ;Yes - put out dot
call CO
;
ENDIF
;
IF LIBRARY
jmp DSPMLP ;Go for next char
;
;Have now displayed member name
nmend:
; In later versions multiple across
lxi h,namexc ;Max no of names across sofar
mov a,m
inx h ;Step to names across sofar
inr m ;Count current
cmp m ;Over max?
jnc notmax ;not yet
mvi m,0 ;Yes - reset
call CDISP
DB CR,LF,0
jmp nyet1
notmax:
call CDISP
ENDIF
IF LIBRARY AND NOT OSBORNE
DB ' '
ENDIF
IF LIBRARY
DB '| ',0
nyet1:
POP H ;Reset to start of this entry
;
nyet:
lxi b,20h ;Length of each entry
dad b ;Step to next
pop b ;Get entry count (remaining)
dcr b
jnz dirlp ;More members
LDA MEMNAM ;Do we have member name on command line?
ORA A
JZ EXIT ;if not, we have shown dir, now exit
call CDISP
db 'Not in LBR',cr,lf,0
jmp EXIT ;and show the poor schmuck the directory
;
; Found the member name
found:
pop b ;Clear stack
lxi d,12
dad d
push h ;save pointer for now,
inx h ;point to size
inx h
mov a,m ;get low byte
inx h
mov h,m
mov l,a
ora h ;if a=0 then file is 0k
jz nullen ;go complain
xthl ;get pointer back, save size
mov a,m ;get file address
inx h
mov h,m
mov l,a
SHLD SCZERO ;Save as first file sector
POP D ; & get size back
DAD D ;Convert to last sector no (inclusive)
SHLD SCLAST
ENDIF
;
IF LIBRARY AND SQUEEZE
LDA SQFLG ;Get SQ flag in case of double squeeze
ORA A
JZ NOLBSQ ;Ok, library itself not squeezed
CALL CDISP
DB 'unSQ LBR',CR,LF,0
JMP EXIT
NOLBSQ:
CALL CHKSQ ;Check if member squeezed
ENDIF
;
IF LIBRARY
CALL FILBF0 ;Refill buffer, now for member
; (FILBUF handles member offset in library)
ret
;
; ;Member is empty
nullen:
CALL CDISP
DB 'Empty',CR,LF,0
JMP EXIT
ENDIF
;
; Get input if any
GETIN:
MVI C,6 ;direct console I/O
MVI E,0FFH ;__set up for input
CALL BDOS ;Get char
RET
;
; Compare strings HL> to DE> over <B>
; <DE> and <B> are changed, <HL> kept
cpstr:
push h
cp$lp:
ldax d
cmp m
jnz cp$ex ;No match
inx d
inx h
dcr b
jnz cp$lp
cp$ex:
pop h
ret
;
; Compare <HL> to <DE>
; Z - equal; C - <HL> less than <DE>
; if equal returns <A>=0
cmphlde:
mov a,h
sub d
rnz
mov a,l
sub e
ret
;
; Skip blanks in input
;
EATSP: MOV A,M ;get character if there is one
INX H
DCR B ;b=number of characters left
RZ ;no more characters
CPI SPACE ;ignore spaces
JZ EATSP
DCX H ;Step back to 1st non-blank
INR B
ORA A ;Force NZ
RET
;
; Skip name in input
;
FILNAM: MOV A,M ;get characters in file name
INX H
DCR B ;b=number of characters left
RZ ;only file name in tail
CPI SPACE ;wait for next space
JNZ FILNAM
ORA A ;Force NZ
RET ;Blank
;
; Move from HL> to DE> over <B>
;
MOVE:
MOV A,M
STAX D
INX H ;Step to next source
INX D ; & destination
DCR B ;Reduce count (00=256)
JNZ MOVE
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
sta FCBCRR+2 ; and overflow
shld numvals ;Clear # nodes
ENDIF
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ;Get 1st sector for member
SHLD NXTSEC ;& save as next sector
ENDIF
;
IF SQUEEZE
shld FCBCRR ;Clear next record
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
; Read and validate signature word
call getw ;Read 1st word in file
lxi d,sqsign ;Get expected value
call cmphlde
rnz
mvi a,1
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,'Bad SQ tree',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 & 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,'EOF?',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,'EOF',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 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
;
;
IF LIBRARY
namexc: db (MAXCHR/14)-1 ;No of directory names across display
db 0 ;No of names so far
dirsiz: db 0 ;# of members possible in directory
memnam db 0 ;Member name specified on command line
SCZERO: DW 0 ;First sector for member
SCLAST: DW 0FFFFH ;Last sector for member (included in member)
; SCZERO and SCLAST are relative in file
LBFLG: DB 0 ;File is a library file
memfcb: DS 12 ;Member name here
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+256*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