main.c 12 KB

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