main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  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 <fcall.h>
  14. #include <9p.h>
  15. #include <ctype.h>
  16. #include "dat.h"
  17. void mainctl(void*);
  18. void startcmd(char *[], int*);
  19. void stdout2body(void*);
  20. int debug;
  21. int notepg;
  22. int eraseinput;
  23. int dirty = 0;
  24. Window *win; /* the main window */
  25. void
  26. usage(void)
  27. {
  28. fprint(2, "usage: win [command]\n");
  29. threadexitsall("usage");
  30. }
  31. void
  32. threadmain(int argc, char *argv[])
  33. {
  34. int i, j;
  35. char *dir, *tag, *name;
  36. char buf[1024], **av;
  37. quotefmtinstall();
  38. rfork(RFNAMEG);
  39. ARGBEGIN{
  40. case 'd':
  41. debug = 1;
  42. chatty9p++;
  43. break;
  44. case 'e':
  45. eraseinput = 1;
  46. break;
  47. case 'D':
  48. {extern int _threaddebuglevel;
  49. _threaddebuglevel = 1<<20;
  50. }
  51. }ARGEND
  52. if(argc == 0){
  53. av = emalloc(3*sizeof(char*));
  54. av[0] = "rc";
  55. av[1] = "-i";
  56. name = getenv("sysname");
  57. }else{
  58. av = argv;
  59. name = utfrrune(av[0], '/');
  60. if(name)
  61. name++;
  62. else
  63. name = av[0];
  64. }
  65. if(getwd(buf, sizeof buf) == 0)
  66. dir = "/";
  67. else
  68. dir = buf;
  69. dir = estrdup(dir);
  70. tag = estrdup(dir);
  71. tag = eappend(estrdup(tag), "/-", name);
  72. win = newwindow();
  73. snprint(buf, sizeof buf, "%d", win->id);
  74. putenv("winid", buf);
  75. winname(win, tag);
  76. wintagwrite(win, "Send Noscroll", 5+8);
  77. threadcreate(mainctl, win, STACK);
  78. mountcons();
  79. threadcreate(fsloop, nil, STACK);
  80. startpipe();
  81. startcmd(av, &notepg);
  82. strcpy(buf, "win");
  83. j = 3;
  84. for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){
  85. strcpy(buf+j, " ");
  86. strcpy(buf+j+1, argv[i]);
  87. j += 1+strlen(argv[i]);
  88. }
  89. ctlprint(win->ctl, "scroll");
  90. winsetdump(win, dir, buf);
  91. }
  92. int
  93. EQUAL(char *s, char *t)
  94. {
  95. while(tolower(*s) == tolower(*t++))
  96. if(*s++ == '\0')
  97. return 1;
  98. return 0;
  99. }
  100. int
  101. command(Window *w, char *s)
  102. {
  103. while(*s==' ' || *s=='\t' || *s=='\n')
  104. s++;
  105. if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){
  106. write(notepg, "hangup", 6);
  107. windel(w, 1);
  108. threadexitsall(nil);
  109. return 1;
  110. }
  111. if(EQUAL(s, "scroll")){
  112. ctlprint(w->ctl, "scroll\nshow");
  113. return 1;
  114. }
  115. if(EQUAL(s, "noscroll")){
  116. ctlprint(w->ctl, "noscroll");
  117. return 1;
  118. }
  119. return 0;
  120. }
  121. static long
  122. utfncpy(char *to, char *from, int n)
  123. {
  124. char *end, *e;
  125. e = to+n;
  126. if(to >= e)
  127. return 0;
  128. end = memccpy(to, from, '\0', e - to);
  129. if(end == nil){
  130. end = e;
  131. if(end[-1]&0x80){
  132. if(end-2>=to && (end[-2]&0xE0)==0xC0)
  133. return end-to;
  134. if(end-3>=to && (end[-3]&0xF0)==0xE0)
  135. return end-to;
  136. while(end>to && (*--end&0xC0)==0x80)
  137. ;
  138. }
  139. }else
  140. end--;
  141. return end - to;
  142. }
  143. /* sendinput and fsloop run in the same proc (can't interrupt each other). */
  144. static Req *q;
  145. static Req **eq;
  146. static int
  147. __sendinput(Window *w, uint32_t q0, uint32_t q1)
  148. {
  149. char *s, *t;
  150. int n, nb, eofchar;
  151. static int partial;
  152. static char tmp[UTFmax];
  153. Req *r;
  154. Rune rune;
  155. if(!q)
  156. return 0;
  157. r = q;
  158. n = 0;
  159. if(partial){
  160. Partial:
  161. nb = partial;
  162. if(nb > r->ifcall.count)
  163. nb = r->ifcall.count;
  164. memmove(r->ofcall.data, tmp, nb);
  165. if(nb!=partial)
  166. memmove(tmp, tmp+nb, partial-nb);
  167. partial -= nb;
  168. q = r->aux;
  169. if(q == nil)
  170. eq = &q;
  171. r->aux = nil;
  172. r->ofcall.count = nb;
  173. if(debug)
  174. fprint(2, "satisfy read with partial\n");
  175. respond(r, nil);
  176. return n;
  177. }
  178. if(q0==q1)
  179. return 0;
  180. s = emalloc((q1-q0)*UTFmax+1);
  181. n = winread(w, q0, q1, s);
  182. s[n] = '\0';
  183. t = strpbrk(s, "\n\004");
  184. if(t == nil){
  185. free(s);
  186. return 0;
  187. }
  188. r = q;
  189. eofchar = 0;
  190. if(*t == '\004'){
  191. eofchar = 1;
  192. *t = '\0';
  193. }else
  194. *++t = '\0';
  195. nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count);
  196. if(nb==0 && s<t && r->ifcall.count > 0){
  197. partial = utfncpy(tmp, s, UTFmax);
  198. assert(partial > 0);
  199. chartorune(&rune, tmp);
  200. partial = runelen(rune);
  201. free(s);
  202. n = 1;
  203. goto Partial;
  204. }
  205. n = utfnlen(r->ofcall.data, nb);
  206. if(nb==strlen(s) && eofchar)
  207. n++;
  208. r->ofcall.count = nb;
  209. q = r->aux;
  210. if(q == nil)
  211. eq = &q;
  212. r->aux = nil;
  213. if(debug)
  214. fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data);
  215. respond(r, nil);
  216. return n;
  217. }
  218. static int
  219. _sendinput(Window *w, uint32_t q0, uint32_t *q1)
  220. {
  221. char buf[32];
  222. int n;
  223. n = __sendinput(w, q0, *q1);
  224. if(!n || !eraseinput)
  225. return n;
  226. /* erase q0 to q0+n */
  227. sprint(buf, "#%lud,#%lud", q0, q0+n);
  228. winsetaddr(w, buf, 0);
  229. write(w->data, buf, 0);
  230. *q1 -= n;
  231. return 0;
  232. }
  233. int
  234. sendinput(Window *w, uint32_t q0, uint32_t *q1)
  235. {
  236. uint32_t n;
  237. Req *oq;
  238. n = 0;
  239. do {
  240. oq = q;
  241. n += _sendinput(w, q0+n, q1);
  242. } while(q != oq);
  243. return n;
  244. }
  245. Event esendinput;
  246. void
  247. fsloop(void*)
  248. {
  249. Fsevent e;
  250. Req **l, *r;
  251. eq = &q;
  252. memset(&esendinput, 0, sizeof esendinput);
  253. esendinput.c1 = 'C';
  254. for(;;){
  255. while(recv(fschan, &e) == -1)
  256. ;
  257. r = e.r;
  258. switch(e.type){
  259. case 'r':
  260. *eq = r;
  261. r->aux = nil;
  262. eq = &r->aux;
  263. /* call sendinput with hostpt and endpt */
  264. sendp(win->cevent, &esendinput);
  265. break;
  266. case 'f':
  267. for(l=&q; *l; l=&(*l)->aux){
  268. if(*l == r->oldreq){
  269. *l = (*l)->aux;
  270. if(*l == nil)
  271. eq = l;
  272. respond(r->oldreq, "interrupted");
  273. break;
  274. }
  275. }
  276. respond(r, nil);
  277. break;
  278. }
  279. }
  280. }
  281. void
  282. sendit(char *s)
  283. {
  284. // char tmp[32];
  285. write(win->body, s, strlen(s));
  286. /*
  287. * RSC: The problem here is that other procs can call sendit,
  288. * so we lose our single-threadedness if we call sendinput.
  289. * In fact, we don't even have the right queue memory,
  290. * I think that we'll get a write event from the body write above,
  291. * and we can do the sendinput then, from our single thread.
  292. *
  293. * I still need to figure out how to test this assertion for
  294. * programs that use /srv/win*
  295. *
  296. winselect(win, "$", 0);
  297. seek(win->addr, 0UL, 0);
  298. if(read(win->addr, tmp, 2*12) == 2*12)
  299. hostpt += sendinput(win, hostpt, atol(tmp), );
  300. */
  301. }
  302. void
  303. execevent(Window *w, Event *e, int (*command)(Window*, char*))
  304. {
  305. Event *ea, *e2;
  306. int n, na, len, needfree;
  307. char *s, *t;
  308. ea = nil;
  309. e2 = nil;
  310. if(e->flag & 2)
  311. e2 = recvp(w->cevent);
  312. if(e->flag & 8){
  313. ea = recvp(w->cevent);
  314. na = ea->nb;
  315. recvp(w->cevent);
  316. }else
  317. na = 0;
  318. needfree = 0;
  319. s = e->b;
  320. if(e->nb==0 && (e->flag&2)){
  321. s = e2->b;
  322. e->q0 = e2->q0;
  323. e->q1 = e2->q1;
  324. e->nb = e2->nb;
  325. }
  326. if(e->nb==0 && e->q0<e->q1){
  327. /* fetch data from window */
  328. s = emalloc((e->q1-e->q0)*UTFmax+2);
  329. n = winread(w, e->q0, e->q1, s);
  330. s[n] = '\0';
  331. needfree = 1;
  332. }else
  333. if(na){
  334. t = emalloc(strlen(s)+1+na+2);
  335. sprint(t, "%s %s", s, ea->b);
  336. if(needfree)
  337. free(s);
  338. s = t;
  339. needfree = 1;
  340. }
  341. /* if it's a known command, do it */
  342. /* if it's a long message, it can't be for us anyway */
  343. if(!command(w, s) && s[0]!='\0'){ /* send it as typed text */
  344. /* if it's a built-in from the tag, send it back */
  345. if(e->flag & 1)
  346. fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
  347. else{ /* send text to main window */
  348. len = strlen(s);
  349. if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){
  350. if(!needfree){
  351. /* if(needfree), we left room for a newline before */
  352. t = emalloc(len+2);
  353. strcpy(t, s);
  354. s = t;
  355. needfree = 1;
  356. }
  357. s[len++] = '\n';
  358. s[len] = '\0';
  359. }
  360. sendit(s);
  361. }
  362. }
  363. if(needfree)
  364. free(s);
  365. }
  366. int
  367. hasboundary(Rune *r, int nr)
  368. {
  369. int i;
  370. for(i=0; i<nr; i++)
  371. if(r[i]=='\n' || r[i]=='\004')
  372. return 1;
  373. return 0;
  374. }
  375. void
  376. mainctl(void *v)
  377. {
  378. Window *w;
  379. Event *e;
  380. int delta, pendingS, pendingK;
  381. uint32_t hostpt, endpt;
  382. char tmp[32];
  383. w = v;
  384. proccreate(wineventproc, w, STACK);
  385. hostpt = 0;
  386. endpt = 0;
  387. winsetaddr(w, "0", 0);
  388. pendingS = 0;
  389. pendingK = 0;
  390. for(;;){
  391. if(debug)
  392. fprint(2, "input range %lud-%lud\n", hostpt, endpt);
  393. e = recvp(w->cevent);
  394. if(debug)
  395. fprint(2, "msg: %C %C %d %d %d %d %q\n",
  396. e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b);
  397. switch(e->c1){
  398. default:
  399. Unknown:
  400. fprint(2, "unknown message %c%c\n", e->c1, e->c2);
  401. break;
  402. case 'C': /* input needed for /dev/cons */
  403. if(pendingS)
  404. pendingK = 1;
  405. else
  406. hostpt += sendinput(w, hostpt, &endpt);
  407. break;
  408. case 'S': /* output to stdout */
  409. sprint(tmp, "#%lud", hostpt);
  410. winsetaddr(w, tmp, 0);
  411. write(w->data, e->b, e->nb);
  412. pendingS += e->nr;
  413. break;
  414. case 'E': /* write to tag or body; body happens due to sendit */
  415. delta = e->q1-e->q0;
  416. if(e->c2=='I'){
  417. endpt += delta;
  418. if(e->q0 < hostpt)
  419. hostpt += delta;
  420. else
  421. hostpt += sendinput(w, hostpt, &endpt);
  422. break;
  423. }
  424. if(!islower(e->c2))
  425. fprint(2, "win msg: %C %C %d %d %d %d %q\n",
  426. e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
  427. break;
  428. case 'F': /* generated by our actions (specifically case 'S' above) */
  429. delta = e->q1-e->q0;
  430. if(e->c2=='D'){
  431. /* we know about the delete by _sendinput */
  432. break;
  433. }
  434. if(e->c2=='I'){
  435. pendingS -= e->q1 - e->q0;
  436. if(pendingS < 0)
  437. fprint(2, "win: pendingS = %d\n", pendingS);
  438. if(e->q0 != hostpt)
  439. fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt);
  440. endpt += delta;
  441. hostpt += delta;
  442. sendp(writechan, nil);
  443. if(pendingS == 0 && pendingK){
  444. pendingK = 0;
  445. hostpt += sendinput(w, hostpt, &endpt);
  446. }
  447. break;
  448. }
  449. if(!islower(e->c2))
  450. fprint(2, "win msg: %C %C %d %d %d %d %q\n",
  451. e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
  452. break;
  453. case 'K':
  454. delta = e->q1-e->q0;
  455. switch(e->c2){
  456. case 'D':
  457. endpt -= delta;
  458. if(e->q1 < hostpt)
  459. hostpt -= delta;
  460. else if(e->q0 < hostpt)
  461. hostpt = e->q0;
  462. break;
  463. case 'I':
  464. delta = e->q1 - e->q0;
  465. endpt += delta;
  466. if(endpt < e->q1) /* just in case */
  467. endpt = e->q1;
  468. if(e->q0 < hostpt)
  469. hostpt += delta;
  470. if(e->nr>0 && e->r[e->nr-1]==0x7F){
  471. write(notepg, "interrupt", 9);
  472. hostpt = endpt;
  473. break;
  474. }
  475. if(e->q0 >= hostpt
  476. && hasboundary(e->r, e->nr)){
  477. /*
  478. * If we are between the S message (which
  479. * we processed by inserting text in the
  480. * window) and the F message notifying us
  481. * that the text has been inserted, then our
  482. * impression of the hostpt and acme's
  483. * may be different. This could be seen if you
  484. * hit enter a bunch of times in a con
  485. * session. To work around the unreliability,
  486. * only send input if we don't have an S pending.
  487. * The same race occurs between when a character
  488. * is typed and when we get notice of it, but
  489. * since characters tend to be typed at the end
  490. * of the buffer, we don't run into it. There's
  491. * no workaround possible for this typing race,
  492. * since we can't tell when the user has typed
  493. * something but we just haven't been notified.
  494. */
  495. if(pendingS)
  496. pendingK = 1;
  497. else
  498. hostpt += sendinput(w, hostpt, &endpt);
  499. }
  500. break;
  501. }
  502. break;
  503. case 'M': /* mouse */
  504. delta = e->q1-e->q0;
  505. switch(e->c2){
  506. case 'x':
  507. case 'X':
  508. execevent(w, e, command);
  509. break;
  510. case 'l': /* reflect all searches back to acme */
  511. case 'L':
  512. if(e->flag & 2)
  513. recvp(w->cevent);
  514. winwriteevent(w, e);
  515. break;
  516. case 'I':
  517. endpt += delta;
  518. if(e->q0 < hostpt)
  519. hostpt += delta;
  520. else
  521. hostpt += sendinput(w, hostpt, &endpt);
  522. break;
  523. case 'D':
  524. endpt -= delta;
  525. if(e->q1 < hostpt)
  526. hostpt -= delta;
  527. else if(e->q0 < hostpt)
  528. hostpt = e->q0;
  529. break;
  530. case 'd': /* modify away; we don't care */
  531. case 'i':
  532. break;
  533. default:
  534. goto Unknown;
  535. }
  536. }
  537. }
  538. }
  539. enum
  540. {
  541. NARGS = 100,
  542. NARGCHAR = 8*1024,
  543. EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
  544. };
  545. struct Exec
  546. {
  547. char **argv;
  548. Channel *cpid;
  549. };
  550. int
  551. lookinbin(char *s)
  552. {
  553. if(s[0] == '/')
  554. return 0;
  555. if(s[0]=='.' && s[1]=='/')
  556. return 0;
  557. if(s[0]=='.' && s[1]=='.' && s[2]=='/')
  558. return 0;
  559. return 1;
  560. }
  561. /* adapted from mail. not entirely free of details from that environment */
  562. void
  563. execproc(void *v)
  564. {
  565. struct Exec *e;
  566. char *cmd, **av;
  567. Channel *cpid;
  568. e = v;
  569. rfork(RFCFDG|RFNOTEG);
  570. av = e->argv;
  571. close(0);
  572. open("/dev/cons", OREAD);
  573. close(1);
  574. open("/dev/cons", OWRITE);
  575. dup(1, 2);
  576. cpid = e->cpid;
  577. free(e);
  578. procexec(cpid, av[0], av);
  579. if(lookinbin(av[0])){
  580. cmd = estrstrdup("/bin/", av[0]);
  581. procexec(cpid, cmd, av);
  582. }
  583. error("can't exec %s: %r", av[0]);
  584. }
  585. void
  586. startcmd(char *argv[], int *notepg)
  587. {
  588. struct Exec *e;
  589. Channel *cpid;
  590. char buf[64];
  591. int pid;
  592. e = emalloc(sizeof(struct Exec));
  593. e->argv = argv;
  594. cpid = chancreate(sizeof(uint32_t), 0);
  595. e->cpid = cpid;
  596. sprint(buf, "/mnt/wsys/%d", win->id);
  597. bind(buf, "/dev/acme", MREPL);
  598. proccreate(execproc, e, EXECSTACK);
  599. do
  600. pid = recvul(cpid);
  601. while(pid == -1);
  602. sprint(buf, "/proc/%d/notepg", pid);
  603. *notepg = open(buf, OWRITE);
  604. }