1implement Tkcmd; 2 3include "sys.m"; 4 sys: Sys; 5 stderr: ref Sys->FD; 6include "draw.m"; 7 draw: Draw; 8 Display, Image, Point: import draw; 9include "tk.m"; 10 tk: Tk; 11include "tkclient.m"; 12 tkclient: Tkclient; 13include "bufio.m"; 14include "arg.m"; 15 16Tkcmd : module { 17 init: fn(ctxt: ref Draw->Context, argv: list of string); 18}; 19 20usage() 21{ 22 sys->print("usage: tkcmd [-iu] [toplevelarg]\n"); 23 raise "fail:usage"; 24} 25 26badmodule(m: string) 27{ 28 sys->fprint(stderr, "tkcmd: cannot load %s: %r\n", m); 29 raise "fail:bad module"; 30} 31 32init(ctxt: ref Draw->Context, argv: list of string) 33{ 34 sys = load Sys Sys->PATH; 35 stderr = sys->fildes(2); 36 draw = load Draw Draw->PATH; 37 tk = load Tk Tk->PATH; 38 if (tk == nil) 39 badmodule(Tk->PATH); 40 tkclient = load Tkclient Tkclient->PATH; 41 if (tkclient==nil) 42 badmodule(Tkclient->PATH); 43 arg := load Arg Arg->PATH; 44 if (arg == nil) 45 badmodule(Arg->PATH); 46 47 arg->init(argv); 48 update := 1; 49 interactive := isconsole(sys->fildes(0)); 50 while ((opt := arg->opt()) != 0) { 51 case opt { 52 'i' => 53 interactive = 1; 54 'u' => 55 update = 0; 56 * => 57 usage(); 58 } 59 } 60 argv = arg->argv(); 61 arg = nil; 62 tkarg := ""; 63 if (argv != nil) { 64 if (tl argv != nil) 65 usage(); 66 tkarg = hd argv; 67 } 68 69 sys->pctl(Sys->NEWPGRP, nil); 70 tkclient->init(); 71 shellit(ctxt, tkarg, interactive, update); 72} 73 74isconsole(fd: ref Sys->FD): int 75{ 76 (ok1, d1) := sys->fstat(fd); 77 (ok2, d2) := sys->stat("/dev/cons"); 78 if (ok1 < 0 || ok2 < 0) 79 return 0; 80 return d1.dtype == d2.dtype && d1.qid.path == d2.qid.path; 81} 82 83shellit(ctxt: ref Draw->Context, arg: string, interactive, update: int) 84{ 85 (Wwsh, winctl) := tkclient->toplevel(ctxt, arg, "Tk", Tkclient->Appl); 86 tkclient->onscreen(Wwsh, nil); 87 tkclient->startinput(Wwsh, "ptr" :: "kbd" :: nil); 88 wm := Wwsh.ctxt; 89 if(update) 90 tk->cmd(Wwsh, "update"); 91 ps1 := ""; 92 ps2 := ""; 93 if (!interactive) 94 ps1 = ps2 = ""; 95 96 lines := chan of string; 97 sync := chan of int; 98 spawn grab_lines(ps1, ps2, lines, sync); 99 output := chan of string; 100 tk->namechan(Wwsh, output, "stdout"); 101 pid := <-sync; 102Loop: 103 for(;;) alt { 104 c := <-wm.kbd => 105 tk->keyboard(Wwsh, c); 106 m := <-wm.ptr => 107 tk->pointer(Wwsh, *m); 108 c := <-wm.ctl or 109 c = <-Wwsh.wreq => 110 tkclient->wmctl(Wwsh, c); 111 line := <-lines => 112 if (line == nil) 113 break Loop; 114 if (line[0] == '#') 115 break; 116 line = line[0:len line - 1]; 117 result := tk->cmd(Wwsh, line); 118 if (result != nil) 119 sys->print("#%s\n", result); 120 if (update) 121 tk->cmd(Wwsh, "update"); 122 sys->print("%s", ps1); 123 menu := <-winctl => 124 tkclient->wmctl(Wwsh, menu); 125 s := <-output => 126 sys->print("#<stdout>%s\n", s); 127 sys->print("%s", ps1); 128 } 129} 130 131grab_lines(new_inp, unfin: string, lines: chan of string, sync: chan of int) 132{ 133 sync <-= sys->pctl(0, nil); 134 { 135 bufmod := load Bufio Bufio->PATH; 136 Iobuf: import bufmod; 137 if (bufmod == nil) { 138 lines <-= nil; 139 return; 140 } 141 sys->print("%s", new_inp); 142 iob := bufmod->fopen(sys->fildes(0),bufmod->OREAD); 143 if (iob==nil){ 144 sys->fprint(stderr, "tkcmd: cannot open stdin for reading.\n"); 145 lines <-= nil; 146 return; 147 } 148 line := ""; 149 while((input := iob.gets('\n')) != nil) { 150 line+=input; 151 if (!finished(line,0)) 152 sys->print("%s", unfin); 153 else{ 154 lines <-= line; 155 line=nil; 156 } 157 } 158 lines <-= nil; 159 }exception e{ 160 "*" => 161 sys->fprint(stderr, "tkcmd: fail: %s\n", e); 162 lines <-= nil; 163 } 164} 165 166# returns 1 if the line has matching braces, brackets and 167# double-quotes and does not end in "\\\n" 168finished(s : string, termchar : int) : int { 169 cb:=0; 170 dq:=0; 171 sb:=0; 172 if (s==nil) return 1; 173 if (termchar=='}') cb++; 174 if (termchar==']') sb++; 175 if (len s > 1 && s[len s -2]=='\\') 176 return 0; 177 if (s[0]=='{') cb++; 178 if (s[0]=='}' && cb>0) cb--; 179 if (s[0]=='[') sb++; 180 if (s[0]==']' && sb>0) sb--; 181 if (s[0]=='"') dq=1-dq; 182 for(i:=1;i<len s;i++){ 183 if (s[i]=='{' && s[i-1]!='\\') cb++; 184 if (s[i]=='}' && s[i-1]!='\\' && cb>0) cb--; 185 if (s[i]=='[' && s[i-1]!='\\') sb++; 186 if (s[i]==']' && s[i-1]!='\\' && sb>0) sb--; 187 if (s[i]=='"' && s[i-1]!='\\') dq=1-dq; 188 } 189 return (cb==0 && sb==0 && dq==0); 190} 191