LineEDitor: Difference between revisions
From Pickwiki
Jump to navigationJump to search
m link fix |
IanMcGowan (talk | contribs) Add source code, grabbed from archive.org |
||
| Line 4: | Line 4: | ||
https://sites.google.com/site/nzpickie/home/programs | https://sites.google.com/site/nzpickie/home/programs | ||
<PRE> | |||
program led | |||
* This editor reproduces the UniData Alternate Editor for QM/U2 | |||
* The code is based on LED, a line editor released into | |||
* the public domain by Public Trust of New Zealand. | |||
* Written by Keith Robert Johnson. | |||
*==================================================================== | |||
* Version information | |||
* 2.00 - Simplified code - No longer supporting R83 | |||
* Downcased the source to comply with QM standards. | |||
*==================================================================== | |||
$define universe | |||
$ifdef qm | |||
$include err.h | |||
voc = @voc | |||
$else | |||
open 'VOC' to voc else stop 201,'VOC' | |||
$endif | |||
$ifdef universe | |||
$options information | |||
$endif | |||
$ifdef unidata | |||
$basictype 'U' | |||
$endif | |||
* INITIALISE | |||
prompt '' | |||
am = char(254); vm = char(253); sm = char(252) | |||
true = 1 = 1; false = not(true); qt = '"\':"'" | |||
common /led$data/ edkeep,secure,kept | |||
equ cellsize to 100 | |||
dim memr(1) | |||
* List of verbs for viewing data only | |||
viewverb = 'VIEW':am:'BROWSE':am:'LOOK' | |||
* XCOM data - YES this editor will do $commands like AE does | |||
dim junk(100) | |||
equ this to junk(1) | |||
equ item to junk(2) | |||
equ here to junk(3) | |||
equ x$cc to junk(11) | |||
equ comi to junk(13) | |||
equ comd to junk(14) | |||
equ last to junk(15) | |||
equ comdmark to junk(19) | |||
equ wordmark to junk(20) | |||
equ fnam to junk(24) | |||
equ xsep to junk(25) | |||
mat junk = '' | |||
xsep = ' ' | |||
wordmark = ' ' | |||
comdmark = '`' | |||
* Local data | |||
begn = @(0) ; ceop = @(-3) ; ceol = @(-4) ; goup = @(-10) | |||
revb = @(-13) ; revf = @(-14) ; undb = @(-15) ; undf = @(-16) | |||
heap = false ; salt = '' ; rlen = 0 | |||
plen = system(3)-1 ; pwin = plen-1 ; line = '' ; here = 0 | |||
dim fr(10) ; mat fr = '' ; fr(3) = 'MCU' | |||
oops = '' ; oopc = '' ; oopl = '' ; oopf = '' | |||
oopb = '' ; oopk = '' | |||
join = '' ; nill = '' ; fold = '' | |||
macn = 0 ; macc = '' | |||
pick = '' ; lastfind = '' ; huge = 99999999 | |||
* Turn off page prompt | |||
test = @(0,0) | |||
* Find Match words - a LOOP can have multiple WHILE and UNTIL conditions | |||
fm.words = '' ; fm.findf = '' ; fm.finda = '' | |||
fm.words<1> = 'END' ; fm.findf<1> = 'END' | |||
fm.finda<1> = 'IF':vm:'END':vm:'OPEN':vm:'OPENSEQ':vm:'BEGIN':vm:'LOCATE' | |||
fm.words<2> = 'LOOP' ; fm.findf<2> = 'REPEAT':vm:'UNTIL':vm:'WHILE' | |||
fm.words<3> = 'UNTIL'; fm.findf<3> = fm.findf<2> | |||
fm.finda<3> = 'LOOP':vm:'UNTIL':vm:'WHILE' | |||
fm.words<4> = 'WHILE' | |||
fm.findf<4> = fm.findf<2>; fm.finda<4> = fm.finda<3> | |||
fm.words<5> = 'FOR' ; fm.findf<5> = 'NEXT' | |||
fm.words<6> = 'NEXT' ; fm.finda<6> = 'FOR' | |||
fm.words<7> = 'BEGIN' ; fm.findf<7> = 'END CASE':vm:'CASE' | |||
fm.words<8> = 'CASE' ; fm.findf<8> = 'CASE':vm:'END CASE' | |||
fm.finda<8> = 'BEGIN CASE':vm:'CASE' | |||
fm.words<9> = 'LOCKED' ; fm.findf<9> = 'END' | |||
fm.finda<9> = 'READU':vm:'READVU':vm:'MATREADU' | |||
fm.words<10> = 'REPEAT' ; fm.finda<10> = fm.finda<3> | |||
* Special for C code | |||
fm.words<11> = '{' ; fm.findf<11> = '}' | |||
fm.words<12> = '}' ; fm.finda<12> = '{' | |||
* | |||
endwords = 'IF\OPEN\OPENSEQ\READNEXT\READ\READU\READV\READVU\' | |||
endwords := 'MATREAD\MATREADU\LOCATE' | |||
convert '\' to am in endwords | |||
* page editor stuff | |||
botl = system(3) - 2; clpg = @(-1) | |||
* bell = char(7) ; span = system(2) | |||
bell = @sys.bell ; span = system(2) | |||
bott = @(0,system(3)-1):ceol | |||
* Define key activity numbers - 22 keys defined | |||
equ uarr to 1, darr to 2, larr to 3, rarr to 4 | |||
equ upag to 5, dpag to 6, lpag to 7, rpag to 8 | |||
equ tpag to 9, bpag to 10 | |||
equ escp to 11, phlp to 12, zoom to 13 | |||
equ delc to 14, dell to 15, delr to 16 | |||
equ back to 17, carr to 18, togg to 19, writ to 20 | |||
equ skey to 21, rkey to 22 | |||
* Set up the keys - In QM we can use generic key mapping (YAY) | |||
* but I also like to have default keys | |||
acts = '' ; keys = '' | |||
* Arrow keys | |||
acts<-1> = uarr ; keys<-1> = char(205) | |||
acts<-1> = uarr ; keys<-1> = char(26) | |||
acts<-1> = darr ; keys<-1> = char(206) | |||
acts<-1> = darr ; keys<-1> = char(10) | |||
acts<-1> = larr ; keys<-1> = char(203) | |||
acts<-1> = larr ; keys<-1> = char(21) | |||
acts<-1> = rarr ; keys<-1> = char(204) | |||
acts<-1> = rarr ; keys<-1> = char(6) | |||
* Page movement keys | |||
acts<-1> = upag ; keys<-1> = char(207) | |||
acts<-1> = upag ; keys<-1> = char(16) | |||
acts<-1> = dpag ; keys<-1> = char(208) | |||
acts<-1> = dpag ; keys<-1> = char(14) | |||
acts<-1> = lpag ; keys<-1> = char(209) | |||
acts<-1> = lpag ; keys<-1> = char(1) | |||
acts<-1> = rpag ; keys<-1> = char(210) | |||
acts<-1> = rpag ; keys<-1> = char(5) | |||
acts<-1> = tpag ; keys<-1> = char(214) | |||
acts<-1> = tpag ; keys<-1> = char(20) | |||
acts<-1> = bpag ; keys<-1> = char(215) | |||
acts<-1> = bpag ; keys<-1> = char(2) | |||
* delete character, line, and delete to end of line keys | |||
acts<-1> = delc ; keys<-1> = char(212) | |||
acts<-1> = delc ; keys<-1> = char(4) | |||
acts<-1> = dell ; keys<-1> = char(216) | |||
acts<-1> = dell ; keys<-1> = char(127) | |||
acts<-1> = dell ; keys<-1> = char(24) | |||
acts<-1> = delr ; keys<-1> = char(217) | |||
acts<-1> = delr ; keys<-1> = char(11) | |||
acts<-1> = delr ; keys<-1> = char(18) ;* for Wyse terminals | |||
* backspace and carriage return keys | |||
acts<-1> = back ; keys<-1> = char(008) | |||
acts<-1> = carr ; keys<-1> = char(013) | |||
* escape, help, Go to line, toggle insert/overwrite mode, save keys | |||
acts<-1> = escp ; keys<-1> = char(027) | |||
acts<-1> = escp ; keys<-1> = char(017) | |||
acts<-1> = phlp ; keys<-1> = char(128) | |||
acts<-1> = zoom ; keys<-1> = char(007) | |||
acts<-1> = togg ; keys<-1> = char(211) | |||
acts<-1> = togg ; keys<-1> = char(009) | |||
acts<-1> = writ ; keys<-1> = char(129) | |||
acts<-1> = writ ; keys<-1> = char(023) | |||
* search key, reverse search key | |||
acts<-1> = skey ; keys<-1> = char(130) ;* F3 for search | |||
acts<-1> = rkey ; keys<-1> = char(166) ;* shift-F3 for reverse search | |||
mode = 'LINE' | |||
* The saved stuff | |||
pres = '' ; look = '' ; stak = '' | |||
wild = false ; shew = false | |||
chan = '' ; olda = '' ; cmat = '' ; mmat = '' | |||
caseflag = false ; spaceflag = true ; blockflag = true | |||
* Save the standard defaults in the session variable if it's not set | |||
$ifdef universe | |||
if unassigned(edkeep) then edkeep = '0' | |||
$else | |||
if assigned(edkeep) else edkeep = '0' | |||
$endif | |||
if edkeep eq '0' then | |||
edkeep = pres:am:look:am:stak:am:wild:am:chan:am:olda:am:shew | |||
edkeep := am:cmat:am:mmat:am:not(caseflag):am:not(spaceflag) | |||
edkeep := am:not(blockflag) | |||
kept = '' | |||
end | |||
* Get the 'as-is' settings from the session variable | |||
pres = edkeep<1> | |||
look = edkeep<2> | |||
stak = edkeep<3> | |||
wild = edkeep<4> ; wild = not(not(wild)) | |||
chan = edkeep<5> | |||
olda = edkeep<6> | |||
shew = edkeep<7> ; shew = not(not(shew)) | |||
cmat = edkeep<8> | |||
mmat = edkeep<9> | |||
caseflag = not(edkeep<10>) | |||
spaceflag = not(edkeep<11>) | |||
blockflag = not(edkeep<12>) | |||
* Get forced default flags | |||
!&&& | |||
! nick = true | |||
!&&& | |||
read temp from voc, '&ED.OPTIONS' then | |||
line = upcase(trim(remove(temp, dlim))) | |||
if line[1,1] eq 'X' then | |||
loop | |||
line = upcase(trim(remove(temp, dlim))) | |||
begin case | |||
case line[1,8] eq 'BLOCK ON' | |||
blockflag = true | |||
case line[1,9] eq 'BLOCK OFF' | |||
blockflag = false | |||
case line[1,7] eq 'CASE ON' | |||
caseflag = true | |||
case line[1,8] eq 'CASE OFF' | |||
caseflag = true | |||
case line[1,8] eq 'SPACE ON' | |||
spaceflag = true | |||
case line[1,9] eq 'SPACE OFF' | |||
spaceflag = true | |||
case line[1,7] eq 'SHOW ON' | |||
shew = true | |||
case line[1,8] eq 'SHOW OFF' | |||
shew = true | |||
end case | |||
while dlim repeat | |||
end | |||
end | |||
$ifdef universe | |||
if unassigned(secure) then secure = '0' | |||
$else | |||
if assigned(secure) else secure = '0' | |||
$endif | |||
prepprog = '' ; prepflag = false | |||
postprog = '' ; postflag = false | |||
*********** UniData AE-style security start | |||
$ifdef unidata | |||
prepprog = getenv('PREPROG_AE_UDT') | |||
$endif | |||
$ifdef universe | |||
execute 'ENV' capturing temp | |||
xxno = dcount(temp,am) | |||
for xx = 1 to xxno | |||
line = temp<xx> | |||
if field(line,'=',1) eq 'PREPROG_AE_UDT' then | |||
prepprog = field(line,'=',2) | |||
xxno = xx | |||
end | |||
next xx | |||
$endif | |||
$ifdef qm | |||
* QM doesn't allow underscores in environmental variables, so | |||
* this is the closest I can get to AE environmental variable name. | |||
call !atvar(prepprog,'@PREPROG.AE.UDT') | |||
$endif | |||
* These next two tests are from the AE security documentation | |||
* They may not be required, but you can set them up if you want | |||
* if prepprog[1,3] eq 'AE_' then prepprog = '' | |||
* if prepprog[len(prepprog)-2,3] ne '_AE' then prepprog = '' | |||
if prepprog ne '' then prepflag = true | |||
* The following security definitions mirror those of I_AE_SECURITY | |||
* in UniData. I have only copied the functionality for SEC.SET | |||
* being "NONE" (that is, this user cannot edit) and the general | |||
* disabling of LOAD via the SEC.LOAD.FLG at first call to @PREPPROG; | |||
* and inhibiting of file updates via subsequent @PREPPROG calls. | |||
dim security(40) | |||
equ sec.set to security(1) ;* set by preprog on very first call | |||
* These fields are set in preprog | |||
equ sec.read.flg to security(2) ;* read ok or not | |||
equ sec.write.flg to security(3) ;* write ok or not | |||
equ sec.delete.flg to security(4) ;* delete ok or not | |||
equ sec.unload.flg to security(5) ;* unload ok or not | |||
equ sec.load.flg to security(6) ;* load ok or not | |||
equ sec.xeq.flg to security(7) ;* xeq ok or not | |||
equ sec.xcom.flg to security(8) ;* xcoms ok or not | |||
* the following 5 fields pass information to preprog & postprog, | |||
equ sec.fn to security(9) ;* file name | |||
equ sec.id to security(10);* record id | |||
equ sec.dir.flg to security(11);* 1 if file is a directory | |||
equ sec.newfile.flg to security(12);* 1 if new file name | |||
equ sec.active.sel.flg to security(13);* 1 if select list is active | |||
* this is how to make AE stop and return to calling program or ecl | |||
equ sec.stop.flg to security(14);* set to 1 to force ae to stop | |||
* for secondary calls to preprog; the first 3 cannot be changed | |||
equ sec.call2.type to security(15);* 1 load, 2 unload | |||
equ sec.fn2 to security(16);* second file - for load/unload | |||
equ sec.id2 to security(17);* second id - for load or unload | |||
equ sec.ok2.flg to security(18);* if 1, ok to load/unload | |||
* 19-22 are used by postprog, which I have not implemented | |||
equ sec.dict.flg to security(23) ;* 1 if fn is dict ... | |||
equ sec.dict2.flg to security(24) ;* 1 if fn2 is dict ... | |||
* field 25 is specific to UNIDATA AE, this and all other fields unused | |||
* WARNING: preprog programs should not use the STOP or ABORT statements | |||
* they should use the SEC.STOP.FLG to end nicely. | |||
*********** UniData AE-style security end | |||
* QM has it's own source control system depending on a callable program | |||
* named SOURCE.CONTROL existing. It has the following fields | |||
* | |||
* DICT.FLAG - 'DICT' if a dictionary, otherwise '' | |||
* FILE.NAME - name of file to be written | |||
* RECORD.NAME - name of record to be written | |||
* RECORD.DATA - the record to write | |||
* CALLER - calling program identifier, I have used '3' | |||
* WRITE.ALLOWED - 1 on call, returns 1 if write allowed and 0 otherwise | |||
* UPDATED - 0 on call, returns 1 if RECORD.DATA is changed | |||
source.control = false | |||
$ifdef qm | |||
if catalogued('SOURCE.CONTROL') then source.control = true | |||
$else | |||
* We can implement QM-style security if we want | |||
if prepprog eq 'SOURCE.CONTROL' then source.control = true | |||
$endif | |||
if source.control then prepflag = false ; prepprog = '' | |||
name = @logname | |||
levl = @level | |||
path = @path | |||
term = @tty | |||
whom = @userno | |||
acct = @who | |||
* This is to display unprintable characters safely | |||
badc = char(255) | |||
for xx = 0 to 31 ; badc := char(xx) ; next xx | |||
for xx = 127 to 250 ; badc := char(xx) ; next xx | |||
gudc = str('~',len(badc)) | |||
* eeePC does not distinguish between these | |||
if index(upcase(system(7)),'EEEPC',1) then | |||
badc := char(251):char(252):char(253); gudc := '[\]' | |||
end else | |||
badc := char(251):char(252):char(253) | |||
gudc := char(179):char(178):char(185) | |||
end | |||
* The yes/no can be language independant! | |||
yes = 'Yes' ; yes = upcase(trim(yes)) | |||
no = 'No' ; no = upcase(trim(no)) | |||
ny = '(':no[1,1]:'/':yes[1,1]:') >' | |||
* Want to see these thing in a single page | |||
presnumb = system(3)-2 | |||
if presnumb gt 20 then presnumb = 20 | |||
looknumb = presnumb; channumb = presnumb | |||
* Want this to be no more than five pages | |||
staknumb = (presnumb+1)*5+1 | |||
* Parse the command line - long way in before work starts, eh? | |||
* Anything in brackets is an option - but we do not use them at all. | |||
* "verb" is how this was called so it should work to call again | |||
verb = '' | |||
$ifdef qm | |||
$include parser.h | |||
call !parser(parser$reset, 0, @sentence, 0) | |||
opts = false | |||
options = '' | |||
sentence = '' | |||
loop | |||
call !parser(parser$get.token, type, param, keyword) | |||
until type eq parser$end do | |||
begin case | |||
case type eq 4 ; opts = true | |||
case type eq 5 ; opts = false | |||
case opts ; options<-1> = param | |||
case 1 ; sentence<-1> = param | |||
end case | |||
repeat | |||
$else | |||
rest = @sentence | |||
keepquot = false | |||
gosub parse.rest | |||
sentence = bite | |||
temp = dcount(sentence,am) | |||
options = sentence<temp> | |||
if options[1,1] eq '(' then | |||
options = field(field(options,'(',2),')',1) | |||
sentence = delete(bite,temp,0,0) | |||
end else options = '' | |||
$endif | |||
if options ne '' then options = ' (':options:')' | |||
* The C option allows the user to build paragraphs | |||
* using DATA statements to control the editor. | |||
* Otherwise they are restricted to an interactive mode. | |||
if index(upcase(options),'C',1) | |||
then editpage = false | |||
else editpage = true | |||
if upcase(sentence<1>) eq 'RUN' then | |||
verb = sentence<1>:' ':sentence<2>:' ' | |||
sentence = delete(sentence,1,0,0) | |||
sentence = delete(sentence,1,0,0) | |||
end | |||
verb = verb:sentence<1> | |||
sentence = delete(sentence,1,0,0) | |||
* Check if a viewing verb has been used | |||
* If so, we can turn off both security systems (I mope I'm right!) | |||
* The security flags are set safe, and each command is tested | |||
* individually, so I think it's pretty safe. | |||
* FORMAT is still allowed, but no other change command. | |||
viewflag = false ; view = 'edit' | |||
locate(upcase(verb),viewverb;posn) then | |||
viewflag = true | |||
view = 'view' | |||
source.control = false | |||
prepflag = false | |||
end | |||
* OR, they used the V option | |||
if index(upcase(options),'V',1) then | |||
viewflag = true | |||
view = 'view' | |||
source.control = false | |||
prepflag = false | |||
end | |||
* HELP location | |||
help.def = '2.00' | |||
help = '' | |||
pagehelp = '' | |||
fnam = sentence<1> | |||
sentence = delete(sentence,1,0,0) | |||
if upcase(fnam) eq 'DICT' then | |||
fnam = 'DICT ':sentence<1> | |||
sentence = delete(sentence,1,0,0) | |||
end | |||
idlist = sentence | |||
if system(11) and idlist ne '' then | |||
crt 'A select list was active, but specific ids were entered.' | |||
crt 'Select list will be ignored.' | |||
crt str('-',len('Select list will be ignored.')) | |||
clearselect | |||
end | |||
open 'AE_COMS' to acom else | |||
$ifdef qm | |||
execute 'CREATE.FILE AE_COMS' | |||
$else | |||
execute 'CREATE.FILE AE_COMS 1 7' | |||
$endif | |||
open 'AE_COMS' to acom else stop 'Cannot open ':'AE_COMS' | |||
test = @(0,0) | |||
end | |||
* Get file | |||
loop | |||
got.file = false | |||
if fnam eq '' then | |||
stub = 'File name? ' | |||
gosub get.rope; fnam = rope; crt | |||
end | |||
if fnam eq '' then stop | |||
dprt = field(fnam,' ',1) | |||
fprt = field(fnam,' ',2) | |||
if fprt eq '' then fprt = dprt ; dprt = '' | |||
open dprt, fprt to file then | |||
got.file = true | |||
end else | |||
open upcase(dprt),upcase(fprt) to file then | |||
got.file = true | |||
end else | |||
crt 'Cannot open ':'"':fnam:'"' | |||
fnam = '' | |||
end | |||
end | |||
until got.file do | |||
repeat | |||
if fileinfo(file,3) eq '4' then bleach = false else bleach = true | |||
bleach = upcase(fileinfo(file,2)) | |||
if bleach[2] = 'BP' or bleach[7] = 'SFPROGS' | |||
then bleach = false | |||
else bleach = true | |||
* Get the record | |||
if idlist eq '*' then | |||
idlist = '' | |||
execute 'SELECT ':dprt:' ':fprt | |||
test = @(0,0) | |||
end | |||
if system(11) then | |||
eof = false | |||
loop | |||
readnext id else eof = true | |||
until eof do | |||
idlist<-1> = id | |||
repeat | |||
end | |||
loop | |||
killsign = false | |||
if idlist eq '' then | |||
stub = 'Record name? ' | |||
gosub get.rope; rest = rope ; crt | |||
keepquot = false | |||
gosub parse.rest | |||
idlist = bite | |||
bite = '' ; rest = '' | |||
end | |||
idcnt = dcount(idlist,am) | |||
for id = 1 to idcnt until killsign | |||
item = idlist<id> | |||
gosub edit.item | |||
next id | |||
while killsign do | |||
idlist = '' | |||
repeat | |||
edkeep = pres:am:look:am:stak:am:wild:am:chan:am:olda:am:shew | |||
edkeep := am:cmat:am:mmat:am:not(caseflag):am:not(spaceflag) | |||
edkeep := am:not(blockflag):am:lower(kept) | |||
stop | |||
* SUBROUTINES | |||
* *********** | |||
edit.item: | |||
stopsign = false | |||
here = 0 ; dnum = 0 | |||
beg = 0 ; fin = 0 ; krj = '' | |||
crt | |||
if idcnt gt 1 then crt '<':id:'/':idcnt:'> ': | |||
if prepflag then | |||
if secure eq '0' then | |||
mat security = '' | |||
sec.set = '' | |||
call @prepprog(mat security) | |||
if sec.set eq 'NONE' then stop | |||
if sec.stop.flg then stop | |||
secure = sec.set | |||
end | |||
mat security = '' | |||
sec.set = secure | |||
if sec.set then | |||
sec.fn = fprt | |||
sec.id = item | |||
sec.dir.flg = fileinfo(file,3) = '4' | |||
sec.newfile.flg = false | |||
sec.active.sel.flg = false | |||
sec.dict.flg = (dprt = 'DICT') | |||
call @prepprog(mat security) | |||
if sec.stop.flg then stop | |||
if not(sec.read.flg) then return | |||
end | |||
end else | |||
sec.stop.flg = false | |||
sec.read.flg = true | |||
sec.write.flg = true | |||
sec.delete.flg = true | |||
sec.xcom.flg = true | |||
sec.unload.flg = true | |||
sec.load.flg = true | |||
sec.xeq.flg = true | |||
sec.ok2.flg = true | |||
* Apply the viewing flag | |||
if viewflag then | |||
crt 'VIEW ONLY - NO UPDATES ALLOWED' | |||
sec.write.flg = false | |||
sec.delete.flg = false | |||
sec.xcom.flg = false | |||
sec.unload.flg = false | |||
sec.load.flg = false | |||
sec.xeq.flg = false | |||
sec.ok2.flg = false | |||
end | |||
end | |||
readu this from file, item locked goto locked.record then | |||
lock = true | |||
carry.on: | |||
gosub parse.record | |||
crt 'Top of "':item:'" in "':fnam:'", ':last:' lines, ':len(this):' characters.' | |||
end else | |||
lock = true | |||
this = '' | |||
gosub parse.record | |||
crt 'Top of new "':item:'" in "':fnam:'".' | |||
end | |||
orig = this | |||
gosub get.lfmt | |||
* Edit the record | |||
loop | |||
if mode<1> eq 'PAGE' then | |||
pcol = rem(pchr-1,span) | |||
prow = here+1-ptop | |||
crt @(60,0):ceol:revb:mode<2>:revf:' ':fmt(here,'R#4'): | |||
crt ',':fmt(pchr,'L#4'): | |||
bite = temp[pchr,1] | |||
if bite ne '' then crt ' (':seq(bite):')': | |||
crt @(pcol,prow): | |||
gosub get.page.comd | |||
if mode eq 'LINE' then | |||
crt bott:'Line Editor Mode': | |||
if that ne this then | |||
crt ' - CHANGES HAVE BEEN MADE': | |||
oops = that ; oopc = 'PE' | |||
oopl = savl<1> ; oopf = savl<2> | |||
oopb = beg:am:fin ; oopk = krj | |||
end | |||
crt | |||
that = '' | |||
gosub display.line | |||
end | |||
end | |||
if mode<1> eq 'LINE' then | |||
* Get the command | |||
if x$cc ne '' then | |||
comi = x$cc<1> | |||
x$cc = delete(x$cc,1,0,0) | |||
end else | |||
if mode<1> eq 'PAGE' then continue | |||
if salt ne '' then | |||
comi = salt<1,1,1>; del salt<1,1,1> | |||
end else | |||
stub = prmt:': '; heap = true | |||
gosub get.rope; comi = rope; heap = false | |||
end | |||
if macn then macc<1,1,-1> = comi | |||
end | |||
gosub parse.command | |||
if not(numb eq '' or numb matches '1N0N') then | |||
crt ; gosub bad.command | |||
continue | |||
end | |||
if comd eq '' then | |||
gosub null.command | |||
if comd eq '' then continue | |||
end | |||
* Save command to list | |||
if comi ne '' and comi ne stak<1,1> and comd ne 'D' then | |||
stak = insert(stak,1,1,0,comi) | |||
stak = delete(stak,1,staknumb,0) | |||
end | |||
* Apply the command | |||
if comd ne 'R' then crt | |||
if comd matches '1N0N' then | |||
here = comd | |||
if here gt last then here = last | |||
gosub display.line | |||
continue | |||
end | |||
loop | |||
redo = false | |||
first = comd[1,1] | |||
posn = index('ABCDEFGHIJKLMNOPQRSTUVWXYZ',first,1) | |||
on posn gosub a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z | |||
while redo do repeat | |||
if stopsign then release file, item ; lock = false ; return | |||
end | |||
repeat | |||
return | |||
parse.command: | |||
comi = trimf(comi) | |||
dlim = oconv(oconv(comi,'MC/A'),'MC/N')[1,1] | |||
if dlim eq '' then | |||
rest = '' | |||
comd = upcase(comi) | |||
end else | |||
posn = index(comi,dlim,1) | |||
rest = comi[posn+1,huge] | |||
comd = upcase(comi[1,posn-1]) | |||
end | |||
temp = oconv(comd,'MCN')[1,1] | |||
if temp ne '' then | |||
temp = index(comd,temp,1) | |||
numb = comd[temp,huge] | |||
comd = comd[1,temp-1] | |||
end else numb = '' | |||
return | |||
parse.line: | |||
if line eq comdmark then line = '' | |||
xx = 1 | |||
loop | |||
temp = index(line,'^',xx) | |||
while temp do | |||
bite = line[temp,5] | |||
if bite matches '"^^"3N' then | |||
line = line[1,temp-1]:line[temp+1,len(line)] | |||
xx += 1 | |||
end else | |||
bite = bite[1,4] | |||
if bite matches '"^"3N' then | |||
line= line[1,temp-1]:char(bite[2,3]):line[temp+4,len(line)] | |||
end else xx += 1 | |||
end | |||
repeat | |||
return | |||
a: begin case | |||
case comd eq 'A' ; * append | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then rest = olda<1,1> | |||
if rest eq '' then | |||
crt 'No previous append command to repeat' | |||
gosub bad.comd | |||
return | |||
end | |||
olda = rest:vm:dlim | |||
line = rest ; gosub parse.line ; rest = line | |||
chng = 0 ; save = here ; savl = last | |||
dnum = 1 | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line | |||
line = line:rest | |||
if not(chng) then gosub savethis | |||
memr(cell)<lnum> = line | |||
chng += 1 | |||
if shew or dnum lt plen then gosub display.line | |||
next here | |||
here = dusk | |||
if chng then | |||
gosub reset.record | |||
crt chng:' lines changed - now at ':here | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
b: begin case | |||
case comd eq 'B' and dlim eq '' ; * bottom | |||
here = last ; gosub display.line | |||
case index('\B\BD\BK\BR\BS\','\':comd:'\',1) ; * break line | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
crt 'The second field is empty.' | |||
gosub bad.comd | |||
return | |||
end | |||
chng = 0 ; save = here ; savl = last ; show = '' | |||
gosub set.bounds | |||
for here = dusk to dawn step -1 | |||
gosub get.line | |||
posn = index(line,rest,1) | |||
if posn then | |||
left = line[1,posn-1] | |||
temp = line[posn+len(rest),len(line)] | |||
if temp ne '' or comd eq 'BS' then | |||
begin case | |||
case comd eq 'BD' ; line = left:rest | |||
case comd eq 'BK' ; line = temp | |||
case comd eq 'BR' ; line = temp:left:rest | |||
case comd eq 'BS' ; line = temp:rest:left | |||
case 1 ; line = left:rest | |||
end case | |||
memr(cell)<lnum> = line | |||
show = insert(show,1,0,0,here) | |||
numb += 1 | |||
chng += 1 | |||
if comd eq 'B' then | |||
dusk += 1 | |||
last += 1 | |||
lnum += 1 | |||
line = temp | |||
gosub insert.line | |||
end | |||
end | |||
end | |||
next here | |||
if chng then | |||
gosub savethis | |||
gosub reset.record | |||
zzno = dcount(show,am) | |||
savl = 0 ; dnum = 1 | |||
for zz = 1 to zzno | |||
here = show<zz> + savl | |||
if shew or dnum lt plen then gosub display.line | |||
if comd eq 'B' and zzno gt 1 then | |||
here += 1 | |||
savl += 1 | |||
if shew or dnum lt plen then gosub display.line | |||
end | |||
next zz | |||
show = '' | |||
end | |||
if comd eq 'B' | |||
then here = dusk + numb - 2 | |||
else here = dusk | |||
if here gt last then here = last | |||
if chng then | |||
crt 'Split ':numb:' records. Now at line ':here | |||
end | |||
gosub get.line | |||
case index('\BC\BCD\BCK\BCR\BCS\','\':comd:'\',1) ; * Break @ Column | |||
if viewflag then gosub viewonly ; return | |||
posn = trim(field(rest,dlim,1)) | |||
if not(posn matches '1n0n') then | |||
crt 'No column position given' | |||
gosub bad.comd | |||
return | |||
end | |||
chng = 0 ; save = here ; show = '' | |||
gosub set.bounds | |||
for here = dusk to dawn step -1 | |||
gosub get.line | |||
if len(line) gt posn then | |||
left = line[1,posn-1] | |||
temp = line[posn+1,len(line)] | |||
if temp ne '' or comd eq 'BCS' then | |||
begin case | |||
case comd eq 'BCD' ; line = left:rest | |||
case comd eq 'BCK' ; line = temp | |||
case comd eq 'BCR' ; line = temp:left:rest | |||
case comd eq 'BCS' ; line = temp:rest:left | |||
case 1 ; line = left:rest | |||
end case | |||
memr(cell)<lnum> = line | |||
show = insert(show,1,0,0,here) | |||
numb += 1 | |||
chng += 1 | |||
if comd eq 'BC' then | |||
dusk += 1 | |||
last += 1 | |||
lnum += 1 | |||
line = temp | |||
gosub insert.line | |||
end | |||
end | |||
end | |||
next here | |||
if chng then | |||
gosub savethis | |||
gosub reset.record | |||
zzno = dcount(show,am) | |||
savl = 0 ; dnum = 1 | |||
for zz = 1 to zzno | |||
here = show<zz> + savl | |||
if shew or dnum lt plen then gosub display.line | |||
if comd eq 'BC' and zzno gt 1 then | |||
here += 1 | |||
savl += 1 | |||
if shew or dnum lt plen then gosub display.line | |||
end | |||
next zz | |||
show = '' | |||
end | |||
if comd eq 'BC' | |||
then here = dusk + numb - 2 | |||
else here = dusk | |||
if here gt last then here = last | |||
if chng then | |||
crt 'Split ':numb:' records. Now at line ':here | |||
end | |||
gosub get.line | |||
case comd eq 'BLEACH' ; * change BLEACH flag | |||
rest = upcase(rest) | |||
begin case | |||
case rest eq 'ON' ; bleach = true | |||
case rest eq 'OFF' ; bleach = false | |||
case 1 ; bleach = not(bleach) | |||
end case | |||
if bleach | |||
then crt 'Colours disabled' | |||
else crt 'Colours enabled' | |||
case comd eq 'BLOCK' ; * change BLOCK flag | |||
rest = upcase(rest) | |||
begin case | |||
case rest eq 'ON' ; blockflag = true | |||
case rest eq 'OFF' ; blockflag = false | |||
case 1 ; blockflag = not(blockflag) | |||
end case | |||
if blockflag then | |||
crt 'Verification of block actions enabled' | |||
end else crt 'Verification of block actions disabled' | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
c: begin case | |||
case comd eq 'C' ; * change | |||
if viewflag then gosub viewonly ; return | |||
if numb eq '' and dlim eq '' then | |||
comd = 'RA' | |||
comi = 'RA1' | |||
numb = 1 | |||
end | |||
gosub change.command | |||
case comd eq 'CAT' ; comd = 'J' ; redo = true | |||
case comd eq 'CASE' ; * change casing flag for 'L' | |||
rest = upcase(rest) | |||
begin case | |||
case rest eq 'ON' ; caseflag = true | |||
case rest eq 'OFF' ; caseflag = false | |||
case 1 ; caseflag = not(caseflag) | |||
end case | |||
if caseflag then | |||
crt 'Searches are case-sensitive' | |||
end else crt 'Searches are not case-sensitive' | |||
case comd eq 'CD' ; * command delimiter display (change) | |||
if dlim eq '' then | |||
crt 'Command delimiter is ': | |||
end else | |||
temp = '`,;#$%&~|[]{}/"':"'" | |||
if index(temp,dlim,1) then | |||
comdmark = dlim | |||
crt 'Command delimiter is ': | |||
end else | |||
crt dlim:' is not a valid command delimiter.' | |||
crt 'Characters available for delimiters: ':temp | |||
crt 'Characters reserved for other uses: \.*!?-+=^@<>_:' | |||
crt 'Command delimiter is ': | |||
end | |||
end | |||
if comdmark eq '"' | |||
then crt "'":comdmark:"'" | |||
else crt '"':comdmark:'"' | |||
case comd eq 'CLEAR' ; * Clear the kept buffer | |||
if kept eq '' | |||
then crt 'Nothing in KEPT buffer' | |||
else crt 'KEPT buffer cleared' | |||
kept = '' | |||
case comd = 'COPY' ; * copy to kept buffer | |||
if comd eq upcase(comi) then | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd; return | |||
end | |||
rest = beg | |||
numb = fin-beg+1 | |||
end | |||
rest = trim(rest) | |||
if numb eq '' then gosub parse.atts | |||
if rest eq '' then rest = here | |||
if not(rest matches '1N0N') or numb eq '' then | |||
crt 'Formats are: "COPY" (from <> block) or "COPYn" or "COPYn/s" or "COPY/s/f".' | |||
gosub bad.comd ; return | |||
end | |||
if numb lt 1 then | |||
crt 'Nothing done - no lines selected.' | |||
comi = ''; return | |||
end | |||
if numb gt last then | |||
crt 'Nothing done - record does not have that many lines.' | |||
comi = '' ; return | |||
end | |||
kept = field(this,am,rest,numb) | |||
numb = dcount(kept,am) | |||
if numb then crt numb:' lines copied to KEPT buffer starting at line ':rest | |||
case comd eq 'CM' ; * changematch command | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
if cmat eq '' then | |||
crt 'No previous ChangeMatch command to repeat.' | |||
comi = '' | |||
return | |||
end else | |||
dlim = cmat<1,1> | |||
rest = cmat<1,2> | |||
numb = cmat<1,3> | |||
end | |||
end | |||
gosub changematch.command | |||
case comd eq 'COL' ; * column display | |||
temp = '' | |||
for xx = 1 to 9 | |||
temp = temp:space(9):xx | |||
next xx | |||
if lfmt | |||
then crt begn:space(llen+2):temp[1,span-llen-2] | |||
else crt begn:temp[1,span] | |||
temp = str('1234567890',10) | |||
if lfmt | |||
then crt begn:space(llen+2):temp[1,span-llen-2] | |||
else crt begn:temp[1,span] | |||
temp = '' | |||
case comd eq 'COUNT' ; * show the count of a string | |||
line = rest ; gosub parse.line ; rest = line | |||
if rest eq '' then | |||
crt 'No string given to count' | |||
gosub bad.comd ; return | |||
end | |||
gosub set.bounds | |||
if not(caseflag) then rest = upcase(rest) | |||
temp = 0 | |||
for here = dawn to dusk | |||
gosub get.line | |||
if caseflag | |||
then temp = temp + count(line,rest) | |||
else temp = temp + count(upcase(line),rest) | |||
next here | |||
here = dusk | |||
crt temp:' occurances of string.' | |||
case comd eq 'CRT' ; * insert crt line for programmer | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
crt 'You have not said what to put on CRT line!' | |||
comi = '' | |||
return | |||
end | |||
gosub savethat | |||
here += 1 ; last += 1 ; lnum += 1 | |||
if dlim ne '"' and dlim ne '\' then dlim = "'" | |||
line = 'CRT ':dlim:rest:' = ':dlim:':':rest | |||
gosub insert.line | |||
gosub reset.record | |||
gosub display.line | |||
case comd eq 'CUT' ;* Move lines to kept buffer | |||
if viewflag then gosub viewonly ; return | |||
if comd eq upcase(comi) then | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd; return | |||
end | |||
rest = beg | |||
numb = fin-beg+1 | |||
end | |||
rest = trim(rest) | |||
if numb eq '' then gosub parse.atts | |||
if rest eq '' then rest = here | |||
if not(rest matches '1N0N') or numb eq '' then | |||
crt 'Formats are: "CUT" (from <> block) or "CUTn" or "CUTn/s" or "CUT/s/f".' | |||
gosub bad.comd; return | |||
end | |||
if numb gt last then | |||
crt 'Nothing done - record does not have that many lines.' | |||
comi = '' ; return | |||
end | |||
kept = field(this,am,rest,numb) | |||
numb = dcount(kept,am) | |||
dawn = rest | |||
dusk = rest+numb-1 | |||
gosub delete.lines | |||
if numb then crt numb:' lines moved to KEPT buffer starting at line ':rest | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
d: begin case | |||
case comd eq 'D' ; * display current line | |||
if here gt last then here = last | |||
gosub display.line | |||
case comd eq 'DE' ; * delete lines | |||
if viewflag then gosub viewonly ; return | |||
chng = 0 ; save = here ; savl = last | |||
if rest ne '' then | |||
patt = rest | |||
cto = '' | |||
cfrom = 'DE' | |||
gosub cm.del.entry | |||
return | |||
end | |||
gosub set.bounds | |||
gosub delete.lines | |||
here = dawn | |||
if here gt last then | |||
here = last | |||
crt 'Bottom. Line ':here:' was above the last delete.' | |||
end else | |||
crt 'At line ':here:'. Deleted ':chng:' lines.' | |||
gosub display.line | |||
end | |||
$ifdef qm | |||
case comd eq 'DISPLAY' ; * insert display line for programmer | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
crt 'You have not said what to put on DISPLAY line!' | |||
comi = '' | |||
return | |||
end | |||
gosub savethat | |||
here += 1 ; last += 1 ; lnum += 1 | |||
if dlim ne '"' and dlim ne '\' then dlim = "'" | |||
line = 'DISPLAY ':dlim:rest:' = ':dlim:':':rest | |||
gosub insert.line | |||
gosub reset.record | |||
gosub display.line | |||
$endif | |||
case comd eq 'DROP' ; * remove the block | |||
if viewflag then gosub viewonly ; return | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd ; return | |||
end | |||
if beg le 1 then | |||
temp = 0 | |||
end else | |||
temp = index(this,am,beg-1) | |||
if not(temp) then | |||
crt 'Error - Block start line not defined' ; *Cannot find beginning of block | |||
gosub bad.comd ; return | |||
end | |||
end | |||
if fin eq last then | |||
temp -= 1 | |||
temp<2> = len(this) | |||
end else | |||
temp<2> = index(this,am,fin) | |||
end | |||
if not(temp<2>) then | |||
crt 'Error - Block end line not defined' ; *Cannot find end of block | |||
gosub bad.comd ; return | |||
end | |||
numb = fin - beg + 1 | |||
if blockflag then | |||
if beg eq fin | |||
then stub = 'Delete line ': beg:' ' | |||
else stub = 'Delete block from line ': beg:' to line ': fin:'? ' | |||
gosub get.answ | |||
if answ ne yes[1,1] then | |||
crt 'Block command cancelled.' | |||
return | |||
end | |||
end | |||
dawn = beg; dusk = fin | |||
gosub delete.lines | |||
crt 'Dropped (deleted) ':numb:' lines.' | |||
gosub display.line | |||
case comd eq 'DTX' ; * decimal to hex | |||
if not(rest matches '1N0N') then | |||
crt 'Numeric value required' | |||
gosub bad.comd ; return | |||
end | |||
if len(rest) gt 9 then | |||
crt 'Must be less than one billion (1,000,000,000)' | |||
gosub bad.comd ; return | |||
end | |||
$ifdef universe | |||
crt dtx(rest) | |||
$else | |||
crt oconv(rest,'MX') | |||
$endif | |||
case comd eq 'DUP' ; * duplicate previous line | |||
if viewflag then gosub viewonly ; return | |||
if here lt 1 then | |||
crt 'No current line' | |||
gosub bad.comd ; return | |||
end | |||
if numb eq '' and rest matches '1N0N' then numb = rest | |||
if numb lt 1 then numb = 1 | |||
gosub savethat | |||
gosub get.line | |||
for xx = 1 to numb | |||
gosub insert.line | |||
last += 1 | |||
next xx | |||
gosub reset.record | |||
crt 'Inserted ':numb:' copies of line ':here:' after line ':here:'. Still at ':here:'.' | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
e: begin case | |||
case comd eq 'EC' ; * edit called program (in this file) | |||
if here lt 1 then here = 1 | |||
gosub get.line | |||
line = trim(line) | |||
temp = upcase(line) | |||
good = index(temp,'CALL ',1) | |||
if good then line = trim(line[good+5,huge]) | |||
line = trim(field(line,'(',1)) | |||
if index(line,' ',1) then good = false | |||
if line[1,1] eq '@' then | |||
crt 'Leading "@" is logical pointer' | |||
good = false | |||
end | |||
if not(good) then | |||
crt 'The EC command requires lines in format "CALL ID" or "CALL ID(..."' | |||
gosub bad.comd ; return | |||
end | |||
* readv temp from file, line, 1 else | |||
* crt '"':line:'" is not in this file' | |||
* gosub bad.comd ; return | |||
* end | |||
* execute verb:' ':fnam:' ':line | |||
readv temp from file, line, 1 then | |||
execute verb:' ':fnam:' ':line:options | |||
end else | |||
test = false | |||
readv vlin from voc, line, 2 then | |||
vcnt = dcount(vlin,'/') | |||
vlin = field(vlin,'/',vcnt-1) | |||
vlin = vlin[1,len(vlin)-2] | |||
test = trans(vlin,line,-1,'X') | |||
end | |||
if test then | |||
execute verb:' ':vlin:' ':line:options | |||
end else | |||
crt '"':line:'" is not in this file' | |||
gosub bad.comd ; return | |||
end | |||
end | |||
*** | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
case comd = 'ECS' ; * edit command stack | |||
ttid = whom:'_':levl:'_commands' | |||
temp = raise(stak) | |||
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing command stack' | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read temp from acom, ttid else temp = '' | |||
temp = field(temp,am,1,staknumb-1) | |||
stak = lower(temp) | |||
delete acom, ttid | |||
case comd eq 'EDITPAGE' | |||
editpage = not(editpage) | |||
*> | |||
if editpage then | |||
begn = @(0) ; goup = @(-10) | |||
prmt = '*':str('-',llen-1) | |||
end else | |||
begn = char(13) ; goup = '' | |||
prmt = str('-',llen) | |||
end | |||
crt 'editpage = ':editpage | |||
*> | |||
case comd eq 'EF' ; * edit fields | |||
numb = numb + 0 | |||
if numb lt 0 or numb gt 255 then | |||
crt numb:' is outside range 0-255' | |||
comi = '' | |||
return | |||
end | |||
vmrk = char(numb) | |||
vals = 'char':numb | |||
gosub edit.fields | |||
vmrk = char(numb); gosub reset.fields | |||
case comd eq 'EI' ; * edit included code | |||
if here lt 1 then here = 1 | |||
gosub get.line | |||
line = field(line,';',1) | |||
line = trim(line) | |||
good = true | |||
temp = field(line,' ',1) | |||
temp = upcase(temp) | |||
if temp ne 'INCLUDE' and temp ne '$INCLUDE' then good = false | |||
line = trim(line[len(temp)+1,len(line)]) | |||
begin case | |||
case dcount(line,' ') gt 3 ; good = false | |||
case dcount(line,' ') eq 3 | |||
if field(line,' ',1) ne 'DICT' then good = false | |||
case dcount(line,' ') eq 1 | |||
readv test from file, line, 1 then | |||
line = fnam:' ':line | |||
end else | |||
test = trans('SYSCOM',line,1,'X') | |||
if test ne '' | |||
then line = 'SYSCOM ':line | |||
else line = fnam:' ':line | |||
end | |||
end case | |||
if not(good) then | |||
crt 'The EI command requires lines in format "$IN... {DICT} {FN} ID"' | |||
gosub bad.comd ; return | |||
end | |||
execute verb:' ':line:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
case comd eq 'EIT' ; * edit i-types (@) | |||
if dprt and here eq 2 and upcase(this[1,1]) else | |||
crt 'EIT is only for line 2 of a dictionary I-type' | |||
return | |||
end | |||
gosub get.line ; temp = line | |||
gosub split.itype | |||
ttid = whom:'_':levl:'_IType.in.line#':here | |||
write bite on acom, ttid on error gosub writerr ; return | |||
crt view:'ing IType as fields...': | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read line from acom, ttid else line = '' | |||
delete acom, ttid | |||
vmrk = ';'; gosub reset.fields | |||
* case comd eq 'EM' ; * edit MESSAGES | |||
* if numb eq '' and rest matches '1N0N' then numb = rest | |||
* if numb then | |||
* execute verb:' MESSAGES ':numb:options | |||
* end else | |||
* if here lt 1 then here = 1 | |||
* gosub get.line | |||
* line = trim(line) | |||
* temp = upcase(line) | |||
* good = index(temp,'SYSMSG',1) | |||
* if good then line = trim(line[good+6,huge]) | |||
* line = trim(field(line,'(',2)) | |||
* line = trim(field(field(line,')',1),',',1)) | |||
* if not(line matches '1N0N') then good = false | |||
* if not(good) then | |||
* crt 'The EM command requires lines in format "...sysmsg(1N0N..."' | |||
* crt 'Or a command like EMnnnn (nnnn is a message number)' | |||
* gosub bad.comd ; return | |||
* end | |||
* execute verb:' MESSAGES ':line:options | |||
* end | |||
* test = @(0,0) | |||
* crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
case comd = 'EK' ; * edit kept buffer | |||
ttid = whom:'_':levl:'_keptbuffer' | |||
write kept on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing kept buffer': | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read kept from acom, ttid else kept = '' | |||
delete acom, ttid | |||
case comd = 'EPR' ; * edit prestores | |||
numb = numb + 0 | |||
if numb lt 0 or numb gt presnumb then | |||
crt 'PRestore must be in range 1-':presnumb:'.' | |||
gosub bad.comd ; return | |||
end | |||
ttid = whom:'_':levl:'_prestores' | |||
temp = raise(pres) | |||
if numb then | |||
bite = raise(temp<numb>) | |||
write bite on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing prestore ':view: | |||
end else | |||
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing prestores': | |||
end | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
if numb then | |||
read bite from acom, ttid else bite = '' | |||
temp<numb> = lower(bite) | |||
end else | |||
read temp from acom, ttid else temp = '' | |||
end | |||
pres = lower(temp) | |||
delete acom, ttid | |||
case comd = 'ESS' ; * edit search stack | |||
ttid = whom:'_':levl:'_searches' | |||
temp = raise(look) | |||
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing search stack': | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read temp from acom, ttid else look = '' | |||
look = lower(temp) | |||
delete acom, ttid | |||
case comd eq 'ESV' ; * edit subvalues | |||
vmrk = sm ; vals = 'subvalues' | |||
gosub edit.fields | |||
vmrk = sm; gosub reset.fields | |||
case comd eq 'ET' ; * edit tabs | |||
ttid = whom:'_':levl:'_tabs' | |||
xxno = dcount(krj<1>,@vm) | |||
temp = '' | |||
for xx = 1 to xxno | |||
temp<xx> = krj<2,xx>:' ':krj<1,xx> | |||
next xx | |||
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return | |||
crt view:'ing line tabs': | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read temp from acom, ttid else temp = '' | |||
xxno = dcount(temp,@am) | |||
krj = @am:@am:krj<3> | |||
yy = '' | |||
for xx = 1 to xxno | |||
bite = trim(temp<xx,1,1>) | |||
left = field(bite,' ',1) | |||
rest = field(bite,' ',2,99) | |||
if left matches '1N0N' then left += 0 else left = 0 | |||
if left gt last then left = 0 | |||
if left then | |||
yy += 1 | |||
if rest eq '' then rest = 'T':left | |||
krj<1,yy> = rest | |||
krj<2,yy> = left | |||
end | |||
next xxno | |||
if krj<3> gt yy then krj<3> = yy | |||
if krj<1> ne '' and krj<3> lt 1 then krj<3> = 1 | |||
delete acom, ttid | |||
case comd eq 'EV' ; * edit values | |||
vmrk = vm ; vals = 'values' | |||
gosub edit.fields | |||
vmrk = vm; gosub reset.fields | |||
case comd eq 'EW' ; * edit words (as defined by wordmark) | |||
vmrk = wordmark ; vals = 'words' | |||
gosub edit.fields | |||
vmrk = wordmark; gosub reset.fields | |||
* Various forms for quitting | |||
case comd eq 'EX' or comd = 'EXIT' ; comd = 'Q' ; redo = true | |||
case comd eq 'EXK' or comd = 'EXITK' ; comd = 'QK' ; redo = true | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
f: begin case | |||
case comd eq 'FD' ; * delete item | |||
if viewflag then gosub viewonly ; return | |||
if not(sec.delete.flg) then | |||
crt 'Delete disabled' | |||
comi = '' | |||
return | |||
end | |||
gosub write.record | |||
case comd eq 'FILE' ; comd = 'SV' ; redo = true | |||
case comd[1,2] eq 'FI' ; * file item | |||
if viewflag then gosub viewonly ; return | |||
if not(sec.write.flg) then | |||
crt 'File disabled' | |||
comi = '' | |||
return | |||
end | |||
temp = comd[3,len(comd)] | |||
convert 'BCRDL' to '' in temp | |||
if temp eq '' then gosub write.record else gosub bad.command | |||
case comd eq 'FL' or comd eq 'FLA' ; * find labels | |||
if not(caseflag) then rest = upcase(rest) | |||
if index(comd,'A',1) then | |||
bump = -1 | |||
dawn = here - 1 | |||
if dawn lt 1 then return | |||
if numb then dusk = here - numb else dusk = 1 | |||
if dusk lt 1 then dusk = 1 | |||
end else | |||
bump = 1 | |||
dawn = here + 1 | |||
if dawn gt last then dawn = 1 | |||
if numb then dusk = dawn + numb else dusk = last | |||
if dusk gt last then dusk = last | |||
end | |||
for here = dawn to dusk step bump | |||
gosub get.line | |||
gosub find.label | |||
if not(caseflag) then temp = upcase(temp) | |||
if temp ne '' then | |||
if rest eq '' or temp matches rest then | |||
gosub display.line | |||
if not(numb) then return | |||
end | |||
end | |||
next here | |||
crt | |||
gosub display.line | |||
case comd eq 'FM' or comd eq 'FMA' ; * find match command | |||
gosub get.line | |||
* Get rid of any label | |||
gosub find.label | |||
thisline = trimf(line) | |||
if temp ne '' then | |||
thisline = thisline[len(temp)+1,huge] | |||
if thisline[1,1] eq ':' then thisline = thisline[2,huge] | |||
thisline = trimf(thisline) | |||
end | |||
* Get the first word on the line | |||
word = field(trim(upcase(thisline)),' ',1) | |||
begin case | |||
case rest ne '' | |||
seek = upcase(rest) | |||
case word[1,1] eq '*' or word[1,1] eq '!' | |||
seek = word[1,1] | |||
case 1 | |||
locate(word,fm.words;posn) then | |||
if index(comd,'A' ,1) then | |||
seek = fm.finda<posn> | |||
end else | |||
seek = fm.findf<posn> | |||
end | |||
end else | |||
locate(word,endwords;posn) then | |||
seek = 'END' | |||
end else | |||
crt 'Starting word "':word:'" unknown' | |||
gosub bad.comd ; return | |||
end | |||
end | |||
end case | |||
if seek eq '' then | |||
crt word:' has no matching word for ':comd | |||
gosub bad.comd ; return | |||
end | |||
posn = index(upcase(line),word,1) | |||
xxno = dcount(seek,vm) | |||
for xx = 1 to xxno | |||
seek<1,xx> = space(posn-1):seek<1,xx> | |||
next xx | |||
if index(comd,'A',1) then | |||
bump = -1 | |||
dawn = here - 1 | |||
if dawn lt 1 then return | |||
dusk = 1 | |||
end else | |||
bump = 1 | |||
dawn = here + 1 | |||
if dawn gt last then return | |||
dusk = last | |||
end | |||
save = here | |||
for here = dawn to dusk step bump | |||
gosub get.line | |||
line = upcase(line) | |||
if line[1,1] ne '' then | |||
temp = field(line,' ',1) | |||
if num(temp) or temp[len(temp),1] eq ':' then | |||
temp = len(temp) | |||
line = space(temp):line[temp+1,len(line)] | |||
end | |||
end | |||
for xx = 1 to xxno | |||
slen = len(seek<1,xx>) | |||
if line[1,slen] eq seek<1,xx> then | |||
if trim(line[slen+1,1]) eq '' then | |||
gosub display.line | |||
return | |||
end | |||
end | |||
next xx | |||
next here | |||
here = save | |||
gosub get.line | |||
case comd eq 'FOLD' ; * fold the line | |||
if viewflag then gosub viewonly ; return | |||
chng = 0 ; save = here ; savl = last | |||
if dlim ne '' then fold = '' | |||
if rest eq '' then rest = fold | |||
if rest eq '' then rest = span-llen-2 | |||
if not(rest matches '1N0N') then | |||
crt 'Non-numeric length - try HELP FOLD.' | |||
comi = '' | |||
return | |||
end | |||
fold = rest | |||
gosub get.line | |||
crt 'FOLD line to length ':fold | |||
bite = line | |||
gosub parse.bite | |||
gosub check.line | |||
if chng then gosub reset.record | |||
case comd eq 'FOR' or comd eq 'FORMAT' ; * format this item | |||
rest = upcase(rest) | |||
temp = index(rest,'-M',1) | |||
if temp then fr(1) = field(rest[temp+2,huge],' ',1) ; fr(2) = '' | |||
if not(fr(1) matches '1N0N') then fr(1) = '' | |||
if fr(1) eq '' then | |||
temp = this<1> | |||
fr(1) = len(temp) - len(trimf(temp)) | |||
end | |||
temp = index(rest,'-I',1) | |||
if temp then fr(2) = field(rest[temp+2,huge],' ',1) | |||
if not(fr(2) matches '1N0N') then fr(2) = '' | |||
if fr(2) eq '' then | |||
fr(2) = int((fr(1)+1)/2) | |||
if fr(2) lt 2 then fr(2) = 2 | |||
end | |||
if index(rest,'-A',1) then fr(9) = true else fr(9) = '' | |||
if index(rest,'-N',1) then fr(10) = true else fr(10) = '' | |||
if index(rest,'-C',1) then | |||
fr(1) = 0 | |||
fr(2) = 1 | |||
fr(9) = true | |||
fr(10) = true | |||
end | |||
if last lt 1 then return | |||
gosub savethat | |||
crt 'Margin=':fr(1):', Indentation=':fr(2) | |||
gosub indenter | |||
gosub set.record | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
g: begin case | |||
case comd eq 'G' ; * Go to line | |||
if numb eq '' then | |||
if dlim eq '<' and beg ne '' then here = beg | |||
if dlim eq '>' and fin ne '' then here = fin | |||
end else here = numb | |||
if here gt last then here = last | |||
gosub display.line | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
h: begin case | |||
case comd eq 'H' or comd eq 'HELP' | |||
gosub show.help | |||
case comd eq 'HEX' ; * show this line in hexadecimal | |||
if not(here) then return | |||
gosub get.line | |||
temp = '' | |||
xxno = len(line) | |||
for xx = 1 to xxno | |||
bit = line[xx,1] | |||
$ifdef universe | |||
bit = dtx(seq(bit)) | |||
$else | |||
bit = oconv(seq(bit),'MX') | |||
$endif | |||
$ifdef unidata | |||
bit = fmt(bit,'2/0R') | |||
$else | |||
bit = fmt(bit,'R%2') | |||
$endif | |||
temp<1> = temp<1>:bit[1,1] | |||
temp<2> = temp<2>:bit[2,1] | |||
next xx | |||
if lfmt then crt fmt(here,lfmt):': ': | |||
crt temp<1> | |||
if lfmt then crt space(llen+2): | |||
crt temp<2> | |||
temp = '' | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
i: begin case | |||
case comd eq 'I' ; * insert lines | |||
if viewflag then gosub viewonly ; return | |||
chng = 0 ; save = here ; savl = last | |||
if rest ne '' then | |||
if numb lt 1 then numb = 1 | |||
inum = numb | |||
gosub get.line | |||
if not(chng) then gosub savethis | |||
if here gt 0 then | |||
memr(cell)<lnum> := str(am:rest,inum) | |||
end else memr(1)<1> = str(rest:am,inum):memr(1)<1> | |||
if here le beg then beg += inum | |||
if here le fin then fin += inum | |||
yyno = dcount(krj<1>,vm) | |||
for yy = 1 to yyno | |||
if krj<2,yy> gt here then krj<2,yy> += inum | |||
next yy | |||
here = here + inum | |||
gosub reset.record | |||
gosub get.line | |||
gosub display.line | |||
crt 'At line ':here:'. ':inum:' lines inserted, bottom now at line ':last:'.' | |||
end else | |||
if nill ne '' then | |||
crt 'Terminate input with "':nill:'"' | |||
end | |||
!&&& | |||
! if nick then gosub get.line | |||
!&&& | |||
loop | |||
!&&& | |||
! if nick | |||
! then pill = space(len(line)-len(trimf(line))) | |||
! else pill = '' | |||
! pick = pill | |||
! pill := nill | |||
!&&& | |||
new1 = here + 1 | |||
stub = new1:'=' | |||
if lfmt then stub = fmt(new1,lfmt):'=' | |||
gosub get.rope; line = rope | |||
!&&& | |||
until line eq nill do | |||
! until line eq nill or line eq pill do | |||
!&&& | |||
gosub parse.line | |||
last += 1 | |||
here += 1 | |||
lnum += 1 | |||
if not(chng) then gosub savethis | |||
chng += 1 | |||
gosub insert.line | |||
temp = len(last) | |||
if lfmt then | |||
if temp gt 3 and temp ne llen then gosub get.lfmt | |||
end | |||
if line eq nill then | |||
crt begn: | |||
if lfmt then crt fmt(new1,lfmt):'= ': | |||
end | |||
crt | |||
numb -= 1 | |||
if numb eq 0 then exit | |||
repeat | |||
crt begn:ceol: | |||
end | |||
if chng then gosub reset.record | |||
case comd eq 'IC' ; * iconv | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
crt 'No conversion given' | |||
gosub bad.comd ; return | |||
end | |||
ccom = '*':rest ; gosub conv.command | |||
case comd eq 'IN' ; * insert from execute | |||
if viewflag then gosub viewonly ; return | |||
if trim(rest) eq '' then | |||
crt 'No external command given' | |||
comi = '' ; return | |||
end | |||
execute rest capturing bite | |||
test = @(0,0) | |||
numb = dcount(bite,am) | |||
if numb then | |||
gosub savethat | |||
this = insert(this,here+1,0,0,bite) | |||
gosub set.record | |||
crt 'Inserted ':numb:' lines; still at line ':here:'.' | |||
end else | |||
crt 'Nothing done - no output from command.' | |||
comi = '' ; return | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
j: begin case | |||
case comd eq 'J' ; * join lines | |||
if viewflag then gosub viewonly ; return | |||
if dlim ne '' then | |||
line = rest ; gosub parse.line ; join = line | |||
end | |||
if here and here lt last then | |||
chng = 0 ; save = here ; savl = last | |||
gosub get.line | |||
test = line | |||
here += 1 | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line | |||
test = test:join:line | |||
next here | |||
gosub delete.lines | |||
if chng eq 0 then return | |||
here = save | |||
oopl = here | |||
gosub get.line | |||
memr(cell)<lnum> = test | |||
gosub reset.record | |||
end | |||
gosub display.line | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
k: begin case | |||
case comd eq 'KEEP' or comd eq 'KEEPA' | |||
gosub get.load | |||
if temp eq '' then return | |||
if comd[len(comd),1] ne 'A' then | |||
gosub get.lines | |||
if not(temp) then return | |||
end | |||
kept = temp | |||
temp = dcount(temp,am) | |||
crt 'At line ':here:', ':temp:' lines loaded into kept buffer.' | |||
temp = '' | |||
case comd eq 'KEPT' or comd eq 'K' ; * display kept | |||
xxno = dcount(kept,am) | |||
if xxno lt 1 then | |||
crt 'Nothing in KEPT buffer' | |||
return | |||
end | |||
bit = len(xxno) | |||
disp = '***** Contents of KEPT buffer (':xxno:' lines) *****' | |||
stub = 'Press return to continue showing KEPT buffer, Q to quit' | |||
for xx = 1 to xxno | |||
temp = oconv(kept<xx>,'MCP')[1,wide-bit-1] | |||
disp<-1> = fmt(xx,'R#':bit):':':temp | |||
next xx | |||
gosub show.disp | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
l: begin case | |||
case index('\L\LN\LA\LNA\LAN\','\':comd:'\',1) ; * list or locate | |||
if upcase(comi) eq 'L' then | |||
if look<1,1> eq '' then | |||
crt 'No previous locate command to repeat.' | |||
comi = '' | |||
return | |||
end | |||
comi = look<1,1> | |||
gosub parse.command | |||
if comd eq '' then comd = 'L' ; numb = huge | |||
redo = true | |||
return | |||
end | |||
finder = '' | |||
seeker = dlim | |||
if seeker eq '!' or seeker eq '&' then | |||
finder = rest | |||
convert dlim to am in finder | |||
if finder<2> eq '' then finder = '' else rest = finder<1> | |||
end | |||
looper = dcount(finder,am) | |||
if rest ne '' then | |||
gosub parse.cols | |||
if not(good) then return | |||
end else | |||
if dlim ne '' then | |||
crt 'The second field is empty.' | |||
gosub bad.comd ; return | |||
end | |||
cols = '' | |||
end | |||
if index(comd,'A',1) then | |||
bump = -1 | |||
dawn = here - 1 | |||
if dawn lt 1 then dawn = 1 | |||
if numb then dusk = here - numb + 1 else dusk = 1 | |||
if dusk lt 1 then dusk = 1 | |||
end else | |||
bump = 1 | |||
dawn = here + 1 | |||
if dawn gt last then dawn = 1 | |||
if numb then dusk = dawn + numb - 1 else dusk = last | |||
if dusk gt last then dusk = last | |||
end | |||
if looper then rest = finder else looper = 1 | |||
line = rest ; gosub parse.line ; rest = line | |||
lastfind = rest<1> | |||
if not(caseflag) then rest = upcase(rest) | |||
if spaceflag else convert ' ':char(9) to '' in rest | |||
for here = dawn to dusk step bump | |||
gosub get.line | |||
if cols then line = line[cols,colf] | |||
if caseflag then temp = line else temp = upcase(line) | |||
if spaceflag else convert ' ':char(9) to '' in temp | |||
badder = false ; gooder = false | |||
for xx = 1 to looper | |||
if index(temp,rest<xx>,1) | |||
then gooder = true | |||
else badder = true | |||
next xx | |||
if seeker eq '&' then gooder = not(badder) | |||
if gooder then | |||
if not(index(comd,'N',1)) then | |||
gosub display.line | |||
if not(numb) then exit | |||
end | |||
end else | |||
if index(comd,'N',1) then | |||
gosub display.line | |||
if not(numb) then exit | |||
end | |||
end | |||
next here | |||
if numb then here = dusk | |||
crt 'Now at line ':here: | |||
if here eq last then crt ' (bottom)': | |||
crt '.' | |||
if rest ne '' and comi ne '' and comi ne look<1,1> then | |||
look = insert(look,1,1,0,comi) | |||
look = field(look,vm,1,looknumb) | |||
end | |||
case comd eq 'LC' ; * lower case (make line in) | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then ccom = 'MCL' else ccom = 'QMCL' | |||
gosub conv.command | |||
* Various forms for loading stuff | |||
case comd eq 'LD' or comd eq 'LOAD' or comd eq 'LDA' or comd eq 'LOADA' | |||
if viewflag then gosub viewonly ; return | |||
if not(sec.load.flg) then | |||
crt 'LOAD disabled' | |||
comi = '' | |||
return | |||
end | |||
gosub get.load | |||
if temp eq '' then return | |||
if prepflag then | |||
sec.call2.type = 1 | |||
sec.fn2 = ofpt | |||
sec.id2 = oipt | |||
sec.dict2.flg = (odpt = 'DICT') | |||
call @prepprog(mat security) | |||
if sec.stop.flg then stop | |||
if not(sec.ok2.flg) then | |||
gosub bad.comd ; return | |||
end | |||
end | |||
if comd[len(comd),1] ne 'A' then | |||
gosub get.lines | |||
if not(temp) then return | |||
end | |||
gosub savethat | |||
this = insert(this,here+1,0,0,temp) | |||
temp = dcount(temp,am) | |||
here = here + temp | |||
crt 'At line ':here:', ':temp:' lines loaded.' | |||
temp = '' | |||
gosub set.record | |||
case comd eq 'LL' ; * long lines | |||
if not(rest matches '1N0N') then | |||
rest = span-llen-2 | |||
crt 'LL':numb:'/':rest | |||
end | |||
dawn = here + 1 | |||
if dawn gt last then dawn = 1 | |||
if numb then dusk = here + numb else dusk = last | |||
if dusk gt last then dusk = last | |||
for here = dawn to dusk | |||
gosub get.line | |||
temp = trim(line[rest,huge]) | |||
if temp ne '' then | |||
gosub display.line | |||
if not(numb) then return | |||
end | |||
next here | |||
crt | |||
gosub display.line | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
m: begin case | |||
case comd eq 'M' ; * pattern matching | |||
rest = field(rest,dlim,1) | |||
if rest eq '' and mmat ne '' then | |||
dlim = mmat<1,1> | |||
rest = mmat<1,2> | |||
end | |||
if rest eq '' then | |||
crt 'No pattern given to match' | |||
return | |||
end | |||
gosub changematch.command | |||
case comd eq 'MACRO' | |||
if macn then | |||
temp = dcount(macc<1,1>,sm) | |||
macc = delete(macc,1,1,temp) | |||
macc = delete(macc,1,1,temp) | |||
if macc ne '' then | |||
pres<1,macn> = macc<1,1> | |||
crt 'Macro saved to PRestore ':macn | |||
end else | |||
crt 'Macro empty - not saved' | |||
end | |||
macc = '' | |||
macn = 0 | |||
end else | |||
if numb eq '' then numb = 1 | |||
if numb gt presnumb or numb lt 1 then | |||
crt 'PRestore must be in range 1-':presnumb:'.' | |||
comi = '' | |||
return | |||
end | |||
crt 'Macro being recorded for PRestore ':numb | |||
macn = numb | |||
end | |||
case comd eq 'MERGE' or comd eq 'ME' ; * merge stuff | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' and numb eq '' then | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd | |||
return | |||
end | |||
numb = fin - beg + 1 | |||
if blockflag then | |||
if beg eq fin | |||
then stub = 'Copy line ':beg:' to under line ':here:'? ' | |||
else stub = 'Copy lines ':beg:'-':fin:' to under line ':here:'? ' | |||
gosub get.answ | |||
if answ ne yes[1,1] then | |||
crt 'Block command cancelled.' | |||
return | |||
end | |||
end | |||
dlim = ' ' | |||
rest = beg:' ':fin | |||
numb = '' | |||
end | |||
rest = trim(rest) | |||
if numb eq '' then gosub parse.atts | |||
if numb ne '' and rest eq '' then rest = here | |||
if not(rest matches '1N0N') or numb eq '' then | |||
crt 'Format of MErge command is: "MEn/s"; eg: "ME10/15" or "ME/s/f"; eg: "ME/15/24"' | |||
gosub bad.comd ; return | |||
end | |||
* if numb gt last then | |||
* crt 'Nothing done - record does not have that many lines.' | |||
* comi = '' ; return | |||
* end | |||
bite = field(this,am,rest,numb) | |||
if numb ne 1 or bite ne '' then numb = dcount(bite,am) | |||
if numb then | |||
gosub savethat | |||
this = insert(this,here+1,0,0,bite) | |||
gosub set.record | |||
if beg gt here then beg = beg + numb | |||
if fin gt here then fin = fin + numb | |||
xxno = dcount(krj<1>,vm) | |||
for xx = 1 to xxno | |||
if krj<2,xx> gt here then krj<2,xx> += numb | |||
next xx | |||
crt 'Merged ':numb:' lines starting at line ':rest:'; still at line ':here:'.' | |||
end else | |||
crt 'Nothing done - this line is within the range.' | |||
comi = '' ; return | |||
end | |||
case comd eq 'MOVE' or comd eq 'MV' ; * move stuff | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd | |||
return | |||
end | |||
if here le fin and here ge beg then | |||
crt 'A block may not be moved into itself. MERGE will work.' | |||
comi = '' | |||
return | |||
end | |||
numb = fin - beg + 1 | |||
if blockflag then | |||
if beg eq fin then | |||
stub = 'Move line ':beg:' to after line ':here:' OK? ':ny | |||
end else | |||
stub = 'Move lines ':beg:'-':fin:' to after line ':here:' OK? ':ny | |||
end | |||
gosub get.answ | |||
if answ ne yes[1,1] then | |||
crt 'Block command cancelled.' | |||
return | |||
end | |||
end | |||
dlim = ' ' | |||
rest = beg:' ':fin | |||
numb = '' | |||
end | |||
rest = trim(rest) | |||
if numb eq '' then gosub parse.atts | |||
if not(rest matches '1N0N') or numb eq '' then | |||
crt 'Format of MoVe command is: "MVn/s"; eg: "MV10/15" or "MV/s/f"; eg: "MV/15/24"' | |||
gosub bad.comd ; return | |||
end | |||
dusk = rest + numb - 1 | |||
if dusk gt last then dusk = last | |||
if here ge rest and here le dusk then | |||
crt 'Nothing done - this line is within the range.' | |||
comi = '' ; return | |||
end | |||
bite = field(this,am,rest,numb) | |||
numb = dcount(bite,am) | |||
if numb then | |||
gosub savethat | |||
if here gt dusk then | |||
this = insert(this,here+1,0,0,bite) | |||
if rest gt 1 | |||
then this = this[1,col1()-1]:this[col2(),len(this)] | |||
else this = this[col2()+1,len(this)] | |||
end else | |||
this = this[1,col1()-1]:this[col2(),len(this)] | |||
this = insert(this,here+1,0,0,bite) | |||
end | |||
gosub set.record | |||
if here gt dusk then | |||
here = here - numb | |||
crt 'Moved ':numb:' lines starting at line ':rest:'; now at line ':here:'.' | |||
end else | |||
crt 'Moved ':numb:' lines starting at line ':rest:'; still at line ':here:'.' | |||
end | |||
!############## | |||
posn = beg; gosub recalc.posn; beg = posn | |||
posn = fin; gosub recalc.posn; fin = posn | |||
xxno = dcount(krj<1>,vm) | |||
for xx = 1 to xxno | |||
posn = krj<2,xx>; gosub recalc.posn; krj<2,xx> = posn | |||
next xx | |||
end else | |||
crt 'Nothing done - no lines selected.' | |||
comi = '' ; return | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
n: begin case | |||
case comd eq 'N' ; * same as "+" | |||
if numb eq '' then numb = 1 | |||
here = here + numb | |||
if here gt last then here = last | |||
gosub display.line | |||
case comd eq 'NULL' ; * null line input definition | |||
dlim = trim(dlim):trim(rest) | |||
dlim = dlim[1,1] | |||
nill = dlim | |||
if nill eq '"' then | |||
bit = "'":nill:"'" | |||
end else bit = '"':nill:'"' | |||
crt 'NULL character to terminate INSERT is ':bit:'.' | |||
comi = '' | |||
case comd eq 'NUM' ; * toggle the line numbering | |||
if lfmt eq '' then | |||
crt 'Line Numbering is ON' | |||
gosub get.lfmt | |||
end else | |||
crt 'Line Numbering is OFF' | |||
lfmt = '' | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
o: begin case | |||
case comd eq 'OC' ; * oconv | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then | |||
crt 'No conversion given' | |||
gosub bad.comd ; return | |||
end | |||
ccom = rest ; gosub conv.command | |||
case comd[1,2] eq 'OO' ; * undo last change | |||
if oopc ne '' then | |||
this = oops | |||
here = oopl | |||
last = oopf | |||
beg = oopb<1> | |||
fin = oopb<2> | |||
krj = oopk | |||
gosub set.record | |||
crt '"':oopc:'" undone - now at line ':here:'.' | |||
oops = '' ; oopc = '' ; oopl = '' ; oopf = '' | |||
oopb = '' ; oopk = '' | |||
gosub display.line | |||
end else | |||
crt 'last change already "undone" or nothing to undo' | |||
end | |||
comi = '' | |||
case comd eq 'OUT' | |||
gosub outline | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
p: begin case | |||
case comd eq 'P' ; * page on | |||
if numb else numb = plen | |||
if here ge last then here = 0 | |||
here += 1 | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub display.line | |||
next here | |||
here = dusk | |||
case comd eq 'PA' ; * print window up to here | |||
if numb else numb = pwin | |||
save = here | |||
here = here - numb | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub display.line | |||
next here | |||
here = save | |||
crt 'Still at line ':here:'.' | |||
case comd = 'PASTE' and rest eq '' ; * paste from kept | |||
if viewflag then gosub viewonly ; return | |||
if kept eq '' then | |||
crt 'Nothing in KEPT buffer' | |||
comi = '' ; return | |||
end | |||
gosub savethat | |||
numb = dcount(kept,am) | |||
this = insert(this,here+1,0,0,kept) | |||
gosub set.record | |||
crt 'Pasted ':numb:' lines from KEPT buffer; still at line ':here:'.' | |||
if beg gt here then beg += numb | |||
if fin gt here then fin += numb | |||
xxno = dcount(krj<1>,vm) | |||
for xx = 1 to xxno | |||
if krj<2,xx> gt here then krj<2,xx> += numb | |||
next xx | |||
case comd eq 'PASTE' ; * save the kept buffer | |||
if viewflag then gosub viewonly ; return | |||
if kept eq '' then | |||
crt 'Nothing in KEPT buffer' | |||
comi = '' ; return | |||
end | |||
gosub save.stuff | |||
case comd eq 'PE' ; * page editor mode | |||
if not(editpage) then | |||
crt 'Page editing not possible at this terminal' | |||
comi = '' | |||
return | |||
end | |||
that = this ; savl = here:am:last | |||
if this eq '' then this = am | |||
if here lt 1 then here = 1 | |||
ptop = here | |||
mode = 'PAGE':am:'View' | |||
if sec.write.flg then mode<2> = 'Ins' | |||
pchr = 1 | |||
chng = '' ; show = '' | |||
gosub display.page | |||
*> | |||
gosub get.line | |||
*> | |||
temp = line | |||
case comd eq 'PL' ; * print window from here | |||
if numb else numb = pwin | |||
save = here | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub display.line | |||
next here | |||
here = save | |||
crt 'Still at line ':here:'.' | |||
case comd eq 'PP' ; * print window bracketing here | |||
if numb else numb = pwin | |||
save = here | |||
here = here - int(numb/2) | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub display.line | |||
next here | |||
here = save | |||
crt 'Still at line ':here:'.' | |||
case comd eq 'PR' ; * prestore processing | |||
if numb eq '' then | |||
crt 'Defined prestores (':presnumb:' Maximum)' | |||
for xx = 1 to presnumb | |||
temp = pres<1,xx> | |||
convert sm to comdmark in temp | |||
$ifdef unidata | |||
crt fmt(xx,'2/0R'):' ':temp | |||
$else | |||
crt fmt(xx,'R%2'):' ':temp | |||
$endif | |||
next xx | |||
return | |||
end | |||
if numb gt presnumb or numb lt 1 then | |||
crt 'PRestore must be in range 1-':presnumb:'.' | |||
comi = '' | |||
return | |||
end | |||
if dlim ne '' then | |||
if not(rest eq rest<1,1,1>) then | |||
crt 'Invalid - delimiter in prestore' | |||
comi = '' | |||
return | |||
end | |||
pres<1,numb> = change(rest,dlim,sm) | |||
end else | |||
salt = pres<1,numb> | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
q: begin case | |||
* Various forms for quitting | |||
case comd eq 'Q' or comd = 'QK' or comd = 'QUIT' or comd = 'QUITK' | |||
if not(viewflag) and (orig ne this) then | |||
stub = '***** Record changed --- OK to Quit? (N/Y)>' | |||
gosub get.answ | |||
if answ eq yes[1,1] then stopsign = true | |||
end else stopsign = true | |||
if stopsign then | |||
if orig eq '' then | |||
crt 'Quit "':item:'" in file "':fnam:'" not created.' | |||
end else crt 'Quit "':item:'" in file "':fnam:'" unchanged.' | |||
if index(comd,'K',1) then | |||
killsign = true | |||
if idcnt gt 1 then crt 'Select list cancelled.' | |||
end | |||
end | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
r: begin case | |||
case comd eq 'RA' ; * view or repeat change | |||
if viewflag then gosub viewonly ; return | |||
gosub change.command | |||
case comd eq 'R' and dlim ne '' and index(rest,dlim,1) ; * change | |||
if viewflag then gosub viewonly ; return | |||
crt ; comd = 'C' | |||
gosub change.command | |||
case comd eq 'R' ; * replace lines | |||
if viewflag then crt ; gosub viewonly ; return | |||
if not(last) then | |||
crt 'Empty record, use Insert (I) command.' | |||
comi = '' | |||
return | |||
end | |||
if here lt 1 then here = 1 ; gosub display.line | |||
chng = 0 ; save = here ; savl = last | |||
if numb lt 1 then numb = 1 | |||
if dlim ne '' and rest eq '' then rest = ' ' | |||
loop | |||
crt begn: | |||
if lfmt then crt fmt(here,lfmt):'=': | |||
crt ceop: | |||
if rest eq '' then | |||
stub = here:'=' | |||
if lfmt then stub = fmt(here,lfmt):'=' | |||
gosub get.rope; line = rope | |||
end else line = rest | |||
gosub parse.line | |||
until line eq '' do | |||
crt goup:begn:ceol: | |||
if lfmt then crt fmt(here,lfmt):': ': | |||
crt line | |||
if line eq comdmark then | |||
line = '' | |||
crt begn: | |||
if lfmt then crt fmt(here,lfmt):': ': | |||
end | |||
if numb gt 1 then crt | |||
if line eq ' ' then line = '' | |||
if not(chng) then gosub savethis | |||
chng += 1 | |||
memr(cell)<lnum> = line | |||
here += 1 ; numb -= 1 | |||
gosub get.line | |||
if numb eq 0 then exit | |||
repeat | |||
if here ne save then here -= 1 | |||
if chng then gosub reset.record; gosub get.line | |||
crt begn:ceol: | |||
case comd eq 'RELEASE' ; * release the item lock | |||
release file,item | |||
lock = false | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
s: begin case | |||
case comd eq 'S' ; * search processing | |||
if numb eq '' then | |||
crt 'Last ':looknumb:' searches (latest first)' | |||
for xx = 1 to looknumb | |||
$ifdef unidata | |||
crt fmt(xx,'2/0R'):' ':look<1,xx> | |||
$else | |||
crt fmt(xx,'R%2'):' ':look<1,xx> | |||
$endif | |||
next xx | |||
return | |||
end | |||
if numb gt looknumb or numb lt 1 then | |||
crt 'Search must be in range 1-':looknumb:'.' | |||
comi = '' | |||
return | |||
end | |||
comi = look<1,numb> | |||
if comi eq '' then | |||
crt 'There is no search number ':numb:'.' | |||
return | |||
end | |||
look = delete(look,1,numb,0) | |||
look = insert(look,1,1,0,comi) | |||
gosub parse.command | |||
if comd eq '' then comd = 'L' ; numb = huge | |||
comi = '' | |||
redo = true | |||
case comd eq 'SAVE' or comd eq 'SV' ; * save the item | |||
if viewflag then gosub viewonly ; return | |||
comd = 'SV' | |||
if rest eq '' then | |||
if not(sec.write.flg) then | |||
crt 'File disabled' | |||
comi = '' | |||
return | |||
end | |||
gosub write.record | |||
end else gosub save.stuff | |||
case comd eq 'SEQ' ; * build a sequence | |||
if viewflag then gosub viewonly ; return | |||
if dlim eq '' then | |||
crt 'Too few fields in this command.' | |||
gosub bad.comd ; return | |||
end | |||
good = true | |||
cfrom = field(rest,dlim,1) | |||
cto = field(rest,dlim,2) | |||
if cto eq '' then cto = 1 | |||
if not(num(cto)) then | |||
crt 'Base for sequence command must be a number.' | |||
good = false | |||
end | |||
bit = field(rest,dlim,3) | |||
if bit eq '' then bit = 1 | |||
if not(num(bit)) then | |||
crt 'Increment for sequence command must be a number.' | |||
good = false | |||
end else | |||
if not(bit) then | |||
crt 'Increment for sequence command must not be zero.' | |||
good = false | |||
end | |||
end | |||
if not(good) then gosub bad.comd ; return | |||
rest = dlim:field(rest,dlim,4,2) | |||
if rest ne dlim then | |||
gosub parse.cols | |||
if not(good) then return | |||
end else cols = '' | |||
chng = 0 ; save = here ; savl = last | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line ; temp = line | |||
if cols then | |||
bite = index(line[cols,colf],cfrom,1) | |||
if bite then bite = bite + cols - 1 | |||
end else | |||
bite = index(line,cfrom,1) | |||
end | |||
if bite then | |||
temp = line[1,bite-1]:cto | |||
temp = temp:line[bite+len(cfrom),len(line)] | |||
end | |||
if '*':temp ne '*':line then | |||
cto = cto + bit | |||
if not(chng) then gosub savethis | |||
chng += 1 | |||
memr(cell)<lnum> = temp | |||
gosub display.line | |||
end | |||
next here | |||
here = dusk | |||
if chng then gosub reset.record | |||
case comd eq 'SHOW' ; * show changes flag | |||
rest = upcase(rest) | |||
begin case | |||
case rest eq 'ON' ; shew = true | |||
case rest eq 'OFF' ; shew = false | |||
case 1 ; shew = not(shew) | |||
end case | |||
if shew | |||
then crt 'Show changes flag is ON' | |||
else crt 'Show changes flag is OFF' | |||
case comd eq 'SORT' or comd eq 'SORTU' ; * sort the block | |||
if viewflag then gosub viewonly ; return | |||
test = index(comd,'U',1) | |||
if not(beg) and not(fin) then | |||
crt 'Command requests a block operation, but no block is defined.' | |||
gosub bad.comd | |||
return | |||
end | |||
if beg le 1 then | |||
temp = 0 | |||
end else | |||
temp = index(this,am,beg-1) | |||
if not(temp) then | |||
crt 'Cannot find beginning of block' | |||
gosub bad.comd ; return | |||
end | |||
end | |||
rest = upcase(rest) | |||
if rest eq '' then rest = 'AL' | |||
if not(index('*AR*AL*DR*DL*','*':rest:'*',1)) then | |||
crt 'Invalid sort sequence - use "AL" "AR" "DL" or "DR"' | |||
gosub bad.comd ; return | |||
end | |||
temp<2> = index(this,am,fin) | |||
if fin eq last then temp<2> = len(this)+1 | |||
if not(temp<2>) then | |||
crt 'Cannot find end of block' | |||
gosub bad.comd ; return | |||
end | |||
if blockflag then | |||
stub = 'Sort block beginning at ': beg:' and ending at ': fin:'?' | |||
gosub get.answ | |||
if answ ne yes[1,1] then | |||
crt 'Block command cancelled.' | |||
return | |||
end | |||
end | |||
gosub savethat | |||
bits = '' | |||
for here = beg to fin | |||
gosub get.line | |||
locate(line,bits;posn;rest) then | |||
if test then good = false else good = true | |||
end else good = true | |||
if good then bits = insert(bits,posn;line) | |||
next here | |||
here = oopl | |||
if fin ne last | |||
then this = this[1,temp<1>]:bits:am:this[temp<2>+1,len(this)] | |||
else this = this[1,temp<1>]:bits | |||
bits = '' | |||
gosub set.record | |||
* If any tags are in the sorted block then clear the tags, | |||
* as it really makes no sense to try and sort them. | |||
good = true | |||
xxno = dcount(krj<1>,vm) | |||
for xx = 1 to xxno | |||
posn = krj<2,xx> | |||
if posn ge beg and posn le fin then good = false | |||
next xx | |||
if not(good) then | |||
krj = '' | |||
crt 'Tags cleared' | |||
end | |||
gosub display.line | |||
case comd eq 'SPACE' ; * change spacing flag for 'L' | |||
rest = upcase(rest) | |||
begin case | |||
case rest eq 'ON' ; spaceflag = true | |||
case rest eq 'OFF' ; spaceflag = false | |||
case 1 ; spaceflag = not(spaceflag) | |||
end case | |||
if spaceflag then | |||
crt 'SPACE flag is ON' | |||
end else crt 'SPACE flag is OFF' | |||
case comd eq 'SPOOL' ; * print | |||
save = here | |||
if numb eq '' and rest matches '1N0N' then numb = rest | |||
if numb eq '' then here = 1 ; numb = last | |||
gosub set.bounds | |||
head = 'Record - ':item:' File - ':fnam:' Account - ':acct:' ' | |||
head = head:timedate():"'LL'" | |||
temp = span | |||
printer on | |||
temp = temp - llen - 2 | |||
heading head | |||
for here = dawn to dusk | |||
gosub get.line | |||
convert badc to gudc in line | |||
print fmt(here,lfmt):': ':line[1,temp] | |||
loop | |||
line = line[temp+1,len(line)] | |||
until line eq '' do | |||
print space(llen+2):line[1,temp] | |||
repeat | |||
next here | |||
printer close | |||
if dawn ne 1 or dusk ne last then | |||
crt 'Lines ':dawn:' to ':dusk:' of ': | |||
end | |||
crt '"':item:'" spooled to the printer.' | |||
here = save | |||
case comd eq 'SPOOLHELP' ; * print the help | |||
rest = am | |||
gosub show.help | |||
case comd eq 'STAMP' ; * stamp it | |||
if viewflag then gosub viewonly ; return | |||
gosub savethat | |||
last += 1 ; here += 1 ; lnum += 1 | |||
line = '* Last updated by ':name:' in account ':acct:' at ':timedate() | |||
gosub insert.line | |||
gosub reset.record | |||
gosub display.line | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
t: begin case | |||
case comd eq 'T' ; * top | |||
here = 0 | |||
gosub display.line | |||
case comd eq 'TC' ; * text case (make line in) | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then ccom = 'MCT' else ccom = 'QMCT' | |||
gosub conv.command | |||
* Various ways to TRIM the line | |||
case comd eq 'TRIM' or comd = 'TRIMF' or comd = 'TRIMB' | |||
if viewflag then gosub viewonly ; return | |||
chng = 0 ; save = here ; savl = last | |||
if rest and comd eq 'TRIM' then | |||
seek = field(rest,dlim,1) | |||
if seek matches '3n' then seek = char(seek) | |||
mark = field(rest,dlim,2) | |||
mark = upcase(trim(mark))[1,1] | |||
if index('ABCDEFLRT',mark,1) else | |||
crt 'Invalid TRIM argument - must be one of "ABCDEFLRT"' | |||
gosub bad.comd | |||
return | |||
end | |||
end else seek = '' | |||
show = shew ; dnum = 1 | |||
if numb eq '' and rest matches '1N0N' then numb = rest | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line | |||
begin case | |||
case comd eq 'TRIM' | |||
if seek eq '' | |||
then temp = trim(line) | |||
else temp = trim(line,seek,mark) | |||
case comd eq 'TRIMF' ; temp = trimf(line) | |||
case comd eq 'TRIMB' ; temp = trimb(line) | |||
end case | |||
gosub check.line | |||
next here | |||
here = dusk | |||
if chng then | |||
gosub reset.record | |||
crt chng:' lines changed - now at ':here | |||
end | |||
case comd eq 'TWIN' or comd eq 'TRIPLE' ; * sideways cloning of line | |||
if viewflag then gosub viewonly ; return | |||
if dlim ne '' then | |||
line = rest ; gosub parse.line ; join = line | |||
end | |||
if here and here le last else return | |||
chng = 0 ; save = here | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line | |||
if comd eq 'TWIN' | |||
then test = line:join:line | |||
else test = line:join:line:join:line | |||
if test ne line then | |||
chng += 1 | |||
memr(cell)<lnum> = test | |||
end | |||
next here | |||
if chng eq 0 then return | |||
temp = 'Split ':chng:' lines' | |||
if join ne '' then temp := ' and joined the parts with "':join:'"' | |||
crt temp | |||
here = save | |||
gosub savethat | |||
gosub reset.record | |||
gosub display.line | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
u: begin case | |||
case comd eq 'U' ; * same as "-" | |||
if numb eq '' then numb = 1 | |||
here = here - numb | |||
if here lt 0 then here = 0 | |||
if here gt last then here = last | |||
gosub display.line | |||
case comd eq 'UC' ; * upper case (make line in) | |||
if viewflag then gosub viewonly ; return | |||
if rest eq '' then ccom = 'MCU' else ccom = 'QMCU' | |||
gosub conv.command | |||
case comd eq 'UNLOAD' ; comd = 'SV' ; redo = true | |||
if viewflag then gosub viewonly ; return | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
v: begin case | |||
case comd eq 'V' ; * version information | |||
crt (upcase(verb):' = ') 'R#20':help.def | |||
$ifdef qm | |||
temp = trans('NEWVOC','$RELEASE',2,'X') | |||
if temp eq '' then | |||
temp = trans('VOC','$RELEASE',2,'X') | |||
end | |||
if temp eq '' then temp = '?' | |||
crt ('QM = ') 'R#20':temp | |||
*> | |||
crt ('Licence = ') 'R#20':system(31) | |||
*> | |||
$endif | |||
$ifdef unidata | |||
crt ' UniData version ':oconv('version','TVOC;X;;1') | |||
$endif | |||
$ifdef universe | |||
temp = oconv('RELLEVEL','TNEWACC;X;;2') | |||
if temp eq '' then | |||
temp = oconv('RELLEVEL','TVOC;X;;2') | |||
end | |||
if temp eq '' then temp = 'not known' | |||
crt ' UniVerse version ':temp | |||
case comd eq 'VLIST' | |||
execute comi capturing disp | |||
stub = "Press return to continue showing VLIST 'T'op '-'back 'Q'uit" | |||
gosub show.disp | |||
$endif | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
w: begin case | |||
case comd eq 'W' or comd eq 'WHERE' ; * what we are editing | |||
crt | |||
if viewflag | |||
then crt 'Viewing "':item:'" in file "':fnam:'"' | |||
else crt 'Editing "':item:'" in file "':fnam:'"' | |||
if idcnt gt 1 then crt ' [':id:'/':idcnt:']': | |||
crt | |||
if here gt last then here = last | |||
gosub display.line | |||
case comd eq 'WM' ; * word marker display (change) | |||
if dlim ne '' then wordmark = dlim | |||
if wordmark eq '"' | |||
then crt 'WordMark is ':"'":wordmark:"'" | |||
else crt 'WordMark is ':'"':wordmark:'"' | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
x: begin case | |||
* Another way of quitting | |||
case comd eq 'X' ; comd = 'QK' ; redo = true | |||
case comd eq 'XEQ' ; * execute a command | |||
if viewflag then gosub viewonly ; return | |||
if not(sec.xeq.flg) then | |||
crt 'XEQ disabled' | |||
comi = '' | |||
return | |||
end | |||
loop | |||
if rest ne '' then execute rest | |||
test = @(0,0) | |||
stub = '<RETURN> or command :' | |||
gosub get.rope; rest = rope | |||
if rest eq '' then | |||
crt; crt 'Returned - ': | |||
crt 'Editing "':item:'" in file "':fnam:'"' | |||
end | |||
until rest eq '' do | |||
*> | |||
crt | |||
*> | |||
repeat | |||
gosub display.line | |||
case comd eq 'XTD' ; * hex to decimal | |||
$ifdef universe | |||
crt xtd(rest) | |||
$else | |||
crt iconv(rest,'MX') | |||
$endif | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
y: begin case | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
z: begin case | |||
case 1 ; gosub bad.command | |||
end case | |||
return | |||
set.bounds: | |||
if numb eq '' then numb = 1 | |||
dawn = here | |||
if dawn lt 1 then dawn = 1 | |||
dusk = dawn + numb - 1 | |||
if dusk gt last then dusk = last | |||
numb = 0 | |||
return | |||
null.command: | |||
if dlim eq ':' then comd = 'XEQ' ; return | |||
if dlim eq '/' then | |||
comd = 'L' | |||
if numb eq '' then numb = huge | |||
return | |||
end | |||
if dlim eq '-' or dlim eq '+' then | |||
if rest eq '' then rest = 1 | |||
end | |||
if numb ne '' then comd = numb ; return | |||
if dlim eq '' and rest eq '' then | |||
here += 1 | |||
if here gt last then here = 1 | |||
gosub display.line | |||
return | |||
end | |||
crt | |||
begin case | |||
case dlim eq '+' and rest matches '1N0N' | |||
here = here + rest | |||
if here gt last then here = last | |||
gosub display.line | |||
case dlim eq '-' and rest matches '1N0N' | |||
here = here - rest | |||
if here lt 0 then here = 0 | |||
if here gt last then here = last | |||
gosub display.line | |||
case dlim eq '^' | |||
wild = not(wild) | |||
if wild | |||
then crt 'Expansion of non-printing characters enabled' | |||
else crt 'Expansion of non-printing characters disabled' | |||
case dlim eq '=' | |||
crt 'UNIDATA prestore is not implemented - Use "PR"' | |||
case dlim eq '.' | |||
gosub dot.command | |||
case dlim eq '$' | |||
if not(sec.xcom.flg) then | |||
crt '$ external commands disabled' | |||
comi = '' | |||
return | |||
end | |||
save = comi ; comi = rest | |||
gosub parse.command | |||
comi = save | |||
comd = '$':comd | |||
xcom = oconv(comd,'TAE_XCOMS;X;2;2') | |||
begin case | |||
case xcom eq '' | |||
crt 'Record "':comd:'" does not exist in "AE_XCOMS".' | |||
case xcom[len(xcom)-2,3] ne '_AE' | |||
disp = '' | |||
disp<-1> = "Line 2 of record '":rest:"' in file 'AE_XCOMS'" | |||
disp<-1> = "contains '":xcom:"'." | |||
disp<-1> = '' | |||
disp<-1> = 'This line should contain the name of a Basic subroutine that' | |||
disp<-1> = "has been written to implement the external command '":rest:"'." | |||
disp<-1> = "The program name must end in '_AE'." | |||
stub = 'Press RETURN to continue' | |||
gosub show.disp | |||
case 1 | |||
that = this ; savl = here:am:last:beg:am:fin:am:krj | |||
save = comi:am:comd:am:item:am:fnam | |||
comd = comd:' ':rest | |||
call @xcom(mat junk) | |||
item = save<3> | |||
fnam = save<4> | |||
if here lt 0 then here = 0 | |||
gosub set.record | |||
if here gt last then here = last | |||
comd = '' | |||
if that ne this then | |||
crt save<2>:' - CHANGES HAVE BEEN MADE' | |||
oops = that ; oopc = save<1> | |||
oopl = savl<1> ; oopf = savl<2> | |||
oopb = savl<3>:am:savl<4> ; oopk = field(savl,am,5,3) | |||
end | |||
that = '' | |||
end case | |||
case comi eq '?' | |||
disp = ' Login name = ':name:' (':term:', userno ':whom:')' | |||
disp<-1> = ' Account = ':acct | |||
if path ne '' then disp<-1> = ' VOC path = ':path | |||
disp<-1> = ' Level = ':levl | |||
disp<-1> = ' File name = ':fnam | |||
disp<-1> = ' Record id = ':item | |||
disp<-1> = ' Current line = ':here | |||
disp<-1> = ' Lines = ':last | |||
disp<-1> = ' Characters = ':len(this) | |||
if chan ne '' then | |||
disp<-1> = 'Last Change command = ':chan<1,1> | |||
end | |||
if cmat ne '' then | |||
temp = 'CM':cmat<1,3>:cmat<1,1>:cmat<1,2> | |||
disp<-1> = 'Last CMatch command = ':temp | |||
end | |||
if olda then | |||
temp = 'A':olda<1,2>:olda<1,1> | |||
disp<-1> = 'Last Append command = ':temp | |||
end | |||
if beg or fin then | |||
disp<-1> = ' Block = ':beg:'-':fin | |||
end | |||
if comdmark eq '"' then | |||
temp = "'":comdmark:"'" | |||
end else temp = '"':comdmark:'"' | |||
disp<-1> = 'Command Delimiter is ':temp:', ' | |||
if nill eq '"' then | |||
temp = "'":nill:"'" | |||
end else temp = '"':nill:'"' | |||
disp := 'character to end inserting is ':temp:', ' | |||
if wordmark eq '"' then | |||
temp = "'":wordmark:"'" | |||
end else temp = '"':wordmark:'"' | |||
disp := 'WordMark is ':temp | |||
disp<-1> = 'Page: window for PA/PL/PP is ':pwin:', length for P is ':plen | |||
if wild | |||
then disp<-1> = 'Expansion of non-printing characters enabled' | |||
else disp<-1> = 'Expansion of non-printing characters disabled' | |||
if caseflag then | |||
disp<-1> = 'CASE':' flag ON':', ' | |||
end else disp<-1> = 'CASE':' flag OFF':', ' | |||
if spaceflag then | |||
disp := 'SPACE':' flag ON':', ' | |||
end else disp := 'SPACE':' flag OFF':', ' | |||
if shew then | |||
disp := 'SHOW':' flag ON':', ' | |||
end else disp := 'SHOW':' flag OFF':', ' | |||
if blockflag then | |||
disp := 'BLOCK':' flag ON' | |||
end else disp := 'BLOCK':' flag OFF' | |||
if oopc ne '' then | |||
disp<-1> = 'OOPS will restore record prior to command: ':oopc | |||
end else | |||
disp<-1> = 'OOPS already executed, or no changes in effect.' | |||
end | |||
gosub show.disp | |||
case comi[1,2] eq '<>' ; gosub botharr | |||
case comi[1,1] eq '<' ; gosub leftarr | |||
case comi[1,1] eq '>' ; gosub rightarr | |||
case dlim eq '\' and rest[1,1] eq '\' ;* clear the tag pointers | |||
krj = '' | |||
crt 'Tags cleared' | |||
case dlim eq '\' ;* set a tag pointer | |||
locate(here,krj,2;posn) then | |||
crt 'There is already a Tag on line ':here | |||
return | |||
end | |||
if rest eq '' then rest = 'T':here | |||
rest = upcase(rest) | |||
locate(rest,krj,1;posn) then | |||
crt 'There is already a Tag labelled ':rest | |||
return | |||
end | |||
posn = krj<3> | |||
krj<1> = field(krj<1>,vm,1,posn) | |||
posn += 1 | |||
krj<1,posn> = rest | |||
krj<2,posn> = here | |||
krj<3> = posn | |||
crt 'Setting Tag labelled ':rest:' at line ':here | |||
case (dlim eq '[' or dlim eq ']') and (rest[1,1] eq '[' or rest[1,1] eq ']') | |||
if krj<3> eq '' | |||
then disp = 'No Tag found' | |||
else disp = 'Tags at line-Labelled' | |||
posn = krj<3> | |||
xxno = dcount(krj<1>,vm) | |||
for xx = 1 to xxno | |||
disp<-1> = krj<2,xx> 'r#12' | |||
if xx eq posn then disp := '>' else disp := ' ' | |||
disp := krj<1,xx> | |||
next xx | |||
convert badc to gudc in disp | |||
gosub show.disp | |||
case dlim eq '[' and rest eq '' | |||
posn = krj<3>-1 | |||
if posn gt 0 then | |||
comd = krj<2,posn> | |||
krj<3> = posn | |||
crt 'Moved to line ':comd:' labelled ':krj<1 | |||
end else comd = '' | |||
if comd eq '' then crt 'No Tag found' | |||
case dlim eq ']' and rest eq '' | |||
posn = krj<3>+1 | |||
comd = krj<2,posn> | |||
if comd eq '' then | |||
crt 'No Tag found' | |||
end else | |||
krj<3> = posn | |||
crt 'Moved to line ':comd:' labelled ':krj<1 | |||
end | |||
case dlim eq '[' or dlim eq ']' | |||
locate(upcase(rest),krj,1;posn) then comd = krj<2,posn> else comd = '' | |||
if comd ne '' then | |||
krj<3> = posn | |||
crt 'Moved to line ':comd:' labelled ':krj<1 | |||
return | |||
end else crt 'No Tag found' | |||
case 1 | |||
gosub bad.command | |||
end case | |||
return | |||
parse.cols: | |||
good = true | |||
cols = field(rest,dlim,2) | |||
convert ',.' to '--' in cols | |||
rest = field(rest,dlim,1) | |||
colf = field(cols,'-',2) | |||
cols = field(cols,'-',1) | |||
if colf eq '' then colf = cols | |||
if cols ne '' then | |||
if not(cols matches '1N0N') or not(colf matches '1N0N') then | |||
crt 'Column specifications must be positive whole numbers.' | |||
gosub bad.comd | |||
good = false | |||
return | |||
end | |||
end | |||
if colf lt cols then | |||
crt 'Ending column # must exceed or equal starting column #.' | |||
gosub bad.comd | |||
good = false | |||
return | |||
end | |||
colf = colf - cols + 1 | |||
return | |||
parse.atts: | |||
convert '-' to dlim in rest | |||
if dlim eq '"' then temp = "'" else temp = '"' | |||
temp = '1N0N':temp:dlim:temp:'1N0N' | |||
if rest matches temp then | |||
numb = field(rest,dlim,2) - field(rest,dlim,1) + 1 | |||
rest = field(rest,dlim,1) | |||
end | |||
return | |||
change.command: | |||
if comd eq 'RA' then | |||
if numb eq '' then | |||
crt 'Last ':channumb:' changes (latest first)' | |||
for xx = 1 to channumb | |||
$ifdef unidata | |||
crt fmt(xx,'2/0R'):' ':chan<1,xx> | |||
$else | |||
crt fmt(xx,'R%2'):' ':chan<1,xx> | |||
$endif | |||
next xx | |||
return | |||
end | |||
if numb gt channumb or numb lt 1 then | |||
crt 'Change must be in range 1-':channumb:'.' | |||
comi = '' | |||
return | |||
end | |||
comi = chan<1,numb> | |||
if comi eq '' then | |||
crt 'There is no change number ':numb:'.' | |||
return | |||
end | |||
chan = delete(chan,1,numb,0) | |||
chan = insert(chan,1,1,0,comi) | |||
gosub parse.command | |||
comi = 'RA' | |||
end | |||
save = upcase(field(rest,dlim,3,2)) | |||
if save ne '' then rest = rest[1,col1()] | |||
gosub get.fromto | |||
temp = save | |||
if comi eq '' then return | |||
chng = 0 ; save = here ; savl = last | |||
glob = index(temp,'G',1) | |||
show = shew or index(temp,'S',1) | |||
convert dlim:'GS' to '-' in temp | |||
rest = dlim:temp | |||
gosub parse.cols | |||
if not(good) then return | |||
if numb lt plen then show = true | |||
dnum = 1 | |||
gosub set.bounds | |||
for here = dawn to dusk | |||
gosub get.line | |||
gosub change.line | |||
gosub check.line | |||
next here | |||
here = dusk | |||
if comi ne '' and upcase(comi) ne 'RA' then | |||
chan = insert(chan,1,1,0,comi) | |||
chan = delete(chan,1,channumb,0) | |||
end | |||
if chng then | |||
gosub reset.record | |||
if not(show) and dnum gt plen then | |||
crt chng:' lines changed - now at ':here | |||
end | |||
end | |||
return | |||
get.fromto: | |||
if count(rest,dlim) gt 2 then | |||
crt 'Too many delimiters (3 max.).' | |||
comi = '' | |||
return | |||
end | |||
line = field(rest,dlim,1) | |||
gosub parse.line | |||
cfrom = line | |||
line = field(rest,dlim,2) | |||
gosub parse.line | |||
cto = line | |||
if cto eq '' and count(rest,dlim) lt 2 then | |||
crt 'Missing required TO field (for "CHANGE/FROM/TO").' | |||
comi = '' | |||
return | |||
end | |||
return | |||
change.line: | |||
if cfrom eq '' then | |||
temp = cto:line | |||
end else | |||
if glob then | |||
temp = change(line,cfrom,cto) | |||
end else | |||
temp = index(line,cfrom,1) | |||
if temp then | |||
temp = line[1,temp-1]:cto:line[temp+len(cfrom),len(line)] | |||
end else temp = line | |||
end | |||
end | |||
return | |||
conv.command: | |||
chng = 0 ; save = here ; savl = last | |||
show = shew or index(rest,'S',1) or index(rest,'s',1) | |||
dnum = 1 | |||
if numb lt plen then show = true | |||
if numb eq '' and rest matches '1N0N' then numb = rest | |||
gosub set.bounds | |||
ctyp = ccom[1,1] | |||
begin case | |||
* ICONV | |||
case ctyp eq '*' ; ccom = ccom[2,huge] | |||
* Text conversion LC, TC, or UC command | |||
case ctyp eq 'Q' ; ccom = ccom[2,huge] | |||
end case | |||
for here = dawn to dusk | |||
gosub get.line | |||
begin case | |||
case ctyp eq '*' | |||
temp = iconv(line,ccom) | |||
case ctyp eq 'Q' | |||
temp = field(trim(line),' ',1) | |||
flag = false | |||
if temp ne 'REMOVE' then | |||
if temp[1,3] eq 'REM' then flag = true | |||
if temp[1,1] eq '*' then flag = true | |||
if temp[1,1] eq '!' then flag = true | |||
end | |||
if flag then | |||
temp = line | |||
end else | |||
xxno = len(line) | |||
temp = '' | |||
flag = '' | |||
for xx = 1 to xxno | |||
bit = line[xx,1] | |||
begin case | |||
case bit eq flag ; flag = '' | |||
case flag ne '' | |||
case index(qt,bit,1) ; flag = bit | |||
*> | |||
case bit eq ';' | |||
test = trim(line[xx+1,huge])[1,1] | |||
if test eq '*' or test eq '!' then flag = am | |||
*> | |||
case 1 ; bit = oconv(bit,ccom) | |||
end case | |||
temp = temp:bit | |||
next xx | |||
end | |||
case 1 | |||
temp = oconv(line,ccom) | |||
end case | |||
if temp eq '' then temp = line | |||
gosub check.line | |||
next here | |||
here = dusk | |||
if chng then | |||
gosub reset.record | |||
if not(show) and dnum gt plen then | |||
crt chng:' lines changed - now at ':here | |||
end | |||
end | |||
return | |||
dot.command: | |||
if trim(comi) eq '.' then comi = '.L1' | |||
save = comi | |||
comi = field(comi,dlim,2,huge) | |||
gosub parse.command | |||
begin case | |||
case comd eq 'A' ; * append to line | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) then | |||
crt 'History command ':numb:' does not exist.' | |||
end else | |||
stak<1,numb> := rest | |||
$ifdef unidata | |||
crt fmt(numb,'3/0R'):'. ':stak<1,numb> | |||
$else | |||
crt fmt(numb,'R%3'):'. ':stak<1,numb> | |||
$endif | |||
end | |||
case comd eq 'C' ; * change lines | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) then | |||
crt 'History command ':numb:' does not exist.' | |||
end else | |||
gosub get.fromto | |||
if comi eq '' then comd = '' ; return | |||
glob = index(field(rest,dlim,3),'G',1) | |||
glob = glob + index(field(rest,dlim,3),'g',1) | |||
line = stak<1,numb> | |||
gosub change.line | |||
stak<1,numb> = temp | |||
$ifdef unidata | |||
crt fmt(numb,'3/0R'):'. ':temp | |||
$else | |||
crt fmt(numb,'R%3'):'. ':temp | |||
$endif | |||
end | |||
case comd eq 'D' ; * delete lines | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) then | |||
crt 'History command ':numb:' does not exist.' | |||
end else | |||
stak = delete(stak,1,numb,0) | |||
crt 'History #':numb:' DELETEd.' | |||
end | |||
case comd eq 'I' ; * insert a new line | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) then | |||
crt 'History command ':numb:' does not exist.' | |||
end else | |||
if rest ne '' then | |||
stak = insert(stak,1,numb,0,rest) | |||
stak = delete(stak,1,staknumb,0) | |||
$ifdef unidata | |||
crt fmt(numb,'3/0R'):'. ':stak<1,numb> | |||
$else | |||
crt fmt(numb,'R%3'):'. ':stak<1,numb> | |||
$endif | |||
end | |||
end | |||
case comd eq 'L' ; * list lines | |||
if numb eq '' then numb = plen | |||
if numb gt dcount(stak,vm) then numb = dcount(stak,vm) | |||
temp = rem(numb+1,plen) | |||
for xx = numb to 1 step -1 | |||
$ifdef unidata | |||
crt fmt(xx,'3/0R'):'. ':stak<1,xx> | |||
$else | |||
crt fmt(xx,'R%3'):'. ':stak<1,xx> | |||
$endif | |||
if xx gt 1 and rem(xx,plen) eq temp then | |||
stub = 'Press return to continue, Q to quit' | |||
rlen = 1 | |||
gosub get.rope; crt begn:ceol: | |||
wait = trim(upcase(rope))[1,1] | |||
if wait eq 'Q' then exit | |||
end | |||
next xx | |||
case comd eq 'R' ; * restore a line to latest | |||
if numb eq '' then numb = 1 | |||
if numb le dcount(stak,vm) then | |||
temp = stak<1,numb> | |||
stak = insert(stak,1,1,0,temp) | |||
stak = delete(stak,1,staknumb,0) | |||
end | |||
case comd eq 'S' | |||
if numb eq '' then numb = 1 | |||
if numb gt presnumb then | |||
crt numb:' is greater than pre-store limit of ':presnumb | |||
return | |||
end | |||
rest = trim(rest) | |||
dawn = field(rest,dlim,1) ; if dawn eq '' then dawn = 1 | |||
dusk = field(rest,dlim,2) ; if dusk eq '' then dusk = 1 | |||
if not(dawn matches '1N0N' and dusk matches '1N0N') then | |||
crt 'One of the values was not a number' | |||
return | |||
end | |||
if dawn gt dusk then temp = dawn ; dawn = dusk ; dusk = temp | |||
temp = '' | |||
for xx = dusk to dawn step -1 | |||
temp<1,1,-1> = stak<1,xx> | |||
next xx | |||
pres<1,numb> = temp | |||
case comd eq 'U' ; * upcase line | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) | |||
then crt 'History command ':numb:' does not exist.' | |||
else stak<1,numb> = upcase(stak<1,numb>) | |||
case comd eq 'UL' ; * downcase line | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) | |||
then crt 'History command ':numb:' does not exist.' | |||
else stak<1,numb> = downcase(stak<1,numb>) | |||
case comd eq 'UT' ; * mixed case line | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) | |||
then crt 'History command ':numb:' does not exist.' | |||
else stak<1,numb> = oconv(stak<1,numb>,'mct') | |||
case comd eq 'X' ; * re-execute an editor command | |||
if numb eq '' then numb = 1 | |||
if numb gt dcount(stak,vm) then | |||
crt 'History command ':numb:' does not exist.' | |||
end else | |||
salt = stak<1,numb> | |||
stak = delete(stak,1,numb,0) | |||
end | |||
case 1 | |||
comi = save | |||
gosub bad.command | |||
end case | |||
comi = '' ; comd = '' | |||
return | |||
viewonly: | |||
crt 'That command is not allowed in VIEW mode':bell | |||
comi = '' | |||
return | |||
bad.command: | |||
crt 'Command not understood - try "H" for help.' | |||
bad.comd: | |||
xxno = len(comi) | |||
temp = '' | |||
for xx = 1 to xxno | |||
bite = comi[xx,1] | |||
bite = seq(bite) | |||
if bite ge 127 or bite lt 32 then | |||
$ifdef unidata | |||
bite = '^':fmt(bite,'3/0R') | |||
$else | |||
bite = '^':fmt(bite,'R%3') | |||
$endif | |||
end else bite = char(bite) | |||
temp = temp:bite | |||
next xx | |||
crt 'Command was: "':temp:'"' | |||
temp = '' | |||
comi = '' | |||
return | |||
save.stuff: | |||
if not(sec.unload.flg) then | |||
crt 'Unload disabled' | |||
comi = '' | |||
return | |||
end | |||
keepquot = false | |||
gosub parse.rest | |||
odpt = '' ; ofpt = bite<1> ; oipt = bite<2> | |||
onam = ofpt | |||
if ofpt eq 'DICT' then | |||
odpt = ofpt ; ofpt = oipt ; oipt = bite<3> | |||
onam = onam:' ':ofpt | |||
end | |||
if oipt eq '' then | |||
if odpt ne '' then | |||
crt 'Cannot save to null item.' | |||
gosub bad.comd ; return | |||
end | |||
oipt = ofpt ; odpt = dprt ; ofpt = fprt ; onam = fnam | |||
end | |||
if dprt eq odpt and fprt eq ofpt then | |||
ofil = file | |||
end else | |||
open odpt, ofpt to ofil else | |||
crt 'Cannot open ':'"':fnam:'"' | |||
gosub bad.comd ; return | |||
end | |||
end | |||
if prepflag then | |||
sec.call2.type = 2 | |||
sec.fn2 = ofpt | |||
sec.id2 = oipt | |||
sec.dict2.flg = (odpt = 'DICT') | |||
call @prepprog(mat security) | |||
if sec.stop.flg then stop | |||
if not(sec.ok2.flg) then | |||
gosub bad.comd ; return | |||
end | |||
end | |||
if source.control then | |||
dict.flag = odpt | |||
file.name = ofpt | |||
record.name = oipt | |||
record.data = this | |||
caller = '3' | |||
write.allowed = '1' | |||
updated = '0' | |||
call source.control(dict.flag,file.name, | |||
record.name,record.data,caller,write.allowed,updated) | |||
if write.allowed ne '1' then | |||
crt 'WRITE NOT ALLOWED' | |||
return | |||
end | |||
end | |||
readv test from ofil, oipt, 1 then | |||
stub = 'Record already exists. Overwrite (y/n)? ' | |||
gosub get.answ | |||
if answ ne yes[1,1] then return | |||
end | |||
if comd eq 'PASTE' then | |||
write kept on ofil, oipt on error gosub writerr ; return | |||
end else | |||
write this on ofil, oipt on error gosub writerr ; return | |||
end | |||
crt 'Record "':oipt:'" saved in "':onam:'".' | |||
return | |||
write.record: | |||
if rest ne '' then | |||
if comd eq 'FD' then | |||
crt '"FD" operates only on the current record & file.' | |||
end else | |||
crt '"FI" only for current record & file. Use SAVE.' | |||
end | |||
gosub bad.comd ; return | |||
end | |||
if source.control then | |||
dict.flag = dprt | |||
file.name = fprt | |||
record.name = item | |||
if comd eq 'FD' then record.data = '' else record.data = this | |||
caller = '3' | |||
write.allowed = '1' | |||
updated = '0' | |||
call source.control(dict.flag,file.name, | |||
record.name,record.data,caller,write.allowed,updated) | |||
if write.allowed ne '1' then | |||
crt 'WRITE NOT ALLOWED' | |||
return | |||
end | |||
end | |||
if not(lock) then | |||
crt 'Record lock has been released! Write not allowed.' | |||
comi = '' | |||
return | |||
end | |||
if comd eq 'FD' then | |||
stub = '***** You are about to DELETE the record! OK? ':ny | |||
gosub get.answ | |||
if answ ne yes[1,1] then return | |||
delete file, item on error gosub writerr ; return | |||
crt 'Deleted "':item:'" from file "':fnam:'".' | |||
end else | |||
if comd eq 'SV' then | |||
writeu this on file, item on error gosub writerr ; return | |||
orig = this ; oops = '' ; oopc = '' ; oopl = '' ; oopf = '' | |||
oopb = '' ; oopk = '' | |||
crt 'Saved "':item:'" in "':fnam:'" - now at line ':here:'.' | |||
return | |||
end else | |||
write this on file, item on error gosub writerr ; return | |||
if orig eq this then | |||
crt 'Filed "':item:'" in file "':fnam:'" UNCHANGED.' | |||
end else crt 'Filed "':item:'" in file "':fnam:'".' | |||
oops = '' ; oopc = '' ; oopl = '' ; oopf = '' ; * ewd | |||
end | |||
end | |||
stopsign = true | |||
if index(comd,'B',1) then | |||
temp = 'BASIC' | |||
$ifdef qm | |||
if index(comd,'D',1) then temp<2> = ' DEBUGGING' | |||
$endif | |||
gosub exec.that | |||
end | |||
if index(comd,'C',1) then | |||
temp = 'CATALOG' | |||
begin case | |||
case index(comd,'L',1) ; temp<2> = ' LOCAL' | |||
* case index(comd,'G',1) ; temp<2> = ' GLOBAL' | |||
end case | |||
gosub exec.that | |||
end | |||
if index(comd,'R',1) then temp = 'RUN' ; gosub exec.that | |||
return | |||
edit.fields: | |||
if here lt 1 then here = 1 | |||
gosub get.line ; temp = line | |||
convert vmrk to am in line | |||
ttid = whom:'_':levl:'_':vals:'.in.line#':here | |||
write line on acom, ttid on error gosub writerr ; return | |||
crt view:'ing ':vals:' as fields...': | |||
execute verb:' AE_COMS ':ttid:options | |||
test = @(0,0) | |||
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"' | |||
read line from acom, ttid else line = '' | |||
delete acom, ttid | |||
return | |||
reset.fields: | |||
convert am to vmrk in line | |||
if temp ne line then | |||
gosub savethat | |||
memr(cell)<lnum> = line | |||
gosub reset.record | |||
end | |||
return | |||
get.load: | |||
temp = '' | |||
if trim(rest) eq '' then | |||
stub = 'Record name, or file name and record name >' | |||
gosub get.rope; rest = rope; crt | |||
if trim(rest) eq '' then temp = ''; return | |||
end | |||
keepquot = false | |||
gosub parse.rest | |||
onam = bite<1> | |||
onid = bite<2> | |||
if onam eq 'DICT' then | |||
onam = onam:' ':onid | |||
onid = bite<3> | |||
if onid eq '' then onid = item | |||
end | |||
if onid eq '' then onid = onam ; onam = '' | |||
if onid eq '' then return | |||
if onam eq '' then | |||
onam = fnam | |||
odpt = dprt | |||
ofpt = fprt | |||
ofil = file | |||
end else | |||
odpt = field(onam,' ',1) | |||
ofpt = field(onam,' ',2) | |||
if ofpt eq '' then ofpt = odpt ; odpt = '' | |||
open odpt, ofpt to ofil else | |||
crt 'Cannot open ':onam | |||
gosub bad.comd ; return | |||
end | |||
end | |||
read temp from ofil, onid else | |||
if dcount(bite,am) eq 1 then | |||
open onid to ofil then | |||
read temp from ofil, item then return | |||
end | |||
end | |||
crt 'Record "':onid:'" was not found on file "':onam:'".' | |||
gosub bad.comd ; return | |||
end | |||
return | |||
changematch.command: | |||
patt = field(rest,dlim,1) | |||
gosub parse.pattern | |||
if not(good) then | |||
crt 'Pattern: character "':bit:'" is not allowed unless quoted.' | |||
comi = '' | |||
return | |||
end | |||
if comd eq 'CM' then cmat = dlim:vm:rest:vm:numb | |||
cto = field(rest,dlim,3,huge) | |||
line = cto ; gosub parse.line ; cto = line | |||
cfrom = upcase(field(rest,dlim,2)) | |||
if cfrom eq '' then cfrom = 'L' | |||
if cfrom eq 'L' then mmat = dlim:vm:rest | |||
if numb eq '' and cto eq '' and (cfrom eq 'L' or cfrom eq 'N') then | |||
numb = last | |||
flag = true | |||
end else flag = false | |||
if len(cfrom) eq 1 and index('ADLNPR',cfrom,1) then | |||
end else | |||
gosub parse.cols | |||
if not(good) then return | |||
cfrom = '' | |||
colf = cols + colf - 1 | |||
end | |||
cm.del.entry: | |||
gosub set.bounds | |||
show = shew ; dnum = 1 | |||
chng = 0 ; save = here ; savl = last ; dnum = 2 | |||
test = '' | |||
for here = dawn to dusk | |||
gosub get.line | |||
if cfrom eq 'DE' | |||
then good = index(line,patt,1) | |||
else good = (line matches patt) | |||
if not(good) then | |||
if cfrom eq 'N' then | |||
numb += 1 | |||
if show or numb lt plen then gosub display.line | |||
if flag then dusk = here | |||
end | |||
continue | |||
end | |||
numb += 1 | |||
temp = line | |||
begin case | |||
case cfrom eq 'A' | |||
temp = line:cto | |||
case cfrom[1,1] eq 'D' | |||
if show or numb lt plen then crt fmt((here + chng),lfmt):'+ ':line | |||
test<-1> = here | |||
case cfrom eq 'L' | |||
gosub display.line | |||
if flag then dusk = here | |||
case cfrom eq 'P' | |||
temp = cto:line | |||
case cfrom eq 'R' | |||
temp = cto | |||
case cfrom eq 'N' | |||
numb -= 1 | |||
case 1 | |||
gosub parse.temp | |||
end case | |||
if not(index('DL',cfrom,1)) or cfrom eq '' then | |||
gosub check.line | |||
end | |||
next here | |||
if cfrom[1,1] eq 'D' and numb then | |||
gosub savethis | |||
for here = numb to 1 step -1 | |||
temp = test<here> | |||
cell = int((temp-1)/cellsize) + 1 | |||
coff = rem(temp,cellsize) | |||
if coff eq 0 then coff = cellsize | |||
del memr(cell)<coff> | |||
if beg eq temp then beg = 0 | |||
if beg gt temp then beg -= 1 | |||
if fin eq temp then fin = 0 | |||
if fin gt temp then fin -= 1 | |||
for xx = dcount(krj<1>,vm) to 1 step -1 | |||
begin case | |||
case krj<2,xx> gt temp ; krj<2,xx> -= 1 | |||
case krj<2,xx> eq temp | |||
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1 | |||
end case | |||
next xx | |||
next here | |||
test = '' | |||
gosub reset.record | |||
here = dusk - numb | |||
end else | |||
here = dusk | |||
end | |||
if dawn ne dusk then | |||
if here lt last | |||
then crt 'At line ':here:'.' | |||
else crt 'Bottom at ':here:'.' | |||
end | |||
if not(numb) then | |||
if cfrom eq 'N' then | |||
crt 'No lines (in ':dawn:'-':dusk:') NOT matching pattern "':patt:'"' | |||
end else crt 'No lines (in ':dawn:'-':dusk:') matching pattern "':patt:'"' | |||
end else | |||
begin case | |||
case cfrom[1,1] eq 'D' | |||
crt 'Deleted ':numb:' lines matching "':patt:'"' | |||
case cfrom eq 'L' | |||
crt 'Found ':numb:' lines matching "':patt:'"' | |||
case cfrom eq 'N' | |||
crt 'Found ':numb:' lines NOT matching "':patt:'"' | |||
end case | |||
end | |||
if chng then | |||
gosub reset.record | |||
begin case | |||
case dawn eq dusk | |||
return | |||
case cfrom eq 'A' | |||
crt '"':cto:'" appended to ': | |||
case cfrom[1,1] eq 'D' | |||
crt 'Deleted ': | |||
case cfrom eq 'P' | |||
crt '"':cto:'" prefixed to ': | |||
case cfrom eq 'R' | |||
crt 'Replaced with "%", ': | |||
case cfrom eq 'L' or cfrom eq 'N' | |||
case cols eq colf | |||
crt 'Element ':cols:' changed to "':cto:'" in ': | |||
case cols | |||
crt 'Element ':cols:'-':colf:' changed to "':cto:'" in ': | |||
end case | |||
if chng eq 1 | |||
then crt '1 line matching "':patt:'"' | |||
else crt chng:' lines matching "':patt:'"' | |||
end | |||
return | |||
parse.pattern: | |||
* bits<1> are the pattern pieces | |||
* <2> quote or 'p'attern flag | |||
* <3> partial patterns | |||
cntr = 1 | |||
bits = '' | |||
flag = '' | |||
good = true | |||
first = true | |||
xxno = len(patt) | |||
gosub quote.pattern | |||
for xx = 1 to xxno | |||
bit = patt[xx,1] | |||
begin case | |||
case bit = flag | |||
flag = '' | |||
first = true | |||
cntr = cntr + 1 | |||
case flag ne '' | |||
bits<1,cntr> = bits<1,cntr>:bit | |||
case index(qt,bit,1) | |||
bits<2,cntr> = bit | |||
flag = bit | |||
case first | |||
if not(bit matches '1n') then | |||
good = false | |||
return | |||
end | |||
first = false | |||
bits<2,cntr> = 'p' | |||
bits<1,cntr> = bits<1,cntr>:bit | |||
if bit eq '0' then bits<3,cntr> = patt[xx+2,xxno] | |||
case 1 | |||
if not(index('AaNnXx',bit,1)) then | |||
good = false | |||
return | |||
end | |||
bits<1,cntr> = bits<1,cntr>:oconv(bit,'mcu') | |||
first = true | |||
cntr = cntr + 1 | |||
end case | |||
next xx | |||
cntr = cntr - 1 | |||
return | |||
quote.pattern: | |||
* Adds quotes to the pattern if required | |||
* If they use any quotes at all, we don't do a thing | |||
if index(patt,'"',1) then return | |||
if index(patt,'\',1) then return | |||
if index(patt,"'",1) then return | |||
xx = 1 | |||
temp = '' | |||
test = '' | |||
loop | |||
left = patt[xx,2]:'*' | |||
if index('0123456789',left[1,1],1) and index('AaNnXx',left[2,1],1) then | |||
if test ne '' then temp := "'":test:"'" | |||
temp := patt[xx,2] | |||
test = '' | |||
xx += 1 | |||
end else test := patt[xx,1] | |||
until xx gt xxno do | |||
xx += 1 | |||
repeat | |||
patt = temp | |||
if test ne '' then patt := "'":test:"'" | |||
return | |||
parse.temp: | |||
temp = '' | |||
posn = 1 | |||
xxno = len(line) | |||
for xx = 1 to cntr | |||
what = bits<1,xx> | |||
type = bits<2,xx> | |||
nmbr = what[1,1] | |||
begin case | |||
case xx gt colf | |||
temp<xx> = line[posn,xxno] | |||
xx = cntr | |||
case type ne 'p' | |||
temp<xx> = line[posn,len(what)] | |||
posn = posn + len(what) | |||
case xx = cntr | |||
temp<xx> = line[posn,xxno] | |||
case nmbr = '0' | |||
* look to match the rest of the line with the partial pattern | |||
test = bits<3,xx> | |||
yy = posn | |||
bit = '' | |||
loop | |||
until yy gt xxno do | |||
chit = line[yy,xxno] | |||
until chit matches test do | |||
bit := chit[1,1] | |||
yy += 1 | |||
repeat | |||
posn += len(bit) | |||
temp<xx> = bit | |||
case 1 | |||
bit = line[posn,nmbr] | |||
posn += len(bit) | |||
temp<xx> = bit | |||
end case | |||
next xx | |||
temp<cols> = cto | |||
for xx = cols+1 to colf | |||
temp = delete(temp,cols+1) | |||
next xx | |||
convert am to '' in temp | |||
return | |||
get.lines: | |||
stub = '"Q"uit, or starting line > ' | |||
pick = 1 | |||
gosub get.rope; dawn = rope | |||
dawn = upcase(trim(dawn)) | |||
if dawn eq '' then dawn = 'Q' | |||
if dawn[1,1] eq 'Q' then temp = false ; crt ; return | |||
if not(dawn matches '1N0N') then | |||
crt | |||
crt 'Nothing done - starting and ending lines must be numeric.' | |||
gosub bad.comd ; return | |||
end | |||
if dawn gt dcount(temp,am) then | |||
crt | |||
crt 'Nothing done - record does not have that many lines.' | |||
gosub bad.comd ; return | |||
end | |||
stub = stub:dawn:' ':', ending line > ' | |||
pick = dcount(temp,am) | |||
gosub get.rope; dusk = rope | |||
dusk = upcase(trim(dusk)) | |||
if dusk eq '' then dusk = 'Q' | |||
if dusk[1,1] eq 'Q' then temp = false ; crt ; return | |||
if not(dusk matches '1N0N') then | |||
crt | |||
crt 'Nothing done - starting and ending lines must be numeric.' | |||
gosub bad.comd ; return | |||
end | |||
if dusk gt dcount(temp,am) then | |||
dusk = dcount(temp,am) | |||
crt begn:'File is ':onam:': "Q"uit, or starting line > ':dawn:', ':dusk: | |||
end | |||
temp = field(temp,am,dawn,dusk-dawn+1) | |||
crt | |||
return | |||
parse.bite: | |||
temp = '' | |||
loop | |||
while bite ne '' do | |||
bite = trimf(bite) | |||
xx = fold | |||
if count(bite[1,xx],' ') and trim(bite[xx+1,1]) ne '' then | |||
loop | |||
until trim(bite[xx,1]) eq '' do | |||
xx -=1 | |||
repeat | |||
temp<-1> = bite[1,xx-1] | |||
end else | |||
temp<-1> = bite[1,xx] | |||
end | |||
bite = bite[xx+1,len(bite)] | |||
repeat | |||
return | |||
show.help: | |||
crt | |||
if help eq '' then | |||
help = '' | |||
help<-1> = ' ':verb:' version ':help.def | |||
help<-1> = ' This program can be called with the following formats:' | |||
help<-1> = " ":verb:" file and record id's are prompted for" | |||
help<-1> = " ":verb:" file record id's are prompted for" | |||
help<-1> = " ":verb:" file id ":view:" the record 'id' in 'file'" | |||
help<-1> = " ":verb:" file id id... ":view:" multiple records in 'file'" | |||
help<-1> = " ":verb:" file * ":view:" all records in 'file'" | |||
help<-1> = " SELECT may precede '":verb:" file' command" | |||
help<-1> = ' Special ASCII characters may be entered as:' | |||
help<-1> = ' ^nnn where nnn is the decimal character code (like ^027)' | |||
help<-1> = ' ^ will enter a single UP ARROW character.' | |||
help<-1> = ' The following commands may be used in the Editor:' | |||
help<-1> = 'A# - Do the last Append command again for # lines.' | |||
help<-1> = "A# any - Append 'any' to # lines (default 1)." | |||
help<-1> = 'B + Set the current line pointer to the BOTTOM line.' | |||
help<-1> = "B# any - BREAK # lines (default 1) after string 'any' into two lines." | |||
help<-1> = 'BC# posn = Break Column - Break # lines (default 1) after posn into two.' | |||
help<-1> = 'BCD# posn = Break Column and Discard the second part.' | |||
help<-1> = 'BCK# posn = Break Column and Keep only the second part.' | |||
help<-1> = 'BCR# posn = Break Column and Reverse the order of the two parts.' | |||
help<-1> = 'BCS# posn = Break Column and Swap the parts about the character at posn.' | |||
help<-1> = "BD# any - BREAK after string 'any' and Discard the second part." | |||
help<-1> = "BK# any - BREAK after string 'any' and Keep only the second part." | |||
help<-1> = "BR# any - BREAK after string 'any' and Reverse the order of the two parts." | |||
help<-1> = "BS# any - BREAK after string 'any' and Swap the parts about 'any'." | |||
help<-1> = 'BLEACH ON/OFF# Switch colourisation flag.' | |||
help<-1> = 'BLOCK ON/OFF + Switch block operation confirmation flag.' | |||
help<-1> = ' If neither ON nor OFF is used, then toggle BLOCK flag.' | |||
help<-1> = "C - Do the last 'CHANGE' command again." | |||
help<-1> = 'C/// - CHANGE one or more lines. Full formats is:' | |||
help<-1> = ' C[#]/from/to/[G][S]' | |||
help<-1> = ' where / - is any delimiter character.' | |||
help<-1> = ' # - number of lines to CHANGE (default 1).' | |||
help<-1> = ' from - is the character string to be replaced.' | |||
help<-1> = ' to - is the character string to substitute.' | |||
help<-1> = " G - 'G'lobal flag - CHANGE all instances in line." | |||
help<-1> = " S - 'S'how flag - display all changes made." | |||
help<-1> = 'CASE ON/OFF + Switch CASE flag for FL, FLA, L, LA, LN, LNA commands.' | |||
help<-1> = ' If neither ON nor OFF is used, then toggle CASE flag.' | |||
help<-1> = ' OFF means that the commands are not case sensitive.' | |||
help<-1> = "CAT - Synonym for 'J'oin." | |||
help<-1> = 'CD + Show or change the command delimiter.' | |||
help<-1> = ' (this is the input for a blank line).' | |||
help<-1> = 'CLEAR # Clear the kept buffer.' | |||
help<-1> = 'CM/// - ChangeMatch one or more lines. Full formats is:' | |||
help<-1> = ' CM[#]/pattern[/range/to]' | |||
help<-1> = ' where / - is any delimiter character.' | |||
help<-1> = ' # - number of lines to CHANGE (default 1).' | |||
help<-1> = ' pattern - is the pattern match for the line.' | |||
help<-1> = ' to - is the character string to substitute/add.' | |||
help<-1> = ' range - Can be numeric, which field(s) to change,' | |||
help<-1> = " or 'A'ppend or 'P'refix to the line," | |||
help<-1> = " or 'D'elete, 'R'eplace, 'L'ocate (default) the line." | |||
help<-1> = " EG 'CM/6X' will scan to the line matching '6X'." | |||
help<-1> = " Also; 'N'ot - locate the next non-matching line." | |||
help<-1> = 'COL + Display relative COLUMN POSITIONS on the Terminal.' | |||
help<-1> = 'COPY # Copy the predefined block to the kept buffer.' | |||
help<-1> = 'COPY# # Copy the next # lines to the kept buffer.' | |||
help<-1> = 'COPYx/y # Copy x lines starting at line y to the kept buffer.' | |||
help<-1> = 'COPY/x/y # Copy lines from x to y inclusive to the kept buffer.' | |||
help<-1> = "COUNT#/any + Count of 'any' in next # lines (default 1)." | |||
help<-1> = "CRT xxxx - Inserts a line CRT 'xxxx = ':xxxx" | |||
help<-1> = ' Use double quote or backslash as delimiter to change quotes.' | |||
help<-1> = 'CUT = Move the predefined block to the kept buffer.' | |||
help<-1> = 'CUT# = Move the next # lines to the kept buffer.' | |||
help<-1> = 'CUTx/y = Move x lines starting at line y to kept buffer.' | |||
help<-1> = 'CUT/x/y = Move lines from x to y inclusive to kept buffer.' | |||
help<-1> = 'D + Display the current line.' | |||
help<-1> = 'DE - DELETE the current line.' | |||
help<-1> = "DE# - DELETE '#' lines (default 1)." | |||
help<-1> = "DE#/any - DELETE as above, but only if the line contains 'any'." | |||
help<-1> = "DISPLAY xxxx - Inserts a line DISPLAY 'xxxx = ':xxxx" | |||
help<-1> = ' Just like CRT, handy to distinguish debug code.' | |||
help<-1> = 'DROP - Remove the predefined block.' | |||
help<-1> = "DTX any + Convert decimal string 'any' to hexadecimal and display it." | |||
help<-1> = 'DUP - DUPLICATE the current line.' | |||
help<-1> = "DUP# - DUPLICATE the current line '#' times." | |||
help<-1> = 'EC + Edit a called subroutine in this file.' | |||
help<-1> = 'ECS # Edit the command stack.' | |||
help<-1> = 'EF# + Edit fields delimited by CHAR(#) as lines.' | |||
help<-1> = 'EI + Edit the included code.' | |||
help<-1> = 'EIT + Edit I-type (not just a split on semi-colon).' | |||
help<-1> = 'EK # Edit the kept buffer.' | |||
help<-1> = 'EPR + Edit the prestored commands.' | |||
help<-1> = 'EPR# # Edit prestored commqnd #.' | |||
help<-1> = 'ESS # Edit Search Stack.' | |||
help<-1> = 'ESV + Edit subvalues as 1ines.' | |||
help<-1> = 'ET # Edit the line tabs.' | |||
help<-1> = 'EV + Edit multivalues as lines.' | |||
help<-1> = 'EW + Edit words as lines.' | |||
help<-1> = 'EXIT (EX) + QUIT - EXIT the program.' | |||
help<-1> = 'EXITK (EXK) + QUITKill - EXIT the program, abandon any active SELECT list.' | |||
help<-1> = 'FD - DELETE the entire record from the file.' | |||
help<-1> = 'FI - FILE the record. You can also process it.' | |||
help<-1> = ' FIB = BASIC, FIC = CATALOG, FIR = RUN' | |||
help<-1> = ' You can have up to three processes (EG. FIBCR).' | |||
help<-1> = ' You can modify BASIC with D for DEBUGGING (EG. FIBD).' | |||
help<-1> = ' You can modify CATALOG with L for LOCAL (EG. FICL).' | |||
help<-1> = 'FILE - Synonym for SAVE.' | |||
help<-1> = 'FL + Find the next Label.' | |||
help<-1> = "FL any + Find the label 'any' or matching pattern 'any'." | |||
help<-1> = 'FL# + Find (display) the labels in next # lines.' | |||
help<-1> = 'FLA + Find label above this line.' | |||
help<-1> = 'FM + Find Matching logic by position.' | |||
help<-1> = 'FMA + Find Matching logic by position above this line.' | |||
help<-1> = 'FOLD/length - Split current line (on blanks if possible) to fit width.' | |||
help<-1> = 'FORMAT (FOR) + FORMAT a BASIC program to show logical structure by' | |||
help<-1> = ' indenting. This has the following keywords;' | |||
help<-1> = " '-Mx' = Set margin to x." | |||
help<-1> = " '-Iy' = Set Indentation to y." | |||
help<-1> = " '-A' = Align comments with code." | |||
help<-1> = " '-N' = No CASE indentation." | |||
help<-1> = " '-C' = Compress - same as '-M0 -I1 -A -N'." | |||
help<-1> = "G# + GO TO line '#' ('G' is optional)." | |||
help<-1> = 'HELP (H) + Prompt user to display HELP information on the Terminal.' | |||
help<-1> = "HELP any + Display HELP information on Terminal for 'any'." | |||
help<-1> = 'HELP NEW + Display HELP information on new features.' | |||
help<-1> = 'HEX + Displays the current line in hexadecimal.' | |||
help<-1> = 'I - INSERT new lines AFTER the current line. Prompt for' | |||
help<-1> = ' successive lines. INPUT until NULL input. An INPUT line' | |||
help<-1> = ' of a single space will store an empty line.' | |||
help<-1> = "I any - INSERT (INPUT) the line 'any' AFTER the current line." | |||
help<-1> = "I#/any - INSERT # lines of 'any' AFTER the current line." | |||
help<-1> = "IC any - IConv the line using the conversion 'any'." | |||
help<-1> = 'IN command - Insert the results of the command AFTER the current line.' | |||
help<-1> = ' It is not a good idea to use a command requiring input.' | |||
help<-1> = "J#/any - Join next '#' lines (default 1), separated by 'any'." | |||
help<-1> = "KEEP name # Copy the record 'name' into the kept buffer." | |||
help<-1> = " line #'s will be prompted." | |||
help<-1> = "KEEP f name # Copy the record 'name' from file 'f' into the kept buffer," | |||
help<-1> = " line #'s will be prompted." | |||
help<-1> = 'KEEPA # KEEPAll - KEEP without line # prompting.' | |||
help<-1> = 'KEPT (K) # Display the kept buffer.' | |||
help<-1> = "L + Repeat the last 'LOCATE' command (L, LA, LN, or LNA)." | |||
help<-1> = "L any + LOCATE the next line that contains the string 'any'." | |||
help<-1> = "L#/any/10-20 + LOCATE in next # lines those with 'any' in columns 10 to 20." | |||
help<-1> = " So 'L#' effectively lists # lines." | |||
help<-1> = "L#!any!THING # LOCATE in next # lines those with 'any' OR 'THING'." | |||
help<-1> = "L#&any&THING # LOCATE in next # lines those with 'any' AND 'THING'." | |||
help<-1> = ' ! and & work this way for LA, LN, and LNA commands too.' | |||
help<-1> = 'LA#/any/1-20 + Locate lines above this one (reverse order).' | |||
help<-1> = "LC# - Change '#' lines to lower case (default 1)." | |||
help<-1> = 'LC# any Comments and quoted strings are unchanged.' | |||
help<-1> = "LL#/length + Show lines 'length' or longer (null '#' is a search)." | |||
help<-1> = "LN#/any/1-20 + LOCATE NOT - line without 'any' in columns 10 to 20." | |||
help<-1> = "LNA#/an/1-20 + LOCATE line above this without 'an' in columns 1 to 20." | |||
help<-1> = "LOAD name - LOAD the record 'name' from the current FILE," | |||
help<-1> = " line #'s will be prompted." | |||
help<-1> = "LOAD f name - LOAD the record 'name' from file 'f'," | |||
help<-1> = " line #'s will be prompted." | |||
help<-1> = 'LOADA - LOADAll - LOAD without line # prompting.' | |||
help<-1> = 'LD - Synonym for LOAD.' | |||
help<-1> = 'LDA - Synonym for LOADA.' | |||
help<-1> = 'M pattern + Search for a line matching the pattern.' | |||
help<-1> = 'MACRO# + Toggle macro recording into #th PRESTORE command.' | |||
help<-1> = 'MERGE (ME) = Merge a copy of the predefined block after the current line.' | |||
help<-1> = 'MERGEx/y = Merge x lines starting at line y.' | |||
help<-1> = 'MERGE/x/y = Merge lines starting at x to line y inclusive.' | |||
help<-1> = 'MOVE (MV) - Move the predefined block to after the current line.' | |||
help<-1> = 'MOVEx/y = Move the x lines starting at line y.' | |||
help<-1> = 'MOVE/x/y = Move the lines starting at x to line y inclusive.' | |||
help<-1> = 'NUM + Toggle the line numbering.' | |||
help<-1> = "NULL/symbol + Change the null line input for 'I' to 'symbol'." | |||
help<-1> = "OC# any - OConv '#' lines using the conversion 'any'." | |||
help<-1> = 'OOPS - RESTORE the record to the condition prior to last change.' | |||
help<-1> = "OUT# # Outline (labels, gotos, gosubs) for '#' lines (default all)." | |||
help<-1> = 'OUT# CEPS Show Calls, Executes, Performs, and caSe also (* for all).' | |||
help<-1> = 'P + PRINT on Terminal one page worth of lines.' | |||
help<-1> = "P# + PRINT on Terminal '#' lines starting with the current line." | |||
help<-1> = "PA# + PRINT the current line and the prior '#' lines," | |||
help<-1> = ' do not change the current line pointer.' | |||
help<-1> = "PASTE = Paste the kept buffer after the current line'." | |||
help<-1> = "PASTE name = Copy the kept buffer under the specified 'name'." | |||
help<-1> = "PASTE f name = Copy the kept buffer as record 'name' in file 'f'." | |||
help<-1> = 'PE + Page Edit mode.' | |||
help<-1> = "PL# + PRINT the current line and the next '#' lines," | |||
help<-1> = ' do not change the current line pointer.' | |||
help<-1> = "PP# + PAGE.PRINT a window of '#' lines around the current line," | |||
help<-1> = ' do not change the current line pointer.' | |||
help<-1> = 'PR + Show the PRESTORE commands.' | |||
help<-1> = 'PR# + Run the #th PRESTORE command.' | |||
help<-1> = 'PR#/any + Change the #th PRESTORE command.' | |||
help<-1> = ' where / - is any delimiter character which will also be' | |||
help<-1> = ' used as the command separator.' | |||
help<-1> = 'QUIT (Q) + QUIT - EXIT the program.' | |||
help<-1> = 'QUITK (QK) + QuitKill - EXIT the program, abandon any active SELECT list.' | |||
help<-1> = 'R - Replace the line with prompted for text.' | |||
help<-1> = "R any - REPLACE this line with 'any'." | |||
help<-1> = "R#/any - REPLACE # lines with 'any'." | |||
help<-1> = 'R/// - CHANGE one or more lines (same as C/// command).' | |||
help<-1> = "RA = Show last 20 'CHANGE' commands." | |||
help<-1> = "RA# = Repeat #th 'CHANGE' command." | |||
help<-1> = 'RELEASE + RELEASE the update record LOCK for this file.' | |||
help<-1> = "S - Show last 20 'LOCATE' commands." | |||
help<-1> = "S# - Repeat #th 'LOCATE' command." | |||
help<-1> = 'SAVE - SAVE a copy of this record under the original name.' | |||
help<-1> = "SAVE name - SAVE a copy of this record under the specified 'name'." | |||
help<-1> = "SAVE f name - SAVE a copy of this record as record 'name' in file 'f'." | |||
help<-1> = 'SEQ#//// - Build a sequence. Format is:' | |||
help<-1> = ' SEQ#/from/base/inc/cols' | |||
help<-1> = ' where / - is any delimiter character.' | |||
help<-1> = ' # - number of lines to CHANGE (default 1).' | |||
help<-1> = ' from - is the character string to be replaced.' | |||
help<-1> = ' base - is the start number (defaults to 1).' | |||
help<-1> = ' inc - is the increment (defaults to 1).' | |||
help<-1> = ' cols - restricts the change to a column range.' | |||
help<-1> = "SHOW ON/OFF + toggle overriding 'S'how flag for 'C' command." | |||
help<-1> = " OFF won't show more than a page of changes." | |||
help<-1> = ' If neither ON nor OFF is used, then toggle SHOW flag.' | |||
help<-1> = "SORT seq - Sort the predefined block (seq defaults to 'AL')." | |||
help<-1> = "SORTU seq # Sort unique predefined block ('AL' default seq)." | |||
help<-1> = 'SPACE ON/OFF + Switch SPACE flag for L, LA, LN, LNA commands.' | |||
help<-1> = ' If neither ON nor OFF is used, then toggle SPACE flag.' | |||
help<-1> = ' OFF means that the commands will ignore spaces and tabs.' | |||
help<-1> = 'SPOOL + SPOOL entire record to PRINTER.' | |||
help<-1> = "SPOOL# + SPOOL '#' lines to the PRINTER." | |||
help<-1> = 'SPOOLHELP + SPOOL the HELP listing to the default PRINTER.' | |||
help<-1> = "SPOUT# # SPOO outline (labels, gotos, gosubs) for '#' lines (default all)." | |||
help<-1> = 'SPOUT# CEPS Show Calls, Executes, Performs, and caSe also (* for all).' | |||
help<-1> = "STAMP - INSERT a 'last modified' stamp into the record, which" | |||
help<-1> = " begins with a '*' (for BASIC 'comment'), and contains the" | |||
help<-1> = ' account name, LOGIN name (if different from account name),' | |||
help<-1> = ' date and time. Used to mark when record was last changed.' | |||
help<-1> = 'SV - Synonym for SAVE.' | |||
help<-1> = 'T + Set current line to the TOP (before first line).' | |||
help<-1> = "TC# - Change '#' lines to text or mixed case (default 1)." | |||
help<-1> = 'TC# any Comments and quoted strings are unchanged.' | |||
help<-1> = "TRIM# - TRIM '#' lines (default 1)." | |||
help<-1> = "TRIM# a b = TRIM '#' lines of character 'a' with argument 'b'." | |||
help<-1> = "TRIMB# - TRIMB '#' lines (default 1)." | |||
help<-1> = "TRIMF# - TRIMF '#' lines (default 1)." | |||
help<-1> = "TRIPLE#/any = Copy '#' lines (default 1) into three clones, joined by 'any'." | |||
help<-1> = "TWIN#/any = Copy '#' lines (default 1) into two clones, joined by 'any'." | |||
help<-1> = "UC# - Change '#' lines to upper case (default 1)." | |||
help<-1> = 'UC# any Comments and quoted strings are unchanged.' | |||
help<-1> = 'UNLOAD - Synonym for SAVE.' | |||
help<-1> = 'V + Version information.' | |||
help<-1> = 'WHERE (W) + Show the item and file being ':view:'ed.' | |||
help<-1> = 'WM + Show or change the word marker.' | |||
help<-1> = 'X + QuitKill - EXIT the program, abandon any active SELECT list.' | |||
help<-1> = 'XEQ - The XEQ command allows a user to execute any legal PERFORM' | |||
help<-1> = ' command from within the program. Upon completion of the' | |||
help<-1> = ' command, control will be returned back to the program.' | |||
help<-1> = "XTD any + Convert hexadecimal string 'any' to decimal and display it." | |||
help<-1> = '/any + Same as L99999999/any - NOTE you are left at the bottom.' | |||
help<-1> = ".A# any + APPEND 'any' to command '#' (default 1)." | |||
help<-1> = ".C#/// + CHANGE stack command '#' (default 1). Syntax is like 'C'." | |||
help<-1> = ".D# + DELETE stack command '#' (default 1)." | |||
help<-1> = ".I# any + INSERT 'any' at stack position '#' (default 1)." | |||
help<-1> = ".L# + LIST on the Terminal the last '#' stack commands." | |||
help<-1> = ".R# + RECALL (copy) command '#' to stack position 1." | |||
help<-1> = ".S# n m + SAVE stack n to m as prestore '#' (all default to 1)." | |||
help<-1> = ".U# # UPCASE stack command '#' (default 1)." | |||
help<-1> = ".UL# # lower case stack command '#' (default 1)." | |||
help<-1> = ".UT# # text case stack command '#' (default 1)." | |||
help<-1> = ".X# + EXECUTE stack command '#' (default 1)." | |||
help<-1> = ' The command will be put in stack position 1.' | |||
help<-1> = "+# + Advance current line pointer by '#' lines (default 1)." | |||
help<-1> = "-# + Back up current line pointer by '#' lines (default 1)." | |||
help<-1> = "\ # Set a line tag with default label like 'T#'." | |||
help<-1> = "\any # Set a line tag labelled 'any'." | |||
help<-1> = '\\ # Clear the line tags.' | |||
help<-1> = "]any # Go to the line tag 'any'." | |||
help<-1> = "[any # Go to the line tag 'any'." | |||
help<-1> = '] # Go to the next line tag.' | |||
help<-1> = '[ # Go to the previous line tag.' | |||
help<-1> = ']] # Display the line tags.' | |||
help<-1> = '[[ # Display the line tags.' | |||
help<-1> = "# + Set the current line pointer to the '#' line." | |||
help<-1> = '<# + Sets the starting block pointer to # (current line default).' | |||
help<-1> = '># + Sets the ending block pointer to # (current line default).' | |||
help<-1> = '<># # + Set both block pointers at the same time.' | |||
help<-1> = '^ + Switch UP ARROW on/off to show non-printing characters as' | |||
help<-1> = ' ^nnn where nnn is the decimal equivalent of ASCII code.' | |||
help<-1> = '? + Show various parameters - easier to use than explain.' | |||
end | |||
rest = trim(upcase(rest)) | |||
if rest eq am then | |||
hard = true | |||
rest = '' | |||
end else hard = false | |||
disp = '' | |||
stub = '' | |||
if rest eq '' then flag = true else flag = false | |||
if rest eq 'NEW' then disp = 'New Features':am | |||
good = false | |||
xxno = dcount(help,am) | |||
for xx = 1 to xxno | |||
temp = help<xx> | |||
bite = temp[1,len(rest)] | |||
bit = temp[14,1] | |||
if index('-+=#',bit,1) | |||
then temp = temp[1,13]:'-':temp[15,huge] | |||
else bit = '' | |||
if bit ne '' then | |||
flag = false | |||
if bit eq '#' and rest eq 'NEW' then flag = true | |||
if (bit eq '#' or bit eq '+') and rest eq '' then flag = true | |||
if not(viewflag) then | |||
if bit eq 'eq' and rest eq 'NEW' then flag = true | |||
if bit eq '=' or bit eq '-' and rest eq '' then flag = true | |||
end | |||
end | |||
if not(flag) and rest ne '' and bite eq rest then | |||
if bit eq '#' or bit eq '+' then flag = true | |||
if not(viewflag) then | |||
if bit eq '=' or bit eq '-' then flag = true | |||
end | |||
end | |||
if flag then | |||
disp<-1> = temp | |||
good = true | |||
end | |||
next xx | |||
if not(good) then | |||
disp := am | |||
disp<-1> = 'No explanation of "':rest:'" is available.' | |||
disp<-1> = 'For a list of words that have explanations, type "HELP".' | |||
disp := am | |||
end | |||
if hard then gosub print.disp else gosub show.disp | |||
return | |||
show.disp: | |||
write disp on voc,'&DISP.':whom | |||
if stub eq '' then stub = 'Press return to continue showing explanation, Q to quit' | |||
xxno = dcount(disp,am) | |||
pg = 0 | |||
for xx = 1 to xxno | |||
pg += 1 | |||
if pg ge system(3) then | |||
loop | |||
rlen = 1 | |||
gosub get.rope; answ = rope | |||
crt begn:ceol: | |||
answ = trim(upcase(answ))[1,1] | |||
until index('QT-',answ,1) do | |||
repeat | |||
if answ eq 'Q' then return | |||
if answ eq 'T' then xx = 1 | |||
if answ eq '-' then | |||
xx -= 2*(system(3)-1) | |||
if xx lt 1 then xx = 1 | |||
end | |||
pg = 1 | |||
end | |||
crt disp<xx> | |||
next xx | |||
disp = '' | |||
return | |||
print.disp: | |||
printer on | |||
heading upcase(verb):" help file ":timedate():"'LL'" | |||
xxno = dcount(disp,am) | |||
for xx = 1 to xxno | |||
print disp<xx> | |||
next xx | |||
printer close | |||
return | |||
get.page.comd: | |||
gosub get.keyc | |||
do.page.comd: | |||
locate(keyc,keys;cpos) then cpos = acts<cpos> else cpos = 0 | |||
begin case | |||
case cpos eq uarr ;* up key | |||
if here le 1 then crt bell:; return | |||
gosub check.page | |||
here -= 1 | |||
if prow le 1 then | |||
ptop = ptop - botl | |||
if ptop lt 1 then ptop = 1 | |||
gosub disp.page | |||
end | |||
gosub get.line; temp = line | |||
case cpos eq darr ;* down key | |||
if here ge last then crt bell:; return | |||
gosub check.page | |||
here += 1 | |||
if prow ge botl then | |||
ptop = ptop + botl | |||
if ptop ge last then ptop = last - botl + 1 | |||
if ptop le 1 then ptop = 1 | |||
gosub display.page | |||
end | |||
gosub get.line; temp = line | |||
case cpos eq larr ;* left key | |||
if pchr le 1 then crt bell:; return | |||
pchr -= 1 | |||
if pchr lt ppos then | |||
gosub check.page | |||
gosub disp.page | |||
end | |||
case cpos eq rarr ;* right key | |||
pchr += 1 | |||
if pchr-ppos ge span then | |||
gosub check.page | |||
gosub disp.page | |||
end | |||
case cpos eq upag ;* page up key | |||
gosub check.page | |||
ptop -= botl | |||
if ptop lt 1 then ptop = 1 | |||
here -= botl | |||
if here lt 1 then here = 1 | |||
pchr = 1 | |||
gosub get.line; temp = line | |||
gosub disp.page | |||
case cpos eq dpag ;* page down key | |||
gosub check.page | |||
ptop = ptop + botl | |||
if ptop ge last then ptop = last - botl + 1 | |||
here = here + botl | |||
if here gt last then here = last | |||
pchr = 1 | |||
gosub get.line; temp = line | |||
gosub disp.page | |||
case cpos eq lpag ;* start of line key | |||
pchr = 1 | |||
if pchr lt ppos then gosub check.page; gosub disp.page | |||
case cpos eq rpag ;* end of line key | |||
pchr = len(temp)+1 | |||
if pchr lt ppos then gosub check.page; gosub disp.page | |||
if pchr-ppos ge span then | |||
gosub check.page | |||
gosub disp.page | |||
end | |||
case cpos eq tpag ;* top page key | |||
gosub check.page | |||
here = 1 | |||
ptop = 1 | |||
pchr = 1 | |||
gosub disp.page | |||
gosub get.line; temp = line | |||
case cpos eq bpag ;* bottom page key | |||
gosub check.page | |||
here = last | |||
ptop = last - botl + 1 | |||
gosub get.line | |||
pchr = len(line)+1 | |||
gosub disp.page | |||
gosub get.line; temp = line | |||
case cpos eq escp ;* escape key | |||
if this ne that then | |||
crt @(0,botl):ceol:revb:'ABANDONING CHANGES':revf | |||
end | |||
this = that | |||
here = savl<1> | |||
gosub set.record | |||
mode = 'LINE' | |||
case cpos eq phlp ;* help key | |||
gosub check.page | |||
gosub page.help | |||
case cpos eq zoom ;* Go to line key | |||
crt bott: | |||
stub = 'Go to line :' | |||
stay = pchr | |||
gosub get.rope; numb = trim(rope) | |||
pchr = stay | |||
crt bott:revb:'Press <F1> for help.':revf: | |||
if not(numb matches '1N0N') then numb = here | |||
if numb gt last then numb = last | |||
if numb eq here then return | |||
gosub check.page | |||
here = numb | |||
ptop = here | |||
pchr = 1 | |||
gosub disp.page | |||
gosub get.line; temp = line | |||
case cpos eq skey ;* forward search | |||
crt bott: | |||
stub = 'Search: ':'> ' | |||
stay = pchr | |||
pick = lastfind; gosub get.rope; lastfind = rope | |||
pchr = stay | |||
crt bott:revb:'Press <F1> for help.':revf: | |||
if lastfind eq '' then return | |||
* is it in this line or the rest of the item? | |||
test = index(temp[pchr+1,huge],lastfind,1) | |||
save = here | |||
gosub check.page | |||
if test then | |||
test += pchr | |||
end else | |||
dawn = here+1 | |||
dusk = last | |||
for here = dawn to dusk until test | |||
gosub get.line | |||
test = index(line,lastfind,1) | |||
if test then save = here | |||
next here | |||
end | |||
if test then | |||
if save lt ptop or save ge (ptop+botl) then ptop = save | |||
here = save | |||
pchr = test | |||
gosub disp.page | |||
end else here = save | |||
gosub get.line; temp = line | |||
case cpos eq rkey ;* reverse search | |||
crt bott: | |||
stub = 'Search: ':'< ' | |||
stay = pchr | |||
pick = lastfind; gosub get.rope; lastfind = rope | |||
pchr = stay | |||
crt bott:revb:'Press <F1> for help.':revf: | |||
if lastfind eq '' then return | |||
* is it in this line before the cursor position or the rest of the item above? | |||
test = index(temp[1,pchr-1],lastfind,1) | |||
save = here | |||
gosub check.page | |||
if not(test) then | |||
dawn = 1 | |||
dusk = here-1 | |||
for here = dusk to dawn step -1 until test | |||
gosub get.line | |||
what = count(line,lastfind) | |||
if what then | |||
test = index(line,lastfind,what) | |||
save = here | |||
end | |||
next here | |||
end | |||
if test then | |||
if save lt ptop or save ge (ptop+botl) then ptop = save | |||
here = save | |||
pchr = test | |||
gosub disp.page | |||
end else here = save | |||
gosub get.line; temp = line | |||
case not(sec.write.flg) | |||
crt bell: | |||
case cpos eq delc ;* delete character key | |||
if temp eq '' then return | |||
if pchr eq 1 then | |||
temp = temp[2,len(temp)] | |||
end else | |||
temp = temp[1,pchr-1]:temp[pchr+1,len(temp)] | |||
end | |||
crap = temp[pchr,span-pcol] | |||
convert badc to gudc in crap | |||
crt @(pcol,prow):ceol:crap: | |||
case cpos eq dell ;* delete line key | |||
del this<here> | |||
gosub set.record | |||
gosub disp.page | |||
gosub get.line; temp = line | |||
case cpos eq delr ;* delete to end of line key | |||
if pchr gt len(temp) then | |||
if here ge last then crt bell:; return | |||
line = fmt(temp,'l#':pchr-1):this<here+1> | |||
del this<here> | |||
this<here> = line | |||
gosub set.record | |||
gosub disp.page | |||
gosub get.line; temp = line | |||
end else | |||
temp = temp[1,pchr-1] | |||
this<here> = temp | |||
memr(cell)<lnum> = temp | |||
line = temp | |||
crt @(pcol,prow):ceol: | |||
end | |||
case cpos eq back ;* backspace key | |||
if pchr eq 1 then crt bell:; return | |||
pchr -= 1 | |||
temp = temp[1,pchr-1]:temp[pchr+1,len(temp)] | |||
if pchr lt ppos then | |||
gosub check.page | |||
gosub disp.page | |||
end else | |||
pcol = rem(pchr-1,span) | |||
crt @(pcol,prow):ceol: | |||
crap = temp[pchr,span-pcol] | |||
convert badc to gudc in crap | |||
crt crap: | |||
end | |||
case cpos eq carr ;* carriage return key | |||
if pchr eq 1 then | |||
line = '' | |||
end else | |||
line = temp[1,pchr-1] | |||
temp = temp[pchr,len(temp)] | |||
end | |||
if lnum eq 0 then lnum = 1 | |||
memr(cell)<lnum> = line | |||
last += 1 | |||
lnum += 1 | |||
line = temp | |||
gosub insert.line | |||
gosub reset.record | |||
here += 1 | |||
pchr = 1 | |||
if prow ge botl then | |||
ptop = ptop + botl | |||
if ptop ge last then ptop = last - botl + 1 | |||
if ptop le 1 then ptop = 1 | |||
gosub display.page | |||
end else gosub disp.page | |||
gosub get.line; temp = line | |||
case cpos eq togg ;* toggle mode key | |||
if mode<2> eq 'Ins' then | |||
mode<2> = 'Rep' | |||
end else mode<2> = 'Ins' | |||
case cpos eq writ ;* write away data key | |||
gosub check.page | |||
mode = 'LINE' | |||
case seq(keyc) lt 28 or seq(keyc) gt 127 or len(keyc) gt 1 | |||
crt bell: | |||
case seq(keyc) eq 30 or seq(keyc) eq 31 | |||
crt bell: | |||
case 1 | |||
if seq(keyc) eq 28 then keyc = char(252) | |||
if seq(keyc) eq 29 then keyc = char(253) | |||
if pchr and len(temp) lt (pchr-1) then | |||
temp = temp:str(' ',pchr) | |||
temp = temp[1,pchr-1] | |||
end | |||
if mode<2> eq 'Ins' | |||
then offset = pchr | |||
else offset = pchr+1 | |||
if pchr eq 1 | |||
then temp = keyc:temp[offset,len(temp)] | |||
else temp = temp[1,pchr-1]:keyc:temp[offset,len(temp)] | |||
if mode<2> eq 'Ins' then | |||
crt @(pcol,prow):ceol: | |||
crap = temp[pchr,span-pcol] | |||
end else crap = keyc | |||
convert badc to gudc in crap | |||
crt @(pcol,prow):crap: | |||
pchr += 1 | |||
if pchr-ppos ge span then | |||
gosub check.page | |||
gosub disp.page | |||
end | |||
end case | |||
return | |||
check.page: | |||
if '*':temp ne '*':line then | |||
memr(cell)<lnum> = temp | |||
gosub reset.record | |||
end | |||
return | |||
page.help: | |||
gosub clear.page | |||
if pagehelp eq '' then | |||
if sec.write.flg then | |||
pagehelp = '' | |||
pagehelp<-1> = ' Page editing help' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' Cursor movement keys Line movement keys' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' UP = <UP arrow> or ^Z LEFT END = <Home> or ^A' | |||
pagehelp<-1> = ' DOWN = <DOWN arrow> or ^J RIGHT END = <End> or ^E' | |||
pagehelp<-1> = ' LEFT = <LEFT arrow> or ^U GO TO LINE = ^G' | |||
pagehelp<-1> = ' RIGHT = <RIGHT arrow> or ^F (prompts for desired line)' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' Page movement keys Deleting keys' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' PREVIOUS = <Page Up> or ^P DELETE CHAR = <Delete> or ^D' | |||
pagehelp<-1> = ' NEXT = <Page Down> or ^N DELETE LINE = <Ctrl-Home> or ^X' | |||
pagehelp<-1> = ' TOP = <Ctrl-Page Up> or ^T DELETE TO EOL = <Ctrl-End> or ^K or ^R' | |||
pagehelp<-1> = ' BOTTOM = <Ctrl-Page Down> or ^B' | |||
pagehelp<-1> = ' <Ctrl-]> = Value Mark' | |||
pagehelp<-1> = ' <Backspace> is destructive <Ctrl-\> = Sub-value Mark' | |||
pagehelp<-1> = ' <Enter> splits the line' | |||
pagehelp<-1> = ' <Insert> or <Tab> toggles between the insert and overwrite modes' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' <F2> or ^W Returns to line editor mode WITH changes' | |||
pagehelp<-1> = ' <Esc> or ^Q Returns without changes' | |||
end else | |||
pagehelp = '' | |||
pagehelp<-1> = ' Page viewing help' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' Cursor movement keys Line movement keys' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' UP = <UP arrow> or ^Z LEFT END = <Home> or ^A' | |||
pagehelp<-1> = ' DOWN = <DOWN arrow> or ^J RIGHT END = <End> or ^E' | |||
pagehelp<-1> = ' LEFT = <LEFT arrow> or ^U GO TO LINE = ^G' | |||
pagehelp<-1> = ' RIGHT = <RIGHT arrow> or ^F (prompts for desired line)' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' Page movement keys ' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' PREVIOUS = <Page Up> or ^P ' | |||
pagehelp<-1> = ' NEXT = <Page Down> or ^N ' | |||
pagehelp<-1> = ' TOP = <Ctrl-Page Up> or ^T' | |||
pagehelp<-1> = ' BOTTOM = <Ctrl-Page Down> or ^B' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = '' | |||
pagehelp<-1> = ' <Esc> or ^Q Returns without changes' | |||
end | |||
end | |||
disp = pagehelp ; stub = '' | |||
gosub show.disp | |||
crt bott: | |||
stub = 'Press RETURN to continue' | |||
gosub get.rope | |||
gosub display.page | |||
return | |||
get.line: | |||
line = '' | |||
if here eq 0 then | |||
cell = 1 | |||
lnum = 0 | |||
return | |||
end | |||
if here gt last then return | |||
cell = int((here-1)/cellsize) + 1 | |||
coff = rem(here,cellsize) | |||
if ooff and ocel eq cell and ooff eq coff - 1 then | |||
lnum = ooff ; ooff = coff | |||
end else | |||
tlin = memr(cell) | |||
lnum = 0 ; ocel = cell ; ooff = coff | |||
end | |||
loop | |||
remove bite from tlin setting dlim | |||
line = line:bite | |||
while dlim do | |||
if dlim eq 2 then | |||
lnum += 1 | |||
if lnum eq coff then exit | |||
line = '' | |||
end else | |||
line = line:char(256-dlim) | |||
end | |||
repeat | |||
if not(dlim) then lnum += 1 | |||
return | |||
delete.lines: | |||
chng = 0 | |||
if dawn gt dusk then | |||
crt 'No deletion possible - ':dawn:' > ':dusk:'.' | |||
return | |||
end | |||
gosub savethat | |||
chng = dusk - dawn + 1 | |||
begin case | |||
case dawn le 1 and dusk ge last | |||
krj = '' | |||
this = '' | |||
beg = 0 | |||
fin = 0 | |||
case dusk ge last | |||
temp = index(this,am,dawn-1) | |||
this = this[1,temp-1] | |||
if beg gt dawn then beg = 0 | |||
if fin gt dawn then fin = 0 | |||
for xx = dcount(krj<1>,vm) to 1 step -1 | |||
if krj<2,xx> gt dawn then | |||
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1 | |||
end | |||
next xx | |||
case dawn eq 1 | |||
temp = index(this,am,dusk) | |||
this = this[temp+1,len(this)] | |||
if beg le dusk then beg = 0 else beg = beg - chng | |||
if fin le dusk then fin = 0 else fin = fin - chng | |||
for xx = dcount(krj<1>,vm) to 1 step -1 | |||
if krj<2,xx> le dusk then | |||
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1 | |||
end | |||
next xx | |||
case 1 | |||
temp = index(this,am,dawn-1) | |||
temp<2> = index(this,am,dusk) | |||
this = this[1,temp<1>]:this[temp<2>+1,len(this)] | |||
if beg ge dawn and beg le dusk then beg = 0 else | |||
if beg gt dusk then beg -= chng | |||
end | |||
if fin ge dawn and fin le dusk then fin = 0 else | |||
if fin gt dusk then fin -= chng | |||
end | |||
for xx = dcount(krj<1>,vm) to 1 step -1 | |||
begin case | |||
case krj<2,xx> gt dusk ; krj<2,xx> -= chng | |||
case krj<2,xx> ge dawn | |||
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1 | |||
end case | |||
next xx | |||
end case | |||
begin case | |||
case here gt dusk | |||
here = here - dusk + dawn - 1 | |||
case here gt dawn | |||
here = dawn | |||
end case | |||
gosub set.record | |||
return | |||
check.line: | |||
if '*':temp ne '*':line then | |||
if not(chng) then gosub savethis | |||
chng += 1 | |||
memr(cell)<lnum> = temp | |||
if shew or dnum lt plen then gosub display.line | |||
end | |||
return | |||
insert.line: | |||
if here le beg then beg += 1 | |||
if here le fin then fin += 1 | |||
yyno = dcount(krj<1>,vm) | |||
for yy = 1 to yyno | |||
if krj<2,yy> gt here then krj<2,yy> += 1 | |||
next yy | |||
memr(cell) = insert(memr(cell),lnum,0,0,line) | |||
if lfmt and len(last) gt 3 and len(last) ne llen then gosub get.lfmt | |||
return | |||
display.line: | |||
begin case | |||
case last eq 0 | |||
here = 0 | |||
gosub get.line | |||
crt begn:'Top of empty record.' | |||
case here eq 0 | |||
gosub get.line | |||
crt 'Top.' | |||
case here gt last | |||
crt 'Bottom.' | |||
case 1 | |||
gosub get.line | |||
if wild then | |||
xxno = len(line) | |||
temp = '' | |||
for xx = 1 to xxno | |||
bite = line[xx,1] | |||
bite = seq(bite) | |||
if bite ge 127 or bite lt 32 then | |||
$ifdef unidata | |||
bite = '^':fmt(bite,'3/0R') | |||
$else | |||
bite = '^':fmt(bite,'R%3') | |||
$endif | |||
end else bite = char(bite) | |||
temp = temp:bite | |||
next xx | |||
line = temp | |||
end else convert badc to gudc in line | |||
crt begn:ceol: | |||
if lfmt then | |||
blk = ': ' | |||
if here eq beg then blk = '< ' | |||
if here eq fin then blk = '> ' | |||
if here eq beg and here eq fin then blk = '<>' | |||
if lfmt then crt (here lfmt):blk: | |||
end | |||
if bleach then | |||
crt line | |||
end else | |||
if here ge beg and here le fin | |||
then showline = @(-13):@(-5):line:@(-6):@(-14) | |||
* else call SORT.LINE(showline,line,1,len(line),lastfind,caseflag) | |||
else setoff = 1 ; width = len(line) ; gosub getshowline | |||
crt showline | |||
end | |||
dnum += 1 | |||
if here eq last then crt 'Bottom at line ':last:'.' | |||
end case | |||
return | |||
clear.page: | |||
for xx = system(3)-1 to 0 step -1 | |||
crt @(00,xx):ceol: | |||
next xx | |||
return | |||
display.page: | |||
crt clpg | |||
disp.page: | |||
if pchr lt 1 then pchr = 1 | |||
gosub clear.page | |||
gosub get.lfmt | |||
crt bott:revb:'Press <F1> for help.':revf: | |||
crt @(0,0):ceol:revb: | |||
if viewflag | |||
then crt 'Viewing "':item:'" in file "':fnam:'"': | |||
else crt 'Editing "':item:'" in file "':fnam:'"': | |||
crt revf: | |||
if idcnt gt 1 then crt ' <':id:'/':idcnt:'> ': | |||
crt | |||
ppos = int((pchr-1)/span) | |||
ppos = span*ppos+1 | |||
save = here:am:lnum:am:cell:am:line | |||
for xx = 1 to botl | |||
here = ptop + xx - 1 | |||
gosub get.line | |||
if bleach then | |||
disp = line[ppos,span] | |||
convert badc to gudc in disp | |||
end else | |||
convert badc to gudc in line | |||
disp = line | |||
if here ge beg and here le fin | |||
then showline = @(-13):@(-5):disp[ppos,span]:@(-6):@(-14) | |||
* else call SORT.LINE(showline,disp,ppos,span,lastfind,caseflag) | |||
else setoff = ppos ; width = span ; gosub getshowline | |||
disp = showline | |||
end | |||
crt @(0,xx):disp: | |||
next xx | |||
here = save<1>; lnum = save<2>; cell = save<3>; line = save<4> | |||
return | |||
savethis: | |||
oops = this ; oopc = comi ; oopl = save ; oopf = savl | |||
oopb = beg:am:fin ; oopk = krj | |||
* if level eq 0 then write oops on voc, '&LED.':whom | |||
return | |||
savethat: | |||
oops = this ; oopc = comi ; oopl = here ; oopf = last | |||
oopb = beg:am:fin ; oopk = krj | |||
* if level eq 0 then write oops on voc, '&LED.':whom | |||
return | |||
reset.record: | |||
matbuild this from memr using am | |||
set.record: | |||
gosub parse.record | |||
gosub get.line | |||
if len(last) gt 3 and len(last) ne llen then gosub get.lfmt | |||
return | |||
parse.record: | |||
this = this | |||
ocel = '' ; ooff = '' | |||
last = dcount(this,am) | |||
if last eq 0 then | |||
dim memr(1) | |||
mat memr = '' | |||
cell = 1 ; lnum = 0 | |||
return | |||
end | |||
numcells = int((last-1)/cellsize)+1 | |||
dim memr(numcells) | |||
mat memr = '' | |||
cell = 1 | |||
lnum = 0 | |||
for cell = 1 to numcells | |||
memr(cell) = field(this,@am,(cell-1)*cellsize+1,cellsize) | |||
next cell | |||
! line = '' | |||
! loop | |||
! remove bite from this setting mark | |||
! line = line:bite | |||
! begin case | |||
! case mark eq 0 | |||
! if line ne '' then | |||
! line = line[1,len(line)] | |||
! end | |||
! memr(cell) = line | |||
! case mark eq 2 | |||
! lnum += 1 | |||
! if lnum ge cellsize then | |||
! memr(cell) = line | |||
! line = '' | |||
! cell += 1 | |||
! lnum = 0 | |||
! end else | |||
! line = line:char(256-mark) | |||
! end | |||
! case 1 | |||
! line = line:char(256-mark) | |||
! end case | |||
! while mark do | |||
! repeat | |||
cell = 1 | |||
lnum = 0 | |||
return | |||
locked.record: | |||
stub = 'Record is currently locked by another user. Try again? ':ny:' ' | |||
gosub get.rope; answ = rope | |||
answ = upcase(trim(answ)) | |||
if answ eq 'PASSWORD' then | |||
lock = false | |||
read this from file, item then goto carry.on | |||
end | |||
if answ[1,1] eq yes[1,1] then goto edit.item | |||
return | |||
exec.that: | |||
temp = temp<1>:' ':fnam:' ':item:temp<2> | |||
if fileinfo(file,3) ne '4' then | |||
crt 'Cannot ':temp:' - must be type 1 or 19' | |||
return | |||
end | |||
execute temp | |||
test = @(0,0) | |||
return | |||
parse.rest: | |||
bite = '' | |||
flag = '' | |||
posn = 1 | |||
xxno = len(rest) | |||
for xx = 1 to xxno | |||
bit = rest[xx,1] | |||
if flag eq '' then | |||
if bit eq ' ' then | |||
if bite<posn> ne '' then posn += 1 | |||
end else | |||
if index(qt,bit,1) then | |||
flag = bit | |||
if keepquot then bite<posn> = bite<posn>:bit | |||
end else | |||
if bit eq '(' then | |||
flag = ')' | |||
if bite<posn> ne '' then posn += 1 | |||
bite<posn> = '(' | |||
end else bite<posn> = bite<posn>:bit | |||
end | |||
end | |||
end else | |||
if bit ne flag then | |||
bite<posn> = bite<posn>:bit | |||
end else | |||
if keepquot or bit eq ')' then bite<posn> = bite<posn>:bit | |||
posn += 1 | |||
flag = '' | |||
end | |||
end | |||
next xx | |||
return | |||
split.itype: | |||
bite = '' | |||
flag = '' | |||
posn = 1 | |||
xxno = len(line) | |||
for xx = 1 to xxno | |||
bit = line[xx,1] | |||
if flag eq '' then | |||
if bit eq ';' then | |||
posn += 1 | |||
end else | |||
if index(qt,bit,1) then flag = bit | |||
if bit eq '(' then flag = ')' | |||
bite<posn> = bite<posn>:bit | |||
end | |||
end else | |||
if bit eq flag[1,1] then flag = flag[2,huge] | |||
if bit eq '(' and flag[1,1] eq ')' then flag := ')' | |||
bite<posn> = bite<posn>:bit | |||
end | |||
next xx | |||
return | |||
get.lfmt: | |||
* set up the line format | |||
llen = len(last) | |||
if llen lt 3 then llen = 3 | |||
$ifdef unidata | |||
lfmt = llen:'/0R' | |||
$else | |||
lfmt = 'R%':llen | |||
if index(item,'_IType.',1) then lfmt = llen:'@R' | |||
$endif | |||
prmt = '*':str('-',llen-1) | |||
return | |||
leftarr: * | |||
numb = oconv(trim(comi[2,len(comi)]),'MCN') | |||
if numb eq '' then numb = here | |||
if numb gt last then numb = '' | |||
if numb ge 0 then | |||
crt 'Block starts at line ':numb: | |||
beg = numb | |||
if fin and beg gt fin then | |||
crt '; End moved from ':fin:' to ':beg | |||
fin = beg | |||
mov = 1 | |||
end else | |||
if fin then mov = fin - beg + 1 else mov = last - beg | |||
crt ' (':mov:' lines)' | |||
end | |||
if numb eq here then gosub display.line | |||
end else crt 'Cannot mark line ':numb | |||
return | |||
rightarr: * | |||
numb = oconv(trim(comi[2,len(comi)]),'MCN') | |||
if numb eq '' then numb = here | |||
if numb gt last then numb = '' | |||
if numb ge 0 then | |||
crt 'Block ends at line ':numb: | |||
fin = numb | |||
if beg gt fin then | |||
crt '; Start moved from ':beg:' to ':fin | |||
beg = fin | |||
mov = 1 | |||
end else | |||
if beg then mov = fin - beg + 1 else mov = fin | |||
crt ' (':mov:' lines)' | |||
end | |||
if numb eq here then gosub display.line | |||
end else crt 'Cannot mark line ':numb | |||
return | |||
botharr: * | |||
numb = trim(comi[3,len(comi)]) | |||
begin case | |||
case numb matches '1N0N' | |||
numb = numb:am:numb | |||
case numb matches '1N0N"-"1N0N' | |||
numb = field(numb,'-',1):am:field(numb,'-',2) | |||
case numb matches '1N0N" "1N0N' | |||
numb = field(numb,' ',1):am:field(numb,' ',2) | |||
case numb eq '' | |||
numb = here:am:here | |||
case 1 | |||
numb = '' | |||
end case | |||
if numb<2> gt last then numb<2> = last | |||
if numb<1> gt last then numb = '' | |||
if numb<2> lt numb<1> then | |||
crt 'Block starts at ':numb<1>:' and ends at ':numb<2>:' => ': | |||
numb = '' | |||
end | |||
if numb ne '' then | |||
beg = numb<1> | |||
fin = numb<2> | |||
if beg eq fin then | |||
crt 'Block starts and ends at line ':beg | |||
end else | |||
crt 'Block starts at ':beg:' and ends at ':fin | |||
end | |||
if here eq beg or here eq fin then | |||
gosub display.line | |||
end | |||
end else crt 'Cannot mark Block' | |||
return | |||
recalc.posn: | |||
begin case | |||
case posn lt rest and posn le oopl | |||
case posn lt rest and posn gt oopl | |||
posn += numb | |||
case posn ge rest and posn lt (rest+numb) | |||
posn += (here+1-rest) | |||
case posn ge (rest+numb) and posn le oopl | |||
posn -= numb | |||
end case | |||
return | |||
find.label: | |||
temp = field(trimf(line),' ',1) | |||
temp = trim(temp,char(13),'B') | |||
chit = temp[1,1] | |||
begin case | |||
case chit eq '*' or chit eq '!' ; temp = '' | |||
case chit matches '1N' or chit eq '.' | |||
temp = field(temp,'*',1) | |||
temp = field(temp,'!',1) | |||
temp = field(temp,':',1) | |||
test = convert('.0123456789','',temp) | |||
if test ne '' then temp = '' | |||
case chit matches '1A' and index(temp,':',1) | |||
temp = field(temp,':',1) | |||
test = oconv(oconv(temp,'MC/A'),'MC/N') | |||
test = convert('._%$','',test) | |||
if test ne '' then temp = '' | |||
case 1 | |||
temp = '' | |||
end case | |||
return | |||
get.answ: | |||
loop | |||
*> | |||
rlen = 1 | |||
*> | |||
gosub get.rope | |||
answ = upcase(trim(rope)[1,1]) | |||
until answ eq yes[1,1] or answ eq no[1,1] do | |||
crt 'Please answer Y or N' | |||
repeat | |||
crt | |||
return | |||
writerr: | |||
$ifdef qm | |||
if status() eq er$trigger then | |||
crt 'Data validation error: ': @trigger.return.code | |||
end else | |||
crt 'Write error ': status():' (o/s error %2) - Data not saved. Original data will be lost if you leave the editor now.' | |||
end | |||
$else | |||
crt 'Write error ': status():' (o/s error %2) - Data not saved. Original data will be lost if you leave the editor now.' | |||
$endif | |||
return | |||
indenter: | |||
marg = fr(1) ;* the margin | |||
dent = fr(2) ;* the indentation | |||
supp = fr(6) ;* flag - suppress '!' output | |||
astx = not(fr(9)) ;* flag - keep '*' comments on page edge | |||
suit = not(fr(10)) ;* flag - indent 'CASE' statements | |||
dead = 'ACDGHIJKMPQSVXYZ' | |||
push = 'LOOP\WHILE\UNTIL\FOR\THEN\ELSE\BEGIN\LOCKED\ON~ERROR' | |||
pull = 'UNTIL\WHILE\REPEAT\NEXT\END' | |||
convert '\' to am in push | |||
convert '\' to am in pull | |||
skip = ';:" (' : "'" | |||
marx = '\"' : "'" | |||
bang = false | |||
xxno = dcount(this,am) | |||
dim part(100) | |||
matparse part from this, am | |||
this = '' | |||
bite = '' | |||
first = true | |||
for xx = 1 to xxno | |||
there = rem(xx,100) | |||
if not(there) then | |||
if first then this = bite else this = this:am:bite | |||
first = false | |||
bite = '' | |||
thisline = part(100) | |||
temp = part(0) | |||
matparse part from temp, am | |||
if not(supp) then bang = true; crt '!': | |||
end else thisline = part(there) | |||
if trim(thisline) eq '' then | |||
if first then bite<there> = '' else bite<there+1> = '' | |||
continue | |||
end | |||
note = false | |||
wcnt = 0; more = 0; less = 0 | |||
mark = ''; tags = ''; lastword = '' | |||
zz = 1 | |||
thisline = trimf(thisline) | |||
if thisline matches '1N0N"*"0X' then | |||
temp = field(thisline,'*',1) | |||
thisline = temp:' ':thisline[col2(),len(thisline)] | |||
end | |||
thatline = upcase(thisline) | |||
thatline = change(thatline, 'ON ERROR', 'ON~ERROR') | |||
left = field(thatline,' ',1) | |||
if num(left) or left[len(left),1] eq ':' then | |||
if not(index(left,'=',1)) then tags = thisline[1,len(left)] | |||
end | |||
if tags gt '' then | |||
thisline = trimf(thisline[col2()+1,len(thisline)]) | |||
thatline = trimf(thatline[col2()+1,len(thatline)]) | |||
end | |||
zzno = len(thisline) | |||
loop | |||
while zz lt zzno and not(note) do | |||
loop | |||
thisun = thatline[zz,1] | |||
begin case | |||
case mark eq '' and index(marx,thisun,1) | |||
mark = thisun | |||
case mark ne '' | |||
if thisun eq mark then mark = '' | |||
case wcnt and thisun eq ';' | |||
that = field(trim(thatline[zz+1,zzno]),' ',1) | |||
if that[1,3] eq 'REM' then that = '' | |||
if that[1,1] eq '*' then that = '' | |||
if that[1,1] eq '!' then that = '' | |||
if that eq '' then zz = zzno | |||
case wcnt | |||
case thisun eq '!' or thisun eq '$' | |||
note = true; zz = zzno | |||
case thisun eq '*' | |||
if astx then note = true | |||
zz = zzno | |||
case field(thatline,' ',1) eq 'REM' | |||
note = true; zz = zzno | |||
end case | |||
while (index(skip,thisun,1) or mark) and zz lt zzno do | |||
zz += 1 | |||
repeat | |||
left = zz | |||
loop | |||
thisun = thatline[zz,1] | |||
until index(skip,thisun,1) or zz gt zzno do | |||
zz += 1 | |||
repeat | |||
word = thatline[left,zz-left] | |||
wcnt += 1 | |||
if wcnt ne 1 then | |||
if word eq 'WHILE' or word eq 'UNTIL' then word = ' ' | |||
if word eq 'NEXT' or word eq 'REPEAT' then | |||
word = ' ' | |||
more -= dent | |||
end | |||
if lastword eq 'LOCKED' then more -= dent | |||
end else | |||
if word eq 'LOCKED' or word eq 'THEN' then | |||
if word eq trim(thatline) then less += dent | |||
end | |||
end | |||
if word eq 'CASE' then | |||
if lastword ne 'BEGIN' and lastword ne 'END' then | |||
more += dent | |||
less += dent | |||
end | |||
if suit and lastword eq 'BEGIN' then more += dent | |||
if suit and lastword eq 'END' then less += dent | |||
end | |||
if not(index(dead,word[1,1],1)) then | |||
locate(word,pull;rubbish) then less += dent | |||
test = word ne 'THEN' & word ne 'ELSE' & word ne 'ON~ERROR' | |||
that = trim(thisline[zz,zzno]) | |||
if that[1,1] eq ';' then | |||
that = trim(that[2,zzno])[1,3] | |||
if that[1,3] eq 'REM' then that = '' | |||
if that[1,1] eq '*' then that = '' | |||
if that[1,1] eq '!' then that = '' | |||
end | |||
if test or that eq '' then | |||
locate(word,push;rubbish) then | |||
more += dent | |||
end | |||
end | |||
if word eq 'THEN' or word eq 'LOCKED' then | |||
if that eq '' and lastword eq '' then less -= dent | |||
end | |||
if that ne '' and lastword eq '' then | |||
if word eq 'THEN' or word eq 'ELSE' then | |||
more -= dent | |||
less -= dent | |||
end | |||
if word eq 'LOCKED' and trim(that)[1,1] ne '=' | |||
then more -= dent ; less -= dent | |||
end | |||
end | |||
lastword = word | |||
repeat | |||
marg -= less | |||
if tags eq '' then pict = '' else pict = 'L#':(len(tags)+1) | |||
if marg gt len(tags) then pict = 'L#':marg | |||
if thisline eq '!' or thisline eq '$' then note = true | |||
if thatline eq 'REM' then note = true | |||
if astx and thisline eq '*' then note = true | |||
if note then | |||
if tags eq '' then pict = '' else pict = 'L#':(len(tags)+1) | |||
end | |||
thisline = trimb(fmt(tags,pict):thisline) | |||
if first then | |||
bite<there> = thisline | |||
end else bite<there+1> = thisline | |||
marg += more | |||
next xx | |||
if bang then crt | |||
if bite ne '' then | |||
if first then this = bite else this = this:am:bite | |||
end | |||
that = '' | |||
return | |||
get.rope: | |||
* If the terminal doesn't support screen addressing, do simple input | |||
if not(editpage) then | |||
crt begn:stub: | |||
*> input rope: | |||
if rlen then | |||
input rope,rlen: | |||
rlen = 0 | |||
end else input rope: | |||
*> | |||
return | |||
end | |||
* | |||
* The following variables are used | |||
* | |||
* BARE - what you are going to reveal (the displayed part) | |||
* CRAM - insert mode on (vs overwrite mode) | |||
* PCOL - display position | |||
* STEM - the prefix part of the display line | |||
* ICON - a picture of what you last displayed | |||
* PANS - the PAN increment | |||
* PPOS - the PAN origin | |||
* WIDE - the PAN width | |||
* PULP - SEQ(COMI) - what you get from a key press | |||
* PURE - untouched, a virgin | |||
* POSN - the stack position | |||
* PCHR - text position | |||
pans = int(span/2) | |||
posn = 0 | |||
rope = pick; pick = '' | |||
loop | |||
if heap then | |||
stem = prmt:': ' | |||
if posn then stem = '*':fmt(posn, "3'0'R"):stem[5,huge] | |||
end else stem = '*':stub | |||
wide = span - len(stem) - 1 | |||
pans = int(wide/2) | |||
ppos = 1 | |||
pchr = 1 | |||
cram = true | |||
icon = space(span) | |||
crt begn : ceol : | |||
pure = true | |||
!&&& | |||
! if nick and trim(rope) = '' then pchr = len(rope)+1 ; pure = false | |||
!&&& | |||
loop | |||
begin case | |||
*> case pchr lt ppos ; ppos -= pans | |||
case pchr lt ppos | |||
loop while pchr lt ppos ; ppos -= pans ; repeat | |||
case pchr ge (ppos+wide) | |||
loop while pchr ge(ppos+wide) ; ppos += pans ; repeat | |||
*> case pchr ge (ppos+wide) ; ppos += pans | |||
end case | |||
bare = stem : rope[ppos, wide] | |||
pcol = 0 | |||
if icon ne bare then | |||
yyno = 0 | |||
for yy = 1 to span until yyno | |||
if bare[yy,1] ne icon[yy,1] then yyno = yy | |||
next yy | |||
crt @(yyno-1):bare[yyno,span-yyno]:ceol:@(pcol): | |||
icon = bare[1,span] | |||
end | |||
pcol = len(stem) + pchr - ppos | |||
crt @(pcol) : | |||
gosub get.keyc | |||
locate(keyc,keys;cpos) then cpos = acts<cpos> else cpos = 0 | |||
pulp = seq(keyc) | |||
if pulp lt 32 or pulp gt 128 then keyc = '' | |||
if pure then | |||
if cpos eq 0 and keyc ne '' then | |||
rope = '' | |||
pchr = 1 | |||
end | |||
crt @(0): | |||
if cram then crt '>': else crt '#': | |||
crt @(pcol): | |||
pure = false | |||
end | |||
begin case | |||
case heap and (cpos = uarr or cpos = upag) | |||
if posn lt dcount(stak, vm) then | |||
posn += 1 | |||
rope = stak<1,posn> | |||
end | |||
exit | |||
case heap and (cpos = darr or cpos = dpag) | |||
if posn gt 1 then | |||
posn -= 1 | |||
rope = stak<1,posn> | |||
end else | |||
posn = 0 | |||
rope = '' | |||
end | |||
exit | |||
case heap and cpos = skey | |||
if rope eq '' then | |||
if look<1> eq '' then continue | |||
comi = look<1,1> | |||
gosub parse.command | |||
rope = 'L':dlim:rest | |||
end else rope = 'L/':rope | |||
if rope eq look<1> then rope = 'L' | |||
return | |||
case heap and cpos = rkey | |||
if rope eq '' then | |||
if look<1> eq '' then continue | |||
comi = look<1,1> | |||
gosub parse.command | |||
rope = 'LA':dlim:rest | |||
end else rope = 'LA/':rope | |||
if rope eq look<1> then rope = 'L' | |||
return | |||
case heap and cpos = writ and pulp ne 23 | |||
rope = 'PE' | |||
return | |||
case heap and cpos = phlp | |||
stub = '' ; heap = false ; rest = '' | |||
gosub show.help | |||
rope = 'D' | |||
return | |||
case cpos = larr | |||
if pchr gt 1 then pchr -= 1 | |||
case cpos = rarr | |||
if pchr le len(rope) then pchr += 1 | |||
case cpos = lpag | |||
pchr = 1 | |||
case cpos = rpag | |||
pchr = len(rope) + 1 | |||
case cpos = escp | |||
posn = 0 | |||
rope = '' | |||
exit | |||
case cpos = delc | |||
rope = rope[1, pchr-1] : rope[pchr+1, huge] | |||
case cpos = delr | |||
rope = rope[1, pchr-1] | |||
case cpos = back | |||
if pchr gt 1 then | |||
pchr -= 1 | |||
rope = rope[1, pchr-1] : rope[pchr+1, huge] | |||
end | |||
case cpos = carr | |||
if heap then | |||
crt begn : ceol : ':' : rope: | |||
if posn then | |||
if rope eq stak<1,posn> then del stak<1,posn> | |||
end | |||
end | |||
return | |||
case cpos = togg | |||
cram = not(cram) | |||
crt @(0): | |||
if cram then crt '>': else crt '#': | |||
crt @(pcol): | |||
case pulp eq 23 ;* ctrl-w | |||
dope = downcase(rope) | |||
mope = upcase(rope) | |||
tope = oconv(rope,'MCT') | |||
begin case | |||
case rope eq tope and dope eq tope ; rope = mope | |||
case rope eq tope ; rope = dope | |||
case rope eq mope ; rope = tope | |||
case 1 ; rope = mope | |||
end case | |||
case pulp ge 32 and pulp lt 128 | |||
if cram then | |||
rope = rope[1, pchr-1] : keyc : rope[pchr, huge] | |||
end else | |||
if pchr le len(rope) | |||
then rope[pchr, 1] = keyc | |||
else rope := keyc | |||
end | |||
pchr += 1 | |||
case 1 | |||
crt bell: | |||
end case | |||
if rlen and len(rope) ge rlen then | |||
crt keyc: | |||
rlen = 0 | |||
return | |||
end | |||
repeat | |||
repeat | |||
return | |||
get.keyc: | |||
$ifdef qm | |||
if not(index(upcase(system(7)),'EEEPC',1)) then | |||
keyc = keycode() | |||
return | |||
end | |||
$endif | |||
common /keys$krj/ termtype,eseq,keyd,base,full | |||
if not(assigned(termtype)) then termtype = '' | |||
if termtype ne oconv(system(7),'MCU') then gosub setup.keys | |||
keyc = '' | |||
loop | |||
$ifdef unidata | |||
mine = in() | |||
$else | |||
mine = keyin() | |||
$endif | |||
locate(mine,base;post) then gosub get.rest | |||
locate(mine,eseq;cmd) | |||
then keyc = char(keyd<cmd>) | |||
else if len(mine) eq 1 then keyc = mine | |||
while keyc eq '' do repeat | |||
return | |||
get.rest: | |||
loop | |||
$ifdef unidata | |||
a = system(12) | |||
loop | |||
until system(12) ge (a+5) do | |||
repeat | |||
$else | |||
nap 5 | |||
$endif | |||
input your,-1 | |||
while your do | |||
$ifdef unidata | |||
mine := in() | |||
$else | |||
mine := upcase(keyin()) | |||
$endif | |||
locate(mine,full,post;your) then return | |||
repeat | |||
return | |||
setup.keys: | |||
* Define the key numbers - these are based on QM keycode() | |||
*====================================================================== | |||
* Arrow keys | |||
equ lark to 203, rark to 204, uark to 205, dark to 206 | |||
* Page up and down, home and end | |||
equ upak to 207, dpak to 208, homk to 209, endk to 210 | |||
* Insert, delete, backtab, delete line, backspace | |||
equ insk to 211, deck to 212, btbk to 213, delk to 127, bspk to 8 | |||
* Control - Page up and down, homk and end | |||
equ cupk to 214, cdpk to 215, chok to 216, cenk to 217 | |||
* Function, Control+Function, Alt+Function, Shift+Function | |||
equ f1 to 128, cf1 to 140, af1 to 152, sf1 to 164 | |||
equ f2 to 129, cf2 to 141, af2 to 153, sf2 to 165 | |||
equ f3 to 130, cf3 to 142, af3 to 154, sf3 to 166 | |||
equ f4 to 131, cf4 to 143, af4 to 155, sf4 to 167 | |||
equ f5 to 132, cf5 to 144, af5 to 156, sf5 to 168 | |||
equ f6 to 133, cf6 to 145, af6 to 157, sf6 to 169 | |||
equ f7 to 134, cf7 to 146, af7 to 158, sf7 to 170 | |||
equ f8 to 135, cf8 to 147, af8 to 159, sf8 to 171 | |||
equ f9 to 136, cf9 to 148, af9 to 160, sf9 to 172 | |||
equ f10 to 137, cf10 to 149, af10 to 161, sf10 to 173 | |||
equ f11 to 138, cf11 to 150, af11 to 162, sf11 to 174 | |||
equ f12 to 139, cf12 to 151, af12 to 163, sf12 to 175 | |||
*====================================================================== | |||
* Stash the escape sequences and key codes in labelled common | |||
termtype = oconv(system(7),'MCU') | |||
* Set up keys good for many terminals and as defaults | |||
eseq = '' ; keyd = '' | |||
keyd<-1> = lark; eseq<-1> = char(21) | |||
keyd<-1> = rark; eseq<-1> = char(6) | |||
keyd<-1> = uark; eseq<-1> = char(26) | |||
keyd<-1> = dark; eseq<-1> = char(10) | |||
keyd<-1> = homk; eseq<-1> = char(1) | |||
keyd<-1> = endk; eseq<-1> = char(5) | |||
keyd<-1> = deck; eseq<-1> = char(4) | |||
keyd<-1> = upak; eseq<-1> = char(27):'[5~' | |||
keyd<-1> = dpak; eseq<-1> = char(27):'[6~' | |||
* Now do settings that don't interfere between terminals | |||
* VT-type terminals - cater for alternative arrow sequences | |||
keyd<-1> = rark; eseq<-1> = char(27):'[C' | |||
keyd<-1> = rark; eseq<-1> = char(27):'OC' | |||
keyd<-1> = uark; eseq<-1> = char(27):'[A' | |||
keyd<-1> = uark; eseq<-1> = char(27):'OA' | |||
keyd<-1> = dark; eseq<-1> = char(27):'[B' | |||
keyd<-1> = dark; eseq<-1> = char(27):'OB' | |||
keyd<-1> = insk; eseq<-1> = char(27):'[1~' | |||
keyd<-1> = deck; eseq<-1> = char(27):'[4~' | |||
keyd<-1> = btbk; eseq<-1> = char(27):'[Z' | |||
keyd<-1> = f1 ; eseq<-1> = char(27):'OP' | |||
keyd<-1> = f2 ; eseq<-1> = char(27):'OQ' | |||
keyd<-1> = f3 ; eseq<-1> = char(27):'OR' | |||
keyd<-1> = f4 ; eseq<-1> = char(27):'OS' | |||
keyd<-1> = f5 ; eseq<-1> = char(27):'OT' | |||
keyd<-1> = f6 ; eseq<-1> = char(27):'[17~' | |||
keyd<-1> = f7 ; eseq<-1> = char(27):'[18~' | |||
keyd<-1> = f8 ; eseq<-1> = char(27):'[19~' | |||
keyd<-1> = f9 ; eseq<-1> = char(27):'[20~' | |||
keyd<-1> = f10 ; eseq<-1> = char(27):'[21~' | |||
keyd<-1> = f11 ; eseq<-1> = char(27):'[23~' | |||
keyd<-1> = f12 ; eseq<-1> = char(27):'[24~' | |||
* Wyse-type terminals | |||
keyd<-1> = insk; eseq<-1> = char(27):'Q' | |||
keyd<-1> = deck; eseq<-1> = char(27):'W' | |||
keyd<-1> = btbk; eseq<-1> = char(27):'I' | |||
keyd<-1> = f1 ; eseq<-1> = char(1):'@':char(13) | |||
keyd<-1> = f2 ; eseq<-1> = char(1):'A':char(13) | |||
keyd<-1> = f3 ; eseq<-1> = char(1):'B':char(13) | |||
keyd<-1> = f4 ; eseq<-1> = char(1):'C':char(13) | |||
keyd<-1> = f5 ; eseq<-1> = char(1):'D':char(13) | |||
keyd<-1> = f6 ; eseq<-1> = char(1):'E':char(13) | |||
keyd<-1> = f7 ; eseq<-1> = char(1):'F':char(13) | |||
keyd<-1> = f8 ; eseq<-1> = char(1):'G':char(13) | |||
keyd<-1> = f9 ; eseq<-1> = char(1):'H':char(13) | |||
keyd<-1> = f10 ; eseq<-1> = char(1):'I':char(13) | |||
keyd<-1> = f11 ; eseq<-1> = char(1):'J':char(13) | |||
keyd<-1> = f12 ; eseq<-1> = char(1):'K':char(13) | |||
* ADDS-type terminals | |||
keyd<-1> = f1 ; eseq<-1> = char(2):'1':char(13) | |||
keyd<-1> = f2 ; eseq<-1> = char(2):'2':char(13) | |||
keyd<-1> = f3 ; eseq<-1> = char(2):'3':char(13) | |||
keyd<-1> = f4 ; eseq<-1> = char(2):'4':char(13) | |||
keyd<-1> = f5 ; eseq<-1> = char(2):'5':char(13) | |||
keyd<-1> = f6 ; eseq<-1> = char(2):'6':char(13) | |||
keyd<-1> = f7 ; eseq<-1> = char(2):'7':char(13) | |||
keyd<-1> = f8 ; eseq<-1> = char(2):'8':char(13) | |||
keyd<-1> = f9 ; eseq<-1> = char(2):'9':char(13) | |||
keyd<-1> = f10 ; eseq<-1> = char(2):':':char(13) | |||
keyd<-1> = f11 ; eseq<-1> = char(2):';':char(13) | |||
keyd<-1> = f12 ; eseq<-1> = char(2):'<':char(13) | |||
* xterm type - like my ASUS eeePC | |||
keyd<-1> = bspk ; eseq<-1> = char(127) | |||
keyd<-1> = delk ; eseq<-1> = char(27):'[3;2~' | |||
keyd<-1> = f5 ; eseq<-1> = char(27):'[15~' | |||
keyd<-1> = sf1 ; eseq<-1> = char(27):'O2P' | |||
keyd<-1> = sf2 ; eseq<-1> = char(27):'O2Q' | |||
keyd<-1> = sf3 ; eseq<-1> = char(27):'O2R' | |||
keyd<-1> = sf4 ; eseq<-1> = char(27):'O2S' | |||
keyd<-1> = sf5 ; eseq<-1> = char(27):'[15;2~' | |||
keyd<-1> = sf6 ; eseq<-1> = char(27):'[17;2~' | |||
keyd<-1> = sf7 ; eseq<-1> = char(27):'[18;2~' | |||
keyd<-1> = sf8 ; eseq<-1> = char(27):'[19;2~' | |||
keyd<-1> = sf9 ; eseq<-1> = char(27):'[20;2~' | |||
keyd<-1> = sf10 ; eseq<-1> = char(27):'[21;2~' | |||
keyd<-1> = sf11 ; eseq<-1> = char(27):'[23;2~' | |||
keyd<-1> = sf12 ; eseq<-1> = char(27):'[24;2~' | |||
* Now do terminal-specific settings | |||
* VT-type terminals | |||
if termtype[1,2] eq 'VT' or termtype[1,5] eq 'XTERM' then | |||
keyd<-1> = lark; eseq<-1> = char(27):'[D' | |||
keyd<-1> = lark; eseq<-1> = char(27):'OD' | |||
end else | |||
keyd<-1> = insk; eseq<-1> = char(27):'[D' | |||
keyd<-1> = deck; eseq<-1> = char(27):'OD' | |||
end | |||
* Wyse-type terminals | |||
if termtype[1,2] eq 'WY' then | |||
keyd<-1> = lark; eseq<-1> = char(8) | |||
keyd<-1> = rark; eseq<-1> = char(12) | |||
keyd<-1> = uark; eseq<-1> = char(11) | |||
keyd<-1> = btbk; eseq<-1> = char(27):'O' ;* ! | |||
end | |||
* for my lttle ASUS eeePC & Linux - What a cool thing it is! | |||
if index(termtype,'EEEPC',1) then | |||
keyd<-1> = chok; eseq<-1> = char(27):'[2H' ;* Shift-Home actually | |||
keyd<-1> = homk; eseq<-1> = char(27):'[H' | |||
keyd<-1> = endk; eseq<-1> = char(27):'[F' | |||
keyd<-1> = insk; eseq<-1> = char(27):'[2~' | |||
keyd<-1> = deck; eseq<-1> = char(27):'[3~' | |||
end else | |||
keyd<-1> = homk; eseq<-1> = char(27):'[2~' | |||
keyd<-1> = endk; eseq<-1> = char(27):'[3~' | |||
end | |||
* Populate the escape sequence test variables | |||
base = ''; full = '' | |||
amax = dcount(eseq,am) | |||
for anum = 1 to amax | |||
temp = eseq<anum> | |||
if len(temp) le 1 then continue | |||
locate(temp[1,1],base;post) else | |||
post = dcount(base,am)+1 | |||
end | |||
base<post> = temp[1,1] | |||
full<post,-1> = temp | |||
next anum | |||
return | |||
outline: | |||
* to display logic simplisticly | |||
rest = oconv(rest,'MCU') | |||
if index(rest,'*',1) then rest = 'CEPS' | |||
bot = here + 1 | |||
if bot gt last then bot = 1 | |||
if numb then msup = here + numb else msup = last | |||
if msup gt last then msup = last | |||
for here = bot to msup | |||
gosub get.line | |||
gosub find.label | |||
line = ' ':upcase(line) | |||
begin case | |||
case chit eq '*' or chit eq '!' ; line = '' | |||
case index(line,' GOTO ',1) | |||
case index(line,' GO ',1) | |||
case index(line,' GOSUB ',1) | |||
case rest eq '' ; line = '' | |||
case index(rest,'C',1) and index(line,' ':'CALL',1) | |||
case index(rest,'E',1) and index(line,' ':'EXECUTE',1) | |||
case index(rest,'P',1) and index(line,' ':'PERFORM',1) | |||
case index(rest,'S',1) and index(line,' ':'CASE',1) | |||
case 1 ; line = '' | |||
end case | |||
if temp ne '' or line ne '' then gosub display.line | |||
next here | |||
return | |||
getshowline: | |||
if unassigned(puncs) then | |||
puncs = ', []()<>=+-/*:#!' | |||
funcs = 'ABS\ABSS\ACOS\ADDS\ALPHA\ANDS\ASCII\ASIN\ASSIGNED\' | |||
funcs := 'ATAN\BITAND\BITNOT\BITOR\BITRESET\BITSET\BITTEST\' | |||
funcs := 'BITXOR\CATS\CHANGE\CHAR\CHARS\CHECKSUM\COL1\COL2\' | |||
funcs := 'CONTINUE\CONVERT\COS\COSH\COUNT\COUNTS\DATE\DCOUNT\' | |||
funcs := 'DELETE\DIV\DIVS\DOWNCASE\DQUOTE\DTX\EBCDIC\EQS\' | |||
funcs := 'EREPLACE\EXCHANGE\EXP\EXTRACT\FADD\FDIV\FFIX\FFLT\' | |||
funcs := 'FIELD\FIELDS\FIELDSTORE\FILEINFO\FIX\FMT\FMTDP\' | |||
funcs := 'FMTS\FMTSDP\FMUL\FOLD\FOLDDP\FSUB\GES\GET\' | |||
funcs := 'GETLOCALE\GETREM\GROUP\GTS\ICHECK\ICONV\ICONVS\' | |||
funcs := 'IFS\ILPROMPT\INDEX\INDEXS\INDICES\INMAT\INSERT\INT\' | |||
funcs := 'ISNULL\ISNULLS\ITYPE\KEYIN\LEFT\LEN\LENDP\LENS\' | |||
funcs := 'LENSDP\LES\LN\LOWER\LTS\MATCHFIELD\MAXIMUM\MINIMUM\' | |||
funcs := 'MOD\MODS\MULS\NEG\NEGS\NES\NOT\NOTS\NUM\NUMS\OCONV\' | |||
funcs := 'OCONVS\ORS\PWR\QUOTE\RAISE\REAL\RECORDLOCKED\REM\' | |||
funcs := 'REMOVE\REPLACE\REUSE\RIGHT\RND\RPC.CALL\RPC.CONNECT\' | |||
funcs := 'RPC.DISCONNECT\SADD\SCMP\SDIV\SEEK\SELECTINFO\SEND\' | |||
funcs := 'SENTENCE\SEQ\SEQS\SETLOCALE\SIN\SINH\SLEEP\SMUL\' | |||
funcs := 'SOUNDEX\SPACE\SPACES\SPLICE\SQRT\SQUOTE\SSUB\STATUS\' | |||
funcs := 'STR\STRS\SUBR\SUBS\SUBSTRINGS\SUM\SUMMATION\SYSTEM\' | |||
funcs := 'TAN\TANH\TERMINFO\TIME\TIMEDATE\TPARM\TRANS\TRIM\' | |||
funcs := 'TRIMB\TRIMBS\TRIMF\TRIMFS\TRIMS\UNASSIGNED\' | |||
funcs := 'UNICHAR\UPCASE\XLATE\XTD' | |||
convert '\' to @am in funcs | |||
keywords = 'ABORT\AUTHORIZATION\AUXMAP\BEGIN\BREAK\BSCAN\' | |||
keywords := 'BYTE\BYTELEN\BYTETYPE\BYTEVAL\CALL\CASE\CHAIN\' | |||
keywords := 'CLEAR\CLEARDATA\CLEARFILE\CLEARPROMPTS\CLEARSELECT\' | |||
keywords := 'CLOSE\CLOSESEQ\COMMIT\COMMON\COMPARE\CONSTANTS\' | |||
keywords := 'CONVERT\CREATE\CRT\DATA\DEBUG\DEFFUN\DEL\DELETE\' | |||
keywords := 'DELETELIST\DELETEU\DIM\DIMENSION\DISPLAY\DO\ECHO\ELSE\' | |||
keywords := 'END\ENTER\EQU\EQUATE\ERRMSG\EXECUTE\EXIT\FILELOCK\' | |||
keywords := 'FILEUNLOCK\FIND\FINDSTR\FLUSH\FOOTING\FOR\FORMLIST\' | |||
keywords := 'FUNCTION\GET\GETLIST\GETX\GO\GOSUB\GOTO\GROUPSTORE\' | |||
keywords := 'HEADING\HUSH\IF\INCLUDE\INPUT\INPUTCLEAR\INPUTDISP\' | |||
keywords := 'INPUTDP\INPUTERR\INPUTIF\INPUTNULL\INPUTTRAP\INS\' | |||
keywords := 'KEYEDIT\KEYEXIT\KEYTRAP\LET\LOCALEINFO\LOCATE\LOCK\' | |||
keywords := 'LOOP\MAT\MATBUILD\MATCH\MATCHES\MATPARSE\MATREAD\MATREADL\' | |||
keywords := 'MATREADU\MATWRITE\MATWRITEU\NAP\NEXT\NOBUF\NULL\' | |||
keywords := 'NUMERIC.DATA\ON\OPEN\OPENCHECK\OPENDEV\OPENPATH\' | |||
keywords := 'OPENSEQ\PAGE\PERFORM\PRECISION\PRINT\PRINTER\' | |||
keywords := 'PRINTERR\PROCREAD\PROCWRITE\PROGRAM\PROMPT\' | |||
keywords := 'RANDOMIZE\READ\READBLK\READL\READLIST\READNEXT\' | |||
keywords := 'READSEQ\READT\READU\READV\READVL\READVU\RECORDLOCK\' | |||
keywords := 'RELEASE\REM\REMOVE\REPEAT\RETURN\REVREMOVE\REWIND\' | |||
keywords := 'ROLLBACK\SEEK\SELECT\SELECTE\SELECTINDEX\SETREM\' | |||
keywords := 'SSELECT\START\STATUS\STOP\STORAGE\SUBROUTINE\' | |||
keywords := 'TABSTOP\THEN\TIMEOUT\TO\TPRINT\TRANSACTION\TTYCTL\' | |||
keywords := 'TTYGET\TTYSET\UNICHARS\UNISEQ\UNISEQS\UNLOCK\UNTIL\' | |||
keywords := 'UPRINT\WEOF\WEOFSEQ\WRITE\WRITEBLK\WRITELIST\' | |||
keywords := 'WRITESEQ\WRITESEQF\WRITET\WRITEU\WRITEV\WRITEVU' | |||
convert '\' to @am in keywords | |||
si.label = 1 | |||
si.comment = 2 | |||
si.string = 3 | |||
si.key = 4 | |||
si.operator = 5 | |||
si.function = 6 | |||
si.directive = 7 | |||
si.highlight = 8 | |||
si.doc = 9 | |||
bi.hiword = 10 | |||
* Highlights for HostAccess | |||
bo = @(-58) ; bf = @(-59) | |||
wo = @(-5) ; wf = @(-6) | |||
ro = @(-13) ; rf = @(-12) | |||
uo = @(-15) ; uf = @(-12) | |||
hi.commenton = uo:bo | |||
hi.commentoff = uf:bf | |||
hi.labelon = bo | |||
hi.labeloff = bf | |||
hi.selecton = ro:wo | |||
hi.selectoff = wf:rf | |||
hi.stringon = wo | |||
hi.stringoff = wf | |||
hi.keyon = uo | |||
hi.keyoff = uf | |||
hi.opon = '' | |||
hi.opoff = '' | |||
hi.funcon = bo | |||
hi.funcoff = bf | |||
hi.diron = wo | |||
hi.diroff = wf | |||
hi.docon = ro:bo | |||
hi.docoff = rf:bf | |||
end | |||
l = len(line) | |||
* If the line is too long, don't colourise it | |||
if l gt 2000 then | |||
showline = line[setoff,width] | |||
return | |||
end | |||
myline = line | |||
oldmyline = myline | |||
myline = trimf(myline) | |||
mask = space(l - len(myline)) | |||
word = myline[' ',1,1] | |||
if word[' ',1,1] match '1N0N' or word match '1A0X":"' then | |||
mask := str(si.label,len(word)):' ' | |||
myline = myline[' ',2,999] | |||
word = myline[' ',1,1] | |||
end | |||
begin case | |||
case word[1,1] eq '*' or word[1,1] eq '!' | |||
if count(myline,'@@') then | |||
mask := str(si.doc, l) | |||
end else | |||
mask := str(si.comment, l) | |||
end | |||
case word[1,1] eq '$' or word[1,1] eq '#' | |||
mask := str(si.directive, l) | |||
case 1 | |||
dc = count(myline,';') | |||
if not(dc) then | |||
mask := space(l) | |||
end else | |||
foundcomment = false | |||
for z = 1 to dc until foundcomment | |||
word = trimf(myline[';',z+1,1]) | |||
if word[1,1] eq '*' or word[1,1] eq '!' then | |||
foundcomment = z | |||
end | |||
next | |||
if foundcomment then | |||
mask := space(len(myline[';',1, foundcomment])):str(si.comment, l) | |||
end else | |||
mask := space(l) | |||
end | |||
end | |||
end case | |||
lin = convert(puncs,str(@fm,len(puncs)), upcase(oldmyline)) | |||
dc3 = dcount(lin,@fm) | |||
for q = 1 to dc3 | |||
word = lin[@fm,q,1] | |||
st = col1()+ 1 | |||
if st gt 1 then | |||
if mask[st-1,1] eq ' ' and oldmyline[st-1,1] ne ' ' then | |||
mask[st-1,1] = si.operator ; * operators too | |||
end | |||
end | |||
begin case | |||
case word[1,1] eq '"' | |||
ix = index(lin[st+1,huge],'"',1) | |||
if ix then | |||
if mask[st,1] eq ' ' then | |||
q = dcount(lin[1, ix+st],@fm) | |||
mask[st, ix+1] = str(si.string, ix+1) | |||
end | |||
end | |||
case word[1,1] eq "'" | |||
ix = index(lin[st+1,huge],"'",1) | |||
if ix then | |||
if mask[st,1] eq ' ' then | |||
q = dcount(lin[1, ix+st],@fm) | |||
mask[st, ix+1] = str(si.string, ix+1) | |||
end | |||
end | |||
case 1 | |||
locate(word,keywords;dpos;'AL') then | |||
if mask[st,1] eq ' ' then | |||
mask[st, len(word)] = str(si.key, len(word)) | |||
end | |||
end else | |||
locate(word,funcs;dpos;'AL') then | |||
* Functions are followed by a bracket | |||
brak = '' | |||
fpos = len(lin[@fm,1,q])+1 | |||
if fpos then brak = trim(oldmyline[fpos,999])[1,1] | |||
if brak eq '(' and mask[st,1] eq ' ' then | |||
mask[st,len(word)] = str(si.function, len(word)) | |||
end | |||
end | |||
end | |||
end case | |||
next | |||
word = lastfind | |||
if word ne '' then | |||
oc = 1 | |||
loop | |||
if caseflag | |||
then ix = index(oldmyline,word,oc) | |||
else ix = index(upcase(oldmyline),upcase(word),oc) | |||
while ix do | |||
oc += 1 | |||
mask[ix, len(word)] = str(si.highlight, len(word)) | |||
repeat | |||
end | |||
myline = oldmyline[setoff,width] | |||
mask = mask[setoff,width] | |||
showline = '' | |||
old = '' | |||
l = len(myline) | |||
for k = 1 to l | |||
c = mask[k,1] | |||
if c ne old then | |||
begin case | |||
case old eq si.label | |||
showline := hi.labeloff | |||
case old eq si.comment | |||
showline := hi.commentoff | |||
case old eq si.key | |||
showline := hi.keyoff | |||
case old eq si.string | |||
showline := hi.stringoff | |||
case old eq si.key | |||
showline := hi.keyoff | |||
case old eq si.operator | |||
showline := hi.opoff | |||
case old eq si.function | |||
showline := hi.funcoff | |||
case old eq si.directive | |||
showline := hi.diroff | |||
case old eq si.highlight | |||
showline := hi.selectoff | |||
end case | |||
begin case | |||
case c eq si.label | |||
showline := hi.labelon | |||
case c eq si.comment | |||
showline := hi.commenton | |||
case c eq si.key | |||
showline := hi.keyon | |||
case c eq si.string | |||
showline := hi.stringon | |||
case c eq si.operator | |||
showline := hi.opon | |||
case c eq si.function | |||
showline := hi.funcon | |||
case c eq si.directive | |||
showline := hi.diron | |||
case c eq si.highlight | |||
showline := hi.selecton | |||
case c eq si.doc | |||
showline := hi.docon | |||
end case | |||
old = mask[k,1] | |||
end | |||
showline := myline[k,1] | |||
next | |||
begin case | |||
case old eq si.label | |||
showline := hi.labeloff | |||
case old eq si.comment | |||
showline := hi.commentoff | |||
case old eq si.key | |||
showline := hi.keyoff | |||
case old eq si.string | |||
showline := hi.stringoff | |||
case old eq si.function | |||
showline := hi.funcoff | |||
case old eq si.operator | |||
showline := hi.opoff | |||
case old eq si.directive | |||
showline := hi.diroff | |||
case old eq si.highlight | |||
showline := hi.selectoff | |||
case old eq si.doc | |||
showline := hi.docoff | |||
end case | |||
return | |||
</PRE> | |||
Latest revision as of 14:58, 10 October 2024
Back to BasicSource
My version of Unidata's AE that was written to cope with a move to Universe when we were relying on AE's security capabilities. This has a few extra things like an embedded full-page editor and search and change histories. The original source code (version 1.03) was released to public domain by Public Trust of New Zealand as a way of thanking the Pick community for assistance given over the years.
https://sites.google.com/site/nzpickie/home/programs
program led
* This editor reproduces the UniData Alternate Editor for QM/U2
* The code is based on LED, a line editor released into
* the public domain by Public Trust of New Zealand.
* Written by Keith Robert Johnson.
*====================================================================
* Version information
* 2.00 - Simplified code - No longer supporting R83
* Downcased the source to comply with QM standards.
*====================================================================
$define universe
$ifdef qm
$include err.h
voc = @voc
$else
open 'VOC' to voc else stop 201,'VOC'
$endif
$ifdef universe
$options information
$endif
$ifdef unidata
$basictype 'U'
$endif
* INITIALISE
prompt ''
am = char(254); vm = char(253); sm = char(252)
true = 1 = 1; false = not(true); qt = '"\':"'"
common /led$data/ edkeep,secure,kept
equ cellsize to 100
dim memr(1)
* List of verbs for viewing data only
viewverb = 'VIEW':am:'BROWSE':am:'LOOK'
* XCOM data - YES this editor will do $commands like AE does
dim junk(100)
equ this to junk(1)
equ item to junk(2)
equ here to junk(3)
equ x$cc to junk(11)
equ comi to junk(13)
equ comd to junk(14)
equ last to junk(15)
equ comdmark to junk(19)
equ wordmark to junk(20)
equ fnam to junk(24)
equ xsep to junk(25)
mat junk = ''
xsep = ' '
wordmark = ' '
comdmark = '`'
* Local data
begn = @(0) ; ceop = @(-3) ; ceol = @(-4) ; goup = @(-10)
revb = @(-13) ; revf = @(-14) ; undb = @(-15) ; undf = @(-16)
heap = false ; salt = '' ; rlen = 0
plen = system(3)-1 ; pwin = plen-1 ; line = '' ; here = 0
dim fr(10) ; mat fr = '' ; fr(3) = 'MCU'
oops = '' ; oopc = '' ; oopl = '' ; oopf = ''
oopb = '' ; oopk = ''
join = '' ; nill = '' ; fold = ''
macn = 0 ; macc = ''
pick = '' ; lastfind = '' ; huge = 99999999
* Turn off page prompt
test = @(0,0)
* Find Match words - a LOOP can have multiple WHILE and UNTIL conditions
fm.words = '' ; fm.findf = '' ; fm.finda = ''
fm.words<1> = 'END' ; fm.findf<1> = 'END'
fm.finda<1> = 'IF':vm:'END':vm:'OPEN':vm:'OPENSEQ':vm:'BEGIN':vm:'LOCATE'
fm.words<2> = 'LOOP' ; fm.findf<2> = 'REPEAT':vm:'UNTIL':vm:'WHILE'
fm.words<3> = 'UNTIL'; fm.findf<3> = fm.findf<2>
fm.finda<3> = 'LOOP':vm:'UNTIL':vm:'WHILE'
fm.words<4> = 'WHILE'
fm.findf<4> = fm.findf<2>; fm.finda<4> = fm.finda<3>
fm.words<5> = 'FOR' ; fm.findf<5> = 'NEXT'
fm.words<6> = 'NEXT' ; fm.finda<6> = 'FOR'
fm.words<7> = 'BEGIN' ; fm.findf<7> = 'END CASE':vm:'CASE'
fm.words<8> = 'CASE' ; fm.findf<8> = 'CASE':vm:'END CASE'
fm.finda<8> = 'BEGIN CASE':vm:'CASE'
fm.words<9> = 'LOCKED' ; fm.findf<9> = 'END'
fm.finda<9> = 'READU':vm:'READVU':vm:'MATREADU'
fm.words<10> = 'REPEAT' ; fm.finda<10> = fm.finda<3>
* Special for C code
fm.words<11> = '{' ; fm.findf<11> = '}'
fm.words<12> = '}' ; fm.finda<12> = '{'
*
endwords = 'IF\OPEN\OPENSEQ\READNEXT\READ\READU\READV\READVU\'
endwords := 'MATREAD\MATREADU\LOCATE'
convert '\' to am in endwords
* page editor stuff
botl = system(3) - 2; clpg = @(-1)
* bell = char(7) ; span = system(2)
bell = @sys.bell ; span = system(2)
bott = @(0,system(3)-1):ceol
* Define key activity numbers - 22 keys defined
equ uarr to 1, darr to 2, larr to 3, rarr to 4
equ upag to 5, dpag to 6, lpag to 7, rpag to 8
equ tpag to 9, bpag to 10
equ escp to 11, phlp to 12, zoom to 13
equ delc to 14, dell to 15, delr to 16
equ back to 17, carr to 18, togg to 19, writ to 20
equ skey to 21, rkey to 22
* Set up the keys - In QM we can use generic key mapping (YAY)
* but I also like to have default keys
acts = '' ; keys = ''
* Arrow keys
acts<-1> = uarr ; keys<-1> = char(205)
acts<-1> = uarr ; keys<-1> = char(26)
acts<-1> = darr ; keys<-1> = char(206)
acts<-1> = darr ; keys<-1> = char(10)
acts<-1> = larr ; keys<-1> = char(203)
acts<-1> = larr ; keys<-1> = char(21)
acts<-1> = rarr ; keys<-1> = char(204)
acts<-1> = rarr ; keys<-1> = char(6)
* Page movement keys
acts<-1> = upag ; keys<-1> = char(207)
acts<-1> = upag ; keys<-1> = char(16)
acts<-1> = dpag ; keys<-1> = char(208)
acts<-1> = dpag ; keys<-1> = char(14)
acts<-1> = lpag ; keys<-1> = char(209)
acts<-1> = lpag ; keys<-1> = char(1)
acts<-1> = rpag ; keys<-1> = char(210)
acts<-1> = rpag ; keys<-1> = char(5)
acts<-1> = tpag ; keys<-1> = char(214)
acts<-1> = tpag ; keys<-1> = char(20)
acts<-1> = bpag ; keys<-1> = char(215)
acts<-1> = bpag ; keys<-1> = char(2)
* delete character, line, and delete to end of line keys
acts<-1> = delc ; keys<-1> = char(212)
acts<-1> = delc ; keys<-1> = char(4)
acts<-1> = dell ; keys<-1> = char(216)
acts<-1> = dell ; keys<-1> = char(127)
acts<-1> = dell ; keys<-1> = char(24)
acts<-1> = delr ; keys<-1> = char(217)
acts<-1> = delr ; keys<-1> = char(11)
acts<-1> = delr ; keys<-1> = char(18) ;* for Wyse terminals
* backspace and carriage return keys
acts<-1> = back ; keys<-1> = char(008)
acts<-1> = carr ; keys<-1> = char(013)
* escape, help, Go to line, toggle insert/overwrite mode, save keys
acts<-1> = escp ; keys<-1> = char(027)
acts<-1> = escp ; keys<-1> = char(017)
acts<-1> = phlp ; keys<-1> = char(128)
acts<-1> = zoom ; keys<-1> = char(007)
acts<-1> = togg ; keys<-1> = char(211)
acts<-1> = togg ; keys<-1> = char(009)
acts<-1> = writ ; keys<-1> = char(129)
acts<-1> = writ ; keys<-1> = char(023)
* search key, reverse search key
acts<-1> = skey ; keys<-1> = char(130) ;* F3 for search
acts<-1> = rkey ; keys<-1> = char(166) ;* shift-F3 for reverse search
mode = 'LINE'
* The saved stuff
pres = '' ; look = '' ; stak = ''
wild = false ; shew = false
chan = '' ; olda = '' ; cmat = '' ; mmat = ''
caseflag = false ; spaceflag = true ; blockflag = true
* Save the standard defaults in the session variable if it's not set
$ifdef universe
if unassigned(edkeep) then edkeep = '0'
$else
if assigned(edkeep) else edkeep = '0'
$endif
if edkeep eq '0' then
edkeep = pres:am:look:am:stak:am:wild:am:chan:am:olda:am:shew
edkeep := am:cmat:am:mmat:am:not(caseflag):am:not(spaceflag)
edkeep := am:not(blockflag)
kept = ''
end
* Get the 'as-is' settings from the session variable
pres = edkeep<1>
look = edkeep<2>
stak = edkeep<3>
wild = edkeep<4> ; wild = not(not(wild))
chan = edkeep<5>
olda = edkeep<6>
shew = edkeep<7> ; shew = not(not(shew))
cmat = edkeep<8>
mmat = edkeep<9>
caseflag = not(edkeep<10>)
spaceflag = not(edkeep<11>)
blockflag = not(edkeep<12>)
* Get forced default flags
!&&&
! nick = true
!&&&
read temp from voc, '&ED.OPTIONS' then
line = upcase(trim(remove(temp, dlim)))
if line[1,1] eq 'X' then
loop
line = upcase(trim(remove(temp, dlim)))
begin case
case line[1,8] eq 'BLOCK ON'
blockflag = true
case line[1,9] eq 'BLOCK OFF'
blockflag = false
case line[1,7] eq 'CASE ON'
caseflag = true
case line[1,8] eq 'CASE OFF'
caseflag = true
case line[1,8] eq 'SPACE ON'
spaceflag = true
case line[1,9] eq 'SPACE OFF'
spaceflag = true
case line[1,7] eq 'SHOW ON'
shew = true
case line[1,8] eq 'SHOW OFF'
shew = true
end case
while dlim repeat
end
end
$ifdef universe
if unassigned(secure) then secure = '0'
$else
if assigned(secure) else secure = '0'
$endif
prepprog = '' ; prepflag = false
postprog = '' ; postflag = false
*********** UniData AE-style security start
$ifdef unidata
prepprog = getenv('PREPROG_AE_UDT')
$endif
$ifdef universe
execute 'ENV' capturing temp
xxno = dcount(temp,am)
for xx = 1 to xxno
line = temp<xx>
if field(line,'=',1) eq 'PREPROG_AE_UDT' then
prepprog = field(line,'=',2)
xxno = xx
end
next xx
$endif
$ifdef qm
* QM doesn't allow underscores in environmental variables, so
* this is the closest I can get to AE environmental variable name.
call !atvar(prepprog,'@PREPROG.AE.UDT')
$endif
* These next two tests are from the AE security documentation
* They may not be required, but you can set them up if you want
* if prepprog[1,3] eq 'AE_' then prepprog = ''
* if prepprog[len(prepprog)-2,3] ne '_AE' then prepprog = ''
if prepprog ne '' then prepflag = true
* The following security definitions mirror those of I_AE_SECURITY
* in UniData. I have only copied the functionality for SEC.SET
* being "NONE" (that is, this user cannot edit) and the general
* disabling of LOAD via the SEC.LOAD.FLG at first call to @PREPPROG;
* and inhibiting of file updates via subsequent @PREPPROG calls.
dim security(40)
equ sec.set to security(1) ;* set by preprog on very first call
* These fields are set in preprog
equ sec.read.flg to security(2) ;* read ok or not
equ sec.write.flg to security(3) ;* write ok or not
equ sec.delete.flg to security(4) ;* delete ok or not
equ sec.unload.flg to security(5) ;* unload ok or not
equ sec.load.flg to security(6) ;* load ok or not
equ sec.xeq.flg to security(7) ;* xeq ok or not
equ sec.xcom.flg to security(8) ;* xcoms ok or not
* the following 5 fields pass information to preprog & postprog,
equ sec.fn to security(9) ;* file name
equ sec.id to security(10);* record id
equ sec.dir.flg to security(11);* 1 if file is a directory
equ sec.newfile.flg to security(12);* 1 if new file name
equ sec.active.sel.flg to security(13);* 1 if select list is active
* this is how to make AE stop and return to calling program or ecl
equ sec.stop.flg to security(14);* set to 1 to force ae to stop
* for secondary calls to preprog; the first 3 cannot be changed
equ sec.call2.type to security(15);* 1 load, 2 unload
equ sec.fn2 to security(16);* second file - for load/unload
equ sec.id2 to security(17);* second id - for load or unload
equ sec.ok2.flg to security(18);* if 1, ok to load/unload
* 19-22 are used by postprog, which I have not implemented
equ sec.dict.flg to security(23) ;* 1 if fn is dict ...
equ sec.dict2.flg to security(24) ;* 1 if fn2 is dict ...
* field 25 is specific to UNIDATA AE, this and all other fields unused
* WARNING: preprog programs should not use the STOP or ABORT statements
* they should use the SEC.STOP.FLG to end nicely.
*********** UniData AE-style security end
* QM has it's own source control system depending on a callable program
* named SOURCE.CONTROL existing. It has the following fields
*
* DICT.FLAG - 'DICT' if a dictionary, otherwise ''
* FILE.NAME - name of file to be written
* RECORD.NAME - name of record to be written
* RECORD.DATA - the record to write
* CALLER - calling program identifier, I have used '3'
* WRITE.ALLOWED - 1 on call, returns 1 if write allowed and 0 otherwise
* UPDATED - 0 on call, returns 1 if RECORD.DATA is changed
source.control = false
$ifdef qm
if catalogued('SOURCE.CONTROL') then source.control = true
$else
* We can implement QM-style security if we want
if prepprog eq 'SOURCE.CONTROL' then source.control = true
$endif
if source.control then prepflag = false ; prepprog = ''
name = @logname
levl = @level
path = @path
term = @tty
whom = @userno
acct = @who
* This is to display unprintable characters safely
badc = char(255)
for xx = 0 to 31 ; badc := char(xx) ; next xx
for xx = 127 to 250 ; badc := char(xx) ; next xx
gudc = str('~',len(badc))
* eeePC does not distinguish between these
if index(upcase(system(7)),'EEEPC',1) then
badc := char(251):char(252):char(253); gudc := '[\]'
end else
badc := char(251):char(252):char(253)
gudc := char(179):char(178):char(185)
end
* The yes/no can be language independant!
yes = 'Yes' ; yes = upcase(trim(yes))
no = 'No' ; no = upcase(trim(no))
ny = '(':no[1,1]:'/':yes[1,1]:') >'
* Want to see these thing in a single page
presnumb = system(3)-2
if presnumb gt 20 then presnumb = 20
looknumb = presnumb; channumb = presnumb
* Want this to be no more than five pages
staknumb = (presnumb+1)*5+1
* Parse the command line - long way in before work starts, eh?
* Anything in brackets is an option - but we do not use them at all.
* "verb" is how this was called so it should work to call again
verb = ''
$ifdef qm
$include parser.h
call !parser(parser$reset, 0, @sentence, 0)
opts = false
options = ''
sentence = ''
loop
call !parser(parser$get.token, type, param, keyword)
until type eq parser$end do
begin case
case type eq 4 ; opts = true
case type eq 5 ; opts = false
case opts ; options<-1> = param
case 1 ; sentence<-1> = param
end case
repeat
$else
rest = @sentence
keepquot = false
gosub parse.rest
sentence = bite
temp = dcount(sentence,am)
options = sentence<temp>
if options[1,1] eq '(' then
options = field(field(options,'(',2),')',1)
sentence = delete(bite,temp,0,0)
end else options = ''
$endif
if options ne '' then options = ' (':options:')'
* The C option allows the user to build paragraphs
* using DATA statements to control the editor.
* Otherwise they are restricted to an interactive mode.
if index(upcase(options),'C',1)
then editpage = false
else editpage = true
if upcase(sentence<1>) eq 'RUN' then
verb = sentence<1>:' ':sentence<2>:' '
sentence = delete(sentence,1,0,0)
sentence = delete(sentence,1,0,0)
end
verb = verb:sentence<1>
sentence = delete(sentence,1,0,0)
* Check if a viewing verb has been used
* If so, we can turn off both security systems (I mope I'm right!)
* The security flags are set safe, and each command is tested
* individually, so I think it's pretty safe.
* FORMAT is still allowed, but no other change command.
viewflag = false ; view = 'edit'
locate(upcase(verb),viewverb;posn) then
viewflag = true
view = 'view'
source.control = false
prepflag = false
end
* OR, they used the V option
if index(upcase(options),'V',1) then
viewflag = true
view = 'view'
source.control = false
prepflag = false
end
* HELP location
help.def = '2.00'
help = ''
pagehelp = ''
fnam = sentence<1>
sentence = delete(sentence,1,0,0)
if upcase(fnam) eq 'DICT' then
fnam = 'DICT ':sentence<1>
sentence = delete(sentence,1,0,0)
end
idlist = sentence
if system(11) and idlist ne '' then
crt 'A select list was active, but specific ids were entered.'
crt 'Select list will be ignored.'
crt str('-',len('Select list will be ignored.'))
clearselect
end
open 'AE_COMS' to acom else
$ifdef qm
execute 'CREATE.FILE AE_COMS'
$else
execute 'CREATE.FILE AE_COMS 1 7'
$endif
open 'AE_COMS' to acom else stop 'Cannot open ':'AE_COMS'
test = @(0,0)
end
* Get file
loop
got.file = false
if fnam eq '' then
stub = 'File name? '
gosub get.rope; fnam = rope; crt
end
if fnam eq '' then stop
dprt = field(fnam,' ',1)
fprt = field(fnam,' ',2)
if fprt eq '' then fprt = dprt ; dprt = ''
open dprt, fprt to file then
got.file = true
end else
open upcase(dprt),upcase(fprt) to file then
got.file = true
end else
crt 'Cannot open ':'"':fnam:'"'
fnam = ''
end
end
until got.file do
repeat
if fileinfo(file,3) eq '4' then bleach = false else bleach = true
bleach = upcase(fileinfo(file,2))
if bleach[2] = 'BP' or bleach[7] = 'SFPROGS'
then bleach = false
else bleach = true
* Get the record
if idlist eq '*' then
idlist = ''
execute 'SELECT ':dprt:' ':fprt
test = @(0,0)
end
if system(11) then
eof = false
loop
readnext id else eof = true
until eof do
idlist<-1> = id
repeat
end
loop
killsign = false
if idlist eq '' then
stub = 'Record name? '
gosub get.rope; rest = rope ; crt
keepquot = false
gosub parse.rest
idlist = bite
bite = '' ; rest = ''
end
idcnt = dcount(idlist,am)
for id = 1 to idcnt until killsign
item = idlist<id>
gosub edit.item
next id
while killsign do
idlist = ''
repeat
edkeep = pres:am:look:am:stak:am:wild:am:chan:am:olda:am:shew
edkeep := am:cmat:am:mmat:am:not(caseflag):am:not(spaceflag)
edkeep := am:not(blockflag):am:lower(kept)
stop
* SUBROUTINES
* ***********
edit.item:
stopsign = false
here = 0 ; dnum = 0
beg = 0 ; fin = 0 ; krj = ''
crt
if idcnt gt 1 then crt '<':id:'/':idcnt:'> ':
if prepflag then
if secure eq '0' then
mat security = ''
sec.set = ''
call @prepprog(mat security)
if sec.set eq 'NONE' then stop
if sec.stop.flg then stop
secure = sec.set
end
mat security = ''
sec.set = secure
if sec.set then
sec.fn = fprt
sec.id = item
sec.dir.flg = fileinfo(file,3) = '4'
sec.newfile.flg = false
sec.active.sel.flg = false
sec.dict.flg = (dprt = 'DICT')
call @prepprog(mat security)
if sec.stop.flg then stop
if not(sec.read.flg) then return
end
end else
sec.stop.flg = false
sec.read.flg = true
sec.write.flg = true
sec.delete.flg = true
sec.xcom.flg = true
sec.unload.flg = true
sec.load.flg = true
sec.xeq.flg = true
sec.ok2.flg = true
* Apply the viewing flag
if viewflag then
crt 'VIEW ONLY - NO UPDATES ALLOWED'
sec.write.flg = false
sec.delete.flg = false
sec.xcom.flg = false
sec.unload.flg = false
sec.load.flg = false
sec.xeq.flg = false
sec.ok2.flg = false
end
end
readu this from file, item locked goto locked.record then
lock = true
carry.on:
gosub parse.record
crt 'Top of "':item:'" in "':fnam:'", ':last:' lines, ':len(this):' characters.'
end else
lock = true
this = ''
gosub parse.record
crt 'Top of new "':item:'" in "':fnam:'".'
end
orig = this
gosub get.lfmt
* Edit the record
loop
if mode<1> eq 'PAGE' then
pcol = rem(pchr-1,span)
prow = here+1-ptop
crt @(60,0):ceol:revb:mode<2>:revf:' ':fmt(here,'R#4'):
crt ',':fmt(pchr,'L#4'):
bite = temp[pchr,1]
if bite ne '' then crt ' (':seq(bite):')':
crt @(pcol,prow):
gosub get.page.comd
if mode eq 'LINE' then
crt bott:'Line Editor Mode':
if that ne this then
crt ' - CHANGES HAVE BEEN MADE':
oops = that ; oopc = 'PE'
oopl = savl<1> ; oopf = savl<2>
oopb = beg:am:fin ; oopk = krj
end
crt
that = ''
gosub display.line
end
end
if mode<1> eq 'LINE' then
* Get the command
if x$cc ne '' then
comi = x$cc<1>
x$cc = delete(x$cc,1,0,0)
end else
if mode<1> eq 'PAGE' then continue
if salt ne '' then
comi = salt<1,1,1>; del salt<1,1,1>
end else
stub = prmt:': '; heap = true
gosub get.rope; comi = rope; heap = false
end
if macn then macc<1,1,-1> = comi
end
gosub parse.command
if not(numb eq '' or numb matches '1N0N') then
crt ; gosub bad.command
continue
end
if comd eq '' then
gosub null.command
if comd eq '' then continue
end
* Save command to list
if comi ne '' and comi ne stak<1,1> and comd ne 'D' then
stak = insert(stak,1,1,0,comi)
stak = delete(stak,1,staknumb,0)
end
* Apply the command
if comd ne 'R' then crt
if comd matches '1N0N' then
here = comd
if here gt last then here = last
gosub display.line
continue
end
loop
redo = false
first = comd[1,1]
posn = index('ABCDEFGHIJKLMNOPQRSTUVWXYZ',first,1)
on posn gosub a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
while redo do repeat
if stopsign then release file, item ; lock = false ; return
end
repeat
return
parse.command:
comi = trimf(comi)
dlim = oconv(oconv(comi,'MC/A'),'MC/N')[1,1]
if dlim eq '' then
rest = ''
comd = upcase(comi)
end else
posn = index(comi,dlim,1)
rest = comi[posn+1,huge]
comd = upcase(comi[1,posn-1])
end
temp = oconv(comd,'MCN')[1,1]
if temp ne '' then
temp = index(comd,temp,1)
numb = comd[temp,huge]
comd = comd[1,temp-1]
end else numb = ''
return
parse.line:
if line eq comdmark then line = ''
xx = 1
loop
temp = index(line,'^',xx)
while temp do
bite = line[temp,5]
if bite matches '"^^"3N' then
line = line[1,temp-1]:line[temp+1,len(line)]
xx += 1
end else
bite = bite[1,4]
if bite matches '"^"3N' then
line= line[1,temp-1]:char(bite[2,3]):line[temp+4,len(line)]
end else xx += 1
end
repeat
return
a: begin case
case comd eq 'A' ; * append
if viewflag then gosub viewonly ; return
if rest eq '' then rest = olda<1,1>
if rest eq '' then
crt 'No previous append command to repeat'
gosub bad.comd
return
end
olda = rest:vm:dlim
line = rest ; gosub parse.line ; rest = line
chng = 0 ; save = here ; savl = last
dnum = 1
gosub set.bounds
for here = dawn to dusk
gosub get.line
line = line:rest
if not(chng) then gosub savethis
memr(cell)<lnum> = line
chng += 1
if shew or dnum lt plen then gosub display.line
next here
here = dusk
if chng then
gosub reset.record
crt chng:' lines changed - now at ':here
end
case 1 ; gosub bad.command
end case
return
b: begin case
case comd eq 'B' and dlim eq '' ; * bottom
here = last ; gosub display.line
case index('\B\BD\BK\BR\BS\','\':comd:'\',1) ; * break line
if viewflag then gosub viewonly ; return
if rest eq '' then
crt 'The second field is empty.'
gosub bad.comd
return
end
chng = 0 ; save = here ; savl = last ; show = ''
gosub set.bounds
for here = dusk to dawn step -1
gosub get.line
posn = index(line,rest,1)
if posn then
left = line[1,posn-1]
temp = line[posn+len(rest),len(line)]
if temp ne '' or comd eq 'BS' then
begin case
case comd eq 'BD' ; line = left:rest
case comd eq 'BK' ; line = temp
case comd eq 'BR' ; line = temp:left:rest
case comd eq 'BS' ; line = temp:rest:left
case 1 ; line = left:rest
end case
memr(cell)<lnum> = line
show = insert(show,1,0,0,here)
numb += 1
chng += 1
if comd eq 'B' then
dusk += 1
last += 1
lnum += 1
line = temp
gosub insert.line
end
end
end
next here
if chng then
gosub savethis
gosub reset.record
zzno = dcount(show,am)
savl = 0 ; dnum = 1
for zz = 1 to zzno
here = show<zz> + savl
if shew or dnum lt plen then gosub display.line
if comd eq 'B' and zzno gt 1 then
here += 1
savl += 1
if shew or dnum lt plen then gosub display.line
end
next zz
show = ''
end
if comd eq 'B'
then here = dusk + numb - 2
else here = dusk
if here gt last then here = last
if chng then
crt 'Split ':numb:' records. Now at line ':here
end
gosub get.line
case index('\BC\BCD\BCK\BCR\BCS\','\':comd:'\',1) ; * Break @ Column
if viewflag then gosub viewonly ; return
posn = trim(field(rest,dlim,1))
if not(posn matches '1n0n') then
crt 'No column position given'
gosub bad.comd
return
end
chng = 0 ; save = here ; show = ''
gosub set.bounds
for here = dusk to dawn step -1
gosub get.line
if len(line) gt posn then
left = line[1,posn-1]
temp = line[posn+1,len(line)]
if temp ne '' or comd eq 'BCS' then
begin case
case comd eq 'BCD' ; line = left:rest
case comd eq 'BCK' ; line = temp
case comd eq 'BCR' ; line = temp:left:rest
case comd eq 'BCS' ; line = temp:rest:left
case 1 ; line = left:rest
end case
memr(cell)<lnum> = line
show = insert(show,1,0,0,here)
numb += 1
chng += 1
if comd eq 'BC' then
dusk += 1
last += 1
lnum += 1
line = temp
gosub insert.line
end
end
end
next here
if chng then
gosub savethis
gosub reset.record
zzno = dcount(show,am)
savl = 0 ; dnum = 1
for zz = 1 to zzno
here = show<zz> + savl
if shew or dnum lt plen then gosub display.line
if comd eq 'BC' and zzno gt 1 then
here += 1
savl += 1
if shew or dnum lt plen then gosub display.line
end
next zz
show = ''
end
if comd eq 'BC'
then here = dusk + numb - 2
else here = dusk
if here gt last then here = last
if chng then
crt 'Split ':numb:' records. Now at line ':here
end
gosub get.line
case comd eq 'BLEACH' ; * change BLEACH flag
rest = upcase(rest)
begin case
case rest eq 'ON' ; bleach = true
case rest eq 'OFF' ; bleach = false
case 1 ; bleach = not(bleach)
end case
if bleach
then crt 'Colours disabled'
else crt 'Colours enabled'
case comd eq 'BLOCK' ; * change BLOCK flag
rest = upcase(rest)
begin case
case rest eq 'ON' ; blockflag = true
case rest eq 'OFF' ; blockflag = false
case 1 ; blockflag = not(blockflag)
end case
if blockflag then
crt 'Verification of block actions enabled'
end else crt 'Verification of block actions disabled'
case 1 ; gosub bad.command
end case
return
c: begin case
case comd eq 'C' ; * change
if viewflag then gosub viewonly ; return
if numb eq '' and dlim eq '' then
comd = 'RA'
comi = 'RA1'
numb = 1
end
gosub change.command
case comd eq 'CAT' ; comd = 'J' ; redo = true
case comd eq 'CASE' ; * change casing flag for 'L'
rest = upcase(rest)
begin case
case rest eq 'ON' ; caseflag = true
case rest eq 'OFF' ; caseflag = false
case 1 ; caseflag = not(caseflag)
end case
if caseflag then
crt 'Searches are case-sensitive'
end else crt 'Searches are not case-sensitive'
case comd eq 'CD' ; * command delimiter display (change)
if dlim eq '' then
crt 'Command delimiter is ':
end else
temp = '`,;#$%&~|[]{}/"':"'"
if index(temp,dlim,1) then
comdmark = dlim
crt 'Command delimiter is ':
end else
crt dlim:' is not a valid command delimiter.'
crt 'Characters available for delimiters: ':temp
crt 'Characters reserved for other uses: \.*!?-+=^@<>_:'
crt 'Command delimiter is ':
end
end
if comdmark eq '"'
then crt "'":comdmark:"'"
else crt '"':comdmark:'"'
case comd eq 'CLEAR' ; * Clear the kept buffer
if kept eq ''
then crt 'Nothing in KEPT buffer'
else crt 'KEPT buffer cleared'
kept = ''
case comd = 'COPY' ; * copy to kept buffer
if comd eq upcase(comi) then
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd; return
end
rest = beg
numb = fin-beg+1
end
rest = trim(rest)
if numb eq '' then gosub parse.atts
if rest eq '' then rest = here
if not(rest matches '1N0N') or numb eq '' then
crt 'Formats are: "COPY" (from <> block) or "COPYn" or "COPYn/s" or "COPY/s/f".'
gosub bad.comd ; return
end
if numb lt 1 then
crt 'Nothing done - no lines selected.'
comi = ''; return
end
if numb gt last then
crt 'Nothing done - record does not have that many lines.'
comi = '' ; return
end
kept = field(this,am,rest,numb)
numb = dcount(kept,am)
if numb then crt numb:' lines copied to KEPT buffer starting at line ':rest
case comd eq 'CM' ; * changematch command
if viewflag then gosub viewonly ; return
if rest eq '' then
if cmat eq '' then
crt 'No previous ChangeMatch command to repeat.'
comi = ''
return
end else
dlim = cmat<1,1>
rest = cmat<1,2>
numb = cmat<1,3>
end
end
gosub changematch.command
case comd eq 'COL' ; * column display
temp = ''
for xx = 1 to 9
temp = temp:space(9):xx
next xx
if lfmt
then crt begn:space(llen+2):temp[1,span-llen-2]
else crt begn:temp[1,span]
temp = str('1234567890',10)
if lfmt
then crt begn:space(llen+2):temp[1,span-llen-2]
else crt begn:temp[1,span]
temp = ''
case comd eq 'COUNT' ; * show the count of a string
line = rest ; gosub parse.line ; rest = line
if rest eq '' then
crt 'No string given to count'
gosub bad.comd ; return
end
gosub set.bounds
if not(caseflag) then rest = upcase(rest)
temp = 0
for here = dawn to dusk
gosub get.line
if caseflag
then temp = temp + count(line,rest)
else temp = temp + count(upcase(line),rest)
next here
here = dusk
crt temp:' occurances of string.'
case comd eq 'CRT' ; * insert crt line for programmer
if viewflag then gosub viewonly ; return
if rest eq '' then
crt 'You have not said what to put on CRT line!'
comi = ''
return
end
gosub savethat
here += 1 ; last += 1 ; lnum += 1
if dlim ne '"' and dlim ne '\' then dlim = "'"
line = 'CRT ':dlim:rest:' = ':dlim:':':rest
gosub insert.line
gosub reset.record
gosub display.line
case comd eq 'CUT' ;* Move lines to kept buffer
if viewflag then gosub viewonly ; return
if comd eq upcase(comi) then
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd; return
end
rest = beg
numb = fin-beg+1
end
rest = trim(rest)
if numb eq '' then gosub parse.atts
if rest eq '' then rest = here
if not(rest matches '1N0N') or numb eq '' then
crt 'Formats are: "CUT" (from <> block) or "CUTn" or "CUTn/s" or "CUT/s/f".'
gosub bad.comd; return
end
if numb gt last then
crt 'Nothing done - record does not have that many lines.'
comi = '' ; return
end
kept = field(this,am,rest,numb)
numb = dcount(kept,am)
dawn = rest
dusk = rest+numb-1
gosub delete.lines
if numb then crt numb:' lines moved to KEPT buffer starting at line ':rest
case 1 ; gosub bad.command
end case
return
d: begin case
case comd eq 'D' ; * display current line
if here gt last then here = last
gosub display.line
case comd eq 'DE' ; * delete lines
if viewflag then gosub viewonly ; return
chng = 0 ; save = here ; savl = last
if rest ne '' then
patt = rest
cto = ''
cfrom = 'DE'
gosub cm.del.entry
return
end
gosub set.bounds
gosub delete.lines
here = dawn
if here gt last then
here = last
crt 'Bottom. Line ':here:' was above the last delete.'
end else
crt 'At line ':here:'. Deleted ':chng:' lines.'
gosub display.line
end
$ifdef qm
case comd eq 'DISPLAY' ; * insert display line for programmer
if viewflag then gosub viewonly ; return
if rest eq '' then
crt 'You have not said what to put on DISPLAY line!'
comi = ''
return
end
gosub savethat
here += 1 ; last += 1 ; lnum += 1
if dlim ne '"' and dlim ne '\' then dlim = "'"
line = 'DISPLAY ':dlim:rest:' = ':dlim:':':rest
gosub insert.line
gosub reset.record
gosub display.line
$endif
case comd eq 'DROP' ; * remove the block
if viewflag then gosub viewonly ; return
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd ; return
end
if beg le 1 then
temp = 0
end else
temp = index(this,am,beg-1)
if not(temp) then
crt 'Error - Block start line not defined' ; *Cannot find beginning of block
gosub bad.comd ; return
end
end
if fin eq last then
temp -= 1
temp<2> = len(this)
end else
temp<2> = index(this,am,fin)
end
if not(temp<2>) then
crt 'Error - Block end line not defined' ; *Cannot find end of block
gosub bad.comd ; return
end
numb = fin - beg + 1
if blockflag then
if beg eq fin
then stub = 'Delete line ': beg:' '
else stub = 'Delete block from line ': beg:' to line ': fin:'? '
gosub get.answ
if answ ne yes[1,1] then
crt 'Block command cancelled.'
return
end
end
dawn = beg; dusk = fin
gosub delete.lines
crt 'Dropped (deleted) ':numb:' lines.'
gosub display.line
case comd eq 'DTX' ; * decimal to hex
if not(rest matches '1N0N') then
crt 'Numeric value required'
gosub bad.comd ; return
end
if len(rest) gt 9 then
crt 'Must be less than one billion (1,000,000,000)'
gosub bad.comd ; return
end
$ifdef universe
crt dtx(rest)
$else
crt oconv(rest,'MX')
$endif
case comd eq 'DUP' ; * duplicate previous line
if viewflag then gosub viewonly ; return
if here lt 1 then
crt 'No current line'
gosub bad.comd ; return
end
if numb eq '' and rest matches '1N0N' then numb = rest
if numb lt 1 then numb = 1
gosub savethat
gosub get.line
for xx = 1 to numb
gosub insert.line
last += 1
next xx
gosub reset.record
crt 'Inserted ':numb:' copies of line ':here:' after line ':here:'. Still at ':here:'.'
case 1 ; gosub bad.command
end case
return
e: begin case
case comd eq 'EC' ; * edit called program (in this file)
if here lt 1 then here = 1
gosub get.line
line = trim(line)
temp = upcase(line)
good = index(temp,'CALL ',1)
if good then line = trim(line[good+5,huge])
line = trim(field(line,'(',1))
if index(line,' ',1) then good = false
if line[1,1] eq '@' then
crt 'Leading "@" is logical pointer'
good = false
end
if not(good) then
crt 'The EC command requires lines in format "CALL ID" or "CALL ID(..."'
gosub bad.comd ; return
end
* readv temp from file, line, 1 else
* crt '"':line:'" is not in this file'
* gosub bad.comd ; return
* end
* execute verb:' ':fnam:' ':line
readv temp from file, line, 1 then
execute verb:' ':fnam:' ':line:options
end else
test = false
readv vlin from voc, line, 2 then
vcnt = dcount(vlin,'/')
vlin = field(vlin,'/',vcnt-1)
vlin = vlin[1,len(vlin)-2]
test = trans(vlin,line,-1,'X')
end
if test then
execute verb:' ':vlin:' ':line:options
end else
crt '"':line:'" is not in this file'
gosub bad.comd ; return
end
end
***
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
case comd = 'ECS' ; * edit command stack
ttid = whom:'_':levl:'_commands'
temp = raise(stak)
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing command stack'
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read temp from acom, ttid else temp = ''
temp = field(temp,am,1,staknumb-1)
stak = lower(temp)
delete acom, ttid
case comd eq 'EDITPAGE'
editpage = not(editpage)
*>
if editpage then
begn = @(0) ; goup = @(-10)
prmt = '*':str('-',llen-1)
end else
begn = char(13) ; goup = ''
prmt = str('-',llen)
end
crt 'editpage = ':editpage
*>
case comd eq 'EF' ; * edit fields
numb = numb + 0
if numb lt 0 or numb gt 255 then
crt numb:' is outside range 0-255'
comi = ''
return
end
vmrk = char(numb)
vals = 'char':numb
gosub edit.fields
vmrk = char(numb); gosub reset.fields
case comd eq 'EI' ; * edit included code
if here lt 1 then here = 1
gosub get.line
line = field(line,';',1)
line = trim(line)
good = true
temp = field(line,' ',1)
temp = upcase(temp)
if temp ne 'INCLUDE' and temp ne '$INCLUDE' then good = false
line = trim(line[len(temp)+1,len(line)])
begin case
case dcount(line,' ') gt 3 ; good = false
case dcount(line,' ') eq 3
if field(line,' ',1) ne 'DICT' then good = false
case dcount(line,' ') eq 1
readv test from file, line, 1 then
line = fnam:' ':line
end else
test = trans('SYSCOM',line,1,'X')
if test ne ''
then line = 'SYSCOM ':line
else line = fnam:' ':line
end
end case
if not(good) then
crt 'The EI command requires lines in format "$IN... {DICT} {FN} ID"'
gosub bad.comd ; return
end
execute verb:' ':line:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
case comd eq 'EIT' ; * edit i-types (@)
if dprt and here eq 2 and upcase(this[1,1]) else
crt 'EIT is only for line 2 of a dictionary I-type'
return
end
gosub get.line ; temp = line
gosub split.itype
ttid = whom:'_':levl:'_IType.in.line#':here
write bite on acom, ttid on error gosub writerr ; return
crt view:'ing IType as fields...':
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read line from acom, ttid else line = ''
delete acom, ttid
vmrk = ';'; gosub reset.fields
* case comd eq 'EM' ; * edit MESSAGES
* if numb eq '' and rest matches '1N0N' then numb = rest
* if numb then
* execute verb:' MESSAGES ':numb:options
* end else
* if here lt 1 then here = 1
* gosub get.line
* line = trim(line)
* temp = upcase(line)
* good = index(temp,'SYSMSG',1)
* if good then line = trim(line[good+6,huge])
* line = trim(field(line,'(',2))
* line = trim(field(field(line,')',1),',',1))
* if not(line matches '1N0N') then good = false
* if not(good) then
* crt 'The EM command requires lines in format "...sysmsg(1N0N..."'
* crt 'Or a command like EMnnnn (nnnn is a message number)'
* gosub bad.comd ; return
* end
* execute verb:' MESSAGES ':line:options
* end
* test = @(0,0)
* crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
case comd = 'EK' ; * edit kept buffer
ttid = whom:'_':levl:'_keptbuffer'
write kept on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing kept buffer':
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read kept from acom, ttid else kept = ''
delete acom, ttid
case comd = 'EPR' ; * edit prestores
numb = numb + 0
if numb lt 0 or numb gt presnumb then
crt 'PRestore must be in range 1-':presnumb:'.'
gosub bad.comd ; return
end
ttid = whom:'_':levl:'_prestores'
temp = raise(pres)
if numb then
bite = raise(temp<numb>)
write bite on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing prestore ':view:
end else
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing prestores':
end
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
if numb then
read bite from acom, ttid else bite = ''
temp<numb> = lower(bite)
end else
read temp from acom, ttid else temp = ''
end
pres = lower(temp)
delete acom, ttid
case comd = 'ESS' ; * edit search stack
ttid = whom:'_':levl:'_searches'
temp = raise(look)
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing search stack':
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read temp from acom, ttid else look = ''
look = lower(temp)
delete acom, ttid
case comd eq 'ESV' ; * edit subvalues
vmrk = sm ; vals = 'subvalues'
gosub edit.fields
vmrk = sm; gosub reset.fields
case comd eq 'ET' ; * edit tabs
ttid = whom:'_':levl:'_tabs'
xxno = dcount(krj<1>,@vm)
temp = ''
for xx = 1 to xxno
temp<xx> = krj<2,xx>:' ':krj<1,xx>
next xx
write temp on acom, ttid on error crt 'WRITE failure - file not updated' ; return
crt view:'ing line tabs':
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read temp from acom, ttid else temp = ''
xxno = dcount(temp,@am)
krj = @am:@am:krj<3>
yy = ''
for xx = 1 to xxno
bite = trim(temp<xx,1,1>)
left = field(bite,' ',1)
rest = field(bite,' ',2,99)
if left matches '1N0N' then left += 0 else left = 0
if left gt last then left = 0
if left then
yy += 1
if rest eq '' then rest = 'T':left
krj<1,yy> = rest
krj<2,yy> = left
end
next xxno
if krj<3> gt yy then krj<3> = yy
if krj<1> ne '' and krj<3> lt 1 then krj<3> = 1
delete acom, ttid
case comd eq 'EV' ; * edit values
vmrk = vm ; vals = 'values'
gosub edit.fields
vmrk = vm; gosub reset.fields
case comd eq 'EW' ; * edit words (as defined by wordmark)
vmrk = wordmark ; vals = 'words'
gosub edit.fields
vmrk = wordmark; gosub reset.fields
* Various forms for quitting
case comd eq 'EX' or comd = 'EXIT' ; comd = 'Q' ; redo = true
case comd eq 'EXK' or comd = 'EXITK' ; comd = 'QK' ; redo = true
case 1 ; gosub bad.command
end case
return
f: begin case
case comd eq 'FD' ; * delete item
if viewflag then gosub viewonly ; return
if not(sec.delete.flg) then
crt 'Delete disabled'
comi = ''
return
end
gosub write.record
case comd eq 'FILE' ; comd = 'SV' ; redo = true
case comd[1,2] eq 'FI' ; * file item
if viewflag then gosub viewonly ; return
if not(sec.write.flg) then
crt 'File disabled'
comi = ''
return
end
temp = comd[3,len(comd)]
convert 'BCRDL' to '' in temp
if temp eq '' then gosub write.record else gosub bad.command
case comd eq 'FL' or comd eq 'FLA' ; * find labels
if not(caseflag) then rest = upcase(rest)
if index(comd,'A',1) then
bump = -1
dawn = here - 1
if dawn lt 1 then return
if numb then dusk = here - numb else dusk = 1
if dusk lt 1 then dusk = 1
end else
bump = 1
dawn = here + 1
if dawn gt last then dawn = 1
if numb then dusk = dawn + numb else dusk = last
if dusk gt last then dusk = last
end
for here = dawn to dusk step bump
gosub get.line
gosub find.label
if not(caseflag) then temp = upcase(temp)
if temp ne '' then
if rest eq '' or temp matches rest then
gosub display.line
if not(numb) then return
end
end
next here
crt
gosub display.line
case comd eq 'FM' or comd eq 'FMA' ; * find match command
gosub get.line
* Get rid of any label
gosub find.label
thisline = trimf(line)
if temp ne '' then
thisline = thisline[len(temp)+1,huge]
if thisline[1,1] eq ':' then thisline = thisline[2,huge]
thisline = trimf(thisline)
end
* Get the first word on the line
word = field(trim(upcase(thisline)),' ',1)
begin case
case rest ne ''
seek = upcase(rest)
case word[1,1] eq '*' or word[1,1] eq '!'
seek = word[1,1]
case 1
locate(word,fm.words;posn) then
if index(comd,'A' ,1) then
seek = fm.finda<posn>
end else
seek = fm.findf<posn>
end
end else
locate(word,endwords;posn) then
seek = 'END'
end else
crt 'Starting word "':word:'" unknown'
gosub bad.comd ; return
end
end
end case
if seek eq '' then
crt word:' has no matching word for ':comd
gosub bad.comd ; return
end
posn = index(upcase(line),word,1)
xxno = dcount(seek,vm)
for xx = 1 to xxno
seek<1,xx> = space(posn-1):seek<1,xx>
next xx
if index(comd,'A',1) then
bump = -1
dawn = here - 1
if dawn lt 1 then return
dusk = 1
end else
bump = 1
dawn = here + 1
if dawn gt last then return
dusk = last
end
save = here
for here = dawn to dusk step bump
gosub get.line
line = upcase(line)
if line[1,1] ne '' then
temp = field(line,' ',1)
if num(temp) or temp[len(temp),1] eq ':' then
temp = len(temp)
line = space(temp):line[temp+1,len(line)]
end
end
for xx = 1 to xxno
slen = len(seek<1,xx>)
if line[1,slen] eq seek<1,xx> then
if trim(line[slen+1,1]) eq '' then
gosub display.line
return
end
end
next xx
next here
here = save
gosub get.line
case comd eq 'FOLD' ; * fold the line
if viewflag then gosub viewonly ; return
chng = 0 ; save = here ; savl = last
if dlim ne '' then fold = ''
if rest eq '' then rest = fold
if rest eq '' then rest = span-llen-2
if not(rest matches '1N0N') then
crt 'Non-numeric length - try HELP FOLD.'
comi = ''
return
end
fold = rest
gosub get.line
crt 'FOLD line to length ':fold
bite = line
gosub parse.bite
gosub check.line
if chng then gosub reset.record
case comd eq 'FOR' or comd eq 'FORMAT' ; * format this item
rest = upcase(rest)
temp = index(rest,'-M',1)
if temp then fr(1) = field(rest[temp+2,huge],' ',1) ; fr(2) = ''
if not(fr(1) matches '1N0N') then fr(1) = ''
if fr(1) eq '' then
temp = this<1>
fr(1) = len(temp) - len(trimf(temp))
end
temp = index(rest,'-I',1)
if temp then fr(2) = field(rest[temp+2,huge],' ',1)
if not(fr(2) matches '1N0N') then fr(2) = ''
if fr(2) eq '' then
fr(2) = int((fr(1)+1)/2)
if fr(2) lt 2 then fr(2) = 2
end
if index(rest,'-A',1) then fr(9) = true else fr(9) = ''
if index(rest,'-N',1) then fr(10) = true else fr(10) = ''
if index(rest,'-C',1) then
fr(1) = 0
fr(2) = 1
fr(9) = true
fr(10) = true
end
if last lt 1 then return
gosub savethat
crt 'Margin=':fr(1):', Indentation=':fr(2)
gosub indenter
gosub set.record
case 1 ; gosub bad.command
end case
return
g: begin case
case comd eq 'G' ; * Go to line
if numb eq '' then
if dlim eq '<' and beg ne '' then here = beg
if dlim eq '>' and fin ne '' then here = fin
end else here = numb
if here gt last then here = last
gosub display.line
case 1 ; gosub bad.command
end case
return
h: begin case
case comd eq 'H' or comd eq 'HELP'
gosub show.help
case comd eq 'HEX' ; * show this line in hexadecimal
if not(here) then return
gosub get.line
temp = ''
xxno = len(line)
for xx = 1 to xxno
bit = line[xx,1]
$ifdef universe
bit = dtx(seq(bit))
$else
bit = oconv(seq(bit),'MX')
$endif
$ifdef unidata
bit = fmt(bit,'2/0R')
$else
bit = fmt(bit,'R%2')
$endif
temp<1> = temp<1>:bit[1,1]
temp<2> = temp<2>:bit[2,1]
next xx
if lfmt then crt fmt(here,lfmt):': ':
crt temp<1>
if lfmt then crt space(llen+2):
crt temp<2>
temp = ''
case 1 ; gosub bad.command
end case
return
i: begin case
case comd eq 'I' ; * insert lines
if viewflag then gosub viewonly ; return
chng = 0 ; save = here ; savl = last
if rest ne '' then
if numb lt 1 then numb = 1
inum = numb
gosub get.line
if not(chng) then gosub savethis
if here gt 0 then
memr(cell)<lnum> := str(am:rest,inum)
end else memr(1)<1> = str(rest:am,inum):memr(1)<1>
if here le beg then beg += inum
if here le fin then fin += inum
yyno = dcount(krj<1>,vm)
for yy = 1 to yyno
if krj<2,yy> gt here then krj<2,yy> += inum
next yy
here = here + inum
gosub reset.record
gosub get.line
gosub display.line
crt 'At line ':here:'. ':inum:' lines inserted, bottom now at line ':last:'.'
end else
if nill ne '' then
crt 'Terminate input with "':nill:'"'
end
!&&&
! if nick then gosub get.line
!&&&
loop
!&&&
! if nick
! then pill = space(len(line)-len(trimf(line)))
! else pill = ''
! pick = pill
! pill := nill
!&&&
new1 = here + 1
stub = new1:'='
if lfmt then stub = fmt(new1,lfmt):'='
gosub get.rope; line = rope
!&&&
until line eq nill do
! until line eq nill or line eq pill do
!&&&
gosub parse.line
last += 1
here += 1
lnum += 1
if not(chng) then gosub savethis
chng += 1
gosub insert.line
temp = len(last)
if lfmt then
if temp gt 3 and temp ne llen then gosub get.lfmt
end
if line eq nill then
crt begn:
if lfmt then crt fmt(new1,lfmt):'= ':
end
crt
numb -= 1
if numb eq 0 then exit
repeat
crt begn:ceol:
end
if chng then gosub reset.record
case comd eq 'IC' ; * iconv
if viewflag then gosub viewonly ; return
if rest eq '' then
crt 'No conversion given'
gosub bad.comd ; return
end
ccom = '*':rest ; gosub conv.command
case comd eq 'IN' ; * insert from execute
if viewflag then gosub viewonly ; return
if trim(rest) eq '' then
crt 'No external command given'
comi = '' ; return
end
execute rest capturing bite
test = @(0,0)
numb = dcount(bite,am)
if numb then
gosub savethat
this = insert(this,here+1,0,0,bite)
gosub set.record
crt 'Inserted ':numb:' lines; still at line ':here:'.'
end else
crt 'Nothing done - no output from command.'
comi = '' ; return
end
case 1 ; gosub bad.command
end case
return
j: begin case
case comd eq 'J' ; * join lines
if viewflag then gosub viewonly ; return
if dlim ne '' then
line = rest ; gosub parse.line ; join = line
end
if here and here lt last then
chng = 0 ; save = here ; savl = last
gosub get.line
test = line
here += 1
gosub set.bounds
for here = dawn to dusk
gosub get.line
test = test:join:line
next here
gosub delete.lines
if chng eq 0 then return
here = save
oopl = here
gosub get.line
memr(cell)<lnum> = test
gosub reset.record
end
gosub display.line
case 1 ; gosub bad.command
end case
return
k: begin case
case comd eq 'KEEP' or comd eq 'KEEPA'
gosub get.load
if temp eq '' then return
if comd[len(comd),1] ne 'A' then
gosub get.lines
if not(temp) then return
end
kept = temp
temp = dcount(temp,am)
crt 'At line ':here:', ':temp:' lines loaded into kept buffer.'
temp = ''
case comd eq 'KEPT' or comd eq 'K' ; * display kept
xxno = dcount(kept,am)
if xxno lt 1 then
crt 'Nothing in KEPT buffer'
return
end
bit = len(xxno)
disp = '***** Contents of KEPT buffer (':xxno:' lines) *****'
stub = 'Press return to continue showing KEPT buffer, Q to quit'
for xx = 1 to xxno
temp = oconv(kept<xx>,'MCP')[1,wide-bit-1]
disp<-1> = fmt(xx,'R#':bit):':':temp
next xx
gosub show.disp
case 1 ; gosub bad.command
end case
return
l: begin case
case index('\L\LN\LA\LNA\LAN\','\':comd:'\',1) ; * list or locate
if upcase(comi) eq 'L' then
if look<1,1> eq '' then
crt 'No previous locate command to repeat.'
comi = ''
return
end
comi = look<1,1>
gosub parse.command
if comd eq '' then comd = 'L' ; numb = huge
redo = true
return
end
finder = ''
seeker = dlim
if seeker eq '!' or seeker eq '&' then
finder = rest
convert dlim to am in finder
if finder<2> eq '' then finder = '' else rest = finder<1>
end
looper = dcount(finder,am)
if rest ne '' then
gosub parse.cols
if not(good) then return
end else
if dlim ne '' then
crt 'The second field is empty.'
gosub bad.comd ; return
end
cols = ''
end
if index(comd,'A',1) then
bump = -1
dawn = here - 1
if dawn lt 1 then dawn = 1
if numb then dusk = here - numb + 1 else dusk = 1
if dusk lt 1 then dusk = 1
end else
bump = 1
dawn = here + 1
if dawn gt last then dawn = 1
if numb then dusk = dawn + numb - 1 else dusk = last
if dusk gt last then dusk = last
end
if looper then rest = finder else looper = 1
line = rest ; gosub parse.line ; rest = line
lastfind = rest<1>
if not(caseflag) then rest = upcase(rest)
if spaceflag else convert ' ':char(9) to '' in rest
for here = dawn to dusk step bump
gosub get.line
if cols then line = line[cols,colf]
if caseflag then temp = line else temp = upcase(line)
if spaceflag else convert ' ':char(9) to '' in temp
badder = false ; gooder = false
for xx = 1 to looper
if index(temp,rest<xx>,1)
then gooder = true
else badder = true
next xx
if seeker eq '&' then gooder = not(badder)
if gooder then
if not(index(comd,'N',1)) then
gosub display.line
if not(numb) then exit
end
end else
if index(comd,'N',1) then
gosub display.line
if not(numb) then exit
end
end
next here
if numb then here = dusk
crt 'Now at line ':here:
if here eq last then crt ' (bottom)':
crt '.'
if rest ne '' and comi ne '' and comi ne look<1,1> then
look = insert(look,1,1,0,comi)
look = field(look,vm,1,looknumb)
end
case comd eq 'LC' ; * lower case (make line in)
if viewflag then gosub viewonly ; return
if rest eq '' then ccom = 'MCL' else ccom = 'QMCL'
gosub conv.command
* Various forms for loading stuff
case comd eq 'LD' or comd eq 'LOAD' or comd eq 'LDA' or comd eq 'LOADA'
if viewflag then gosub viewonly ; return
if not(sec.load.flg) then
crt 'LOAD disabled'
comi = ''
return
end
gosub get.load
if temp eq '' then return
if prepflag then
sec.call2.type = 1
sec.fn2 = ofpt
sec.id2 = oipt
sec.dict2.flg = (odpt = 'DICT')
call @prepprog(mat security)
if sec.stop.flg then stop
if not(sec.ok2.flg) then
gosub bad.comd ; return
end
end
if comd[len(comd),1] ne 'A' then
gosub get.lines
if not(temp) then return
end
gosub savethat
this = insert(this,here+1,0,0,temp)
temp = dcount(temp,am)
here = here + temp
crt 'At line ':here:', ':temp:' lines loaded.'
temp = ''
gosub set.record
case comd eq 'LL' ; * long lines
if not(rest matches '1N0N') then
rest = span-llen-2
crt 'LL':numb:'/':rest
end
dawn = here + 1
if dawn gt last then dawn = 1
if numb then dusk = here + numb else dusk = last
if dusk gt last then dusk = last
for here = dawn to dusk
gosub get.line
temp = trim(line[rest,huge])
if temp ne '' then
gosub display.line
if not(numb) then return
end
next here
crt
gosub display.line
case 1 ; gosub bad.command
end case
return
m: begin case
case comd eq 'M' ; * pattern matching
rest = field(rest,dlim,1)
if rest eq '' and mmat ne '' then
dlim = mmat<1,1>
rest = mmat<1,2>
end
if rest eq '' then
crt 'No pattern given to match'
return
end
gosub changematch.command
case comd eq 'MACRO'
if macn then
temp = dcount(macc<1,1>,sm)
macc = delete(macc,1,1,temp)
macc = delete(macc,1,1,temp)
if macc ne '' then
pres<1,macn> = macc<1,1>
crt 'Macro saved to PRestore ':macn
end else
crt 'Macro empty - not saved'
end
macc = ''
macn = 0
end else
if numb eq '' then numb = 1
if numb gt presnumb or numb lt 1 then
crt 'PRestore must be in range 1-':presnumb:'.'
comi = ''
return
end
crt 'Macro being recorded for PRestore ':numb
macn = numb
end
case comd eq 'MERGE' or comd eq 'ME' ; * merge stuff
if viewflag then gosub viewonly ; return
if rest eq '' and numb eq '' then
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd
return
end
numb = fin - beg + 1
if blockflag then
if beg eq fin
then stub = 'Copy line ':beg:' to under line ':here:'? '
else stub = 'Copy lines ':beg:'-':fin:' to under line ':here:'? '
gosub get.answ
if answ ne yes[1,1] then
crt 'Block command cancelled.'
return
end
end
dlim = ' '
rest = beg:' ':fin
numb = ''
end
rest = trim(rest)
if numb eq '' then gosub parse.atts
if numb ne '' and rest eq '' then rest = here
if not(rest matches '1N0N') or numb eq '' then
crt 'Format of MErge command is: "MEn/s"; eg: "ME10/15" or "ME/s/f"; eg: "ME/15/24"'
gosub bad.comd ; return
end
* if numb gt last then
* crt 'Nothing done - record does not have that many lines.'
* comi = '' ; return
* end
bite = field(this,am,rest,numb)
if numb ne 1 or bite ne '' then numb = dcount(bite,am)
if numb then
gosub savethat
this = insert(this,here+1,0,0,bite)
gosub set.record
if beg gt here then beg = beg + numb
if fin gt here then fin = fin + numb
xxno = dcount(krj<1>,vm)
for xx = 1 to xxno
if krj<2,xx> gt here then krj<2,xx> += numb
next xx
crt 'Merged ':numb:' lines starting at line ':rest:'; still at line ':here:'.'
end else
crt 'Nothing done - this line is within the range.'
comi = '' ; return
end
case comd eq 'MOVE' or comd eq 'MV' ; * move stuff
if viewflag then gosub viewonly ; return
if rest eq '' then
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd
return
end
if here le fin and here ge beg then
crt 'A block may not be moved into itself. MERGE will work.'
comi = ''
return
end
numb = fin - beg + 1
if blockflag then
if beg eq fin then
stub = 'Move line ':beg:' to after line ':here:' OK? ':ny
end else
stub = 'Move lines ':beg:'-':fin:' to after line ':here:' OK? ':ny
end
gosub get.answ
if answ ne yes[1,1] then
crt 'Block command cancelled.'
return
end
end
dlim = ' '
rest = beg:' ':fin
numb = ''
end
rest = trim(rest)
if numb eq '' then gosub parse.atts
if not(rest matches '1N0N') or numb eq '' then
crt 'Format of MoVe command is: "MVn/s"; eg: "MV10/15" or "MV/s/f"; eg: "MV/15/24"'
gosub bad.comd ; return
end
dusk = rest + numb - 1
if dusk gt last then dusk = last
if here ge rest and here le dusk then
crt 'Nothing done - this line is within the range.'
comi = '' ; return
end
bite = field(this,am,rest,numb)
numb = dcount(bite,am)
if numb then
gosub savethat
if here gt dusk then
this = insert(this,here+1,0,0,bite)
if rest gt 1
then this = this[1,col1()-1]:this[col2(),len(this)]
else this = this[col2()+1,len(this)]
end else
this = this[1,col1()-1]:this[col2(),len(this)]
this = insert(this,here+1,0,0,bite)
end
gosub set.record
if here gt dusk then
here = here - numb
crt 'Moved ':numb:' lines starting at line ':rest:'; now at line ':here:'.'
end else
crt 'Moved ':numb:' lines starting at line ':rest:'; still at line ':here:'.'
end
!##############
posn = beg; gosub recalc.posn; beg = posn
posn = fin; gosub recalc.posn; fin = posn
xxno = dcount(krj<1>,vm)
for xx = 1 to xxno
posn = krj<2,xx>; gosub recalc.posn; krj<2,xx> = posn
next xx
end else
crt 'Nothing done - no lines selected.'
comi = '' ; return
end
case 1 ; gosub bad.command
end case
return
n: begin case
case comd eq 'N' ; * same as "+"
if numb eq '' then numb = 1
here = here + numb
if here gt last then here = last
gosub display.line
case comd eq 'NULL' ; * null line input definition
dlim = trim(dlim):trim(rest)
dlim = dlim[1,1]
nill = dlim
if nill eq '"' then
bit = "'":nill:"'"
end else bit = '"':nill:'"'
crt 'NULL character to terminate INSERT is ':bit:'.'
comi = ''
case comd eq 'NUM' ; * toggle the line numbering
if lfmt eq '' then
crt 'Line Numbering is ON'
gosub get.lfmt
end else
crt 'Line Numbering is OFF'
lfmt = ''
end
case 1 ; gosub bad.command
end case
return
o: begin case
case comd eq 'OC' ; * oconv
if viewflag then gosub viewonly ; return
if rest eq '' then
crt 'No conversion given'
gosub bad.comd ; return
end
ccom = rest ; gosub conv.command
case comd[1,2] eq 'OO' ; * undo last change
if oopc ne '' then
this = oops
here = oopl
last = oopf
beg = oopb<1>
fin = oopb<2>
krj = oopk
gosub set.record
crt '"':oopc:'" undone - now at line ':here:'.'
oops = '' ; oopc = '' ; oopl = '' ; oopf = ''
oopb = '' ; oopk = ''
gosub display.line
end else
crt 'last change already "undone" or nothing to undo'
end
comi = ''
case comd eq 'OUT'
gosub outline
case 1 ; gosub bad.command
end case
return
p: begin case
case comd eq 'P' ; * page on
if numb else numb = plen
if here ge last then here = 0
here += 1
gosub set.bounds
for here = dawn to dusk
gosub display.line
next here
here = dusk
case comd eq 'PA' ; * print window up to here
if numb else numb = pwin
save = here
here = here - numb
gosub set.bounds
for here = dawn to dusk
gosub display.line
next here
here = save
crt 'Still at line ':here:'.'
case comd = 'PASTE' and rest eq '' ; * paste from kept
if viewflag then gosub viewonly ; return
if kept eq '' then
crt 'Nothing in KEPT buffer'
comi = '' ; return
end
gosub savethat
numb = dcount(kept,am)
this = insert(this,here+1,0,0,kept)
gosub set.record
crt 'Pasted ':numb:' lines from KEPT buffer; still at line ':here:'.'
if beg gt here then beg += numb
if fin gt here then fin += numb
xxno = dcount(krj<1>,vm)
for xx = 1 to xxno
if krj<2,xx> gt here then krj<2,xx> += numb
next xx
case comd eq 'PASTE' ; * save the kept buffer
if viewflag then gosub viewonly ; return
if kept eq '' then
crt 'Nothing in KEPT buffer'
comi = '' ; return
end
gosub save.stuff
case comd eq 'PE' ; * page editor mode
if not(editpage) then
crt 'Page editing not possible at this terminal'
comi = ''
return
end
that = this ; savl = here:am:last
if this eq '' then this = am
if here lt 1 then here = 1
ptop = here
mode = 'PAGE':am:'View'
if sec.write.flg then mode<2> = 'Ins'
pchr = 1
chng = '' ; show = ''
gosub display.page
*>
gosub get.line
*>
temp = line
case comd eq 'PL' ; * print window from here
if numb else numb = pwin
save = here
gosub set.bounds
for here = dawn to dusk
gosub display.line
next here
here = save
crt 'Still at line ':here:'.'
case comd eq 'PP' ; * print window bracketing here
if numb else numb = pwin
save = here
here = here - int(numb/2)
gosub set.bounds
for here = dawn to dusk
gosub display.line
next here
here = save
crt 'Still at line ':here:'.'
case comd eq 'PR' ; * prestore processing
if numb eq '' then
crt 'Defined prestores (':presnumb:' Maximum)'
for xx = 1 to presnumb
temp = pres<1,xx>
convert sm to comdmark in temp
$ifdef unidata
crt fmt(xx,'2/0R'):' ':temp
$else
crt fmt(xx,'R%2'):' ':temp
$endif
next xx
return
end
if numb gt presnumb or numb lt 1 then
crt 'PRestore must be in range 1-':presnumb:'.'
comi = ''
return
end
if dlim ne '' then
if not(rest eq rest<1,1,1>) then
crt 'Invalid - delimiter in prestore'
comi = ''
return
end
pres<1,numb> = change(rest,dlim,sm)
end else
salt = pres<1,numb>
end
case 1 ; gosub bad.command
end case
return
q: begin case
* Various forms for quitting
case comd eq 'Q' or comd = 'QK' or comd = 'QUIT' or comd = 'QUITK'
if not(viewflag) and (orig ne this) then
stub = '***** Record changed --- OK to Quit? (N/Y)>'
gosub get.answ
if answ eq yes[1,1] then stopsign = true
end else stopsign = true
if stopsign then
if orig eq '' then
crt 'Quit "':item:'" in file "':fnam:'" not created.'
end else crt 'Quit "':item:'" in file "':fnam:'" unchanged.'
if index(comd,'K',1) then
killsign = true
if idcnt gt 1 then crt 'Select list cancelled.'
end
end
case 1 ; gosub bad.command
end case
return
r: begin case
case comd eq 'RA' ; * view or repeat change
if viewflag then gosub viewonly ; return
gosub change.command
case comd eq 'R' and dlim ne '' and index(rest,dlim,1) ; * change
if viewflag then gosub viewonly ; return
crt ; comd = 'C'
gosub change.command
case comd eq 'R' ; * replace lines
if viewflag then crt ; gosub viewonly ; return
if not(last) then
crt 'Empty record, use Insert (I) command.'
comi = ''
return
end
if here lt 1 then here = 1 ; gosub display.line
chng = 0 ; save = here ; savl = last
if numb lt 1 then numb = 1
if dlim ne '' and rest eq '' then rest = ' '
loop
crt begn:
if lfmt then crt fmt(here,lfmt):'=':
crt ceop:
if rest eq '' then
stub = here:'='
if lfmt then stub = fmt(here,lfmt):'='
gosub get.rope; line = rope
end else line = rest
gosub parse.line
until line eq '' do
crt goup:begn:ceol:
if lfmt then crt fmt(here,lfmt):': ':
crt line
if line eq comdmark then
line = ''
crt begn:
if lfmt then crt fmt(here,lfmt):': ':
end
if numb gt 1 then crt
if line eq ' ' then line = ''
if not(chng) then gosub savethis
chng += 1
memr(cell)<lnum> = line
here += 1 ; numb -= 1
gosub get.line
if numb eq 0 then exit
repeat
if here ne save then here -= 1
if chng then gosub reset.record; gosub get.line
crt begn:ceol:
case comd eq 'RELEASE' ; * release the item lock
release file,item
lock = false
case 1 ; gosub bad.command
end case
return
s: begin case
case comd eq 'S' ; * search processing
if numb eq '' then
crt 'Last ':looknumb:' searches (latest first)'
for xx = 1 to looknumb
$ifdef unidata
crt fmt(xx,'2/0R'):' ':look<1,xx>
$else
crt fmt(xx,'R%2'):' ':look<1,xx>
$endif
next xx
return
end
if numb gt looknumb or numb lt 1 then
crt 'Search must be in range 1-':looknumb:'.'
comi = ''
return
end
comi = look<1,numb>
if comi eq '' then
crt 'There is no search number ':numb:'.'
return
end
look = delete(look,1,numb,0)
look = insert(look,1,1,0,comi)
gosub parse.command
if comd eq '' then comd = 'L' ; numb = huge
comi = ''
redo = true
case comd eq 'SAVE' or comd eq 'SV' ; * save the item
if viewflag then gosub viewonly ; return
comd = 'SV'
if rest eq '' then
if not(sec.write.flg) then
crt 'File disabled'
comi = ''
return
end
gosub write.record
end else gosub save.stuff
case comd eq 'SEQ' ; * build a sequence
if viewflag then gosub viewonly ; return
if dlim eq '' then
crt 'Too few fields in this command.'
gosub bad.comd ; return
end
good = true
cfrom = field(rest,dlim,1)
cto = field(rest,dlim,2)
if cto eq '' then cto = 1
if not(num(cto)) then
crt 'Base for sequence command must be a number.'
good = false
end
bit = field(rest,dlim,3)
if bit eq '' then bit = 1
if not(num(bit)) then
crt 'Increment for sequence command must be a number.'
good = false
end else
if not(bit) then
crt 'Increment for sequence command must not be zero.'
good = false
end
end
if not(good) then gosub bad.comd ; return
rest = dlim:field(rest,dlim,4,2)
if rest ne dlim then
gosub parse.cols
if not(good) then return
end else cols = ''
chng = 0 ; save = here ; savl = last
gosub set.bounds
for here = dawn to dusk
gosub get.line ; temp = line
if cols then
bite = index(line[cols,colf],cfrom,1)
if bite then bite = bite + cols - 1
end else
bite = index(line,cfrom,1)
end
if bite then
temp = line[1,bite-1]:cto
temp = temp:line[bite+len(cfrom),len(line)]
end
if '*':temp ne '*':line then
cto = cto + bit
if not(chng) then gosub savethis
chng += 1
memr(cell)<lnum> = temp
gosub display.line
end
next here
here = dusk
if chng then gosub reset.record
case comd eq 'SHOW' ; * show changes flag
rest = upcase(rest)
begin case
case rest eq 'ON' ; shew = true
case rest eq 'OFF' ; shew = false
case 1 ; shew = not(shew)
end case
if shew
then crt 'Show changes flag is ON'
else crt 'Show changes flag is OFF'
case comd eq 'SORT' or comd eq 'SORTU' ; * sort the block
if viewflag then gosub viewonly ; return
test = index(comd,'U',1)
if not(beg) and not(fin) then
crt 'Command requests a block operation, but no block is defined.'
gosub bad.comd
return
end
if beg le 1 then
temp = 0
end else
temp = index(this,am,beg-1)
if not(temp) then
crt 'Cannot find beginning of block'
gosub bad.comd ; return
end
end
rest = upcase(rest)
if rest eq '' then rest = 'AL'
if not(index('*AR*AL*DR*DL*','*':rest:'*',1)) then
crt 'Invalid sort sequence - use "AL" "AR" "DL" or "DR"'
gosub bad.comd ; return
end
temp<2> = index(this,am,fin)
if fin eq last then temp<2> = len(this)+1
if not(temp<2>) then
crt 'Cannot find end of block'
gosub bad.comd ; return
end
if blockflag then
stub = 'Sort block beginning at ': beg:' and ending at ': fin:'?'
gosub get.answ
if answ ne yes[1,1] then
crt 'Block command cancelled.'
return
end
end
gosub savethat
bits = ''
for here = beg to fin
gosub get.line
locate(line,bits;posn;rest) then
if test then good = false else good = true
end else good = true
if good then bits = insert(bits,posn;line)
next here
here = oopl
if fin ne last
then this = this[1,temp<1>]:bits:am:this[temp<2>+1,len(this)]
else this = this[1,temp<1>]:bits
bits = ''
gosub set.record
* If any tags are in the sorted block then clear the tags,
* as it really makes no sense to try and sort them.
good = true
xxno = dcount(krj<1>,vm)
for xx = 1 to xxno
posn = krj<2,xx>
if posn ge beg and posn le fin then good = false
next xx
if not(good) then
krj = ''
crt 'Tags cleared'
end
gosub display.line
case comd eq 'SPACE' ; * change spacing flag for 'L'
rest = upcase(rest)
begin case
case rest eq 'ON' ; spaceflag = true
case rest eq 'OFF' ; spaceflag = false
case 1 ; spaceflag = not(spaceflag)
end case
if spaceflag then
crt 'SPACE flag is ON'
end else crt 'SPACE flag is OFF'
case comd eq 'SPOOL' ; * print
save = here
if numb eq '' and rest matches '1N0N' then numb = rest
if numb eq '' then here = 1 ; numb = last
gosub set.bounds
head = 'Record - ':item:' File - ':fnam:' Account - ':acct:' '
head = head:timedate():"'LL'"
temp = span
printer on
temp = temp - llen - 2
heading head
for here = dawn to dusk
gosub get.line
convert badc to gudc in line
print fmt(here,lfmt):': ':line[1,temp]
loop
line = line[temp+1,len(line)]
until line eq '' do
print space(llen+2):line[1,temp]
repeat
next here
printer close
if dawn ne 1 or dusk ne last then
crt 'Lines ':dawn:' to ':dusk:' of ':
end
crt '"':item:'" spooled to the printer.'
here = save
case comd eq 'SPOOLHELP' ; * print the help
rest = am
gosub show.help
case comd eq 'STAMP' ; * stamp it
if viewflag then gosub viewonly ; return
gosub savethat
last += 1 ; here += 1 ; lnum += 1
line = '* Last updated by ':name:' in account ':acct:' at ':timedate()
gosub insert.line
gosub reset.record
gosub display.line
case 1 ; gosub bad.command
end case
return
t: begin case
case comd eq 'T' ; * top
here = 0
gosub display.line
case comd eq 'TC' ; * text case (make line in)
if viewflag then gosub viewonly ; return
if rest eq '' then ccom = 'MCT' else ccom = 'QMCT'
gosub conv.command
* Various ways to TRIM the line
case comd eq 'TRIM' or comd = 'TRIMF' or comd = 'TRIMB'
if viewflag then gosub viewonly ; return
chng = 0 ; save = here ; savl = last
if rest and comd eq 'TRIM' then
seek = field(rest,dlim,1)
if seek matches '3n' then seek = char(seek)
mark = field(rest,dlim,2)
mark = upcase(trim(mark))[1,1]
if index('ABCDEFLRT',mark,1) else
crt 'Invalid TRIM argument - must be one of "ABCDEFLRT"'
gosub bad.comd
return
end
end else seek = ''
show = shew ; dnum = 1
if numb eq '' and rest matches '1N0N' then numb = rest
gosub set.bounds
for here = dawn to dusk
gosub get.line
begin case
case comd eq 'TRIM'
if seek eq ''
then temp = trim(line)
else temp = trim(line,seek,mark)
case comd eq 'TRIMF' ; temp = trimf(line)
case comd eq 'TRIMB' ; temp = trimb(line)
end case
gosub check.line
next here
here = dusk
if chng then
gosub reset.record
crt chng:' lines changed - now at ':here
end
case comd eq 'TWIN' or comd eq 'TRIPLE' ; * sideways cloning of line
if viewflag then gosub viewonly ; return
if dlim ne '' then
line = rest ; gosub parse.line ; join = line
end
if here and here le last else return
chng = 0 ; save = here
gosub set.bounds
for here = dawn to dusk
gosub get.line
if comd eq 'TWIN'
then test = line:join:line
else test = line:join:line:join:line
if test ne line then
chng += 1
memr(cell)<lnum> = test
end
next here
if chng eq 0 then return
temp = 'Split ':chng:' lines'
if join ne '' then temp := ' and joined the parts with "':join:'"'
crt temp
here = save
gosub savethat
gosub reset.record
gosub display.line
case 1 ; gosub bad.command
end case
return
u: begin case
case comd eq 'U' ; * same as "-"
if numb eq '' then numb = 1
here = here - numb
if here lt 0 then here = 0
if here gt last then here = last
gosub display.line
case comd eq 'UC' ; * upper case (make line in)
if viewflag then gosub viewonly ; return
if rest eq '' then ccom = 'MCU' else ccom = 'QMCU'
gosub conv.command
case comd eq 'UNLOAD' ; comd = 'SV' ; redo = true
if viewflag then gosub viewonly ; return
case 1 ; gosub bad.command
end case
return
v: begin case
case comd eq 'V' ; * version information
crt (upcase(verb):' = ') 'R#20':help.def
$ifdef qm
temp = trans('NEWVOC','$RELEASE',2,'X')
if temp eq '' then
temp = trans('VOC','$RELEASE',2,'X')
end
if temp eq '' then temp = '?'
crt ('QM = ') 'R#20':temp
*>
crt ('Licence = ') 'R#20':system(31)
*>
$endif
$ifdef unidata
crt ' UniData version ':oconv('version','TVOC;X;;1')
$endif
$ifdef universe
temp = oconv('RELLEVEL','TNEWACC;X;;2')
if temp eq '' then
temp = oconv('RELLEVEL','TVOC;X;;2')
end
if temp eq '' then temp = 'not known'
crt ' UniVerse version ':temp
case comd eq 'VLIST'
execute comi capturing disp
stub = "Press return to continue showing VLIST 'T'op '-'back 'Q'uit"
gosub show.disp
$endif
case 1 ; gosub bad.command
end case
return
w: begin case
case comd eq 'W' or comd eq 'WHERE' ; * what we are editing
crt
if viewflag
then crt 'Viewing "':item:'" in file "':fnam:'"'
else crt 'Editing "':item:'" in file "':fnam:'"'
if idcnt gt 1 then crt ' [':id:'/':idcnt:']':
crt
if here gt last then here = last
gosub display.line
case comd eq 'WM' ; * word marker display (change)
if dlim ne '' then wordmark = dlim
if wordmark eq '"'
then crt 'WordMark is ':"'":wordmark:"'"
else crt 'WordMark is ':'"':wordmark:'"'
case 1 ; gosub bad.command
end case
return
x: begin case
* Another way of quitting
case comd eq 'X' ; comd = 'QK' ; redo = true
case comd eq 'XEQ' ; * execute a command
if viewflag then gosub viewonly ; return
if not(sec.xeq.flg) then
crt 'XEQ disabled'
comi = ''
return
end
loop
if rest ne '' then execute rest
test = @(0,0)
stub = '<RETURN> or command :'
gosub get.rope; rest = rope
if rest eq '' then
crt; crt 'Returned - ':
crt 'Editing "':item:'" in file "':fnam:'"'
end
until rest eq '' do
*>
crt
*>
repeat
gosub display.line
case comd eq 'XTD' ; * hex to decimal
$ifdef universe
crt xtd(rest)
$else
crt iconv(rest,'MX')
$endif
case 1 ; gosub bad.command
end case
return
y: begin case
case 1 ; gosub bad.command
end case
return
z: begin case
case 1 ; gosub bad.command
end case
return
set.bounds:
if numb eq '' then numb = 1
dawn = here
if dawn lt 1 then dawn = 1
dusk = dawn + numb - 1
if dusk gt last then dusk = last
numb = 0
return
null.command:
if dlim eq ':' then comd = 'XEQ' ; return
if dlim eq '/' then
comd = 'L'
if numb eq '' then numb = huge
return
end
if dlim eq '-' or dlim eq '+' then
if rest eq '' then rest = 1
end
if numb ne '' then comd = numb ; return
if dlim eq '' and rest eq '' then
here += 1
if here gt last then here = 1
gosub display.line
return
end
crt
begin case
case dlim eq '+' and rest matches '1N0N'
here = here + rest
if here gt last then here = last
gosub display.line
case dlim eq '-' and rest matches '1N0N'
here = here - rest
if here lt 0 then here = 0
if here gt last then here = last
gosub display.line
case dlim eq '^'
wild = not(wild)
if wild
then crt 'Expansion of non-printing characters enabled'
else crt 'Expansion of non-printing characters disabled'
case dlim eq '='
crt 'UNIDATA prestore is not implemented - Use "PR"'
case dlim eq '.'
gosub dot.command
case dlim eq '$'
if not(sec.xcom.flg) then
crt '$ external commands disabled'
comi = ''
return
end
save = comi ; comi = rest
gosub parse.command
comi = save
comd = '$':comd
xcom = oconv(comd,'TAE_XCOMS;X;2;2')
begin case
case xcom eq ''
crt 'Record "':comd:'" does not exist in "AE_XCOMS".'
case xcom[len(xcom)-2,3] ne '_AE'
disp = ''
disp<-1> = "Line 2 of record '":rest:"' in file 'AE_XCOMS'"
disp<-1> = "contains '":xcom:"'."
disp<-1> = ''
disp<-1> = 'This line should contain the name of a Basic subroutine that'
disp<-1> = "has been written to implement the external command '":rest:"'."
disp<-1> = "The program name must end in '_AE'."
stub = 'Press RETURN to continue'
gosub show.disp
case 1
that = this ; savl = here:am:last:beg:am:fin:am:krj
save = comi:am:comd:am:item:am:fnam
comd = comd:' ':rest
call @xcom(mat junk)
item = save<3>
fnam = save<4>
if here lt 0 then here = 0
gosub set.record
if here gt last then here = last
comd = ''
if that ne this then
crt save<2>:' - CHANGES HAVE BEEN MADE'
oops = that ; oopc = save<1>
oopl = savl<1> ; oopf = savl<2>
oopb = savl<3>:am:savl<4> ; oopk = field(savl,am,5,3)
end
that = ''
end case
case comi eq '?'
disp = ' Login name = ':name:' (':term:', userno ':whom:')'
disp<-1> = ' Account = ':acct
if path ne '' then disp<-1> = ' VOC path = ':path
disp<-1> = ' Level = ':levl
disp<-1> = ' File name = ':fnam
disp<-1> = ' Record id = ':item
disp<-1> = ' Current line = ':here
disp<-1> = ' Lines = ':last
disp<-1> = ' Characters = ':len(this)
if chan ne '' then
disp<-1> = 'Last Change command = ':chan<1,1>
end
if cmat ne '' then
temp = 'CM':cmat<1,3>:cmat<1,1>:cmat<1,2>
disp<-1> = 'Last CMatch command = ':temp
end
if olda then
temp = 'A':olda<1,2>:olda<1,1>
disp<-1> = 'Last Append command = ':temp
end
if beg or fin then
disp<-1> = ' Block = ':beg:'-':fin
end
if comdmark eq '"' then
temp = "'":comdmark:"'"
end else temp = '"':comdmark:'"'
disp<-1> = 'Command Delimiter is ':temp:', '
if nill eq '"' then
temp = "'":nill:"'"
end else temp = '"':nill:'"'
disp := 'character to end inserting is ':temp:', '
if wordmark eq '"' then
temp = "'":wordmark:"'"
end else temp = '"':wordmark:'"'
disp := 'WordMark is ':temp
disp<-1> = 'Page: window for PA/PL/PP is ':pwin:', length for P is ':plen
if wild
then disp<-1> = 'Expansion of non-printing characters enabled'
else disp<-1> = 'Expansion of non-printing characters disabled'
if caseflag then
disp<-1> = 'CASE':' flag ON':', '
end else disp<-1> = 'CASE':' flag OFF':', '
if spaceflag then
disp := 'SPACE':' flag ON':', '
end else disp := 'SPACE':' flag OFF':', '
if shew then
disp := 'SHOW':' flag ON':', '
end else disp := 'SHOW':' flag OFF':', '
if blockflag then
disp := 'BLOCK':' flag ON'
end else disp := 'BLOCK':' flag OFF'
if oopc ne '' then
disp<-1> = 'OOPS will restore record prior to command: ':oopc
end else
disp<-1> = 'OOPS already executed, or no changes in effect.'
end
gosub show.disp
case comi[1,2] eq '<>' ; gosub botharr
case comi[1,1] eq '<' ; gosub leftarr
case comi[1,1] eq '>' ; gosub rightarr
case dlim eq '\' and rest[1,1] eq '\' ;* clear the tag pointers
krj = ''
crt 'Tags cleared'
case dlim eq '\' ;* set a tag pointer
locate(here,krj,2;posn) then
crt 'There is already a Tag on line ':here
return
end
if rest eq '' then rest = 'T':here
rest = upcase(rest)
locate(rest,krj,1;posn) then
crt 'There is already a Tag labelled ':rest
return
end
posn = krj<3>
krj<1> = field(krj<1>,vm,1,posn)
posn += 1
krj<1,posn> = rest
krj<2,posn> = here
krj<3> = posn
crt 'Setting Tag labelled ':rest:' at line ':here
case (dlim eq '[' or dlim eq ']') and (rest[1,1] eq '[' or rest[1,1] eq ']')
if krj<3> eq ''
then disp = 'No Tag found'
else disp = 'Tags at line-Labelled'
posn = krj<3>
xxno = dcount(krj<1>,vm)
for xx = 1 to xxno
disp<-1> = krj<2,xx> 'r#12'
if xx eq posn then disp := '>' else disp := ' '
disp := krj<1,xx>
next xx
convert badc to gudc in disp
gosub show.disp
case dlim eq '[' and rest eq ''
posn = krj<3>-1
if posn gt 0 then
comd = krj<2,posn>
krj<3> = posn
crt 'Moved to line ':comd:' labelled ':krj<1
end else comd = ''
if comd eq '' then crt 'No Tag found'
case dlim eq ']' and rest eq ''
posn = krj<3>+1
comd = krj<2,posn>
if comd eq '' then
crt 'No Tag found'
end else
krj<3> = posn
crt 'Moved to line ':comd:' labelled ':krj<1
end
case dlim eq '[' or dlim eq ']'
locate(upcase(rest),krj,1;posn) then comd = krj<2,posn> else comd = ''
if comd ne '' then
krj<3> = posn
crt 'Moved to line ':comd:' labelled ':krj<1
return
end else crt 'No Tag found'
case 1
gosub bad.command
end case
return
parse.cols:
good = true
cols = field(rest,dlim,2)
convert ',.' to '--' in cols
rest = field(rest,dlim,1)
colf = field(cols,'-',2)
cols = field(cols,'-',1)
if colf eq '' then colf = cols
if cols ne '' then
if not(cols matches '1N0N') or not(colf matches '1N0N') then
crt 'Column specifications must be positive whole numbers.'
gosub bad.comd
good = false
return
end
end
if colf lt cols then
crt 'Ending column # must exceed or equal starting column #.'
gosub bad.comd
good = false
return
end
colf = colf - cols + 1
return
parse.atts:
convert '-' to dlim in rest
if dlim eq '"' then temp = "'" else temp = '"'
temp = '1N0N':temp:dlim:temp:'1N0N'
if rest matches temp then
numb = field(rest,dlim,2) - field(rest,dlim,1) + 1
rest = field(rest,dlim,1)
end
return
change.command:
if comd eq 'RA' then
if numb eq '' then
crt 'Last ':channumb:' changes (latest first)'
for xx = 1 to channumb
$ifdef unidata
crt fmt(xx,'2/0R'):' ':chan<1,xx>
$else
crt fmt(xx,'R%2'):' ':chan<1,xx>
$endif
next xx
return
end
if numb gt channumb or numb lt 1 then
crt 'Change must be in range 1-':channumb:'.'
comi = ''
return
end
comi = chan<1,numb>
if comi eq '' then
crt 'There is no change number ':numb:'.'
return
end
chan = delete(chan,1,numb,0)
chan = insert(chan,1,1,0,comi)
gosub parse.command
comi = 'RA'
end
save = upcase(field(rest,dlim,3,2))
if save ne '' then rest = rest[1,col1()]
gosub get.fromto
temp = save
if comi eq '' then return
chng = 0 ; save = here ; savl = last
glob = index(temp,'G',1)
show = shew or index(temp,'S',1)
convert dlim:'GS' to '-' in temp
rest = dlim:temp
gosub parse.cols
if not(good) then return
if numb lt plen then show = true
dnum = 1
gosub set.bounds
for here = dawn to dusk
gosub get.line
gosub change.line
gosub check.line
next here
here = dusk
if comi ne '' and upcase(comi) ne 'RA' then
chan = insert(chan,1,1,0,comi)
chan = delete(chan,1,channumb,0)
end
if chng then
gosub reset.record
if not(show) and dnum gt plen then
crt chng:' lines changed - now at ':here
end
end
return
get.fromto:
if count(rest,dlim) gt 2 then
crt 'Too many delimiters (3 max.).'
comi = ''
return
end
line = field(rest,dlim,1)
gosub parse.line
cfrom = line
line = field(rest,dlim,2)
gosub parse.line
cto = line
if cto eq '' and count(rest,dlim) lt 2 then
crt 'Missing required TO field (for "CHANGE/FROM/TO").'
comi = ''
return
end
return
change.line:
if cfrom eq '' then
temp = cto:line
end else
if glob then
temp = change(line,cfrom,cto)
end else
temp = index(line,cfrom,1)
if temp then
temp = line[1,temp-1]:cto:line[temp+len(cfrom),len(line)]
end else temp = line
end
end
return
conv.command:
chng = 0 ; save = here ; savl = last
show = shew or index(rest,'S',1) or index(rest,'s',1)
dnum = 1
if numb lt plen then show = true
if numb eq '' and rest matches '1N0N' then numb = rest
gosub set.bounds
ctyp = ccom[1,1]
begin case
* ICONV
case ctyp eq '*' ; ccom = ccom[2,huge]
* Text conversion LC, TC, or UC command
case ctyp eq 'Q' ; ccom = ccom[2,huge]
end case
for here = dawn to dusk
gosub get.line
begin case
case ctyp eq '*'
temp = iconv(line,ccom)
case ctyp eq 'Q'
temp = field(trim(line),' ',1)
flag = false
if temp ne 'REMOVE' then
if temp[1,3] eq 'REM' then flag = true
if temp[1,1] eq '*' then flag = true
if temp[1,1] eq '!' then flag = true
end
if flag then
temp = line
end else
xxno = len(line)
temp = ''
flag = ''
for xx = 1 to xxno
bit = line[xx,1]
begin case
case bit eq flag ; flag = ''
case flag ne ''
case index(qt,bit,1) ; flag = bit
*>
case bit eq ';'
test = trim(line[xx+1,huge])[1,1]
if test eq '*' or test eq '!' then flag = am
*>
case 1 ; bit = oconv(bit,ccom)
end case
temp = temp:bit
next xx
end
case 1
temp = oconv(line,ccom)
end case
if temp eq '' then temp = line
gosub check.line
next here
here = dusk
if chng then
gosub reset.record
if not(show) and dnum gt plen then
crt chng:' lines changed - now at ':here
end
end
return
dot.command:
if trim(comi) eq '.' then comi = '.L1'
save = comi
comi = field(comi,dlim,2,huge)
gosub parse.command
begin case
case comd eq 'A' ; * append to line
if numb eq '' then numb = 1
if numb gt dcount(stak,vm) then
crt 'History command ':numb:' does not exist.'
end else
stak<1,numb> := rest
$ifdef unidata
crt fmt(numb,'3/0R'):'. ':stak<1,numb>
$else
crt fmt(numb,'R%3'):'. ':stak<1,numb>
$endif
end
case comd eq 'C' ; * change lines
if numb eq '' then numb = 1
if numb gt dcount(stak,vm) then
crt 'History command ':numb:' does not exist.'
end else
gosub get.fromto
if comi eq '' then comd = '' ; return
glob = index(field(rest,dlim,3),'G',1)
glob = glob + index(field(rest,dlim,3),'g',1)
line = stak<1,numb>
gosub change.line
stak<1,numb> = temp
$ifdef unidata
crt fmt(numb,'3/0R'):'. ':temp
$else
crt fmt(numb,'R%3'):'. ':temp
$endif
end
case comd eq 'D' ; * delete lines
if numb eq '' then numb = 1
if numb gt dcount(stak,vm) then
crt 'History command ':numb:' does not exist.'
end else
stak = delete(stak,1,numb,0)
crt 'History #':numb:' DELETEd.'
end
case comd eq 'I' ; * insert a new line
if numb eq '' then numb = 1
if numb gt dcount(stak,vm) then
crt 'History command ':numb:' does not exist.'
end else
if rest ne '' then
stak = insert(stak,1,numb,0,rest)
stak = delete(stak,1,staknumb,0)
$ifdef unidata
crt fmt(numb,'3/0R'):'. ':stak<1,numb>
$else
crt fmt(numb,'R%3'):'. ':stak<1,numb>
$endif
end
end
case comd eq 'L' ; * list lines
if numb eq '' then numb = plen
if numb gt dcount(stak,vm) then numb = dcount(stak,vm)
temp = rem(numb+1,plen)
for xx = numb to 1 step -1
$ifdef unidata
crt fmt(xx,'3/0R'):'. ':stak<1,xx>
$else
crt fmt(xx,'R%3'):'. ':stak<1,xx>
$endif
if xx gt 1 and rem(xx,plen) eq temp then
stub = 'Press return to continue, Q to quit'
rlen = 1
gosub get.rope; crt begn:ceol:
wait = trim(upcase(rope))[1,1]
if wait eq 'Q' then exit
end
next xx
case comd eq 'R' ; * restore a line to latest
if numb eq '' then numb = 1
if numb le dcount(stak,vm) then
temp = stak<1,numb>
stak = insert(stak,1,1,0,temp)
stak = delete(stak,1,staknumb,0)
end
case comd eq 'S'
if numb eq '' then numb = 1
if numb gt presnumb then
crt numb:' is greater than pre-store limit of ':presnumb
return
end
rest = trim(rest)
dawn = field(rest,dlim,1) ; if dawn eq '' then dawn = 1
dusk = field(rest,dlim,2) ; if dusk eq '' then dusk = 1
if not(dawn matches '1N0N' and dusk matches '1N0N') then
crt 'One of the values was not a number'
return
end
if dawn gt dusk then temp = dawn ; dawn = dusk ; dusk = temp
temp = ''
for xx = dusk to dawn step -1
temp<1,1,-1> = stak<1,xx>
next xx
pres<1,numb> = temp
case comd eq 'U' ; * upcase line
if numb eq '' then numb = 1
if numb gt dcount(stak,vm)
then crt 'History command ':numb:' does not exist.'
else stak<1,numb> = upcase(stak<1,numb>)
case comd eq 'UL' ; * downcase line
if numb eq '' then numb = 1
if numb gt dcount(stak,vm)
then crt 'History command ':numb:' does not exist.'
else stak<1,numb> = downcase(stak<1,numb>)
case comd eq 'UT' ; * mixed case line
if numb eq '' then numb = 1
if numb gt dcount(stak,vm)
then crt 'History command ':numb:' does not exist.'
else stak<1,numb> = oconv(stak<1,numb>,'mct')
case comd eq 'X' ; * re-execute an editor command
if numb eq '' then numb = 1
if numb gt dcount(stak,vm) then
crt 'History command ':numb:' does not exist.'
end else
salt = stak<1,numb>
stak = delete(stak,1,numb,0)
end
case 1
comi = save
gosub bad.command
end case
comi = '' ; comd = ''
return
viewonly:
crt 'That command is not allowed in VIEW mode':bell
comi = ''
return
bad.command:
crt 'Command not understood - try "H" for help.'
bad.comd:
xxno = len(comi)
temp = ''
for xx = 1 to xxno
bite = comi[xx,1]
bite = seq(bite)
if bite ge 127 or bite lt 32 then
$ifdef unidata
bite = '^':fmt(bite,'3/0R')
$else
bite = '^':fmt(bite,'R%3')
$endif
end else bite = char(bite)
temp = temp:bite
next xx
crt 'Command was: "':temp:'"'
temp = ''
comi = ''
return
save.stuff:
if not(sec.unload.flg) then
crt 'Unload disabled'
comi = ''
return
end
keepquot = false
gosub parse.rest
odpt = '' ; ofpt = bite<1> ; oipt = bite<2>
onam = ofpt
if ofpt eq 'DICT' then
odpt = ofpt ; ofpt = oipt ; oipt = bite<3>
onam = onam:' ':ofpt
end
if oipt eq '' then
if odpt ne '' then
crt 'Cannot save to null item.'
gosub bad.comd ; return
end
oipt = ofpt ; odpt = dprt ; ofpt = fprt ; onam = fnam
end
if dprt eq odpt and fprt eq ofpt then
ofil = file
end else
open odpt, ofpt to ofil else
crt 'Cannot open ':'"':fnam:'"'
gosub bad.comd ; return
end
end
if prepflag then
sec.call2.type = 2
sec.fn2 = ofpt
sec.id2 = oipt
sec.dict2.flg = (odpt = 'DICT')
call @prepprog(mat security)
if sec.stop.flg then stop
if not(sec.ok2.flg) then
gosub bad.comd ; return
end
end
if source.control then
dict.flag = odpt
file.name = ofpt
record.name = oipt
record.data = this
caller = '3'
write.allowed = '1'
updated = '0'
call source.control(dict.flag,file.name,
record.name,record.data,caller,write.allowed,updated)
if write.allowed ne '1' then
crt 'WRITE NOT ALLOWED'
return
end
end
readv test from ofil, oipt, 1 then
stub = 'Record already exists. Overwrite (y/n)? '
gosub get.answ
if answ ne yes[1,1] then return
end
if comd eq 'PASTE' then
write kept on ofil, oipt on error gosub writerr ; return
end else
write this on ofil, oipt on error gosub writerr ; return
end
crt 'Record "':oipt:'" saved in "':onam:'".'
return
write.record:
if rest ne '' then
if comd eq 'FD' then
crt '"FD" operates only on the current record & file.'
end else
crt '"FI" only for current record & file. Use SAVE.'
end
gosub bad.comd ; return
end
if source.control then
dict.flag = dprt
file.name = fprt
record.name = item
if comd eq 'FD' then record.data = '' else record.data = this
caller = '3'
write.allowed = '1'
updated = '0'
call source.control(dict.flag,file.name,
record.name,record.data,caller,write.allowed,updated)
if write.allowed ne '1' then
crt 'WRITE NOT ALLOWED'
return
end
end
if not(lock) then
crt 'Record lock has been released! Write not allowed.'
comi = ''
return
end
if comd eq 'FD' then
stub = '***** You are about to DELETE the record! OK? ':ny
gosub get.answ
if answ ne yes[1,1] then return
delete file, item on error gosub writerr ; return
crt 'Deleted "':item:'" from file "':fnam:'".'
end else
if comd eq 'SV' then
writeu this on file, item on error gosub writerr ; return
orig = this ; oops = '' ; oopc = '' ; oopl = '' ; oopf = ''
oopb = '' ; oopk = ''
crt 'Saved "':item:'" in "':fnam:'" - now at line ':here:'.'
return
end else
write this on file, item on error gosub writerr ; return
if orig eq this then
crt 'Filed "':item:'" in file "':fnam:'" UNCHANGED.'
end else crt 'Filed "':item:'" in file "':fnam:'".'
oops = '' ; oopc = '' ; oopl = '' ; oopf = '' ; * ewd
end
end
stopsign = true
if index(comd,'B',1) then
temp = 'BASIC'
$ifdef qm
if index(comd,'D',1) then temp<2> = ' DEBUGGING'
$endif
gosub exec.that
end
if index(comd,'C',1) then
temp = 'CATALOG'
begin case
case index(comd,'L',1) ; temp<2> = ' LOCAL'
* case index(comd,'G',1) ; temp<2> = ' GLOBAL'
end case
gosub exec.that
end
if index(comd,'R',1) then temp = 'RUN' ; gosub exec.that
return
edit.fields:
if here lt 1 then here = 1
gosub get.line ; temp = line
convert vmrk to am in line
ttid = whom:'_':levl:'_':vals:'.in.line#':here
write line on acom, ttid on error gosub writerr ; return
crt view:'ing ':vals:' as fields...':
execute verb:' AE_COMS ':ttid:options
test = @(0,0)
crt 'Back ':view:'ing the record "':item:'" in file "':fnam:'"'
read line from acom, ttid else line = ''
delete acom, ttid
return
reset.fields:
convert am to vmrk in line
if temp ne line then
gosub savethat
memr(cell)<lnum> = line
gosub reset.record
end
return
get.load:
temp = ''
if trim(rest) eq '' then
stub = 'Record name, or file name and record name >'
gosub get.rope; rest = rope; crt
if trim(rest) eq '' then temp = ''; return
end
keepquot = false
gosub parse.rest
onam = bite<1>
onid = bite<2>
if onam eq 'DICT' then
onam = onam:' ':onid
onid = bite<3>
if onid eq '' then onid = item
end
if onid eq '' then onid = onam ; onam = ''
if onid eq '' then return
if onam eq '' then
onam = fnam
odpt = dprt
ofpt = fprt
ofil = file
end else
odpt = field(onam,' ',1)
ofpt = field(onam,' ',2)
if ofpt eq '' then ofpt = odpt ; odpt = ''
open odpt, ofpt to ofil else
crt 'Cannot open ':onam
gosub bad.comd ; return
end
end
read temp from ofil, onid else
if dcount(bite,am) eq 1 then
open onid to ofil then
read temp from ofil, item then return
end
end
crt 'Record "':onid:'" was not found on file "':onam:'".'
gosub bad.comd ; return
end
return
changematch.command:
patt = field(rest,dlim,1)
gosub parse.pattern
if not(good) then
crt 'Pattern: character "':bit:'" is not allowed unless quoted.'
comi = ''
return
end
if comd eq 'CM' then cmat = dlim:vm:rest:vm:numb
cto = field(rest,dlim,3,huge)
line = cto ; gosub parse.line ; cto = line
cfrom = upcase(field(rest,dlim,2))
if cfrom eq '' then cfrom = 'L'
if cfrom eq 'L' then mmat = dlim:vm:rest
if numb eq '' and cto eq '' and (cfrom eq 'L' or cfrom eq 'N') then
numb = last
flag = true
end else flag = false
if len(cfrom) eq 1 and index('ADLNPR',cfrom,1) then
end else
gosub parse.cols
if not(good) then return
cfrom = ''
colf = cols + colf - 1
end
cm.del.entry:
gosub set.bounds
show = shew ; dnum = 1
chng = 0 ; save = here ; savl = last ; dnum = 2
test = ''
for here = dawn to dusk
gosub get.line
if cfrom eq 'DE'
then good = index(line,patt,1)
else good = (line matches patt)
if not(good) then
if cfrom eq 'N' then
numb += 1
if show or numb lt plen then gosub display.line
if flag then dusk = here
end
continue
end
numb += 1
temp = line
begin case
case cfrom eq 'A'
temp = line:cto
case cfrom[1,1] eq 'D'
if show or numb lt plen then crt fmt((here + chng),lfmt):'+ ':line
test<-1> = here
case cfrom eq 'L'
gosub display.line
if flag then dusk = here
case cfrom eq 'P'
temp = cto:line
case cfrom eq 'R'
temp = cto
case cfrom eq 'N'
numb -= 1
case 1
gosub parse.temp
end case
if not(index('DL',cfrom,1)) or cfrom eq '' then
gosub check.line
end
next here
if cfrom[1,1] eq 'D' and numb then
gosub savethis
for here = numb to 1 step -1
temp = test<here>
cell = int((temp-1)/cellsize) + 1
coff = rem(temp,cellsize)
if coff eq 0 then coff = cellsize
del memr(cell)<coff>
if beg eq temp then beg = 0
if beg gt temp then beg -= 1
if fin eq temp then fin = 0
if fin gt temp then fin -= 1
for xx = dcount(krj<1>,vm) to 1 step -1
begin case
case krj<2,xx> gt temp ; krj<2,xx> -= 1
case krj<2,xx> eq temp
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1
end case
next xx
next here
test = ''
gosub reset.record
here = dusk - numb
end else
here = dusk
end
if dawn ne dusk then
if here lt last
then crt 'At line ':here:'.'
else crt 'Bottom at ':here:'.'
end
if not(numb) then
if cfrom eq 'N' then
crt 'No lines (in ':dawn:'-':dusk:') NOT matching pattern "':patt:'"'
end else crt 'No lines (in ':dawn:'-':dusk:') matching pattern "':patt:'"'
end else
begin case
case cfrom[1,1] eq 'D'
crt 'Deleted ':numb:' lines matching "':patt:'"'
case cfrom eq 'L'
crt 'Found ':numb:' lines matching "':patt:'"'
case cfrom eq 'N'
crt 'Found ':numb:' lines NOT matching "':patt:'"'
end case
end
if chng then
gosub reset.record
begin case
case dawn eq dusk
return
case cfrom eq 'A'
crt '"':cto:'" appended to ':
case cfrom[1,1] eq 'D'
crt 'Deleted ':
case cfrom eq 'P'
crt '"':cto:'" prefixed to ':
case cfrom eq 'R'
crt 'Replaced with "%", ':
case cfrom eq 'L' or cfrom eq 'N'
case cols eq colf
crt 'Element ':cols:' changed to "':cto:'" in ':
case cols
crt 'Element ':cols:'-':colf:' changed to "':cto:'" in ':
end case
if chng eq 1
then crt '1 line matching "':patt:'"'
else crt chng:' lines matching "':patt:'"'
end
return
parse.pattern:
* bits<1> are the pattern pieces
* <2> quote or 'p'attern flag
* <3> partial patterns
cntr = 1
bits = ''
flag = ''
good = true
first = true
xxno = len(patt)
gosub quote.pattern
for xx = 1 to xxno
bit = patt[xx,1]
begin case
case bit = flag
flag = ''
first = true
cntr = cntr + 1
case flag ne ''
bits<1,cntr> = bits<1,cntr>:bit
case index(qt,bit,1)
bits<2,cntr> = bit
flag = bit
case first
if not(bit matches '1n') then
good = false
return
end
first = false
bits<2,cntr> = 'p'
bits<1,cntr> = bits<1,cntr>:bit
if bit eq '0' then bits<3,cntr> = patt[xx+2,xxno]
case 1
if not(index('AaNnXx',bit,1)) then
good = false
return
end
bits<1,cntr> = bits<1,cntr>:oconv(bit,'mcu')
first = true
cntr = cntr + 1
end case
next xx
cntr = cntr - 1
return
quote.pattern:
* Adds quotes to the pattern if required
* If they use any quotes at all, we don't do a thing
if index(patt,'"',1) then return
if index(patt,'\',1) then return
if index(patt,"'",1) then return
xx = 1
temp = ''
test = ''
loop
left = patt[xx,2]:'*'
if index('0123456789',left[1,1],1) and index('AaNnXx',left[2,1],1) then
if test ne '' then temp := "'":test:"'"
temp := patt[xx,2]
test = ''
xx += 1
end else test := patt[xx,1]
until xx gt xxno do
xx += 1
repeat
patt = temp
if test ne '' then patt := "'":test:"'"
return
parse.temp:
temp = ''
posn = 1
xxno = len(line)
for xx = 1 to cntr
what = bits<1,xx>
type = bits<2,xx>
nmbr = what[1,1]
begin case
case xx gt colf
temp<xx> = line[posn,xxno]
xx = cntr
case type ne 'p'
temp<xx> = line[posn,len(what)]
posn = posn + len(what)
case xx = cntr
temp<xx> = line[posn,xxno]
case nmbr = '0'
* look to match the rest of the line with the partial pattern
test = bits<3,xx>
yy = posn
bit = ''
loop
until yy gt xxno do
chit = line[yy,xxno]
until chit matches test do
bit := chit[1,1]
yy += 1
repeat
posn += len(bit)
temp<xx> = bit
case 1
bit = line[posn,nmbr]
posn += len(bit)
temp<xx> = bit
end case
next xx
temp<cols> = cto
for xx = cols+1 to colf
temp = delete(temp,cols+1)
next xx
convert am to '' in temp
return
get.lines:
stub = '"Q"uit, or starting line > '
pick = 1
gosub get.rope; dawn = rope
dawn = upcase(trim(dawn))
if dawn eq '' then dawn = 'Q'
if dawn[1,1] eq 'Q' then temp = false ; crt ; return
if not(dawn matches '1N0N') then
crt
crt 'Nothing done - starting and ending lines must be numeric.'
gosub bad.comd ; return
end
if dawn gt dcount(temp,am) then
crt
crt 'Nothing done - record does not have that many lines.'
gosub bad.comd ; return
end
stub = stub:dawn:' ':', ending line > '
pick = dcount(temp,am)
gosub get.rope; dusk = rope
dusk = upcase(trim(dusk))
if dusk eq '' then dusk = 'Q'
if dusk[1,1] eq 'Q' then temp = false ; crt ; return
if not(dusk matches '1N0N') then
crt
crt 'Nothing done - starting and ending lines must be numeric.'
gosub bad.comd ; return
end
if dusk gt dcount(temp,am) then
dusk = dcount(temp,am)
crt begn:'File is ':onam:': "Q"uit, or starting line > ':dawn:', ':dusk:
end
temp = field(temp,am,dawn,dusk-dawn+1)
crt
return
parse.bite:
temp = ''
loop
while bite ne '' do
bite = trimf(bite)
xx = fold
if count(bite[1,xx],' ') and trim(bite[xx+1,1]) ne '' then
loop
until trim(bite[xx,1]) eq '' do
xx -=1
repeat
temp<-1> = bite[1,xx-1]
end else
temp<-1> = bite[1,xx]
end
bite = bite[xx+1,len(bite)]
repeat
return
show.help:
crt
if help eq '' then
help = ''
help<-1> = ' ':verb:' version ':help.def
help<-1> = ' This program can be called with the following formats:'
help<-1> = " ":verb:" file and record id's are prompted for"
help<-1> = " ":verb:" file record id's are prompted for"
help<-1> = " ":verb:" file id ":view:" the record 'id' in 'file'"
help<-1> = " ":verb:" file id id... ":view:" multiple records in 'file'"
help<-1> = " ":verb:" file * ":view:" all records in 'file'"
help<-1> = " SELECT may precede '":verb:" file' command"
help<-1> = ' Special ASCII characters may be entered as:'
help<-1> = ' ^nnn where nnn is the decimal character code (like ^027)'
help<-1> = ' ^ will enter a single UP ARROW character.'
help<-1> = ' The following commands may be used in the Editor:'
help<-1> = 'A# - Do the last Append command again for # lines.'
help<-1> = "A# any - Append 'any' to # lines (default 1)."
help<-1> = 'B + Set the current line pointer to the BOTTOM line.'
help<-1> = "B# any - BREAK # lines (default 1) after string 'any' into two lines."
help<-1> = 'BC# posn = Break Column - Break # lines (default 1) after posn into two.'
help<-1> = 'BCD# posn = Break Column and Discard the second part.'
help<-1> = 'BCK# posn = Break Column and Keep only the second part.'
help<-1> = 'BCR# posn = Break Column and Reverse the order of the two parts.'
help<-1> = 'BCS# posn = Break Column and Swap the parts about the character at posn.'
help<-1> = "BD# any - BREAK after string 'any' and Discard the second part."
help<-1> = "BK# any - BREAK after string 'any' and Keep only the second part."
help<-1> = "BR# any - BREAK after string 'any' and Reverse the order of the two parts."
help<-1> = "BS# any - BREAK after string 'any' and Swap the parts about 'any'."
help<-1> = 'BLEACH ON/OFF# Switch colourisation flag.'
help<-1> = 'BLOCK ON/OFF + Switch block operation confirmation flag.'
help<-1> = ' If neither ON nor OFF is used, then toggle BLOCK flag.'
help<-1> = "C - Do the last 'CHANGE' command again."
help<-1> = 'C/// - CHANGE one or more lines. Full formats is:'
help<-1> = ' C[#]/from/to/[G][S]'
help<-1> = ' where / - is any delimiter character.'
help<-1> = ' # - number of lines to CHANGE (default 1).'
help<-1> = ' from - is the character string to be replaced.'
help<-1> = ' to - is the character string to substitute.'
help<-1> = " G - 'G'lobal flag - CHANGE all instances in line."
help<-1> = " S - 'S'how flag - display all changes made."
help<-1> = 'CASE ON/OFF + Switch CASE flag for FL, FLA, L, LA, LN, LNA commands.'
help<-1> = ' If neither ON nor OFF is used, then toggle CASE flag.'
help<-1> = ' OFF means that the commands are not case sensitive.'
help<-1> = "CAT - Synonym for 'J'oin."
help<-1> = 'CD + Show or change the command delimiter.'
help<-1> = ' (this is the input for a blank line).'
help<-1> = 'CLEAR # Clear the kept buffer.'
help<-1> = 'CM/// - ChangeMatch one or more lines. Full formats is:'
help<-1> = ' CM[#]/pattern[/range/to]'
help<-1> = ' where / - is any delimiter character.'
help<-1> = ' # - number of lines to CHANGE (default 1).'
help<-1> = ' pattern - is the pattern match for the line.'
help<-1> = ' to - is the character string to substitute/add.'
help<-1> = ' range - Can be numeric, which field(s) to change,'
help<-1> = " or 'A'ppend or 'P'refix to the line,"
help<-1> = " or 'D'elete, 'R'eplace, 'L'ocate (default) the line."
help<-1> = " EG 'CM/6X' will scan to the line matching '6X'."
help<-1> = " Also; 'N'ot - locate the next non-matching line."
help<-1> = 'COL + Display relative COLUMN POSITIONS on the Terminal.'
help<-1> = 'COPY # Copy the predefined block to the kept buffer.'
help<-1> = 'COPY# # Copy the next # lines to the kept buffer.'
help<-1> = 'COPYx/y # Copy x lines starting at line y to the kept buffer.'
help<-1> = 'COPY/x/y # Copy lines from x to y inclusive to the kept buffer.'
help<-1> = "COUNT#/any + Count of 'any' in next # lines (default 1)."
help<-1> = "CRT xxxx - Inserts a line CRT 'xxxx = ':xxxx"
help<-1> = ' Use double quote or backslash as delimiter to change quotes.'
help<-1> = 'CUT = Move the predefined block to the kept buffer.'
help<-1> = 'CUT# = Move the next # lines to the kept buffer.'
help<-1> = 'CUTx/y = Move x lines starting at line y to kept buffer.'
help<-1> = 'CUT/x/y = Move lines from x to y inclusive to kept buffer.'
help<-1> = 'D + Display the current line.'
help<-1> = 'DE - DELETE the current line.'
help<-1> = "DE# - DELETE '#' lines (default 1)."
help<-1> = "DE#/any - DELETE as above, but only if the line contains 'any'."
help<-1> = "DISPLAY xxxx - Inserts a line DISPLAY 'xxxx = ':xxxx"
help<-1> = ' Just like CRT, handy to distinguish debug code.'
help<-1> = 'DROP - Remove the predefined block.'
help<-1> = "DTX any + Convert decimal string 'any' to hexadecimal and display it."
help<-1> = 'DUP - DUPLICATE the current line.'
help<-1> = "DUP# - DUPLICATE the current line '#' times."
help<-1> = 'EC + Edit a called subroutine in this file.'
help<-1> = 'ECS # Edit the command stack.'
help<-1> = 'EF# + Edit fields delimited by CHAR(#) as lines.'
help<-1> = 'EI + Edit the included code.'
help<-1> = 'EIT + Edit I-type (not just a split on semi-colon).'
help<-1> = 'EK # Edit the kept buffer.'
help<-1> = 'EPR + Edit the prestored commands.'
help<-1> = 'EPR# # Edit prestored commqnd #.'
help<-1> = 'ESS # Edit Search Stack.'
help<-1> = 'ESV + Edit subvalues as 1ines.'
help<-1> = 'ET # Edit the line tabs.'
help<-1> = 'EV + Edit multivalues as lines.'
help<-1> = 'EW + Edit words as lines.'
help<-1> = 'EXIT (EX) + QUIT - EXIT the program.'
help<-1> = 'EXITK (EXK) + QUITKill - EXIT the program, abandon any active SELECT list.'
help<-1> = 'FD - DELETE the entire record from the file.'
help<-1> = 'FI - FILE the record. You can also process it.'
help<-1> = ' FIB = BASIC, FIC = CATALOG, FIR = RUN'
help<-1> = ' You can have up to three processes (EG. FIBCR).'
help<-1> = ' You can modify BASIC with D for DEBUGGING (EG. FIBD).'
help<-1> = ' You can modify CATALOG with L for LOCAL (EG. FICL).'
help<-1> = 'FILE - Synonym for SAVE.'
help<-1> = 'FL + Find the next Label.'
help<-1> = "FL any + Find the label 'any' or matching pattern 'any'."
help<-1> = 'FL# + Find (display) the labels in next # lines.'
help<-1> = 'FLA + Find label above this line.'
help<-1> = 'FM + Find Matching logic by position.'
help<-1> = 'FMA + Find Matching logic by position above this line.'
help<-1> = 'FOLD/length - Split current line (on blanks if possible) to fit width.'
help<-1> = 'FORMAT (FOR) + FORMAT a BASIC program to show logical structure by'
help<-1> = ' indenting. This has the following keywords;'
help<-1> = " '-Mx' = Set margin to x."
help<-1> = " '-Iy' = Set Indentation to y."
help<-1> = " '-A' = Align comments with code."
help<-1> = " '-N' = No CASE indentation."
help<-1> = " '-C' = Compress - same as '-M0 -I1 -A -N'."
help<-1> = "G# + GO TO line '#' ('G' is optional)."
help<-1> = 'HELP (H) + Prompt user to display HELP information on the Terminal.'
help<-1> = "HELP any + Display HELP information on Terminal for 'any'."
help<-1> = 'HELP NEW + Display HELP information on new features.'
help<-1> = 'HEX + Displays the current line in hexadecimal.'
help<-1> = 'I - INSERT new lines AFTER the current line. Prompt for'
help<-1> = ' successive lines. INPUT until NULL input. An INPUT line'
help<-1> = ' of a single space will store an empty line.'
help<-1> = "I any - INSERT (INPUT) the line 'any' AFTER the current line."
help<-1> = "I#/any - INSERT # lines of 'any' AFTER the current line."
help<-1> = "IC any - IConv the line using the conversion 'any'."
help<-1> = 'IN command - Insert the results of the command AFTER the current line.'
help<-1> = ' It is not a good idea to use a command requiring input.'
help<-1> = "J#/any - Join next '#' lines (default 1), separated by 'any'."
help<-1> = "KEEP name # Copy the record 'name' into the kept buffer."
help<-1> = " line #'s will be prompted."
help<-1> = "KEEP f name # Copy the record 'name' from file 'f' into the kept buffer,"
help<-1> = " line #'s will be prompted."
help<-1> = 'KEEPA # KEEPAll - KEEP without line # prompting.'
help<-1> = 'KEPT (K) # Display the kept buffer.'
help<-1> = "L + Repeat the last 'LOCATE' command (L, LA, LN, or LNA)."
help<-1> = "L any + LOCATE the next line that contains the string 'any'."
help<-1> = "L#/any/10-20 + LOCATE in next # lines those with 'any' in columns 10 to 20."
help<-1> = " So 'L#' effectively lists # lines."
help<-1> = "L#!any!THING # LOCATE in next # lines those with 'any' OR 'THING'."
help<-1> = "L#&any&THING # LOCATE in next # lines those with 'any' AND 'THING'."
help<-1> = ' ! and & work this way for LA, LN, and LNA commands too.'
help<-1> = 'LA#/any/1-20 + Locate lines above this one (reverse order).'
help<-1> = "LC# - Change '#' lines to lower case (default 1)."
help<-1> = 'LC# any Comments and quoted strings are unchanged.'
help<-1> = "LL#/length + Show lines 'length' or longer (null '#' is a search)."
help<-1> = "LN#/any/1-20 + LOCATE NOT - line without 'any' in columns 10 to 20."
help<-1> = "LNA#/an/1-20 + LOCATE line above this without 'an' in columns 1 to 20."
help<-1> = "LOAD name - LOAD the record 'name' from the current FILE,"
help<-1> = " line #'s will be prompted."
help<-1> = "LOAD f name - LOAD the record 'name' from file 'f',"
help<-1> = " line #'s will be prompted."
help<-1> = 'LOADA - LOADAll - LOAD without line # prompting.'
help<-1> = 'LD - Synonym for LOAD.'
help<-1> = 'LDA - Synonym for LOADA.'
help<-1> = 'M pattern + Search for a line matching the pattern.'
help<-1> = 'MACRO# + Toggle macro recording into #th PRESTORE command.'
help<-1> = 'MERGE (ME) = Merge a copy of the predefined block after the current line.'
help<-1> = 'MERGEx/y = Merge x lines starting at line y.'
help<-1> = 'MERGE/x/y = Merge lines starting at x to line y inclusive.'
help<-1> = 'MOVE (MV) - Move the predefined block to after the current line.'
help<-1> = 'MOVEx/y = Move the x lines starting at line y.'
help<-1> = 'MOVE/x/y = Move the lines starting at x to line y inclusive.'
help<-1> = 'NUM + Toggle the line numbering.'
help<-1> = "NULL/symbol + Change the null line input for 'I' to 'symbol'."
help<-1> = "OC# any - OConv '#' lines using the conversion 'any'."
help<-1> = 'OOPS - RESTORE the record to the condition prior to last change.'
help<-1> = "OUT# # Outline (labels, gotos, gosubs) for '#' lines (default all)."
help<-1> = 'OUT# CEPS Show Calls, Executes, Performs, and caSe also (* for all).'
help<-1> = 'P + PRINT on Terminal one page worth of lines.'
help<-1> = "P# + PRINT on Terminal '#' lines starting with the current line."
help<-1> = "PA# + PRINT the current line and the prior '#' lines,"
help<-1> = ' do not change the current line pointer.'
help<-1> = "PASTE = Paste the kept buffer after the current line'."
help<-1> = "PASTE name = Copy the kept buffer under the specified 'name'."
help<-1> = "PASTE f name = Copy the kept buffer as record 'name' in file 'f'."
help<-1> = 'PE + Page Edit mode.'
help<-1> = "PL# + PRINT the current line and the next '#' lines,"
help<-1> = ' do not change the current line pointer.'
help<-1> = "PP# + PAGE.PRINT a window of '#' lines around the current line,"
help<-1> = ' do not change the current line pointer.'
help<-1> = 'PR + Show the PRESTORE commands.'
help<-1> = 'PR# + Run the #th PRESTORE command.'
help<-1> = 'PR#/any + Change the #th PRESTORE command.'
help<-1> = ' where / - is any delimiter character which will also be'
help<-1> = ' used as the command separator.'
help<-1> = 'QUIT (Q) + QUIT - EXIT the program.'
help<-1> = 'QUITK (QK) + QuitKill - EXIT the program, abandon any active SELECT list.'
help<-1> = 'R - Replace the line with prompted for text.'
help<-1> = "R any - REPLACE this line with 'any'."
help<-1> = "R#/any - REPLACE # lines with 'any'."
help<-1> = 'R/// - CHANGE one or more lines (same as C/// command).'
help<-1> = "RA = Show last 20 'CHANGE' commands."
help<-1> = "RA# = Repeat #th 'CHANGE' command."
help<-1> = 'RELEASE + RELEASE the update record LOCK for this file.'
help<-1> = "S - Show last 20 'LOCATE' commands."
help<-1> = "S# - Repeat #th 'LOCATE' command."
help<-1> = 'SAVE - SAVE a copy of this record under the original name.'
help<-1> = "SAVE name - SAVE a copy of this record under the specified 'name'."
help<-1> = "SAVE f name - SAVE a copy of this record as record 'name' in file 'f'."
help<-1> = 'SEQ#//// - Build a sequence. Format is:'
help<-1> = ' SEQ#/from/base/inc/cols'
help<-1> = ' where / - is any delimiter character.'
help<-1> = ' # - number of lines to CHANGE (default 1).'
help<-1> = ' from - is the character string to be replaced.'
help<-1> = ' base - is the start number (defaults to 1).'
help<-1> = ' inc - is the increment (defaults to 1).'
help<-1> = ' cols - restricts the change to a column range.'
help<-1> = "SHOW ON/OFF + toggle overriding 'S'how flag for 'C' command."
help<-1> = " OFF won't show more than a page of changes."
help<-1> = ' If neither ON nor OFF is used, then toggle SHOW flag.'
help<-1> = "SORT seq - Sort the predefined block (seq defaults to 'AL')."
help<-1> = "SORTU seq # Sort unique predefined block ('AL' default seq)."
help<-1> = 'SPACE ON/OFF + Switch SPACE flag for L, LA, LN, LNA commands.'
help<-1> = ' If neither ON nor OFF is used, then toggle SPACE flag.'
help<-1> = ' OFF means that the commands will ignore spaces and tabs.'
help<-1> = 'SPOOL + SPOOL entire record to PRINTER.'
help<-1> = "SPOOL# + SPOOL '#' lines to the PRINTER."
help<-1> = 'SPOOLHELP + SPOOL the HELP listing to the default PRINTER.'
help<-1> = "SPOUT# # SPOO outline (labels, gotos, gosubs) for '#' lines (default all)."
help<-1> = 'SPOUT# CEPS Show Calls, Executes, Performs, and caSe also (* for all).'
help<-1> = "STAMP - INSERT a 'last modified' stamp into the record, which"
help<-1> = " begins with a '*' (for BASIC 'comment'), and contains the"
help<-1> = ' account name, LOGIN name (if different from account name),'
help<-1> = ' date and time. Used to mark when record was last changed.'
help<-1> = 'SV - Synonym for SAVE.'
help<-1> = 'T + Set current line to the TOP (before first line).'
help<-1> = "TC# - Change '#' lines to text or mixed case (default 1)."
help<-1> = 'TC# any Comments and quoted strings are unchanged.'
help<-1> = "TRIM# - TRIM '#' lines (default 1)."
help<-1> = "TRIM# a b = TRIM '#' lines of character 'a' with argument 'b'."
help<-1> = "TRIMB# - TRIMB '#' lines (default 1)."
help<-1> = "TRIMF# - TRIMF '#' lines (default 1)."
help<-1> = "TRIPLE#/any = Copy '#' lines (default 1) into three clones, joined by 'any'."
help<-1> = "TWIN#/any = Copy '#' lines (default 1) into two clones, joined by 'any'."
help<-1> = "UC# - Change '#' lines to upper case (default 1)."
help<-1> = 'UC# any Comments and quoted strings are unchanged.'
help<-1> = 'UNLOAD - Synonym for SAVE.'
help<-1> = 'V + Version information.'
help<-1> = 'WHERE (W) + Show the item and file being ':view:'ed.'
help<-1> = 'WM + Show or change the word marker.'
help<-1> = 'X + QuitKill - EXIT the program, abandon any active SELECT list.'
help<-1> = 'XEQ - The XEQ command allows a user to execute any legal PERFORM'
help<-1> = ' command from within the program. Upon completion of the'
help<-1> = ' command, control will be returned back to the program.'
help<-1> = "XTD any + Convert hexadecimal string 'any' to decimal and display it."
help<-1> = '/any + Same as L99999999/any - NOTE you are left at the bottom.'
help<-1> = ".A# any + APPEND 'any' to command '#' (default 1)."
help<-1> = ".C#/// + CHANGE stack command '#' (default 1). Syntax is like 'C'."
help<-1> = ".D# + DELETE stack command '#' (default 1)."
help<-1> = ".I# any + INSERT 'any' at stack position '#' (default 1)."
help<-1> = ".L# + LIST on the Terminal the last '#' stack commands."
help<-1> = ".R# + RECALL (copy) command '#' to stack position 1."
help<-1> = ".S# n m + SAVE stack n to m as prestore '#' (all default to 1)."
help<-1> = ".U# # UPCASE stack command '#' (default 1)."
help<-1> = ".UL# # lower case stack command '#' (default 1)."
help<-1> = ".UT# # text case stack command '#' (default 1)."
help<-1> = ".X# + EXECUTE stack command '#' (default 1)."
help<-1> = ' The command will be put in stack position 1.'
help<-1> = "+# + Advance current line pointer by '#' lines (default 1)."
help<-1> = "-# + Back up current line pointer by '#' lines (default 1)."
help<-1> = "\ # Set a line tag with default label like 'T#'."
help<-1> = "\any # Set a line tag labelled 'any'."
help<-1> = '\\ # Clear the line tags.'
help<-1> = "]any # Go to the line tag 'any'."
help<-1> = "[any # Go to the line tag 'any'."
help<-1> = '] # Go to the next line tag.'
help<-1> = '[ # Go to the previous line tag.'
help<-1> = ']] # Display the line tags.'
help<-1> = '[[ # Display the line tags.'
help<-1> = "# + Set the current line pointer to the '#' line."
help<-1> = '<# + Sets the starting block pointer to # (current line default).'
help<-1> = '># + Sets the ending block pointer to # (current line default).'
help<-1> = '<># # + Set both block pointers at the same time.'
help<-1> = '^ + Switch UP ARROW on/off to show non-printing characters as'
help<-1> = ' ^nnn where nnn is the decimal equivalent of ASCII code.'
help<-1> = '? + Show various parameters - easier to use than explain.'
end
rest = trim(upcase(rest))
if rest eq am then
hard = true
rest = ''
end else hard = false
disp = ''
stub = ''
if rest eq '' then flag = true else flag = false
if rest eq 'NEW' then disp = 'New Features':am
good = false
xxno = dcount(help,am)
for xx = 1 to xxno
temp = help<xx>
bite = temp[1,len(rest)]
bit = temp[14,1]
if index('-+=#',bit,1)
then temp = temp[1,13]:'-':temp[15,huge]
else bit = ''
if bit ne '' then
flag = false
if bit eq '#' and rest eq 'NEW' then flag = true
if (bit eq '#' or bit eq '+') and rest eq '' then flag = true
if not(viewflag) then
if bit eq 'eq' and rest eq 'NEW' then flag = true
if bit eq '=' or bit eq '-' and rest eq '' then flag = true
end
end
if not(flag) and rest ne '' and bite eq rest then
if bit eq '#' or bit eq '+' then flag = true
if not(viewflag) then
if bit eq '=' or bit eq '-' then flag = true
end
end
if flag then
disp<-1> = temp
good = true
end
next xx
if not(good) then
disp := am
disp<-1> = 'No explanation of "':rest:'" is available.'
disp<-1> = 'For a list of words that have explanations, type "HELP".'
disp := am
end
if hard then gosub print.disp else gosub show.disp
return
show.disp:
write disp on voc,'&DISP.':whom
if stub eq '' then stub = 'Press return to continue showing explanation, Q to quit'
xxno = dcount(disp,am)
pg = 0
for xx = 1 to xxno
pg += 1
if pg ge system(3) then
loop
rlen = 1
gosub get.rope; answ = rope
crt begn:ceol:
answ = trim(upcase(answ))[1,1]
until index('QT-',answ,1) do
repeat
if answ eq 'Q' then return
if answ eq 'T' then xx = 1
if answ eq '-' then
xx -= 2*(system(3)-1)
if xx lt 1 then xx = 1
end
pg = 1
end
crt disp<xx>
next xx
disp = ''
return
print.disp:
printer on
heading upcase(verb):" help file ":timedate():"'LL'"
xxno = dcount(disp,am)
for xx = 1 to xxno
print disp<xx>
next xx
printer close
return
get.page.comd:
gosub get.keyc
do.page.comd:
locate(keyc,keys;cpos) then cpos = acts<cpos> else cpos = 0
begin case
case cpos eq uarr ;* up key
if here le 1 then crt bell:; return
gosub check.page
here -= 1
if prow le 1 then
ptop = ptop - botl
if ptop lt 1 then ptop = 1
gosub disp.page
end
gosub get.line; temp = line
case cpos eq darr ;* down key
if here ge last then crt bell:; return
gosub check.page
here += 1
if prow ge botl then
ptop = ptop + botl
if ptop ge last then ptop = last - botl + 1
if ptop le 1 then ptop = 1
gosub display.page
end
gosub get.line; temp = line
case cpos eq larr ;* left key
if pchr le 1 then crt bell:; return
pchr -= 1
if pchr lt ppos then
gosub check.page
gosub disp.page
end
case cpos eq rarr ;* right key
pchr += 1
if pchr-ppos ge span then
gosub check.page
gosub disp.page
end
case cpos eq upag ;* page up key
gosub check.page
ptop -= botl
if ptop lt 1 then ptop = 1
here -= botl
if here lt 1 then here = 1
pchr = 1
gosub get.line; temp = line
gosub disp.page
case cpos eq dpag ;* page down key
gosub check.page
ptop = ptop + botl
if ptop ge last then ptop = last - botl + 1
here = here + botl
if here gt last then here = last
pchr = 1
gosub get.line; temp = line
gosub disp.page
case cpos eq lpag ;* start of line key
pchr = 1
if pchr lt ppos then gosub check.page; gosub disp.page
case cpos eq rpag ;* end of line key
pchr = len(temp)+1
if pchr lt ppos then gosub check.page; gosub disp.page
if pchr-ppos ge span then
gosub check.page
gosub disp.page
end
case cpos eq tpag ;* top page key
gosub check.page
here = 1
ptop = 1
pchr = 1
gosub disp.page
gosub get.line; temp = line
case cpos eq bpag ;* bottom page key
gosub check.page
here = last
ptop = last - botl + 1
gosub get.line
pchr = len(line)+1
gosub disp.page
gosub get.line; temp = line
case cpos eq escp ;* escape key
if this ne that then
crt @(0,botl):ceol:revb:'ABANDONING CHANGES':revf
end
this = that
here = savl<1>
gosub set.record
mode = 'LINE'
case cpos eq phlp ;* help key
gosub check.page
gosub page.help
case cpos eq zoom ;* Go to line key
crt bott:
stub = 'Go to line :'
stay = pchr
gosub get.rope; numb = trim(rope)
pchr = stay
crt bott:revb:'Press <F1> for help.':revf:
if not(numb matches '1N0N') then numb = here
if numb gt last then numb = last
if numb eq here then return
gosub check.page
here = numb
ptop = here
pchr = 1
gosub disp.page
gosub get.line; temp = line
case cpos eq skey ;* forward search
crt bott:
stub = 'Search: ':'> '
stay = pchr
pick = lastfind; gosub get.rope; lastfind = rope
pchr = stay
crt bott:revb:'Press <F1> for help.':revf:
if lastfind eq '' then return
* is it in this line or the rest of the item?
test = index(temp[pchr+1,huge],lastfind,1)
save = here
gosub check.page
if test then
test += pchr
end else
dawn = here+1
dusk = last
for here = dawn to dusk until test
gosub get.line
test = index(line,lastfind,1)
if test then save = here
next here
end
if test then
if save lt ptop or save ge (ptop+botl) then ptop = save
here = save
pchr = test
gosub disp.page
end else here = save
gosub get.line; temp = line
case cpos eq rkey ;* reverse search
crt bott:
stub = 'Search: ':'< '
stay = pchr
pick = lastfind; gosub get.rope; lastfind = rope
pchr = stay
crt bott:revb:'Press <F1> for help.':revf:
if lastfind eq '' then return
* is it in this line before the cursor position or the rest of the item above?
test = index(temp[1,pchr-1],lastfind,1)
save = here
gosub check.page
if not(test) then
dawn = 1
dusk = here-1
for here = dusk to dawn step -1 until test
gosub get.line
what = count(line,lastfind)
if what then
test = index(line,lastfind,what)
save = here
end
next here
end
if test then
if save lt ptop or save ge (ptop+botl) then ptop = save
here = save
pchr = test
gosub disp.page
end else here = save
gosub get.line; temp = line
case not(sec.write.flg)
crt bell:
case cpos eq delc ;* delete character key
if temp eq '' then return
if pchr eq 1 then
temp = temp[2,len(temp)]
end else
temp = temp[1,pchr-1]:temp[pchr+1,len(temp)]
end
crap = temp[pchr,span-pcol]
convert badc to gudc in crap
crt @(pcol,prow):ceol:crap:
case cpos eq dell ;* delete line key
del this<here>
gosub set.record
gosub disp.page
gosub get.line; temp = line
case cpos eq delr ;* delete to end of line key
if pchr gt len(temp) then
if here ge last then crt bell:; return
line = fmt(temp,'l#':pchr-1):this<here+1>
del this<here>
this<here> = line
gosub set.record
gosub disp.page
gosub get.line; temp = line
end else
temp = temp[1,pchr-1]
this<here> = temp
memr(cell)<lnum> = temp
line = temp
crt @(pcol,prow):ceol:
end
case cpos eq back ;* backspace key
if pchr eq 1 then crt bell:; return
pchr -= 1
temp = temp[1,pchr-1]:temp[pchr+1,len(temp)]
if pchr lt ppos then
gosub check.page
gosub disp.page
end else
pcol = rem(pchr-1,span)
crt @(pcol,prow):ceol:
crap = temp[pchr,span-pcol]
convert badc to gudc in crap
crt crap:
end
case cpos eq carr ;* carriage return key
if pchr eq 1 then
line = ''
end else
line = temp[1,pchr-1]
temp = temp[pchr,len(temp)]
end
if lnum eq 0 then lnum = 1
memr(cell)<lnum> = line
last += 1
lnum += 1
line = temp
gosub insert.line
gosub reset.record
here += 1
pchr = 1
if prow ge botl then
ptop = ptop + botl
if ptop ge last then ptop = last - botl + 1
if ptop le 1 then ptop = 1
gosub display.page
end else gosub disp.page
gosub get.line; temp = line
case cpos eq togg ;* toggle mode key
if mode<2> eq 'Ins' then
mode<2> = 'Rep'
end else mode<2> = 'Ins'
case cpos eq writ ;* write away data key
gosub check.page
mode = 'LINE'
case seq(keyc) lt 28 or seq(keyc) gt 127 or len(keyc) gt 1
crt bell:
case seq(keyc) eq 30 or seq(keyc) eq 31
crt bell:
case 1
if seq(keyc) eq 28 then keyc = char(252)
if seq(keyc) eq 29 then keyc = char(253)
if pchr and len(temp) lt (pchr-1) then
temp = temp:str(' ',pchr)
temp = temp[1,pchr-1]
end
if mode<2> eq 'Ins'
then offset = pchr
else offset = pchr+1
if pchr eq 1
then temp = keyc:temp[offset,len(temp)]
else temp = temp[1,pchr-1]:keyc:temp[offset,len(temp)]
if mode<2> eq 'Ins' then
crt @(pcol,prow):ceol:
crap = temp[pchr,span-pcol]
end else crap = keyc
convert badc to gudc in crap
crt @(pcol,prow):crap:
pchr += 1
if pchr-ppos ge span then
gosub check.page
gosub disp.page
end
end case
return
check.page:
if '*':temp ne '*':line then
memr(cell)<lnum> = temp
gosub reset.record
end
return
page.help:
gosub clear.page
if pagehelp eq '' then
if sec.write.flg then
pagehelp = ''
pagehelp<-1> = ' Page editing help'
pagehelp<-1> = ''
pagehelp<-1> = ' Cursor movement keys Line movement keys'
pagehelp<-1> = ''
pagehelp<-1> = ' UP = <UP arrow> or ^Z LEFT END = <Home> or ^A'
pagehelp<-1> = ' DOWN = <DOWN arrow> or ^J RIGHT END = <End> or ^E'
pagehelp<-1> = ' LEFT = <LEFT arrow> or ^U GO TO LINE = ^G'
pagehelp<-1> = ' RIGHT = <RIGHT arrow> or ^F (prompts for desired line)'
pagehelp<-1> = ''
pagehelp<-1> = ' Page movement keys Deleting keys'
pagehelp<-1> = ''
pagehelp<-1> = ' PREVIOUS = <Page Up> or ^P DELETE CHAR = <Delete> or ^D'
pagehelp<-1> = ' NEXT = <Page Down> or ^N DELETE LINE = <Ctrl-Home> or ^X'
pagehelp<-1> = ' TOP = <Ctrl-Page Up> or ^T DELETE TO EOL = <Ctrl-End> or ^K or ^R'
pagehelp<-1> = ' BOTTOM = <Ctrl-Page Down> or ^B'
pagehelp<-1> = ' <Ctrl-]> = Value Mark'
pagehelp<-1> = ' <Backspace> is destructive <Ctrl-\> = Sub-value Mark'
pagehelp<-1> = ' <Enter> splits the line'
pagehelp<-1> = ' <Insert> or <Tab> toggles between the insert and overwrite modes'
pagehelp<-1> = ''
pagehelp<-1> = ' <F2> or ^W Returns to line editor mode WITH changes'
pagehelp<-1> = ' <Esc> or ^Q Returns without changes'
end else
pagehelp = ''
pagehelp<-1> = ' Page viewing help'
pagehelp<-1> = ''
pagehelp<-1> = ' Cursor movement keys Line movement keys'
pagehelp<-1> = ''
pagehelp<-1> = ' UP = <UP arrow> or ^Z LEFT END = <Home> or ^A'
pagehelp<-1> = ' DOWN = <DOWN arrow> or ^J RIGHT END = <End> or ^E'
pagehelp<-1> = ' LEFT = <LEFT arrow> or ^U GO TO LINE = ^G'
pagehelp<-1> = ' RIGHT = <RIGHT arrow> or ^F (prompts for desired line)'
pagehelp<-1> = ''
pagehelp<-1> = ' Page movement keys '
pagehelp<-1> = ''
pagehelp<-1> = ' PREVIOUS = <Page Up> or ^P '
pagehelp<-1> = ' NEXT = <Page Down> or ^N '
pagehelp<-1> = ' TOP = <Ctrl-Page Up> or ^T'
pagehelp<-1> = ' BOTTOM = <Ctrl-Page Down> or ^B'
pagehelp<-1> = ''
pagehelp<-1> = ''
pagehelp<-1> = ' <Esc> or ^Q Returns without changes'
end
end
disp = pagehelp ; stub = ''
gosub show.disp
crt bott:
stub = 'Press RETURN to continue'
gosub get.rope
gosub display.page
return
get.line:
line = ''
if here eq 0 then
cell = 1
lnum = 0
return
end
if here gt last then return
cell = int((here-1)/cellsize) + 1
coff = rem(here,cellsize)
if ooff and ocel eq cell and ooff eq coff - 1 then
lnum = ooff ; ooff = coff
end else
tlin = memr(cell)
lnum = 0 ; ocel = cell ; ooff = coff
end
loop
remove bite from tlin setting dlim
line = line:bite
while dlim do
if dlim eq 2 then
lnum += 1
if lnum eq coff then exit
line = ''
end else
line = line:char(256-dlim)
end
repeat
if not(dlim) then lnum += 1
return
delete.lines:
chng = 0
if dawn gt dusk then
crt 'No deletion possible - ':dawn:' > ':dusk:'.'
return
end
gosub savethat
chng = dusk - dawn + 1
begin case
case dawn le 1 and dusk ge last
krj = ''
this = ''
beg = 0
fin = 0
case dusk ge last
temp = index(this,am,dawn-1)
this = this[1,temp-1]
if beg gt dawn then beg = 0
if fin gt dawn then fin = 0
for xx = dcount(krj<1>,vm) to 1 step -1
if krj<2,xx> gt dawn then
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1
end
next xx
case dawn eq 1
temp = index(this,am,dusk)
this = this[temp+1,len(this)]
if beg le dusk then beg = 0 else beg = beg - chng
if fin le dusk then fin = 0 else fin = fin - chng
for xx = dcount(krj<1>,vm) to 1 step -1
if krj<2,xx> le dusk then
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1
end
next xx
case 1
temp = index(this,am,dawn-1)
temp<2> = index(this,am,dusk)
this = this[1,temp<1>]:this[temp<2>+1,len(this)]
if beg ge dawn and beg le dusk then beg = 0 else
if beg gt dusk then beg -= chng
end
if fin ge dawn and fin le dusk then fin = 0 else
if fin gt dusk then fin -= chng
end
for xx = dcount(krj<1>,vm) to 1 step -1
begin case
case krj<2,xx> gt dusk ; krj<2,xx> -= chng
case krj<2,xx> ge dawn
del krj<1,xx> ; del krj<2,xx> ; krj<3> -= 1
end case
next xx
end case
begin case
case here gt dusk
here = here - dusk + dawn - 1
case here gt dawn
here = dawn
end case
gosub set.record
return
check.line:
if '*':temp ne '*':line then
if not(chng) then gosub savethis
chng += 1
memr(cell)<lnum> = temp
if shew or dnum lt plen then gosub display.line
end
return
insert.line:
if here le beg then beg += 1
if here le fin then fin += 1
yyno = dcount(krj<1>,vm)
for yy = 1 to yyno
if krj<2,yy> gt here then krj<2,yy> += 1
next yy
memr(cell) = insert(memr(cell),lnum,0,0,line)
if lfmt and len(last) gt 3 and len(last) ne llen then gosub get.lfmt
return
display.line:
begin case
case last eq 0
here = 0
gosub get.line
crt begn:'Top of empty record.'
case here eq 0
gosub get.line
crt 'Top.'
case here gt last
crt 'Bottom.'
case 1
gosub get.line
if wild then
xxno = len(line)
temp = ''
for xx = 1 to xxno
bite = line[xx,1]
bite = seq(bite)
if bite ge 127 or bite lt 32 then
$ifdef unidata
bite = '^':fmt(bite,'3/0R')
$else
bite = '^':fmt(bite,'R%3')
$endif
end else bite = char(bite)
temp = temp:bite
next xx
line = temp
end else convert badc to gudc in line
crt begn:ceol:
if lfmt then
blk = ': '
if here eq beg then blk = '< '
if here eq fin then blk = '> '
if here eq beg and here eq fin then blk = '<>'
if lfmt then crt (here lfmt):blk:
end
if bleach then
crt line
end else
if here ge beg and here le fin
then showline = @(-13):@(-5):line:@(-6):@(-14)
* else call SORT.LINE(showline,line,1,len(line),lastfind,caseflag)
else setoff = 1 ; width = len(line) ; gosub getshowline
crt showline
end
dnum += 1
if here eq last then crt 'Bottom at line ':last:'.'
end case
return
clear.page:
for xx = system(3)-1 to 0 step -1
crt @(00,xx):ceol:
next xx
return
display.page:
crt clpg
disp.page:
if pchr lt 1 then pchr = 1
gosub clear.page
gosub get.lfmt
crt bott:revb:'Press <F1> for help.':revf:
crt @(0,0):ceol:revb:
if viewflag
then crt 'Viewing "':item:'" in file "':fnam:'"':
else crt 'Editing "':item:'" in file "':fnam:'"':
crt revf:
if idcnt gt 1 then crt ' <':id:'/':idcnt:'> ':
crt
ppos = int((pchr-1)/span)
ppos = span*ppos+1
save = here:am:lnum:am:cell:am:line
for xx = 1 to botl
here = ptop + xx - 1
gosub get.line
if bleach then
disp = line[ppos,span]
convert badc to gudc in disp
end else
convert badc to gudc in line
disp = line
if here ge beg and here le fin
then showline = @(-13):@(-5):disp[ppos,span]:@(-6):@(-14)
* else call SORT.LINE(showline,disp,ppos,span,lastfind,caseflag)
else setoff = ppos ; width = span ; gosub getshowline
disp = showline
end
crt @(0,xx):disp:
next xx
here = save<1>; lnum = save<2>; cell = save<3>; line = save<4>
return
savethis:
oops = this ; oopc = comi ; oopl = save ; oopf = savl
oopb = beg:am:fin ; oopk = krj
* if level eq 0 then write oops on voc, '&LED.':whom
return
savethat:
oops = this ; oopc = comi ; oopl = here ; oopf = last
oopb = beg:am:fin ; oopk = krj
* if level eq 0 then write oops on voc, '&LED.':whom
return
reset.record:
matbuild this from memr using am
set.record:
gosub parse.record
gosub get.line
if len(last) gt 3 and len(last) ne llen then gosub get.lfmt
return
parse.record:
this = this
ocel = '' ; ooff = ''
last = dcount(this,am)
if last eq 0 then
dim memr(1)
mat memr = ''
cell = 1 ; lnum = 0
return
end
numcells = int((last-1)/cellsize)+1
dim memr(numcells)
mat memr = ''
cell = 1
lnum = 0
for cell = 1 to numcells
memr(cell) = field(this,@am,(cell-1)*cellsize+1,cellsize)
next cell
! line = ''
! loop
! remove bite from this setting mark
! line = line:bite
! begin case
! case mark eq 0
! if line ne '' then
! line = line[1,len(line)]
! end
! memr(cell) = line
! case mark eq 2
! lnum += 1
! if lnum ge cellsize then
! memr(cell) = line
! line = ''
! cell += 1
! lnum = 0
! end else
! line = line:char(256-mark)
! end
! case 1
! line = line:char(256-mark)
! end case
! while mark do
! repeat
cell = 1
lnum = 0
return
locked.record:
stub = 'Record is currently locked by another user. Try again? ':ny:' '
gosub get.rope; answ = rope
answ = upcase(trim(answ))
if answ eq 'PASSWORD' then
lock = false
read this from file, item then goto carry.on
end
if answ[1,1] eq yes[1,1] then goto edit.item
return
exec.that:
temp = temp<1>:' ':fnam:' ':item:temp<2>
if fileinfo(file,3) ne '4' then
crt 'Cannot ':temp:' - must be type 1 or 19'
return
end
execute temp
test = @(0,0)
return
parse.rest:
bite = ''
flag = ''
posn = 1
xxno = len(rest)
for xx = 1 to xxno
bit = rest[xx,1]
if flag eq '' then
if bit eq ' ' then
if bite<posn> ne '' then posn += 1
end else
if index(qt,bit,1) then
flag = bit
if keepquot then bite<posn> = bite<posn>:bit
end else
if bit eq '(' then
flag = ')'
if bite<posn> ne '' then posn += 1
bite<posn> = '('
end else bite<posn> = bite<posn>:bit
end
end
end else
if bit ne flag then
bite<posn> = bite<posn>:bit
end else
if keepquot or bit eq ')' then bite<posn> = bite<posn>:bit
posn += 1
flag = ''
end
end
next xx
return
split.itype:
bite = ''
flag = ''
posn = 1
xxno = len(line)
for xx = 1 to xxno
bit = line[xx,1]
if flag eq '' then
if bit eq ';' then
posn += 1
end else
if index(qt,bit,1) then flag = bit
if bit eq '(' then flag = ')'
bite<posn> = bite<posn>:bit
end
end else
if bit eq flag[1,1] then flag = flag[2,huge]
if bit eq '(' and flag[1,1] eq ')' then flag := ')'
bite<posn> = bite<posn>:bit
end
next xx
return
get.lfmt:
* set up the line format
llen = len(last)
if llen lt 3 then llen = 3
$ifdef unidata
lfmt = llen:'/0R'
$else
lfmt = 'R%':llen
if index(item,'_IType.',1) then lfmt = llen:'@R'
$endif
prmt = '*':str('-',llen-1)
return
leftarr: *
numb = oconv(trim(comi[2,len(comi)]),'MCN')
if numb eq '' then numb = here
if numb gt last then numb = ''
if numb ge 0 then
crt 'Block starts at line ':numb:
beg = numb
if fin and beg gt fin then
crt '; End moved from ':fin:' to ':beg
fin = beg
mov = 1
end else
if fin then mov = fin - beg + 1 else mov = last - beg
crt ' (':mov:' lines)'
end
if numb eq here then gosub display.line
end else crt 'Cannot mark line ':numb
return
rightarr: *
numb = oconv(trim(comi[2,len(comi)]),'MCN')
if numb eq '' then numb = here
if numb gt last then numb = ''
if numb ge 0 then
crt 'Block ends at line ':numb:
fin = numb
if beg gt fin then
crt '; Start moved from ':beg:' to ':fin
beg = fin
mov = 1
end else
if beg then mov = fin - beg + 1 else mov = fin
crt ' (':mov:' lines)'
end
if numb eq here then gosub display.line
end else crt 'Cannot mark line ':numb
return
botharr: *
numb = trim(comi[3,len(comi)])
begin case
case numb matches '1N0N'
numb = numb:am:numb
case numb matches '1N0N"-"1N0N'
numb = field(numb,'-',1):am:field(numb,'-',2)
case numb matches '1N0N" "1N0N'
numb = field(numb,' ',1):am:field(numb,' ',2)
case numb eq ''
numb = here:am:here
case 1
numb = ''
end case
if numb<2> gt last then numb<2> = last
if numb<1> gt last then numb = ''
if numb<2> lt numb<1> then
crt 'Block starts at ':numb<1>:' and ends at ':numb<2>:' => ':
numb = ''
end
if numb ne '' then
beg = numb<1>
fin = numb<2>
if beg eq fin then
crt 'Block starts and ends at line ':beg
end else
crt 'Block starts at ':beg:' and ends at ':fin
end
if here eq beg or here eq fin then
gosub display.line
end
end else crt 'Cannot mark Block'
return
recalc.posn:
begin case
case posn lt rest and posn le oopl
case posn lt rest and posn gt oopl
posn += numb
case posn ge rest and posn lt (rest+numb)
posn += (here+1-rest)
case posn ge (rest+numb) and posn le oopl
posn -= numb
end case
return
find.label:
temp = field(trimf(line),' ',1)
temp = trim(temp,char(13),'B')
chit = temp[1,1]
begin case
case chit eq '*' or chit eq '!' ; temp = ''
case chit matches '1N' or chit eq '.'
temp = field(temp,'*',1)
temp = field(temp,'!',1)
temp = field(temp,':',1)
test = convert('.0123456789','',temp)
if test ne '' then temp = ''
case chit matches '1A' and index(temp,':',1)
temp = field(temp,':',1)
test = oconv(oconv(temp,'MC/A'),'MC/N')
test = convert('._%$','',test)
if test ne '' then temp = ''
case 1
temp = ''
end case
return
get.answ:
loop
*>
rlen = 1
*>
gosub get.rope
answ = upcase(trim(rope)[1,1])
until answ eq yes[1,1] or answ eq no[1,1] do
crt 'Please answer Y or N'
repeat
crt
return
writerr:
$ifdef qm
if status() eq er$trigger then
crt 'Data validation error: ': @trigger.return.code
end else
crt 'Write error ': status():' (o/s error %2) - Data not saved. Original data will be lost if you leave the editor now.'
end
$else
crt 'Write error ': status():' (o/s error %2) - Data not saved. Original data will be lost if you leave the editor now.'
$endif
return
indenter:
marg = fr(1) ;* the margin
dent = fr(2) ;* the indentation
supp = fr(6) ;* flag - suppress '!' output
astx = not(fr(9)) ;* flag - keep '*' comments on page edge
suit = not(fr(10)) ;* flag - indent 'CASE' statements
dead = 'ACDGHIJKMPQSVXYZ'
push = 'LOOP\WHILE\UNTIL\FOR\THEN\ELSE\BEGIN\LOCKED\ON~ERROR'
pull = 'UNTIL\WHILE\REPEAT\NEXT\END'
convert '\' to am in push
convert '\' to am in pull
skip = ';:" (' : "'"
marx = '\"' : "'"
bang = false
xxno = dcount(this,am)
dim part(100)
matparse part from this, am
this = ''
bite = ''
first = true
for xx = 1 to xxno
there = rem(xx,100)
if not(there) then
if first then this = bite else this = this:am:bite
first = false
bite = ''
thisline = part(100)
temp = part(0)
matparse part from temp, am
if not(supp) then bang = true; crt '!':
end else thisline = part(there)
if trim(thisline) eq '' then
if first then bite<there> = '' else bite<there+1> = ''
continue
end
note = false
wcnt = 0; more = 0; less = 0
mark = ''; tags = ''; lastword = ''
zz = 1
thisline = trimf(thisline)
if thisline matches '1N0N"*"0X' then
temp = field(thisline,'*',1)
thisline = temp:' ':thisline[col2(),len(thisline)]
end
thatline = upcase(thisline)
thatline = change(thatline, 'ON ERROR', 'ON~ERROR')
left = field(thatline,' ',1)
if num(left) or left[len(left),1] eq ':' then
if not(index(left,'=',1)) then tags = thisline[1,len(left)]
end
if tags gt '' then
thisline = trimf(thisline[col2()+1,len(thisline)])
thatline = trimf(thatline[col2()+1,len(thatline)])
end
zzno = len(thisline)
loop
while zz lt zzno and not(note) do
loop
thisun = thatline[zz,1]
begin case
case mark eq '' and index(marx,thisun,1)
mark = thisun
case mark ne ''
if thisun eq mark then mark = ''
case wcnt and thisun eq ';'
that = field(trim(thatline[zz+1,zzno]),' ',1)
if that[1,3] eq 'REM' then that = ''
if that[1,1] eq '*' then that = ''
if that[1,1] eq '!' then that = ''
if that eq '' then zz = zzno
case wcnt
case thisun eq '!' or thisun eq '$'
note = true; zz = zzno
case thisun eq '*'
if astx then note = true
zz = zzno
case field(thatline,' ',1) eq 'REM'
note = true; zz = zzno
end case
while (index(skip,thisun,1) or mark) and zz lt zzno do
zz += 1
repeat
left = zz
loop
thisun = thatline[zz,1]
until index(skip,thisun,1) or zz gt zzno do
zz += 1
repeat
word = thatline[left,zz-left]
wcnt += 1
if wcnt ne 1 then
if word eq 'WHILE' or word eq 'UNTIL' then word = ' '
if word eq 'NEXT' or word eq 'REPEAT' then
word = ' '
more -= dent
end
if lastword eq 'LOCKED' then more -= dent
end else
if word eq 'LOCKED' or word eq 'THEN' then
if word eq trim(thatline) then less += dent
end
end
if word eq 'CASE' then
if lastword ne 'BEGIN' and lastword ne 'END' then
more += dent
less += dent
end
if suit and lastword eq 'BEGIN' then more += dent
if suit and lastword eq 'END' then less += dent
end
if not(index(dead,word[1,1],1)) then
locate(word,pull;rubbish) then less += dent
test = word ne 'THEN' & word ne 'ELSE' & word ne 'ON~ERROR'
that = trim(thisline[zz,zzno])
if that[1,1] eq ';' then
that = trim(that[2,zzno])[1,3]
if that[1,3] eq 'REM' then that = ''
if that[1,1] eq '*' then that = ''
if that[1,1] eq '!' then that = ''
end
if test or that eq '' then
locate(word,push;rubbish) then
more += dent
end
end
if word eq 'THEN' or word eq 'LOCKED' then
if that eq '' and lastword eq '' then less -= dent
end
if that ne '' and lastword eq '' then
if word eq 'THEN' or word eq 'ELSE' then
more -= dent
less -= dent
end
if word eq 'LOCKED' and trim(that)[1,1] ne '='
then more -= dent ; less -= dent
end
end
lastword = word
repeat
marg -= less
if tags eq '' then pict = '' else pict = 'L#':(len(tags)+1)
if marg gt len(tags) then pict = 'L#':marg
if thisline eq '!' or thisline eq '$' then note = true
if thatline eq 'REM' then note = true
if astx and thisline eq '*' then note = true
if note then
if tags eq '' then pict = '' else pict = 'L#':(len(tags)+1)
end
thisline = trimb(fmt(tags,pict):thisline)
if first then
bite<there> = thisline
end else bite<there+1> = thisline
marg += more
next xx
if bang then crt
if bite ne '' then
if first then this = bite else this = this:am:bite
end
that = ''
return
get.rope:
* If the terminal doesn't support screen addressing, do simple input
if not(editpage) then
crt begn:stub:
*> input rope:
if rlen then
input rope,rlen:
rlen = 0
end else input rope:
*>
return
end
*
* The following variables are used
*
* BARE - what you are going to reveal (the displayed part)
* CRAM - insert mode on (vs overwrite mode)
* PCOL - display position
* STEM - the prefix part of the display line
* ICON - a picture of what you last displayed
* PANS - the PAN increment
* PPOS - the PAN origin
* WIDE - the PAN width
* PULP - SEQ(COMI) - what you get from a key press
* PURE - untouched, a virgin
* POSN - the stack position
* PCHR - text position
pans = int(span/2)
posn = 0
rope = pick; pick = ''
loop
if heap then
stem = prmt:': '
if posn then stem = '*':fmt(posn, "3'0'R"):stem[5,huge]
end else stem = '*':stub
wide = span - len(stem) - 1
pans = int(wide/2)
ppos = 1
pchr = 1
cram = true
icon = space(span)
crt begn : ceol :
pure = true
!&&&
! if nick and trim(rope) = '' then pchr = len(rope)+1 ; pure = false
!&&&
loop
begin case
*> case pchr lt ppos ; ppos -= pans
case pchr lt ppos
loop while pchr lt ppos ; ppos -= pans ; repeat
case pchr ge (ppos+wide)
loop while pchr ge(ppos+wide) ; ppos += pans ; repeat
*> case pchr ge (ppos+wide) ; ppos += pans
end case
bare = stem : rope[ppos, wide]
pcol = 0
if icon ne bare then
yyno = 0
for yy = 1 to span until yyno
if bare[yy,1] ne icon[yy,1] then yyno = yy
next yy
crt @(yyno-1):bare[yyno,span-yyno]:ceol:@(pcol):
icon = bare[1,span]
end
pcol = len(stem) + pchr - ppos
crt @(pcol) :
gosub get.keyc
locate(keyc,keys;cpos) then cpos = acts<cpos> else cpos = 0
pulp = seq(keyc)
if pulp lt 32 or pulp gt 128 then keyc = ''
if pure then
if cpos eq 0 and keyc ne '' then
rope = ''
pchr = 1
end
crt @(0):
if cram then crt '>': else crt '#':
crt @(pcol):
pure = false
end
begin case
case heap and (cpos = uarr or cpos = upag)
if posn lt dcount(stak, vm) then
posn += 1
rope = stak<1,posn>
end
exit
case heap and (cpos = darr or cpos = dpag)
if posn gt 1 then
posn -= 1
rope = stak<1,posn>
end else
posn = 0
rope = ''
end
exit
case heap and cpos = skey
if rope eq '' then
if look<1> eq '' then continue
comi = look<1,1>
gosub parse.command
rope = 'L':dlim:rest
end else rope = 'L/':rope
if rope eq look<1> then rope = 'L'
return
case heap and cpos = rkey
if rope eq '' then
if look<1> eq '' then continue
comi = look<1,1>
gosub parse.command
rope = 'LA':dlim:rest
end else rope = 'LA/':rope
if rope eq look<1> then rope = 'L'
return
case heap and cpos = writ and pulp ne 23
rope = 'PE'
return
case heap and cpos = phlp
stub = '' ; heap = false ; rest = ''
gosub show.help
rope = 'D'
return
case cpos = larr
if pchr gt 1 then pchr -= 1
case cpos = rarr
if pchr le len(rope) then pchr += 1
case cpos = lpag
pchr = 1
case cpos = rpag
pchr = len(rope) + 1
case cpos = escp
posn = 0
rope = ''
exit
case cpos = delc
rope = rope[1, pchr-1] : rope[pchr+1, huge]
case cpos = delr
rope = rope[1, pchr-1]
case cpos = back
if pchr gt 1 then
pchr -= 1
rope = rope[1, pchr-1] : rope[pchr+1, huge]
end
case cpos = carr
if heap then
crt begn : ceol : ':' : rope:
if posn then
if rope eq stak<1,posn> then del stak<1,posn>
end
end
return
case cpos = togg
cram = not(cram)
crt @(0):
if cram then crt '>': else crt '#':
crt @(pcol):
case pulp eq 23 ;* ctrl-w
dope = downcase(rope)
mope = upcase(rope)
tope = oconv(rope,'MCT')
begin case
case rope eq tope and dope eq tope ; rope = mope
case rope eq tope ; rope = dope
case rope eq mope ; rope = tope
case 1 ; rope = mope
end case
case pulp ge 32 and pulp lt 128
if cram then
rope = rope[1, pchr-1] : keyc : rope[pchr, huge]
end else
if pchr le len(rope)
then rope[pchr, 1] = keyc
else rope := keyc
end
pchr += 1
case 1
crt bell:
end case
if rlen and len(rope) ge rlen then
crt keyc:
rlen = 0
return
end
repeat
repeat
return
get.keyc:
$ifdef qm
if not(index(upcase(system(7)),'EEEPC',1)) then
keyc = keycode()
return
end
$endif
common /keys$krj/ termtype,eseq,keyd,base,full
if not(assigned(termtype)) then termtype = ''
if termtype ne oconv(system(7),'MCU') then gosub setup.keys
keyc = ''
loop
$ifdef unidata
mine = in()
$else
mine = keyin()
$endif
locate(mine,base;post) then gosub get.rest
locate(mine,eseq;cmd)
then keyc = char(keyd<cmd>)
else if len(mine) eq 1 then keyc = mine
while keyc eq '' do repeat
return
get.rest:
loop
$ifdef unidata
a = system(12)
loop
until system(12) ge (a+5) do
repeat
$else
nap 5
$endif
input your,-1
while your do
$ifdef unidata
mine := in()
$else
mine := upcase(keyin())
$endif
locate(mine,full,post;your) then return
repeat
return
setup.keys:
* Define the key numbers - these are based on QM keycode()
*======================================================================
* Arrow keys
equ lark to 203, rark to 204, uark to 205, dark to 206
* Page up and down, home and end
equ upak to 207, dpak to 208, homk to 209, endk to 210
* Insert, delete, backtab, delete line, backspace
equ insk to 211, deck to 212, btbk to 213, delk to 127, bspk to 8
* Control - Page up and down, homk and end
equ cupk to 214, cdpk to 215, chok to 216, cenk to 217
* Function, Control+Function, Alt+Function, Shift+Function
equ f1 to 128, cf1 to 140, af1 to 152, sf1 to 164
equ f2 to 129, cf2 to 141, af2 to 153, sf2 to 165
equ f3 to 130, cf3 to 142, af3 to 154, sf3 to 166
equ f4 to 131, cf4 to 143, af4 to 155, sf4 to 167
equ f5 to 132, cf5 to 144, af5 to 156, sf5 to 168
equ f6 to 133, cf6 to 145, af6 to 157, sf6 to 169
equ f7 to 134, cf7 to 146, af7 to 158, sf7 to 170
equ f8 to 135, cf8 to 147, af8 to 159, sf8 to 171
equ f9 to 136, cf9 to 148, af9 to 160, sf9 to 172
equ f10 to 137, cf10 to 149, af10 to 161, sf10 to 173
equ f11 to 138, cf11 to 150, af11 to 162, sf11 to 174
equ f12 to 139, cf12 to 151, af12 to 163, sf12 to 175
*======================================================================
* Stash the escape sequences and key codes in labelled common
termtype = oconv(system(7),'MCU')
* Set up keys good for many terminals and as defaults
eseq = '' ; keyd = ''
keyd<-1> = lark; eseq<-1> = char(21)
keyd<-1> = rark; eseq<-1> = char(6)
keyd<-1> = uark; eseq<-1> = char(26)
keyd<-1> = dark; eseq<-1> = char(10)
keyd<-1> = homk; eseq<-1> = char(1)
keyd<-1> = endk; eseq<-1> = char(5)
keyd<-1> = deck; eseq<-1> = char(4)
keyd<-1> = upak; eseq<-1> = char(27):'[5~'
keyd<-1> = dpak; eseq<-1> = char(27):'[6~'
* Now do settings that don't interfere between terminals
* VT-type terminals - cater for alternative arrow sequences
keyd<-1> = rark; eseq<-1> = char(27):'[C'
keyd<-1> = rark; eseq<-1> = char(27):'OC'
keyd<-1> = uark; eseq<-1> = char(27):'[A'
keyd<-1> = uark; eseq<-1> = char(27):'OA'
keyd<-1> = dark; eseq<-1> = char(27):'[B'
keyd<-1> = dark; eseq<-1> = char(27):'OB'
keyd<-1> = insk; eseq<-1> = char(27):'[1~'
keyd<-1> = deck; eseq<-1> = char(27):'[4~'
keyd<-1> = btbk; eseq<-1> = char(27):'[Z'
keyd<-1> = f1 ; eseq<-1> = char(27):'OP'
keyd<-1> = f2 ; eseq<-1> = char(27):'OQ'
keyd<-1> = f3 ; eseq<-1> = char(27):'OR'
keyd<-1> = f4 ; eseq<-1> = char(27):'OS'
keyd<-1> = f5 ; eseq<-1> = char(27):'OT'
keyd<-1> = f6 ; eseq<-1> = char(27):'[17~'
keyd<-1> = f7 ; eseq<-1> = char(27):'[18~'
keyd<-1> = f8 ; eseq<-1> = char(27):'[19~'
keyd<-1> = f9 ; eseq<-1> = char(27):'[20~'
keyd<-1> = f10 ; eseq<-1> = char(27):'[21~'
keyd<-1> = f11 ; eseq<-1> = char(27):'[23~'
keyd<-1> = f12 ; eseq<-1> = char(27):'[24~'
* Wyse-type terminals
keyd<-1> = insk; eseq<-1> = char(27):'Q'
keyd<-1> = deck; eseq<-1> = char(27):'W'
keyd<-1> = btbk; eseq<-1> = char(27):'I'
keyd<-1> = f1 ; eseq<-1> = char(1):'@':char(13)
keyd<-1> = f2 ; eseq<-1> = char(1):'A':char(13)
keyd<-1> = f3 ; eseq<-1> = char(1):'B':char(13)
keyd<-1> = f4 ; eseq<-1> = char(1):'C':char(13)
keyd<-1> = f5 ; eseq<-1> = char(1):'D':char(13)
keyd<-1> = f6 ; eseq<-1> = char(1):'E':char(13)
keyd<-1> = f7 ; eseq<-1> = char(1):'F':char(13)
keyd<-1> = f8 ; eseq<-1> = char(1):'G':char(13)
keyd<-1> = f9 ; eseq<-1> = char(1):'H':char(13)
keyd<-1> = f10 ; eseq<-1> = char(1):'I':char(13)
keyd<-1> = f11 ; eseq<-1> = char(1):'J':char(13)
keyd<-1> = f12 ; eseq<-1> = char(1):'K':char(13)
* ADDS-type terminals
keyd<-1> = f1 ; eseq<-1> = char(2):'1':char(13)
keyd<-1> = f2 ; eseq<-1> = char(2):'2':char(13)
keyd<-1> = f3 ; eseq<-1> = char(2):'3':char(13)
keyd<-1> = f4 ; eseq<-1> = char(2):'4':char(13)
keyd<-1> = f5 ; eseq<-1> = char(2):'5':char(13)
keyd<-1> = f6 ; eseq<-1> = char(2):'6':char(13)
keyd<-1> = f7 ; eseq<-1> = char(2):'7':char(13)
keyd<-1> = f8 ; eseq<-1> = char(2):'8':char(13)
keyd<-1> = f9 ; eseq<-1> = char(2):'9':char(13)
keyd<-1> = f10 ; eseq<-1> = char(2):':':char(13)
keyd<-1> = f11 ; eseq<-1> = char(2):';':char(13)
keyd<-1> = f12 ; eseq<-1> = char(2):'<':char(13)
* xterm type - like my ASUS eeePC
keyd<-1> = bspk ; eseq<-1> = char(127)
keyd<-1> = delk ; eseq<-1> = char(27):'[3;2~'
keyd<-1> = f5 ; eseq<-1> = char(27):'[15~'
keyd<-1> = sf1 ; eseq<-1> = char(27):'O2P'
keyd<-1> = sf2 ; eseq<-1> = char(27):'O2Q'
keyd<-1> = sf3 ; eseq<-1> = char(27):'O2R'
keyd<-1> = sf4 ; eseq<-1> = char(27):'O2S'
keyd<-1> = sf5 ; eseq<-1> = char(27):'[15;2~'
keyd<-1> = sf6 ; eseq<-1> = char(27):'[17;2~'
keyd<-1> = sf7 ; eseq<-1> = char(27):'[18;2~'
keyd<-1> = sf8 ; eseq<-1> = char(27):'[19;2~'
keyd<-1> = sf9 ; eseq<-1> = char(27):'[20;2~'
keyd<-1> = sf10 ; eseq<-1> = char(27):'[21;2~'
keyd<-1> = sf11 ; eseq<-1> = char(27):'[23;2~'
keyd<-1> = sf12 ; eseq<-1> = char(27):'[24;2~'
* Now do terminal-specific settings
* VT-type terminals
if termtype[1,2] eq 'VT' or termtype[1,5] eq 'XTERM' then
keyd<-1> = lark; eseq<-1> = char(27):'[D'
keyd<-1> = lark; eseq<-1> = char(27):'OD'
end else
keyd<-1> = insk; eseq<-1> = char(27):'[D'
keyd<-1> = deck; eseq<-1> = char(27):'OD'
end
* Wyse-type terminals
if termtype[1,2] eq 'WY' then
keyd<-1> = lark; eseq<-1> = char(8)
keyd<-1> = rark; eseq<-1> = char(12)
keyd<-1> = uark; eseq<-1> = char(11)
keyd<-1> = btbk; eseq<-1> = char(27):'O' ;* !
end
* for my lttle ASUS eeePC & Linux - What a cool thing it is!
if index(termtype,'EEEPC',1) then
keyd<-1> = chok; eseq<-1> = char(27):'[2H' ;* Shift-Home actually
keyd<-1> = homk; eseq<-1> = char(27):'[H'
keyd<-1> = endk; eseq<-1> = char(27):'[F'
keyd<-1> = insk; eseq<-1> = char(27):'[2~'
keyd<-1> = deck; eseq<-1> = char(27):'[3~'
end else
keyd<-1> = homk; eseq<-1> = char(27):'[2~'
keyd<-1> = endk; eseq<-1> = char(27):'[3~'
end
* Populate the escape sequence test variables
base = ''; full = ''
amax = dcount(eseq,am)
for anum = 1 to amax
temp = eseq<anum>
if len(temp) le 1 then continue
locate(temp[1,1],base;post) else
post = dcount(base,am)+1
end
base<post> = temp[1,1]
full<post,-1> = temp
next anum
return
outline:
* to display logic simplisticly
rest = oconv(rest,'MCU')
if index(rest,'*',1) then rest = 'CEPS'
bot = here + 1
if bot gt last then bot = 1
if numb then msup = here + numb else msup = last
if msup gt last then msup = last
for here = bot to msup
gosub get.line
gosub find.label
line = ' ':upcase(line)
begin case
case chit eq '*' or chit eq '!' ; line = ''
case index(line,' GOTO ',1)
case index(line,' GO ',1)
case index(line,' GOSUB ',1)
case rest eq '' ; line = ''
case index(rest,'C',1) and index(line,' ':'CALL',1)
case index(rest,'E',1) and index(line,' ':'EXECUTE',1)
case index(rest,'P',1) and index(line,' ':'PERFORM',1)
case index(rest,'S',1) and index(line,' ':'CASE',1)
case 1 ; line = ''
end case
if temp ne '' or line ne '' then gosub display.line
next here
return
getshowline:
if unassigned(puncs) then
puncs = ', []()<>=+-/*:#!'
funcs = 'ABS\ABSS\ACOS\ADDS\ALPHA\ANDS\ASCII\ASIN\ASSIGNED\'
funcs := 'ATAN\BITAND\BITNOT\BITOR\BITRESET\BITSET\BITTEST\'
funcs := 'BITXOR\CATS\CHANGE\CHAR\CHARS\CHECKSUM\COL1\COL2\'
funcs := 'CONTINUE\CONVERT\COS\COSH\COUNT\COUNTS\DATE\DCOUNT\'
funcs := 'DELETE\DIV\DIVS\DOWNCASE\DQUOTE\DTX\EBCDIC\EQS\'
funcs := 'EREPLACE\EXCHANGE\EXP\EXTRACT\FADD\FDIV\FFIX\FFLT\'
funcs := 'FIELD\FIELDS\FIELDSTORE\FILEINFO\FIX\FMT\FMTDP\'
funcs := 'FMTS\FMTSDP\FMUL\FOLD\FOLDDP\FSUB\GES\GET\'
funcs := 'GETLOCALE\GETREM\GROUP\GTS\ICHECK\ICONV\ICONVS\'
funcs := 'IFS\ILPROMPT\INDEX\INDEXS\INDICES\INMAT\INSERT\INT\'
funcs := 'ISNULL\ISNULLS\ITYPE\KEYIN\LEFT\LEN\LENDP\LENS\'
funcs := 'LENSDP\LES\LN\LOWER\LTS\MATCHFIELD\MAXIMUM\MINIMUM\'
funcs := 'MOD\MODS\MULS\NEG\NEGS\NES\NOT\NOTS\NUM\NUMS\OCONV\'
funcs := 'OCONVS\ORS\PWR\QUOTE\RAISE\REAL\RECORDLOCKED\REM\'
funcs := 'REMOVE\REPLACE\REUSE\RIGHT\RND\RPC.CALL\RPC.CONNECT\'
funcs := 'RPC.DISCONNECT\SADD\SCMP\SDIV\SEEK\SELECTINFO\SEND\'
funcs := 'SENTENCE\SEQ\SEQS\SETLOCALE\SIN\SINH\SLEEP\SMUL\'
funcs := 'SOUNDEX\SPACE\SPACES\SPLICE\SQRT\SQUOTE\SSUB\STATUS\'
funcs := 'STR\STRS\SUBR\SUBS\SUBSTRINGS\SUM\SUMMATION\SYSTEM\'
funcs := 'TAN\TANH\TERMINFO\TIME\TIMEDATE\TPARM\TRANS\TRIM\'
funcs := 'TRIMB\TRIMBS\TRIMF\TRIMFS\TRIMS\UNASSIGNED\'
funcs := 'UNICHAR\UPCASE\XLATE\XTD'
convert '\' to @am in funcs
keywords = 'ABORT\AUTHORIZATION\AUXMAP\BEGIN\BREAK\BSCAN\'
keywords := 'BYTE\BYTELEN\BYTETYPE\BYTEVAL\CALL\CASE\CHAIN\'
keywords := 'CLEAR\CLEARDATA\CLEARFILE\CLEARPROMPTS\CLEARSELECT\'
keywords := 'CLOSE\CLOSESEQ\COMMIT\COMMON\COMPARE\CONSTANTS\'
keywords := 'CONVERT\CREATE\CRT\DATA\DEBUG\DEFFUN\DEL\DELETE\'
keywords := 'DELETELIST\DELETEU\DIM\DIMENSION\DISPLAY\DO\ECHO\ELSE\'
keywords := 'END\ENTER\EQU\EQUATE\ERRMSG\EXECUTE\EXIT\FILELOCK\'
keywords := 'FILEUNLOCK\FIND\FINDSTR\FLUSH\FOOTING\FOR\FORMLIST\'
keywords := 'FUNCTION\GET\GETLIST\GETX\GO\GOSUB\GOTO\GROUPSTORE\'
keywords := 'HEADING\HUSH\IF\INCLUDE\INPUT\INPUTCLEAR\INPUTDISP\'
keywords := 'INPUTDP\INPUTERR\INPUTIF\INPUTNULL\INPUTTRAP\INS\'
keywords := 'KEYEDIT\KEYEXIT\KEYTRAP\LET\LOCALEINFO\LOCATE\LOCK\'
keywords := 'LOOP\MAT\MATBUILD\MATCH\MATCHES\MATPARSE\MATREAD\MATREADL\'
keywords := 'MATREADU\MATWRITE\MATWRITEU\NAP\NEXT\NOBUF\NULL\'
keywords := 'NUMERIC.DATA\ON\OPEN\OPENCHECK\OPENDEV\OPENPATH\'
keywords := 'OPENSEQ\PAGE\PERFORM\PRECISION\PRINT\PRINTER\'
keywords := 'PRINTERR\PROCREAD\PROCWRITE\PROGRAM\PROMPT\'
keywords := 'RANDOMIZE\READ\READBLK\READL\READLIST\READNEXT\'
keywords := 'READSEQ\READT\READU\READV\READVL\READVU\RECORDLOCK\'
keywords := 'RELEASE\REM\REMOVE\REPEAT\RETURN\REVREMOVE\REWIND\'
keywords := 'ROLLBACK\SEEK\SELECT\SELECTE\SELECTINDEX\SETREM\'
keywords := 'SSELECT\START\STATUS\STOP\STORAGE\SUBROUTINE\'
keywords := 'TABSTOP\THEN\TIMEOUT\TO\TPRINT\TRANSACTION\TTYCTL\'
keywords := 'TTYGET\TTYSET\UNICHARS\UNISEQ\UNISEQS\UNLOCK\UNTIL\'
keywords := 'UPRINT\WEOF\WEOFSEQ\WRITE\WRITEBLK\WRITELIST\'
keywords := 'WRITESEQ\WRITESEQF\WRITET\WRITEU\WRITEV\WRITEVU'
convert '\' to @am in keywords
si.label = 1
si.comment = 2
si.string = 3
si.key = 4
si.operator = 5
si.function = 6
si.directive = 7
si.highlight = 8
si.doc = 9
bi.hiword = 10
* Highlights for HostAccess
bo = @(-58) ; bf = @(-59)
wo = @(-5) ; wf = @(-6)
ro = @(-13) ; rf = @(-12)
uo = @(-15) ; uf = @(-12)
hi.commenton = uo:bo
hi.commentoff = uf:bf
hi.labelon = bo
hi.labeloff = bf
hi.selecton = ro:wo
hi.selectoff = wf:rf
hi.stringon = wo
hi.stringoff = wf
hi.keyon = uo
hi.keyoff = uf
hi.opon = ''
hi.opoff = ''
hi.funcon = bo
hi.funcoff = bf
hi.diron = wo
hi.diroff = wf
hi.docon = ro:bo
hi.docoff = rf:bf
end
l = len(line)
* If the line is too long, don't colourise it
if l gt 2000 then
showline = line[setoff,width]
return
end
myline = line
oldmyline = myline
myline = trimf(myline)
mask = space(l - len(myline))
word = myline[' ',1,1]
if word[' ',1,1] match '1N0N' or word match '1A0X":"' then
mask := str(si.label,len(word)):' '
myline = myline[' ',2,999]
word = myline[' ',1,1]
end
begin case
case word[1,1] eq '*' or word[1,1] eq '!'
if count(myline,'@@') then
mask := str(si.doc, l)
end else
mask := str(si.comment, l)
end
case word[1,1] eq '$' or word[1,1] eq '#'
mask := str(si.directive, l)
case 1
dc = count(myline,';')
if not(dc) then
mask := space(l)
end else
foundcomment = false
for z = 1 to dc until foundcomment
word = trimf(myline[';',z+1,1])
if word[1,1] eq '*' or word[1,1] eq '!' then
foundcomment = z
end
next
if foundcomment then
mask := space(len(myline[';',1, foundcomment])):str(si.comment, l)
end else
mask := space(l)
end
end
end case
lin = convert(puncs,str(@fm,len(puncs)), upcase(oldmyline))
dc3 = dcount(lin,@fm)
for q = 1 to dc3
word = lin[@fm,q,1]
st = col1()+ 1
if st gt 1 then
if mask[st-1,1] eq ' ' and oldmyline[st-1,1] ne ' ' then
mask[st-1,1] = si.operator ; * operators too
end
end
begin case
case word[1,1] eq '"'
ix = index(lin[st+1,huge],'"',1)
if ix then
if mask[st,1] eq ' ' then
q = dcount(lin[1, ix+st],@fm)
mask[st, ix+1] = str(si.string, ix+1)
end
end
case word[1,1] eq "'"
ix = index(lin[st+1,huge],"'",1)
if ix then
if mask[st,1] eq ' ' then
q = dcount(lin[1, ix+st],@fm)
mask[st, ix+1] = str(si.string, ix+1)
end
end
case 1
locate(word,keywords;dpos;'AL') then
if mask[st,1] eq ' ' then
mask[st, len(word)] = str(si.key, len(word))
end
end else
locate(word,funcs;dpos;'AL') then
* Functions are followed by a bracket
brak = ''
fpos = len(lin[@fm,1,q])+1
if fpos then brak = trim(oldmyline[fpos,999])[1,1]
if brak eq '(' and mask[st,1] eq ' ' then
mask[st,len(word)] = str(si.function, len(word))
end
end
end
end case
next
word = lastfind
if word ne '' then
oc = 1
loop
if caseflag
then ix = index(oldmyline,word,oc)
else ix = index(upcase(oldmyline),upcase(word),oc)
while ix do
oc += 1
mask[ix, len(word)] = str(si.highlight, len(word))
repeat
end
myline = oldmyline[setoff,width]
mask = mask[setoff,width]
showline = ''
old = ''
l = len(myline)
for k = 1 to l
c = mask[k,1]
if c ne old then
begin case
case old eq si.label
showline := hi.labeloff
case old eq si.comment
showline := hi.commentoff
case old eq si.key
showline := hi.keyoff
case old eq si.string
showline := hi.stringoff
case old eq si.key
showline := hi.keyoff
case old eq si.operator
showline := hi.opoff
case old eq si.function
showline := hi.funcoff
case old eq si.directive
showline := hi.diroff
case old eq si.highlight
showline := hi.selectoff
end case
begin case
case c eq si.label
showline := hi.labelon
case c eq si.comment
showline := hi.commenton
case c eq si.key
showline := hi.keyon
case c eq si.string
showline := hi.stringon
case c eq si.operator
showline := hi.opon
case c eq si.function
showline := hi.funcon
case c eq si.directive
showline := hi.diron
case c eq si.highlight
showline := hi.selecton
case c eq si.doc
showline := hi.docon
end case
old = mask[k,1]
end
showline := myline[k,1]
next
begin case
case old eq si.label
showline := hi.labeloff
case old eq si.comment
showline := hi.commentoff
case old eq si.key
showline := hi.keyoff
case old eq si.string
showline := hi.stringoff
case old eq si.function
showline := hi.funcoff
case old eq si.operator
showline := hi.opoff
case old eq si.directive
showline := hi.diroff
case old eq si.highlight
showline := hi.selectoff
case old eq si.doc
showline := hi.docoff
end case
return