OBJNAM ED.SBR ; Created 23-Aug-85, last modified 23-Jan-86
; Puts specified Interactive BASIC line into user's input buffer for
; editing using the VUE-like system line input editing facility.
; by Irv Bromberg, Medic/OS Consultants, Toronto, Canada
RADIX 10
VEDIT=19
VMINOR=2
VMAJOR=4
VSUB=0
IF EQ,1
Assembled under AMOS/L 1.3 program 4.2(19) size is 908 bytes, hash code
is 001-606-273-412.
Calling syntax: XCALL ED,LineSpec
where LineSpec is a floating expression specifying BASIC line# to be
edited or is a string containing an ED.SBR command. The valid ED.SBR
commands are:
xcall ed,"F" edit first line
xcall ed,"L" edit last line
xcall ed,"N" edit next line (same as XCALL ED with no parameter)
xcall ed,"P" edit previous line
xcall ed,"I" insert line
The insert line command brings up the last edited line number followed
by a space provided that that line number does not already exist. It
therefore inserts AFTER the last edited line. You may wish to leave gaps
between line numbers for later use, in that case use the insert line
command repeatedly (convenient if a RELIEF function key is defined for
this, see below) until the desired line number appears OR simply
backspace to change the line number to leave the desired gap, being
careful not to use an existing line number.
Because of the way RELIEF handles programmable functions it is
convenient to program the following functions into RELIEF.TBL:
@f=xcall ed,"f" ; Funct-f =edit first line
@l=xcall ed,"l" ; Funct-l =edit last line
@n=xcall ed,"n" ; Funct-n =edit next line
@p=xcall ed,"p" ; Funct-p =edit previous line
@i=xcall ed,"i" ; Funct-i =insert line
@e=xcall ed,$ ; Funct-e =allow line# to be input
This allows the desired function key to be hit without having to clear
the currently edited line since RELIEF automatically clears the current
input line before processing the programmable function keycode.
The specified line is displayed for editing using the VUE-like system
line editor (LINEED, RELIEF, or AMOS/L 1.4 system line editor) Any
Horizontal Tab control characters in the source code of the line will be
converted to single spaces as the line is displayed, so that the line
editor will not get confused. The cursor will be left at the end of the
line to be edited. If the line is too long for the user's terminal's
type-ahead input buffer a warning will be issued (excess cannot be
displayed). ED.SBR can only be invoked from Interactive BASIC - when it
is called from a compiled BASIC program it will display an error message
and signal a Control-C Operator Interrupt to BASIC. The default line
number is the line after the last line edited by ED.SBR, or the first
line if ED.SBR is being called for the first time since the BASIC.LIT
command was invoked (the last edited line number is stored in the
filename extension word of the memory module containing the program
being edited - this word is not used by BASIC and therefore use of it
does not interfere with BASIC programming). When a line number greater
than the last existing line number is specified ED displays the number
of the last existing line. Attempt to go to next line after the last
line causes the last line to be returned (except for Insert command).
SCALE is supported (scaled floating values) for line numbers.
Edit history:
3.1(15) 4-Dec-85 Released to AMUS, for publication in AMUS.LOG.
3.2(16) 11-Dec-85 Added support for SCALE (scaled floating values).
Use user stack for floating workspace.
4.0(17) 16-Dec-85 Major rewrite to add ED.SBR string commands
4.1(18) 17-Dec-85 "Next" to stop at end of program instead of errmsg.
18-Dec-85 Made SCALE support optional by conditional assembly.
30-Dec-85 Changed back SCALE to required assembly.
4.2(19) 23-Jan-86 Fix to work with RELIEF's new KBD re-display patch,
need to TRMICP a ^S before the line and a ^Q after it.
ENDC
SCALE=128 ; =offset to SCALE value in BASIC impure area
PHDR -1,0,PH$REE!PH$REU ; re-entrant & re-usable
TST @Impure ; are we in Interactive BASIC?
BNE Go
TYPECR <?ED.SBR can only be called from Interactive BASIC>
MOV JOBCUR,JCB
ORW #J.CCC,JOBSTS(JCB) ; signal error to BASIC program
RTN
Go: MOV @Impure,Prog
LEA LastLn,-6(Prog) ; last edited line stored in EXT word
CLR LineNo ; pre-clear for word move
MOVW (LastLn),LineNo
CLR Length ; pre-clear for word moves
CLR Line ; pre-clear last line number
ADD #2,Prog ; now pointing to first line length
TSTW @ArgBas ; any parameters passed?
JEQ Next ; no, go to next line
MOVB 2(ArgBas),Ptype ; get parameter type
CMPB Ptype,#4 ; line number must be floating
JEQ GetFlt
CMPB Ptype,#2 ; is it string?
BNE Syntax ; yes, go parse the string
Parse: MOV 4(ArgBas),Atemp ; index the string
MOVB @Atemp,Char ; get the command character
UCS ; make it uppercase
CMPB Char,#'F ; "First"?
BNE 10$
CLR LineNo ; set next after zero
JMP Next
10$: CMPB Char,#'L ; "Last"?
JEQ FndLast
CMPB Char,#'N ; "Next"?
JEQ Next ; yes, goto next line
CMPB Char,#'P ; "Previous"?
JEQ FndPrev
CMPB Char,#'I ; "Insert"?
JEQ Insert
Syntax: TTYI
ASCII "?Syntax: XCALL ED,LineSpec"
BYTE CR
ASCII "LineSpec may be line number (floating expression) or"
BYTE CR
ASCII "F=First L=Last N=Next P=Previous I=Insert"
BYTE CR,0
Empty: BYTE ' ,0 ; empty line for insert
EVEN
RTN
Insert: ; find last edited line number
INCW LineNo ; make sure next line# doesn't exist
10$: MOV Line,LastNo
ADDW Length,Prog
MOVW @Prog,Length
MOVW 2(Prog),Line
CMPW Line,#-1 ; trap reached end of prog
BEQ OK
CMPW Line,LineNo
BLO 10$
BNE OK
TYPECR <?Cannot insert, line already exists>
RTN ; return to BASIC
OK: LEA Prog,Empty ; point to empty line for insertion
SUB #4,Prog
MOVW #1,Length ; only one space there
JMP Found
FndPrev:MOV Line,LastNo ; find previous line number
MOV Prog,Atemp ; save pointer
ADDW Length,Prog
MOVW @Prog,Length
MOVW 2(Prog),Line
CMPW Line,#-1 ; trap reached end of prog
BEQ 10$
CMPW Line,LineNo
BLO FndPrev
10$: MOV Atemp,Prog ; restore pointer to Prev line
MOVW @Prog,Length
MOVW 2(Prog),Line
MOVW Line,LineNo
JMP Found
Next: MOV Line,LastNo
MOV Prog,Atemp ; in case we pass end of program
ADDW Length,Prog
MOVW @Prog,Length
MOVW 2(Prog),Line
CMPW Line,#-1 ; trap reached end of prog
BEQ SetLast
CMPW Line,LineNo
BLOS Next
MOVW Line,LineNo
JMP Found
FndLast:MOV Line,LastNo ; search for last line
MOV Prog,Atemp ; save pointer
ADDW Length,Prog
MOVW @Prog,Length
MOVW 2(Prog),Line
CMPW Line,#-1 ; trap reached end of prog
BNE FndLast
SetLast:MOV Atemp,Prog ; recall pointer
MOVW @Prog,Length
MOVW 2(Prog),Line ; recall line#
MOVW Line,LineNo
JMP Found
GetFlt: MOV 4(ArgBas),Float ; get address of specified line#
SUB #6,SP ; get some workspace
MOV SP,Worksp ; point there
MOVB (Float)+,(Worksp)+ ; get line#
MOVB (Float)+,(Worksp)+
MOVB (Float)+,(Worksp)+
MOVB (Float)+,(Worksp)+
MOVB (Float)+,(Worksp)+
MOVB (Float)+,(Worksp)+
MOV SP,Worksp ; restore pointer
MOV Scale(Impure),D7 ; scale factor in use?
BEQ GetNum
NEG D7
FPWR @Worksp,D7 ; yes, adjust the scaled value
GetNum: FFTOL @Worksp,LineNo ; get specified line number
ADD #6,SP ; return stack workspace
TST LineNo
BNE ChkTop
Range: TYPECR <?Line number must be in range 1 to 65533>
RTN
ChkTop: CMP LineNo,#65533 ; make sure line# within range
BHI Range
NxtLin: MOV Line,LastNo
ADDW Length,Prog ; skip to next line
MOVW @Prog,Length ; get next line length
MOVW 2(Prog),Line ; get next line number
CMPW Line,#-1 ; -1 means end of program found
BEQ Passed
CMPW Line,LineNo ; is this the matching line number?
BLO NxtLin ; too low, keep searching
BEQ Found ; yes, found it
NotFnd: TYPECR <?Line not found>
RTN
Passed: MOV LastNo,Number ; get last line number found
BEQ Nil ; nothing found
TYPE <?Last line number is> ; passed last existing line number
DCVT 0,OT$TRM!OT$LSP ; so show what that line number is
CRLF
RTN
Nil: TYPECR <?No program found>
RTN
Found: MOVW LineNo,@LastLn ; save last edited line#
MOV JOBCUR,JCB
MOV JOBTRM(JCB),TCB
MOV T.IBS(TCB),Count
SUB #5,Count ; allow for CR LF NULL, DBF pre-decr
; found specified line#, cursor up and clear eos to keep things neat
MOVW #Cmd!3,CrtCmd ; cursor up
TCRT
MOVW #Cmd!10,CrtCmd ; clear to eos
TCRT
LEA String,4(Prog) ; now skip ahead to first blank/tab
10$: MOVB (String)+,Char
CMPB Char,#SPACE
BEQ 20$
CMPB Char,#HT ; have to output HT as single space
BEQ 20$ ; else line editor will get confused
DEC Length
BR 10$
20$: MOV LineNo,Number ; copy for DCVT
SUB #8,SP ; get some memory workspace
MOV SP,ASCBUF
DCVT 0,OT$MEM!OT$TSP ; output line# to input buffer
CLRB (ASCBUF) ; terminate with NULL
MOV ASCBUF,Total
SUB SP,Total ; calculate length of line number
ADD Length,Total ; add length of line
CMP Total,Count ; check if we have enough room
BLOS PutNum ; yes, no warning
Warning:TTYI
ASCII "%Warning - Line longer than Input Buffer, "
ASCII "excess cannot be displayed"
BYTE CR,0
EVEN
WaitOIP:TSTB T.STS(TCB) ; Wait for OIP to finish before
BPL 10$ ; continuing
SLEEP #500 ; sleep wastes less CPU time than
BR WaitOIP ; a tight loop would
10$: ; output has finished
PutNum: CLR Char
MOVB #XOFF,Char ; suspend terminal output
TRMICP
ORW #J.TIW,JOBSTS(JCB) ; fake input wait state
MOV SP,ASCBUF ; restore pointer to start of number
NxtDig: MOVB (ASCBUF)+,Char ; get next digit
BEQ PutLin ; terminate on NULL
TRMICP
DBF Count,NxtDig
PutLin: ADD #8,SP ; return used workspace
NxtChr: MOVB (String)+,Char ; reached NULL terminator in string?
BEQ Done
CMPB Char,#HT ; if it's a tab, convert to a space
BNE 10$
MOVB #SPACE,Char
10$: TRMICP ; force it as input to self
DBF Count,NxtChr
Done: ANDW #^C<J.TIW>,JOBSTS(JCB) ; undo fake input wait state
MOVB #XON,Char ; re-enable terminal output
TRMICP
RTN ; (leave cursor positioned at the end of the displayed line)