; Program: VIEW ; Purpose: Text File Examination ; Author: Robert Friefeld, Long Beach, CA ; Assembly: SLR assembler and linker ; Date: 15 Jan 1988 ;=========================================================================== vers equ 43 ; Version number ; Version 4.3: ; - Requires Z33 for filename parser. ; Basic facts true equ -1 false equ 0 ; Assembly options expert equ false ; True = assembly without help screen wrtok equ true ; Permit block i/o to disk (write, merge) lstok equ true ; Permit output to list insok equ false ; True = use CRT insert line code hardvid equ false ; True = use hard coded CRT routines, not VLIB tabsize equ 8 ; Tab expansion ovrlap equ 1 ; Number of lines to overlap on scroll fbufsz equ 20 ; Find string length initsz equ 16 ; Printer initialization string length ; Required minimum CRT size crtcol equ 80 crtlns equ 24 INCLUDE SYSDEF.LIB ; ; Library needs ; .request vlib,z33lib,z3lib,syslib ; VLIB ext getvid,z3vinit if [not hardvid] ext tinit,dinit,stndout,stndend,at,cls,ereol endif ; not hardvid ; Z33LIB ext z33chk,scan,fcbchk ; Z3LIB ext getwhl,getcrt,$memry,wait1s,wait1ms ; SYSLIB ext $memry ; ; CODE BEGINS ; db 'Z3ENV' ; Z-tool header db 3 z3eadr: dw 0000h ; Installed by Z33 dw 100h ;---------------------------------------------------------------------------- ; ; PATCHABLE OPTIONS ; ; Printer initialization string sent by "I" command. ; Begins with byte count, then the bytes. String may contain 0. IF LSTOK init$str: db 1 ; Char count db cr ; Chars ds (initsz+1)-($-init$str) ENDIF ; ; If CRT supports insert line function, performance of VIEW is enhanced by ; using it. INSFLG tells VIEW whether or not user has installed code. insflg: db insok ; True = use insert line, false = work around ; This is the insert line code. Default is used by most terminals. A ; terminating 0 must immediately follow the string (as below). inscrt: db esc,'E',0,0 ; Insert line on CRT, up to 4 bytes. db 0 ; Scan speed - speed of continuous scrolling ; Smaller number goes faster. Use a power of 2 scanspd: db 20h ; END PATCHES ;---------------------------------------------------------------------------- ; ; START OF PROGRAM ; start: ld (stksav),sp ; Set up local stack ld sp,stack ; ; Initialize to ENV ; call z33chk ; Make sure of Z3x environment jp nz,noz33 ; Nope ld hl,(z3eadr) ; Initialize vlib routines call z3vinit call getvid jp z,novid ; Exit with message if no TCAP support call getwhl ; Must be wheel jp z,nowhl call getcrt ; Check for minimum crt size ld a,(hl) cp crtcol jp c,nocrt dec a ld (width),a ; Use crtwidth-1 columns (usu. 79) inc hl ld a,(hl) cp crtlns jp c,nocrt ld (prrow),a ; Save last row for prompts dec a ld (scrlns),a ; Data lines is 1 less call tinit ; ; Check command line options ; ld a,(fcb+1) ; Reject blank file spec cp ' ' jp z,nope cp '/' jp z,nope ; ; Begin main program ; ld hl,($memry) ; Set pointer to text buffer ld (text),hl call getfil ; Read the file into memory call cls ; Restart entry resrt: ld hl,(text) ; Set Start Pointer to beginning of file ld (srtptr),hl ld (table),hl ; Initialize block markers call initmrk ; Initialize marker table call seteos ; Set pointer to last screen prnscr: call pscreen ; Print screen pointed to by SRTPTR ; ; Command input routine ; command: call getchr ; Get command cp '0' ; Go right to markers jr c,clist cp '9'+1 jr nc,clist jp gomark clist: call case db 'A' ; Last page of file dw last db 'D' ; Forward a line dw down db 'E' ; Erase markers dw erase db 'F' ; Next screen dw next db 'G' ; Forward 5 lines dw find db 'H' ; Find string dw find0 db 'I' ; Initialize printer dw init$prt db 'J' ; Previous screen dw prev db 'K' ; Back a line dw up db 'L' ; Scan backward dw back db 'M' ; Append a file dw merge db 'O' ; Mark beginning of block dw mark db 'P' ; List from mark to cursor dw list db 'Q' ; Quick set marker dw auto db 'R' ; Read in more text dw read db 'S' ; Scan forward dw fscan db 'T' ; Type a line on printer dw type db 'U' ; Delete marked block dw dblock db 'W' ; Write marked block dw wblock db 'X' dw exit0 db 'Y' ; Delete top line from buffer dw delete db ';' ; Top of file dw top db 20h ; jump ahead 10 lines dw hop db cr ; next screen dw next db '?' ; Help dw info db '/' dw info db 0 ; Table delimiter jp command ; Loop back on invalid input ; ; Print screen pointed to by SRTPTR ; pscreen: call homcrs ld hl,(srtptr) push hl ; If near end then print entire last screen ld de,(eosptr) ; Compute position relative to last screen xor a ; Reset carry flag sbc hl,de pop hl jr z,prn1 ; We are at or before last screen so go ahead jp nc,last ; We are past last screen so back up prn1: ld a,(scrlns) ld b,a ; Line count in B prnlp1: call clreol call prnline djnz prnlp1 ; Print SCRLNS lines ld (nxtptr),hl ; And set Next Pointer call retcrs ; Cursor to prompt line ret ; ; PRINT ONE LINE OF TEXT ; HL -> first char on entry, next char on exit ; prnline: push bc ; Preserve possible loop counter on entry xor a ld c,a ; Char counter for CRT width and tabs prnl1: ld a,(hl) ; Get char cp eof ; At end? jr z,prnl2 ; Can occur on text smaller than one screen call prnl3 ; Print the character cp cr ; Are we at end of line? inc hl ; Bump pointer jr nz,prnl1 ; No prnl2: pop bc call print db lf+80h ret ; Exit routine ; PRINT THE CHAR IF THE LINE IS NOT FULL prnl3: cp cr ; Always print cr jp z,conout cp tab jr z,prnl5 ; Expand tab prnl4: ld e,a ; Save char inc c ; Bump char counter ld a,(width) ; Exceeded line width? cp c jr c,prnl42 ; Yes prnl41: ld a,e ; Restore char jp pctl ; Send it out ; LINE OVERFLOW prnl42: ld a,(lflag) ; Are we listing? or a jr nz,prnl41 ; Yes, keep sending chars call stndout ; Display OVFL indicator call print db '>',bs+80h jp stndend ; TAB EXPANSION prnl5: ld a,c ; Compute char count MOD tabsize sub tabsize jr nc,$-2 neg ; Spaces to next tab in A ld b,a ; Use as loop counter ld a,' ' ; Print space prnl51: call prnl4 ; Send it out, if room, and update char count ret c ; Line overflow, quit djnz prnl51 ret ; ; Print next screen ; next: ld hl,(nxtptr) ld a,eof ; Is there a next screen? cp (hl) jp z,command ; No ld b,ovrlap ; Back up scroll overlap lines call pvline djnz $-3 ld (srtptr),hl ; Start becomes Next jp prnscr ; ; Print top screen ; top: ld hl,(text) ld (srtptr),hl jp prnscr ; ; Print last screen ; last: ld hl,(eosptr) ld (srtptr),hl ; Start at end of text jp prnscr ; And back up one page ; ; Print next line ; down: call dnline jp command ; ; Hop forward 10 lines ; hop: ld b,10 hop0: push bc call dnline pop bc djnz hop0 jp command ; ; Keep printing until a key is pressed ; fscan: call dnline jp z,command call sbreak jp nz,command call wait jr fscan ; Check for scan terminator or speed change sbreak: call breaker ret z ; No character, continue call getchr ; Dispose of character cp '+' jr z,scplus cp '=' jr z,scplus cp '-' jr z,scminus or -1 ; NZ means break ret scplus: xor a ld hl,scanspd rr (hl) cp (hl) jr nz,scpl1 inc (hl) scpl1: xor a ret scminus: xor a ld hl,scanspd rl (hl) cp (hl) jr nz,scpl1 ld (hl),80h jr scpl1 ; Print next line dnline: ld hl,(nxtptr) ld a,eof ; Check EOF cp (hl) ret z ; There is no next line call prnline ; Print the line ld (nxtptr),hl ; Set Next Pointer ld hl,(srtptr) ; Set Start Pointer one line further along call nxline ld (srtptr),hl or -1 ; A NZ flag on return ret ; Search for next line of text nxline: ld a,(hl) cp eof ret z inc hl cp cr jr nz,nxline ret ; Returns HL at character after cr ; ; Print previous screen ; prev: ld hl,(srtptr) ld a,(scrlns) sub ovrlap ld b,a prev0: call pvline ; Count back SCRLNS-ovrlap lines djnz prev0 ld (srtptr),hl ; Set Start Pointer jp prnscr ; Print the screen ; ; SEARCH FOR START OF PREVIOUS LINE OF TEXT ; pvline: push bc ; Save possible loop counter on entry ld de,(text) ; Are we already at beginning of file? ld b,2 prvlp: dec hl xor a push hl sbc hl,de pop hl jr c,prv0 ; Yes, so we are done ld a,(hl) ; Look for last cr cp cr jr nz,prvlp ; Haven't found cr yet djnz prvlp prv0: inc hl pop bc ret ; ; Previous line ; up: call upline jp command ; ; Scan backward ; back: ld a,(insflg) cp true jr nz,back2 back1: call upline ; Repeat previous line until key pressed jp z,command call sbreak jp nz,command call wait ; Give screen time to catch up jr back1 back2: ld hl,(srtptr) ld b,10 call pvline djnz $-3 ld (srtptr),hl jp prnscr upline: ld de,(text) ; Don't do it if at beginning already ld hl,(srtptr) xor a sbc hl,de ret z ld hl,(srtptr) ; Back up a line call pvline ld (srtptr),hl ; Set pointer ld a,(insflg) cp true jr nz,upl1 call inslin ; Home cursor and insert a blank line call prnline ; Print the line ld hl,(nxtptr) ; Set Next Pointer call pvline ld (nxtptr),hl call retcrs ; Return cursor to bottom of screen upl0: call cr$clr ; Erase dead line or a,0ffh ret upl1: call pscreen jr upl0 ; ; Find a string ; find: call print ; Prompt db 1,'Find ->',' '+80h ld hl,finbuf ; Read string to find call readst call stndend call cr$clr ; Erase it from screen find0: ld a,(finbuf+1) ; String length or a jp z,command ; 0 length string ... abort ex af,af' ; Save it ; START SEARCH AT NEXT LINE ld hl,(srtptr) call nxline ; HL now -> next line finlp0: ld de,finbuf+2 ; First char finlp1: call fmatch ; Compare upcase of (hl) and (de) inc hl ; Bump text pointer jr nz,finlp1 ; No match, keep moving through text ; AT THIS POINT, FIRST CHAR IS MATCHED ex af,af' ; Recover string length ld b,a ex af,af' dec b ; We have already found 1 jr z,findex ; Done if only 1 char to match finlp2: inc de call fmatch jr nz,finlp0 ; No match ... start looking again inc hl ; So far, so good djnz finlp2 ; Match next chars ; THE STRING IS IN THE CURRENT LINE, MOVE IT TO TOP OF SCREEN findex: call pvline ; Find previous line call nxline ; Go to beginning of this line ld (srtptr),hl findex0: jp prnscr ; Show the screen ; MATCH ROUTINE fmatch: ld a,(hl) cp eof jr z,finot call upcase ld c,a ld a,(de) call upcase cp c ret finot: pop af ; Clear stack call cr$clr ; String not found - print message call print db 1,'"'+80h ld hl,findat ex af,af' ld b,a finot0: ld a,(hl) inc hl call pctl call stndout djnz finot0 finot1: call print db '" ???',2,' '+80h jp command ; ; Marker routines ; ; Clear marker table erase: ld hl,eramsg call qprompt jr z,erasex call initmrk erasex: jp command eramsg: db 'Erase markers 1-','9'+80h ; Initialize marker table initmrk: ld de,(text) ld hl,table+3 ld b,9 initm1: ld (hl),e inc hl ld (hl),d inc hl inc hl djnz initm1 ret ; Marker table scanner. ; Input char to match in A and HL -> table to scan. ; Return address from pointer table in HL. ; Match returns Z and char in A. Else NZ and char lost. mcase: ex af,af' ;save char xor a mcase1: ex af,af' ;restore char cp (hl) ; Match? inc hl ; Set pointer to val's addr jr z,mcase0 ; Match inc hl ; Point to next val inc hl ex af,af' ;check for list terminator cp (hl) jr nz,mcase1 ; Keep looking or -1 mcasex: ret ; No match, return NZ mcase0: ld e,(hl) ; Load address inc hl ld d,(hl) ex de,hl ret ; Go to marker # in A gomark: ld hl,marks call mcase ; Return HL has address of marker jp nz,command ; No match push af ; If deletes done, make sure we are in text ld (srtptr),hl ld de,(eosptr) ; If marker no longer in text xor a ; Go to last screen sbc hl,de jr c,gogo1 ex de,hl ; Problem, load eosptr ld (srtptr),hl gogo1: call pscreen pop af call earx jp command marks: db '0' table: dw 0 ; Table of marker addresses irpc xx,123456789 ; Generate table db '&xx' dw 0 endm db 0 ; Find the first free marker and assign it to SRTPTR auto: ld de,(text) ld b,9 ld ix,table+1 auto1: inc ix inc ix ld l,(ix) inc ix ld h,(ix) xor a sbc hl,de jr z,auto2 ; Found, # = 10-b djnz auto1 call print db 1,'No free markers',2,' '+80h autox: jp command auto2: ld a,'0'+10 sub b call ear0 jr autox ; Set marker # (A) to top of current screen ear0: ld de,(srtptr) call ear01 earx: push af call cr$clr call print db 1,'Marke','r'+80h pop af call conout call stndend ret ear01: ld hl,marks ld b,10 ear1: cp (hl) jr z,ear2 inc hl inc hl inc hl djnz ear1 ret ; Invalid marker number ear2: inc hl ld (hl),e inc hl ld (hl),d ret mark: call print db 1,'Block starts at top of screen',2,' '+80h ld hl,(srtptr) ld (table),hl jp command ; ; LIST MARKED PORTION OF FILE ; list: IF [NOT LSTOK] call print db 1,'OUTPUT TO LIST NOT ENABLED',2,0 jp command ELSE ld hl,lstmsg call qprompt ; Are we serious? (And is printer on?) jr z,list4 ; Abort ; Compute print block size ld de,(table) ; Beginning of block ld hl,(nxtptr) ; End of block xor a sbc hl,de ; Block size now in HL jp c,dblkerr ; If beginning at or after end then no go jp z,dblkerr ; Print reminder call print db 1,'Printing ...',2,' '+80h ; Set up pointers ex de,hl ; Block size in DE, start in HL push de pop bc ; Block size in HL ld de,0 ; Count # lines in DE ld a,cr list1: cpir ; Count line feeds jp po,list11 ; Loop expired inc de jr list1 list11: call plcon ; Switch output to list push de pop bc ; Count to BC inc bc ; Actually need 1 more ld hl,(table) ; Print BC lines list3: call prnline ; Output switched to list: call lbreak jr nz,list31 dec bc ld a,b or c jr nz,list3 list31: call plcoff ; Switch output to con: lsterr: ld a,bell ; Beep on finish print call conout list4: call cr$clr listx: jp command lstmsg: db 'Print from MARK','0'+80h lbreak: call breaker ret z ; no char call getchr cp 3 jr z,lbrk1 cp esc jr z,lbrk1 xor a ret lbrk1: or -1 ret ENDIF ; ; SEND INIT STRING TO PRINTER ; init$prt: IF [NOT LSTOK] jp list ELSE ld hl,initmsg call qprompt jr z,list4 ld hl,init$str call plcon ; Send it out ld b,(hl) ; Contains returned char count xor a ; Zero A or b jr z,initx ; If there was no input, just send CRLF init01: inc hl ld a,(hl) call conout djnz init01 initx: call plcoff jp command initmsg: db 'Init Printe','r'+80h ENDIF ; ; Type line on list dev ; type: IF [NOT LSTOK] jp list ELSE ld a,(tflag) ; First time only, make sure printer ON or a jr nz,type1 ld hl,typmsg call qprompt jp z,command or -1 ; Command has been executed, skip question ld (tflag),a type1: call print ; Get the line db 1,'Type ->',' '+80h ; Prompt ld hl,tbuf ld (hl),80 call readst type2: call plcon ; Send it out ld b,(hl) ; Contains returned char count xor a ; Zero A or b jr z,tex ; If there was no input, just send CRLF type3: inc hl ld a,(hl) call conout djnz type3 tex: call print db cr,lf+80h call plcoff call stndend call cr$clr ; Clear the command line jp command typmsg: db 1,'Type to LST',':'+80h ENDIF ; (LSTOK) ; Enter with HL -> message. Return Z if answer = N. qprompt: call stndout call print1 call print db '? (Y/n)',2,' '+80h call getchr cp 'N' ret ; ; Delete block ; dblock: ld hl,blkmsg call qprompt jp z,command ld de,(table) ; Beginning of block ld (dblkptr),de ; Save ld hl,(nxtptr) ; End of block ld (blkend),hl ; Save this xor a ; Compute block size sbc hl,de ; Block size now in HL jp c,dblkerr ; If beginning at or after end then... jp z,dblkerr ; Abort ld (dblksz),hl ; Save block length ld de,(nxtptr) ; Move remaining text up call dblk1 call seteos ; Recompute EOS pointer ld hl,(dblkptr) ; Reset SRT pointer ld (srtptr),hl call remark ; Check for out of bounds markers ld hl,(srtptr) ; Wind up display ld de,(text) xor a sbc hl,de call z,cls jp prnscr dblk1: ld hl,(eofptr) ; Move trailing text up xor a sbc hl,de push hl ; Move length to BC counter pop bc inc bc ; Actually, need one more count ex de,hl ; HL = end of block ld de,(dblkptr) ; DE = start of block ldir ; Move text dec de ; This is location of EOF byte ld (eofptr),de ; Reset pointer ret dblkerr: call print db 1,'Marker error',2,bell+80h jp command blkmsg: db 'Delete from MARK 0 to her','e'+80h ; Reset markers affected by deletion remark: ld b,9 ; Loop through markers ld a,'0' ; Will check markers 0..9 rem1: push bc ; Save counter ld hl,marks call mcase ; Return HL = marker #n ld (remptr),hl ; Save push af xor a ex de,hl ; Marker -> DE ld hl,(srtptr) sbc hl,de ; Block start - Marker jr nc,rem2 ; Marker before block, OK xor a ld hl,(blkend) sbc hl,de ; Block end - Marker jr nc,rem11 ; Marker inside block xor a ; Marker after block, move it up ex de,hl ; Marker -> HL ld de,(dblksz) sbc hl,de ; Marker - block size -> new location ex de,hl rem12: pop af ; Recover marker # push af call ear01 ; Reset it jr rem2 rem11: ld de,(srtptr) ; Inside block, set marker to start of block jr rem12 rem2: ld hl,(remptr) ; Marker -> HL ld de,(eosptr) ; Make sure we are inside text xor a sbc hl,de ; MARKER - EOSPTR jr c,rem3 ; OK, marker before EOS pop af ; Restore # push af ; Save it again call ear01 ; Set the pointer to start of text rem3: pop af inc a pop bc djnz rem1 ret ; Delete top line delete: ld hl,(srtptr) ; Start at top of screen ld (dblkptr),hl ; Save pointer call dnline ; Remove line from screen jr z,dele0 ; No room to move ld (blkend),hl ; Save end of block ld de,(dblkptr) ; HL-DE = dead line length xor a ; Compute block size sbc hl,de ; Block size now in HL ld (dblksz),hl ; Save block length ld de,(srtptr) ; EOF-SRT = length of remaining text call dblk1 ; Move remaining text up ld hl,(dblkptr) ; Reset SRT pointer ld (srtptr),hl ld de,(dblksz) ; Recompute EOS ld hl,(eosptr) xor a sbc hl,de ld (eosptr),hl ld hl,(nxtptr) ; Recompute NXT sbc hl,de ld (nxtptr),hl call remark ; Update markers dele0: jp command ; Set End Screen Pointer seteos: ld hl,(eofptr) ld a,(scrlns) ld b,a sete1: call pvline ; Back up one screen from end djnz sete1 ld (eosptr),hl ; Now set pointer ret ; ; WRITE BLOCK TO FILE ROUTINES ; wblock: if [not wrtok] call print db 1,'OUTPUT TO DISK NOT ENABLED',2,0 jp command else ld de,(table) ; Beginning of block ld hl,(nxtptr) ; ld (sbkptr),de ; Copy pointers ld (ebkptr),hl xor a sbc hl,de ; Block size now in HL jp c,dblkerr ; If beginning at or after end then... jp z,dblkerr ; Abort call wblocks ; Save fcb wblock1: call print db 1,'Write block to >',2,' '+80h call fcbget jr z,wblockx ; On error call logusr call open ; Does file exist? jr z,wblock2 ; No call cr$clr ld hl,fexmsg ; Append to it? call qprompt jr z,wblockx ; No ; Append to end of file wblock11: ld de,fcb ld c,35 ; Get end address call bdos ld hl,(fcb+21h) ; Decrement it dec hl ld (fcb+21h),hl ld c,33 ; Direct read of last record ld de,fcb call bdos ; Last record now in tbuf ld hl,tbuf ; Point to first eof ld bc,128 ld a,1ah cpir dec hl ld (aptr),hl ; Save it ld a,c ; How much left? inc a ld (aflag),a ; Save it and signal status jr wblock21 fexmsg: db 'File exists - Appen','d'+80h wblock2: call make wblock21: call wrtblk call close wblockx: call wblockr call cr$clr jp command ; Write Block ; sbkptr = start block ebkptr = end block ; enter with file to write open ... on exit close it wrtblk: ld hl,(ebkptr) ; Compute block size ld de,(sbkptr) xor a sbc hl,de ret c ; Oops inc hl ; # of bytes to write xor a ld (wlfflg),a ; Set LF flag ld ix,(sbkptr) ; IX -> start of block wblk1: ld a,(aflag) ; Appending? or a jr nz,wblk5 ; YES call wblk3 ; Fill tbuf with eof ld b,128 ld de,tbuf ; Move 1 record to tbuf wblk2: ld a,(wlfflg) ; LF pending from last record? or a jr z,wblk22 ; no xor a ; reset flag ld (wlfflg),a wblk21: ld a,lf ; Load the lf jr wblk23 wblk22: dec hl ; Check count ld a,h or l jr z,wblk4 ; All done, flush buffer ld a,(ix) ; Load tbuf, adding in lf's inc ix wblk23: ld (de),a inc de cp cr jr z,wblk24 djnz wblk2 wblk11: call wblk4 ; Write the buffer ret nz ; Disk full jr wblk1 wblk24: djnz wblk21 ; Room for LF or -1 ; No room ld (wlfflg),a ; Set flag jr wblk11 wblk5: ld b,a ; Remaining count for full buffer xor a ld (aflag),a ld de,(aptr) jr wblk2 ; Resume write loop wblk3: ex de,hl ; Save HL counter ld b,128 ; Fill tbuf with eof ld hl,tbuf ld a,1ah ld (hl),a inc hl djnz $-2 ex de,hl ret wblk4: push hl push ix ld c,writef ld de,fcb call bdos or a pop ix pop hl ret z ; All ok call cr$clr ; Disk full call print db 1,'Disk full. File truncated.',2,bell+80h or -1 ret ; ; FILE MANIPULATION ROUTINES ; make: ld de,fcb ld c,makef call bdos ret close: ld de,fcb ld c,closef call bdos ret wblocks: ld hl,fcb ; Save the current fcb in wbuf ld de,wbuf ld bc,36 ldir ret wblockr: ld hl,wbuf ; Restore the fcb ld de,fcb ld bc,36 ldir call logusr ret ENDIF ; write enable ; ; Read another file ; Get file name, append all that fits to end of text merge: if [not wrtok] call print db 1,'MERGE NOT ENABLED ',2,bell+80h jp command else call wblocks ; Preserve fcb merge1: call print db 1,'Read file:',2,' '+80h call fcbget jr z,mergex ; On abort call cr$clr call logusr call open ; Does file exist? jr nz,merge2 ; Yes call print db 1,'No file //',2,' '+80h jr merge1 merge2: ld hl,(eofptr) call red3 mergex: call wblockr ; Restore original fcb call cr$clr ld hl,(srtptr) jp prnscr ; ; Input a file name, make an fcb ; ; RETURN Z = ABORT, NZ = OK WITH A = USER NUMBER fcbsz equ 24 fcbget: call stndout ld hl,fcbuf call readst ; Using local routine instead of BDOS call stndend ld a,(hl) ; Pointing to returned char count or a ret z ; Nothing, quit ld b,(hl) fcbg01: inc hl ld a,(hl) call upcase ld (hl),a djnz fcbg01 ld hl,fcbfil ; Set up filename ld de,fcb call scan ; Parse it call fcbchk ; OK? jr nz,fcberr ; Something wrong inc de ; Reject blank file ld a,(de) cp ' ' jr z,fcberr ld bc,11 ; Reject ambig file ex de,hl ld a,'?' cpir jr z,fcberr fcbgx: or 0ffh ; NZ = OK ld a,(fcb+13) ret fcberr: call cr$clr call print db 1,'Invalid // Name >',2,' '+80h jp fcbget ENDIF ; wrt block enable logusr: ld a,(fcb+13) ld (usr),a ld e,a ld c,sguserf call bdos ret usr: ds 1 open: ld de,fcb ; Returns Z if no file found ld c,openf call bdos cp 0ffh ret ; Read file into buffer getfil: ld hl,(bdos+1) ; BDOS location ld a,(2) ; Get BIOS page sub h ; Get offset cp 0eh ; Compare to standard ld a,h jr nz,getf1 ; CCP protected by RSX sub 9 ; Enough for CCP getf1: sub 1 ; For markers at end of file ld h,a ld (topmem),hl ; Store as top of memory getfil1: ld c,setdmaf ld de,tbuf call bdos ; ld hl,fcb+1 ; ld bc,11 ; Reject ambiguous file spec ; ld a,'?' ; cpir ; jp z,nope call logusr call open jp z,nofile ; Open fails xor a ld (eoflag),a ; Flag = EOF not encountered. ; FILE READ LOOP ; File read into tbuf, MSB masked, lf stripped, transfered to text buffer ld de,(text) ; Start of text pointer getlp1: ld hl,(topmem) ; Check memory full xor a sbc hl,de jr c,toobig ; Yes push de ld de,fcb1 ; Read a record ld c,readf call bdos pop de call loadfil ; Load it into text buffer jr z,getlp1 ; Keep reading, eof not encountered geteof: ld (eoflag),a ; Set EOF flag ret ; MOVE RECORD INTO TEXT BUFFER loadfil: ld hl,tbuf ld b,80h ldfil01: ld a,(hl) inc hl and 7fh ; Mask MSB cp lf jr z,ldfil02 ; Skip lf cp eof jr z,ldfil03 ; Done, set up EOF pointers ld (de),a inc de ldfil02: djnz ldfil01 xor a ; Z = not done ret ldfil03: ld a,cr ; Add a cr to the end ld (de),a inc de ld a,eof ; Mark end with eof ld (de),a ld (eofptr),de ; Save location or -1 ; NZ = done ret ; FILE HAS FILLED AVAILABLE MEMORY, PRINT WARNING toobig: push de call print db 'Memory Full ',bell+80h call wait1s pop de jr ldfil03 ; Read no more ; Read more file or start again read: ld a,(eoflag) ; Has EOF been encountered. or a jr nz,rdmsg ; If so, send message ld hl,(eofptr) dec hl ; Back up over last cr ld a,(hl) ; Unless everything has been deleted cp cr jr z,red1 inc hl red1: call red3 jp prnscr red3: ex de,hl call getlp1 ; Fill memory with more of file call seteos ret rdmsg: ld hl,readmsg call qprompt jp z,command call cls read1: ld hl,fcb+12 ld b,4 read2: ld (hl),0 inc hl djnz read2 ld a,(usr) ; Restore user number ld (fcb+13),a ld hl,fcb+32 ld (hl),0 call getfil1 jp resrt readmsg: db 'No more to read. Start ove','r'+80h ; Print file name what: call print db 1,'File:',' '+80h call pfil call stndend jp command pfil: call pdsk ; Print du:file.typ call pusr ld a,':' call conout call pfn ret pdsk: ld a,(fcb) ; Print file disc cp 0 jr nz,pdsk0 ld c,25 call bdos inc a pdsk0: add a,'A'-1 jp conout pusr: ld a,(usr) cp 10 jr c,pusr0 ; User # 0..9 ld b,0 ; 10's counter pusr1: sub 10 inc b cp 10 jr nc,pusr1 push af ld a,'0' add b call conout ; Print 10's pop af pusr0: add a,'0' jp conout ; Print remainder pfn: ld b,8 ; Print file name ld hl,fcb+1 call pfn0 push hl ld a,'.' call conout pop hl ld b,3 pfn0: ld a,(hl) cp ' ' jr z,pfn1 call conout pfn1: inc hl djnz pfn0 ret ; Help screen display info: IF EXPERT jp what ELSE call cls ; Show HELP info on request call help call print db cr,lf,'FILE:',' '+80h call pfil call retcrs call print db 1,'... any key ...',2,' '+80h call getchr call cls jp prnscr help: call vprint db cr,lf,tab,tab,tab,1,'<<<< VIEW ' db vers/10+'0','.',vers mod 10+'0' db ' COMMANDS >>>>',2 db cr,lf,lf db cr,lf db '|',1,'ESC',2,'| Halt Listing' db ' ',1,' 1 2 ...',2,' Go To Mark # ',1,'... 9 0 ',2 db ' ',1,'+',2,'|',1,'-',2,' Scan Speed',cr,lf db cr,lf db ' Quick Write Erase Delete Delete',cr,lf db ' Mark Block Marks Read Type Line Block ' db ' Init Mark Print',cr,lf db ' --- --- --- --- --- --- ---' db ' --- --- ---',cr,lf db ' |',1,' Q ',2,'| |',1,' W ',2,'| |',1,' E ',2,'| ' db '|',1,' R ',2,'| ' db '|',1,' T ',2,'| |',1,' Y ',2,'| |',1,' U ',2,'|' db ' |',1,' I ',2,'| |',1,' O ',2,'| |',1,' P ',2,'|',cr,lf db ' --- --- --- --- --- --- ---' db ' --- --- ---',cr,lf db ' --- --- --- --- --- --- ---' db ' --- --- ---',cr,lf db ' |',1,' A ',2,'| |',1,' S ',2,'| |',1,' D ',2,'| ' db '|',1,' F ',2,'| |',1,' G ',2,'| |',1,' H ',2,'| |',1 db ' J ',2,'|' db ' |',1,' K ',2,'| |',1,' L ',2,'| |',1,' ; ',2,'|',cr,lf db ' --- --- --- --- --- --- ---' db ' --- --- ---',cr,lf db ' End Scan Next Next Find Find Up ' db ' Up R/Scan Top',cr,lf db ' Line Screen RPT Screen' db ' Line',cr,lf db cr,lf,1,'X',2,' - Exit ',1,'M',2,' - Merge ' db 1,'',2,' - Hop 10 lines ',1,'',2,' - F ' db 1,'?,/',2,' - Help, File Name' db cr,lf,0 ret ENDIF ; (EXPERT) ; ; Utilities ; cr$clr: ld a,cr ; Print CR, CLREOL call conout clreol: call ereol ret homcrs: call at db 1,1 ; Put your home cursor sequence here ret inslin: push hl call homcrs ld hl,inscrt call print1 ; Insert a blank line at top of screen call clreol pop hl ret retcrs: call at prrow: db 24 db 1 ret wait: ld a,(scanspd) ; Slow down continuous scrolling ld b,a inc b call wait1ms djnz $-3 ret ; ; DISPLAY CONTROL CHARACTERS AS ^n ; pctl: cp 7fh ; Don't print DEL ret z cp 20h jp nc,conout ; Not a control ; We have a control push af ; save char ld a,(lflag) ; send stndout if not listing? or a call z,stndout ld a,'^' call conout pop af ; restore char add 40h ; make it printable call conout inc c ; bump tab expansion counter for "^" char push af ; send stndend if not listing ld a,(lflag) or a call z,stndend pop af ret ; SWITCHING CONOUT plcon: xor a dec a ld (lflag),a ; Flag ld a,listf ; Switch to lst: output plcon1: ld (clsw),a ; Poke list byte at ld c,bdosf ret plcoff: xor a ld (lflag),a ld a,wrconf ; Switch to con: output jr plcon1 conout: ; Print char in A push hl push de push bc push af and 7fh ld e,a clsw equ $+1 ld c,wrconf call bdos pop af pop bc pop de pop hl ret vprint: print: ex (sp),hl ; Get address call print1 ex (sp),hl ; Put address ret ; ; Print String (terminated in 0) pted to by HL ; print1: ld a,(hl) ; Done? inc hl ; Pt to next or a ; 0 terminator ret z cp dim ; Standout? jr z,print1d cp bright ; Standend? jr z,print1b call conout ; Print char or a ; MSB set? ret m jr print1 print1d: call stndout ; Dim jr print1 print1b: call stndend ; Bright jr print1 getc: push hl ; Get a character via BIOS push bc getc1: ld c,dirconf ld e,-1 call bdos or a ; Nothing entered yet jr z,getc1 pop bc pop hl ret getchr: ld c,rdconf ; Get a char and erase line call bdos push af call cr$clr pop af ; Fall through to upcase upcase: cp 'a' ; Upcase char in A ret c cp 'z'+1 ret nc and 5fh ret ; ; Case - jump table scanner, version 1.1 ; Affect only alternate registers. ; Format: call case ;call with value to match in A ; db val1 ;first val to match ; dw addr1 ;jump address ; ... ; db 0 ;end table ; else next instuction executes if no match case: exx ; Preserve regs ex (sp),hl ; Hl -> next addr after call ex af,af' ;save char xor a case1: ex af,af' ;restore char cp (hl) ; Match? inc hl ; Set pointer to val's jump addr jr z,case0 ; If match, jump inc hl ; Point to next val inc hl ex af,af' ;check for list terminator cp (hl) jr nz,case1 ; Keep looking inc hl ; No match, execute next instruction ex af,af' ;restore A casex: ex (sp),hl exx ; Restore other regs ret case0: ld e,(hl) ; Load address inc hl ld d,(hl) ex de,hl jr casex ; Go ; READ STRING routine ; Input: hl -> buffer ; buf: db n ; max chars ; db 1 ; char count ; ds n+1 ; buffer space ; Input terminated by . On return HL -> char count ; Enter CR, 0(@), DEL, ^X or ^P as ^Pn. Others may be entered directly. readst: ld b,(hl) ; Hl -> max chars ld c,b ; Preserve it in c inc hl ; Pointing to returned char count push hl ; Save this inc hl ; Pointing to buffer rds1: call getc ; Get a char cp cr ; Done? jr z,rds0 cp del ; Correction jr z,rds2 cp bs jr z,rds2 cp 'X'-'@' jr z,rds3 cp 'P'-'@' ; ^P call z,rds4 ld (hl),a ; Save char call pctl ; Echo char inc hl djnz rds1 ; Get more inc hl rds0: ld (hl),0 ; Terminating 0 ld a,c ; Calculate # chars sub b pop hl ; Returned char addr ld (hl),a ret ; Exit routine rds2: call rds20 jr rds1 rds20: ld a,b ; At beginning of buffer/line? cp c ret nc ; Yes, skip delete dec hl ; Back up inc b ; Restore count ld a,(hl) cp 20h ; Ctl char? call c,rds21 ; Yes, double backspace rds21: push hl call print ; Erase screen echo db bs,' ',bs+80h pop hl ret rds3: ld a,c ; ^X erase line sub b jr z,rds1 ld b,a rds31: push bc call rds20 pop bc djnz rds31 ld b,c jr rds1 rds4: call getc ; ^P option, get next char cp 40h ; < '@' ? ret c ; Yes, leave it alone and 5fh ; Upcase it sub 40h ; Convert to control ret breaker: push hl push bc ld c,constf call bdos or a pop bc pop hl ret ; ; Wyse video here if selected if hardvid include hardvid.lib endif ; ; EXITS ; nope: call print db 'VIEW, Ver ',vers/10+'0','.',vers mod 10+'0' db cr,lf db 'Syntax: VIEW [du:|dir:]ufn',0 IF [NOT EXPERT] call help ENDIF jp exit nofile: call pfil call print db ' not found',' '+80h jr exit nowhl: call print db 'ERR: WHEEL',0 jr exit nocrt: call print db 'ERR: CRT < 80x24',0 jr exit novid: call print db 'ERR: INSTALLATION/TCAP',0 jr exit noz33: call print db 'NEED ZCPR33',0 jr exit exit0: call cls exit: call dinit ld sp,(stksav) ; Restore stack pointer ret ; To CCP ; ; DATA ; if wrtok fcbuf: db fcbsz fcbcnt: ds 1 fcbfil: ds fcbsz+1 sbkptr ds 2 ebkptr ds 2 wlfflg ds 1 wbuf: ds 36 aflag: ds 1 aptr: ds 2 endif finbuf: db fbufsz ds 1 findat: ds fbufsz+1 ; Buffer dblksz: ds 2 dblkptr: ds 2 remptr: ds 2 blkend: ds 2 width ds 1 scrlns ds 1 lflag ds 1 tflag ds 1 filptr ds 2 ; Scratch pointer eoflag ds 1 ; EOF encountered flag srtptr ds 2 ; Start Pointer -> beginning of screen nxtptr ds 2 ; Next Pointer -> beginning of next screen eosptr ds 2 ; End of Screen Pointer -> last screen eofptr ds 2 ; End of File Pointer -> end of text topmem ds 2 ; Top of Memory stksav ds 60 ; Save incoming stack pointer stack equ $ ; Top of local stack text ds 2 end start