xfid.c 20 KB

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