home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
txtutl
/
bishow34.ark
/
BISHOW34.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-09-25
|
51KB
|
1,981 lines
; BISHOW v34 - buffered bidirectional file scroll utility'
;
; Ver 34, 25 Sep 1987, Ernest F. Barnhart, N8DVE, Dayton, OH
; - Added cursor off/on for the Kaypro computers.
; - Changed back to using control key for real Wordstar
; compatibility.
; - Changed keys to allow the set function to work correctly.
; - Changed format of help screen.
; - Changed format of help lines.
;
; Ver 33, 29 Sep 86, Charlie Kestner, Hammond, Ind
; - clarified the LIBRARY AND SQUEEZE help message
; since this is probably version MOST folk would use.
; - eliminated having to use control key. Now just plain
; S, D, E, X, E, & C function for Wordstar users.
; - changed over some of the command keys for folk who
; like to use cursor/numeric pad. NO need to shift
; the numeric pad, plain numbers will do it.
; - long help key is now "/".
;
; Ver 32, 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 31, 15 Jan 84, Frans van Duinen, Toronto, Ont
; - made unsqueeze message optional
; - added library capability
; - fixed bug in conditional assembly of CLRSCR
;
; Ver 29, 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
; record 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 28, 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 Sigi Kluger of El
; Paso,Texas. The code was lifted, to allow
; continued use of ASM.COM
;
;
; Ver 17, 1 Aug 83, Ted H. Emigh ...!unc!tucc!emigh
; - added screen width specification
; - added screen definition commands (see notes below)
;
; Ver 16, 2 Jul 83, Chuck Forsberg
; - added commands for more, mince, vi familiarity.
; Bad command gives help.
;
; Ver 15.1, 26 June 83, Dick Mead
; - added "?" for help on commands.
;
; Ver 15, 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 14, 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 13, 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 12, 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 11, 30 Mar 83 - added BDOS function 6. W.F.Mcgee
;
; Ver 10, 23 Aug 82 Phil Cary, 748 Kenilworth Parkway, Baton
; 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 records from a 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 "MAXREC" 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 mini-
; mum column displayed (allowing you to "window" the output) and the
; number of lines ("SCROLN"). A zero for the maximum column displayed
; willgive an unlimited screen width. The maximum column displayed and
; the number of lines can be set when calling BISHOW, such as "BISHOW
; FILENAME.EXT 79 24" will give 79 columns and 24 lines with "BISHOW
; FILENAME.EXT 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.
;
; Justa small contribution to the public domain software as partial pay-
; ment for the many fine and educational programs the system has given
; me.
; - Phil Cary.
;-----------------------------------------------------------------------
;Define version number for help message
;
VERS EQU 3
REVS EQU 4
;
;
NO EQU 0
YES EQU NOT NO
;
; 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
;
KAYPRO EQU YES ; Use cursor on/off function
HEATH EQU NO ; Assemble for H-19 terminal
OSBORNE EQU NO ; Assemble for 52-column screen
;
SHORT EQU NO ; No SQ or LBR = 1k / with SQ and LBR = 2k
LONG EQU YES ; Duplicate keys, includes help, margin set
SQUEEZE EQU YES ; Optional, to handle squeezed files
LIBRARY EQU YES ; Optional, to handle .LBR files
;
NOWAIT EQU YES ; True = no wait after screen clear
SILENT EQU YES ; True = no superfluous "unsqueezing text" msg
;
IF NOT OSBORNE
SCROLN EQU 23 ; Number of lines per scroll
MAXCHR EQU 80 ; Number of characters per line
ENDIF ; NOT OSBORNE
;
IF OSBORNE
SCROLN EQU 24 ; Number of lines per scroll
MAXCHR EQU 51 ; Number of characters per line
ENDIF ; OSBORNE
;
; Change the help tables if you change keys
;
; Command keys - short version
;
LINE EQU 'X'-40H
LINE2 EQU SPACE
PAGE EQU 'C'-40H
PAGE2 EQU CR
LINEUP EQU 'E'-40H
LINEUP2 EQU 'E'-40H
PAGEUP EQU 'R'-40H
PAGEUP2 EQU 'R'-40H
ARWLFT EQU 'S'-40H
ARWLFT2 EQU 'S'-40H
ARWRT EQU 'D'-40H
ARWRT2 EQU 'D'-40H
TOP EQU 'T'
TOP2 EQU '7'
QUIT EQU 'Q'
QUITCL EQU ESC
;
; Additional command keys - long version
;
IF LONG
LINE3 EQU LF
LINE4 EQU '+'
LINE5 EQU '2'
LINE6 EQU '2'
PAGE3 EQU '3'
PAGE4 EQU '3'
PAGE5 EQU '3'
LINEUP3 EQU '8'
LINEUP4 EQU '-'
LINEUP5 EQU '8'
PAGEUP3 EQU '9'
ARWLFT3 EQU '4'
ARWRT3 EQU '6'
SETKEY EQU 'S'
HUH EQU 'H'
HUH2 EQU '/'
ENDIF ; LONG
;
;-----------------------------------------------------------------------
;
; Check help and CLRSCR routines
;
;-----------------------------------------------------------------------
;
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
;
MAXREC EQU 32 ; Number of records 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 down line up page down page top left right'
DB ' set help quit',CR,LF
DB ' 8 2 9 3 7 4 6 '
DB ' S / ESC',CR,LF
DB ENDMSG
JMP GETCMD
ENDIF ; LONG AND NOT OSBORNE
;
IF LONG AND OSBORNE
HELP3: JMP HELP2
ENDIF ; LONG AND OSBORNE
;
IF LONG AND NOT OSBORNE
HELP2:
CALL CDISP
DB CR,LF,LF
DB ' ^E - line up ^R 9 page up ^S 4 left '
DB ' S set Q quit',CR,LF
DB ' ^X <SP> line ^C <CR> page ^D 6 right'
DB ' T 7 top ESC clear',CR,LF
DB ENDMSG
JMP GETCMD
ENDIF ; LONG AND NOT OSBORNE
;
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 ; LONG AND OSBORNE
;
; Check your clear code
;
CLRSCR:
CALL CDISP ; Command to erase screen and home cursor
;
IF NOT (HEATH OR OSBORNE)
DB 1AH,ENDMSG ; Put your screen clear string here
ENDIF ; NOT (HEATH OR OSBORNE)
;
IF HEATH
DB ESC,'E',ENDMSG ; For H/Z-19 terminal -- Change as required
ENDIF ; HEATH
;
IF OSBORNE
DB 1AH,ENDMSG ; For Osborne (& Televideo?)
ENDIF ; OSBORNE
;
; 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 ; NOT NOWAIT
;
RET ; Return from clrscr
;-----------------------------------------------------------------------
;
; START OF PROGRAM
;
;-----------------------------------------------------------------------
;
START:
IF HEATH
CALL CDISP
DB ESC,'x5',ENDMSG ; Disable cursor
ENDIF ; HEATH
;
IF KAYPRO
CALL CDISP
DB ESC,'C4',ENDMSG ; Disable cursor
ENDIF ; KAYPRO
;
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 ; LIBRARY
;
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
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 ; LIBRARY
;
; Handle screen width and 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 ; SQUEEZE
;
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 records
ENDIF ; LIBRARY
;
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)
JC WRTFW1 ; Continue with next character
CALL FILBUF ; Fill the disk buffer with next records
JMP WRTFW0 ; Start over
;
HELP: CALL CLRSCR
CALL CDISP
DB CR,LF
DB 'BISHOW v',(VERS MOD 10)+'0'
DB REVS/10+'0',(REVS MOD 10)+'0'
DB ', 25 Sep 1987'
DB CR,LF,LF
;
IF LIBRARY AND SQUEEZE
DB ' BISHOW is a buffered, bi-directional'
DB ' file pager that will display',CR,LF
DB ' various forms of text files. Syntax is:',CR,LF,CR,LF
DB ' bishow filename.typ [cols] [lines]',CR,LF,CR,LF
DB ' Normal or squeezed ASCII or WordStar '
DB 'files may be viewed.',CR,LF,CR,LF
DB ' A directory of a library file, or a '
DB 'member of a library file may',CR,LF
DB ' be seen. Syntax is:',CR,LF,CR,LF
DB ' bishow librname.lbr',CR,LF
DB ' bishow librname membrnam.typ',CR,LF,CR,LF
DB ' Note that the .LBR extension MUST be appended to '
DB 'the library name.',CR,LF
DB ' in order to display the librarys directory. ',CR,LF,CR,LF
DB ' (Type a "/" while viewing a file '
DB 'to see command summary.)',CR,LF
DB ENDMSG
ENDIF ; LIBRARY AND SQUEEZE
;
IF LIBRARY AND NOT SQUEEZE
DB 'bishow a:FILnotSQ.lbr '
ENDIF ; LIBRARY AND NOT SQUEEZE
;
IF SQUEEZE AND NOT LIBRARY
DB 'bishow a:SQZorNOT.fil '
ENDIF ; SQUEEZE AND NOT LIBRARY
;
IF (NOT SQUEEZE) AND (NOT LIBRARY)
DB 'bishow d:anyPLAIN.fil '
ENDIF ; (NOT SQUEEZE) AND (NOT LIBRARY)
;
IF LIBRARY
DB '[member] '
ENDIF ; LIBRARY
;
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
;
; Commands for short version
;
GETCM2: 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 ; LONG
;
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 records
;
; 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)
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
;
; Test for top of file
;
FILBAK: 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 RECCNT ; Get no of records last read
LXI D,MAXREC ; 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>
; .CBCRR Reset to record zero
STA FCBCRR
;
IF NOT LIBRARY
STA FCBCRR+1 ;
STA FCBCRR+2 ; __and clear the overflow
ENDIF ; NOT LIBRARY
;
IF LIBRARY
LHLD SCZERO ; Set to record zero for file/member
SHLD FCBCRR
ENDIF ; LIBRARY
;
; Fill buffer from spec'd record
;
FILBUF: MVI B,MAXREC ; Number of records to read
;
FILB1S:
IF LIBRARY
LHLD SCZERO ; Get top record for member
XCHG
LHLD FCBCRR ; Is this top of file?
CALL CMPHLDE ; This it? (<A>=0 if equal)
ENDIF ; LIBRARY
;
IF NOT LIBRARY
LHLD FCBCRR ; Is this top of file?
MOV A,H
ORA L
ENDIF ; NOT LIBRARY
;
STA TOPBUF ; Set top of file in buffer flag
LXI D,DSKBUF ; Load start of disk buffer
LXI H,0 ; Zero out the
SHLD RECCNT ; __number of records in buffer
; ; Z - top, NZ - not top
IF SQUEEZE
LDA SQFLG ; Is this a squeezed file
ORA A
JNZ FILSQ ; Yes -
ENDIF ; SQUEEZE
;
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 RECCNT ; Get records in buffer
INX H ; Bump it
SHLD RECCNT ; Store it
POP B
POP D
POP H
JNZ RDERR ; No, last record read
;
IF LIBRARY
PUSH D ; Save record buffer pointer
LHLD FCBCRR ; Get current record number
XCHG
LHLD SCLAST ; & get last record for member (or FFFF)
CALL CMPHLDE ; Are we within member
POP D
JC RDERR ; No, last record read
ENDIF ; LIBRARY
;
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 record
;
; Fill buffer from squeezed file. This RTN handles mapping from UNSQ
; record # to record, byte and bit in squeeze stream. On input (no
; allowance made for records # over 65535) <B> contains number of records
; wanted DE> buffer where records wanted, Ignored in this version,
; always full DSKBUF
;
IF SQUEEZE
FILSQ: LHLD FCBCRR ; Get # for 1st record wanted
XCHG
PUSH D ; Save to restore after unsq
LHLD NXTREC ; & 1st record after buffered ones
CALL CMPHLDE ; Consecutive?
JZ USQNXT ; Yes - fine
JNC USQBAK ; No - lower
;
; Next record after latest but not consec
;
CALL CDISP
DB CR,LF,'Disjoint records',CR,LF,0
JMP EXIT ; Should never happen
;
USQBAK: DS 0 ; Going backward
ENDIF ; SQUEEZE
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ; Get 1st record for member
CALL CMPHLDE ; All the way back to start?
ENDIF ; SQUEEZE AND LIBRARYX
;
IF SQUEEZE AND NOT LIBRARY
MOV A,D ; All the way?
ORA E
ENDIF ; SQUEEZE AND NOT LIBRARY
;
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 record 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
STA SQBYT+1 ; Set offset 1st data byte
MOV A,C
STA SQBYT ; For now offset within record only
LHLD SQBSC1 ; Get no of first SQ record now in buffer
XCHG ; <HL> wanted 1st record, <DE> actual 1st
CALL CMPHLDE ; Is 1st buffer record low/equal 1st data sect?
JNC USQ1OK ; Yes - first wanted record SQ in buffer
;
; Max header 1035 bytes + file name)
;
; Force reload of SQ buffer
;
SHLD NXTSQS ; No - 1st data record b/4 1st buffer sect
; (note is probab not record 0
; because of header, eg decoding tree)
MVI A,1 ; Set rewind with I/O
STA SQREWD ; Set rewind flag
XRA A
STA SQEOF ; Reset end of file on SQ
; Leave current extent alone. This is
; how BDOS knows how to switch the
; extents. It checks if the current
; extent no agrees with the wanted
; record.
STA FCBCRR+2 ; & count overflow, should not be needed
MOV D,A
JMP USQNX1 ; Go adjust buffer pointer
; (NOP since <DE>=0
;
; SQ text still in buffer
;
; <DE> # of 1st record in SQ buf
; <HL> # of wanted SQ record
; (Max 100H SQ records in buffer)
;
USQ1OK: MOV A,L
SUB E
RAR ; Convert to pages (100H)
;
; Know Cy=0 in
; Leaves carry set if odd number of records
;
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
;
; Next record consecutive
;
USQNXT: LHLD NXTSQS ; Get no of next SQ record
SHLD FCBCRR
;
; Build mapping table entry
;
LHLD INBUFS ; Calculate offer in buffer
LXI D,-SQBUF
DAD D
MOV C,L ; Keep offset within record
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 record no
ORA A ; Is next byte at start of record?
JNZ RECTOK
DCR H ; Yes - step back one record
;
RECTOK: DCR A
ANI 7FH ; And adjust byte index
MOV E,H
MVI D,0
LHLD SQBSC1 ; # of 1st record in buffer
DAD D
XCHG ; <D> absolute SQ record no
LHLD SQMAP ; Get index
MOV M,E ; Save abs SQ record 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 ; SQUEEZE
;
IF SQUEEZE AND NOT SILENT
CALL CDISP ; Show msg where is
DB '>>> Unsqueezing Text <<<',ENDMSG
; Corrupts display if after CR but before LF
ENDIF ; SQUEEZE AND NOT SILENT
;
IF SQUEEZE
CALL FILUSQ ; Fills unsq buffer
ENDIF ; SQUEEZE
;
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 ; SQUEEZE AND NOT SILENT
;
IF SQUEEZE
LHLD FCBCRR ; Get no of next SQ record
SHLD NXTSQS
LHLD NXTADR ; Calc # of unsq records in buf
LXI D,-DSKBUF ; (as neg no)
DAD D ; Calc length
DAD H ; & convert to records in <H>
MOV L,H
MVI H,0
SHLD RECCNT ; Save # of records in DSKBUF
POP D ; Get FCBCRR as passed by calling rtn
DAD D ; & calc new one
SHLD FCBCRR
SHLD NXTREC
RET
ENDIF ; SQUEEZE
;
; 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
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 ; LONG
;
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 ; LONG
;
; Adjust char min/max on cursor left/rt
;
ADJMM: PUSH H
CPI ARWLFT ; Move left (decrease)?
JZ ADJM1 ; Set flag
CPI ARWLFT2
JZ ADJM1
;
IF LONG
CPI ARWLFT3
JZ ADJM1
ENDIF ; LONG
;
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
;
; Adjust to right
;
ADJMMS: 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 ; LONG
;
; Clear screen only on <ESC> exit
;
EXITCL: CALL CLRSCR ; Clear the screen
;
EXIT: LXI D,FCB ; Close file
MVI C,CLOSE ; --in case this is MP/M
CALL BDOS
;
EXIT1:
IF HEATH
CALL CDISP ; Re-enable cursor
DB ESC,'y5',ENDMSG
ENDIF ; HEATH
;
IF KAYPRO
CALL CDISP
DB ESC,'B4',ENDMSG ; Enable cursor
ENDIF ; KAYPRO
;
LHLD STACK ; Get old stack
SPHL
RET ; Return to CCP
;
; Check for Library file
;
IF LIBRARY
CHKLB: 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 records)
MOV A,M ; Assume <255 entries
RAL
RAL ; Convert # records 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 ; LIBRARY
;
IF LIBRARY AND NOT OSBORNE
MOV A,B
CPI 3 ; Only 3 more?
JNZ DSPMLP ; No -
MVI A,'.' ; Yes - put out dot
CALL CO
ENDIF ; LIBRARY AND NOT OSBORNE
;
IF LIBRARY
JMP DSPMLP ; Go for next char
;
; Have now displayed member name
;
NMEND: 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 ; LIBRARY
;
IF LIBRARY AND NOT OSBORNE
DB ' '
ENDIF ; LIBRARY AND NOT OSBORNE
;
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
JNZ XLIB ; If not then display message
CALL CDISP
DB CR,LF,ENDMSG ; Leave blank line after directory
JMP EXIT
;
XLIB: 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 record
POP D ; & get size back
DAD D ; Convert to last record no (inclusive)
SHLD SCLAST
ENDIF ; LIBRARY
;
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 ; LIBRARY AND SQUEEZE
;
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 ; LIBRARY
;
; Get input if any
;
GETIN: MVI C,6 ; Direct console I/O
MVI E,0FFH ; __set up for input
CALL BDOS ; Get character
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
;
;******************************************************
; USQ support code *
; 10/12/83 by Dave Rand *
;******************************************************
;
; Check for SQ file, initialize tree if so
;
IF SQUEEZE
CHKSQ: 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 ; SQUEEZE
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ; Get 1st record for member
SHLD NXTREC ; & save as next record
ENDIF ; SQUEEZE AND LIBRARY
;
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 buffer aft 1 sect
;
; Ccauses the SQ buffer to contain records 1+ only (not zero), normally
; fine since recort 0 contains only header info. Record 0 will be re-
; read 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 ; Records (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 and save checksum
;
RDCHKS: CALL GETW ; Get checksum, and store
SHLD FILCHKS
RET
;
; Read and 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-0FFH) and is thus limited to 255 nodes and 255 characters represen-
; ted 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 - 0FFh)
;
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 different codes, every ASCII and
; non-ASCII character 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>,
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: 1) flag byte, 2) left
; child index/character and 3) right child index/character. Codes 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, child pointer or character
POP D
MOV A,H
ORA A
RZ ; Child index, <H>=0,<L>=index
MOV A,L
CMA
MOV L,A ; Convert character to register 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 ; Calculate adjustment required
;
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 ; And 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)
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 character
;
; 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 ; and this one
STA RCNT ; Keep count yet to be retd
LDA LAST ; Return second time
CMP A
RET
;
; Normal character, no run active
;
NORUN: STA LAST ; This may be the start
CMP A
RET
;
;
; Read bits and decode to character. Nnote 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 character
;
; <D> should always remain zero
;
ANI 1010B ; Mask unwanted bits
JZ BITLP ; Reg child pointer
;
; Got to character 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 register EOF
;
GOTEOF:
MVI A,EOF
ORA A
RET
;
; Get input word (low/high, 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: DS 0
;
BADR: CALL CDISP
DB CR,LF,'EOF?',CR,LF,0
JMP EXIT
;
; Get single (unencoded) character
;
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 RECCNT ; Save record count (decoded buffer only)
PUSH H
LXI H,SQBUF ; Set input buffer as empty,
SHLD INBUFS ; _and start of buffer
XCHG ; DE> buffer, next record 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 records
MOV B,H ; No of records to read
LHLD FCBCRR ; No of 1st record to read
SHLD SQBSC1
CALL FILBU1 ; Read record 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 record number
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 ; and flag EOF
;
; Input buffer re-filled
;
GETRF2: POP H
SHLD RECCNT ; Restore record 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 ; SQUEEZE
;
; Memory allocation
;
RECCNT: DW 0 ; Number of records 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
NXTREC: DW 0 ; Next (unsqueezed) record 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 record in SQ buffer
NXTSQS: DW 0 ; No of last record in SQ buffer
ENDIF ; SQUEEZE
;
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 record for member
SCLAST: DW 0FFFFH ; Last record 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 ; LIBRARY
;
DS 60 ; Stack area
STACK: DS 2 ; Old stack saved here
DSKBUF EQU $ ; Disk buffer area above the program
;
ENDBUF EQU DSKBUF+MAXREC*128
;
IF SQUEEZE
SQTREE EQU ENDBUF ; Space for SQ decoding tree
SQMAP EQU SQTREE+256*3
;
; Space for SQ buffer mapping table contains squeeze record #, squeeze
; byte and bit offset for every time DSKBUF was filled. 1st entry con-
; tains index to latest mapping triplet to handle run compr straddling
; buffer end, should also store rcnt and last.
;
SQBUF EQU SQMAP+100*4 ; (allows for 100 8k buffers)
ENDIF ; SQUEEZE
;
; Input (squeezed) buffer, runs up to top of free memoryot
;
END TPA