1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <thread.h>
5 #include "win.h"
6 #include "adict.h"
7
8 enum
9 {
10 STACK = 8192,
11 };
12
13 char *prog = "adict";
14 char *lprog = "/bin/adict";
15 char *xprog = "/bin/dict";
16 char *dict, *pattern, *curaddr[MAXMATCH], *curone, *args[6], buffer[80];
17 char abuffer[80], fbuffer[80], pbuffer[80];
18 int curindex, count, Eopen, Mopen;
19 Win Mwin, Ewin, Dwin;
20
21 void openwin(char*, char*, Win*, int);
22 void handle(Win*, int);
23 void rexec(void*);
24 void pexec(void*);
25 int getaddr(char*);
26
27 void
usage(void)28 usage(void)
29 {
30 fprint(2, "usage: %s [-d dictname] [pattern]\n", argv0);
31 threadexitsall(nil);
32 }
33
34 int mainstacksize = STACK;
35
36 void
threadmain(int argc,char ** argv)37 threadmain(int argc, char** argv)
38 {
39 ARGBEGIN{
40 case 'd':
41 dict = strdup(ARGF());
42 break;
43 default:
44 usage();
45 }ARGEND
46
47 /* if running as other name, note that fact */
48 if(access(argv0, AEXIST) == 0)
49 lprog = argv0;
50
51 switch(argc){
52 case 1:
53 pattern = pbuffer;
54 strcpy(pattern,argv[0]);
55 if(dict == nil)
56 dict = "pgw";
57 break;
58 case 0:
59 break;
60 default:
61 usage();
62 }
63
64 if ((dict == nil) && (pattern == nil))
65 openwin(prog,"", &Dwin, Dictwin);
66 if (pattern == nil)
67 openwin(prog,"",&Ewin, Entrywin);
68 if ((count = getaddr(pattern)) <= 1)
69 openwin(prog,"Prev Next", &Ewin, Entrywin);
70 else
71 openwin(prog, "", &Mwin, Matchwin);
72 }
73
74 static int
procrexec(char * xprog,...)75 procrexec(char *xprog, ...)
76 {
77 int fpipe[2];
78 void *rexarg[4];
79 Channel *c;
80 va_list va;
81 int i;
82 char *p;
83
84 pipe(fpipe);
85 va_start(va, xprog);
86 p = xprog;
87 for(i=0; p && i+1<nelem(args); i++){
88 args[i] = p;
89 p = va_arg(va, char*);
90 }
91 args[i] = nil;
92
93 c = chancreate(sizeof(ulong), 0);
94 rexarg[0] = xprog;
95 rexarg[1] = args;
96 rexarg[2] = fpipe;
97 rexarg[3] = c;
98
99 proccreate(rexec, rexarg, STACK);
100 recvul(c);
101 chanfree(c);
102 close(fpipe[1]);
103 return fpipe[0];
104 }
105
106 int
getaddr(char * pattern)107 getaddr(char *pattern)
108 {
109 /* Get char offset into dictionary of matches. */
110
111 int fd, i;
112 Biobuf inbuf;
113 char *bufptr;
114 char *obuf;
115
116 if (pattern == nil) {
117 curone = nil;
118 curindex = 0;
119 curaddr[curindex] = nil;
120 return 0;
121 }
122
123 sprint(buffer,"/%s/A", pattern);
124 fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
125 Binit(&inbuf, fd, OREAD);
126 i = 0;
127 curindex = 0;
128 while ((bufptr = Brdline(&inbuf, '\n')) != nil && (i < (MAXMATCH-1))) {
129 bufptr[Blinelen(&inbuf)-1] = 0;
130 obuf=bufptr;
131 while (bufptr[0] != '#' && bufptr[0] != 0) bufptr++;
132 if(bufptr[0] == 0)
133 print("whoops buf «%s»\n", obuf);
134 curaddr[i] = malloc(strlen(bufptr));
135 strcpy(curaddr[i], bufptr);
136 i++;
137 }
138 curaddr[i] = nil;
139 if (i == MAXMATCH)
140 fprint(2, "Too many matches!\n");
141 Bterm(&inbuf);
142 close(fd);
143
144 curone = curaddr[curindex];
145 return(i);
146 }
147
148 char*
getpattern(char * addr)149 getpattern(char *addr)
150 {
151 /* Get the pattern corresponding to an absolute address.*/
152 int fd;
153 char *res, *t;
154
155 res = nil;
156 sprint(buffer,"%sh", addr);
157 fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
158 if (read(fd, pbuffer, 80) > 80)
159 fprint(2, "Error in getting addres from dict.\n");
160 else {
161 t = pbuffer;
162 /* remove trailing whitespace, newline */
163 if (t != nil){
164 while(*t != 0 && *t != '\n')
165 t++;
166 if(t == 0 && t > pbuffer)
167 t--;
168 while(t >= pbuffer && (*t==' ' || *t=='\n' || *t=='\t' || *t=='\r'))
169 *t-- = 0;
170 }
171 res = pbuffer;
172 }
173 close(fd);
174 return(res);
175 }
176
177 char*
chgaddr(int dir)178 chgaddr(int dir)
179 {
180 /* Increment or decrement the current address (curone). */
181
182 int fd;
183 char *res, *t;
184
185 res = nil;
186 if (dir < 0)
187 sprint(buffer,"%s-a", curone);
188 else
189 sprint(buffer,"%s+a", curone);
190 fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
191 if (read(fd, abuffer, 80) > 80)
192 fprint(2, "Error in getting addres from dict.\n");
193 else {
194 res = abuffer;
195 while (*res != '#') res++;
196 t = res;
197 while ((*t != '\n') && (t != nil)) t++;
198 if (t != nil) *t = 0;
199 }
200 close(fd);
201 return(res);
202 }
203
204 void
dispdicts(Win * cwin)205 dispdicts(Win *cwin)
206 {
207 /* Display available dictionaries in window. */
208
209 int fd, nb, i;
210 char buf[1024], *t;
211
212 fd = procrexec(xprog, "-d", "?", nil);
213 wreplace(cwin, "0,$","",0); /* Clear window */
214 while ((nb = read(fd, buf, 1024)) > 0) {
215 t = buf;
216 i = 0;
217 if (strncmp("Usage", buf, 5) == 0) { /* Remove first line. */
218 while (t[0] != '\n') {
219 t++;
220 i++;
221 }
222 t++;
223 i++;
224 }
225 wwritebody(cwin, t, nb-i);
226 }
227 close(fd);
228 wclean(cwin);
229 }
230
231 void
dispentry(Win * cwin)232 dispentry(Win *cwin)
233 {
234 /* Display the current selection in window. */
235
236 int fd, nb;
237 char buf[BUFSIZE];
238
239 if (curone == nil) {
240 if (pattern != nil) {
241 sprint(buf,"Pattern not found.\n");
242 wwritebody(cwin, buf, 19);
243 wclean(cwin);
244 }
245 return;
246 }
247 sprint(buffer,"%sp", curone);
248 fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
249 wreplace(cwin, "0,$","",0); /* Clear window */
250 while ((nb = read(fd, buf, BUFSIZE)) > 0) {
251 wwritebody(cwin, buf, nb);
252 }
253 close(fd);
254 wclean(cwin);
255 }
256
257 void
dispmatches(Win * cwin)258 dispmatches(Win *cwin)
259 {
260 /* Display the current matches. */
261
262 int fd, nb;
263 char buf[BUFSIZE];
264
265 sprint(buffer,"/%s/H", pattern);
266 fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
267 while ((nb = read(fd, buf, BUFSIZE)) > 0)
268 wwritebody(cwin, buf, nb);
269 close(fd);
270 wclean(cwin);
271 }
272
273 char*
format(char * s)274 format(char *s)
275 {
276 /* Format a string to be written in window tag. Acme doesn't like */
277 /* non alpha-num's in the tag line. */
278
279 char *t, *h;
280
281 t = fbuffer;
282 if (s == nil) {
283 *t = 0;
284 return t;
285 }
286 strcpy(t, s);
287 h = t;
288 while (*t != 0) {
289 if (!(((*t >= 'a') && (*t <= 'z')) ||
290 ((*t >= 'A') && (*t <= 'Z')) ||
291 ((*t >= '0') && (*t <= '9'))))
292 *t = '_';
293 t++;
294 }
295 if (strlen(h) > MAXTAG)
296 h[MAXTAG] = 0;
297 if (strcmp(s,h) == 0) return s;
298 return h;
299 }
300
301 void
openwin(char * name,char * buttons,Win * twin,int wintype)302 openwin(char *name, char *buttons, Win *twin, int wintype)
303 {
304 char buf[80];
305
306 wnew(twin);
307 if (wintype == Dictwin)
308 sprint(buf,"%s",name);
309 else
310 if ((wintype == Entrywin) && (count > 1))
311 sprint(buf,"%s/%s/%s/%d",name, dict, format(pattern), curindex+1);
312 else
313 sprint(buf,"%s/%s/%s",name, dict, format(pattern));
314 wname(twin, buf);
315 wtagwrite(twin, buttons, strlen(buttons));
316 wclean(twin);
317 wdormant(twin);
318 if (wintype == Dictwin)
319 dispdicts(twin);
320 if (wintype == Matchwin) {
321 Mopen = True;
322 dispmatches(twin);
323 }
324 if (wintype == Entrywin) {
325 Eopen = True;
326 dispentry(twin);
327 }
328 handle(twin, wintype);
329 }
330
331 void
vopenwin(void * v)332 vopenwin(void *v)
333 {
334 void **arg;
335 char *name, *buttons;
336 Win *twin;
337 int wintype;
338
339 arg = v;
340 name = arg[0];
341 buttons = arg[1];
342 twin = arg[2];
343 wintype = (int)arg[3];
344 sendul(arg[4], 0);
345
346 openwin(name, buttons, twin, wintype);
347 threadexits(nil);
348 }
349
350 void
procopenwin(char * name,char * buttons,Win * twin,int wintype)351 procopenwin(char *name, char *buttons, Win *twin, int wintype)
352 {
353 void *arg[5];
354 Channel *c;
355
356 c = chancreate(sizeof(ulong), 0);
357 arg[0] = name;
358 arg[1] = buttons;
359 arg[2] = twin;
360 arg[3] = (void*)wintype;
361 arg[4] = c;
362 proccreate(vopenwin, arg, STACK);
363 recvul(c);
364 chanfree(c);
365 }
366
367 void
rexec(void * v)368 rexec(void *v)
369 {
370 void **arg;
371 char *prog;
372 char **args;
373 int *fd;
374 Channel *c;
375
376 arg = v;
377 prog = arg[0];
378 args = arg[1];
379 fd = arg[2];
380 c = arg[3];
381
382 rfork(RFENVG|RFFDG);
383 dup(fd[1], 1);
384 close(fd[1]);
385 close(fd[0]);
386 procexec(c, prog, args);
387 fprint(2, "Remote pipe execution failed: %s %r\n", prog);
388 abort();
389 threadexits(nil);
390 }
391
392 void
pexec(void * v)393 pexec(void *v)
394 {
395 void **arg;
396 char *prog;
397 char **args;
398 Channel *c;
399
400 arg = v;
401 prog = arg[0];
402 args = arg[1];
403 c = arg[2];
404
405 procexec(c, prog, args);
406 fprint(2, "Remote execution failed: %s %r\n", prog);
407 abort();
408 threadexits(nil);
409 }
410
411 void
procpexec(char * prog,char ** args)412 procpexec(char *prog, char **args)
413 {
414 void *rexarg[4];
415 Channel *c;
416
417 c = chancreate(sizeof(ulong), 0);
418 rexarg[0] = prog;
419 rexarg[1] = args;
420 rexarg[2] = c;
421
422 proccreate(pexec, rexarg, STACK);
423 recvul(c);
424 chanfree(c);
425 }
426
427 void
kill(void)428 kill(void)
429 {
430 /* Kill all processes related to this one. */
431 int fd;
432
433 sprint(buffer, "/proc/%d/notepg", getpid());
434 fd = open(buffer, OWRITE);
435 rfork(RFNOTEG);
436 write(fd, "kill", 4);
437 }
438
439 int
command(char * com,Win * w,int wintype)440 command(char *com, Win *w, int wintype)
441 {
442 char *buf;
443
444 if (strncmp(com, "Del", 3) == 0) {
445 switch(wintype){
446 case Entrywin:
447 if (wdel(w)) {
448 Eopen = False;
449 threadexits(nil);
450 }
451 break;
452 case Dictwin:
453 if (wdel(w))
454 threadexits(nil);
455 break;
456 case Matchwin:
457 kill();
458 if (Eopen)
459 if (~wdel(&Ewin)) /* Remove the entry window */
460 wdel(&Ewin);
461 if (!wdel(w))
462 wdel(w);
463 threadexits(nil);
464 break;
465 }
466 return True;
467 }
468 if (strncmp(com, "Next", 4) == 0){
469 if (curone != nil) {
470 curone = chgaddr(1);
471 buf = getpattern(curone);
472 sprint(buffer,"%s/%s/%s", prog, dict, format(buf));
473 wname(w, buffer);
474 dispentry(w);
475 }
476 return True;
477 }
478 if (strncmp(com, "Prev",4) == 0){
479 if (curone != nil) {
480 curone = chgaddr(-1);
481 buf = getpattern(curone);
482 sprint(buffer,"%s/%s/%s", prog, dict, format(buf));
483 wname(w, buffer);
484 dispentry(w);
485 }
486 return True;
487 }
488 if (strncmp(com, "Nmatch",6) == 0){
489 if (curaddr[++curindex] == nil)
490 curindex = 0;
491 curone = curaddr[curindex];
492 if (curone != nil) {
493 sprint(buffer,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1);
494 wname(w, buffer);
495 dispentry(w);
496 }
497 return True;
498 }
499 return False;
500 }
501
502 void
handle(Win * w,int wintype)503 handle(Win *w, int wintype)
504 {
505 Event e, e2, ea, etoss;
506 char *s, *t, buf[80];
507 int tmp, na;
508
509 while (True) {
510 wevent(w, &e);
511 switch(e.c2){
512 default:
513 /* fprint(2,"unknown message %c%c\n", e.c1, e.c2); */
514 break;
515 case 'i':
516 /* fprint(2,"'%s' inserted in tag at %d\n", e.b, e.q0);*/
517 break;
518 case 'I':
519 /* fprint(2,"'%s' inserted in body at %d\n", e.b, e.q0);*/
520 break;
521 case 'd':
522 /* fprint(2, "'%s' deleted in tag at %d\n", e.b, e.q0);*/
523 break;
524 case 'D':
525 /* fprint(2, "'%s' deleted in body at %d\n", e.b, e.q0);*/
526 break;
527 case 'x':
528 case 'X': /* Execute command. */
529 if (e.flag & 2)
530 wevent(w, &e2);
531 if(e.flag & 8){
532 wevent(w, &ea);
533 wevent(w, &etoss);
534 na = ea.nb;
535 } else
536 na = 0;
537 s = e.b;
538 if ((e.flag & 2) && e.nb == 0)
539 s = e2.b;
540 if(na){
541 t = malloc(strlen(s)+1+na+1);
542 snprint(t, strlen(s)+1+na+1, "%s %s", s, ea.b);
543 s = t;
544 }
545 /* if it's a long message, it can't be for us anyway */
546 if(!command(s, w, wintype)) /* send it back */
547 wwriteevent(w, &e);
548 if(na)
549 free(s);
550 break;
551 case 'l':
552 case 'L': /* Look for something. */
553 if (e.flag & 2)
554 wevent(w, &e);
555 wclean(w); /* Set clean bit. */
556 if (wintype == Dictwin) {
557 strcpy(buf, e.b);
558 args[0] = lprog;
559 args[1] = "-d";
560 args[2] = buf;
561 args[3] = nil;
562 procpexec(lprog, args); /* New adict with chosen dict. */
563 }
564 if (wintype == Entrywin) {
565 strcpy(buf, e.b);
566 args[0] = lprog;
567 args[1] = "-d";
568 args[2] = dict;
569 args[3] = buf;
570 args[4] = nil;
571 procpexec(lprog, args); /* New adict with chosen pattern. */
572 }
573 if (wintype == Matchwin) {
574 tmp = atoi(e.b) - 1;
575 if ((tmp >= 0) && (tmp < MAXMATCH) && (curaddr[tmp] != nil)) {
576 curindex = tmp;
577 curone = curaddr[curindex];
578 /* Display selected match. */
579 if (Eopen) {
580 sprint(buf,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1);
581 wname(&Ewin, buf);
582 dispentry(&Ewin);
583 }
584 else
585 procopenwin(prog,"Nmatch Prev Next", &Ewin, Entrywin);
586 }
587 }
588 break;
589 }
590 }
591 }
592