adict.c 11 KB

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