xfid.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  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. b = winctlprint(w, buf, 1);
  286. goto Readb;
  287. Readbuf:
  288. b = buf;
  289. Readb:
  290. n = strlen(b);
  291. if(off > n)
  292. off = n;
  293. if(off+x->count > n)
  294. x->count = n-off;
  295. fc.count = x->count;
  296. fc.data = b+off;
  297. respond(x, &fc, nil);
  298. if(b != buf)
  299. free(b);
  300. break;
  301. case QWevent:
  302. xfideventread(x, w);
  303. break;
  304. case QWdata:
  305. /* BUG: what should happen if q1 > q0? */
  306. if(w->addr.q0 > w->body.file->nc){
  307. respond(x, &fc, Eaddr);
  308. break;
  309. }
  310. w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc);
  311. w->addr.q1 = w->addr.q0;
  312. break;
  313. case QWtag:
  314. xfidutfread(x, &w->tag, w->tag.file->nc, QWtag);
  315. break;
  316. case QWrdsel:
  317. seek(w->rdselfd, off, 0);
  318. n = x->count;
  319. if(n > BUFSIZE)
  320. n = BUFSIZE;
  321. b = fbufalloc();
  322. n = read(w->rdselfd, b, n);
  323. if(n < 0){
  324. respond(x, &fc, "I/O error in temp file");
  325. break;
  326. }
  327. fc.count = n;
  328. fc.data = b;
  329. respond(x, &fc, nil);
  330. fbuffree(b);
  331. break;
  332. default:
  333. sprint(buf, "unknown qid %d in read", q);
  334. respond(x, &fc, nil);
  335. }
  336. winunlock(w);
  337. }
  338. void
  339. xfidwrite(Xfid *x)
  340. {
  341. Fcall fc;
  342. int c, cnt, qid, q, nb, nr, eval;
  343. char buf[64], *err;
  344. Window *w;
  345. Rune *r;
  346. Range a;
  347. Text *t;
  348. uint q0, tq0, tq1;
  349. qid = FILE(x->f->qid);
  350. w = x->f->w;
  351. if(w){
  352. c = 'F';
  353. if(qid==QWtag || qid==QWbody)
  354. c = 'E';
  355. winlock(w, c);
  356. if(w->col == nil){
  357. winunlock(w);
  358. respond(x, &fc, Edel);
  359. return;
  360. }
  361. }
  362. x->data[x->count] = 0;
  363. switch(qid){
  364. case Qcons:
  365. w = errorwin(x->f->mntdir, 'X');
  366. t=&w->body;
  367. goto BodyTag;
  368. case Qlabel:
  369. fc.count = x->count;
  370. respond(x, &fc, nil);
  371. break;
  372. case QWaddr:
  373. x->data[x->count] = 0;
  374. r = bytetorune(x->data, &nr);
  375. t = &w->body;
  376. wincommit(w, t);
  377. eval = TRUE;
  378. a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
  379. free(r);
  380. if(nb < nr){
  381. respond(x, &fc, Ebadaddr);
  382. break;
  383. }
  384. if(!eval){
  385. respond(x, &fc, Eaddr);
  386. break;
  387. }
  388. w->addr = a;
  389. fc.count = x->count;
  390. respond(x, &fc, nil);
  391. break;
  392. case Qeditout:
  393. case QWeditout:
  394. r = bytetorune(x->data, &nr);
  395. if(w)
  396. err = edittext(w, w->wrselrange.q1, r, nr);
  397. else
  398. err = edittext(nil, 0, r, nr);
  399. free(r);
  400. if(err != nil){
  401. respond(x, &fc, err);
  402. break;
  403. }
  404. fc.count = x->count;
  405. respond(x, &fc, nil);
  406. break;
  407. case QWbody:
  408. case QWwrsel:
  409. t = &w->body;
  410. goto BodyTag;
  411. case QWctl:
  412. xfidctlwrite(x, w);
  413. break;
  414. case QWdata:
  415. a = w->addr;
  416. t = &w->body;
  417. wincommit(w, t);
  418. if(a.q0>t->file->nc || a.q1>t->file->nc){
  419. respond(x, &fc, Eaddr);
  420. break;
  421. }
  422. r = runemalloc(x->count);
  423. cvttorunes(x->data, x->count, r, &nb, &nr, nil);
  424. if(w->nomark == FALSE){
  425. seq++;
  426. filemark(t->file);
  427. }
  428. q0 = a.q0;
  429. if(a.q1 > q0){
  430. textdelete(t, q0, a.q1, TRUE);
  431. w->addr.q1 = q0;
  432. }
  433. tq0 = t->q0;
  434. tq1 = t->q1;
  435. textinsert(t, q0, r, nr, TRUE);
  436. if(tq0 >= q0)
  437. tq0 += nr;
  438. if(tq1 >= q0)
  439. tq1 += nr;
  440. textsetselect(t, tq0, tq1);
  441. if(!t->w->noscroll)
  442. textshow(t, q0, q0+nr, 0);
  443. textscrdraw(t);
  444. winsettag(w);
  445. free(r);
  446. w->addr.q0 += nr;
  447. w->addr.q1 = w->addr.q0;
  448. fc.count = x->count;
  449. respond(x, &fc, nil);
  450. break;
  451. case QWevent:
  452. xfideventwrite(x, w);
  453. break;
  454. case QWtag:
  455. t = &w->tag;
  456. goto BodyTag;
  457. BodyTag:
  458. q = x->f->nrpart;
  459. cnt = x->count;
  460. if(q > 0){
  461. memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */
  462. memmove(x->data, x->f->rpart, q);
  463. cnt += q;
  464. x->f->nrpart = 0;
  465. }
  466. r = runemalloc(cnt);
  467. cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
  468. /* approach end of buffer */
  469. while(fullrune(x->data+nb, cnt-nb)){
  470. c = nb;
  471. nb += chartorune(&r[nr], x->data+c);
  472. if(r[nr])
  473. nr++;
  474. }
  475. if(nb < cnt){
  476. memmove(x->f->rpart, x->data+nb, cnt-nb);
  477. x->f->nrpart = cnt-nb;
  478. }
  479. if(nr > 0){
  480. wincommit(w, t);
  481. if(qid == QWwrsel){
  482. q0 = w->wrselrange.q1;
  483. if(q0 > t->file->nc)
  484. q0 = t->file->nc;
  485. }else
  486. q0 = t->file->nc;
  487. if(qid == QWtag)
  488. textinsert(t, q0, r, nr, TRUE);
  489. else{
  490. if(w->nomark == FALSE){
  491. seq++;
  492. filemark(t->file);
  493. }
  494. q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
  495. textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
  496. if(qid!=QWwrsel && !t->w->noscroll)
  497. textshow(t, q0+nr, q0+nr, 1);
  498. textscrdraw(t);
  499. }
  500. winsettag(w);
  501. if(qid == QWwrsel)
  502. w->wrselrange.q1 += nr;
  503. free(r);
  504. }
  505. fc.count = x->count;
  506. respond(x, &fc, nil);
  507. break;
  508. default:
  509. sprint(buf, "unknown qid %d in write", qid);
  510. respond(x, &fc, buf);
  511. break;
  512. }
  513. if(w)
  514. winunlock(w);
  515. }
  516. void
  517. xfidctlwrite(Xfid *x, Window *w)
  518. {
  519. Fcall fc;
  520. int i, m, n, nb, nr, nulls;
  521. Rune *r;
  522. char *err, *p, *pp, *q, *e;
  523. int isfbuf, scrdraw, settag;
  524. Text *t;
  525. err = nil;
  526. e = x->data+x->count;
  527. scrdraw = FALSE;
  528. settag = FALSE;
  529. isfbuf = TRUE;
  530. if(x->count < RBUFSIZE)
  531. r = fbufalloc();
  532. else{
  533. isfbuf = FALSE;
  534. r = emalloc(x->count*UTFmax+1);
  535. }
  536. x->data[x->count] = 0;
  537. textcommit(&w->tag, TRUE);
  538. for(n=0; n<x->count; n+=m){
  539. p = x->data+n;
  540. if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
  541. qlock(&w->ctllock);
  542. w->ctlfid = x->f->fid;
  543. m = 4;
  544. }else
  545. if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
  546. w->ctlfid = ~0;
  547. qunlock(&w->ctllock);
  548. m = 6;
  549. }else
  550. if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
  551. t = &w->body;
  552. t->eq0 = ~0;
  553. filereset(t->file);
  554. t->file->mod = FALSE;
  555. w->dirty = FALSE;
  556. settag = TRUE;
  557. m = 5;
  558. }else
  559. if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
  560. t = &w->body;
  561. /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
  562. t->file->mod = TRUE;
  563. w->dirty = TRUE;
  564. settag = TRUE;
  565. m = 5;
  566. }else
  567. if(strncmp(p, "show", 4) == 0){ /* show dot */
  568. t = &w->body;
  569. textshow(t, t->q0, t->q1, 1);
  570. m = 4;
  571. }else
  572. if(strncmp(p, "name ", 5) == 0){ /* set file name */
  573. pp = p+5;
  574. m = 5;
  575. q = memchr(pp, '\n', e-pp);
  576. if(q==nil || q==pp){
  577. err = Ebadctl;
  578. break;
  579. }
  580. *q = 0;
  581. nulls = FALSE;
  582. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  583. if(nulls){
  584. err = "nulls in file name";
  585. break;
  586. }
  587. for(i=0; i<nr; i++)
  588. if(r[i] <= ' '){
  589. err = "bad character in file name";
  590. goto out;
  591. }
  592. out:
  593. seq++;
  594. filemark(w->body.file);
  595. winsetname(w, r, nr);
  596. m += (q+1) - pp;
  597. }else
  598. if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
  599. pp = p+5;
  600. m = 5;
  601. q = memchr(pp, '\n', e-pp);
  602. if(q==nil || q==pp){
  603. err = Ebadctl;
  604. break;
  605. }
  606. *q = 0;
  607. nulls = FALSE;
  608. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  609. if(nulls){
  610. err = "nulls in dump string";
  611. break;
  612. }
  613. w->dumpstr = runetobyte(r, nr);
  614. m += (q+1) - pp;
  615. }else
  616. if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
  617. pp = p+8;
  618. m = 8;
  619. q = memchr(pp, '\n', e-pp);
  620. if(q==nil || q==pp){
  621. err = Ebadctl;
  622. break;
  623. }
  624. *q = 0;
  625. nulls = FALSE;
  626. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  627. if(nulls){
  628. err = "nulls in dump directory string";
  629. break;
  630. }
  631. w->dumpdir = runetobyte(r, nr);
  632. m += (q+1) - pp;
  633. }else
  634. if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
  635. colclose(w->col, w, TRUE);
  636. m = 6;
  637. }else
  638. if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
  639. if(!winclean(w, TRUE)){
  640. err = "file dirty";
  641. break;
  642. }
  643. colclose(w->col, w, TRUE);
  644. m = 3;
  645. }else
  646. if(strncmp(p, "get", 3) == 0){ /* get file */
  647. get(&w->body, nil, nil, FALSE, XXX, nil, 0);
  648. m = 3;
  649. }else
  650. if(strncmp(p, "put", 3) == 0){ /* put file */
  651. put(&w->body, nil, nil, XXX, XXX, nil, 0);
  652. m = 3;
  653. }else
  654. if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
  655. textcommit(&w->body, TRUE);
  656. clampaddr(w);
  657. w->body.q0 = w->addr.q0;
  658. w->body.q1 = w->addr.q1;
  659. textsetselect(&w->body, w->body.q0, w->body.q1);
  660. settag = TRUE;
  661. m = 8;
  662. }else
  663. if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
  664. w->addr.q0 = w->body.q0;
  665. w->addr.q1 = w->body.q1;
  666. m = 8;
  667. }else
  668. if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
  669. textcommit(&w->body, TRUE);
  670. clampaddr(w);
  671. w->limit.q0 = w->addr.q0;
  672. w->limit.q1 = w->addr.q1;
  673. m = 10;
  674. }else
  675. if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
  676. w->nomark = TRUE;
  677. m = 6;
  678. }else
  679. if(strncmp(p, "mark", 4) == 0){ /* mark file */
  680. seq++;
  681. filemark(w->body.file);
  682. settag = TRUE;
  683. m = 4;
  684. }else
  685. if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
  686. w->noscroll = TRUE;
  687. m = 8;
  688. }else
  689. if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
  690. wincleartag(w);
  691. settag = TRUE;
  692. m = 8;
  693. }else
  694. if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
  695. w->noscroll = FALSE;
  696. m = 6;
  697. }else{
  698. err = Ebadctl;
  699. break;
  700. }
  701. while(p[m] == '\n')
  702. m++;
  703. }
  704. if(isfbuf)
  705. fbuffree(r);
  706. else
  707. free(r);
  708. if(err)
  709. n = 0;
  710. fc.count = n;
  711. respond(x, &fc, err);
  712. if(settag)
  713. winsettag(w);
  714. if(scrdraw)
  715. textscrdraw(&w->body);
  716. }
  717. void
  718. xfideventwrite(Xfid *x, Window *w)
  719. {
  720. Fcall fc;
  721. int m, n;
  722. Rune *r;
  723. char *err, *p, *q;
  724. int isfbuf;
  725. Text *t;
  726. int c;
  727. uint q0, q1;
  728. err = nil;
  729. isfbuf = TRUE;
  730. if(x->count < RBUFSIZE)
  731. r = fbufalloc();
  732. else{
  733. isfbuf = FALSE;
  734. r = emalloc(x->count*UTFmax+1);
  735. }
  736. for(n=0; n<x->count; n+=m){
  737. p = x->data+n;
  738. w->owner = *p++; /* disgusting */
  739. c = *p++;
  740. while(*p == ' ')
  741. p++;
  742. q0 = strtoul(p, &q, 10);
  743. if(q == p)
  744. goto Rescue;
  745. p = q;
  746. while(*p == ' ')
  747. p++;
  748. q1 = strtoul(p, &q, 10);
  749. if(q == p)
  750. goto Rescue;
  751. p = q;
  752. while(*p == ' ')
  753. p++;
  754. if(*p++ != '\n')
  755. goto Rescue;
  756. m = p-(x->data+n);
  757. if('a'<=c && c<='z')
  758. t = &w->tag;
  759. else if('A'<=c && c<='Z')
  760. t = &w->body;
  761. else
  762. goto Rescue;
  763. if(q0>t->file->nc || q1>t->file->nc || q0>q1)
  764. goto Rescue;
  765. qlock(&row); /* just like mousethread */
  766. switch(c){
  767. case 'x':
  768. case 'X':
  769. execute(t, q0, q1, TRUE, nil);
  770. break;
  771. case 'l':
  772. case 'L':
  773. look3(t, q0, q1, TRUE);
  774. break;
  775. default:
  776. qunlock(&row);
  777. goto Rescue;
  778. }
  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. qunlock(&row);
  985. off = x->offset;
  986. cnt = x->count;
  987. if(off > n)
  988. off = n;
  989. if(off+cnt > n)
  990. cnt = n-off;
  991. fc.count = cnt;
  992. memmove(r, b+off, cnt);
  993. fc.data = (char*)r;
  994. if(!isbuf)
  995. free(b);
  996. respond(x, &fc, nil);
  997. fbuffree(r);
  998. }