; 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 ( ) does NOT agree with ; the wanted no . 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) ; 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 ; wanted 1st sector, 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 =0 ; ;SQ text still in buffer USQ1OK: ; # of 1st sector in SQ buf ; # 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 ; 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 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 ; max POP PSW ; 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 to ; Z - equal; C - less than 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 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 ) 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 , ; index/char in 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, ,, 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, =0,=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? =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 ; 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 (=0) lhld FCBCRR ;No of 1st sector to read shld SQBSC1 call FILBU1 ;Read sector into SQBUF ; 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