xfid.c 19 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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->body.file, 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. }
  512. void
  513. xfidctlwrite(Xfid *x, Window *w)
  514. {
  515. Fcall fc;
  516. int i, m, n, nb, nr, nulls;
  517. Rune *r;
  518. char *err, *p, *pp, *q, *e;
  519. int isfbuf, scrdraw, settag;
  520. Text *t;
  521. err = nil;
  522. e = x->data+x->count;
  523. scrdraw = FALSE;
  524. settag = FALSE;
  525. isfbuf = TRUE;
  526. if(x->count < RBUFSIZE)
  527. r = fbufalloc();
  528. else{
  529. isfbuf = FALSE;
  530. r = emalloc(x->count*UTFmax+1);
  531. }
  532. x->data[x->count] = 0;
  533. textcommit(&w->tag, TRUE);
  534. for(n=0; n<x->count; n+=m){
  535. p = x->data+n;
  536. if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
  537. qlock(&w->ctllock);
  538. w->ctlfid = x->f->fid;
  539. m = 4;
  540. }else
  541. if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
  542. w->ctlfid = ~0;
  543. qunlock(&w->ctllock);
  544. m = 6;
  545. }else
  546. if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
  547. t = &w->body;
  548. t->eq0 = ~0;
  549. filereset(t->file);
  550. t->file->mod = FALSE;
  551. w->dirty = FALSE;
  552. settag = TRUE;
  553. m = 5;
  554. }else
  555. if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
  556. t = &w->body;
  557. /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
  558. t->file->mod = TRUE;
  559. w->dirty = TRUE;
  560. settag = TRUE;
  561. m = 5;
  562. }else
  563. if(strncmp(p, "show", 4) == 0){ /* show dot */
  564. t = &w->body;
  565. textshow(t, t->q0, t->q1, 1);
  566. m = 4;
  567. }else
  568. if(strncmp(p, "name ", 5) == 0){ /* set file name */
  569. pp = p+5;
  570. m = 5;
  571. q = memchr(pp, '\n', e-pp);
  572. if(q==nil || q==pp){
  573. err = Ebadctl;
  574. break;
  575. }
  576. *q = 0;
  577. nulls = FALSE;
  578. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  579. if(nulls){
  580. err = "nulls in file name";
  581. break;
  582. }
  583. for(i=0; i<nr; i++)
  584. if(r[i] <= ' '){
  585. err = "bad character in file name";
  586. goto out;
  587. }
  588. out:
  589. seq++;
  590. filemark(w->body.file);
  591. winsetname(w, r, nr);
  592. m += (q+1) - pp;
  593. }else
  594. if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
  595. pp = p+5;
  596. m = 5;
  597. q = memchr(pp, '\n', e-pp);
  598. if(q==nil || q==pp){
  599. err = Ebadctl;
  600. break;
  601. }
  602. *q = 0;
  603. nulls = FALSE;
  604. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  605. if(nulls){
  606. err = "nulls in dump string";
  607. break;
  608. }
  609. w->dumpstr = runetobyte(r, nr);
  610. m += (q+1) - pp;
  611. }else
  612. if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
  613. pp = p+8;
  614. m = 8;
  615. q = memchr(pp, '\n', e-pp);
  616. if(q==nil || q==pp){
  617. err = Ebadctl;
  618. break;
  619. }
  620. *q = 0;
  621. nulls = FALSE;
  622. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  623. if(nulls){
  624. err = "nulls in dump directory string";
  625. break;
  626. }
  627. w->dumpdir = runetobyte(r, nr);
  628. m += (q+1) - pp;
  629. }else
  630. if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
  631. colclose(w->col, w, TRUE);
  632. m = 6;
  633. }else
  634. if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
  635. if(!winclean(w, TRUE)){
  636. err = "file dirty";
  637. break;
  638. }
  639. colclose(w->col, w, TRUE);
  640. m = 3;
  641. }else
  642. if(strncmp(p, "get", 3) == 0){ /* get file */
  643. get(&w->body, nil, nil, FALSE, XXX, nil, 0);
  644. m = 3;
  645. }else
  646. if(strncmp(p, "put", 3) == 0){ /* put file */
  647. put(&w->body, nil, nil, XXX, XXX, nil, 0);
  648. m = 3;
  649. }else
  650. if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
  651. textcommit(&w->body, TRUE);
  652. clampaddr(w);
  653. w->body.q0 = w->addr.q0;
  654. w->body.q1 = w->addr.q1;
  655. textsetselect(&w->body, w->body.q0, w->body.q1);
  656. settag = TRUE;
  657. m = 8;
  658. }else
  659. if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
  660. w->addr.q0 = w->body.q0;
  661. w->addr.q1 = w->body.q1;
  662. m = 8;
  663. }else
  664. if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
  665. textcommit(&w->body, TRUE);
  666. clampaddr(w);
  667. w->limit.q0 = w->addr.q0;
  668. w->limit.q1 = w->addr.q1;
  669. m = 10;
  670. }else
  671. if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
  672. w->nomark = TRUE;
  673. m = 6;
  674. }else
  675. if(strncmp(p, "mark", 4) == 0){ /* mark file */
  676. seq++;
  677. filemark(w->body.file);
  678. settag = TRUE;
  679. m = 4;
  680. }else
  681. if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
  682. w->noscroll = TRUE;
  683. m = 8;
  684. }else
  685. if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
  686. wincleartag(w);
  687. settag = TRUE;
  688. m = 8;
  689. }else
  690. if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
  691. w->noscroll = FALSE;
  692. m = 6;
  693. }else{
  694. err = Ebadctl;
  695. break;
  696. }
  697. while(p[m] == '\n')
  698. m++;
  699. }
  700. if(isfbuf)
  701. fbuffree(r);
  702. else
  703. free(r);
  704. if(err)
  705. n = 0;
  706. fc.count = n;
  707. respond(x, &fc, err);
  708. if(settag)
  709. winsettag(w);
  710. if(scrdraw)
  711. textscrdraw(&w->body);
  712. }
  713. void
  714. xfideventwrite(Xfid *x, Window *w)
  715. {
  716. Fcall fc;
  717. int m, n;
  718. Rune *r;
  719. char *err, *p, *q;
  720. int isfbuf;
  721. Text *t;
  722. int c;
  723. uint q0, q1;
  724. err = nil;
  725. isfbuf = TRUE;
  726. if(x->count < RBUFSIZE)
  727. r = fbufalloc();
  728. else{
  729. isfbuf = FALSE;
  730. r = emalloc(x->count*UTFmax+1);
  731. }
  732. for(n=0; n<x->count; n+=m){
  733. p = x->data+n;
  734. w->owner = *p++; /* disgusting */
  735. c = *p++;
  736. while(*p == ' ')
  737. p++;
  738. q0 = strtoul(p, &q, 10);
  739. if(q == p)
  740. goto Rescue;
  741. p = q;
  742. while(*p == ' ')
  743. p++;
  744. q1 = strtoul(p, &q, 10);
  745. if(q == p)
  746. goto Rescue;
  747. p = q;
  748. while(*p == ' ')
  749. p++;
  750. if(*p++ != '\n')
  751. goto Rescue;
  752. m = p-(x->data+n);
  753. if('a'<=c && c<='z')
  754. t = &w->tag;
  755. else if('A'<=c && c<='Z')
  756. t = &w->body;
  757. else
  758. goto Rescue;
  759. if(q0>t->file->nc || q1>t->file->nc || q0>q1)
  760. goto Rescue;
  761. qlock(&row); /* just like mousethread */
  762. switch(c){
  763. case 'x':
  764. case 'X':
  765. execute(t, q0, q1, TRUE, nil);
  766. break;
  767. case 'l':
  768. case 'L':
  769. look3(t, q0, q1, TRUE);
  770. break;
  771. default:
  772. qunlock(&row);
  773. goto Rescue;
  774. }
  775. qunlock(&row);
  776. }
  777. Out:
  778. if(isfbuf)
  779. fbuffree(r);
  780. else
  781. free(r);
  782. if(err)
  783. n = 0;
  784. fc.count = n;
  785. respond(x, &fc, err);
  786. return;
  787. Rescue:
  788. err = Ebadevent;
  789. goto Out;
  790. }
  791. void
  792. xfidutfread(Xfid *x, Text *t, uint q1, int qid)
  793. {
  794. Fcall fc;
  795. Window *w;
  796. Rune *r;
  797. char *b, *b1;
  798. uint q, off, boff;
  799. int m, n, nr, nb;
  800. w = t->w;
  801. wincommit(w, t);
  802. off = x->offset;
  803. r = fbufalloc();
  804. b = fbufalloc();
  805. b1 = fbufalloc();
  806. n = 0;
  807. if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
  808. boff = w->utflastboff;
  809. q = w->utflastq;
  810. }else{
  811. /* BUG: stupid code: scan from beginning */
  812. boff = 0;
  813. q = 0;
  814. }
  815. w->utflastqid = qid;
  816. while(q<q1 && n<x->count){
  817. /*
  818. * Updating here avoids partial rune problem: we're always on a
  819. * char boundary. The cost is we will usually do one more read
  820. * than we really need, but that's better than being n^2.
  821. */
  822. w->utflastboff = boff;
  823. w->utflastq = q;
  824. nr = q1-q;
  825. if(nr > BUFSIZE/UTFmax)
  826. nr = BUFSIZE/UTFmax;
  827. bufread(t->file, q, r, nr);
  828. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  829. if(boff >= off){
  830. m = nb;
  831. if(boff+m > off+x->count)
  832. m = off+x->count - boff;
  833. memmove(b1+n, b, m);
  834. n += m;
  835. }else if(boff+nb > off){
  836. if(n != 0)
  837. error("bad count in utfrune");
  838. m = nb - (off-boff);
  839. if(m > x->count)
  840. m = x->count;
  841. memmove(b1, b+(off-boff), m);
  842. n += m;
  843. }
  844. boff += nb;
  845. q += nr;
  846. }
  847. fbuffree(r);
  848. fbuffree(b);
  849. fc.count = n;
  850. fc.data = b1;
  851. respond(x, &fc, nil);
  852. fbuffree(b1);
  853. }
  854. int
  855. xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
  856. {
  857. Fcall fc;
  858. Window *w;
  859. Rune *r, junk;
  860. char *b, *b1;
  861. uint q, boff;
  862. int i, rw, m, n, nr, nb;
  863. w = t->w;
  864. wincommit(w, t);
  865. r = fbufalloc();
  866. b = fbufalloc();
  867. b1 = fbufalloc();
  868. n = 0;
  869. q = q0;
  870. boff = 0;
  871. while(q<q1 && n<x->count){
  872. nr = q1-q;
  873. if(nr > BUFSIZE/UTFmax)
  874. nr = BUFSIZE/UTFmax;
  875. bufread(t->file, q, r, nr);
  876. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  877. m = nb;
  878. if(boff+m > x->count){
  879. i = x->count - boff;
  880. /* copy whole runes only */
  881. m = 0;
  882. nr = 0;
  883. while(m < i){
  884. rw = chartorune(&junk, b+m);
  885. if(m+rw > i)
  886. break;
  887. m += rw;
  888. nr++;
  889. }
  890. if(m == 0)
  891. break;
  892. }
  893. memmove(b1+n, b, m);
  894. n += m;
  895. boff += nb;
  896. q += nr;
  897. }
  898. fbuffree(r);
  899. fbuffree(b);
  900. fc.count = n;
  901. fc.data = b1;
  902. respond(x, &fc, nil);
  903. fbuffree(b1);
  904. return q-q0;
  905. }
  906. void
  907. xfideventread(Xfid *x, Window *w)
  908. {
  909. Fcall fc;
  910. char *b;
  911. int i, n;
  912. i = 0;
  913. x->flushed = FALSE;
  914. while(w->nevents == 0){
  915. if(i){
  916. if(!x->flushed)
  917. respond(x, &fc, "window shut down");
  918. return;
  919. }
  920. w->eventx = x;
  921. winunlock(w);
  922. recvp(x->c);
  923. winlock(w, 'F');
  924. i++;
  925. }
  926. n = w->nevents;
  927. if(n > x->count)
  928. n = x->count;
  929. fc.count = n;
  930. fc.data = w->events;
  931. respond(x, &fc, nil);
  932. b = w->events;
  933. w->events = estrdup(w->events+n);
  934. free(b);
  935. w->nevents -= n;
  936. }
  937. void
  938. xfidindexread(Xfid *x)
  939. {
  940. Fcall fc;
  941. int i, j, m, n, nmax, isbuf, cnt, off;
  942. Window *w;
  943. char *b;
  944. Rune *r;
  945. Column *c;
  946. qlock(&row);
  947. nmax = 0;
  948. for(j=0; j<row.ncol; j++){
  949. c = row.col[j];
  950. for(i=0; i<c->nw; i++){
  951. w = c->w[i];
  952. nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
  953. }
  954. }
  955. nmax++;
  956. isbuf = (nmax<=RBUFSIZE);
  957. if(isbuf)
  958. b = (char*)x->buf;
  959. else
  960. b = emalloc(nmax);
  961. r = fbufalloc();
  962. n = 0;
  963. for(j=0; j<row.ncol; j++){
  964. c = row.col[j];
  965. for(i=0; i<c->nw; i++){
  966. w = c->w[i];
  967. /* only show the currently active window of a set */
  968. if(w->body.file->curtext != &w->body)
  969. continue;
  970. winctlprint(w, b+n, 0);
  971. n += Ctlsize;
  972. m = min(RBUFSIZE, w->tag.file->nc);
  973. bufread(w->tag.file, 0, r, m);
  974. m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
  975. while(n<m && b[n]!='\n')
  976. n++;
  977. b[n++] = '\n';
  978. }
  979. }
  980. qunlock(&row);
  981. off = x->offset;
  982. cnt = x->count;
  983. if(off > n)
  984. off = n;
  985. if(off+cnt > n)
  986. cnt = n-off;
  987. fc.count = cnt;
  988. memmove(r, b+off, cnt);
  989. fc.data = (char*)r;
  990. if(!isbuf)
  991. free(b);
  992. respond(x, &fc, nil);
  993. fbuffree(r);
  994. }