URI:
       twin.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR 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.q0, e.q1);
          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 us */
          374                         switch(e.c2){
          375                         case 'I':
          376                         case 'D':                /* body */
          377                                 if(debug)
          378                                         fprint(2, "shift typing %d... ", e.q1-e.q0);
          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.q0, e.q1);
          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 %d... ", e.q1-e.q0);
          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 && e2.nr==0)){
          434                                         /* send it straight back */
          435                                         fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
          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.r);
          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, dfd, 0);
          455                                                 sende(&blank, fd0, cfd, afd, dfd, 0);
          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.c2, e.q0, e.q1);
          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 waiting. */
          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, "passphrase")) {
          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; resetting\n", x);
          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 above write. */
          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==ntypeb-1 && raw)){
          751                                 if((typing[i] == '\n' || typing[i] == 0x04) && ntypebreak > 0)
          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 }