; 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 ; as an alias to 'E'dit, as an alias to 'A'bort, and ; 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 .....Edit command line" defb cret,lf,tab,tab defb "'A' or ....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 .....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 ' ' ; 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 | - 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 | | - 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