begin ; ! April-1985-style Command Line Interpreter
option "-nocheck-nostack-nodiag-low"
conststring title="CLI version 04/10/90"
owninteger i,trouble,tmode=0,bottom
recordformat dictf(integer beg,pos,lim,alt)
recordformat eventfm(integer event,(integer sub or integer subevent),
integer extra,pc,string (255) message,integerarray r(0:15))
@16_1000 shortinteger linenum
@16_10c0 routine printsymbol(integer k)
@16_10c4 routine printstring(string (255)s)
@16_10c8 integerfn readsymbol
@16_10cc integerfn nextsymbol
@16_10d0 routine prompt(string (255)s)
@16_10d4 integerfn testsymbol
@16_10d8 routine selectinput(integer s)
@16_10dc routine selectoutput(integer s)
@16_10e0 routine resetinput
@16_10e4 routine resetoutput
@16_10e8 routine closeinput
@16_10ec routine closeoutput
@16_10f0 routine openinput(integer s,string (255)f)
@16_10f4 routine openoutput(integer s,string (255)f)
@16_10f8 routine etheropen(integer port,statport)
@16_10fc routine etherclose(integer port)
@16_1100 routine etherwrite(integer port,bytename buf,integer length)
@16_1104 integerfn etherread(integer port,bytename buf,integer max)
@16_1108 integerfn fcomm(integer cn,string (255)s)
!16_1124 %integerfn idiv(%integer dividend,divisor)
integerfn idiv(integer dividend,divisor)
integer sign=(dividend!!divisor)&16_80000000,quotient=0,one=1
dividend = -dividend if dividend<0
divisor = -divisor if divisor<0
cycle
exitif divisor<<1<0; divisor = divisor<<1
one = one<<1; result =0 if one=0
repeatuntil dividend-divisor<0
cycle
one = one>>1; exitif one=0; divisor = divisor>>1
while dividend-divisor>=0 cycle
quotient = quotient+one; dividend = dividend-divisor
repeat
repeat
quotient = -quotient unless sign=0
result = quotient
end
@16_1140 routine setterminalmode(integer m)
@16_117c integerfn defname(string (255)s,record (dictf)name d,integer size)
@16_1180 integerfn refname(string (255)s,record (dictf)name d)
@16_1184 routine transname(integer tag,string (255)name s)
@16_1188 routine define event handler
@16_1190 routine phex2(integer x)
@16_1194 routine phex4(integer x)
@16_1198 routine phex(integer x)
@16_3400 record (eventfm)event
@16_35c4 shortinteger userno
@16_3652 shortinteger terminalmode
@16_372c byteinteger cylock
@16_372d byteinteger fsport
@16_3f98 integer mainprogram,mexglob
@16_3fac integer cliparamad
@16_3fb0 record (dictf)comdict,fildict,extdict,sysdict
@16_3ff0 integer freebot,freetop,membot,memtop
routine space; printsymbol(' '); end
routine newline; printsymbol(nl); end
string (255)fn itos(integer v,p)
string (255)s
bytename l
routine printsymbol(integer x)
l = l+1; l[l] = x
end
routine spaces(integer x)
x = x-1 and printsymbol(' ') while x>0
end
routine write(integer n,p)
integer q,r
if p>0 start
p = ¬p; printsymbol(' ') and p = p+1 if n>=0
finish
p = -120 if p<-120
q = idiv(n,10); *move.l d1,r
if q=0 start
p = p+1 if n<0; spaces(-1-p); printsymbol('-') if n<0
else
p = p+1 if p<0; write(q,p)
finish
printsymbol(|r|+'0')
end
s = ""; l == length(s)
write(v,p)
result = s
end
routine write(integer n,p)
printstring(itos(n,p))
end
predicate starts(string (*)name s,integer c)
falseif length(s)=0
falseunless charno(s,1)=c
true
end
string (255)fn substring(string (255) s, integer from,to)
string (255) t
t = ""
from = 1 if from<=0
to = length(s) if to>length(s)
while from <= to cycle
t = t.tostring(charno(s,from)); from = from+1
repeat
result = t
end
predicate started(string (*)name s,integer c)
falseunless starts(s,c)
s = substring(s,2,length(s))
true
end
routine truncate(string (*)name s,integer c)
while started(s,c) cycle
repeat
end
predicate resolves(string (*)name var,fore,
string (255)match,string (*)name aft)
integer i
integerfn INDEX(string (*)name var,match)
!Return index position of first occurrence of match within string
integer i=0,j,l
l=length(match)
cycle
result = 0 if i > length(var)-l
i = i+1
j = 0
cycle
result = i if j = l
j = j+1
repeat until charno(var,i+j-1) # charno(match,j)
repeat
end
routine do aft
aft = substring(var,i+length(match),length(var)) if addr(aft) # 0
end
i = index(var,match)
false if i = 0
if addr(fore) # 0 start
if addr(fore) # addr(var) start
fore = substring(var,1,i-1)
do aft
finish else start
do aft
length(var) = i-1
finish
finish else do aft
true
end
!Aux (%signal does not work)
routine signal(integer e,s,i,string (255)m)
{}selectoutput(0); printstring("*BNAG*")
event_message = m
event_extra = i
e = e&15+(s&255)<<4
*move.l e,d0
*jsr 16_1114
end
routine standardise(string (*)name s)
bytename k
integer i
for i = 1,1,length(s) cycle
k == charno(s,i)
k = k&95 if 'A'<=k&95<='Z'
repeat
end
routine lock
cylock = cylock+1
end
routine unlock
returnif cylock=0
cylock = cylock-1
cylock = 0 and signal(0,1,0,"^Y") if cylock=128
end
routine diagnose; !Print event message, line number, etc
integer e,s,x,i
shortintegername ac,ir,sr
routine symbol(integer x)
if ' '<=x<=126 start
printsymbol('''') if '0'<=x<='9'
printsymbol(x)
printsymbol('''') if '0'<=x<='9'
finishelse write(x,0)
end
e = event_event&15
s = event_subevent
x = event_extra
returnif e=0 and s=0; !normal %stop
selectinput(0); resetinput; closeinput
returnif e=0 and s=1; !^Y
newline
printstring("** ")
printstring("Event "); write(e,0); space; write(s,0)
rest:
space and write(x,0) unless x=0
somerest:
space and printstring(event_message) unless event_message=""
norest:
newline; printstring("Stopped at")
if linenum#0 start
printstring(" line "); write(linenum,0)
finish
if linenum=0 or e=0 start
printstring(" PC "); phex(event_pc)
finish
newline
end
routine close all ins
integer i=4
onevent 9 start
finish
cycle
i = i-1; selectinput(i)
returnif i=0; closeinput
repeat
end
routine close all outs
integer i=4
onevent 9 start
finish
cycle
i=i-1; selectoutput(i)
returnif i=0; closeoutput
repeat
end
routine uclose all outs
integer i=4
onevent 9 start
finish
cycle
i = i-1; exitif i=0
openoutput(i,"")
repeat
selectoutput(0)
end
integerfn allocate(integer amount)
amount = (amount+3)>>2<<2
result = 0 if bottom+amount+1000>freetop
bottom = bottom+amount
result = bottom-amount
end
routine loadfile(string (255)n,integername s,l)
string (255)z
integer x,y,dict
integer pos=1,blocks,pad
integerfn hex
integer n=0,k
cycle
result = n if pos>=length(z); pos = pos+1
k = charno(z,pos-1)-'0'
result = n if k<0
n = n<<4+k
repeat
end
standardise(n)
{}printstring("Loading ";n)
dict = refname(n,fildict)
if dict>0 start {If entry exists
x = integer(dict); y = integer(dict+4)
if x<y start {if file remembered
{}printstring(" - already there"); newline
s = x; l = y-x; return
finish
finish
s = 0; l = 0
{}printstring(" - reading it")
z = "Z".tostring('0'+userno).n.tostring(nl) {Read file into store
lock
etherwrite(fsport,charno(z,1),length(z))
length(z) = etherread(fsport,charno(z,1),255)
unlock
if charno(z,1)='-' start
x = charno(z,2)-'0'; y =length(z)
y = y-1 if charno(z,y)=nl {and it ought to be}
n = "Load ".n
n = n." fails:"
z = substring(z,3,y)
z = n.z
{}printstring(z); newline
signal(3,3,x,z)
finish
blocks = hex; pad = hex
x = blocks<<9-pad
y = allocate(x)
if y<=0 start
y = bottom
lock
cycle
x = etherread(fsport,byteinteger(y),512)
repeatuntil x#512
unlock
{}printstring("No space"); newline
signal(2,1,l,"No space for ".n)
finish
s = y; l = x
lock
cycle
x = etherread(fsport,byteinteger(y),512)
y = y+x
repeatuntil x#512
unlock
if dict>0 start
if integer(dict)=integer(dict+4)=-1 start {marked for remembering
integer(dict) = s; integer(dict+4) = s+l
freebot = bottom
finish
finish
{}printstring(" - Done"); newline
end
routine define symbol(string (255)symbol,value)
integer stag,vtag
standardise(symbol)
stag = defname(symbol,comdict,8)
if stag=0 start
printstring("*Command dict full"); newline; return
finish
vtag = defname(value,fildict,8)
if vtag=0 start
printstring("*File dict full"); newline; return
finish
if stag<0 start
stag = stag<<1>>1
! printstring(symbol.": ".value." replaces ")
! transname(integer(stag),symbol); printstring(symbol); newline
finish
integer(stag) = vtag<<1>>1
end
routine run program(string (255)file,parm)
recordformat mex header f(short magic,flags,export,import,
integer code,short reset,main,integer own,stack,spare1,spare2)
record (mexheaderf)name h
bytename first,second
integer start,limit
routine run(integer xpc,xd6)
integer env
onevent 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 start
*move.l env,a6
set terminal mode(tmode)
if event_event!event_subevent=0 c
then close all outs elsestart
uclose all outs
selectinput(0); resetinput; closeinput
finish
close all ins; diagnose; return
finish
tmode = terminalmode
*move.l a6,env
linenum = 0
*move.l xpc,a0
*move.l xd6,d6
*jsr (a0)
signal(0,0,0,"")
end
cliparamad = addr(parm)
bottom = freebot
loadfile(file,start,limit); limit = limit+start
first == byteinteger(start)
second == byteinteger(start+1)
unless first=16_fe start
printstring("File ".file." starts with ")
phex2(first); printstring(" instead of FE")
newline; return
finish
while started(parm,' ') cycle ; repeat
parm = tostring(255) if parm=""
prompt(":"); selectinput(0); selectoutput(0)
mainprogram = 0
if 1<=second<=3 start ; !Mex format
mainprogram = start
loadfile("fmac:mexrun.mob",start,limit); limit = limit+start
parm = "" if parm = tostring(255)
h == record(start)
start = start+32+h_export
if h_import!h_own#0 c
or shortinteger(start+h_reset<<1)#16_4e75 start
printstring("File fmac:mexrun.mob is not as expected"); newline; return
finish
selectoutput(0); printstring("Diving in"); newline
run(start+h_main<<1,(bottom+3+256)&¬3)
selectoutput(0); printstring("Emerged"); newline
else
printstring("Warning: ".file." starts with FE"); phex2(second); newline
run(limit-4,(bottom+3+256)&¬3)
finish
end
routinespec obeystream(string (255)parms)
routine obeyfile(string (255)verb,parms)
onevent 3,4,9 start
printstring(event_message); newline
return
finish
openinput(1,verb) {Test whether file accessible}
selectinput(0); closeinput
openinput(0,verb)
selectinput(1); closeinput
selectinput(0)
obeystream(parms)
end
predicate verify
string (255)x
integer tag
tag = refname("VERIFY",comdict)
falseif tag<=0
tag = integer(tag)
transname(tag,x)
tag = length(x)
falseif tag=0
tag = charno(x,tag)&1
falseif tag=0
true
end
routine obeyline(string (255)line)
string (255)verb,param,junk
integer tag,pos,sym,lives=9
constintegerarray bit(0:3) = 0,
{ ?>=<;:9876543210/.-,+*)('&%$#"!
2_01010111111111110100111111111100,
2_11111111111111111111111111111111,
2_01111111111111111111111111111111
onevent 2,3,4,9 start
printstring(event_message); newline
return
finish
!First parse the line, split it up into verb and parameters.
!Then perform verb translation.
truncate(line,' '); truncate(line,'{'); truncate(line,' ')
if started(line,'@') start
truncate(line,' ')
line = "@".line
finish
cycle
verb = ""
pos = 1
cycle
exitif pos>length(line); sym = charno(line,pos)
exitif bit(sym>>5&3)&1<<(sym&31)=0
verb = verb.tostring(sym); pos = pos+1
repeat
returnif verb=""
!! sym = '=' %and pos = pos+1 %if sym='_' {suppress symbol translation}
if charno(verb,length(verb))='_' start
sym = '='; length(verb) = length(verb)-1
finish
param = substring(line,pos,length(line))
exitif sym='='
standardise(verb)
tag = refname(verb,comdict)
exitif tag<=0
tag = integer(tag)
transname(tag,verb)
line = verb.param
lives = lives-1
if lives=0 start
printstring("Symbol translation looping: ".line); newline
verb = ""; return
finish
repeat
if verify start
printstring(verb)
printstring(param)
newline
finish
!Now decide whether the command is a symbol definition or
!a request to run a program or a request to obey another file.
if length(param)>1 and charno(param,1)='=' start
definesymbol(verb,substring(param,2,length(param)))
elseif starts(verb,'@')
verb = substring(verb,2,length(verb))
verb = verb.".COM" unless resolves(verb,junk,".",junk)
obeyfile(verb,param)
else
verb = verb.".MOB" unless resolves(verb,junk,".",junk)
runprogram(verb,param)
finish
end
routine obeystream(string (255)parms)
string (63)array parameter(1:8)
string (255)parm,rest,line
integer i
integerfn nsym
integer k
k = nextsymbol&127
k = nl if k<' '
result = k
end
integerfn rsym
constinteger esc=27
integer k,x
x = nsym
readsymbol(k); result = x unless k=esc
readsymbol(k); result = x unless k='?'
readsymbol(k); result = x
end
predicate fits(integer n)
trueif length(line)+n<=255
false
end
routine read line
string (63)p
integer k,kk,i
selectinput(0)
prompt("} ")
cycle
cycle
line = ""
cycle
k = rsym; exitif k=nl
if k='%' and '1'<=nsym<='8' start
k = rsym; p = parameter(k-'0')
if fits(length(p)) start
line = line.p
else
line = line."%" if fits(1)
line = line.tostring(k) if fits(1)
finish
elseif k='-' and nsym=nl
k=rsym
else
line = line.tostring(k) if fits(1)
finish
repeat
exitunless started(line,'!')
continueunless starts(line,'!')
kk = 0
for i = 2,1,length(line) cycle
k = charno(line,i); kk = k unless k=' '
printsymbol(k)
repeat
newline unless kk=':'
repeat
repeatuntil line#""
end
onevent 0,9 start
printstring("Event in obeystream "); printsymbol(event_event+'0'); newline
resetinput; closeinput
return
finish
parms = parm." ".rest while resolves(parms,parm," ",rest)
parms = rest while resolves(parms,parm," ",rest) and parm=""
parms = parm.",".rest while resolves(parms,parm," ",rest)
parms = parm.",".rest while resolves(parms,parm,"/",rest)
parms = parms.","
for i = 1,1,8 cycle
parm = "" unless resolves(parms,parm,",",parms)
parameter(i) = parm
repeat
cycle
readline
obeyline(line)
repeat
end
integerfn handle event; ! Unwind stack frames until event trap is found
constinteger bsr=16_6100,jsrel=16_4eba,bra=16_6000,link=16_4e50
constinteger jmpabslong=16_4ef9,moveltoa6=16_2c7c
constinteger jsra6=16_4eae,jsrabsshort=16_4eb8,jsrabslong=16_4eb9
integer frame,bit
integer retad,entry,eventbeg,eventend,temp,olda6
integername a4,a5,a6,fp,sp
predicate ok(integer lo,hi); ! False unless accessible
falseunless lo<=hi and lo&1=0
trueif membot<=lo and hi<memtop
trueif 0<=lo and hi<16_4000
false
end
! %returnif event_event=9 %and event_subevent=3 %and event_extra=0;!FShangup
! A4 and A5 are assumed to be used as base registers. Their values
! are interpreted as stack frame pointers established using the
! LINK instruction, but only if they point into the stack at an
! even address. The lower of A4 and A5 is selected as pointing to
! the most recent stack frame. It is assumed to point at a pair
! (Old Frame Pointer, Return Address). The return address is used
! to find the BSR instruction which called the current procedure,
! thereby locating its entry-point. As confirmation, the first
! instruction of the thus located procedure is verified to be a
! LINK instruction with the appropriate register number. The word
! preceeding the entry point is taken to be the event mask, bit i
! being set if event i is trapped at this level. The word
! preceeding that is taken to be the relative displacement of the
! (start of the) event block. The trap is ignored if the event was
! signalled from within that event block, so we need to know where
! the end is. We assume that the event block is preceeded by a BRA
! instruction to just past the event block.
bit=1<<event_event
a4 == event_r(12); a5 == event_r(13); a6 == event_r(14); sp == event_r(15)
cycle
cycle
frame = 0; fp == sp
frame = 5 and fp == a5 if ok(a5,a5+7) and sp<=a5
frame = 4 and fp == a4 if ok(a4,a4+7) and sp<=a4 c
and (frame=0 or a4<fp)
result =1 if frame=0
retad = integer(fp+4)
olda6 = a6
result =2 unless ok(retad-6,retad-1)
if shortinteger(retad-4)=bsr start
entry = shortinteger(retad-2)+retad-2
elseif shortinteger(retad-4)=jsrel
entry = shortinteger(retad-2)+retad-2
elseif shortinteger(retad-4)=jsrabsshort
entry = shortinteger(retad-2)
elseif shortinteger(retad-4)=jsra6
result =3 unless ok(fp+8,fp+11)
a6 = integer(fp+8)
temp = a6+shortinteger(retad-2)
result =4 unless ok(temp,temp+11)
result =5 unless shortinteger(temp)=moveltoa6 c
and shortinteger(temp+6)=jmpabslong
result =6 unless integer(temp+2)=olda6
entry = integer(temp+8)
elseif shortinteger(retad-6)=jsrabslong
entry = integer(retad-4)
finishelseresult =7
cycle
result =8 unless ok(entry-4,entry+3)
temp = shortinteger(entry)
if temp=bra start
entry = shortinteger(entry+2)+entry+2
elseif temp=jmpabslong
entry = integer(entry+2)
finishelseexit ; ! Not stepping stone ->
repeat
result =9 unless temp=link+frame
exitif shortinteger(entry-2)&bit#0; ! Trap found ->
sp = fp+8; fp = integer(fp); ! Simulate UNLK, RTS
repeat
eventbeg = shortinteger(entry-4)+entry-4
result =10 unless ok(eventbeg-4,eventbeg-1)
result =11 unless shortinteger(eventbeg-4)=bra
eventend = shortinteger(eventbeg-2)+eventbeg-2
result =12 unless ok(eventbeg,eventend-1)
a6 = olda6 andexitunless eventbeg<event_pc<=eventend
sp = fp+8; fp = integer(fp)
repeat
sp = fp+shortinteger(entry+2); !simulate link
event_r(8) = eventbeg
temp = addr(event_r(0))
*move.l temp,a0
*movem.l (a0),#16_ffff
*jmp (a0)
end
shortinteger(16_3f00-i<<2) = 16_4afc for i = 1,1,64*3
mexglob = 0
cylock = 0
event_event = -1
define event handler
unless event_event=-1 start
trouble = handle event; !Returns only if trouble
selectoutput(0)
set terminal mode(tmode)
printstring("*Trouble "); printsymbol(trouble+'@'); printsymbol(':')
uclose all outs; close all ins
selectinput(0); resetinput; closeinput
selectoutput(0); diagnose
{}printstring(" tsk")
*sub.l #2048,sp
{}printstring(" tsk"); newline
cycle
obeyfile(":t","")
repeat
finish
event_event = 0
*sub.l #2048,sp
printstring(title); newline
bottom = freebot
obeyfile("fmac:astartup.com","")
cycle
obeyfile(":t","")
repeat
endofprogram