xfid.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  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[128];
  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. void
  349. xfidwrite(Xfid *x)
  350. {
  351. Fcall fc;
  352. int c, cnt, qid, q, nb, nr, eval;
  353. char buf[64], *err;
  354. Window *w;
  355. Rune *r;
  356. Range a;
  357. Text *t;
  358. uint q0, tq0, tq1;
  359. qid = FILE(x->f->qid);
  360. w = x->f->w;
  361. if(w){
  362. c = 'F';
  363. if(qid==QWtag || qid==QWbody)
  364. c = 'E';
  365. winlock(w, c);
  366. if(w->col == nil){
  367. winunlock(w);
  368. respond(x, &fc, Edel);
  369. return;
  370. }
  371. }
  372. x->data[x->count] = 0;
  373. switch(qid){
  374. case Qcons:
  375. w = errorwin(x->f->mntdir, 'X');
  376. t=&w->body;
  377. goto BodyTag;
  378. case Qlabel:
  379. fc.count = x->count;
  380. respond(x, &fc, nil);
  381. break;
  382. case QWaddr:
  383. x->data[x->count] = 0;
  384. r = bytetorune(x->data, &nr);
  385. t = &w->body;
  386. wincommit(w, t);
  387. eval = TRUE;
  388. a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
  389. free(r);
  390. if(nb < nr){
  391. respond(x, &fc, Ebadaddr);
  392. break;
  393. }
  394. if(!eval){
  395. respond(x, &fc, Eaddr);
  396. break;
  397. }
  398. w->addr = a;
  399. fc.count = x->count;
  400. respond(x, &fc, nil);
  401. break;
  402. case Qeditout:
  403. case QWeditout:
  404. r = bytetorune(x->data, &nr);
  405. if(w)
  406. err = edittext(w, w->wrselrange.q1, r, nr);
  407. else
  408. err = edittext(nil, 0, r, nr);
  409. free(r);
  410. if(err != nil){
  411. respond(x, &fc, err);
  412. break;
  413. }
  414. fc.count = x->count;
  415. respond(x, &fc, nil);
  416. break;
  417. case QWerrors:
  418. w = errorwinforwin(w);
  419. t = &w->body;
  420. goto BodyTag;
  421. case QWbody:
  422. case QWwrsel:
  423. t = &w->body;
  424. goto BodyTag;
  425. case QWctl:
  426. xfidctlwrite(x, w);
  427. break;
  428. case QWdata:
  429. a = w->addr;
  430. t = &w->body;
  431. wincommit(w, t);
  432. if(a.q0>t->file->nc || a.q1>t->file->nc){
  433. respond(x, &fc, Eaddr);
  434. break;
  435. }
  436. r = runemalloc(x->count);
  437. cvttorunes(x->data, x->count, r, &nb, &nr, nil);
  438. if(w->nomark == FALSE){
  439. seq++;
  440. filemark(t->file);
  441. }
  442. q0 = a.q0;
  443. if(a.q1 > q0){
  444. textdelete(t, q0, a.q1, TRUE);
  445. w->addr.q1 = q0;
  446. }
  447. tq0 = t->q0;
  448. tq1 = t->q1;
  449. textinsert(t, q0, r, nr, TRUE);
  450. if(tq0 >= q0)
  451. tq0 += nr;
  452. if(tq1 >= q0)
  453. tq1 += nr;
  454. textsetselect(t, tq0, tq1);
  455. if(!t->w->noscroll)
  456. textshow(t, q0, q0+nr, 0);
  457. textscrdraw(t);
  458. winsettag(w);
  459. free(r);
  460. w->addr.q0 += nr;
  461. w->addr.q1 = w->addr.q0;
  462. fc.count = x->count;
  463. respond(x, &fc, nil);
  464. break;
  465. case QWevent:
  466. xfideventwrite(x, w);
  467. break;
  468. case QWtag:
  469. t = &w->tag;
  470. goto BodyTag;
  471. BodyTag:
  472. q = x->f->nrpart;
  473. cnt = x->count;
  474. if(q > 0){
  475. memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */
  476. memmove(x->data, x->f->rpart, q);
  477. cnt += q;
  478. x->f->nrpart = 0;
  479. }
  480. r = runemalloc(cnt);
  481. cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
  482. /* approach end of buffer */
  483. while(fullrune(x->data+nb, cnt-nb)){
  484. c = nb;
  485. nb += chartorune(&r[nr], x->data+c);
  486. if(r[nr])
  487. nr++;
  488. }
  489. if(nb < cnt){
  490. memmove(x->f->rpart, x->data+nb, cnt-nb);
  491. x->f->nrpart = cnt-nb;
  492. }
  493. if(nr > 0){
  494. wincommit(w, t);
  495. if(qid == QWwrsel){
  496. q0 = w->wrselrange.q1;
  497. if(q0 > t->file->nc)
  498. q0 = t->file->nc;
  499. }else
  500. q0 = t->file->nc;
  501. if(qid == QWtag)
  502. textinsert(t, q0, r, nr, TRUE);
  503. else{
  504. if(w->nomark == FALSE){
  505. seq++;
  506. filemark(t->file);
  507. }
  508. q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
  509. textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
  510. if(qid!=QWwrsel && !t->w->noscroll)
  511. textshow(t, q0+nr, q0+nr, 1);
  512. textscrdraw(t);
  513. }
  514. winsettag(w);
  515. if(qid == QWwrsel)
  516. w->wrselrange.q1 += nr;
  517. free(r);
  518. }
  519. fc.count = x->count;
  520. respond(x, &fc, nil);
  521. break;
  522. default:
  523. sprint(buf, "unknown qid %d in write", qid);
  524. respond(x, &fc, buf);
  525. break;
  526. }
  527. if(w)
  528. winunlock(w);
  529. }
  530. void
  531. xfidctlwrite(Xfid *x, Window *w)
  532. {
  533. Fcall fc;
  534. int i, m, n, nb, nr, nulls;
  535. Rune *r;
  536. char *err, *p, *pp, *q, *e;
  537. int isfbuf, scrdraw, settag;
  538. Text *t;
  539. err = nil;
  540. e = x->data+x->count;
  541. scrdraw = FALSE;
  542. settag = FALSE;
  543. isfbuf = TRUE;
  544. if(x->count < RBUFSIZE)
  545. r = fbufalloc();
  546. else{
  547. isfbuf = FALSE;
  548. r = emalloc(x->count*UTFmax+1);
  549. }
  550. x->data[x->count] = 0;
  551. textcommit(&w->tag, TRUE);
  552. for(n=0; n<x->count; n+=m){
  553. p = x->data+n;
  554. if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
  555. qlock(&w->ctllock);
  556. w->ctlfid = x->f->fid;
  557. m = 4;
  558. }else
  559. if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
  560. w->ctlfid = ~0;
  561. qunlock(&w->ctllock);
  562. m = 6;
  563. }else
  564. if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
  565. t = &w->body;
  566. t->eq0 = ~0;
  567. filereset(t->file);
  568. t->file->mod = FALSE;
  569. w->dirty = FALSE;
  570. settag = TRUE;
  571. m = 5;
  572. }else
  573. if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
  574. t = &w->body;
  575. /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
  576. t->file->mod = TRUE;
  577. w->dirty = TRUE;
  578. settag = TRUE;
  579. m = 5;
  580. }else
  581. if(strncmp(p, "show", 4) == 0){ /* show dot */
  582. t = &w->body;
  583. textshow(t, t->q0, t->q1, 1);
  584. m = 4;
  585. }else
  586. if(strncmp(p, "name ", 5) == 0){ /* set file name */
  587. pp = p+5;
  588. m = 5;
  589. q = memchr(pp, '\n', e-pp);
  590. if(q==nil || q==pp){
  591. err = Ebadctl;
  592. break;
  593. }
  594. *q = 0;
  595. nulls = FALSE;
  596. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  597. if(nulls){
  598. err = "nulls in file name";
  599. break;
  600. }
  601. for(i=0; i<nr; i++)
  602. if(r[i] <= ' '){
  603. err = "bad character in file name";
  604. goto out;
  605. }
  606. out:
  607. seq++;
  608. filemark(w->body.file);
  609. winsetname(w, r, nr);
  610. m += (q+1) - pp;
  611. }else
  612. if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
  613. pp = p+5;
  614. m = 5;
  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 string";
  625. break;
  626. }
  627. w->dumpstr = runetobyte(r, nr);
  628. m += (q+1) - pp;
  629. }else
  630. if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
  631. pp = p+8;
  632. m = 8;
  633. q = memchr(pp, '\n', e-pp);
  634. if(q==nil || q==pp){
  635. err = Ebadctl;
  636. break;
  637. }
  638. *q = 0;
  639. nulls = FALSE;
  640. cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
  641. if(nulls){
  642. err = "nulls in dump directory string";
  643. break;
  644. }
  645. w->dumpdir = runetobyte(r, nr);
  646. m += (q+1) - pp;
  647. }else
  648. if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
  649. colclose(w->col, w, TRUE);
  650. m = 6;
  651. }else
  652. if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
  653. if(!winclean(w, TRUE)){
  654. err = "file dirty";
  655. break;
  656. }
  657. colclose(w->col, w, TRUE);
  658. m = 3;
  659. }else
  660. if(strncmp(p, "get", 3) == 0){ /* get file */
  661. get(&w->body, nil, nil, FALSE, XXX, nil, 0);
  662. m = 3;
  663. }else
  664. if(strncmp(p, "put", 3) == 0){ /* put file */
  665. put(&w->body, nil, nil, XXX, XXX, nil, 0);
  666. m = 3;
  667. }else
  668. if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
  669. textcommit(&w->body, TRUE);
  670. clampaddr(w);
  671. w->body.q0 = w->addr.q0;
  672. w->body.q1 = w->addr.q1;
  673. textsetselect(&w->body, w->body.q0, w->body.q1);
  674. settag = TRUE;
  675. m = 8;
  676. }else
  677. if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
  678. w->addr.q0 = w->body.q0;
  679. w->addr.q1 = w->body.q1;
  680. m = 8;
  681. }else
  682. if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
  683. textcommit(&w->body, TRUE);
  684. clampaddr(w);
  685. w->limit.q0 = w->addr.q0;
  686. w->limit.q1 = w->addr.q1;
  687. m = 10;
  688. }else
  689. if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
  690. w->nomark = TRUE;
  691. m = 6;
  692. }else
  693. if(strncmp(p, "mark", 4) == 0){ /* mark file */
  694. seq++;
  695. filemark(w->body.file);
  696. settag = TRUE;
  697. m = 4;
  698. }else
  699. if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */
  700. w->filemenu = FALSE;
  701. m = 6;
  702. }else
  703. if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */
  704. w->filemenu = TRUE;
  705. m = 4;
  706. }else
  707. if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
  708. w->noscroll = TRUE;
  709. m = 8;
  710. }else
  711. if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
  712. wincleartag(w);
  713. settag = TRUE;
  714. m = 8;
  715. }else
  716. if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
  717. w->noscroll = FALSE;
  718. m = 6;
  719. }else{
  720. err = Ebadctl;
  721. break;
  722. }
  723. while(p[m] == '\n')
  724. m++;
  725. }
  726. if(isfbuf)
  727. fbuffree(r);
  728. else
  729. free(r);
  730. if(err)
  731. n = 0;
  732. fc.count = n;
  733. respond(x, &fc, err);
  734. if(settag)
  735. winsettag(w);
  736. if(scrdraw)
  737. textscrdraw(&w->body);
  738. }
  739. void
  740. xfideventwrite(Xfid *x, Window *w)
  741. {
  742. Fcall fc;
  743. int m, n;
  744. Rune *r;
  745. char *err, *p, *q;
  746. int isfbuf;
  747. Text *t;
  748. int c;
  749. uint q0, q1;
  750. err = nil;
  751. isfbuf = TRUE;
  752. if(x->count < RBUFSIZE)
  753. r = fbufalloc();
  754. else{
  755. isfbuf = FALSE;
  756. r = emalloc(x->count*UTFmax+1);
  757. }
  758. for(n=0; n<x->count; n+=m){
  759. p = x->data+n;
  760. w->owner = *p++; /* disgusting */
  761. c = *p++;
  762. while(*p == ' ')
  763. p++;
  764. q0 = strtoul(p, &q, 10);
  765. if(q == p)
  766. goto Rescue;
  767. p = q;
  768. while(*p == ' ')
  769. p++;
  770. q1 = strtoul(p, &q, 10);
  771. if(q == p)
  772. goto Rescue;
  773. p = q;
  774. while(*p == ' ')
  775. p++;
  776. if(*p++ != '\n')
  777. goto Rescue;
  778. m = p-(x->data+n);
  779. if('a'<=c && c<='z')
  780. t = &w->tag;
  781. else if('A'<=c && c<='Z')
  782. t = &w->body;
  783. else
  784. goto Rescue;
  785. if(q0>t->file->nc || q1>t->file->nc || q0>q1)
  786. goto Rescue;
  787. qlock(&row); /* just like mousethread */
  788. switch(c){
  789. case 'x':
  790. case 'X':
  791. execute(t, q0, q1, TRUE, nil);
  792. break;
  793. case 'l':
  794. case 'L':
  795. look3(t, q0, q1, TRUE);
  796. break;
  797. default:
  798. qunlock(&row);
  799. goto Rescue;
  800. }
  801. qunlock(&row);
  802. }
  803. Out:
  804. if(isfbuf)
  805. fbuffree(r);
  806. else
  807. free(r);
  808. if(err)
  809. n = 0;
  810. fc.count = n;
  811. respond(x, &fc, err);
  812. return;
  813. Rescue:
  814. err = Ebadevent;
  815. goto Out;
  816. }
  817. void
  818. xfidutfread(Xfid *x, Text *t, uint q1, int qid)
  819. {
  820. Fcall fc;
  821. Window *w;
  822. Rune *r;
  823. char *b, *b1;
  824. uint q, off, boff;
  825. int m, n, nr, nb;
  826. w = t->w;
  827. wincommit(w, t);
  828. off = x->offset;
  829. r = fbufalloc();
  830. b = fbufalloc();
  831. b1 = fbufalloc();
  832. n = 0;
  833. if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
  834. boff = w->utflastboff;
  835. q = w->utflastq;
  836. }else{
  837. /* BUG: stupid code: scan from beginning */
  838. boff = 0;
  839. q = 0;
  840. }
  841. w->utflastqid = qid;
  842. while(q<q1 && n<x->count){
  843. /*
  844. * Updating here avoids partial rune problem: we're always on a
  845. * char boundary. The cost is we will usually do one more read
  846. * than we really need, but that's better than being n^2.
  847. */
  848. w->utflastboff = boff;
  849. w->utflastq = q;
  850. nr = q1-q;
  851. if(nr > BUFSIZE/UTFmax)
  852. nr = BUFSIZE/UTFmax;
  853. bufread(t->file, q, r, nr);
  854. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  855. if(boff >= off){
  856. m = nb;
  857. if(boff+m > off+x->count)
  858. m = off+x->count - boff;
  859. memmove(b1+n, b, m);
  860. n += m;
  861. }else if(boff+nb > off){
  862. if(n != 0)
  863. error("bad count in utfrune");
  864. m = nb - (off-boff);
  865. if(m > x->count)
  866. m = x->count;
  867. memmove(b1, b+(off-boff), m);
  868. n += m;
  869. }
  870. boff += nb;
  871. q += nr;
  872. }
  873. fbuffree(r);
  874. fbuffree(b);
  875. fc.count = n;
  876. fc.data = b1;
  877. respond(x, &fc, nil);
  878. fbuffree(b1);
  879. }
  880. int
  881. xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
  882. {
  883. Fcall fc;
  884. Window *w;
  885. Rune *r, junk;
  886. char *b, *b1;
  887. uint q, boff;
  888. int i, rw, m, n, nr, nb;
  889. w = t->w;
  890. wincommit(w, t);
  891. r = fbufalloc();
  892. b = fbufalloc();
  893. b1 = fbufalloc();
  894. n = 0;
  895. q = q0;
  896. boff = 0;
  897. while(q<q1 && n<x->count){
  898. nr = q1-q;
  899. if(nr > BUFSIZE/UTFmax)
  900. nr = BUFSIZE/UTFmax;
  901. bufread(t->file, q, r, nr);
  902. nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
  903. m = nb;
  904. if(boff+m > x->count){
  905. i = x->count - boff;
  906. /* copy whole runes only */
  907. m = 0;
  908. nr = 0;
  909. while(m < i){
  910. rw = chartorune(&junk, b+m);
  911. if(m+rw > i)
  912. break;
  913. m += rw;
  914. nr++;
  915. }
  916. if(m == 0)
  917. break;
  918. }
  919. memmove(b1+n, b, m);
  920. n += m;
  921. boff += nb;
  922. q += nr;
  923. }
  924. fbuffree(r);
  925. fbuffree(b);
  926. fc.count = n;
  927. fc.data = b1;
  928. respond(x, &fc, nil);
  929. fbuffree(b1);
  930. return q-q0;
  931. }
  932. void
  933. xfideventread(Xfid *x, Window *w)
  934. {
  935. Fcall fc;
  936. char *b;
  937. int i, n;
  938. i = 0;
  939. x->flushed = FALSE;
  940. while(w->nevents == 0){
  941. if(i){
  942. if(!x->flushed)
  943. respond(x, &fc, "window shut down");
  944. return;
  945. }
  946. w->eventx = x;
  947. winunlock(w);
  948. recvp(x->c);
  949. winlock(w, 'F');
  950. i++;
  951. }
  952. n = w->nevents;
  953. if(n > x->count)
  954. n = x->count;
  955. fc.count = n;
  956. fc.data = w->events;
  957. respond(x, &fc, nil);
  958. b = w->events;
  959. w->events = estrdup(w->events+n);
  960. free(b);
  961. w->nevents -= n;
  962. }
  963. void
  964. xfidindexread(Xfid *x)
  965. {
  966. Fcall fc;
  967. int i, j, m, n, nmax, isbuf, cnt, off;
  968. Window *w;
  969. char *b;
  970. Rune *r;
  971. Column *c;
  972. qlock(&row);
  973. nmax = 0;
  974. for(j=0; j<row.ncol; j++){
  975. c = row.col[j];
  976. for(i=0; i<c->nw; i++){
  977. w = c->w[i];
  978. nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
  979. }
  980. }
  981. nmax++;
  982. isbuf = (nmax<=RBUFSIZE);
  983. if(isbuf)
  984. b = (char*)x->buf;
  985. else
  986. b = emalloc(nmax);
  987. r = fbufalloc();
  988. n = 0;
  989. for(j=0; j<row.ncol; j++){
  990. c = row.col[j];
  991. for(i=0; i<c->nw; i++){
  992. w = c->w[i];
  993. /* only show the currently active window of a set */
  994. if(w->body.file->curtext != &w->body)
  995. continue;
  996. winctlprint(w, b+n, 0);
  997. n += Ctlsize;
  998. m = min(RBUFSIZE, w->tag.file->nc);
  999. bufread(w->tag.file, 0, r, m);
  1000. m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
  1001. while(n<m && b[n]!='\n')
  1002. n++;
  1003. b[n++] = '\n';
  1004. }
  1005. }
  1006. qunlock(&row);
  1007. off = x->offset;
  1008. cnt = x->count;
  1009. if(off > n)
  1010. off = n;
  1011. if(off+cnt > n)
  1012. cnt = n-off;
  1013. fc.count = cnt;
  1014. memmove(r, b+off, cnt);
  1015. fc.data = (char*)r;
  1016. if(!isbuf)
  1017. free(b);
  1018. respond(x, &fc, nil);
  1019. fbuffree(r);
  1020. }