xfid.c 19 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. enum
  14. {
  15. Ctlsize = 5*12
  16. };
  17. char Edel[] = "deleted window";
  18. char Ebadctl[] = "ill-formed control message";
  19. char Ebadaddr[] = "bad address syntax";
  20. char Eaddr[] = "address out of range";
  21. char Einuse[] = "already in use";
  22. char Ebadevent[] = "bad event syntax";
  23. extern char Eperm[];
  24. static
  25. void
  26. clampaddr(Window *w)
  27. {
  28. if(w->addr.q0 < 0)
  29. w->addr.q0 = 0;
  30. if(w->addr.q1 < 0)
  31. w->addr.q1 = 0;
  32. if(w->addr.q0 > w->body.file->nc)
  33. w->addr.q0 = w->body.file->nc;
  34. if(w->addr.q1 > w->body.file->nc)
  35. w->addr.q1 = w->body.file->nc;
  36. }
  37. void
  38. xfidctl(void *arg)
  39. {
  40. Xfid *x;
  41. void (*f)(Xfid*);
  42. threadsetname("xfidctlthread");
  43. x = arg;
  44. for(;;){
  45. f = recvp(x->c);
  46. (*f)(x);
  47. flushimage(display, 1);
  48. sendp(cxfidfree, x);
  49. }
  50. }
  51. void
  52. xfidflush(Xfid *x)
  53. {
  54. Fcall fc;
  55. int i, j;
  56. Window *w;
  57. Column *c;
  58. Xfid *wx;
  59. /* search windows for matching tag */
  60. qlock(&row);
  61. for(j=0; j<row.ncol; j++){
  62. c = row.col[j];
  63. for(i=0; i<c->nw; i++){
  64. w = c->w[i];
  65. winlock(w, 'E');
  66. wx = w->eventx;
  67. if(wx!=nil && wx->tag==x->oldtag){
  68. w->eventx = nil;
  69. wx->flushed = TRUE;
  70. sendp(wx->c, nil);
  71. winunlock(w);
  72. goto out;
  73. }
  74. winunlock(w);
  75. }
  76. }
  77. out:
  78. qunlock(&row);
  79. respond(x, &fc, nil);
  80. }
  81. void
  82. xfidopen(Xfid *x)
  83. {
  84. Fcall fc;
  85. Window *w;
  86. Text *t;
  87. char *s;
  88. Rune *r;
  89. int m, n, q, q0, q1;
  90. w = x->f->w;
  91. t = &w->body;
  92. if(w){
  93. winlock(w, 'E');
  94. q = FILE(x->f->qid);
  95. switch(q){
  96. case QWaddr:
  97. if(w->nopen[q]++ == 0){
  98. w->addr = (Range){0,0};
  99. w->limit = (Range){-1,-1};
  100. }
  101. break;
  102. case QWdata:
  103. w->nopen[q]++;
  104. break;
  105. case QWevent:
  106. if(w->nopen[q]++ == 0){
  107. if(!w->isdir && w->col!=nil){
  108. w->filemenu = FALSE;
  109. winsettag(w);
  110. }
  111. }
  112. break;
  113. case QWrdsel:
  114. /*
  115. * Use a temporary file.
  116. * A pipe would be the obvious, but we can't afford the
  117. * broken pipe notification. Using the code to read QWbody
  118. * is n², which should probably also be fixed. Even then,
  119. * though, we'd need to squirrel away the data in case it's
  120. * modified during the operation, e.g. by |sort
  121. */
  122. if(w->rdselfd > 0){
  123. winunlock(w);
  124. respond(x, &fc, Einuse);
  125. return;
  126. }
  127. w->rdselfd = tempfile();
  128. if(w->rdselfd < 0){
  129. winunlock(w);
  130. respond(x, &fc, "can't create temp file");
  131. return;
  132. }
  133. w->nopen[q]++;
  134. q0 = t->q0;
  135. q1 = t->q1;
  136. r = fbufalloc();
  137. s = fbufalloc();
  138. while(q0 < q1){
  139. n = q1 - q0;
  140. if(n > BUFSIZE/UTFmax)
  141. n = BUFSIZE/UTFmax;
  142. bufread(t->file, q0, r, n);
  143. m = snprint(s, BUFSIZE+1, "%.*S", n, r);
  144. if(write(w->rdselfd, s, m) != m){
  145. warning(nil, "can't write temp file for pipe command %r\n");
  146. break;
  147. }
  148. q0 += n;
  149. }
  150. fbuffree(s);
  151. fbuffree(r);
  152. break;
  153. case QWwrsel:
  154. w->nopen[q]++;
  155. seq++;
  156. filemark(t->file);
  157. cut(t, t, nil, FALSE, TRUE, nil, 0);
  158. w->wrselrange = (Range){t->q1, t->q1};
  159. w->nomark = TRUE;
  160. break;
  161. case QWeditout:
  162. if(editing == FALSE){
  163. winunlock(w);
  164. respond(x, &fc, Eperm);
  165. return;
  166. }
  167. w->wrselrange = (Range){t->q1, t->q1};
  168. break;
  169. }
  170. winunlock(w);
  171. }
  172. fc.qid = x->f->qid;
  173. fc.iounit = messagesize-IOHDRSZ;
  174. x->f->open = TRUE;
  175. respond(x, &fc, nil);
  176. }
  177. void
  178. xfidclose(Xfid *x)
  179. {
  180. Fcall fc;
  181. Window *w;
  182. int q;
  183. Text *t;
  184. w = x->f->w;
  185. x->f->busy = FALSE;
  186. if(x->f->open == FALSE){
  187. if(w != nil)
  188. winclose(w);
  189. respond(x, &fc, nil);
  190. return;
  191. }
  192. x->f->open = FALSE;
  193. if(w){
  194. winlock(w, 'E');
  195. q = FILE(x->f->qid);
  196. switch(q){
  197. case QWctl:
  198. if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){
  199. w->ctlfid = ~0;
  200. qunlock(&w->ctllock);
  201. }
  202. break;
  203. case QWdata:
  204. w->nomark = FALSE;
  205. /* fall through */
  206. case QWaddr:
  207. case QWevent: /* BUG: do we need to shut down Xfid? */
  208. if(--w->nopen[q] == 0){
  209. if(q == QWdata)
  210. w->nomark = FALSE;
  211. if(q==QWevent && !w->isdir && w->col!=nil){
  212. w->filemenu = TRUE;
  213. winsettag(w);
  214. }
  215. if(q == QWevent){
  216. free(w->dumpstr);
  217. free(w->dumpdir);
  218. w->dumpstr = nil;
  219. w->dumpdir = nil;
  220. }
  221. }
  222. break;
  223. case QWrdsel:
  224. close(w->rdselfd);
  225. w->rdselfd = 0;
  226. break;
  227. case QWwrsel:
  228. w->nomark = FALSE;
  229. t = &w->body;
  230. /* before: only did this if !w->noscroll, but that didn't seem right in practice */
  231. textshow(t, min(w->wrselrange.q0, t->file->nc),
  232. min(w->wrselrange.q1, t->file->nc), 1);
  233. textscrdraw(t);
  234. break;
  235. }
  236. winunlock(w);
  237. winclose(w);
  238. }
  239. respond(x, &fc, nil);
  240. }
  241. void
  242. xfidread(Xfid *x)
  243. {
  244. Fcall fc;
  245. int n, q;
  246. uint off;
  247. char *b;
  248. char buf[128];
  249. Window *w;
  250. q = FILE(x->f->qid);
  251. w = x->f->w;
  252. if(w == nil){
  253. fc.count = 0;
  254. switch(q){
  255. case Qcons:
  256. case Qlabel:
  257. break;
  258. case Qindex:
  259. xfidindexread(x);
  260. return;
  261. default:
  262. warning(nil, "unknown qid %d\n", q);
  263. break;
  264. }
  265. respond(x, &fc, nil);
  266. return;
  267. }
  268. winlock(w, 'F');
  269. if(w->col == nil){
  270. winunlock(w);
  271. respond(x, &fc, Edel);
  272. return;
  273. }
  274. off = x->offset;
  275. switch(q){
  276. case QWaddr:
  277. textcommit(&w->body, TRUE);
  278. clampaddr(w);
  279. sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);
  280. goto Readbuf;
  281. case QWbody:
  282. xfidutfread(x, &w->body, w->body.file->nc, QWbody);
  283. break;
  284. case QWctl:
  285. winctlprint(w, buf, 1);
  286. goto Readbuf;
  287. Readbuf:
  288. n = strlen(buf);
  289. if(off > n)
  290. off = n;
  291. if(off+x->count > n)
  292. x->count = n-off;
  293. fc.count = x->count;
  294. fc.data = buf+off;
  295. respond(x, &fc, nil);
  296. break;
  297. case QWevent:
  298. xfideventread(x, w);
  299. break;
  300. case QWdata:
  301. /* BUG: what should happen if q1 > q0? */
  302. if(w->addr.q0 > w->body.file->nc){
  303. respond(x, &fc, Eaddr);
  304. break;
  305. }
  306. w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc);
  307. w->addr.q1 = w->addr.q0;
  308. break;
  309. case QWtag:
  310. xfidutfread(x, &w->tag, w->tag.file->nc, QWtag);
  311. break;
  312. case QWrdsel:
  313. seek(w->rdselfd, off, 0);
  314. n = x->count;
  315. if(n > BUFSIZE)
  316. n = BUFSIZE;
  317. b = fbufalloc();
  318. n = read(w->rdselfd, b, n);
  319. if(n < 0){
  320. respond(x, &fc, "I/O error in temp file");
  321. break;
  322. }
  323. fc.count = n;
  324. fc.data = b;
  325. respond(x, &fc, nil);
  326. fbuffree(b);
  327. break;
  328. default:
  329. sprint(buf, "unknown qid %d in read", q);
  330. respond(x, &fc, nil);
  331. }
  332. winunlock(w);
  333. }
  334. void
  335. xfidwrite(Xfid *x)
  336. {
  337. Fcall fc;
  338. int c, cnt, qid, q, nb, nr, eval;
  339. char buf[64], *err;
  340. Window *w;
  341. Rune *r;
  342. Range a;
  343. Text *t;
  344. uint q0, tq0, tq1;
  345. qid = FILE(x->f->qid);
  346. w = x->f->w;
  347. if(w){
  348. c = 'F';
  349. if(qid==QWtag || qid==QWbody)
  350. c = 'E';
  351. winlock(w, c);
  352. if(w->col == nil){
  353. winunlock(w);
  354. respond(x, &fc, Edel);
  355. return;
  356. }
  357. }
  358. x->data[x->count] = 0;
  359. switch(qid){
  360. case Qcons:
  361. w = errorwin(x->f->mntdir, 'X');
  362. t=&w->body;
  363. goto BodyTag;
  364. case Qlabel:
  365. fc.count = x->count;
  366. respond(x, &fc, nil);
  367. break;
  368. case QWaddr:
  369. x->data[x->count] = 0;
  370. r = bytetorune(x->data, &nr);
  371. t = &w->body;
  372. wincommit(w, t);
  373. eval = TRUE;
  374. a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
  375. free(r);
  376. if(nb < nr){
  377. respond(x, &fc, Ebadaddr);
  378. break;
  379. }
  380. if(!eval){
  381. respond(x, &fc, Eaddr);
  382. break;
  383. }
  384. w->addr = a;
  385. fc.count = x->count;
  386. respond(x, &fc, nil);
  387. break;
  388. case Qeditout:
  389. case QWeditout:
  390. r = bytetorune(x->data, &nr);
  391. if(w)
  392. err = edittext(w, w->wrselrange.q1, r, nr);
  393. else
  394. err = edittext(nil, 0, r, nr);
  395. free(r);
  396. if(err != nil){
  397. respond(x, &fc, err);
  398. break;
  399. }
  400. fc.count = x->count;
  401. respond(x, &fc, nil);
  402. break;
  403. case QWbody:
  404. case QWwrsel:
  405. t = &w->body;
  406. goto BodyTag;
  407. case QWctl:
  408. xfidctlwrite(x, w);
  409. break;
  410. case QWdata:
  411. a = w->addr;
  412. t = &w->body;
  413. wincommit(w, t);
  414. if(a.q0>t->file->nc || a.q1>t->file->nc){
  415. respond(x, &fc, Eaddr);
  416. break;
  417. }
  418. r = runemalloc(x->count);
  419. cvttorunes(x->data, x->count, r, &nb, &nr, nil);
  420. if(w->nomark == FALSE){
  421. seq++;
  422. filemark(t->file);
  423. }
  424. q0 = a.q0;
  425. if(a.q1 > q0){
  426. textdelete(t, q0, a.q1, TRUE);
  427. w->addr.q1 = q0;
  428. }
  429. tq0 = t->q0;
  430. tq1 = t->q1;
  431. textinsert(t, q0, r, nr, TRUE);
  432. if(tq0 >= q0)
  433. tq0 += nr;
  434. if(tq1 >= q0)
  435. tq1 += nr;
  436. textsetselect(t, tq0, tq1);
  437. if(!t->w->noscroll)
  438. textshow(t, q0, q0+nr, 0);
  439. textscrdraw(t);
  440. winsettag(w);
  441. free(r);
  442. w->addr.q0 += nr;
  443. w->addr.q1 = w->addr.q0;
  444. fc.count = x->count;
  445. respond(x, &fc, nil);
  446. break;
  447. case QWevent:
  448. xfideventwrite(x, w);
  449. break;
  450. case QWtag:
  451. t = &w->tag;
  452. goto BodyTag;
  453. BodyTag:
  454. q = x->f->nrpart;
  455. cnt = x->count;
  456. if(q > 0){
  457. memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */
  458. memmove(x->data, x->f->rpart, q);
  459. cnt += q;
  460. x->f->nrpart = 0;
  461. }
  462. r = runemalloc(cnt);
  463. cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
  464. /* approach end of buffer */
  465. while(fullrune(x->data+nb, cnt-nb)){
  466. c = nb;
  467. nb += chartorune(&r[nr], x->data+c);
  468. if(r[nr])
  469. nr++;
  470. }
  471. if(nb < cnt){
  472. memmove(x->f->rpart, x->data+nb, cnt-nb);
  473. x->f->nrpart = cnt-nb;
  474. }
  475. if(nr > 0){
  476. wincommit(w, t);
  477. if(qid == QWwrsel){
  478. q0 = w->wrselrange.q1;
  479. if(q0 > t->file->nc)
  480. q0 = t->file->nc;
  481. }else
  482. q0 = t->file->nc;
  483. if(qid == QWtag)
  484. textinsert(t, q0, r, nr, TRUE);
  485. else{
  486. if(w->nomark == FALSE){
  487. seq++;
  488. filemark(t->file);
  489. }
  490. q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
  491. textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
  492. if(qid!=QWwrsel && !t->w->noscroll)
  493. textshow(t, q0+nr, q0+nr, 1);
  494. textscrdraw(t);
  495. }
  496. winsettag(w);
  497. if(qid == QWwrsel)
  498. w->wrselrange.q1 += nr;
  499. free(r);
  500. }
  501. fc.count = x->count;
  502. respond(x, &fc, nil);
  503. break;
  504. default:
  505. sprint(buf, "unknown qid %d in write", qid);
  506. respond(x, &fc, buf);
  507. break;
  508. }
  509. if(w)
  510. winunlock(w);
  511. qlock(&row);
  512. flushwarnings();
  513. qunlock(&row);
  514. }
  515. void
  516. xfidctlwrite(Xfid *x, Window *w)
  517. {
  518. Fcall fc;
  519. int i, m, n, nb, nr, nulls;
  520. Rune *r;
  521. char *err, *p, *pp, *q, *e;
  522. int isfbuf, scrdraw, settag;
  523. Text *t;
  524. err = nil;
  525. e = x->data+x->count;
  526. scrdraw = FALSE;
  527. settag = FALSE;
  528. isfbuf = TRUE;
  529. if(x->count < RBUFSIZE)
  530. r = fbufalloc();
  531. else{
  532. isfbuf = FALSE;
  533. r = emalloc(x->count*UTFmax+1);
  534. }
  535. x->data[x->count] = 0;
  536. textcommit(&w->tag, TRUE);
  537. for(n=0; n<x->count; n+=m){
  538. p = x->data+n;
  539. if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
  540. qlock(&w->ctllock);
  541. w->ctlfid = x->f->fid;
  542. m = 4;
  543. }else
  544. if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
  545. w->ctlfid = ~0;
  546. qunlock(&w->ctllock);
  547. m = 6;
  548. }else
  549. if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
  550. t = &w->body;
  551. t->eq0 = ~0;
  552. filereset(t->file);
  553. t->file->mod = FALSE;
  554. w->dirty = FALSE;
  555. settag = TRUE;
  556. m = 5;
  557. }else
  558. if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
  559. t = &w->body;
  560. /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
  561. t->file->mod = TRUE;
  562. w->dirty = TRUE;
  563. settag = TRUE;
  564. m = 5;
  565. }else
  566. if(strncmp(p, "show", 4) == 0){ /* show dot */
  567. t = &w->body;
  568. textshow(t, t->q0, t->q1, 1);
  569. m = 4;
  570. }else
  571. if(strncmp(p, "name ", 5) == 0){ /* set file name */
  572. pp = p+5;
  573. m = 5;
  574. q = memchr(pp, '\n', e-pp);
  575. if(q==nil || q==pp){
  576. err = Ebadctl;
  577. break;
  578. }
  579. *q = 0;
  580. nulls = FALSE;
  581. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  582. if(nulls){
  583. err = "nulls in file name";
  584. break;
  585. }
  586. for(i=0; i<nr; i++)
  587. if(r[i] <= ' '){
  588. err = "bad character in file name";
  589. goto out;
  590. }
  591. out:
  592. seq++;
  593. filemark(w->body.file);
  594. winsetname(w, r, nr);
  595. m += (q+1) - pp;
  596. }else
  597. if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
  598. pp = p+5;
  599. m = 5;
  600. q = memchr(pp, '\n', e-pp);
  601. if(q==nil || q==pp){
  602. err = Ebadctl;
  603. break;
  604. }
  605. *q = 0;
  606. nulls = FALSE;
  607. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  608. if(nulls){
  609. err = "nulls in dump string";
  610. break;
  611. }
  612. w->dumpstr = runetobyte(r, nr);
  613. m += (q+1) - pp;
  614. }else
  615. if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
  616. pp = p+8;
  617. m = 8;
  618. q = memchr(pp, '\n', e-pp);
  619. if(q==nil || q==pp){
  620. err = Ebadctl;
  621. break;
  622. }
  623. *q = 0;
  624. nulls = FALSE;
  625. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  626. if(nulls){
  627. err = "nulls in dump directory string";
  628. break;
  629. }
  630. w->dumpdir = runetobyte(r, nr);
  631. m += (q+1) - pp;
  632. }else
  633. if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
  634. colclose(w->col, w, TRUE);
  635. m = 6;
  636. }else
  637. if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
  638. if(!winclean(w, TRUE)){
  639. err = "file dirty";
  640. break;
  641. }
  642. colclose(w->col, w, TRUE);
  643. m = 3;
  644. }else
  645. if(strncmp(p, "get", 3) == 0){ /* get file */
  646. get(&w->body, nil, nil, FALSE, XXX, nil, 0);
  647. m = 3;
  648. }else
  649. if(strncmp(p, "put", 3) == 0){ /* put file */
  650. put(&w->body, nil, nil, XXX, XXX, nil, 0);
  651. m = 3;
  652. }else
  653. if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
  654. textcommit(&w->body, TRUE);
  655. clampaddr(w);
  656. w->body.q0 = w->addr.q0;
  657. w->body.q1 = w->addr.q1;
  658. textsetselect(&w->body, w->body.q0, w->body.q1);
  659. settag = TRUE;
  660. m = 8;
  661. }else
  662. if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
  663. w->addr.q0 = w->body.q0;
  664. w->addr.q1 = w->body.q1;
  665. m = 8;
  666. }else
  667. if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
  668. textcommit(&w->body, TRUE);
  669. clampaddr(w);
  670. w->limit.q0 = w->addr.q0;
  671. w->limit.q1 = w->addr.q1;
  672. m = 10;
  673. }else
  674. if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
  675. w->nomark = TRUE;
  676. m = 6;
  677. }else
  678. if(strncmp(p, "mark", 4) == 0){ /* mark file */
  679. seq++;
  680. filemark(w->body.file);
  681. settag = TRUE;
  682. m = 4;
  683. }else
  684. if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
  685. w->noscroll = TRUE;
  686. m = 8;
  687. }else
  688. if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
  689. wincleartag(w);
  690. settag = TRUE;
  691. m = 8;
  692. }else
  693. if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
  694. w->noscroll = FALSE;
  695. m = 6;
  696. }else{
  697. err = Ebadctl;
  698. break;
  699. }
  700. while(p[m] == '\n')
  701. m++;
  702. }
  703. if(isfbuf)
  704. fbuffree(r);
  705. else
  706. free(r);
  707. if(err)
  708. n = 0;
  709. fc.count = n;
  710. respond(x, &fc, err);
  711. if(settag)
  712. winsettag(w);
  713. if(scrdraw)
  714. textscrdraw(&w->body);
  715. }
  716. void
  717. xfideventwrite(Xfid *x, Window *w)
  718. {
  719. Fcall fc;
  720. int m, n;
  721. Rune *r;
  722. char *err, *p, *q;
  723. int isfbuf;
  724. Text *t;
  725. int c;
  726. uint q0, q1;
  727. err = nil;
  728. isfbuf = TRUE;
  729. if(x->count < RBUFSIZE)
  730. r = fbufalloc();
  731. else{
  732. isfbuf = FALSE;
  733. r = emalloc(x->count*UTFmax+1);
  734. }
  735. for(n=0; n<x->count; n+=m){
  736. p = x->data+n;
  737. w->owner = *p++; /* disgusting */
  738. c = *p++;
  739. while(*p == ' ')
  740. p++;
  741. q0 = strtoul(p, &q, 10);
  742. if(q == p)
  743. goto Rescue;
  744. p = q;
  745. while(*p == ' ')
  746. p++;
  747. q1 = strtoul(p, &q, 10);
  748. if(q == p)
  749. goto Rescue;
  750. p = q;
  751. while(*p == ' ')
  752. p++;
  753. if(*p++ != '\n')
  754. goto Rescue;
  755. m = p-(x->data+n);
  756. if('a'<=c && c<='z')
  757. t = &w->tag;
  758. else if('A'<=c && c<='Z')
  759. t = &w->body;
  760. else
  761. goto Rescue;
  762. if(q0>t->file->nc || q1>t->file->nc || q0>q1)
  763. goto Rescue;
  764. qlock(&row); /* just like mousethread */
  765. switch(c){
  766. case 'x':
  767. case 'X':
  768. execute(t, q0, q1, TRUE, nil);
  769. break;
  770. case 'l':
  771. case 'L':
  772. look3(t, q0, q1, TRUE);
  773. break;
  774. default:
  775. qunlock(&row);
  776. goto Rescue;
  777. }
  778. flushwarnings();
  779. qunlock(&row);
  780. }
  781. Out:
  782. if(isfbuf)
  783. fbuffree(r);
  784. else
  785. free(r);
  786. if(err)
  787. n = 0;
  788. fc.count = n;
  789. respond(x, &fc, err);
  790. return;
  791. Rescue:
  792. err = Ebadevent;
  793. goto Out;
  794. }
  795. void
  796. xfidutfread(Xfid *x, Text *t, uint q1, int qid)
  797. {
  798. Fcall fc;
  799. Window *w;
  800. Rune *r;
  801. char *b, *b1;
  802. uint q, off, boff;
  803. int m, n, nr, nb;
  804. w = t->w;
  805. wincommit(w, t);
  806. off = x->offset;
  807. r = fbufalloc();
  808. b = fbufalloc();
  809. b1 = fbufalloc();
  810. n = 0;
  811. if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
  812. boff = w->utflastboff;
  813. q = w->utflastq;
  814. }else{
  815. /* BUG: stupid code: scan from beginning */
  816. boff = 0;
  817. q = 0;
  818. }
  819. w->utflastqid = qid;
  820. while(q<q1 && n<x->count){
  821. /*
  822. * Updating here avoids partial rune problem: we're always on a
  823. * char boundary. The cost is we will usually do one more read
  824. * than we really need, but that's better than being n^2.
  825. */
  826. w->utflastboff = boff;
  827. w->utflastq = q;
  828. nr = q1-q;
  829. if(nr > BUFSIZE/UTFmax)
  830. nr = BUFSIZE/UTFmax;
  831. bufread(t->file, q, r, nr);
  832. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  833. if(boff >= off){
  834. m = nb;
  835. if(boff+m > off+x->count)
  836. m = off+x->count - boff;
  837. memmove(b1+n, b, m);
  838. n += m;
  839. }else if(boff+nb > off){
  840. if(n != 0)
  841. error("bad count in utfrune");
  842. m = nb - (off-boff);
  843. if(m > x->count)
  844. m = x->count;
  845. memmove(b1, b+(off-boff), m);
  846. n += m;
  847. }
  848. boff += nb;
  849. q += nr;
  850. }
  851. fbuffree(r);
  852. fbuffree(b);
  853. fc.count = n;
  854. fc.data = b1;
  855. respond(x, &fc, nil);
  856. fbuffree(b1);
  857. }
  858. int
  859. xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
  860. {
  861. Fcall fc;
  862. Window *w;
  863. Rune *r, junk;
  864. char *b, *b1;
  865. uint q, boff;
  866. int i, rw, m, n, nr, nb;
  867. w = t->w;
  868. wincommit(w, t);
  869. r = fbufalloc();
  870. b = fbufalloc();
  871. b1 = fbufalloc();
  872. n = 0;
  873. q = q0;
  874. boff = 0;
  875. while(q<q1 && n<x->count){
  876. nr = q1-q;
  877. if(nr > BUFSIZE/UTFmax)
  878. nr = BUFSIZE/UTFmax;
  879. bufread(t->file, q, r, nr);
  880. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  881. m = nb;
  882. if(boff+m > x->count){
  883. i = x->count - boff;
  884. /* copy whole runes only */
  885. m = 0;
  886. nr = 0;
  887. while(m < i){
  888. rw = chartorune(&junk, b+m);
  889. if(m+rw > i)
  890. break;
  891. m += rw;
  892. nr++;
  893. }
  894. if(m == 0)
  895. break;
  896. }
  897. memmove(b1+n, b, m);
  898. n += m;
  899. boff += nb;
  900. q += nr;
  901. }
  902. fbuffree(r);
  903. fbuffree(b);
  904. fc.count = n;
  905. fc.data = b1;
  906. respond(x, &fc, nil);
  907. fbuffree(b1);
  908. return q-q0;
  909. }
  910. void
  911. xfideventread(Xfid *x, Window *w)
  912. {
  913. Fcall fc;
  914. char *b;
  915. int i, n;
  916. i = 0;
  917. x->flushed = FALSE;
  918. while(w->nevents == 0){
  919. if(i){
  920. if(!x->flushed)
  921. respond(x, &fc, "window shut down");
  922. return;
  923. }
  924. w->eventx = x;
  925. winunlock(w);
  926. recvp(x->c);
  927. winlock(w, 'F');
  928. i++;
  929. }
  930. n = w->nevents;
  931. if(n > x->count)
  932. n = x->count;
  933. fc.count = n;
  934. fc.data = w->events;
  935. respond(x, &fc, nil);
  936. b = w->events;
  937. w->events = estrdup(w->events+n);
  938. free(b);
  939. w->nevents -= n;
  940. }
  941. void
  942. xfidindexread(Xfid *x)
  943. {
  944. Fcall fc;
  945. int i, j, m, n, nmax, isbuf, cnt, off;
  946. Window *w;
  947. char *b;
  948. Rune *r;
  949. Column *c;
  950. qlock(&row);
  951. nmax = 0;
  952. for(j=0; j<row.ncol; j++){
  953. c = row.col[j];
  954. for(i=0; i<c->nw; i++){
  955. w = c->w[i];
  956. nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
  957. }
  958. }
  959. nmax++;
  960. isbuf = (nmax<=RBUFSIZE);
  961. if(isbuf)
  962. b = (char*)x->buf;
  963. else
  964. b = emalloc(nmax);
  965. r = fbufalloc();
  966. n = 0;
  967. for(j=0; j<row.ncol; j++){
  968. c = row.col[j];
  969. for(i=0; i<c->nw; i++){
  970. w = c->w[i];
  971. /* only show the currently active window of a set */
  972. if(w->body.file->curtext != &w->body)
  973. continue;
  974. winctlprint(w, b+n, 0);
  975. n += Ctlsize;
  976. m = min(RBUFSIZE, w->tag.file->nc);
  977. bufread(w->tag.file, 0, r, m);
  978. m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
  979. while(n<m && b[n]!='\n')
  980. n++;
  981. b[n++] = '\n';
  982. }
  983. }
  984. flushwarnings();
  985. qunlock(&row);
  986. off = x->offset;
  987. cnt = x->count;
  988. if(off > n)
  989. off = n;
  990. if(off+cnt > n)
  991. cnt = n-off;
  992. fc.count = cnt;
  993. memmove(r, b+off, cnt);
  994. fc.data = (char*)r;
  995. if(!isbuf)
  996. free(b);
  997. respond(x, &fc, nil);
  998. fbuffree(r);
  999. }