xfid.c 19 KB

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