home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
zcpr33
/
z3-33
/
z33ver10.lbr
/
Z33VER10.ZZ0
/
Z33VER10.Z80
Wrap
Text File
|
1987-10-15
|
38KB
|
1,691 lines
; PROGRAM: Z33VERR
; DATE: Oct 10,1987
; VERSION: 1.0
; Version 1.0
; This version fixes a bug which caused the screen to be cleared
; any time the program was invoked. I also now make Z33VERR look
; at the quiet flag before printing it's install message. There
; is also a new command line parameter 'S' which will inhibit
; the initial screen clear when an error is detected. Also added
; <CR> as an alias to 'E'dit, <ESC> as an alias to 'A'bort, and
; <SP> as an alias to 'C'ontinue.
; Version 0.9
; This version fixes a long standing bug in VERROR which causes the
; error command to be repeated if you answer no the 'Do you wish to
; edit this command ?' question when the shell stack is not empty.
; Thanks to Jay Sage for Z33ERROR & Paul Pomerleau for VERROR.
; Without the work of these authors, this program would not exist.
; Also thanks to Rick Charnes for proding me to fix the shell bug.
;
; Royce Shofner
; Version 0.8
; This program combines the ZCPR33 prototype error handler (Z33ERR07)
; with VERR17A to produce an inteligent error handler for systems using
; ZCPR33. The internal command line modification routines in Z33ERR07
; have been removed & replaced with the entire VERR17A program. The only
; other changes made to Z33ERR07 is in the submit file delete routine. I
; added a test to inform the user in case the submit file could not be
; deleted (possibly because the system vectors had been modified & ZCPR33
; couldn't be found).
;
; Royce Shofner
;=============================================================================
;
; This section of code is derived from Z33ERR07
;
;=============================================================================
;=============================================================================
;
; D E F I N I T I O N S S E C T I O N
;
;=============================================================================
version equ 10
no equ 0
yes equ not no
bell1 equ yes ; Beep at user on entering error handler
bell2 equ yes ; Beep at user on extra prompts (ZEX/SUBMIT)
cls1 equ yes ; Clear screen when error is detected
cret equ 0dh
lf equ 0ah
bell equ 07h
tab equ 09h
esc equ 1bh
bdos equ 0005h
bios equ 0000h
fcb1 equ 005ch
; Z33LIB references
extrn qerror,getccp,getsrun,haltsub,z33chk
extrn gcmddu,geter3,subon
; Standard library references
extrn z3init
extrn getefcb,getcst,putcst,geterc,getwhl,erradr,getcl1
extrn cout,print,pstr,crlf,qprint,qpstr
extrn mafdc,pafdc
extrn getzrun,haltzex
extrn capin,bline
extrn acase1
extrn getquiet
extrn codend
;=============================================================================
;
; S T A N D A R D P R O G R A M H E A D E R
;
;=============================================================================
cseg
entry:
jp start
defb 'Z3ENV'
defb 3 ; Type-3 environment
envaddr:
dw 0
dw entry
defb version
;=============================================================================
;
; C O N F I G U R A T I O N A R E A
;
;=============================================================================
; Allow bell to sound on error
defb 'BEEPS'
bell1fl:
defb bell1
bell2fl:
defb bell2
defb 'CLS'
clsflg:
defb cls1
defb 'END'
;=============================================================================
;
; M A I N C O D E S E C T I O N
;
;=============================================================================
start:
ld hl,(envaddr) ; Get environment address
call z3init ; Initialize library routines
call z3vini ; initialize vlib
call tinit ; initialize the terminal
jr start1
; We really should set up our own local stack, but I am going to skip
; that for now.
qbanner:
call getquiet
ret nz
banner:
call print ; Display the program header
defb cret,lf
defb ' Z33VERR Version '
defb version / 10 + '0'
defb '.'
defb version mod 10 + '0'
defb cret,lf,0
ret
start1:
ld a,(fcb1+1) ; Check for help request
cp '/'
jr z,help
cp '?'
jr nz,main
help:
call banner
call print
defb cret,lf
defb ' Syntax: ',0
call name
call print
defb ' [Q][S]',cret,lf
defb tab,'[Q]....quiet option (no bells)',cret,lf
defb tab,'[S]....inhibit initial clearScreen',cret,lf,0
ret
main:
call qerror ; See if error handler invocation
jp z,errorh ; If so, branch to error processing
call qbanner ; Print install message if not quiet
;=============================================================================
;
; I N S T A L L A T I O N C O D E
;
;=============================================================================
; Program was invoked manually, so we need to set it up as the error handler.
;----------------------------------------
; Subtask 1 -- determine whether to use a DU, a DIR, or no prefix
;
; The program can examine the ZCPR33 option bytes to determine what features
; are supported (DU and/or DIR forms, which one first, wheel control over DU
; use, etc.). For now I will just assume that a DU prefix will be used and
; will omit coding this block.
job1:
;----------------------------------------
; Subtask 2 -- build error handling command line including directory prefix
; using data from the external FCB. We use the fact that the drive and user
; where the program was actually found along the path are stored in the
; command file control block. The user number is kept in the usual place;
; the drive is kept in the following byte. The drive is in the range 1..16
; (unless the command is resident, in which case the drive byte is 0).
job2:
call gcmddu ; See if we were invoked by GO or JUMP
inc b ; Shift drive back to range 1..16
jr nz,job2a ; If we were not, branch ahead
call qprint ; If drive = 0, we have a resident command
defb bell,' Cannot be installed using GO or JUMP',cret,lf,0
ret
job2a:
call geterc ; Get address of error command line
ex de,hl ; ..into DE
call z33chk ; Make sure we have ZCPR33
jr nz,job2b ; Branch if not
; If ZCPR33, use information in external command FCB to determine drive and
; user number where the file was found.
call gcmddu ; Set BC to directory where program was found
ld a,b ; Work on drive first
add a,'A' ; Convert it to a letter
ld (de),a ; Save in error command line
inc de ; Increment command line pointer
ld a,c ; Work on user number next
call mafdc ; Convert it to decimal number in command line
ld a,':' ; Put in the colon
ld (de),a
inc de
job2b:
call getefcb ; Get pointer to name of this program
inc hl
ld bc,8 ; Copy 8 characters of name
ldir ; ..into error command line
ld a,' ' ; Add a space
ld (de),a
inc de
ld a,(fcb1+1) ; Copy any option character(s) on command line
ld (de),a
inc de
ld a,(fcb1+2)
ld (de),a
inc de
xor a ; Store terminating null
ld (de),a
;----------------------------------------
; Subtask 3 -- Report installation to the user
job3:
call qprint
defb ' Error handling command line set to: ',0
call geterc ; Get pointer to error command line
call qpstr ; Print the string there
call getquiet
ret nz
jp crlf ; One extra line and quit
;=============================================================================
;
; E R R O R H A N D L I N G C O D E
;
;=============================================================================
; This is the main entry point for error handling
errorh:
;----------------------------------------
; Subtask 1 -- Display program signon message and determine whether Z33 is
; running or not. Check for the 'Q' (quiet) command line option. Optionally
; beep the bell. Also test for the 'S' (clearScreen) command line option and
; clear screen if indicated.
task1:
ld a,(fcb1+1) ; Get any option character
call task1a ; test for 'Q'
jr z,task1b
ld a,(fcb1+2)
call task1a
jr task1b
task1a:
cp 'Q' ; If not quiet option, skip ahead
ret nz
ld hl,0 ; Clear the bell flags
ld (bell1fl),hl
ret
task1b:
ld a,(bell1fl)
call beep
task1c:
ld a,(fcb1+1) ; Get any option character
call task1d ; test for 'S'
jr z,task1e
ld a,(fcb1+2)
call task1d
jr task1e
task1d:
cp 'S' ; If not cls option, skip ahead
ret nz
xor a ; reset the clear screen flag
ld (clsflg),a
ret
task1e:
ld a,(clsflg) ; clear screen ?
or a
call nz,cls ; if not 'S' option
call banner ; tell who we are
;----------------------------------------
; Subtask 2 -- Display system status
; This task checks to see if there is anything about the system status that
; might be useful to the user in determining the cause of the error.
; Specifically, if either ZEX or SUBMIT is running or if the wheel byte is off,
; the user is given this information. If not, there is no output.
task2:
call z33chk ; Check for ZCPR33 running
jp nz,task4 ; If not, show only the bad command line
call getzrun ; See if there is anything interesting
jr nz,task2a ; ..to report (ZEX or SUBMIT running or
call getsrun ; ..wheel byte off)
jr nz,task2a
call getwhl
jr nz,task3 ; If none of above, on to task3
task2a:
call print
defb ' Status: ',0
call getzrun ; Find out if ZEX is running
jr z,task2b ; Skip ahead if not
call print
defb ' ZEX running',0
task2b:
call getsrun ; Find out if SUBMIT is running
jr z,task2c ; Skip ahead if not
call print
defb ' SUBMIT running',0
task2c:
call getwhl ; Find out if wheel is off
jr nz,task2d ; If not, on to task3
call print
defb ' WHEEL OFF',0
task2d:
call crlf ; End the line
;----------------------------------------
; Subtask 3 -- Display information about the type of error: error number,
; internal or external, and description.
task3:
call print
defb ' Error Type:',tab,0
call getcst ; Get command status flag
bit 3,a ; See if external command bit is set
jr nz,task3a ; Branch if external error
call print
defb 'CPR/ECP: (#',0
jr task3b
task3a:
call print
defb 'External: (#',0
task3b:
call getcst ; Get the command status flag
res 1,a ; ..and clear the error
res 2,a ; ..and ECP bits
call putcst ; Store the modified value
call geter3 ; Get the command error code
call pafdc ; Display the number
call print
defb ') ',0
ld hl,task3c ; Set up return address
push hl ; ..on stack
call geter3 ; Get command error code again
call acase1 ; CASE function
defb 11 ; Eleven cases
defw unknown ; Default case
defb 1
defw duchange ; Illegal attempt to change directory
defb 2
defw baddu ; Invalid directory
defb 3
defw badpw ; Incorrect password
defb 5
defw badform ; Bad command form (wild or type given)
defb 6
defw badecp ; Command not found by CPR or ECP
defb 7
defw badcmd ; Command file not found by CPR
defb 8
defw ambig ; Ambiguous file spec
defb 9
defw badnum ; Bad numerical value
defb 10
defw nofile ; Object file not found
defb 11
defw diskfull ; Disk is full
defb 12
defw tpafull ; TPA overflow
duchange:
call print
defb 'Illegal attempt to change directory',0
ret
baddu:
call print
defb 'Invalid directory specification',0
ret
badpw:
call print
defb 'Incorrect password',0
ret
badform:
call print
defb 'Bad command form (file type / wild card)',0
ret
badecp:
call print
defb 'Command not found by CCP or ECP',0
ret
badcmd:
call print
defb 'Requested load file not found',0
ret
ambig:
call print
defb 'Ambiguous or missing file name',0
ret
badnum:
call print
defb 'Bad numerical expression',0
ret
nofile:
call print
defb 'Requested operand file not found',0
ret
diskfull:
call print
defb 'Disk full',0
ret
tpafull:
call print
defb 'TPA full (program too big)',0
ret
unknown:
call print
defb 'Unknown error type',0
ret
task3c:
call crlf ; End the line
;----------------------------------------
; Subtask 4 -- Display bad command line
;
; In the final code, much more elaborate error processing would be performed
; here (or more likely, the code here will be used as a framework for existing
; error handlers).
task4:
call print
defb ' Bad Command:',tab,0
call erradr ; Get pointer to bad command line
push hl ; Save for reuse below
scan: ; Find end of this command
ld a,(hl)
or a ; See if end of command line buffer
jr z,task4a
cp ';' ; See if at command separator
jr z,task4a
inc hl ; Point to next character
jr scan ; Continue scanning
task4a:
ld (hl),0 ; Mark end of string
ld (delimptr),hl ; Save ptr to bad command's delimiter
ld (delim),a ; Store delimiter
pop hl ; Restore pointer to beginning of command
push af ; Save delimiting character
call pstr ; Display the bad command
push hl ; Save pointer to rest of command line
call print
defb cret,lf
defb ' Rest of Line:',tab,0
pop hl
pop af ; Get back delimiter of bad command
or a
jr nz,task4b ; Branch if there are more commands
call print
defb 'none',0
jr task4c
task4b:
dec hl ; Pt back to bad command delimiter
ld (hl),a ; Put semicolon back
inc hl
call pstr ; Print rest of command line
task4c:
call crlf ; End the line
;----------------------------------------
; Subtask 5 -- Deal with the bad command
; This is where the real error handling is performed. With normal command
; lines (ZEX and SUBMIT not running), the user has the following three basic
; choices: fix the bad command, skip the bad command, or abort the entire
; command line. If ZEX is running, there is an additional choice that should
; be available: abort the entire ZEX script. Similarly, if SUBMIT is running,
; the user must be given the option to abort the entire submit job.
; This code implements all of the above with the additional feature
; that if the bad command is the last on the line, the option to skip
; to next command is not presented as it would be meaningless. Similarly, if
; neither ZEX nor SUBMIT is running and there are no pending commands, there
; is nothing the user can do, so the code just returns.
task5:
call abort ; test for ZEX and/or SUBMIT
task5a:
call print
defb cret,lf,' Your options:',tab
defb "'E' or <CR>.....Edit command line"
defb cret,lf,tab,tab
defb "'A' or <ESC>....Abort entire command line",0
ld a,(delim) ; Get bad command delimiter
or a
jr z,task5b ; No trailing commands; skip next option
call print
defb cret,lf,tab,tab
defb "'C' or <SP>.....Continue with rest of command line",0
task5b:
call print
defb cret,lf,' Enter choice: ',0
call capin ; get response
ld b,a ; Save for a moment
ld a,(delim) ; Get command delimiter again
or a
ld a,b ; Response back in A
jr z,task5c ; Don't allow 's' choice if no trailing command
cp 'C' ; Continue?
jr z,skip
cp ' ' ; <space> is alias for continue
jr z,skip
task5c:
cp 'A' ; Abort?
jp z,abortmsg
cp esc ; Abort ?
jp z,abortmsg
cp 'E' ; Edit?
jp z,verror
cp cret ; Edit?
jp z,verror
call print
defb bell,0
jr task5b
;-----------------------------------------------------------------------------
; Skip over bad command and resume with next in line
skip:
call getcl1 ; Pt to command line buffer
ld de,(delimptr) ; DE pts to bad command's delimiter
inc de ; Now pointing to next command
ld (hl),e ; Stuff address in
inc hl ; ..first two bytes
ld (hl),d ; ..of multiple command line buffer
call print
defb ' Continuing ...',cret,lf,0
ret ; Resume command execution with next command
;=============================================================================
; Abort zex job and/or submit job
abort:
call getzrun ; See if ZEX is running
jr z,abort2 ; Branch if not
; Deal with running ZEX script
ld a,(bell2fl)
call beep
call print
defb ' Abort ZEX script (Y/N)? '
defb 0
call getyesno ; Get user's answer
jr nz,abort1 ; Branch if negative response
call haltzex ; Abort ZEX
call abortmsg
jr abort2
abort1:
call print
defb ' No'
defb cret,lf,0
; Deal with running SUBMIT job
abort2:
call getsrun ; Is a submit job running
ret z ; If not, return to command processor
ld a,(bell2fl)
call beep
call print
defb ' Abort SUBMIT job (Y/N)? '
defb 0
call getyesno ; Get user's answer
jr nz,abort3 ; Branch if negative response
call subon
jr z,abort3 ; if ZCPR33 not found
call haltsub ; Abort SUBMIT
abortmsg:
call print
defb ' Aborted'
defb cret,lf,0
ret ; Back to command processor
abort3:
call print
defb ' Not ',0
jr abortmsg
;-----------------------------------------------------------------------------
; BEEP -- sound bell if flag in A is nonzero
beep:
or a
ret z
call print
defb bell,0
ret
;-----------------------------------------------------------------------------
; GETYESNO -- get yes/no answer from user
; Only 'Y' or 'y' accepted as affirmative answers. Routine returns Z if
; affirmative, NZ otherwise.
getyesno:
call capin ; Get user response
cp 'Y'
ret
;-----------------------------------------------------------------------------
; PONOFF -- Print ON or OFF in message
;
; If the Z flag is set on entry, 'OFF' is displayed; otherwize 'ON' is
; displayed.
ponoff:
jr z,poff
call print
defb 'ON',0
ret
poff:
call print
defb 'OFF',0
ret
;-----------------------------------------------------------------------------
; NAME -- Display name of command
name:
call getefcb
ld b,8 ; Maximum number of characters in name
name1:
inc hl
ld a,(hl)
cp ' ' ; If space, we are done
ret z
call cout ; Display the next character
djnz name1 ; Work through them
ret
;=============================================================================
;
; B U F F E R S
;
;=============================================================================
dseg
delimptr:
defs 2 ; Pointer to bad command's delimiter
delim:
defs 1 ; Bad command's delimiting character
;=============================================================================
;
; The following code is derived from VERR17
;
;=============================================================================
cseg
extrn z3vini, stndou, stnden ; VLIB
extrn cls, tinit, ereol, gotoxy
extrn dutdir ; Z3LIB
extrn caps ; SYSLIB
;
; customization equates
;
false equ 0
true equ not false
vhelp equ true ; include help information?
inverse equ true
;
; basic definitions
;
quoffs equ 28h ; quiet byte offset
ca equ 'A'-'@'
cc equ 'C'-'@'
cd equ 'D'-'@'
ce equ 'E'-'@'
cf equ 'F'-'@'
cg equ 'G'-'@'
ch equ 'H'-'@'
cj equ 'J'-'@'
ck equ 'K'-'@'
cl equ 'L'-'@'
cm equ 'M'-'@'
cp equ 'P'-'@'
cq equ 'Q'-'@'
cr equ 'R'-'@'
cs equ 'S'-'@'
ct equ 'T'-'@'
cu equ 'U'-'@'
cv equ 'V'-'@'
cx equ 'X'-'@'
cy equ 'Y'-'@'
del equ 7FH
;
; process faulty command buffer
;
verror:
;
; initialize command buffer
;
call getcl1
push hl
ld de,buffer
ld bc,04h
ldir ; move the first 4 bytes of the command
; buffer to our copy of it.
call erradr ; get address of faulty command
ex de,hl ; put it into de
pop hl ; old buffer
push de
ld de,5
add hl,de
pop de
ex de,hl
or a
sbc hl,de ; get difference of new and old pointer
ld c,l
ld b,h ; put it into bc
call getcl1
ld de,5
add hl,de ; beginning of actual command in buffer
ld de,text + 1 ; our beginning of buffer
add hl,bc
ld bc,0ffh ; we can over shoot. won't hurt anything
ldir ; move z3's to ours
edit:
;
; initialize kill buffer
;
ld a,0
ld (kill),a
;
; set up screen for editing
;
call cls ; clear the screen
jp z,notcap ; if it's not covered, we can't do it
ld hl,101h ; top of screen
call gotoxy ; position cusor so we can check for function
jp z,notcap ; bomb out if not covered
call ereol ; blast line so we can check for function
jp z,notcap ; bomb out if not covered
call stndou ; make dim
ld de,instr
call string ; tell 'em what they're using
ld e,':'
ld c,2
call bdos ; put a colon at the end of it
ld hl,012ah
call gotoxy
ld c,25
call bdos ; get the drive
push af
add a,'A' ; make it a letter
ld c,a
call write ; write it
ld e,0ffh
ld c,32
call bdos ; get the user
call pafdc ; write it as a number
ld c,a
pop af ; get drive
ld b,a
call dutdir ; get the ndr
jr z,namedone
push hl
ld c,':'
call write ; and the colon to seperate
pop hl
ld b,8 ; eight chars max
nameloop:
ld a,(hl) ; get the first char
cp ' ' ; is it the last
jr z,namedone ; yup. done
push hl
ld c,a
call write ; write it
pop hl
inc hl
djnz nameloop ; repeat
namedone:
ld c,'>' ; print a '>'
call write
;
if vhelp
call showhelp
endif
;
call stnden ; make normal
;
; initialize buffer for editing
;
xor a ; a := 0
ld bc,0ffh
ld hl,text + 1
cpir ; find the zero at the end of the line
ld a,c
cpl ; a := 255 - a
ld (length),a ; store that in length
ld hl,point
ld (hl),1 ; put us at the start of the buffer
call draw ; write the buffer to screen
;
; main program: keep calling loop
;
doloop: call loop ; execute the editing
jr doloop ; continue this
;
; get input and determine what action results
;
loop:
xor a
ld (beeper),a
call getkey ; bring in a character
ld hl,cmdstr
ld bc,cmdlst - cmdstr
cpir ; compare to cmdstr
jr nz,notcmd ; no match, check for insertion
ld a,cmdlst - cmdstr - 1
sub c ; get difference (how far in the command is)
add a,a ; double it (compensation for dws)
ld c,a ; put that offset in bc
ld hl,cmdlst
add hl,bc ; add it to cmdlst
ld e,(hl) ; get low byte
inc hl
ld d,(hl) ; get high byte
ex de,hl ; put location in hl
jp (hl) ; and go to that location
cmdstr:
db cs,ch,cd,cl,ce,ck,cx,cj,ca,cf
db cc,cg,del,ct,cr,cu,cv,cp,cy,cm
if vhelp
db cq
endif ; help
cmdlst:
dw left
dw left
dw right
dw right
dw up
dw up
dw down
dw down
dw wleft
dw wright
dw cright
dw delrt
dw dellft
dw delwrd
dw delcmd
dw undo
dw flmode
dw vprint
dw quit
dw done
if vhelp
dw needhelp
endif ; help
notcmd:
cp ' ' ; is it a control char that is unallocated?
ret c ; if so, return
cp '{' ; is it lower-case?
jr nc,notlow ; no
cp 'a'
jr c,notlow ; no
sub ' ' ; yes. so up-case it
notlow:
jr putchar ; and enter it
;
; get next key for entry no matter what it is.
;
vprint:
call getkey ; bring in a key
; don't strip control or lower-case chars
;
; put a character (in a) into current position
;
putchar:
ld (char),a ; save the character
ld a,(mode) ; consider mode
or a
jr z,insert ; if mode is 0 then insert, else overwrite
put:
ld a,(point)
ld hl,length
cp (hl) ; find out if this is the null
jr z,insert ; we're at the end so insert
ld de,text
ld l,a
ld h,0
add hl,de ; find the place where the cursor is
ld a,(char)
ld (hl),a ; put the character there
call vwrite ; print it
jp right ; bump the cursor
insert:
ld hl,length
ld a,(maxlen)
cp (hl)
jp z,beepit ; if line would be too long then signal
ld a,(hl) ; a := length
ld l,a
ld h,0
ld de,text
add hl,de ; last character in hl
ld e,l
ld d,h
inc de ; last character + 1 in de
push hl
ld hl,point
sub (hl) ; a := length - point
inc a ; a := a + 1
ld c,a
ld b,0
pop hl
lddr ; move everything over one
ld hl,length
inc (hl) ; add one to the length
ld a,0ffh
ld (ins),a
ld a,(silent)
or a
call z,draw ; refresh the display
xor a
ld (ins),a
jr put ; now toss in the character
;
; put buffer into multi command buffer and reset values
;
done:
ld a,h ; get whether indexed or not
push af
ld hl,point
ld (hl),4 ; move pointer to beginning
ld hl,buffer + 1
call getcl1 ; get location of command line
push hl
ld de,buffer
ex de,hl
ld a,(length)
add a,4 ; move length + 4 bytes
ld c,a
ld b,0
ldir ; move our buffer to z3's
pop hl ; consider command line location
push hl
ld de,4
add hl,de ; calculate first character (cmd line + 4)
pop de
ex de,hl ; put it in de and
ld (hl),e
inc hl
ld (hl),d ; and store that to z3's pointer
pop af ; get whether to do position or not
pop hl ; remove loop's return location
or a
ret z ; if hl was not used for index, h = 0
;
if vhelp
ld hl,1701h
ld a,(hlpflg)
or a
jr nz,dogoxy
endif ; help
;
ld hl,701h
dogoxy: jp gotoxy ; move cursor to clear and exit
;
; abort editing
;
quit:
pop hl ; remove loop's return location
ld hl,301h
call gotoxy ; move cursor to beginning of line
call drclr
;
if vhelp
ld hl,1701h
ld a,(hlpflg)
or a
jr nz,qugoxy
endif ; help
;
ld hl,701h
qugoxy: jp gotoxy ; move cursor to clear and exit
;
; provide list of commands
;
;
if vhelp
needhelp:
ld a,0ffh
ld (hlpflg),a
call showhelp
call stnden
jp gopos
endif ; help
;
;
; bring back text from last delete word
;
undo:
ld a,0ffh
ld (silent),a
ld hl,kill
udloop: ld a,(hl)
or a
jr z,undone
push hl
call putchar
pop hl
inc hl
jr udloop
undone:
xor a
ld (silent),a
jp draw
;
; flip between insert and overwrite mode
;
flmode:
ld hl,140h
call gotoxy ; goto approx center of screen
ld hl,mode ; consider mode
ld a,(hl)
cpl ; make (255 := 0) or (0 := 255)
ld (hl),a ; save that to mode
or a
jr z,inshed ; if insert mode then ereol to rid us of over
ld de,over
call string ; else print over and fall through
inshed: call ereol ; delete over
jp gopos ; reposition cursor
over: db 'insert is off$'
;
; ring console bell
;
beepit:
ld hl,beeper
ld a,(hl) ; consider boolean beeper
or a
ret nz ; if we already beeped, don't do it again
cpl
ld (hl),a ; make beep false
ld c,bell
jp write ; ring bell
;
; delete command (from cursor to semicolon)
;
delcmd:
ld a,0ffh
ld (cmd),a ; set boolean value to true
call delwrd ; pretend to delete a word
xor a ; a := 0
ld (cmd),a ; make cmd false again
ret
;
; move right to end of command (from cursor to semicolon)
;
cright:
ld a,0ffh
ld (cmd),a ; set boolean value to true
call wright ; pretend to move right a word
xor a ; a := 0
ld (cmd),a ; make cmd false again
ret
;
; move one word to left
;
wleft:
xor a
ld hl,endchr
ld (hl),a ; endchr := 0
wlloop:
exx ; swap hl with hl'
ld hl,point
dec (hl) ; move one to the left
ld a,(hl)
cp 1 ; are we at position #1?
jr z,stop ; if so, stop
or a ; are we at position #zero?
jr nz,lnzero ; if not, check for word end
ld a,(length)
ld (hl),a ; else move pointer to the end of the buffer
jr stop ; and stop
lnzero:
call check ; check for word end
exx ; swap hl with hl'
jr nz,lnend ; no, check to repeat
ld (hl),a ; make value non-zero
jr wlloop ; and repeat
lnend: ld a,(hl)
or a ; have we already got a word end character?
jr z,wlloop ; no, so continue
jr stop ; else stop
;
; move one word to right
;
wright:
xor a ; a := 0
ld (rightc),a ; rightc := 0
ld hl,endchr
ld (hl),a ; endchr := 0
wrtloop:
exx ; swap hl with hl'
ld hl,rightc
inc (hl) ; rightc := rightc + 1
ld hl,point
inc (hl) ; move one to right
ld a,(length)
cp (hl) ; are we at the end of the buffer?
jr z,stop ; if so, stop
jr nc,rnzero ; if not, proceed
ld (hl),1 ; if past the end, go to the beginning
jr stop ; and stop
rnzero:
call check ; is it word end?
exx ; swap hl with hl'
jr nz,rnend ; no, check to repeat
ld (hl),a ; make value non-zero
jr wrtloop ; and repeat
rnend: ld a,(hl)
or a ; have we already got a word end character?
jr z,wrtloop ; no, so continue
stop:
jp gopos ; reposition cursor and return
;
; determine whether character ends word
;
check:
ld d,0
ld e,(hl) ; move position to de
ld hl,text
add hl,de ; get position in memory
ld a,(hl) ; consider that character
ex af,af'
ld a,(cmd) ; are we just checking for a semicolon?
or a
jr z,word ; no, check vs. the whole string
ex af,af'
cp ';' ; is it a semicolon?
ret ; send the answer back
word: ex af,af'
ld hl,wordcs
ld bc,wclast-wordcs
cpir ; go through wordcs looking for the character
ret ; flag: zero set if match found
wordcs:
db ' ;,_/\|'''
wclast:
;
; delete word right
;
delwrd:
ld a,(point)
push af
call wright ; find length of word
pop af
ld (point),a ; return to original position
ld a,(rightc) ; rightc = length of word
ld hl,kill
delloop:
ex af,af'
exx ; swap hl and hl'
call delchar ; delete the character we're sitting on
exx ; swap hl and hl'
ld a,(delchr) ; consider deleted character
ld (hl),a ; save deleted character
inc hl ; go to next character in kill buffer
ex af,af'
dec a ; is this the last character?
jr nz,delloop ; no, do it again
xor a
ld (hl),a ; end string with a null
jp draw ; yes, refresh the screen
;
; move character left
;
left:
ld hl,point
dec (hl) ; move to left
jp nz,gopos ; if (position > zero) then show it
ld a,(length)
ld (hl),a ; else put cursor at end of buffer
jp gopos ; then show it
;
; move character right
;
right:
ld hl,point
inc (hl) ; move to right
ld a,(length)
cp (hl)
jp nc,gopos ; if (length > position) then show it
ld (hl),1 ; else put us at the beginning
jp gopos ; and show it
;
; move line up
;
up:
ld a,(point)
cp 81
ret c
sub 80
ld (point),a
jp gopos
;
; move line down
;
down:
ld hl,point
ld a,(length)
sub (hl) ; find difference between end and cursor
cp 81 ; if (diff <= 80) then no char below
jr c,toend ; should we put him at the end?
ld a,(hl)
add a,80 ; else add 80
ld (hl),a ; and store it
jp gopos ; and return
toend: ld a,(length) ; consider length
ld c,(hl)
cp 161 ; is there a third line?
jr c,nothrd ; no, don't subtract a line
sub 80 ; subtract a line
push af
ld a,c ; consider point
sub 80 ; subtract a line
ld c,a ; store point
pop af
nothrd: cp 81 ; is there a second line?
ret c ; no, return
ld a,c ; consider the point
cp 81 ; is cursor is on the last line?
ret nc ; yes, return
ld a,(length)
ld (hl),a ; go to end
jp gopos ; position and return
;
; delete character left
;
dellft:
call left ; move to the left
call delchar ; then delete the character we're on
jp draw ; and refresh the screen
;
; delete character right
;
delrt:
call delchar ; delete the character at our position
jp draw ; and refresh the screen
;
; delete character at cursor position
;
delchar:
ld a,(point)
ld l,a
ld h,0
ld de,text
add hl,de ; get memory location of cursor
ld d,h
ld e,l ; copy it to de
ld a,(hl) ; consider current character
ld (delchr),a ; save it for possible later use
or a
ret z ; if the character is a null, then abort
inc hl
push hl
ld a,(length)
ld hl,point
sub (hl) ; a := length - point
inc a ; a := a + 1
ld c,a
ld b,0 ; bc := a
pop hl
ldir ; move the buffer down one (over character
; to delete, thus erasing it)
ld a,(length)
dec a
ld (length),a ; subtract one from the length
ret ; and return
;
; write command line to screen
;
draw:
call gopos ; go to the cursor position
ld hl,point
ld e,(hl)
aldraw: ld d,0
ld hl,text
add hl,de ; get the memory location of the cursor
drawl: ld a,(hl) ; move current character to a
or a
jr z,drclr ; if it's a null then we're done
push hl
call vwrite ; else write it
pop hl
inc hl ; point to next character
jr drawl ; and repeat
drclr:
ld a,(ins) ; if the calling routine was insert
or a
jr nz,gopos ; then we don't need to ereol
clrloop:
call ereol ; clear to end of line
ld c,cm
call write ; write a ^m (carriage return)
ld c,lf
call write ; write a ^j (line feed)
call ereol ; clear to end of line, again
; fall through to gopos
;
; position cursor as dictated by value of point
;
gopos:
ld a,(point)
ld h,3 ; start at 3rd line
calc:
cp 81
jr c,calcend ; if (length <= 80) then we're done
inc h ; else go down a line
sub 80 ; and subtract 1 line from our number
jr calc ; and check again
calcend:
ld l,a ; make the remainder the x coordinate
jp gotoxy ; and position the cursor
;
; get key from console -- return in a
;
getkey:
ld c,6 ; select direct console i/o
ld e,0ffh ; select get a key in
call bdos ; do the function
or a
jr z,getkey ; if zero keep checking for key
ret ; -- note that this will never return a null
;
; write characters: control characters are highlighted
;
vwrite:
cp ' '
jr c,cchar ; if it's < ' ' then it's a control character
ld c,a
jr write ; else print it
cchar: ; it's a control char, so turn on
; highlight, then it off again
push af
call stndou ; turn on highlight
pop af
add a,'@' ; make control character a normal character
ld c,a
call write ; print the character
jp stnden ; turn off highlight
;
; abort program because of insufficient tcap
;
notcap:
ld de,tcapstr
jp string
tcapstr:
db 'terminal definition insufficient.$'
;
; write character through bios or bdos
;
write:
ld hl,(1) ; get base of bios
ld de,09 ; add offset for console out
add hl,de
jp (hl) ; jump to that location
;
; write help msg
;
if vhelp
showhelp:
ld hl,601h
call gotoxy
;
call stndou
ld a,(hlpflg)
or a
jr nz,bighlp
ld de,lilhlp
jr string
bighlp:
if inverse
ld de,helpmsg
jr string ; print older message
else ; inverse ( if not inverse )
ld hl,helpmsg
shloop: ld a,(hl)
or a
ret z ; end on a null
cp '~'
jr z,doline ; do line function
push hl
call bwrite ; write through bdos
pop hl
inc hl
jr shloop ; repeat
doline:
inc hl
push hl
call stndou ; make text dim
ld b,(hl)
ld e,'-'
ld c,2 ; set up to write '-'
lineloop:
push bc
push de
call bdos ; do the bdos call (for print)
pop de
pop bc
djnz lineloop ; repeat
call stnden ; make normal again
pop hl
inc hl
jr shloop ; repeat
;
; write character through bdos (there must be tabs)
;
bwrite: push af
ld a,(contrl) ; are we in the middle of a ^char?
or a
jr z,skipstnd ; no, skip routine
dec a
ld (contrl),a ; count down one
call z,stndou ; if it's zero, make dim
skipstnd:
pop af
cp 1
jp z,stnden ; ^a = normal video
cp 2
jp z,stndou ; ^b = dim video
cp '|'
jr nz,chkctrl ; so we can print '^'
ld a,'^'
jr notctrl
chkctrl:
cp '^' ; is it a '^'?
jr nz,notctrl ; no, skip
push af
ld a,2
ld (contrl),a ; normal video for two chars
call stnden ; call normal video
pop af
notctrl:
ld e,a
ld c,2
jp bdos ; write the character
endif ; inverse
endif ; help
;
; write string through bdos
;
string:
ld c,9
jp 5
;
; misc. buffers
;
mode: db 0
endchr: db 0
rightc: db 0
ins: db 0
cmd: db 0
char: db 0
beeper: db 0
delchr: db 0
contrl: db 0
silent: db 0
hlpflg: db 0
instr: db 'Z33VERR version ',[version / 10] + '0','.'
db [version mod 10] + '0',' -- error handler$'
if vhelp
lilhlp: db '^Q for help$'
helpmsg:
if inverse
db cret,lf
db 'movement commands | deletion commands | miscellaneous commands ',cret,lf,cret,lf
db ' ^D - char right | ^G - char right | ^P - insert control-char ',cret,lf
db ' ^S - char left | <del> - char left | ^V - toggle insert/overwrite',cret,lf
db ' ^E - line up | ^T - word right | ^U - undelete last ^T or ^R ',cret,lf
db ' ^X - line down | ^R - cmd right | ^Y - abort entire line ',cret,lf
db ' ^F - word right | | <ret> - execute ',cret,lf
db ' ^A - word left | ',cret,lf
db ' ^C - cmd right | ','$'
else ; inverse ( if not inverse )
db ' ~',20,' movement ~',18,cret,lf,lf
db ' ^E ~',2,' word ~',2,' ~',2,' command ~',2,2,cret,lf
db ' |',cret,lf
db ' ^S <-+-> ^D ^A <-+-> ^F <-+-> ^C',cret,lf
db ' v',cret,lf
db ' ^X',cret,lf,lf
db '~',26,' deletion ~',25,cret,lf,lf
db ' ~',2,' character ~',2,' ~',2,' word ~',2,' ~',2,' command ~',2,' ~',2,' line ~',2,cret,lf
db ' del',2,' <-+-> ^G <-+-> ^T <-+-> ^R <- ^Y ->',cret,lf,lf
db '~',24,' miscellaneous ~',22,cret,lf,lf
db '^U undelete word or cmd ^V toggle insert mode',cret,lf
db '^P insert control-char ',1,'return',2,' execute command line',cret,lf,0
endif ; inverse
endif ; help
;
last:
dseg
kill ds 255
buffer ds 2
point equ buffer
maxlen equ buffer + 2
length equ buffer + 3
text equ buffer + 3
end