xref: /plan9/acme/bin/source/adict/adict.c (revision 1fa40b8e14c9d7f57c6217ec3d34b78924e14594)
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