twin.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
twin.c (15339B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <thread.h> | |
4 #include <fcall.h> | |
5 #include <9pclient.h> | |
6 #include "term.h" | |
7 | |
8 const char *termprog = "win"; | |
9 | |
10 #define EVENTSIZE 256 | |
11 #define STACK 32768 | |
12 | |
13 typedef struct Event Event; | |
14 typedef struct Q Q; | |
15 | |
16 struct Event | |
17 { | |
18 int c1; | |
19 int c2; | |
20 int q0; | |
21 int q1; | |
22 int flag; | |
23 int nb; | |
24 int nr; | |
25 char b[EVENTSIZE*UTFmax+1]; | |
26 Rune r[EVENTSIZE+1]; | |
27 }; | |
28 | |
29 Event blank = { | |
30 'M', | |
31 'X', | |
32 0, 0, 0, 1, 1, | |
33 { ' ', 0 }, | |
34 { ' ', 0 } | |
35 }; | |
36 | |
37 struct Q | |
38 { | |
39 QLock lk; | |
40 int p; | |
41 int k; | |
42 }; | |
43 | |
44 Q q; | |
45 | |
46 CFid *eventfd; | |
47 CFid *addrfd; | |
48 CFid *datafd; | |
49 CFid *ctlfd; | |
50 /* int bodyfd; */ | |
51 | |
52 char *typing; | |
53 int ntypeb; | |
54 int ntyper; | |
55 int ntypebreak; | |
56 int debug; | |
57 int rcfd; | |
58 int cook = 1; | |
59 int password; | |
60 int israw(int); | |
61 | |
62 char *name; | |
63 | |
64 char **prog; | |
65 Channel *cwait; | |
66 int pid = -1; | |
67 | |
68 int label(char*, int); | |
69 void error(char*, ...); | |
70 void stdinproc(void*); | |
71 void stdoutproc(void*); | |
72 void type(Event*, int, CFid*, CFid*); | |
73 void sende(Event*, int, CFid*, CFid*, CFid*, int); | |
74 char *onestring(int, char**); | |
75 int delete(Event*); | |
76 void deltype(uint, uint); | |
77 void sendbs(int, int); | |
78 void runproc(void*); | |
79 | |
80 int | |
81 fsfidprint(CFid *fid, char *fmt, ...) | |
82 { | |
83 char buf[256]; | |
84 va_list arg; | |
85 int n; | |
86 | |
87 va_start(arg, fmt); | |
88 n = vsnprint(buf, sizeof buf, fmt, arg); | |
89 va_end(arg); | |
90 return fswrite(fid, buf, n); | |
91 } | |
92 | |
93 void | |
94 usage(void) | |
95 { | |
96 fprint(2, "usage: win cmd args...\n"); | |
97 threadexitsall("usage"); | |
98 } | |
99 | |
100 void | |
101 waitthread(void *v) | |
102 { | |
103 recvp(cwait); | |
104 threadexitsall(nil); | |
105 } | |
106 | |
107 void | |
108 hangupnote(void *a, char *msg) | |
109 { | |
110 if(strcmp(msg, "hangup") == 0 && pid != 0){ | |
111 postnote(PNGROUP, pid, "hangup"); | |
112 noted(NDFLT); | |
113 } | |
114 if(strstr(msg, "child")){ | |
115 char buf[128]; | |
116 int n; | |
117 | |
118 n = awaitnohang(buf, sizeof buf-1); | |
119 if(n > 0){ | |
120 buf[n] = 0; | |
121 if(atoi(buf) == pid) | |
122 threadexitsall(0); | |
123 } | |
124 noted(NCONT); | |
125 } | |
126 noted(NDFLT); | |
127 } | |
128 | |
129 void | |
130 threadmain(int argc, char **argv) | |
131 { | |
132 int fd, id; | |
133 char buf[256]; | |
134 char buf1[128]; | |
135 CFsys *fs; | |
136 char *dump; | |
137 | |
138 dump = onestring(argc, argv); | |
139 | |
140 ARGBEGIN{ | |
141 case 'd': | |
142 debug = 1; | |
143 break; | |
144 case 'n': | |
145 name = EARGF(usage()); | |
146 break; | |
147 default: | |
148 usage(); | |
149 }ARGEND | |
150 | |
151 prog = argv; | |
152 | |
153 if(name == nil){ | |
154 if(argc > 0) | |
155 name = argv[0]; | |
156 else{ | |
157 name = sysname(); | |
158 if(name == nil) | |
159 name = "gnot"; | |
160 } | |
161 } | |
162 | |
163 /* | |
164 * notedisable("sys: write on closed pipe"); | |
165 * not okay to disable the note, because that | |
166 * gets inherited by the subshell, so that something | |
167 * as simple as "yes | sed 10q" never exits. | |
168 * call notifyoff instead. (is notedisable ever safe?) | |
169 */ | |
170 notifyoff("sys: write on closed pipe"); | |
171 | |
172 noteenable("sys: child"); | |
173 notify(hangupnote); | |
174 | |
175 if((fs = nsmount("acme", "")) == 0) | |
176 sysfatal("nsmount acme: %r"); | |
177 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC); | |
178 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12) | |
179 sysfatal("ctl: %r"); | |
180 id = atoi(buf); | |
181 snprint(buf, sizeof buf, "%d", id); | |
182 putenv("winid", buf); | |
183 sprint(buf, "%d/tag", id); | |
184 fd = fsopenfd(fs, buf, OWRITE|OCEXEC); | |
185 write(fd, " Send", 1+4); | |
186 close(fd); | |
187 sprint(buf, "%d/event", id); | |
188 eventfd = fsopen(fs, buf, ORDWR|OCEXEC); | |
189 sprint(buf, "%d/addr", id); | |
190 addrfd = fsopen(fs, buf, ORDWR|OCEXEC); | |
191 sprint(buf, "%d/data", id); | |
192 datafd = fsopen(fs, buf, ORDWR|OCEXEC); | |
193 sprint(buf, "%d/body", id); | |
194 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */ | |
195 if(eventfd==nil || addrfd==nil || datafd==nil) | |
196 sysfatal("data files: %r"); | |
197 /* | |
198 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0) | |
199 sysfatal("data files: %r"); | |
200 */ | |
201 fsunmount(fs); | |
202 | |
203 cwait = threadwaitchan(); | |
204 threadcreate(waitthread, nil, STACK); | |
205 pid = rcstart(argc, argv, &rcfd, nil); | |
206 if(pid == -1) | |
207 sysfatal("exec failed"); | |
208 | |
209 getwd(buf1, sizeof buf1); | |
210 sprint(buf, "name %s/-%s\n0\n", buf1, name); | |
211 fswrite(ctlfd, buf, strlen(buf)); | |
212 sprint(buf, "dumpdir %s/\n", buf1); | |
213 fswrite(ctlfd, buf, strlen(buf)); | |
214 sprint(buf, "dump %s\n", dump); | |
215 fswrite(ctlfd, buf, strlen(buf)); | |
216 sprint(buf, "scroll"); | |
217 fswrite(ctlfd, buf, strlen(buf)); | |
218 | |
219 updatewinsize(25, 80, 0, 0); | |
220 proccreate(stdoutproc, nil, STACK); | |
221 stdinproc(nil); | |
222 } | |
223 | |
224 void | |
225 error(char *s, ...) | |
226 { | |
227 va_list arg; | |
228 | |
229 if(s){ | |
230 va_start(arg, s); | |
231 s = vsmprint(s, arg); | |
232 va_end(arg); | |
233 fprint(2, "win: %s: %r\n", s); | |
234 } | |
235 if(pid != -1) | |
236 postnote(PNGROUP, pid, "hangup"); | |
237 threadexitsall(s); | |
238 } | |
239 | |
240 char* | |
241 onestring(int argc, char **argv) | |
242 { | |
243 char *p; | |
244 int i, n; | |
245 static char buf[1024]; | |
246 | |
247 if(argc == 0) | |
248 return ""; | |
249 p = buf; | |
250 for(i=0; i<argc; i++){ | |
251 n = strlen(argv[i]); | |
252 if(p+n+1 >= buf+sizeof buf) | |
253 break; | |
254 memmove(p, argv[i], n); | |
255 p += n; | |
256 *p++ = ' '; | |
257 } | |
258 p[-1] = 0; | |
259 return buf; | |
260 } | |
261 | |
262 int | |
263 getec(CFid *efd) | |
264 { | |
265 static char buf[8192]; | |
266 static char *bufp; | |
267 static int nbuf; | |
268 | |
269 if(nbuf == 0){ | |
270 nbuf = fsread(efd, buf, sizeof buf); | |
271 if(nbuf <= 0) | |
272 error(nil); | |
273 bufp = buf; | |
274 } | |
275 --nbuf; | |
276 return *bufp++; | |
277 } | |
278 | |
279 int | |
280 geten(CFid *efd) | |
281 { | |
282 int n, c; | |
283 | |
284 n = 0; | |
285 while('0'<=(c=getec(efd)) && c<='9') | |
286 n = n*10+(c-'0'); | |
287 if(c != ' ') | |
288 error("event number syntax"); | |
289 return n; | |
290 } | |
291 | |
292 int | |
293 geter(CFid *efd, char *buf, int *nb) | |
294 { | |
295 Rune r; | |
296 int n; | |
297 | |
298 r = getec(efd); | |
299 buf[0] = r; | |
300 n = 1; | |
301 if(r < Runeself) | |
302 goto Return; | |
303 while(!fullrune(buf, n)) | |
304 buf[n++] = getec(efd); | |
305 chartorune(&r, buf); | |
306 Return: | |
307 *nb = n; | |
308 return r; | |
309 } | |
310 | |
311 void | |
312 gete(CFid *efd, Event *e) | |
313 { | |
314 int i, nb; | |
315 | |
316 e->c1 = getec(efd); | |
317 e->c2 = getec(efd); | |
318 e->q0 = geten(efd); | |
319 e->q1 = geten(efd); | |
320 e->flag = geten(efd); | |
321 e->nr = geten(efd); | |
322 if(e->nr > EVENTSIZE) | |
323 error("event string too long"); | |
324 e->nb = 0; | |
325 for(i=0; i<e->nr; i++){ | |
326 e->r[i] = geter(efd, e->b+e->nb, &nb); | |
327 e->nb += nb; | |
328 } | |
329 e->r[e->nr] = 0; | |
330 e->b[e->nb] = 0; | |
331 if(getec(efd) != '\n') | |
332 error("event syntax 2"); | |
333 } | |
334 | |
335 int | |
336 nrunes(char *s, int nb) | |
337 { | |
338 int i, n; | |
339 Rune r; | |
340 | |
341 n = 0; | |
342 for(i=0; i<nb; n++) | |
343 i += chartorune(&r, s+i); | |
344 return n; | |
345 } | |
346 | |
347 void | |
348 stdinproc(void *v) | |
349 { | |
350 CFid *cfd = ctlfd; | |
351 CFid *efd = eventfd; | |
352 CFid *dfd = datafd; | |
353 CFid *afd = addrfd; | |
354 int fd0 = rcfd; | |
355 Event e, e2, e3, e4; | |
356 int n; | |
357 | |
358 USED(v); | |
359 | |
360 for(;;){ | |
361 if(debug) | |
362 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper); | |
363 gete(efd, &e); | |
364 if(debug) | |
365 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e… | |
366 qlock(&q.lk); | |
367 switch(e.c1){ | |
368 default: | |
369 Unknown: | |
370 print("unknown message %c%c\n", e.c1, e.c2); | |
371 break; | |
372 | |
373 case 'E': /* write to body or tag; can't affect u… | |
374 switch(e.c2){ | |
375 case 'I': | |
376 case 'D': /* body */ | |
377 if(debug) | |
378 fprint(2, "shift typing %d... ",… | |
379 q.p += e.q1-e.q0; | |
380 break; | |
381 | |
382 case 'i': | |
383 case 'd': /* tag */ | |
384 break; | |
385 | |
386 default: | |
387 goto Unknown; | |
388 } | |
389 break; | |
390 | |
391 case 'F': /* generated by our actions; ignore */ | |
392 break; | |
393 | |
394 case 'K': | |
395 case 'M': | |
396 switch(e.c2){ | |
397 case 'I': | |
398 if(e.nr == 1 && e.r[0] == 0x7F) { | |
399 char buf[1]; | |
400 fsprint(addrfd, "#%ud,#%ud", e.q… | |
401 fswrite(datafd, "", 0); | |
402 buf[0] = 0x7F; | |
403 write(fd0, buf, 1); | |
404 break; | |
405 } | |
406 if(e.q0 < q.p){ | |
407 if(debug) | |
408 fprint(2, "shift typing … | |
409 q.p += e.q1-e.q0; | |
410 } | |
411 else if(e.q0 <= q.p+ntyper){ | |
412 if(debug) | |
413 fprint(2, "type... "); | |
414 type(&e, fd0, afd, dfd); | |
415 } | |
416 break; | |
417 | |
418 case 'D': | |
419 n = delete(&e); | |
420 q.p -= n; | |
421 if(israw(fd0) && e.q1 >= q.p+n) | |
422 sendbs(fd0, n); | |
423 break; | |
424 | |
425 case 'x': | |
426 case 'X': | |
427 if(e.flag & 2) | |
428 gete(efd, &e2); | |
429 if(e.flag & 8){ | |
430 gete(efd, &e3); | |
431 gete(efd, &e4); | |
432 } | |
433 if(e.flag&1 || (e.c2=='x' && e.nr==0 && … | |
434 /* send it straight back */ | |
435 fsfidprint(efd, "%c%c%d %d\n", e… | |
436 break; | |
437 } | |
438 if(e.q0==e.q1 && (e.flag&2)){ | |
439 e2.flag = e.flag; | |
440 e = e2; | |
441 } | |
442 char buf[100]; | |
443 snprint(buf, sizeof buf, "%.*S", e.nr, e… | |
444 if(cistrcmp(buf, "cook") == 0) { | |
445 cook = 1; | |
446 break; | |
447 } | |
448 if(cistrcmp(buf, "nocook") == 0) { | |
449 cook = 0; | |
450 break; | |
451 } | |
452 if(e.flag & 8){ | |
453 if(e.q1 != e.q0){ | |
454 sende(&e, fd0, cfd, afd,… | |
455 sende(&blank, fd0, cfd, … | |
456 } | |
457 sende(&e3, fd0, cfd, afd, dfd, 1… | |
458 }else if(e.q1 != e.q0) | |
459 sende(&e, fd0, cfd, afd, dfd, 1); | |
460 break; | |
461 | |
462 case 'l': | |
463 case 'L': | |
464 /* just send it back */ | |
465 if(e.flag & 2) | |
466 gete(efd, &e2); | |
467 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c… | |
468 break; | |
469 | |
470 case 'd': | |
471 case 'i': | |
472 break; | |
473 | |
474 default: | |
475 goto Unknown; | |
476 } | |
477 } | |
478 qunlock(&q.lk); | |
479 } | |
480 } | |
481 | |
482 int | |
483 dropcr(char *p, int n) | |
484 { | |
485 int i; | |
486 char *w, *r, *q; | |
487 | |
488 r = p; | |
489 w = p; | |
490 for(i=0; i<n; i++) { | |
491 switch(*r) { | |
492 case '\b': | |
493 if(w > p) | |
494 w--; | |
495 break; | |
496 case '\r': | |
497 while(i<n-1 && *(r+1) == '\r') { | |
498 r++; | |
499 i++; | |
500 } | |
501 if(i<n && *(r+1) != '\n') { | |
502 q = r; | |
503 while(q>p && *(q-1) != '\n') | |
504 q--; | |
505 if(q > p) { | |
506 w = q; | |
507 break; | |
508 } | |
509 } | |
510 *w++ = '\n'; | |
511 break; | |
512 default: | |
513 *w++ = *r; | |
514 break; | |
515 } | |
516 r++; | |
517 } | |
518 return w-p; | |
519 } | |
520 | |
521 void | |
522 stdoutproc(void *v) | |
523 { | |
524 int fd1 = rcfd; | |
525 CFid *afd = addrfd; | |
526 CFid *dfd = datafd; | |
527 int n, m, w, npart; | |
528 char *buf, *s, *t; | |
529 Rune r; | |
530 char x[16], hold[UTFmax]; | |
531 | |
532 USED(v); | |
533 buf = malloc(8192+UTFmax+1); | |
534 npart = 0; | |
535 for(;;){ | |
536 /* Let typing have a go -- maybe there's a rubout waitin… | |
537 yield(); | |
538 n = read(fd1, buf+npart, 8192); | |
539 if(n <= 0) | |
540 error(nil); | |
541 | |
542 n = echocancel(buf+npart, n); | |
543 if(n == 0) | |
544 continue; | |
545 | |
546 n = dropcrnl(buf+npart, n); | |
547 if(n == 0) | |
548 continue; | |
549 | |
550 n = dropcr(buf+npart, n); | |
551 if(n == 0) | |
552 continue; | |
553 | |
554 /* squash NULs */ | |
555 s = memchr(buf+npart, 0, n); | |
556 if(s){ | |
557 for(t=s; s<buf+npart+n; s++) | |
558 if(*t = *s) /* assign = */ | |
559 t++; | |
560 n = t-(buf+npart); | |
561 } | |
562 | |
563 n += npart; | |
564 | |
565 /* hold on to final partial rune */ | |
566 npart = 0; | |
567 while(n>0 && (buf[n-1]&0xC0)){ | |
568 --n; | |
569 npart++; | |
570 if((buf[n]&0xC0)!=0x80){ | |
571 if(fullrune(buf+n, npart)){ | |
572 w = chartorune(&r, buf+n); | |
573 n += w; | |
574 npart -= w; | |
575 } | |
576 break; | |
577 } | |
578 } | |
579 if(n > 0){ | |
580 memmove(hold, buf+n, npart); | |
581 buf[n] = 0; | |
582 n = label(buf, n); | |
583 buf[n] = 0; | |
584 | |
585 // clumsy but effective: notice password | |
586 // prompts so we can disable echo. | |
587 password = 0; | |
588 if(cistrstr(buf, "password") || cistrstr(buf, "p… | |
589 int i; | |
590 | |
591 i = n; | |
592 while(i > 0 && buf[i-1] == ' ') | |
593 i--; | |
594 password = i > 0 && buf[i-1] == ':'; | |
595 } | |
596 | |
597 qlock(&q.lk); | |
598 m = sprint(x, "#%d", q.p); | |
599 if(fswrite(afd, x, m) != m){ | |
600 fprint(2, "stdout writing address %s: %r… | |
601 if(fswrite(afd, "$", 1) < 0) | |
602 fprint(2, "reset: %r\n"); | |
603 fsseek(afd, 0, 0); | |
604 m = fsread(afd, x, sizeof x-1); | |
605 if(m >= 0){ | |
606 x[m] = 0; | |
607 q.p = atoi(x); | |
608 } | |
609 } | |
610 if(fswrite(dfd, buf, n) != n) | |
611 error("stdout writing body"); | |
612 /* Make sure acme scrolls to the end of the abov… | |
613 if(fswrite(dfd, nil, 0) != 0) | |
614 error("stdout flushing body"); | |
615 q.p += nrunes(buf, n); | |
616 qunlock(&q.lk); | |
617 memmove(buf, hold, npart); | |
618 } | |
619 } | |
620 } | |
621 | |
622 char wdir[512]; | |
623 int | |
624 label(char *sr, int n) | |
625 { | |
626 char *sl, *el, *er, *r, *p; | |
627 | |
628 er = sr+n; | |
629 for(r=er-1; r>=sr; r--) | |
630 if(*r == '\007') | |
631 break; | |
632 if(r < sr) | |
633 return n; | |
634 | |
635 el = r+1; | |
636 if(el-sr > sizeof wdir - strlen(name) - 20) | |
637 sr = el - (sizeof wdir - strlen(name) - 20); | |
638 for(sl=el-3; sl>=sr; sl--) | |
639 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';') | |
640 break; | |
641 if(sl < sr) | |
642 return n; | |
643 | |
644 *r = 0; | |
645 if(strcmp(sl+3, "*9term-hold+") != 0) { | |
646 /* | |
647 * add /-sysname if not present | |
648 */ | |
649 snprint(wdir, sizeof wdir, "name %s", sl+3); | |
650 p = strrchr(wdir, '/'); | |
651 if(p==nil || *(p+1) != '-'){ | |
652 p = wdir+strlen(wdir); | |
653 if(*(p-1) != '/') | |
654 *p++ = '/'; | |
655 *p++ = '-'; | |
656 strcpy(p, name); | |
657 } | |
658 strcat(wdir, "\n0\n"); | |
659 fswrite(ctlfd, wdir, strlen(wdir)); | |
660 } | |
661 | |
662 memmove(sl, el, er-el); | |
663 n -= (el-sl); | |
664 return n; | |
665 } | |
666 | |
667 int | |
668 delete(Event *e) | |
669 { | |
670 uint q0, q1; | |
671 int deltap; | |
672 | |
673 q0 = e->q0; | |
674 q1 = e->q1; | |
675 if(q1 <= q.p) | |
676 return e->q1-e->q0; | |
677 if(q0 >= q.p+ntyper) | |
678 return 0; | |
679 deltap = 0; | |
680 if(q0 < q.p){ | |
681 deltap = q.p-q0; | |
682 q0 = 0; | |
683 }else | |
684 q0 -= q.p; | |
685 if(q1 > q.p+ntyper) | |
686 q1 = ntyper; | |
687 else | |
688 q1 -= q.p; | |
689 deltype(q0, q1); | |
690 return deltap; | |
691 } | |
692 | |
693 void | |
694 addtype(int c, uint p0, char *b, int nb, int nr) | |
695 { | |
696 int i, w; | |
697 Rune r; | |
698 uint p; | |
699 char *b0; | |
700 | |
701 for(i=0; i<nb; i+=w){ | |
702 w = chartorune(&r, b+i); | |
703 if((r==0x7F||r==3) && c=='K'){ | |
704 write(rcfd, "\x7F", 1); | |
705 /* toss all typing */ | |
706 q.p += ntyper+nr; | |
707 ntypebreak = 0; | |
708 ntypeb = 0; | |
709 ntyper = 0; | |
710 /* buglet: more than one delete ignored */ | |
711 return; | |
712 } | |
713 if(r=='\n' || r==0x04) | |
714 ntypebreak++; | |
715 } | |
716 typing = realloc(typing, ntypeb+nb); | |
717 if(typing == nil) | |
718 error("realloc"); | |
719 if(p0 == ntyper) | |
720 memmove(typing+ntypeb, b, nb); | |
721 else{ | |
722 b0 = typing; | |
723 for(p=0; p<p0 && b0<typing+ntypeb; p++){ | |
724 w = chartorune(&r, b0+i); | |
725 b0 += w; | |
726 } | |
727 if(p != p0) | |
728 error("typing: findrune"); | |
729 memmove(b0+nb, b0, (typing+ntypeb)-b0); | |
730 memmove(b0, b, nb); | |
731 } | |
732 ntypeb += nb; | |
733 ntyper += nr; | |
734 } | |
735 | |
736 int | |
737 israw(int fd0) | |
738 { | |
739 return (!cook || password) && !isecho(fd0); | |
740 } | |
741 | |
742 void | |
743 sendtype(int fd0) | |
744 { | |
745 int i, n, nr, raw; | |
746 | |
747 raw = israw(fd0); | |
748 while(ntypebreak || (raw && ntypeb > 0)){ | |
749 for(i=0; i<ntypeb; i++) | |
750 if(typing[i]=='\n' || typing[i]==0x04 || (i==nty… | |
751 if((typing[i] == '\n' || typing[i] == 0x… | |
752 ntypebreak--; | |
753 n = i+1; | |
754 i++; | |
755 if(!raw) | |
756 echoed(typing, n); | |
757 if(write(fd0, typing, n) != n) | |
758 error("sending to program"); | |
759 nr = nrunes(typing, i); | |
760 q.p += nr; | |
761 ntyper -= nr; | |
762 ntypeb -= i; | |
763 memmove(typing, typing+i, ntypeb); | |
764 goto cont2; | |
765 } | |
766 print("no breakchar\n"); | |
767 ntypebreak = 0; | |
768 cont2:; | |
769 } | |
770 } | |
771 | |
772 void | |
773 sendbs(int fd0, int n) | |
774 { | |
775 char buf[128]; | |
776 int m; | |
777 | |
778 memset(buf, 0x08, sizeof buf); | |
779 while(n > 0) { | |
780 m = sizeof buf; | |
781 if(m > n) | |
782 m = n; | |
783 n -= m; | |
784 write(fd0, buf, m); | |
785 } | |
786 } | |
787 | |
788 void | |
789 deltype(uint p0, uint p1) | |
790 { | |
791 int w; | |
792 uint p, b0, b1; | |
793 Rune r; | |
794 | |
795 /* advance to p0 */ | |
796 b0 = 0; | |
797 for(p=0; p<p0 && b0<ntypeb; p++){ | |
798 w = chartorune(&r, typing+b0); | |
799 b0 += w; | |
800 } | |
801 if(p != p0) | |
802 error("deltype 1"); | |
803 /* advance to p1 */ | |
804 b1 = b0; | |
805 for(; p<p1 && b1<ntypeb; p++){ | |
806 w = chartorune(&r, typing+b1); | |
807 b1 += w; | |
808 if(r=='\n' || r==0x04) | |
809 ntypebreak--; | |
810 } | |
811 if(p != p1) | |
812 error("deltype 2"); | |
813 memmove(typing+b0, typing+b1, ntypeb-b1); | |
814 ntypeb -= b1-b0; | |
815 ntyper -= p1-p0; | |
816 } | |
817 | |
818 void | |
819 type(Event *e, int fd0, CFid *afd, CFid *dfd) | |
820 { | |
821 int m, n, nr; | |
822 char buf[128]; | |
823 | |
824 if(e->nr > 0) | |
825 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr); | |
826 else{ | |
827 m = e->q0; | |
828 while(m < e->q1){ | |
829 n = sprint(buf, "#%d", m); | |
830 fswrite(afd, buf, n); | |
831 n = fsread(dfd, buf, sizeof buf); | |
832 nr = nrunes(buf, n); | |
833 while(m+nr > e->q1){ | |
834 do; while(n>0 && (buf[--n]&0xC0)==0x80); | |
835 --nr; | |
836 } | |
837 if(n == 0) | |
838 break; | |
839 addtype(e->c1, m-q.p, buf, n, nr); | |
840 m += nr; | |
841 } | |
842 } | |
843 if(israw(fd0)) { | |
844 n = sprint(buf, "#%d,#%d", e->q0, e->q1); | |
845 fswrite(afd, buf, n); | |
846 fswrite(dfd, "", 0); | |
847 q.p -= e->q1 - e->q0; | |
848 } | |
849 sendtype(fd0); | |
850 if(e->nb > 0 && e->b[e->nb-1] == '\n') | |
851 cook = 1; | |
852 } | |
853 | |
854 void | |
855 sende(Event *e, int fd0, CFid *cfd, CFid *afd, CFid *dfd, int donl) | |
856 { | |
857 int l, m, n, nr, lastc, end; | |
858 char abuf[16], buf[128]; | |
859 | |
860 end = q.p+ntyper; | |
861 l = sprint(abuf, "#%d", end); | |
862 fswrite(afd, abuf, l); | |
863 if(e->nr > 0){ | |
864 fswrite(dfd, e->b, e->nb); | |
865 addtype(e->c1, ntyper, e->b, e->nb, e->nr); | |
866 lastc = e->r[e->nr-1]; | |
867 }else{ | |
868 m = e->q0; | |
869 lastc = 0; | |
870 while(m < e->q1){ | |
871 n = sprint(buf, "#%d", m); | |
872 fswrite(afd, buf, n); | |
873 n = fsread(dfd, buf, sizeof buf); | |
874 nr = nrunes(buf, n); | |
875 while(m+nr > e->q1){ | |
876 do; while(n>0 && (buf[--n]&0xC0)==0x80); | |
877 --nr; | |
878 } | |
879 if(n == 0) | |
880 break; | |
881 l = sprint(abuf, "#%d", end); | |
882 fswrite(afd, abuf, l); | |
883 fswrite(dfd, buf, n); | |
884 addtype(e->c1, ntyper, buf, n, nr); | |
885 lastc = buf[n-1]; | |
886 m += nr; | |
887 end += nr; | |
888 } | |
889 } | |
890 if(donl && lastc!='\n'){ | |
891 fswrite(dfd, "\n", 1); | |
892 addtype(e->c1, ntyper, "\n", 1, 1); | |
893 } | |
894 fswrite(cfd, "dot=addr", 8); | |
895 sendtype(fd0); | |
896 } |