home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
BEEHIVE
/
UTILITYS
/
EASE10.ARC
/
EASE.Z80
< prev
next >
Wrap
Text File
|
1990-07-21
|
37KB
|
1,863 lines
; PROGRAM: Error And Shell Editor
; AUTHOR: Paul Pomerleau and Jay Sage
; DATE: August 1, 1987
; VERSION: 1.0
; Copyright 1987, Paul Pomerleau
; This program provides a history shell and error handler for ZCPR3.3
; A complex line editor is used to edit command lines.
; Run EASEDOC.COM to get a listing of Key-Command Bindings.
; This file assembles with SLR's Z80ASM
;=============================================================================
;
; 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
cr equ 0dh
lf equ 0ah
bell equ 07h
tab equ 09h
bdos equ 0005h
bios equ 0000h
fcb equ 005ch
secbuf equ 0080h
sectop equ 0100h
killlen equ 300
maxsec equ 8
public cout,ccout,print,pstr
extrn qerror, getsrun, haltsub, z33chk, stopxsub, subon
extrn getefcb
extrn getmsg,getcst,putcst,putzex
; extrn print,pstr,cout,ccout,crlf ; TOO LONG!!!! Grr!!!
extrn cst
extrn z3init,z3log,getquiet
extrn getzrun,stopzex,haltzex
extrn erradr,getcl1
extrn acase1,acase2
extrn sua,putud,getud
extrn getwhl,getduok,dutdir
extrn getsh,qshell,shpush,shpop
;=============================================================================
;
; S T A N D A R D P R O G R A M H E A D E R
;
;=============================================================================
ENTRY:
jp START
defb 'Z3ENV'
defb 3 ; Type-3 environment
ENVADDR:
dw 0fe00h
dw ENTRY
defb version
; To go to the Error Handler, just
; go to START with error flag set.
;=============================================================================
;
; C O N F I G U R A T I O N A R E A
;
;=============================================================================
NAME: db 'EASE VAR' ; Command history file
WIDTH: dw 80 ; Length of line
TOOSHORT:
dw 02 ; Don't store in history
; if shorter than...
TABLE: db [[LASTCASE - VECTOR] / 3] ; Number of cases
dw BEEP ; Default case ring bell
VECTOR: db 'Q'
dw SHIFTED ; Meta Key
db 'D'
dw FCHR ; Right Char
db 'S'
dw BCHR ; Left Char
db 'E'
dw UP ; Up line
db 'X'
dw DOWN ; Down line
db 'A'
dw MBWORD ; Left word
db 'F'
dw MFWORD ; Right word
db 'S'+80h
dw GOBOLN ; Start of line
db 'D'+80h
dw GOEOLN ; End of line
db 'G'
dw FDEL ; Del char right
db 'H'
dw DELCHR ; Del char left
db 127
dw DELCHR ; Del char left
db 'T'
dw FDWORD ; Del word right
db 127 + 80h
dw BDWORD ; Del word left
db 'R'
dw CMDKILL ; Kill to semi-colon
db 'Y'+80h
dw DELTOEND ; Delete to end of line
db 'Y'
dw DELLIN ; Delete line
db 'U'
dw UNDO ; Reinsert deleted text
db 'B'
dw BACKLINE ; Back in history shell
db 'N'
dw NEXTLINE ; Forward in history shell
db 'O'
dw BSEARCH ; Search for first char
db 'V'
dw TOGLIN ; Toggle insert
db 'I'
dw ITAB ; Insert Tab char
db 'P'
dw QINSERT ; Insert any char
db 'W'
dw REPLOT ; Redraw line
db 'C'
dw 0 ; Warm Boot
db 'M'
dw DONE ; End edit
db '_'+80h
dw QUITSH ; End EASE
LASTCASE:
PUNC: db ',.:!#%^&<>[]{}()_+-=`~/\|; ',tab
PUNCLEN equ $ - PUNC
;=============================================================================
;
; 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 z33chk
ret nz
call qerror ; See if error handler invocation
jp z,errorh ; If so, branch to error processing
call qshell
jp z,RUNSH ; Yes, don't install
;=============================================================================
;
; 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 shell and error handler.
;----------------------------------------
; Subtask 1 -- determine whether to use a DU or a DIR 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.
;----------------------------------------
; Get user option: if null, do both. If E, then install the error handler
; else install the shell.
call header
ld a,(5dh)
cp ' ' ; Error handler and shell
jr z,BOTH
cp 'E' ; Only error handler
jr z,ERRONLY
jr ISHELL ; Only the shell
BOTH: call ISHELL
;----------------------------------------
; 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).
ERRONLY:
call getmsg ; Get pointer to error command line
ld de,10h ; ..in message buffer
add hl,de
call getquiet
ret nz
call PUT_NAME_TO_HL
call clprint
defb ' Error handling',0
jr P_CLST
ISHELL: call GETSH ; Is there a shell stack?
jr nz,SHFINE ; Yes
SHBAD: call clprint
SHERR: db 'Shell Error',0
ret
SHFINE: ld hl,BUFFER
call PUT_NAME_TO_HL
call SHPUSH ; Store the shell name
jr nz,SHBAD ; Push to deep? Then abort
push hl
call SETFILE
call DELSET ; Delete existing file
call PUTSEC
pop hl
call getquiet
ret nz
PRWELC: call clprint
db ' Shell',0
P_CLST: call print
db ' command line set to: ',0
jp pstr ; Print the string there and quit
DELSET: xor a
ld (SEC),a ; First sector
ld hl,SECBUF + 1 ; +1==So no long pause -- at least at first.
ld (FP),hl
ld c,19 ; Delete
jp FBDOS
PUT_NAME_TO_HL:
push hl ; Save pointer for way below
ex de,hl ; Switch pointer into DE
call getefcb ; Get address of the command FCB
inc hl ; Advance pointer to name of program
; Get drive user from Z33's FCB.
push hl
ld bc,13 ; Offset to drive number
add hl,bc ; HL now points to the drive number
; Here we get the drive where the program was found. Since we know that this
; is not a resident program, there is no need to check for a zero value.
ld a,(hl) ; Get it and
add a,'A'-1 ; ..convert to a letter
ld (de),a ; Save in error command line
inc de ; Increment command line pointer
dec hl ; Back up to user number
ld a,(hl) ; Get it and
call mafdc ; ..convert to decimal in command line
ld a,':' ; Put in the colon
ld (de),a
inc de
cont1:
pop hl ; Restore the pointer to the command name
ld bc,8 ; Copy 8 characters of name
ldir ; ..into error command line
xor a ; Store terminating null
ld (de),a
pop hl
ret
;=============================================================================
;
; 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
task1:
call header
;----------------------------------------
; Subtask 2 -- Display system status
; This task determines whether ZEX and/or SUBMIT are running. Input
; redirection from either of them is turned off while error handling is
; performed (so user can provide the input).
task2:
call stopzex ; Stop ZEX input redirection
call clprint
defb lf,tab,'System Status:',tab,'ZEX '
defb 0
call getzrun ; Find out if ZEX is running
call ponoff ; Print on/off
call subon
jr z,task2a ; Branch if submit not supported
call print
defb ', SUBMIT '
defb 0
; See if submit is supported by the command processor
call stopxsub ; Stop XSUB input redirection
call getsrun ; Get submit running flag
call ponoff ; Print on/off
; See if wheel byte is on or off
task2a:
call print
defb ', WHEEL '
defb 0
call getwhl
call ponoff
;----------------------------------------
; Subtask 3 -- Determine source of the error (internal or external) and
; display that information.
task3:
call qerror
ret nz ; If not an error, then don't show the rest
call clprint
defb tab
defb 0
call getcst ; Get command status flag
bit 3,a ; See if external command bit is set
jr nz,external ; Branch if external error
call print ; "IN"ternal
defb 'In'
defb 0
jr task3a
external:
call print ; "EX"ternal
defb 'Ex'
defb 0
task3a:
call print ; "TERNAL ERROR"
defb 'ternal error: '
defb 0
call xcmdoff ; Clear the external command bit (and ECP bit)
;----------------------------------------
; Subtask 4 -- Determine the error return code and display information about
; the nature of the error. This section of the code can be expanded to cover
; more error types as they are defined.
task4:
call print
defb '#'
defb 0
call getmsg
ld a,(hl) ; Get the error return code
push af ; Save for use below
call pafdc ; Display the number
call print
defb ' -- '
defb 0
pop af ; Get error code back
cp 11
jr c,OKERR
ld a,4
OKERR: add a ; Make 8 bit skip into 16 bit
ld e,a
ld d,0
ld hl,ERRSTRS - 2 ; Add to first string index
add hl,de
ld e,(hl)
inc hl
ld d,(hl) ; Pull in string location
ex de,hl
call pstr ; Print it
jp task4a
ERRSTRS:
defw duchange ; Illegal attempt to change directory
defw baddu ; Invalid directory
defw badpw ; Incorrect password
defw unknown
defw badform ; Bad command form (wild or type given)
defw badecp ; Command not found (even by ECP)
defw badcmd ; Command file not found (ECP skipped)
defw ambig ; Ambiguous file spec
defw badnum ; Bad numerical value
defw nofile ; Object file not found
defw diskfull ; Disk is full
duchange:
defb 'Illegal attempt to change directory',0
baddu:
defb 'Invalid directory specification',0
badpw:
defb 'Incorrect password',0
badform:
defb 'Bad command name (file type or wild card used)',0
badecp:
defb 'Command not found (even by ECP)',0
badcmd:
defb 'Requested load file not found on disk',0
ambig:
defb 'Ambiguous or missing file name',0
badnum:
defb 'Bad numerical expression',0
nofile:
defb 'Requested source file not found',0
diskfull:
defb 'Disk full',0
unknown:
defb 'Unknown error type',0
task4a:
call crlf
;----------------------------------------
; Subtask 5 -- 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).
task5:
call clprint
defb tab,'Bad Command:',tab,0
call erradr ; Get pointer to bad command line
push hl ; Save for reuse below
ld de,BUFFER
scan: ; Find end of this command
ld a,(hl)
or a ; See if end of command line buffer
jr z,task5a
cp ';' ; See if at command separator
jr z,task5a
inc hl ; Point to next character
ld (de),a
inc de
jr scan ; Continue scanning
task5a:
xor a
ld (de),a
OKT5A: ld a,(hl)
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
pop af
or a
jr z,task6 ; If no rest of line, get out without output
push hl ; Save pointer to rest of command line
call clprint
defb tab,'Rest of Line:',tab,0
pop hl
task5b:
dec hl ; Pt back to bad command delimiter
ld (hl),a ; Put semicolon back
inc hl
call pstr ; Print rest of command line
; AND RETURN!
;----------------------------------------
; Subtask 6 -- Deal with the bad command
; This is where the real error handling is performed. Here we just flush
; the entire command line and abort any submit job, but in a real error
; handler, several other functions would be 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.
task6:
call clprint
defb lf,tab,'Your options:'
defb tab,'(E)dit bad command'
defb cr,lf,tab,tab,tab,'(A)bort entire command line'
defb 0
ld a,(delim) ; Get bad command delimiter
or a
jr z,task6a ; No trailing commands; skip next option
call clprint
defb tab,tab,tab,'(C)ontinue with rest of command line',0
task6a:
call clprint
defb tab,'Select: ',0
task6c: 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,task6b ; Don't allow 's' choice if no trailing command
cp 'C' ; Continue?
jr z,skip
task6b:
cp 'A' ; Abort?
jp z,abort
cp 'E' ; Edit?
jp z,edit
call print
defb bell,0 ; Bad input
jr task6c
;-----------------------------------------------------------------------------
; 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 ...',1
ret ; Resume command execution with next command
;-----------------------------------------------------------------------------
; Abort (flush) command line
abort:
call abortmsg
call getzrun ; See if ZEX is running
jr z,abort2 ; Branch if not
; Deal with running ZEX script
call clprint
defb tab,'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',1
; Deal with running SUBMIT job
abort2:
call getsrun ; Is a submit job running
ret z ; If not, return to command processor
call clprint
defb tab,'Abort SUBMIT job (Y/N)? '
defb 0
call getyesno ; Get user's answer
jr nz,abort3 ; Branch if negative response
call haltsub ; Abort SUBMIT
abortmsg:
call print
defb 'Aborted',1
ret
abort3:
call print
defb ' No',1
ret ; Back to command processor
;-----------------------------------------------------------------------------
; XCMDOFF -- turn off external command flag
; This routine turns off the external command bit and the ECP bit in the
; command status flag.
xcmdoff:
call getcst ; Get the command status flag
res 3,a ; Reset the external command bit
res 2,a ; Reset the ECP bit also to prevent reentering
; ..the error handler on return
jp putcst ; Put new value back and return
;-----------------------------------------------------------------------------
; 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
; ------------------------------
; header -- Print program name and version
;
header: call clprint
defb 'Z33 Error And Shell Editor, Vers. '
defb version / 10 + '0'
defb '.'
defb version mod 10 + '0',0
ret
; ------------------------------
; clprint -- Print CR LF and then following string.
clprint:
call crlf
jp print
;-----------------------------------------------------------------------------
; Prompt -- Print a DU/DIR prompt.
;
prompt: call qprompt ; Print the DU:DIR
ld a,(INSFLG)
INSPROMPT:
or a
ld a,'>' ; For insert
jr nz,INSOK
ld a,'}' ; For no insert
INSOK: call cout
ld a,'>'
call cout
ret
qprompt:
call QERROR
jr nz,NOTERR
call CLPRINT
db '[Error] ',0
NOTERR: call getduok
jr z,nodu
ld a,(4)
and 1111b
push af
add a,'A' ; Make it a letter
call cout ; Write it
ld a,(4)
rra
rra
rra
rra
and 1111b
call pafdc ; Write it as a number
ld c,a
pop af ; Get drive
ld b,a
call dutdir ; Get the NDR
ret z
push hl
ld a,':'
call cout ; And the colon to seperate
pop hl
nodu: ld b,8 ; Eight chars max
nameloop:
ld a,(hl) ; Get the first char
cp ' ' ; Is it the last
ret z ; YUP. done
call cout ; Write it
inc hl
djnz nameloop ; Repeat
ret
; -----------------------------------------------------------
; FillLine
; Check length of the new, edited, command line. If it will
; fit, copy it to the Z3 multiple command line buffer and
; return to the CPR to execute it. Otherwise, display error
; message and branch back to the editor.
GETLEN: ld hl,BUFFER
push hl
xor a
ld bc,302
cpir ; Find the ZERO
dec hl
pop de
push hl
sbc hl,de ; Get the length
ld b,h
ld c,l
pop hl
ret
; Now we concattenate the rest of the original command line to the
; command just entered.
FILLL2: ld de,(delimptr) ; Pt to bad command's delimiter
FILLCAT:
ld a,(de) ; Get character
ld (hl),a ; ..and store in buffer
or a ; End of commawd line?
jr z,FILL ; Finished with copy if so
inc bc ; Bump char count
inc de ; ..and pointers
inc hl
jr FILLCAT ; Go back for more
FILL: call getcl1 ; Get Z3 command line addr in hl,
; ..length in a
cp c ; Compare with length of new line
jr c,FILLERR ; Branch if new line too long
ld a,b ; High order byte of length should be 0
or a
jr nz,FILLERR ; Branch if not
push hl ; Save Z3CL
ld de,4 ; Offset to first character in buffer
add hl,de
ex de,hl ; First char address in DE
pop hl ; Z3CL address in HL
ld (hl),e ; Store ptr to first command
inc hl ; At Z3CL
ld (hl),d
ld hl,BUFFER ; Get back pointer to new command
push hl
inc bc ; Adjust length to include trailing null
ldir ; Copy to system command line
call qerror
pop hl
ret z ; Return if it was an error
push hl
call GETLEN ; Get length again
ld hl,(TOOSHORT)
sbc hl,bc
pop hl
ret nc ; Too short to save
push hl
call OPEN ; Open 'er up
call SAVETOWORK ; Move the values around
call RRAND ; Read in the current record
xor a
call WFFILE ; Put the null to space the lines
pop hl
FILLWRITE:
ld a,(hl) ; Loop to put in the whole line
push hl
call WFFILE ; Put in the next char of the line
pop hl
ld a,(hl)
inc hl
or a
jr nz,FILLWRITE
call BNOWRITE
call PUTSEC
xor a
call WFFILE ; Write final spacer null
FLUSH: call WRAND
CLOSE: ld c,16 ; Close the file
FBDOS: ld de,FCB
jp BDOS ; Go back to CPR to execute it
FILLERR: ; To long for CCP to digest
call print
defb bell,lf,tab
defb 'Too long!',1
jr EDIT2
FINDSEC:
call getsh ; Get the sector number from the shell stack
ld bc,128
xor a
cpir ; Find the ZERO
ld a,(hl) ; ?? Must be 0 -- but it isn't -- It's the SEC
ret
SAVETOWORK:
ld a,(SSEC) ; Move the saved vars to the working vars
ld (SEC),a
ld hl,(SFP)
ld (FP),hl
ret
GETSEC: call FINDSEC ; Put the new SEC to the saved var SEC
ld (SSEC),a
inc hl
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld (SFP),hl ; Put the File Pointer to saved FP
jr SAVETOWORK ; Copy saved to working
PUTSEC: call FINDSEC ; Get location of SEC
ld a,(SEC)
ld de,(FP) ; Get SEC & FP
ld (hl),a
inc hl
ld (hl),e
inc hl
ld (hl),d ; Put the into the Shell Stack
ret
;-----------------------------------------------------------------------------
; Edit -- He, He, He...
;
EDIT: call print
db 'E',1 ; Print the 'E' for edit choice
ld bc,BUFFER - ENDFLG - 1 ; Setup for zeroing out
jr SETUP
;--------------------------
; Run Shell (RUNSH) -- clear out the buffers and go to the editor.
RUNSH1: call crlf
RUNSH: call GETSEC ; Get the sector number
xor a
call putcst ; No errors
ld a,1 ; Z3 Cmd line for ZEX
call putzex ; Make ZEX think we are Z3
ld bc,BUFFER - ENDFLG
SETUP: ld hl,INSFLG ; Fill and Zap
ld (hl),0ffh
inc hl
ld (hl),0ffh
inc hl
call ZERO ; Zero out to exhaustion of bc
EDIT2: ld hl,(envaddr) ; Get environment address
call z3init
call OUTPUT1
ELOOP: xor a
ld (NOOUT+1),a ; OK for output
call GETKEY
ld b,a
ld a,(SHIFT) ; Get shift mask
or b
push af
xor a
ld (SHIFT),a ; Clear shift mask
pop af
cp ' '
jr c,CONTROL ; Yes, it's a command
cp 127
jr nc,CONTROL
call INSERT ; No, it's just a letter
jr ELOOP
CONTROL:
ld hl,ELOOP ; Return to...
push hl
ld de,TABLE ; Go to proper command
call UCASE
call acase2
SHIFTED:
ld a,10000000b ; Make shift mask set high bit
ld (SHIFT),a
ret
DELCHR: call DPOS ; Back up and delete forward
ret z
call DELETE
jp SHOWTOEND
FCHR: call FWRAP ; Go ahead a char and wrap if EOL
jp IPOS
FWRAP: ld hl,(POS) ; Check for forward wrap
ld a,(hl)
or a
ret nz
pop hl
jp GOBOLN
BCHR: call BWRAP ; Go back and wrap if BOL
jp DPOS
BWRAP: ld hl,(POS) ; Check for back wrap
dec hl
ld a,(hl)
or a
ret nz
pop hl
jp GOEOLN
MBWORD: call BWRAP ; Word forward with wrap
BWORD: call DPOS ; Word forward without
ret z
inc de
call PUNCCP ; Looking for punctuation
jr z,BWORD ; Skip punct
BWORD2: call DPOS
ret z
inc de
call PUNCCP ; Go till we hit punct
jr nz,BWORD2
dec de
jp IPOS
PUNCCP: ld hl,PUNC ; Check for punctuation
ld bc,PUNCLEN
cpir
ret
FDWORD: ld de,0 ; Delete forward a word
call FWORD ; Word forward
push de
FDWBACK:
ld a,d
or e
jr z,FDWENDBACK
dec de
call DPOS ; Back up same number of Chars
jr FDWBACK
FDWENDBACK
pop de ; Delete same number of chars
jr BDWRD1
BDWORD: ld de,0 ; Delete a word backwards
call BWORD
BDWRD1: ld a,d
or e
jp z,SHOWTOEND
dec de
push de
call DELETE ; Delete same number
pop de
jr BDWRD1
MFWORD: call FWRAP ; Forward word with wrap
FWORD: call IPOS
ret z
inc de
call PUNCCP ; Skip until punct
jr nz,FWORD
FWORD2: call IPOS
ret z
inc de
call PUNCCP ; Skip punct
jr z,FWORD2
dec de
jp DPOS ; Back up one
UP: ld hl,(WIDTH) ; Back 80 chars
BACKUP: ld a,h
or l
ret z
dec hl
push hl
call DPOS ; back up that many
pop hl
ret z
cp ' '
jr nc,BACKUP ; Control chars count double
ld a,h
or l
ret z
dec hl
jr BACKUP
DOWN: ld hl,(WIDTH) ; Go down a line
DOWNLOOP:
ld a,h
or l
ret z
dec hl
push hl
call IPOS ; Forward 'til hl = zero
pop hl
ret z
cp ' ' ; Control chars count double
jr nc,DOWNLOOP
ld a,h
or l
ret z
dec hl
jr DOWNLOOP
DONE: pop hl ; Save it and run it
call DONEOUT
call GETLEN ; Get the length in BC
call qerror ; Was it an error?
jp z,FILLL2
ld a,(BUFFER)
cp ';' ; Comment?
jr z,JRUNSH
or a ; Empty?
JRUNSH: jp z,RUNSH1
jp FILL ; Stuff the buffer
FDEL: call DELETE ; Delete forward a char
ret z
jp SHOWTOEND ; Redisplay
QINSERT:
call GETKEY ; Get a key and insert it -- whatever it is
or a
ret z
jr IJP
ITAB: ld a,tab ; Insert a tab
IJP: jp INSERT
TOGLIN: ld hl,INSFLG ; Toggle the insert flag
ld a,(hl)
cpl
ld (hl),a
ld hl,(POS)
push hl
push af
call GOBOLN
call BACK
call BACK ; Back up to the begining and back to ICHAR
pop af
call INSPROMPT
pop de
TOGLP: ld hl,(POS) ; Go fwd to where we were
sbc hl,de
ret z
call IPOS
jr TOGLP
CMDKILL:
ld hl,(POS)
ld de,KILL
push de
ld bc,killlen ; Stop before NULL in KILL
ldir ; Move it
pop hl
CKL: push hl
call DELETE ; Delete to a semi-colon
pop hl
inc hl
cp ';'
jr z,CKDONE
or a ; Or a NULL
jr nz,CKL
CKDONE: ld (hl),0
jp SHOWTOEND ; Redisplay
DELLIN: ld hl,BUFFER
ld de,KILL
ld bc,killlen ; Stop at NULL in KILL
ldir ; Move it
DELLN1: call GOBOLN ; Go to start
DELTOEND:
call CLRTOEND ; Wipe everything on screen
ld hl,(POS)
ld (hl),0 ; Put a null at the start
ret
GOEOLN: call IPOS ; Move to end of line
jr nz,GOEOLN
ret
GOBOLN: call DPOS ; Move to start of line
jr nz,GOBOLN
ret
REPLOT: ld hl,(POS) ; Reprint entire line
push hl
call GOEOLN ; Go to end and give us a CR LF
REPLT1: call crlf
call OUTPUT ; Redisplay
pop de
GOTOPOS:
or a
call IPOS ; Move fwd to old position
sbc hl,de
ret z
jr c,GOTOPOS
GP2: call DPOS
ret z
sbc hl,de ; Done?
ret z
jr GP2
CAPIN: call cin
; Fall through to UPCASE
UCASE: push bc ; Upcase A
push af
and 80h
ld b,a
pop af
and 7fh ; Keep high bit
call UCASE2 ; Real upcase
or b
pop bc
ret
UCASE2:
cp ' ' ; Standard blah blah upcase funct
jr nc,NOTCTL
add '@'
NOTCTL: cp 'a'
ret c ; Not a lowercase
cp 'z'+1
ret nc ; Not a lowercase
sub ' ' ; Yes, a lowercase
ret
BSEARCH:
call OSHELLCHK ; Check for open, etc.
call CAPIN ; Get a search key
ld b,a
ld hl,(FP) ; Get our locations
ld a,(SEC)
push af
push hl
push bc
ld a,(ENDFLG) ; Did we hit the end?
or a
jr z,BBDONE
ld a,(BACKFLG) ; Did we back up right before this?
or a
jr nz,BBDONE
call BNOWRITE
jr z,BSRCHNO
BBACK: call BNOWRITE ; Find the NULL
jr nz,BBACK
BBDONE: pop bc
BSRCHL: push bc
call BNOWRITE ; Is this the end?
call BNOWRITE
jr z,BSRCHNO
call FNOWRITE ; No, Place us properly
BSRCL1: call BNOWRITE
jr nz,BSRCL1
call FNOWRITE
pop bc
call UCASE ; Make all upcase
cp b
jr nz,BSRCHL ; Same?
call BNOWRITE
xor a
call BESET ; We went back -- Indicate it
pop hl
pop af
jp GETLINE ; Get a whole line in
BSRCHNO:
call BEEP ; Not found do the beep thing
pop bc
PUTBACK:
pop hl
pop af
ld (FP),hl ; Restore our pointers
ld (SEC),a
RRAND: ld c,21h
call DORAND ; Read that first one back in
or a
ret z
ZBUF: push de
ld hl,SECBUF ; Zero out our record
ld bc,127
call ZERO
pop de
ret
QUITSH: call qerror ; Pop the shell stack
ret z ; Unless we are an error handler
pop hl
call SHPOP
DONEOUT:
call GOEOLN ; Go to the end and CR
ld a,13
JCOUT: jp cout
BEEP: ld a,bell
jr JCOUT
BACKLINE: ; Go to previous command line
call OSHELLCHK
ld a,(ENDFLG)
or a
call z,EZER ; Till we get to start
BGET: call BNOWRITE
call z,FNOWRITE
jr z,BEEP ; No command line before
ld hl,TBUF
ld (hl),0
inc hl
BINSERT: ; Insert the line backing up
ld (hl),a
inc hl
push hl
call BNOWRITE
pop hl
jr nz,BINSERT
push hl
ld hl,BACKFLG ; Did we just go backwards?
ld a,(hl)
ld (hl),0ffh
or a
pop hl
jr z,BGET
push hl
call DELLN1 ; Kill existing line
pop hl
dec hl
BIN2: ld a,(hl)
dec hl
or a
ret z ; Put her there
push hl
call INSERT
pop hl
jr BIN2
NEXTLINE:
ld a,(ENDFLG) ; Are we at the end?
or a
ret z
call OSHELLCHK ; Open the sucker if it ain't already
GETLINE:
FGET: call FNOWRITE
jr z,CHKTOP ; At the end?
push af
call NOTTOP ; Set flag
pop af
ld hl,TBUF
FINSERT:
ld (hl),a
inc hl
push hl
call FNOWRITE ; Bring 'em in
pop hl
jr nz,FINSERT
ld (hl),0
ld hl,BACKFLG ; Did we go back?
ld a,(hl)
ld (hl),0
or a
jr nz,FGET
call DELLN1 ; Delete the line
ld hl,TBUF
FIN2: ld a,(hl)
inc hl
or a
ret z
push hl
call INSERT ; Push the chars in
pop hl
jr FIN2
CHKTOP: call DELLN1 ; Clean out existing line
call BNOWRITE
xor a
jr ESET ; Fix End Flag
NOTTOP: xor a
cpl
jr ESET
EZER: xor a ; Set the lot of them
cpl
BESET: ld (BACKFLG),a
ESET: ld (ENDFLG),a
ret
; ---------------------------------------
; Support routines for the commands above
;
SETSCAN:
push af ; Delete line and quiet terminal
call DELLN1
xor a
cpl
ld (NOOUT+1),a
pop af
ret
INSERT: ld e,a ; Put the char in
ld a,(INSFLG)
or a
jr nz,YAINS
ld hl,(POS)
ld a,(hl)
or a
ld a,e
jr nz,OVERWRITE ; Do we insert?
YAINS: xor a
ld b,a
push de
call MOVEUP ; Push them up
pop de
jp z,BEEP ; No room
ld a,e
OVERWRITE:
ld hl,(POS)
ld (hl),a
call IPOS ; Skip over it (printing it)
jr SHOWTOEND ; Redisplay
DELETE: ld de,(POS) ; Kill a char quiet-like
ld a,(de)
or a
ret z
push af
ld hl,DELETED
inc (hl)
cp ' '
jr nc,NOINC2 ; Increment DELETED as neccessary
inc (hl)
NOINC2: call MOVEDOWN
pop af
or a
ret
OUTPUT: call crlf ; New line
OUTPUT1:
call PROMPT ; Redisplay prompt
OUTPUT2:
ld hl,BUFFER ; And command line
ld (POS),hl
jp SHOWTOEND
CLRTOEND:
ld hl,(POS) ; Wipe out command line from cursor to right
ld de,0
CLRLOOP:
ld a,(hl) ; Loop until NULL
or a
jr z,NOWBACK
cp ' '
jr nc,CLR2
inc de
call SPACE ; Two for Control Chars
CLR2: call SPACE ; Overwrite it
inc hl
inc de
jr CLRLOOP
NOWBACK:
ld a,d
or e
ret z
dec de
call BACK ; And return to old location
jr NOWBACK
IPOS: ld hl,(POS) ; Get current char and print it
ld a,(hl)
or a
ret z ; Return zero if NULL
push af
inc hl
ld (POS),hl
push bc
ld b,a
ld a,(NOOUT + 1) ; Silence?
or a
ld a,b
pop bc
call z,ccout
pop af
ret
DPOS: ld hl,(POS) ; Back up (^H)
dec hl
ld a,(hl)
or a
ret z
push af
ld (POS),hl
cp ' '
call c,BACK ; Two for Control Char
call BACK
pop af
ret
SHOWTOEND:
call PRINTHL ; Show line to end
jr nz,SHOWLP
ld hl,DELETED ; With spaces for deleted text
ld a,(hl)
or a
jr z,SHOWLP
SHW1: push af
call SPACE
pop af
dec a
jr nz,SHW1
SHW2: call BACK
dec (hl)
jr nz,SHW2
SHOWLP: ld a,d
or e
ret z
dec de
call DPOS
jr SHOWLP
PRINTHL:
ld de,0 ; Show text at HL to NULL
PHLOOP: call IPOS
ret z
inc de
KILLFLG:
ld a,0 ; Check for UNDO
or a
ret nz
push hl
push de
push bc
ld c,11 ; Check for console in
call BDOS
pop bc
pop de
pop hl
or a
jr z,PHLOOP
call cin ; Check for previous input
ld (GETKEY+1),a
cp ' '
jr c,PHLOOP
cp 127 ; If it's an input, don't redisplay
ret nz
jr PHLOOP
GETKEY: ld b,0
xor a
ld (GETKEY+1),a ; Save the previous key
ld a,b
or a
call z,cin
ret
MOVEUP: ld hl,(POS) ; Move the text up to accept new char
ld a,' '
UPLOOP: ld b,(hl)
ld (hl),a
inc hl
ld a,b
or a
jr nz,UPLOOP
ld (hl),a
ld de,BUFFER + 300
sbc hl,de ; Until the end
jr z,MOVEDOWN ; No good, move it back
or 1
ret
MOVEDOWN: ; Move a char out -- Delete
ld hl,(POS)
ld d,h
ld e,l
DNLOOP: inc hl
ld a,(hl) ; Pull them down till we find a NULL
ld (de),a
or a
inc de
jr nz,DNLOOP
ret
UNDO: ld hl,kill ; Insert Kill buffer
xor a
cpl
ld (KILLFLG + 1),a
call undo1
xor a
ld (KILLFLG + 1),a
jp SHOWTOEND
UNDO1: ld a,(hl) ; insert at HL until NULL
inc hl
or a
ret z
push hl
call INSERT
pop hl
jr UNDO1
WFFILE: call RCHECK ; Forward a char in the file with write
ld de,(FP)
ld (de),a
ld hl,SECTOP-1
sbc hl,de
jr nz,FNOWRITE
call WRAND
FNOWRITE: ; Forward a char
call RCHECK
ld de,(FP)
inc de
ld hl,SECTOP
sbc hl,de
jr nz,NOREAD
ld hl,SEC
inc (hl)
call RRAND
ld de,SECBUF
NOREAD: ld a,(de)
ld (FP),de
or a
ret
WBFILE: call RCHECK ; Back a char in file with write
ld de,(FP)
ld (de),a
ld hl,SECBUF
sbc hl,de
jr nz,BNOWRITE
call WRAND
BNOWRITE: ; Back a char
call RCHECK
ld de,(FP)
dec de
ld hl,SECBUF-1
sbc hl,de
jr nz,NOREAD
ld hl,SEC
dec (hl) ; Should never get to be ZERO... Honest.
jr nc,BNOZERO
ld (hl),0 ; But, what the hell, it's free.
BNOZERO:
call RRAND
ld de,SECTOP-1
ld a,(de)
ld (FP),de
or a
ret
WRAND: ld c,22h ; Write random
call DORAND
or a
ret z
jp nz,WMERR
DORAND: ld a,(SEC) ; Put random record in right place in FCB
ld hl,FCB+33 ; Set the DMA and call BDOS
ld (hl),a
inc hl
xor a
ld (hl),a
inc hl
ld (hl),a
push de
call SETDMA
call FBDOS
pop de
ret
SETDMA: push bc ; Set the DMA to the SECBUF
ld c,1ah
ld de,SECBUF
call BDOS
pop bc
ret
BCD2: push bc ; Format two digit numbers
ld c,0ffh
BCD2A: inc c
sub 10
jr nc,BCD2A ; Put them in BCD (??) form
add a,10
ld b,a
ld a,c
rlca
rlca
rlca
rlca
or b
pop bc
ret
PAFDC: ld d,0 ; Print them out
MAFDC: push af ; Put them in a memory location
call BCD2
push af
rra
rra
rra
rra
and 1111b
call nz,DEPUT ; Output tens
pop af
call DEPUT ; Output ones
pop af
ret
DEPUT: and 1111b
add '0'
inc d
dec d ; Check for output
jp z,COUT
ld (de),a ; Else memory stuff
inc de
ret
;
; Bdos console in. With no echo.
;
CIN: push hl
push de
push bc
ld hl,(1)
ld de,9
add hl,de
ld (hl),0C9h
push hl
ld c,1
call BDOS
pop hl
ld (hl),0c3h
pop bc
pop de
pop hl
ret
RCHECK: push af ; Have we read already?
ld a,(RDFLG)
or a
jr nz,RCK1 ; Yes
cpl
ld (RDFLG),a ; No, now yes
push hl
push bc
call RRAND ; And read
pop bc
pop hl
RCK1: pop af
ret
SETFILE: ; Make FCB ok w/respect to Z33 FCB
ld hl,FCB
ld bc,35 + 80h ; Zero out FCB and DMA.
call ZERO
ld hl,NAME
ld de,FCB+1
ld bc,11
ldir
call getefcb
ld bc,14 ; Offset to drive number
add hl,bc ; HL now points to the drive number
; Here we get the drive where the program was found. Since we know that this
; is not a resident program, there is no need to check for a zero value.
ld a,(hl) ; Get it and
ld de,FCB
ld (de),a
dec hl ; Back up to user number
ld a,(hl) ; Get it and
ld (FCB+13),a ; put it in our FCB
ld de,FCB
jp z3log
OPEN: ld hl,OPENFLG ; Open the file
ld a,(hl)
or a
ret nz
ld (hl),0ffh
call SETFILE
ld c,15 ; Open
call FBDOS
inc a
ret nz
YANEW: call DELSET
ld c,22 ; Make
call FBDOS
inc a
jr z,WMERR
call ZBUF
call SETDMA
ret
ZERO: ld d,h ; Fill and area with zeros
ld e,l
inc de
ld (hl),0
ldir
ret
WMERR: call GOEOLN ; Write and error message
call crlf
ld hl,DISKFULL
call pstr
ld a,'!'
ld (OPENFLG),a
call cout
pop hl
jp REPLOT
OSHELLCHK: ; If we are a shell and its not open already
call qerror ; Open the file
pop hl ; Else POP & RETURN
ret z
push hl
jp OPEN
PRINT: ex (sp),hl ; Print a string
call PSTR
ex (sp),hl
ret
PSTR: push af ; Print a string at HL
ld a,(hl)
inc hl
or a
jr z,PSTR1
cp 1
jr z,DCRLF ; If 1, then end with a CRLF
call COUT
pop af
jr PSTR
DCRLF: call CRLF
PSTR1: pop af
ret
CCOUT: push af
; cp 8 ; For valid CCOUT, these are needed...
; jr z,OK ; But who's gonna know?
; cp 13
; jr z,OK
; cp 10
; jr z,OK
cp ' '
jr nc,OK
push af
ld a,'^'
call COUT
pop af
add '@'
OK: call COUT
pop af
ret
SPACE: ld a,' ' ; Print a space
jr COUT
BACK: ld a,8 ; Print a ^H
COUT: push af ; Output
push bc
push de
push hl
ld e,a
NOOUT: ld a,0 ; Being quiet
or a
ld c,6
call z,pbdos ; And the real print
pop hl
pop de
pop bc
CPOP: pop af
ret
PBDOS: ld a,e
ld hl,SPOS
cp 8
jr z,BACKP
cp 13
jr z,ZEROP
cp 7
jr z,NOIP
cp 10
jr z,NOIP
cp 9
jr z,TABCHR
inc (hl)
NOIP: jp BDOS ; BIOS cout
ZEROP: ld (hl),1
BACKP: dec (hl)
jr NOIP
TABCHR: ld a,' ' ; Expand Tab
call COUT
ld a,7
and (hl)
ret z
jr TABCHR
CRLF: call print ; Print a CRLF
db cr,lf,0
ret
;=============================================================================
; B U F F E R S
;=============================================================================
SSEC equ entry + 1100h
SEC equ ssec + 1
SFP equ sec + 2
FP equ sfp + 2
POS equ fp + 2
DELIMPTR equ pos + 2
DELIM equ delimptr + 2
INSFLG equ delim + 2
BACKFLG equ insflg + 1
ENDFLG equ backflg + 1
RDFLG equ endflg + 1
OPENFLG equ rdflg + 1
SHIFT equ openflg + 1
SPOS equ shift + 1
DELETED equ spos + 1
TBUF equ deleted + 2
KILL equ tbuf + 302
BUFFER equ kill + killlen + 2
DEFAULT_TOP_OF_BUFFER equ buffer + 300
end