1*37da2899SCharles.Forsythimplement Tcl_Core; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsyth# these are the outside modules, self explanatory.. 4*37da2899SCharles.Forsythinclude "sys.m"; 5*37da2899SCharles.Forsyth sys: Sys; 6*37da2899SCharles.Forsythinclude "draw.m"; 7*37da2899SCharles.Forsyth draw: Draw; 8*37da2899SCharles.Forsyth 9*37da2899SCharles.Forsythinclude "bufio.m"; 10*37da2899SCharles.Forsyth bufmod : Bufio; 11*37da2899SCharles.ForsythIobuf : import bufmod; 12*37da2899SCharles.Forsyth 13*37da2899SCharles.Forsythinclude "string.m"; 14*37da2899SCharles.Forsyth str : String; 15*37da2899SCharles.Forsyth 16*37da2899SCharles.Forsythinclude "tk.m"; 17*37da2899SCharles.Forsyth tk: Tk; 18*37da2899SCharles.Forsyth 19*37da2899SCharles.Forsythinclude "wmlib.m"; 20*37da2899SCharles.Forsyth wmlib: Wmlib; 21*37da2899SCharles.Forsyth 22*37da2899SCharles.Forsyth# these are stand alone Tcl libraries, for Tcl pieces that 23*37da2899SCharles.Forsyth# are "big" enough to be called their own. 24*37da2899SCharles.Forsyth 25*37da2899SCharles.Forsythinclude "tcl.m"; 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsythinclude "tcllib.m"; 28*37da2899SCharles.Forsyth 29*37da2899SCharles.Forsythinclude "utils.m"; 30*37da2899SCharles.Forsyth htab: Str_Hashtab; 31*37da2899SCharles.Forsyth mhtab : Mod_Hashtab; 32*37da2899SCharles.Forsyth shtab : Sym_Hashtab; 33*37da2899SCharles.Forsyth stack : Tcl_Stack; 34*37da2899SCharles.Forsyth utils : Tcl_Utils; 35*37da2899SCharles.Forsyth 36*37da2899SCharles.ForsythHash: import htab; 37*37da2899SCharles.ForsythMHash : import mhtab; 38*37da2899SCharles.ForsythSHash : import shtab; 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsyth 41*37da2899SCharles.Forsyth 42*37da2899SCharles.Forsyth 43*37da2899SCharles.Forsyth# global error flag and message. One day, this will be stack based.. 44*37da2899SCharles.Forsytherrmsg : string; 45*37da2899SCharles.Forsytherror, mypid : int; 46*37da2899SCharles.Forsyth 47*37da2899SCharles.Forsythsproc : adt { 48*37da2899SCharles.Forsyth name : string; 49*37da2899SCharles.Forsyth args : string; 50*37da2899SCharles.Forsyth script : string; 51*37da2899SCharles.Forsyth}; 52*37da2899SCharles.Forsyth 53*37da2899SCharles.ForsythTCL_UNKNOWN, TCL_SIMPLE, TCL_ARRAY : con iota; 54*37da2899SCharles.Forsyth 55*37da2899SCharles.Forsyth# Global vars. Simple variables, and associative arrays. 56*37da2899SCharles.Forsythlibmods : ref MHash; 57*37da2899SCharles.Forsythproctab := array[100] of sproc; 58*37da2899SCharles.Forsythretfl : int; 59*37da2899SCharles.Forsythsymtab : ref SHash; 60*37da2899SCharles.Forsythnvtab : ref Hash; 61*37da2899SCharles.Forsythavtab : array of (ref Hash,string); 62*37da2899SCharles.Forsythtclmod : TclData; 63*37da2899SCharles.Forsyth 64*37da2899SCharles.Forsythcore_commands:=array[] of { 65*37da2899SCharles.Forsyth "append" , "array", "break" , "continue" , "catch", "dumpstack", 66*37da2899SCharles.Forsyth "exit" , "expr" , "eval" , 67*37da2899SCharles.Forsyth "for" , "foreach" , 68*37da2899SCharles.Forsyth "global" , "if" , "incr" , "info", 69*37da2899SCharles.Forsyth "lappend" , "level" , "load" , 70*37da2899SCharles.Forsyth "proc" , "return" , "set" , 71*37da2899SCharles.Forsyth "source" ,"switch" , "time" , 72*37da2899SCharles.Forsyth "unset" , "uplevel", "upvar", "while" , "#" 73*37da2899SCharles.Forsyth}; 74*37da2899SCharles.Forsyth 75*37da2899SCharles.Forsyth 76*37da2899SCharles.Forsythabout() : array of string { 77*37da2899SCharles.Forsyth return core_commands; 78*37da2899SCharles.Forsyth} 79*37da2899SCharles.Forsyth 80*37da2899SCharles.Forsythinit(ctxt: ref Draw->Context, argv: list of string) { 81*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 82*37da2899SCharles.Forsyth draw = load Draw Draw->PATH; 83*37da2899SCharles.Forsyth bufmod = load Bufio Bufio->PATH; 84*37da2899SCharles.Forsyth htab = load Str_Hashtab Str_Hashtab->PATH; 85*37da2899SCharles.Forsyth mhtab = load Mod_Hashtab Mod_Hashtab->PATH; 86*37da2899SCharles.Forsyth shtab = load Sym_Hashtab Sym_Hashtab->PATH; 87*37da2899SCharles.Forsyth stack = load Tcl_Stack Tcl_Stack->PATH; 88*37da2899SCharles.Forsyth str = load String String->PATH; 89*37da2899SCharles.Forsyth utils = load Tcl_Utils Tcl_Utils->PATH; 90*37da2899SCharles.Forsyth tk = load Tk Tk->PATH; 91*37da2899SCharles.Forsyth wmlib= load Wmlib Wmlib->PATH; 92*37da2899SCharles.Forsyth if (bufmod == nil || htab == nil || stack == nil || 93*37da2899SCharles.Forsyth str == nil || utils == nil || tk == nil || 94*37da2899SCharles.Forsyth wmlib==nil || mhtab == nil || shtab == nil){ 95*37da2899SCharles.Forsyth sys->print("can't load initial modules %r\n"); 96*37da2899SCharles.Forsyth exit; 97*37da2899SCharles.Forsyth } 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth # get a new stack frame. 100*37da2899SCharles.Forsyth stack->init(); 101*37da2899SCharles.Forsyth (nvtab,avtab,symtab)=stack->newframe(); 102*37da2899SCharles.Forsyth 103*37da2899SCharles.Forsyth libmods=mhtab->alloc(101); 104*37da2899SCharles.Forsyth 105*37da2899SCharles.Forsyth # grab my pid, and set a new group to make me easy to kill. 106*37da2899SCharles.Forsyth mypid=sys->pctl(sys->NEWPGRP, nil); 107*37da2899SCharles.Forsyth 108*37da2899SCharles.Forsyth # no default top window. 109*37da2899SCharles.Forsyth tclmod.top=nil; 110*37da2899SCharles.Forsyth tclmod.context=ctxt; 111*37da2899SCharles.Forsyth tclmod.debug=0; 112*37da2899SCharles.Forsyth 113*37da2899SCharles.Forsyth # set up library modules. 114*37da2899SCharles.Forsyth args:=array[] of {"do_load","io"}; 115*37da2899SCharles.Forsyth do_load(args); 116*37da2899SCharles.Forsyth args=array[] of {"do_load","string"}; 117*37da2899SCharles.Forsyth do_load(args); 118*37da2899SCharles.Forsyth args=array[] of {"do_load","calc"}; 119*37da2899SCharles.Forsyth do_load(args); 120*37da2899SCharles.Forsyth args=array[] of {"do_load","list"}; 121*37da2899SCharles.Forsyth do_load(args); 122*37da2899SCharles.Forsyth args=array[] of {"do_load","tk"}; 123*37da2899SCharles.Forsyth do_load(args); 124*37da2899SCharles.Forsyth arr:=about(); 125*37da2899SCharles.Forsyth for(i:=0;i<len arr;i++) 126*37da2899SCharles.Forsyth libmods.insert(arr[i],nil); 127*37da2899SCharles.Forsyth 128*37da2899SCharles.Forsyth # cmd line args... 129*37da2899SCharles.Forsyth if (argv != nil) 130*37da2899SCharles.Forsyth argv = tl argv; 131*37da2899SCharles.Forsyth while (argv != nil) { 132*37da2899SCharles.Forsyth loadfile(hd argv); 133*37da2899SCharles.Forsyth argv = tl argv; 134*37da2899SCharles.Forsyth } 135*37da2899SCharles.Forsyth 136*37da2899SCharles.Forsyth} 137*37da2899SCharles.Forsyth 138*37da2899SCharles.Forsythset_top(win:ref Tk->Toplevel){ 139*37da2899SCharles.Forsyth tclmod.top=win; 140*37da2899SCharles.Forsyth} 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsythclear_error(){ 143*37da2899SCharles.Forsyth error=0; 144*37da2899SCharles.Forsyth errmsg=""; 145*37da2899SCharles.Forsyth} 146*37da2899SCharles.Forsyth 147*37da2899SCharles.Forsythnotify(num : int,s : string) : string { 148*37da2899SCharles.Forsyth error=1; 149*37da2899SCharles.Forsyth case num{ 150*37da2899SCharles.Forsyth 1 => 151*37da2899SCharles.Forsyth errmsg=sys->sprint( 152*37da2899SCharles.Forsyth "wrong # args: should be \"%s\"",s); 153*37da2899SCharles.Forsyth * => 154*37da2899SCharles.Forsyth errmsg= s; 155*37da2899SCharles.Forsyth } 156*37da2899SCharles.Forsyth return errmsg; 157*37da2899SCharles.Forsyth} 158*37da2899SCharles.Forsyth 159*37da2899SCharles.Forsythgrab_lines(new_inp,unfin: string ,lines : chan of string){ 160*37da2899SCharles.Forsyth error=0; 161*37da2899SCharles.Forsyth tclmod.lines=lines; 162*37da2899SCharles.Forsyth input,line : string; 163*37da2899SCharles.Forsyth if (new_inp==nil) 164*37da2899SCharles.Forsyth new_inp = "tcl%"; 165*37da2899SCharles.Forsyth if (unfin==nil) 166*37da2899SCharles.Forsyth unfin = "tcl>"; 167*37da2899SCharles.Forsyth sys->print("%s ", new_inp); 168*37da2899SCharles.Forsyth iob := bufmod->fopen(sys->fildes(0),bufmod->OREAD); 169*37da2899SCharles.Forsyth if (iob==nil){ 170*37da2899SCharles.Forsyth sys->print("cannot open stdin for reading.\n"); 171*37da2899SCharles.Forsyth return; 172*37da2899SCharles.Forsyth } 173*37da2899SCharles.Forsyth while((input=iob.gets('\n'))!=nil){ 174*37da2899SCharles.Forsyth line+=input; 175*37da2899SCharles.Forsyth if (!finished(line,0)) 176*37da2899SCharles.Forsyth sys->print("%s ", unfin); 177*37da2899SCharles.Forsyth else{ 178*37da2899SCharles.Forsyth lines <- = line; 179*37da2899SCharles.Forsyth line=nil; 180*37da2899SCharles.Forsyth } 181*37da2899SCharles.Forsyth } 182*37da2899SCharles.Forsyth} 183*37da2899SCharles.Forsyth 184*37da2899SCharles.Forsyth# this is the main function. Its input is a complete (i.e. matching 185*37da2899SCharles.Forsyth# brackets etc) tcl script, and its output is a message - if there 186*37da2899SCharles.Forsyth# is one. 187*37da2899SCharles.Forsythevalcmd(s: string, termchar: int) : string { 188*37da2899SCharles.Forsyth msg : string; 189*37da2899SCharles.Forsyth i:=0; 190*37da2899SCharles.Forsyth retfl=0; 191*37da2899SCharles.Forsyth if (tclmod.debug==2) 192*37da2899SCharles.Forsyth sys->print("Entered evalcmd, s=%s, termchar=%c\n",s,termchar); 193*37da2899SCharles.Forsyth # strip null statements.. 194*37da2899SCharles.Forsyth while((i<len s) && (s[i]=='\n' || s[i]==';')) i++; 195*37da2899SCharles.Forsyth if (i==len s) return nil; 196*37da2899SCharles.Forsyth 197*37da2899SCharles.Forsyth # parse the script statement by statement 198*37da2899SCharles.Forsyth for(;s!=nil;i++){ 199*37da2899SCharles.Forsyth # wait till we have a complete statement 200*37da2899SCharles.Forsyth if (i==len s || ((s[i]==termchar || s[i]==';' || s[i]=='\n') 201*37da2899SCharles.Forsyth && finished(s[0:i],termchar))){ 202*37da2899SCharles.Forsyth # throw it away if its a comment... 203*37da2899SCharles.Forsyth if (s[0]!='#') 204*37da2899SCharles.Forsyth argv := parsecmd(s[0:i],termchar,0); 205*37da2899SCharles.Forsyth msg = nil; 206*37da2899SCharles.Forsyth if (tclmod.debug==2) 207*37da2899SCharles.Forsyth for(k:=0;k<len argv;k++) 208*37da2899SCharles.Forsyth sys->print("argv[%d]: (%s)\n",k,argv[k]); 209*37da2899SCharles.Forsyth 210*37da2899SCharles.Forsyth # argv is now a completely parsed array of arguments 211*37da2899SCharles.Forsyth # for the Tcl command.. 212*37da2899SCharles.Forsyth 213*37da2899SCharles.Forsyth # find the module that the command is in and 214*37da2899SCharles.Forsyth # execute it. 215*37da2899SCharles.Forsyth if (len argv != 0){ 216*37da2899SCharles.Forsyth mod:=lookup(argv[0]); 217*37da2899SCharles.Forsyth if (mod!=nil){ 218*37da2899SCharles.Forsyth (error,msg)= 219*37da2899SCharles.Forsyth mod->exec(ref tclmod,argv); 220*37da2899SCharles.Forsyth if (error) 221*37da2899SCharles.Forsyth errmsg=msg; 222*37da2899SCharles.Forsyth } else { 223*37da2899SCharles.Forsyth if (argv[0]!=nil && 224*37da2899SCharles.Forsyth argv[0][0]=='.') 225*37da2899SCharles.Forsyth msg=do_tk(argv); 226*37da2899SCharles.Forsyth else 227*37da2899SCharles.Forsyth msg=exec(argv); 228*37da2899SCharles.Forsyth } 229*37da2899SCharles.Forsyth } 230*37da2899SCharles.Forsyth 231*37da2899SCharles.Forsyth # was there an error? 232*37da2899SCharles.Forsyth if (error) { 233*37da2899SCharles.Forsyth if (len argv > 0 && argv[0]!=""){ 234*37da2899SCharles.Forsyth stat : string; 235*37da2899SCharles.Forsyth stat = "In function "+argv[0]; 236*37da2899SCharles.Forsyth if (len argv >1 && argv[1]!=""){ 237*37da2899SCharles.Forsyth stat[len stat]=' '; 238*37da2899SCharles.Forsyth stat+=argv[1]; 239*37da2899SCharles.Forsyth } 240*37da2899SCharles.Forsyth stat+=".....\n\t"; 241*37da2899SCharles.Forsyth errmsg=stat+errmsg; 242*37da2899SCharles.Forsyth } 243*37da2899SCharles.Forsyth msg=errmsg; 244*37da2899SCharles.Forsyth } 245*37da2899SCharles.Forsyth 246*37da2899SCharles.Forsyth # we stop parsing if we hit a break, continue, return, 247*37da2899SCharles.Forsyth # error, termchar or end of string. 248*37da2899SCharles.Forsyth if (msg=="break" || msg=="continue" || error || retfl==1 249*37da2899SCharles.Forsyth || len s <= i || (len s > i && s[i]==termchar)) 250*37da2899SCharles.Forsyth return msg; 251*37da2899SCharles.Forsyth 252*37da2899SCharles.Forsyth # otherwise eat up the parsed statement and continue 253*37da2899SCharles.Forsyth s=s[i+1:]; 254*37da2899SCharles.Forsyth i=-1; 255*37da2899SCharles.Forsyth } 256*37da2899SCharles.Forsyth } 257*37da2899SCharles.Forsyth return msg; 258*37da2899SCharles.Forsyth} 259*37da2899SCharles.Forsyth 260*37da2899SCharles.Forsyth 261*37da2899SCharles.Forsyth# returns 1 if the line has matching braces, brackets and 262*37da2899SCharles.Forsyth# double-quotes and does not end in "\\\n" 263*37da2899SCharles.Forsythfinished(s : string, termchar : int) : int { 264*37da2899SCharles.Forsyth cb:=0; 265*37da2899SCharles.Forsyth dq:=0; 266*37da2899SCharles.Forsyth sb:=0; 267*37da2899SCharles.Forsyth if (s==nil) return 1; 268*37da2899SCharles.Forsyth if (termchar=='}') cb++; 269*37da2899SCharles.Forsyth if (termchar==']') sb++; 270*37da2899SCharles.Forsyth if (len s > 1 && s[len s -2]=='\\') 271*37da2899SCharles.Forsyth return 0; 272*37da2899SCharles.Forsyth if (s[0]=='{') cb++; 273*37da2899SCharles.Forsyth if (s[0]=='}' && cb>0) cb--; 274*37da2899SCharles.Forsyth if (s[0]=='[') sb++; 275*37da2899SCharles.Forsyth if (s[0]==']' && sb>0) sb--; 276*37da2899SCharles.Forsyth if (s[0]=='"') dq=1-dq; 277*37da2899SCharles.Forsyth for(i:=1;i<len s;i++){ 278*37da2899SCharles.Forsyth if (s[i]=='{' && s[i-1]!='\\') cb++; 279*37da2899SCharles.Forsyth if (s[i]=='}' && s[i-1]!='\\' && cb>0) cb--; 280*37da2899SCharles.Forsyth if (s[i]=='[' && s[i-1]!='\\') sb++; 281*37da2899SCharles.Forsyth if (s[i]==']' && s[i-1]!='\\' && sb>0) sb--; 282*37da2899SCharles.Forsyth if (s[i]=='"' && s[i-1]!='\\') dq=1-dq; 283*37da2899SCharles.Forsyth } 284*37da2899SCharles.Forsyth return (cb==0 && sb==0 && dq==0); 285*37da2899SCharles.Forsyth} 286*37da2899SCharles.Forsyth 287*37da2899SCharles.Forsyth# counts the offset till the next matching ']' 288*37da2899SCharles.Forsythstrip_to_match(s : string, ptr: int) : int { 289*37da2899SCharles.Forsyth j :=0; 290*37da2899SCharles.Forsyth nb:=0; 291*37da2899SCharles.Forsyth while(j<len s){ 292*37da2899SCharles.Forsyth if (s[j]=='{') 293*37da2899SCharles.Forsyth while (j < len s && s[j]!='}') j++; 294*37da2899SCharles.Forsyth if (s[j]=='[') nb++; 295*37da2899SCharles.Forsyth if (s[j]==']'){ 296*37da2899SCharles.Forsyth nb--; 297*37da2899SCharles.Forsyth if (nb==-1) return ptr+j; 298*37da2899SCharles.Forsyth } 299*37da2899SCharles.Forsyth j++; 300*37da2899SCharles.Forsyth } 301*37da2899SCharles.Forsyth return ptr+j; 302*37da2899SCharles.Forsyth} 303*37da2899SCharles.Forsyth 304*37da2899SCharles.Forsyth# returns the type of variable represented by the string s, which is 305*37da2899SCharles.Forsyth# a name. 306*37da2899SCharles.Forsythisa(s: string) : (int,int,string) { 307*37da2899SCharles.Forsyth found,val : int; 308*37da2899SCharles.Forsyth name,al : string; 309*37da2899SCharles.Forsyth curlev:=stack->level(); 310*37da2899SCharles.Forsyth if (tclmod.debug==2) 311*37da2899SCharles.Forsyth sys->print("Called isa with %s, current stack level is %d\n",s,curlev); 312*37da2899SCharles.Forsyth (found,nil)=nvtab.find(s); 313*37da2899SCharles.Forsyth if (found) return (TCL_SIMPLE,curlev,s); 314*37da2899SCharles.Forsyth for (i:=0;i<len avtab;i++){ 315*37da2899SCharles.Forsyth (nil,name)=avtab[i]; 316*37da2899SCharles.Forsyth if (name==s) return (TCL_ARRAY,curlev,s); 317*37da2899SCharles.Forsyth } 318*37da2899SCharles.Forsyth if (symtab==nil) 319*37da2899SCharles.Forsyth return (TCL_UNKNOWN,curlev,s); 320*37da2899SCharles.Forsyth (found,val,al)=symtab.find(s); 321*37da2899SCharles.Forsyth if (!found) 322*37da2899SCharles.Forsyth return (TCL_UNKNOWN,curlev,s); 323*37da2899SCharles.Forsyth (tnv,tav,nil):=stack->examine(val); 324*37da2899SCharles.Forsyth if (tclmod.debug==2) 325*37da2899SCharles.Forsyth sys->print("have a level %d for %s\n",val,al); 326*37da2899SCharles.Forsyth if (tnv!=nil){ 327*37da2899SCharles.Forsyth (found,nil)=tnv.find(al); 328*37da2899SCharles.Forsyth if (found) return (TCL_SIMPLE,val,al); 329*37da2899SCharles.Forsyth } 330*37da2899SCharles.Forsyth if (tav!=nil){ 331*37da2899SCharles.Forsyth for (i=0;i<len tav;i++){ 332*37da2899SCharles.Forsyth (nil,name)=tav[i]; 333*37da2899SCharles.Forsyth if (name==al) return (TCL_ARRAY,val,al); 334*37da2899SCharles.Forsyth } 335*37da2899SCharles.Forsyth } 336*37da2899SCharles.Forsyth if (tclmod.debug==2) 337*37da2899SCharles.Forsyth sys->print("%s not found, creating at stack level %d\n",al,val); 338*37da2899SCharles.Forsyth return (TCL_UNKNOWN,val,al); 339*37da2899SCharles.Forsyth} 340*37da2899SCharles.Forsyth 341*37da2899SCharles.Forsyth# This function only works if the string is already parsed! 342*37da2899SCharles.Forsyth# takes a var_name and returns the hash table for it and the 343*37da2899SCharles.Forsyth# name to look up. This is one of two things: 344*37da2899SCharles.Forsyth# for simple variables: 345*37da2899SCharles.Forsyth# findvar(foo) ---> (nvtab,foo) 346*37da2899SCharles.Forsyth# for associative arrays: 347*37da2899SCharles.Forsyth# findvar(foo(bar)) -----> (avtab[i],bar) 348*37da2899SCharles.Forsyth# where avtab[i].name==foo 349*37da2899SCharles.Forsyth# if create is 1, then an associative array is created upon first 350*37da2899SCharles.Forsyth# reference. 351*37da2899SCharles.Forsyth# returns (nil,error message) if there is a problem. 352*37da2899SCharles.Forsyth 353*37da2899SCharles.Forsythfind_var(s : string,create : int) : (ref Hash,string) { 354*37da2899SCharles.Forsyth rest,name,index : string; 355*37da2899SCharles.Forsyth retval,tnv : ref Hash; 356*37da2899SCharles.Forsyth tav : array of (ref Hash,string); 357*37da2899SCharles.Forsyth i,tag,lev: int; 358*37da2899SCharles.Forsyth (name,index)=str->splitl(s,"("); 359*37da2899SCharles.Forsyth if (index!=nil){ 360*37da2899SCharles.Forsyth (index,rest)=str->splitl(index[1:],")"); 361*37da2899SCharles.Forsyth if (rest!=")") 362*37da2899SCharles.Forsyth return (nil,"bad variable name"); 363*37da2899SCharles.Forsyth } 364*37da2899SCharles.Forsyth (tag,lev,name) = isa(name); 365*37da2899SCharles.Forsyth case tag { 366*37da2899SCharles.Forsyth TCL_SIMPLE => 367*37da2899SCharles.Forsyth if (index!=nil) 368*37da2899SCharles.Forsyth return (nil,"variable isn't array"); 369*37da2899SCharles.Forsyth (tnv,nil,nil)=stack->examine(lev); 370*37da2899SCharles.Forsyth return (tnv,name); 371*37da2899SCharles.Forsyth TCL_ARRAY => 372*37da2899SCharles.Forsyth if (index==nil) 373*37da2899SCharles.Forsyth return (nil,"variable is array"); 374*37da2899SCharles.Forsyth (nil,tav,nil)=stack->examine(lev); 375*37da2899SCharles.Forsyth for(i=0;i<len tav;i++){ 376*37da2899SCharles.Forsyth (retval,rest)=tav[i]; 377*37da2899SCharles.Forsyth if (rest==name) 378*37da2899SCharles.Forsyth return (retval,index); 379*37da2899SCharles.Forsyth } 380*37da2899SCharles.Forsyth return (nil,"find_var: impossible!!"); 381*37da2899SCharles.Forsyth # if we get here, the variable needs to be 382*37da2899SCharles.Forsyth # created. 383*37da2899SCharles.Forsyth TCL_UNKNOWN => 384*37da2899SCharles.Forsyth if (!create) 385*37da2899SCharles.Forsyth return (nil,"no such variable"); 386*37da2899SCharles.Forsyth (tnv,tav,nil)=stack->examine(lev); 387*37da2899SCharles.Forsyth if (index==nil) 388*37da2899SCharles.Forsyth return (tnv,name); 389*37da2899SCharles.Forsyth 390*37da2899SCharles.Forsyth } 391*37da2899SCharles.Forsyth # if we get here, we are creating an associative variable in the 392*37da2899SCharles.Forsyth # tav array. 393*37da2899SCharles.Forsyth for(i=0;i<len tav;i++){ 394*37da2899SCharles.Forsyth (retval,rest)=tav[i]; 395*37da2899SCharles.Forsyth if (rest==nil){ 396*37da2899SCharles.Forsyth retval=htab->alloc(101); 397*37da2899SCharles.Forsyth tav[i]=(retval,name); 398*37da2899SCharles.Forsyth return (retval,index); 399*37da2899SCharles.Forsyth } 400*37da2899SCharles.Forsyth } 401*37da2899SCharles.Forsyth return (nil,"associative array table full!"); 402*37da2899SCharles.Forsyth} 403*37da2899SCharles.Forsyth 404*37da2899SCharles.Forsyth# the main parsing function, a la ousterhouts man pages. Takes a 405*37da2899SCharles.Forsyth# string that is meant to be a tcl statement and parses it, 406*37da2899SCharles.Forsyth# reevaluating and quoting upto the termchar character. If disable 407*37da2899SCharles.Forsyth# is true, then whitespace is not ignored. 408*37da2899SCharles.Forsythparsecmd(s: string, termchar,disable: int) : array of string { 409*37da2899SCharles.Forsyth argv:= array[200] of string; 410*37da2899SCharles.Forsyth buf,nm,id: string; 411*37da2899SCharles.Forsyth argc := 0; 412*37da2899SCharles.Forsyth nc := 0; 413*37da2899SCharles.Forsyth c :=0; 414*37da2899SCharles.Forsyth tab : ref Hash; 415*37da2899SCharles.Forsyth 416*37da2899SCharles.Forsyth if (disable && (termchar=='\n' || termchar==';')) termchar=0; 417*37da2899SCharles.Forsyth outer: 418*37da2899SCharles.Forsyth for (i := 0; i<len s ;) { 419*37da2899SCharles.Forsyth if ((i>0 &&s[i-1]!='\\' &&s[i]==termchar)||(s[0]==termchar)) 420*37da2899SCharles.Forsyth break; 421*37da2899SCharles.Forsyth case int s[i] { 422*37da2899SCharles.Forsyth ' ' or '\t' or '\n' => 423*37da2899SCharles.Forsyth if (!disable){ 424*37da2899SCharles.Forsyth if (nc > 0) { # end of a word? 425*37da2899SCharles.Forsyth argv[argc++] = buf; 426*37da2899SCharles.Forsyth buf = nil; 427*37da2899SCharles.Forsyth nc = 0; 428*37da2899SCharles.Forsyth } 429*37da2899SCharles.Forsyth i++; 430*37da2899SCharles.Forsyth } 431*37da2899SCharles.Forsyth else 432*37da2899SCharles.Forsyth buf[nc++]=s[i++]; 433*37da2899SCharles.Forsyth '$' => 434*37da2899SCharles.Forsyth if (i>0 && s[i-1]=='\\') 435*37da2899SCharles.Forsyth buf[nc++]=s[i++]; 436*37da2899SCharles.Forsyth else { 437*37da2899SCharles.Forsyth (nm,id) = parsename(s[i+1:], termchar); 438*37da2899SCharles.Forsyth if (id!=nil) 439*37da2899SCharles.Forsyth nm=nm+"("+id+")"; 440*37da2899SCharles.Forsyth (tab,nm)=find_var(nm,0); #don't create var! 441*37da2899SCharles.Forsyth if (len nm > 0 && tab!=nil) { 442*37da2899SCharles.Forsyth (found, val) := tab.find(nm); 443*37da2899SCharles.Forsyth buf += val; 444*37da2899SCharles.Forsyth nc += len val; 445*37da2899SCharles.Forsyth #sys->print("Here s[i:] is (%s)\n",s[i:]); 446*37da2899SCharles.Forsyth if(nm==id) 447*37da2899SCharles.Forsyth while(s[i]!=')') i++; 448*37da2899SCharles.Forsyth else 449*37da2899SCharles.Forsyth if (s[i+1]=='{') 450*37da2899SCharles.Forsyth while(s[i]!='}') i++; 451*37da2899SCharles.Forsyth else 452*37da2899SCharles.Forsyth i += len nm; 453*37da2899SCharles.Forsyth if (nc==0 && (i==len s-1 || 454*37da2899SCharles.Forsyth s[i+1]==' ' || 455*37da2899SCharles.Forsyth s[i+1]=='\t'|| 456*37da2899SCharles.Forsyth s[i+1]==termchar)) 457*37da2899SCharles.Forsyth argv[argc++]=buf; 458*37da2899SCharles.Forsyth } else { 459*37da2899SCharles.Forsyth buf[nc++] = '$'; 460*37da2899SCharles.Forsyth } 461*37da2899SCharles.Forsyth i++; 462*37da2899SCharles.Forsyth } 463*37da2899SCharles.Forsyth '{' => 464*37da2899SCharles.Forsyth if (i>0 && s[i-1]=='\\') 465*37da2899SCharles.Forsyth buf[nc++]=s[i++]; 466*37da2899SCharles.Forsyth else if (s[i+1]=='}'){ 467*37da2899SCharles.Forsyth argv[argc++] = nil; 468*37da2899SCharles.Forsyth buf = nil; 469*37da2899SCharles.Forsyth nc = 0; 470*37da2899SCharles.Forsyth i+=2; 471*37da2899SCharles.Forsyth } else { 472*37da2899SCharles.Forsyth nbra := 1; 473*37da2899SCharles.Forsyth for (i++; i < len s; i++) { 474*37da2899SCharles.Forsyth if (s[i] == '{') 475*37da2899SCharles.Forsyth nbra++; 476*37da2899SCharles.Forsyth else if (s[i] == '}') { 477*37da2899SCharles.Forsyth nbra--; 478*37da2899SCharles.Forsyth if (nbra == 0) { 479*37da2899SCharles.Forsyth i++; 480*37da2899SCharles.Forsyth continue outer; 481*37da2899SCharles.Forsyth } 482*37da2899SCharles.Forsyth } 483*37da2899SCharles.Forsyth buf[nc++] = s[i]; 484*37da2899SCharles.Forsyth } 485*37da2899SCharles.Forsyth } 486*37da2899SCharles.Forsyth '[' => 487*37da2899SCharles.Forsyth if (i>0 && s[i-1]=='\\') 488*37da2899SCharles.Forsyth buf[nc++]=s[i++]; 489*37da2899SCharles.Forsyth else{ 490*37da2899SCharles.Forsyth a:=evalcmd(s[i+1:],']'); 491*37da2899SCharles.Forsyth if (error) 492*37da2899SCharles.Forsyth return nil; 493*37da2899SCharles.Forsyth if (nc>0){ 494*37da2899SCharles.Forsyth buf+=a; 495*37da2899SCharles.Forsyth nc += len a; 496*37da2899SCharles.Forsyth } else { 497*37da2899SCharles.Forsyth argv[argc++] = a; 498*37da2899SCharles.Forsyth buf = nil; 499*37da2899SCharles.Forsyth nc = 0; 500*37da2899SCharles.Forsyth } 501*37da2899SCharles.Forsyth i++; 502*37da2899SCharles.Forsyth i=strip_to_match(s[i:],i); 503*37da2899SCharles.Forsyth i++; 504*37da2899SCharles.Forsyth } 505*37da2899SCharles.Forsyth '"' => 506*37da2899SCharles.Forsyth if (i>0 && s[i-1]!='\\' && nc==0){ 507*37da2899SCharles.Forsyth ans:=parsecmd(s[i+1:],'"',1); 508*37da2899SCharles.Forsyth #sys->print("len ans is %d\n",len ans); 509*37da2899SCharles.Forsyth if (len ans!=0){ 510*37da2899SCharles.Forsyth for(;;){ 511*37da2899SCharles.Forsyth i++; 512*37da2899SCharles.Forsyth if(s[i]=='"' && 513*37da2899SCharles.Forsyth s[i-1]!='\\') 514*37da2899SCharles.Forsyth break; 515*37da2899SCharles.Forsyth } 516*37da2899SCharles.Forsyth i++; 517*37da2899SCharles.Forsyth argv[argc++] = ans[0]; 518*37da2899SCharles.Forsyth } else { 519*37da2899SCharles.Forsyth argv[argc++] = nil; 520*37da2899SCharles.Forsyth i+=2; 521*37da2899SCharles.Forsyth } 522*37da2899SCharles.Forsyth buf = nil; 523*37da2899SCharles.Forsyth nc = 0; 524*37da2899SCharles.Forsyth } 525*37da2899SCharles.Forsyth else buf[nc++] = s[i++]; 526*37da2899SCharles.Forsyth * => 527*37da2899SCharles.Forsyth if (s[i]=='\\'){ 528*37da2899SCharles.Forsyth c=unesc(s[i:]); 529*37da2899SCharles.Forsyth if (c!=0){ 530*37da2899SCharles.Forsyth buf[nc++] = c; 531*37da2899SCharles.Forsyth i+=2; 532*37da2899SCharles.Forsyth } else { 533*37da2899SCharles.Forsyth if (i+1 < len s && !(s[i+1]=='"' 534*37da2899SCharles.Forsyth || s[i+1]=='$' || s[i+1]=='{' 535*37da2899SCharles.Forsyth || s[i+1]=='[')) 536*37da2899SCharles.Forsyth buf[nc++]=s[i]; 537*37da2899SCharles.Forsyth i++; 538*37da2899SCharles.Forsyth } 539*37da2899SCharles.Forsyth c=0; 540*37da2899SCharles.Forsyth } else 541*37da2899SCharles.Forsyth buf[nc++]=s[i++]; 542*37da2899SCharles.Forsyth } 543*37da2899SCharles.Forsyth } 544*37da2899SCharles.Forsyth if (nc > 0) # fix up last word if present 545*37da2899SCharles.Forsyth argv[argc++] = buf; 546*37da2899SCharles.Forsyth ret := array[argc] of string; 547*37da2899SCharles.Forsyth ret[0:] = argv[0:argc]; 548*37da2899SCharles.Forsyth return ret; 549*37da2899SCharles.Forsyth} 550*37da2899SCharles.Forsyth 551*37da2899SCharles.Forsyth# parses a name by Tcl rules, a valid name is either $foo, $foo(bar) 552*37da2899SCharles.Forsyth# or ${foo}. 553*37da2899SCharles.Forsythparsename(s: string, termchar: int) : (string,string) { 554*37da2899SCharles.Forsyth ret,arr,rest: string; 555*37da2899SCharles.Forsyth rets : array of string; 556*37da2899SCharles.Forsyth if (len s == 0) 557*37da2899SCharles.Forsyth return (nil,nil); 558*37da2899SCharles.Forsyth if (s[0]=='{'){ 559*37da2899SCharles.Forsyth (ret,nil)=str->splitl(s,"}"); 560*37da2899SCharles.Forsyth #sys->print("returning [%s]\n",ret[1:]); 561*37da2899SCharles.Forsyth return (ret[1:],nil); 562*37da2899SCharles.Forsyth } 563*37da2899SCharles.Forsyth loop: for (i := 0; i < len s && s[i] != termchar; i++) { 564*37da2899SCharles.Forsyth case (s[i]) { 565*37da2899SCharles.Forsyth 'a' to 'z' or 'A' to 'Z' or '0' to '9' or '_' => 566*37da2899SCharles.Forsyth ret[i] = s[i]; 567*37da2899SCharles.Forsyth * => 568*37da2899SCharles.Forsyth break loop; 569*37da2899SCharles.Forsyth '(' => 570*37da2899SCharles.Forsyth arr=ret[0:i]; 571*37da2899SCharles.Forsyth rest=s[i+1:]; 572*37da2899SCharles.Forsyth rets=parsecmd(rest,')',0); 573*37da2899SCharles.Forsyth # should always be len 1? 574*37da2899SCharles.Forsyth if (len rets >1) 575*37da2899SCharles.Forsyth sys->print("len rets>1 in parsename!\n"); 576*37da2899SCharles.Forsyth return (arr,rets[0]); 577*37da2899SCharles.Forsyth } 578*37da2899SCharles.Forsyth } 579*37da2899SCharles.Forsyth return (ret,nil); 580*37da2899SCharles.Forsyth} 581*37da2899SCharles.Forsyth 582*37da2899SCharles.Forsythloadfile(file :string) : string { 583*37da2899SCharles.Forsyth iob : ref Iobuf; 584*37da2899SCharles.Forsyth msg,input,line : string; 585*37da2899SCharles.Forsyth if (file==nil) 586*37da2899SCharles.Forsyth return nil; 587*37da2899SCharles.Forsyth iob = bufmod->open(file,bufmod->OREAD); 588*37da2899SCharles.Forsyth if (iob==nil) 589*37da2899SCharles.Forsyth return notify(0,sys->sprint( 590*37da2899SCharles.Forsyth "couldn't read file \"%s\":%r",file)); 591*37da2899SCharles.Forsyth while((input=iob.gets('\n'))!=nil){ 592*37da2899SCharles.Forsyth line+=input; 593*37da2899SCharles.Forsyth if (finished(line,0)){ 594*37da2899SCharles.Forsyth # put in a return catch here... 595*37da2899SCharles.Forsyth line = prepass(line); 596*37da2899SCharles.Forsyth msg=evalcmd(line,0); 597*37da2899SCharles.Forsyth if (error) return errmsg; 598*37da2899SCharles.Forsyth line=nil; 599*37da2899SCharles.Forsyth } 600*37da2899SCharles.Forsyth } 601*37da2899SCharles.Forsyth return msg; 602*37da2899SCharles.Forsyth} 603*37da2899SCharles.Forsyth 604*37da2899SCharles.Forsyth 605*37da2899SCharles.Forsyth#unescapes a string. Can do better..... 606*37da2899SCharles.Forsythunesc(s: string) : int { 607*37da2899SCharles.Forsyth c: int; 608*37da2899SCharles.Forsyth if (len s == 1) return 0; 609*37da2899SCharles.Forsyth case s[1] { 610*37da2899SCharles.Forsyth 'a'=> c = '\a'; 611*37da2899SCharles.Forsyth 'n'=> c = '\n'; 612*37da2899SCharles.Forsyth 't'=> c = '\t'; 613*37da2899SCharles.Forsyth 'r'=> c = '\r'; 614*37da2899SCharles.Forsyth 'b'=> c = '\b'; 615*37da2899SCharles.Forsyth '\\'=> c = '\\'; 616*37da2899SCharles.Forsyth '}' => c = '}'; 617*37da2899SCharles.Forsyth ']' => c=']'; 618*37da2899SCharles.Forsyth # do hex and octal. 619*37da2899SCharles.Forsyth * => c = 0; 620*37da2899SCharles.Forsyth } 621*37da2899SCharles.Forsyth return c; 622*37da2899SCharles.Forsyth} 623*37da2899SCharles.Forsyth 624*37da2899SCharles.Forsyth# prepass a string and replace "\\n[ \t]*" with ' ' 625*37da2899SCharles.Forsythprepass(s : string) : string { 626*37da2899SCharles.Forsyth for(i := 0; i < len s; i++) { 627*37da2899SCharles.Forsyth if(s[i] != '\\') 628*37da2899SCharles.Forsyth continue; 629*37da2899SCharles.Forsyth j:=i; 630*37da2899SCharles.Forsyth if (s[i+1] == '\n') { 631*37da2899SCharles.Forsyth s[j]=' '; 632*37da2899SCharles.Forsyth i++; 633*37da2899SCharles.Forsyth while(i<len s && (s[i]==' ' || s[i]=='\t')) 634*37da2899SCharles.Forsyth i++; 635*37da2899SCharles.Forsyth if (i==len s) 636*37da2899SCharles.Forsyth s = s[0:j]; 637*37da2899SCharles.Forsyth else 638*37da2899SCharles.Forsyth s=s[0:j]+s[i+1:]; 639*37da2899SCharles.Forsyth i=j; 640*37da2899SCharles.Forsyth } 641*37da2899SCharles.Forsyth } 642*37da2899SCharles.Forsyth return s; 643*37da2899SCharles.Forsyth} 644*37da2899SCharles.Forsyth 645*37da2899SCharles.Forsythexec(argv : array of string) : string { 646*37da2899SCharles.Forsyth msg : string; 647*37da2899SCharles.Forsyth if (argv[0]=="") 648*37da2899SCharles.Forsyth return nil; 649*37da2899SCharles.Forsyth case (argv[0]) { 650*37da2899SCharles.Forsyth "append" => 651*37da2899SCharles.Forsyth msg= do_append(argv); 652*37da2899SCharles.Forsyth "array" => 653*37da2899SCharles.Forsyth msg= do_array(argv); 654*37da2899SCharles.Forsyth "break" or "continue" => 655*37da2899SCharles.Forsyth return argv[0]; 656*37da2899SCharles.Forsyth "catch" => 657*37da2899SCharles.Forsyth msg=do_catch(argv); 658*37da2899SCharles.Forsyth "debug" => 659*37da2899SCharles.Forsyth msg=do_debug(argv); 660*37da2899SCharles.Forsyth "dumpstack" => 661*37da2899SCharles.Forsyth msg=do_dumpstack(argv); 662*37da2899SCharles.Forsyth "exit" => 663*37da2899SCharles.Forsyth do_exit(); 664*37da2899SCharles.Forsyth "expr" => 665*37da2899SCharles.Forsyth msg = do_expr(argv); 666*37da2899SCharles.Forsyth "eval" => 667*37da2899SCharles.Forsyth msg = do_eval(argv); 668*37da2899SCharles.Forsyth "for" => 669*37da2899SCharles.Forsyth msg = do_for(argv); 670*37da2899SCharles.Forsyth "foreach" => 671*37da2899SCharles.Forsyth msg = do_foreach(argv); 672*37da2899SCharles.Forsyth "format" => 673*37da2899SCharles.Forsyth msg = do_string(argv); 674*37da2899SCharles.Forsyth "global" => 675*37da2899SCharles.Forsyth msg = do_global(argv); 676*37da2899SCharles.Forsyth "if" => 677*37da2899SCharles.Forsyth msg = do_if(argv); 678*37da2899SCharles.Forsyth "incr" => 679*37da2899SCharles.Forsyth msg = do_incr(argv); 680*37da2899SCharles.Forsyth "info" => 681*37da2899SCharles.Forsyth msg = do_info(argv); 682*37da2899SCharles.Forsyth "lappend" => 683*37da2899SCharles.Forsyth msg = do_lappend(argv); 684*37da2899SCharles.Forsyth "level" => 685*37da2899SCharles.Forsyth msg=sys->sprint("Current Stack "+ 686*37da2899SCharles.Forsyth "level is %d", 687*37da2899SCharles.Forsyth stack->level()); 688*37da2899SCharles.Forsyth "load" => 689*37da2899SCharles.Forsyth msg=do_load(argv); 690*37da2899SCharles.Forsyth "proc" => 691*37da2899SCharles.Forsyth msg=do_proc(argv); 692*37da2899SCharles.Forsyth "return" => 693*37da2899SCharles.Forsyth msg=do_return(argv); 694*37da2899SCharles.Forsyth retfl =1; 695*37da2899SCharles.Forsyth "set" => 696*37da2899SCharles.Forsyth msg = do_set(argv); 697*37da2899SCharles.Forsyth "source" => 698*37da2899SCharles.Forsyth msg = do_source(argv); 699*37da2899SCharles.Forsyth "string" => 700*37da2899SCharles.Forsyth msg = do_string(argv); 701*37da2899SCharles.Forsyth "switch" => 702*37da2899SCharles.Forsyth msg = do_switch(argv); 703*37da2899SCharles.Forsyth "time" => 704*37da2899SCharles.Forsyth msg=do_time(argv); 705*37da2899SCharles.Forsyth "unset" => 706*37da2899SCharles.Forsyth msg = do_unset(argv); 707*37da2899SCharles.Forsyth "uplevel" => 708*37da2899SCharles.Forsyth msg=do_uplevel(argv); 709*37da2899SCharles.Forsyth "upvar" => 710*37da2899SCharles.Forsyth msg=do_upvar(argv); 711*37da2899SCharles.Forsyth "while" => 712*37da2899SCharles.Forsyth msg = do_while(argv); 713*37da2899SCharles.Forsyth "#" => 714*37da2899SCharles.Forsyth msg=nil; 715*37da2899SCharles.Forsyth * => 716*37da2899SCharles.Forsyth msg = uproc(argv); 717*37da2899SCharles.Forsyth } 718*37da2899SCharles.Forsyth return msg; 719*37da2899SCharles.Forsyth} 720*37da2899SCharles.Forsyth 721*37da2899SCharles.Forsyth# from here on is the list of commands, alpahabetised, we hope. 722*37da2899SCharles.Forsyth 723*37da2899SCharles.Forsythdo_append(argv :array of string) : string { 724*37da2899SCharles.Forsyth tab : ref Hash; 725*37da2899SCharles.Forsyth if (len argv==1 || len argv==2) 726*37da2899SCharles.Forsyth return notify(1, 727*37da2899SCharles.Forsyth "append varName value ?value ...?"); 728*37da2899SCharles.Forsyth name := argv[1]; 729*37da2899SCharles.Forsyth (tab,name)=find_var(name,1); 730*37da2899SCharles.Forsyth if (tab==nil) 731*37da2899SCharles.Forsyth return notify(0,name); 732*37da2899SCharles.Forsyth (found, val) := tab.find(name); 733*37da2899SCharles.Forsyth for (i:=2;i<len argv;i++) 734*37da2899SCharles.Forsyth val+=argv[i]; 735*37da2899SCharles.Forsyth tab.insert(name,val); 736*37da2899SCharles.Forsyth return val; 737*37da2899SCharles.Forsyth} 738*37da2899SCharles.Forsyth 739*37da2899SCharles.Forsythdo_array(argv : array of string) : string { 740*37da2899SCharles.Forsyth tab : ref Hash; 741*37da2899SCharles.Forsyth name : string; 742*37da2899SCharles.Forsyth flag : int; 743*37da2899SCharles.Forsyth if (len argv!=3) 744*37da2899SCharles.Forsyth return notify(1,"array [names, size] name"); 745*37da2899SCharles.Forsyth case argv[1] { 746*37da2899SCharles.Forsyth "names" => 747*37da2899SCharles.Forsyth flag=1; 748*37da2899SCharles.Forsyth "size" => 749*37da2899SCharles.Forsyth flag=0; 750*37da2899SCharles.Forsyth * => 751*37da2899SCharles.Forsyth return notify(0,"expexted names or size, got "+argv[1]); 752*37da2899SCharles.Forsyth 753*37da2899SCharles.Forsyth } 754*37da2899SCharles.Forsyth (tag,lev,al) := isa(argv[2]); 755*37da2899SCharles.Forsyth if (tag!=TCL_ARRAY) 756*37da2899SCharles.Forsyth return notify(0,argv[2]+" isn't an array"); 757*37da2899SCharles.Forsyth (nil,tav,nil):=stack->examine(lev); 758*37da2899SCharles.Forsyth for (i:=0;i<len tav;i++){ 759*37da2899SCharles.Forsyth (tab,name)=tav[i]; 760*37da2899SCharles.Forsyth if (name==al) break; 761*37da2899SCharles.Forsyth } 762*37da2899SCharles.Forsyth if (flag==0) 763*37da2899SCharles.Forsyth return string tab.lsize; 764*37da2899SCharles.Forsyth return tab.dump(); 765*37da2899SCharles.Forsyth} 766*37da2899SCharles.Forsyth 767*37da2899SCharles.Forsythdo_catch(argv : array of string) : string { 768*37da2899SCharles.Forsyth if (len argv==1 || len argv > 3) 769*37da2899SCharles.Forsyth return notify(1,"catch command ?varName?"); 770*37da2899SCharles.Forsyth msg:=evalcmd(argv[1],0); 771*37da2899SCharles.Forsyth if (len argv==3 && error){ 772*37da2899SCharles.Forsyth (tab,name):=find_var(argv[2],1); 773*37da2899SCharles.Forsyth if (tab==nil) 774*37da2899SCharles.Forsyth return notify(0,name); 775*37da2899SCharles.Forsyth tab.insert(name, msg); 776*37da2899SCharles.Forsyth } 777*37da2899SCharles.Forsyth ret:=string error; 778*37da2899SCharles.Forsyth error=0; 779*37da2899SCharles.Forsyth return ret; 780*37da2899SCharles.Forsyth} 781*37da2899SCharles.Forsyth 782*37da2899SCharles.Forsythdo_debug(argv : array of string) : string { 783*37da2899SCharles.Forsyth add : string; 784*37da2899SCharles.Forsyth if (len argv!=2) 785*37da2899SCharles.Forsyth return notify(1,"debug"); 786*37da2899SCharles.Forsyth (i,rest):=str->toint(argv[1],10); 787*37da2899SCharles.Forsyth if (rest!=nil) 788*37da2899SCharles.Forsyth return notify(0,"Expected integer and got "+argv[1]); 789*37da2899SCharles.Forsyth tclmod.debug=i; 790*37da2899SCharles.Forsyth if (tclmod.debug==0) 791*37da2899SCharles.Forsyth add="off"; 792*37da2899SCharles.Forsyth else 793*37da2899SCharles.Forsyth add="on"; 794*37da2899SCharles.Forsyth return "debugging is now "+add+" at level"+ string i; 795*37da2899SCharles.Forsyth} 796*37da2899SCharles.Forsyth 797*37da2899SCharles.Forsythdo_dumpstack(argv : array of string) : string { 798*37da2899SCharles.Forsyth if (len argv!=1) 799*37da2899SCharles.Forsyth return notify(1,"dumpstack"); 800*37da2899SCharles.Forsyth stack->dump(); 801*37da2899SCharles.Forsyth return nil; 802*37da2899SCharles.Forsyth} 803*37da2899SCharles.Forsyth 804*37da2899SCharles.Forsythdo_eval(argv : array of string) : string { 805*37da2899SCharles.Forsyth eval_str : string; 806*37da2899SCharles.Forsyth for(i:=1;i<len argv;i++){ 807*37da2899SCharles.Forsyth eval_str += argv[i]; 808*37da2899SCharles.Forsyth eval_str[len eval_str]=' '; 809*37da2899SCharles.Forsyth } 810*37da2899SCharles.Forsyth return evalcmd(eval_str[0:len eval_str -1],0); 811*37da2899SCharles.Forsyth} 812*37da2899SCharles.Forsyth 813*37da2899SCharles.Forsythdo_exit(){ 814*37da2899SCharles.Forsyth kfd := sys->open("#p/"+string mypid+"/ctl", sys->OWRITE); 815*37da2899SCharles.Forsyth if(kfd == nil) 816*37da2899SCharles.Forsyth sys->print("error opening pid %d (%r)\n",mypid); 817*37da2899SCharles.Forsyth sys->fprint(kfd, "killgrp"); 818*37da2899SCharles.Forsyth exit; 819*37da2899SCharles.Forsyth} 820*37da2899SCharles.Forsyth 821*37da2899SCharles.Forsyth 822*37da2899SCharles.Forsyth 823*37da2899SCharles.Forsythdo_expr(argv : array of string) : string { 824*37da2899SCharles.Forsyth retval : string; 825*37da2899SCharles.Forsyth for (i:=1;i<len argv;i++){ 826*37da2899SCharles.Forsyth retval+=argv[i]; 827*37da2899SCharles.Forsyth retval[len retval]=' '; 828*37da2899SCharles.Forsyth } 829*37da2899SCharles.Forsyth retval=retval[0: len retval -1]; 830*37da2899SCharles.Forsyth argv=parsecmd(retval,0,0); 831*37da2899SCharles.Forsyth cal:=lookup("calc"); 832*37da2899SCharles.Forsyth (err,ret):= cal->exec(ref tclmod,argv); 833*37da2899SCharles.Forsyth if (err) return notify(0,ret); 834*37da2899SCharles.Forsyth return ret; 835*37da2899SCharles.Forsyth} 836*37da2899SCharles.Forsyth 837*37da2899SCharles.Forsyth 838*37da2899SCharles.Forsythdo_for(argv : array of string) : string { 839*37da2899SCharles.Forsyth if (len argv!=5) 840*37da2899SCharles.Forsyth return notify(1,"for start test next command"); 841*37da2899SCharles.Forsyth test := array[] of {"expr",argv[2]}; 842*37da2899SCharles.Forsyth evalcmd(argv[1],0); 843*37da2899SCharles.Forsyth for(;;){ 844*37da2899SCharles.Forsyth msg:=do_expr(test); 845*37da2899SCharles.Forsyth if (msg=="Error!") 846*37da2899SCharles.Forsyth return notify(0,sys->sprint( 847*37da2899SCharles.Forsyth "syntax error in expression \"%s\"", 848*37da2899SCharles.Forsyth argv[2])); 849*37da2899SCharles.Forsyth if (msg=="0") 850*37da2899SCharles.Forsyth return nil; 851*37da2899SCharles.Forsyth msg=evalcmd(argv[4],0); 852*37da2899SCharles.Forsyth if (msg=="break") 853*37da2899SCharles.Forsyth return nil; 854*37da2899SCharles.Forsyth if (msg=="continue"); #do nothing! 855*37da2899SCharles.Forsyth evalcmd(argv[3],0); 856*37da2899SCharles.Forsyth if (error) 857*37da2899SCharles.Forsyth return errmsg; 858*37da2899SCharles.Forsyth } 859*37da2899SCharles.Forsyth} 860*37da2899SCharles.Forsyth 861*37da2899SCharles.Forsyth 862*37da2899SCharles.Forsyth 863*37da2899SCharles.Forsythdo_foreach(argv: array of string) : string{ 864*37da2899SCharles.Forsyth tab : ref Hash; 865*37da2899SCharles.Forsyth if (len argv!=4) 866*37da2899SCharles.Forsyth return notify(1,"foreach varName list command"); 867*37da2899SCharles.Forsyth name := argv[1]; 868*37da2899SCharles.Forsyth (tab,name)=find_var(name,1); 869*37da2899SCharles.Forsyth if (tab==nil) 870*37da2899SCharles.Forsyth return notify(0,name); 871*37da2899SCharles.Forsyth arr:=utils->break_it(argv[2]); 872*37da2899SCharles.Forsyth for(i:=0;i<len arr;i++){ 873*37da2899SCharles.Forsyth tab.insert(name,arr[i]); 874*37da2899SCharles.Forsyth evalcmd(argv[3],0); 875*37da2899SCharles.Forsyth } 876*37da2899SCharles.Forsyth return nil; 877*37da2899SCharles.Forsyth} 878*37da2899SCharles.Forsyth 879*37da2899SCharles.Forsyth 880*37da2899SCharles.Forsyth 881*37da2899SCharles.Forsythdo_global(argv : array of string) : string { 882*37da2899SCharles.Forsyth if (len argv==1) 883*37da2899SCharles.Forsyth return notify(1,"global varName ?varName ...?"); 884*37da2899SCharles.Forsyth if (symtab==nil) 885*37da2899SCharles.Forsyth return nil; 886*37da2899SCharles.Forsyth for (i:=1 ; i < len argv;i++) 887*37da2899SCharles.Forsyth symtab.insert(argv[i],argv[i],0); 888*37da2899SCharles.Forsyth return nil; 889*37da2899SCharles.Forsyth} 890*37da2899SCharles.Forsyth 891*37da2899SCharles.Forsyth 892*37da2899SCharles.Forsyth 893*37da2899SCharles.Forsythdo_if(argv : array of string) : string { 894*37da2899SCharles.Forsyth if (len argv==1) 895*37da2899SCharles.Forsyth return notify(1,"no expression after \"if\" argument"); 896*37da2899SCharles.Forsyth expr1 := array[] of {"expr",argv[1]}; 897*37da2899SCharles.Forsyth msg:=do_expr(expr1); 898*37da2899SCharles.Forsyth if (msg=="Error!") 899*37da2899SCharles.Forsyth return notify(0,sys->sprint( 900*37da2899SCharles.Forsyth "syntax error in expression \"%s\"", 901*37da2899SCharles.Forsyth argv[1])); 902*37da2899SCharles.Forsyth if (len argv==2) 903*37da2899SCharles.Forsyth return notify(1,sys->sprint( 904*37da2899SCharles.Forsyth "no script following \""+ 905*37da2899SCharles.Forsyth "%s\" argument",msg)); 906*37da2899SCharles.Forsyth if (msg=="0"){ 907*37da2899SCharles.Forsyth if (len argv>3){ 908*37da2899SCharles.Forsyth if (argv[3]=="else"){ 909*37da2899SCharles.Forsyth if (len argv==4) 910*37da2899SCharles.Forsyth return notify(1, 911*37da2899SCharles.Forsyth "no script"+ 912*37da2899SCharles.Forsyth " following \"else\" argument"); 913*37da2899SCharles.Forsyth return evalcmd(argv[4],0); 914*37da2899SCharles.Forsyth } 915*37da2899SCharles.Forsyth if (argv[3]=="elseif"){ 916*37da2899SCharles.Forsyth argv[3]="if"; 917*37da2899SCharles.Forsyth return do_if(argv[3:]); 918*37da2899SCharles.Forsyth } 919*37da2899SCharles.Forsyth } 920*37da2899SCharles.Forsyth return nil; 921*37da2899SCharles.Forsyth } 922*37da2899SCharles.Forsyth return evalcmd(argv[2],0); 923*37da2899SCharles.Forsyth} 924*37da2899SCharles.Forsyth 925*37da2899SCharles.Forsythdo_incr(argv :array of string) : string { 926*37da2899SCharles.Forsyth num,xtra : int; 927*37da2899SCharles.Forsyth rest :string; 928*37da2899SCharles.Forsyth tab : ref Hash; 929*37da2899SCharles.Forsyth if (len argv==1) 930*37da2899SCharles.Forsyth return notify(1,"incr varName ?increment?"); 931*37da2899SCharles.Forsyth name := argv[1]; 932*37da2899SCharles.Forsyth (tab,name)=find_var(name,0); #doesn't create!! 933*37da2899SCharles.Forsyth if (tab==nil) 934*37da2899SCharles.Forsyth return notify(0,name); 935*37da2899SCharles.Forsyth (found, val) := tab.find(name); 936*37da2899SCharles.Forsyth if (!found) 937*37da2899SCharles.Forsyth return notify(0,sys->sprint("can't read \"%s\": " 938*37da2899SCharles.Forsyth +"no such variable",name)); 939*37da2899SCharles.Forsyth (num,rest)=str->toint(val,10); 940*37da2899SCharles.Forsyth if (rest!=nil) 941*37da2899SCharles.Forsyth return notify(0,sys->sprint( 942*37da2899SCharles.Forsyth "expected integer but got \"%s\"",val)); 943*37da2899SCharles.Forsyth if (len argv == 2){ 944*37da2899SCharles.Forsyth num+=1; 945*37da2899SCharles.Forsyth tab.insert(name,string num); 946*37da2899SCharles.Forsyth } 947*37da2899SCharles.Forsyth if (len argv == 3) { 948*37da2899SCharles.Forsyth val = argv[2]; 949*37da2899SCharles.Forsyth (xtra,rest)=str->toint(val,10); 950*37da2899SCharles.Forsyth if (rest!=nil) 951*37da2899SCharles.Forsyth return notify(0,sys->sprint( 952*37da2899SCharles.Forsyth "expected integer but got \"%s\"" 953*37da2899SCharles.Forsyth ,val)); 954*37da2899SCharles.Forsyth num+=xtra; 955*37da2899SCharles.Forsyth tab.insert(name, string num); 956*37da2899SCharles.Forsyth } 957*37da2899SCharles.Forsyth return string num; 958*37da2899SCharles.Forsyth} 959*37da2899SCharles.Forsyth 960*37da2899SCharles.Forsythdo_info(argv : array of string) : string { 961*37da2899SCharles.Forsyth if (len argv==1) 962*37da2899SCharles.Forsyth return notify(1,"info option ?arg arg ...?"); 963*37da2899SCharles.Forsyth case argv[1] { 964*37da2899SCharles.Forsyth "args" => 965*37da2899SCharles.Forsyth return do_info_args(argv,0); 966*37da2899SCharles.Forsyth "body" => 967*37da2899SCharles.Forsyth return do_info_args(argv,1); 968*37da2899SCharles.Forsyth "commands" => 969*37da2899SCharles.Forsyth return do_info_commands(argv); 970*37da2899SCharles.Forsyth "exists" => 971*37da2899SCharles.Forsyth return do_info_exists(argv); 972*37da2899SCharles.Forsyth "procs" => 973*37da2899SCharles.Forsyth return do_info_procs(argv); 974*37da2899SCharles.Forsyth 975*37da2899SCharles.Forsyth } 976*37da2899SCharles.Forsyth return sys->sprint( 977*37da2899SCharles.Forsyth "bad option \"%s\": should be args, body, commands, exists, procs", 978*37da2899SCharles.Forsyth argv[1]); 979*37da2899SCharles.Forsyth} 980*37da2899SCharles.Forsyth 981*37da2899SCharles.Forsythdo_info_args(argv : array of string,body :int) : string { 982*37da2899SCharles.Forsyth name: string; 983*37da2899SCharles.Forsyth s : sproc; 984*37da2899SCharles.Forsyth if (body) 985*37da2899SCharles.Forsyth name="body"; 986*37da2899SCharles.Forsyth else 987*37da2899SCharles.Forsyth name="args"; 988*37da2899SCharles.Forsyth if (len argv!=3) 989*37da2899SCharles.Forsyth return notify(1,"info "+name+" procname"); 990*37da2899SCharles.Forsyth for(i:=0;i<len proctab;i++){ 991*37da2899SCharles.Forsyth s=proctab[i]; 992*37da2899SCharles.Forsyth if (s.name==argv[2]) 993*37da2899SCharles.Forsyth break; 994*37da2899SCharles.Forsyth } 995*37da2899SCharles.Forsyth if (i==len proctab) 996*37da2899SCharles.Forsyth return notify(0,argv[2]+" isn't a procedure."); 997*37da2899SCharles.Forsyth if (body) 998*37da2899SCharles.Forsyth return s.script; 999*37da2899SCharles.Forsyth return s.args; 1000*37da2899SCharles.Forsyth} 1001*37da2899SCharles.Forsyth 1002*37da2899SCharles.Forsythdo_info_commands(argv : array of string) : string { 1003*37da2899SCharles.Forsyth if (len argv==1 || len argv>3) 1004*37da2899SCharles.Forsyth return notify(1,"info commands [pattern]"); 1005*37da2899SCharles.Forsyth return libmods.dump(); 1006*37da2899SCharles.Forsyth} 1007*37da2899SCharles.Forsyth 1008*37da2899SCharles.Forsythdo_info_exists(argv : array of string) : string { 1009*37da2899SCharles.Forsyth name, index : string; 1010*37da2899SCharles.Forsyth tab : ref Hash; 1011*37da2899SCharles.Forsyth if (len argv!=3) 1012*37da2899SCharles.Forsyth return notify(1,"info exists varName"); 1013*37da2899SCharles.Forsyth (name,index)=parsename(argv[2],0); 1014*37da2899SCharles.Forsyth (i,nil,nil):=isa(name); 1015*37da2899SCharles.Forsyth if (i==TCL_UNKNOWN) 1016*37da2899SCharles.Forsyth return "0"; 1017*37da2899SCharles.Forsyth if (index==nil) 1018*37da2899SCharles.Forsyth return "1"; 1019*37da2899SCharles.Forsyth (tab,name)=find_var(argv[2],0); 1020*37da2899SCharles.Forsyth if (tab==nil) 1021*37da2899SCharles.Forsyth return "0"; 1022*37da2899SCharles.Forsyth (found, val) := tab.find(name); 1023*37da2899SCharles.Forsyth if (!found) 1024*37da2899SCharles.Forsyth return "0"; 1025*37da2899SCharles.Forsyth return "1"; 1026*37da2899SCharles.Forsyth 1027*37da2899SCharles.Forsyth} 1028*37da2899SCharles.Forsyth 1029*37da2899SCharles.Forsythdo_info_procs(argv : array of string) : string { 1030*37da2899SCharles.Forsyth if (len argv==1 || len argv>3) 1031*37da2899SCharles.Forsyth return notify(1,"info procs [pattern]"); 1032*37da2899SCharles.Forsyth retval : string; 1033*37da2899SCharles.Forsyth for(i:=0;i<len proctab;i++){ 1034*37da2899SCharles.Forsyth s:=proctab[i]; 1035*37da2899SCharles.Forsyth if (s.name!=nil){ 1036*37da2899SCharles.Forsyth retval+=s.name; 1037*37da2899SCharles.Forsyth retval[len retval]=' '; 1038*37da2899SCharles.Forsyth } 1039*37da2899SCharles.Forsyth } 1040*37da2899SCharles.Forsyth return retval; 1041*37da2899SCharles.Forsyth} 1042*37da2899SCharles.Forsyth 1043*37da2899SCharles.Forsythdo_lappend(argv : array of string) : string{ 1044*37da2899SCharles.Forsyth tab : ref Hash; 1045*37da2899SCharles.Forsyth retval :string; 1046*37da2899SCharles.Forsyth retval=nil; 1047*37da2899SCharles.Forsyth if (len argv==1 || len argv==2) 1048*37da2899SCharles.Forsyth return notify(1, 1049*37da2899SCharles.Forsyth "lappend varName value ?value ...?"); 1050*37da2899SCharles.Forsyth name := argv[1]; 1051*37da2899SCharles.Forsyth (tab,name)=find_var(name,1); 1052*37da2899SCharles.Forsyth if (tab==nil) 1053*37da2899SCharles.Forsyth return notify(0,name); 1054*37da2899SCharles.Forsyth (found, val) := tab.find(name); 1055*37da2899SCharles.Forsyth for(i:=2;i<len argv;i++){ 1056*37da2899SCharles.Forsyth flag:=0; 1057*37da2899SCharles.Forsyth if (spaces(argv[i])) flag=1; 1058*37da2899SCharles.Forsyth if (flag) retval[len retval]='{'; 1059*37da2899SCharles.Forsyth retval += argv[i]; 1060*37da2899SCharles.Forsyth if (flag) retval[len retval]='}'; 1061*37da2899SCharles.Forsyth retval[len retval]=' '; 1062*37da2899SCharles.Forsyth } 1063*37da2899SCharles.Forsyth if (retval!=nil) 1064*37da2899SCharles.Forsyth retval=retval[0:len retval-1]; 1065*37da2899SCharles.Forsyth if (val!=nil) 1066*37da2899SCharles.Forsyth retval=val+" "+retval; 1067*37da2899SCharles.Forsyth tab.insert(name,retval); 1068*37da2899SCharles.Forsyth return retval; 1069*37da2899SCharles.Forsyth} 1070*37da2899SCharles.Forsyth 1071*37da2899SCharles.Forsythspaces(s : string) : int{ 1072*37da2899SCharles.Forsyth if (s==nil) return 1; 1073*37da2899SCharles.Forsyth for(i:=0;i<len s;i++) 1074*37da2899SCharles.Forsyth if (s[i]==' ' || s[i]=='\t') return 1; 1075*37da2899SCharles.Forsyth return 0; 1076*37da2899SCharles.Forsyth} 1077*37da2899SCharles.Forsyth 1078*37da2899SCharles.Forsythdo_load(argv : array of string) : string { 1079*37da2899SCharles.Forsyth # look for a dis library to load up, then 1080*37da2899SCharles.Forsyth # add to library array. 1081*37da2899SCharles.Forsyth if (len argv!=2) 1082*37da2899SCharles.Forsyth return notify(1,"load libname"); 1083*37da2899SCharles.Forsyth fname:="/dis/lib/tcl_"+argv[1]+".dis"; 1084*37da2899SCharles.Forsyth mod:= load TclLib fname; 1085*37da2899SCharles.Forsyth if (mod==nil) 1086*37da2899SCharles.Forsyth return notify(0, 1087*37da2899SCharles.Forsyth sys->sprint("Cannot load %s",fname)); 1088*37da2899SCharles.Forsyth arr:=mod->about(); 1089*37da2899SCharles.Forsyth for(i:=0;i<len arr;i++) 1090*37da2899SCharles.Forsyth libmods.insert(arr[i],mod); 1091*37da2899SCharles.Forsyth return nil; 1092*37da2899SCharles.Forsyth} 1093*37da2899SCharles.Forsyth 1094*37da2899SCharles.Forsyth 1095*37da2899SCharles.Forsythdo_proc(argv : array of string) : string { 1096*37da2899SCharles.Forsyth if (len argv != 4) 1097*37da2899SCharles.Forsyth return notify(1,"proc name args body"); 1098*37da2899SCharles.Forsyth for(i:=0;i<len proctab;i++) 1099*37da2899SCharles.Forsyth if (proctab[i].name==nil || 1100*37da2899SCharles.Forsyth proctab[i].name==argv[1]) break; 1101*37da2899SCharles.Forsyth if (i==len proctab) 1102*37da2899SCharles.Forsyth return notify(0,"procedure table full!"); 1103*37da2899SCharles.Forsyth proctab[i].name=argv[1]; 1104*37da2899SCharles.Forsyth proctab[i].args=argv[2]; 1105*37da2899SCharles.Forsyth proctab[i].script=argv[3]; 1106*37da2899SCharles.Forsyth return nil; 1107*37da2899SCharles.Forsyth} 1108*37da2899SCharles.Forsyth 1109*37da2899SCharles.Forsythdo_return(argv : array of string) : string { 1110*37da2899SCharles.Forsyth if (len argv==1) 1111*37da2899SCharles.Forsyth return nil; 1112*37da2899SCharles.Forsyth # put in options here..... 1113*37da2899SCharles.Forsyth return argv[1]; 1114*37da2899SCharles.Forsyth} 1115*37da2899SCharles.Forsyth 1116*37da2899SCharles.Forsythdo_set(argv : array of string) : string { 1117*37da2899SCharles.Forsyth tab : ref Hash; 1118*37da2899SCharles.Forsyth if (len argv == 1 || len argv > 3) 1119*37da2899SCharles.Forsyth return notify(1,"set varName ?newValue?"); 1120*37da2899SCharles.Forsyth name := argv[1]; 1121*37da2899SCharles.Forsyth (tab,name)=find_var(name,1); 1122*37da2899SCharles.Forsyth if (tab==nil) 1123*37da2899SCharles.Forsyth return notify(0,name); 1124*37da2899SCharles.Forsyth (found, val) := tab.find(name); 1125*37da2899SCharles.Forsyth if (len argv == 2) 1126*37da2899SCharles.Forsyth if (!found) 1127*37da2899SCharles.Forsyth val = notify(0,sys->sprint( 1128*37da2899SCharles.Forsyth "can't read \"%s\": " 1129*37da2899SCharles.Forsyth +"no such variable",name)); 1130*37da2899SCharles.Forsyth if (len argv == 3) { 1131*37da2899SCharles.Forsyth val = argv[2]; 1132*37da2899SCharles.Forsyth tab.insert(name, val); 1133*37da2899SCharles.Forsyth } 1134*37da2899SCharles.Forsyth return val; 1135*37da2899SCharles.Forsyth} 1136*37da2899SCharles.Forsyth 1137*37da2899SCharles.Forsythdo_source(argv : array of string) : string { 1138*37da2899SCharles.Forsyth if (len argv !=2) 1139*37da2899SCharles.Forsyth return notify(1,"source fileName"); 1140*37da2899SCharles.Forsyth return loadfile(argv[1]); 1141*37da2899SCharles.Forsyth} 1142*37da2899SCharles.Forsyth 1143*37da2899SCharles.Forsythdo_string(argv : array of string) : string { 1144*37da2899SCharles.Forsyth stringmod := lookup("string"); 1145*37da2899SCharles.Forsyth if (stringmod==nil) 1146*37da2899SCharles.Forsyth return notify(0,sys->sprint( 1147*37da2899SCharles.Forsyth "String Package not loaded (%r)")); 1148*37da2899SCharles.Forsyth (err,retval):= stringmod->exec(ref tclmod,argv); 1149*37da2899SCharles.Forsyth if (err) return notify(0,retval); 1150*37da2899SCharles.Forsyth return retval; 1151*37da2899SCharles.Forsyth} 1152*37da2899SCharles.Forsyth 1153*37da2899SCharles.Forsythdo_switch(argv : array of string) : string { 1154*37da2899SCharles.Forsyth i:=0; 1155*37da2899SCharles.Forsyth arr : array of string; 1156*37da2899SCharles.Forsyth if (len argv < 3) 1157*37da2899SCharles.Forsyth return notify(1,"switch " 1158*37da2899SCharles.Forsyth +"?switches? string pattern body ... "+ 1159*37da2899SCharles.Forsyth "?default body?\""); 1160*37da2899SCharles.Forsyth if (len argv == 3) 1161*37da2899SCharles.Forsyth arr=utils->break_it(argv[2]); 1162*37da2899SCharles.Forsyth else 1163*37da2899SCharles.Forsyth arr=argv[2:]; 1164*37da2899SCharles.Forsyth if (len arr % 2 !=0) 1165*37da2899SCharles.Forsyth return notify(0, 1166*37da2899SCharles.Forsyth "extra switch pattern with no body"); 1167*37da2899SCharles.Forsyth for (i=0;i<len arr;i+=2) 1168*37da2899SCharles.Forsyth if (argv[1]==arr[i]) 1169*37da2899SCharles.Forsyth break; 1170*37da2899SCharles.Forsyth if (i==len arr){ 1171*37da2899SCharles.Forsyth if (arr[i-2]=="default") 1172*37da2899SCharles.Forsyth return evalcmd(arr[i-1],0); 1173*37da2899SCharles.Forsyth else return nil; 1174*37da2899SCharles.Forsyth } 1175*37da2899SCharles.Forsyth while (i<len arr && arr[i+1]=="-") i+=2; 1176*37da2899SCharles.Forsyth return evalcmd(arr[i+1],0); 1177*37da2899SCharles.Forsyth} 1178*37da2899SCharles.Forsyth 1179*37da2899SCharles.Forsythdo_time(argv : array of string) : string { 1180*37da2899SCharles.Forsyth rest : string; 1181*37da2899SCharles.Forsyth end,start,times : int; 1182*37da2899SCharles.Forsyth if (len argv==1 || len argv>3) 1183*37da2899SCharles.Forsyth return notify(1,"time command ?count?"); 1184*37da2899SCharles.Forsyth if (len argv==2) 1185*37da2899SCharles.Forsyth times=1; 1186*37da2899SCharles.Forsyth else{ 1187*37da2899SCharles.Forsyth (times,rest)=str->toint(argv[2],10); 1188*37da2899SCharles.Forsyth if (rest!=nil) 1189*37da2899SCharles.Forsyth return notify(0,sys->sprint( 1190*37da2899SCharles.Forsyth "expected integer but got \"%s\"",argv[2])); 1191*37da2899SCharles.Forsyth } 1192*37da2899SCharles.Forsyth start=sys->millisec(); 1193*37da2899SCharles.Forsyth for(i:=0;i<times;i++) 1194*37da2899SCharles.Forsyth evalcmd(argv[1],0); 1195*37da2899SCharles.Forsyth end=sys->millisec(); 1196*37da2899SCharles.Forsyth r:= (real end - real start) / real times; 1197*37da2899SCharles.Forsyth return sys->sprint("%g milliseconds per iteration", r); 1198*37da2899SCharles.Forsyth} 1199*37da2899SCharles.Forsyth 1200*37da2899SCharles.Forsythdo_unset(argv : array of string) : string { 1201*37da2899SCharles.Forsyth tab : ref Hash; 1202*37da2899SCharles.Forsyth name: string; 1203*37da2899SCharles.Forsyth if (len argv == 1) 1204*37da2899SCharles.Forsyth return notify(1,"unset "+ 1205*37da2899SCharles.Forsyth "varName ?varName ...?"); 1206*37da2899SCharles.Forsyth for(i:=1;i<len argv;i++){ 1207*37da2899SCharles.Forsyth name = argv[i]; 1208*37da2899SCharles.Forsyth (tab,name)=find_var(name,0); 1209*37da2899SCharles.Forsyth if (tab==nil) 1210*37da2899SCharles.Forsyth return notify(0,sys->sprint("can't unset \"%s\": no such" + 1211*37da2899SCharles.Forsyth " variable",name)); 1212*37da2899SCharles.Forsyth tab.delete(name); 1213*37da2899SCharles.Forsyth 1214*37da2899SCharles.Forsyth } 1215*37da2899SCharles.Forsyth return nil; 1216*37da2899SCharles.Forsyth} 1217*37da2899SCharles.Forsyth 1218*37da2899SCharles.Forsythdo_uplevel(argv : array of string) : string { 1219*37da2899SCharles.Forsyth level: int; 1220*37da2899SCharles.Forsyth rest,scr : string; 1221*37da2899SCharles.Forsyth scr=nil; 1222*37da2899SCharles.Forsyth exact:=0; 1223*37da2899SCharles.Forsyth i:=1; 1224*37da2899SCharles.Forsyth if (len argv==1) 1225*37da2899SCharles.Forsyth return notify(1,"uplevel ?level? command ?arg ...?"); 1226*37da2899SCharles.Forsyth if (len argv==2) 1227*37da2899SCharles.Forsyth level=-1; 1228*37da2899SCharles.Forsyth else { 1229*37da2899SCharles.Forsyth lev:=argv[1]; 1230*37da2899SCharles.Forsyth if (lev[0]=='#'){ 1231*37da2899SCharles.Forsyth exact=1; 1232*37da2899SCharles.Forsyth lev=lev[1:]; 1233*37da2899SCharles.Forsyth } 1234*37da2899SCharles.Forsyth (level,rest)=str->toint(lev,10); 1235*37da2899SCharles.Forsyth if (rest!=nil){ 1236*37da2899SCharles.Forsyth i=2; 1237*37da2899SCharles.Forsyth level =-1; 1238*37da2899SCharles.Forsyth } 1239*37da2899SCharles.Forsyth } 1240*37da2899SCharles.Forsyth oldlev:=stack->level(); 1241*37da2899SCharles.Forsyth if (!exact) 1242*37da2899SCharles.Forsyth level+=oldlev; 1243*37da2899SCharles.Forsyth (tnv,tav,sym):=stack->examine(level); 1244*37da2899SCharles.Forsyth if (tnv==nil && tav==nil) 1245*37da2899SCharles.Forsyth return notify(0,"bad level "+argv[1]); 1246*37da2899SCharles.Forsyth if (tclmod.debug==2) 1247*37da2899SCharles.Forsyth sys->print("In uplevel, current level is %d, moving to level %d\n", 1248*37da2899SCharles.Forsyth oldlev,level); 1249*37da2899SCharles.Forsyth stack->move(level); 1250*37da2899SCharles.Forsyth oldav:=avtab; 1251*37da2899SCharles.Forsyth oldnv:=nvtab; 1252*37da2899SCharles.Forsyth oldsym:=symtab; 1253*37da2899SCharles.Forsyth avtab=tav; 1254*37da2899SCharles.Forsyth nvtab=tnv; 1255*37da2899SCharles.Forsyth symtab=sym; 1256*37da2899SCharles.Forsyth for(;i<len argv;i++) 1257*37da2899SCharles.Forsyth scr=scr+argv[i]+" "; 1258*37da2899SCharles.Forsyth msg:=evalcmd(scr[0:len scr-1],0); 1259*37da2899SCharles.Forsyth avtab=oldav; 1260*37da2899SCharles.Forsyth nvtab=oldnv; 1261*37da2899SCharles.Forsyth symtab=oldsym; 1262*37da2899SCharles.Forsyth ok:=stack->move(oldlev); 1263*37da2899SCharles.Forsyth if (tclmod.debug==2) 1264*37da2899SCharles.Forsyth sys->print("Leaving uplevel, current level is %d, moving back to"+ 1265*37da2899SCharles.Forsyth " level %d,move was %d\n", 1266*37da2899SCharles.Forsyth level,oldlev,ok); 1267*37da2899SCharles.Forsyth return msg; 1268*37da2899SCharles.Forsyth} 1269*37da2899SCharles.Forsyth 1270*37da2899SCharles.Forsythdo_upvar(argv : array of string) : string { 1271*37da2899SCharles.Forsyth level:int; 1272*37da2899SCharles.Forsyth rest:string; 1273*37da2899SCharles.Forsyth i:=1; 1274*37da2899SCharles.Forsyth exact:=0; 1275*37da2899SCharles.Forsyth if (len argv<3 || len argv>4) 1276*37da2899SCharles.Forsyth return notify(1,"upvar ?level? ThisVar OtherVar"); 1277*37da2899SCharles.Forsyth if (len argv==3) 1278*37da2899SCharles.Forsyth level=-1; 1279*37da2899SCharles.Forsyth else { 1280*37da2899SCharles.Forsyth lev:=argv[1]; 1281*37da2899SCharles.Forsyth if (lev[0]=='#'){ 1282*37da2899SCharles.Forsyth exact=1; 1283*37da2899SCharles.Forsyth lev=lev[1:]; 1284*37da2899SCharles.Forsyth } 1285*37da2899SCharles.Forsyth (level,rest)=str->toint(lev,10); 1286*37da2899SCharles.Forsyth if (rest!=nil){ 1287*37da2899SCharles.Forsyth i=2; 1288*37da2899SCharles.Forsyth level =-1; 1289*37da2899SCharles.Forsyth } 1290*37da2899SCharles.Forsyth } 1291*37da2899SCharles.Forsyth if (!exact) 1292*37da2899SCharles.Forsyth level+=stack->level(); 1293*37da2899SCharles.Forsyth symtab.insert(argv[i],argv[i+1],level); 1294*37da2899SCharles.Forsyth return nil; 1295*37da2899SCharles.Forsyth} 1296*37da2899SCharles.Forsyth 1297*37da2899SCharles.Forsythdo_while(argv : array of string) : string { 1298*37da2899SCharles.Forsyth if (len argv!=3) 1299*37da2899SCharles.Forsyth return notify(1,"while test command"); 1300*37da2899SCharles.Forsyth for(;;){ 1301*37da2899SCharles.Forsyth expr1 := array[] of {"expr",argv[1]}; 1302*37da2899SCharles.Forsyth msg:=do_expr(expr1); 1303*37da2899SCharles.Forsyth if (msg=="Error!") 1304*37da2899SCharles.Forsyth return notify(0,sys->sprint( 1305*37da2899SCharles.Forsyth "syntax error in expression \"%s\"", 1306*37da2899SCharles.Forsyth argv[1])); 1307*37da2899SCharles.Forsyth if (msg=="0") 1308*37da2899SCharles.Forsyth return nil; 1309*37da2899SCharles.Forsyth evalcmd(argv[2],0); 1310*37da2899SCharles.Forsyth if (error) 1311*37da2899SCharles.Forsyth return errmsg; 1312*37da2899SCharles.Forsyth } 1313*37da2899SCharles.Forsyth} 1314*37da2899SCharles.Forsyth 1315*37da2899SCharles.Forsythuproc(argv : array of string) : string { 1316*37da2899SCharles.Forsyth cmd,add : string; 1317*37da2899SCharles.Forsyth for(i:=0;i< len proctab;i++) 1318*37da2899SCharles.Forsyth if (proctab[i].name==argv[0]) 1319*37da2899SCharles.Forsyth break; 1320*37da2899SCharles.Forsyth if (i==len proctab) 1321*37da2899SCharles.Forsyth return notify(0,sys->sprint("invalid command name \"%s\"", 1322*37da2899SCharles.Forsyth argv[0])); 1323*37da2899SCharles.Forsyth # save tables 1324*37da2899SCharles.Forsyth # push a newframe 1325*37da2899SCharles.Forsyth # bind args to arguments 1326*37da2899SCharles.Forsyth # do cmd 1327*37da2899SCharles.Forsyth # pop frame 1328*37da2899SCharles.Forsyth # return msg 1329*37da2899SCharles.Forsyth 1330*37da2899SCharles.Forsyth # globals are supported, but upvar and uplevel are not! 1331*37da2899SCharles.Forsyth 1332*37da2899SCharles.Forsyth arg_arr:=utils->break_it(proctab[i].args); 1333*37da2899SCharles.Forsyth j:=len arg_arr; 1334*37da2899SCharles.Forsyth if (len argv < j+1 && arg_arr[j-1]!="args"){ 1335*37da2899SCharles.Forsyth j=len argv-1; 1336*37da2899SCharles.Forsyth return notify(0,sys->sprint( 1337*37da2899SCharles.Forsyth "no value given for"+ 1338*37da2899SCharles.Forsyth " parameter \"%s\" to \"%s\"", 1339*37da2899SCharles.Forsyth arg_arr[j],proctab[i].name)); 1340*37da2899SCharles.Forsyth } 1341*37da2899SCharles.Forsyth if ((len argv > j+1) && arg_arr[j-1]!="args") 1342*37da2899SCharles.Forsyth return notify(0,"called "+proctab[i].name+ 1343*37da2899SCharles.Forsyth " with too many arguments"); 1344*37da2899SCharles.Forsyth oldavtab:=avtab; 1345*37da2899SCharles.Forsyth oldnvtab:=nvtab; 1346*37da2899SCharles.Forsyth oldsymtab:=symtab; 1347*37da2899SCharles.Forsyth (nvtab,avtab,symtab)=stack->newframe(); 1348*37da2899SCharles.Forsyth for (j=0;j< len arg_arr-1;j++){ 1349*37da2899SCharles.Forsyth cmd="set "+arg_arr[j]+" {"+argv[j+1]+"}"; 1350*37da2899SCharles.Forsyth evalcmd(cmd,0); 1351*37da2899SCharles.Forsyth } 1352*37da2899SCharles.Forsyth if (len arg_arr>j && arg_arr[j] != "args") { 1353*37da2899SCharles.Forsyth cmd="set "+arg_arr[j]+" {"+argv[j+1]+"}"; 1354*37da2899SCharles.Forsyth evalcmd(cmd,0); 1355*37da2899SCharles.Forsyth } 1356*37da2899SCharles.Forsyth else { 1357*37da2899SCharles.Forsyth if (len arg_arr > j) { 1358*37da2899SCharles.Forsyth if (j+1==len argv) 1359*37da2899SCharles.Forsyth add=""; 1360*37da2899SCharles.Forsyth else 1361*37da2899SCharles.Forsyth add=argv[j+1]; 1362*37da2899SCharles.Forsyth cmd="set "+arg_arr[j]+" "; 1363*37da2899SCharles.Forsyth arglist:="{"+add+" "; 1364*37da2899SCharles.Forsyth j++; 1365*37da2899SCharles.Forsyth while(j<len argv-1) { 1366*37da2899SCharles.Forsyth arglist+=argv[j+1]; 1367*37da2899SCharles.Forsyth arglist[len arglist]=' '; 1368*37da2899SCharles.Forsyth j++; 1369*37da2899SCharles.Forsyth } 1370*37da2899SCharles.Forsyth arglist[len arglist]='}'; 1371*37da2899SCharles.Forsyth cmd+=arglist; 1372*37da2899SCharles.Forsyth evalcmd(cmd,0); 1373*37da2899SCharles.Forsyth } 1374*37da2899SCharles.Forsyth } 1375*37da2899SCharles.Forsyth msg:=evalcmd(proctab[i].script,0); 1376*37da2899SCharles.Forsyth stack->pop(); 1377*37da2899SCharles.Forsyth avtab=oldavtab; 1378*37da2899SCharles.Forsyth nvtab=oldnvtab; 1379*37da2899SCharles.Forsyth symtab=oldsymtab; 1380*37da2899SCharles.Forsyth #sys->print("Error is %d, msg is %s\n",error,msg); 1381*37da2899SCharles.Forsyth return msg; 1382*37da2899SCharles.Forsyth} 1383*37da2899SCharles.Forsyth 1384*37da2899SCharles.Forsythdo_tk(argv : array of string) : string { 1385*37da2899SCharles.Forsyth tkpack:=lookup("button"); 1386*37da2899SCharles.Forsyth (err,retval):= tkpack->exec(ref tclmod,argv); 1387*37da2899SCharles.Forsyth if (err) return notify(0,retval); 1388*37da2899SCharles.Forsyth return retval; 1389*37da2899SCharles.Forsyth} 1390*37da2899SCharles.Forsyth 1391*37da2899SCharles.Forsyth 1392*37da2899SCharles.Forsythlookup(s : string) : TclLib { 1393*37da2899SCharles.Forsyth (found,mod):=libmods.find(s); 1394*37da2899SCharles.Forsyth if (!found) 1395*37da2899SCharles.Forsyth return nil; 1396*37da2899SCharles.Forsyth return mod; 1397*37da2899SCharles.Forsyth} 1398