xfid.c 21 KB

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