mesg.c - sam - An updated version of the sam text editor.
 (HTM) git clone git://vernunftzentrum.de/sam.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       mesg.c (15616B)
       ---
            1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
            2 #include <string.h>
            3 #include <u.h>
            4 #include <libg.h>
            5 #include <frame.h>
            6 #include "flayer.h"
            7 #include "samterm.h"
            8 
            9 extern char *exname;
           10 extern Flayer *flast;
           11 
           12 #define HSIZE   3   /* Type + int16_t count */
           13 Header  h;
           14 uint8_t   indata[DATASIZE+1]; /* room for NUL */
           15 uint8_t   outdata[DATASIZE];
           16 int16_t   outcount;
           17 int hversion;
           18 
           19 void    inmesg(Hmesg, int);
           20 int inshort(int);
           21 int64_t    inlong(int);
           22 void    hsetdot(int, int64_t, int64_t);
           23 void    hmoveto(int, int64_t, Flayer *);
           24 void    hsetsnarf(int);
           25 void    clrlock(void);
           26 int snarfswap(char*, int, char**);
           27 
           28 void
           29 rcv(void)
           30 {
           31     int c;
           32     static int state = 0;
           33     static int count = 0;
           34     static int i = 0;
           35     static int errs = 0;
           36 
           37     while((c=rcvchar()) != -1)
           38         switch(state){
           39         case 0:
           40             h.type = c;
           41             state++;
           42             break;
           43 
           44         case 1:
           45             h.count0 = c;
           46             state++;
           47             break;
           48 
           49         case 2:
           50             h.count1 = c;
           51             count = h.count0|(h.count1<<8);
           52             i = 0;
           53             if(count > DATASIZE){
           54                 if(++errs < 5){
           55                     dumperrmsg(count, h.type, h.count0, c);
           56                     state = 0;
           57                     continue;
           58                 }
           59                 fprintf(stderr, "type %d count %d\n", h.type, count);
           60                 panic("count>DATASIZE");
           61             }
           62             if(count == 0)
           63                 goto zerocount;
           64             state++;
           65             break;
           66 
           67         case 3:
           68             indata[i++] = c;
           69             if(i == count){
           70         zerocount:
           71                 indata[i] = 0;
           72                 inmesg(h.type, count);
           73                 state = count = 0;
           74                 continue;
           75             }
           76             break;
           77         }
           78 }
           79 
           80 Text *
           81 whichtext(int tg)
           82 {
           83     int i;
           84 
           85     for(i=0; i<nname; i++)
           86         if(tag[i] == tg)
           87             return text[i];
           88     panic("whichtext");
           89     return 0;
           90 }
           91 
           92 void
           93 inmesg(Hmesg type, int count)
           94 {
           95     Text *t;
           96     int i, m;
           97     int64_t l, l2;
           98     Flayer *lp;
           99 
          100     m = inshort(0);
          101     l = inlong(2);
          102     switch(type){
          103     case Terror:
          104         panic("rcv error");
          105     default:
          106         fprintf(stderr, "type %d\n", type);
          107         panic("rcv unknown");
          108 
          109     case Hversion:
          110         hversion = m;
          111         if (hversion != VERSION)
          112             panic("host-terminal version mismatch");
          113         break;
          114 
          115     case Hbindname:
          116         l = inlong(2);     /* for 64-bit pointers */
          117         if((i=whichmenu(m)) < 0)
          118             break;
          119         /* in case of a race, a bindname may already have occurred */
          120         if((t=whichtext(m)) == 0)
          121             t=(Text *)l;
          122         else    /* let the old one win; clean up the new one */
          123             while(((Text *)l)->nwin>0)
          124                 closeup(&((Text *)l)->l[((Text *)l)->front]);
          125         text[i] = t;
          126         text[i]->tag = m;
          127         break;
          128 
          129     case Hcurrent:
          130         if(whichmenu(m)<0)
          131             break;
          132         t = whichtext(m);
          133         i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;
          134         if(t==0 && (t = sweeptext(0, m))==0)
          135             break;
          136         if(t->l[t->front].textfn==0)
          137             panic("Hcurrent");
          138         lp = &t->l[t->front];
          139         if(i){
          140             flupfront(lp);
          141             flborder(lp, 0);
          142             work = lp;
          143             flast = lp;
          144         }else
          145             current(lp);
          146         break;
          147 
          148     case Hmovname:
          149         if((m=whichmenu(m)) < 0)
          150             break;
          151         t = text[m];
          152         l = tag[m];
          153         i = name[m][0];
          154         text[m] = 0;    /* suppress panic in menudel */
          155         menudel(m);
          156         if(t == &cmd)
          157             m = 0;
          158         else{
          159             if (nname>0 && text[0]==&cmd)
          160                 m = 1;
          161             else m = 0;
          162             for(; m<nname; m++)
          163                 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)
          164                     break;
          165         }
          166         menuins(m, indata+2, t, i, (int)l);
          167         break;
          168 
          169     case Hgrow:
          170         if(whichmenu(m) >= 0)
          171             hgrow(m, l, inlong(10), true);
          172         break;
          173 
          174     case Hnewname:
          175         menuins(0, (uint8_t *)"", (Text *)0, ' ', m);
          176         break;
          177 
          178     case Hcheck0:
          179         i = whichmenu(m);
          180         if(i>=0) {
          181             t = text[i];
          182             if (t)
          183                 t->lock++;
          184             outTs(Tcheck, m);
          185         }
          186         break;
          187 
          188     case Hcheck:
          189         i = whichmenu(m);
          190         if(i>=0) {
          191             t = text[i];
          192             if (t && t->lock)
          193                 t->lock--;
          194             hcheck(m);
          195         }
          196         break;
          197 
          198     case Hunlock:
          199         clrlock();
          200         break;
          201 
          202     case Hdata:
          203         if(whichmenu(m) >= 0)
          204             l += hdata(m, l, indata+10, count-10);
          205     Checkscroll:
          206         if(m == cmd.tag){
          207             for(i=0; i<NL; i++){
          208                 lp = &cmd.l[i];
          209                 if(lp->textfn)
          210                     center(lp, l>=0? l : lp->p1);
          211             }
          212         }
          213         break;
          214 
          215     case Horigin:
          216         if(whichmenu(m) >= 0){
          217             Text *t = whichtext(m);
          218             l2 = inlong(10);
          219             horigin(m, l, &t->l[l2]);
          220         }
          221         break;
          222 
          223     case Hunlockfile:
          224         if(whichmenu(m)>=0 && (t = whichtext(m))->lock){
          225             --t->lock;
          226             l = -1;
          227             goto Checkscroll;
          228         }
          229         break;
          230 
          231     case Hsetdot:
          232         if(whichmenu(m) >= 0)
          233             hsetdot(m, l, inlong(10));
          234         break;
          235 
          236     case Hgrowdata:
          237         if(whichmenu(m)<0)
          238             break;
          239         hgrow(m, l, inlong(10), false);
          240         whichtext(m)->lock++;   /* fake the request */
          241         l += hdata(m, l, indata+18, count-18);
          242         goto Checkscroll;
          243 
          244     case Hmoveto:
          245         if(whichmenu(m)>=0)
          246             hmoveto(m, l, NULL);
          247         break;
          248 
          249     case Hclean:
          250         if((m = whichmenu(m)) >= 0)
          251             name[m][0] = ' ';
          252         break;
          253 
          254     case Hdirty:
          255         if((m = whichmenu(m))>=0)
          256             name[m][0] = '\'';
          257         break;
          258 
          259     case Hdelname:
          260         if((m=whichmenu(m)) >= 0)
          261             menudel(m);
          262         break;
          263 
          264     case Hcut:
          265         if(whichmenu(m) >= 0)
          266             hcut(m, l, inlong(10));
          267         break;
          268 
          269     case Hclose:
          270         if(whichmenu(m)<0 || (t = whichtext(m))==0)
          271             break;
          272         l = t->nwin;
          273         for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)
          274             if(lp->textfn){
          275                 closeup(lp);
          276                 --l;
          277             }
          278         break;
          279 
          280     case Hsetpat:
          281         setpat((char *)indata);
          282         break;
          283 
          284     case Hsetsnarf:
          285         hsetsnarf(m);
          286         break;
          287 
          288     case Hsnarflen:
          289         snarflen = inlong(0);
          290         break;
          291 
          292     case Hack:
          293         outT0(Tack);
          294         break;
          295 
          296     case Hexit:
          297         outT0(Texit);
          298         mouseexit();
          299         break;
          300     }
          301 }
          302 
          303 void
          304 setlock(void)
          305 {
          306     lock++;
          307     cursorswitch(cursor = LockCursor);
          308 }
          309 
          310 void
          311 clrlock(void)
          312 {
          313     hasunlocked = true;
          314     if(lock > 0)
          315         lock--;
          316     if(lock == 0)
          317         cursorswitch(cursor=DefaultCursor);
          318 }
          319 
          320 void
          321 startfile(Text *t)
          322 {
          323     outTsl(Tstartfile, t->tag, (int64_t)t);      /* for 64-bit pointers */
          324     setlock();
          325 }
          326 
          327 void
          328 startnewfile(int type, Text *t)
          329 {
          330     t->tag = Untagged;
          331     outTl(type, (int64_t)t);             /* for 64-bit pointers */
          332 }
          333 
          334 int
          335 inshort(int n)
          336 {
          337     return indata[n]|(indata[n+1]<<8);
          338 }
          339 
          340 int64_t
          341 inlong(int n)
          342 {
          343     int64_t l;
          344 
          345     l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
          346     l = (l<<16) | (indata[n+3]<<8) | indata[n+2];
          347     l = (l<<16) | (indata[n+1]<<8) | indata[n];
          348     return l;
          349 }
          350 
          351 void
          352 outT0(Tmesg type)
          353 {
          354     outstart(type);
          355     outsend();
          356 }
          357 
          358 void
          359 outTl(Tmesg type, int64_t l)
          360 {
          361     outstart(type);
          362     outlong(l);
          363     outsend();
          364 }
          365 
          366 void
          367 outTs(Tmesg type, int s)
          368 {
          369     outstart(type);
          370     outshort(s);
          371     outsend();
          372 }
          373 
          374 void
          375 outTss(Tmesg type, int s1, int s2)
          376 {
          377     outstart(type);
          378     outshort(s1);
          379     outshort(s2);
          380     outsend();
          381 }
          382 
          383 void
          384 outTslll(Tmesg type, int s1, int64_t l1, int64_t l2, int64_t l3)
          385 {
          386     outstart(type);
          387     outshort(s1);
          388     outlong(l1);
          389     outlong(l2);
          390     outlong(l3);
          391     outsend();
          392 }
          393 
          394 void
          395 outTsll(Tmesg type, int s1, int64_t l1, int64_t l2)
          396 {
          397     outstart(type);
          398     outshort(s1);
          399     outlong(l1);
          400     outlong(l2);
          401     outsend();
          402 }
          403 
          404 void
          405 outTsl(Tmesg type, int s1, int64_t l1)
          406 {
          407     outstart(type);
          408     outshort(s1);
          409     outlong(l1);
          410     outsend();
          411 }
          412 
          413 void
          414 outTslS(Tmesg type, int s1, int64_t l1, wchar_t *s)
          415 {
          416     char buf[DATASIZE*3+1];
          417     char *c;
          418 
          419     outstart(type);
          420     outshort(s1);
          421     outlong(l1);
          422     c = buf;
          423     while(*s)
          424         c += runetochar(c, *s++);
          425     *c++ = 0;
          426     outcopy(c-buf, (uint8_t *)buf);
          427     outsend();
          428 }
          429 
          430 void
          431 outTsls(Tmesg type, int s1, int64_t l1, int s2)
          432 {
          433     outstart(type);
          434     outshort(s1);
          435     outlong(l1);
          436     outshort(s2);
          437     outsend();
          438 }
          439 
          440 void
          441 outstart(Tmesg type)
          442 {
          443     outdata[0] = type;
          444     outcount = 0;
          445 }
          446 
          447 void
          448 outcopy(int count, uint8_t *data)
          449 {
          450     while(count--)
          451         outdata[HSIZE+outcount++] = *data++;    
          452 }
          453 
          454 void
          455 outshort(int s)
          456 {
          457     uint8_t buf[2];
          458 
          459     buf[0]=s;
          460     buf[1]=s>>8;
          461     outcopy(2, buf);
          462 }
          463 
          464 void
          465 outlong(int64_t l)
          466 {
          467     int i;
          468     uint8_t buf[8];
          469 
          470     for(i = 0; i < sizeof(buf); i++, l >>= 8)
          471         buf[i] = l;
          472 
          473     outcopy(8, buf);
          474 }
          475 
          476 void
          477 outsend(void)
          478 {
          479     if(outcount>DATASIZE-HSIZE)
          480         panic("outcount>sizeof outdata");
          481     outdata[1]=outcount;
          482     outdata[2]=outcount>>8;
          483     if(write(1, (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)
          484         exit(EXIT_FAILURE);
          485 }
          486 
          487 
          488 void
          489 hsetdot(int m, int64_t p0, int64_t p1)
          490 {
          491     Text *t = whichtext(m);
          492     Flayer *l = &t->l[t->front];
          493 
          494     flushtyping(true);
          495     flsetselect(l, p0, p1);
          496 }
          497 
          498 void
          499 horigin(int m, int64_t p0, Flayer *l)
          500 {
          501     Text *t = whichtext(m);
          502     l = l ? l : &t->l[t->front];
          503     int64_t a;
          504     uint64_t n;
          505     wchar_t *r;
          506 
          507     if (getlayer(l, t) < 0)
          508         return; /* the user managed to close the layer during the round trip with the host */
          509 
          510     if(!flprepare(l)){
          511         l->origin = p0;
          512         return;
          513     }
          514     a = p0-l->origin;
          515     if(a>=0 && a<l->f.nchars)
          516         frdelete(&l->f, 0, a);
          517     else if(a<0 && -a<l->f.nchars){
          518         r = rload(&t->rasp, p0, l->origin, &n);
          519         frinsert(&l->f, r, r+n, 0);
          520     }else
          521         frdelete(&l->f, 0, l->f.nchars);
          522     l->origin = p0;
          523     scrdraw(l, t->rasp.nrunes);
          524     if(l->visible==Some)
          525         flrefresh(l, l->entire, 0);
          526     hcheck(m);
          527 }
          528 
          529 void
          530 hmoveto(int m, int64_t p0, Flayer *l)
          531 {
          532     Text *t = whichtext(m);
          533     l = l ? l : &t->l[t->front];
          534 
          535     if (p0 < l->origin || p0 - l->origin > l->f.nchars * 9/10)
          536         outTslll(Torigin, m, p0, 2L, getlayer(l, t));
          537 }
          538 
          539 void
          540 hcheck(int m)
          541 {
          542     Flayer *l;
          543     Text *t;
          544     int reqd = 0, i;
          545     int64_t n, nl, a;
          546     wchar_t *r;
          547 
          548     if(m == Untagged)
          549         return;
          550     t = whichtext(m);
          551     if(t == 0)      /* possible in a half-built window */
          552         return;
          553     for(l = &t->l[0], i = 0; i<NL; i++, l++){
          554         if(l->textfn==0 || !flprepare(l))   /* BUG: don't
          555                                need this if BUG below
          556                                is fixed */
          557             continue;
          558         a = t->l[i].origin;
          559         n = rcontig(&t->rasp, a, a+l->f.nchars, true);
          560         if(n<l->f.nchars)   /* text missing in middle of screen */
          561             a+=n;
          562         else{           /* text missing at end of screen? */
          563         Again:
          564             if(l->f.lastlinefull)
          565                 goto Checksel;  /* all's well */
          566             a = t->l[i].origin+l->f.nchars;
          567             n = t->rasp.nrunes-a;
          568             if(n==0)
          569                 goto Checksel;
          570             if(n>TBLOCKSIZE)
          571                 n = TBLOCKSIZE;
          572             n = rcontig(&t->rasp, a, a+n, true);
          573             if(n>0){
          574                 rload(&t->rasp, a, a+n, 0);
          575                 nl = l->f.nchars;
          576                 r = scratch;
          577                 flinsert(l, r, r+n, l->origin+nl);
          578                 if(nl == l->f.nchars)   /* made no progress */
          579                     goto Checksel;
          580                 goto Again;
          581             }
          582         }
          583         if(!reqd){
          584             n = rcontig(&t->rasp, a, a+TBLOCKSIZE, false);
          585             if(n <= 0)
          586                 panic("hcheck request==0");
          587             outTsls(Trequest, m, a, (int)n);
          588             outTs(Tcheck, m);
          589             t->lock++;  /* for the Trequest */
          590             t->lock++;  /* for the Tcheck */
          591             reqd++;
          592         }
          593         Checksel:
          594         flsetselect(l, l->p0, l->p1);
          595     }
          596 }
          597 
          598 void
          599 flnewlyvisible(Flayer *l)
          600 {
          601     hcheck(((Text *)l->user1)->tag);
          602 }
          603 
          604 void
          605 hsetsnarf(int nc)
          606 {
          607     char *s2;
          608     char *s1;
          609     int i;
          610     int n;
          611 
          612     cursorswitch(DeadCursor);
          613     s2 = alloc(nc+1);
          614     for(i=0; i<nc; i++)
          615         s2[i] = getch();
          616     s2[nc] = 0;
          617     n = snarfswap(s2, nc, &s1);
          618     if(n >= 0){
          619         if(!s1)
          620             n = 0;
          621         if(n > SNARFSIZE-1)
          622             n = SNARFSIZE-1;
          623         s1 = realloc(s1, n+1);
          624         if (!s1)
          625             exit(EXIT_FAILURE);
          626         s1[n] = 0;
          627         snarflen = n;
          628         outTs(Tsetsnarf, n);
          629         if(n>0 && write(1, s1, n)!=n)
          630             exit(EXIT_FAILURE);
          631         free(s1);
          632     }else
          633         outTs(Tsetsnarf, 0);
          634     free(s2);
          635     cursorswitch(cursor);
          636 }
          637 
          638 void
          639 hgrow(int m, int64_t a, int64_t new, bool req)
          640 {
          641     int i;
          642     Flayer *l;
          643     Text *t = whichtext(m);
          644     int64_t o, b;
          645 
          646     if(new <= 0)
          647         panic("hgrow");
          648     rresize(&t->rasp, a, 0L, new);
          649     for(l = &t->l[0], i = 0; i<NL; i++, l++){
          650         if(l->textfn == 0)
          651             continue;
          652         o = l->origin;
          653         b = a-o-rmissing(&t->rasp, o, a);
          654         if(a < o)
          655             l->origin+=new;
          656         if(a < l->p0)
          657             l->p0+=new;
          658         if(a < l->p1)
          659             l->p1+=new;
          660         /* must prevent b temporarily becoming unsigned */
          661         if(!req || a<o || (b>0 && b>l->f.nchars) ||
          662             (l->f.nchars==0 && a-o>0))
          663             continue;
          664         if(new>TBLOCKSIZE)
          665             new = TBLOCKSIZE;
          666         outTsls(Trequest, m, a, (int)new);
          667         t->lock++;
          668         req = false;
          669     }
          670 }
          671 
          672 int
          673 hdata1(Text *t, int64_t a, wchar_t *r, int len)
          674 {
          675     int i;
          676     Flayer *l;
          677     int64_t o, b;
          678 
          679     for(l = &t->l[0], i=0; i<NL; i++, l++){
          680         if(l->textfn==0)
          681             continue;
          682         o = l->origin;
          683         b = a-o-rmissing(&t->rasp, o, a);
          684         /* must prevent b temporarily becoming unsigned */
          685         if(a<o || (b>0 && b>l->f.nchars))
          686             continue;
          687         flinsert(l, r, r+len, o+b);
          688     }
          689     rdata(&t->rasp, a, a+len, r);
          690     rclean(&t->rasp);
          691     return len;
          692 }
          693 
          694 int
          695 hdata(int m, int64_t a, uint8_t *s, int len)
          696 {
          697     int i, w;
          698     Text *t = whichtext(m);
          699     wchar_t buf[DATASIZE], *r;
          700 
          701     if(t->lock)
          702         --t->lock;
          703     if(len == 0)
          704         return 0;
          705     r = buf;
          706     for(i=0; i<len; i+=w,s+=w)
          707         w = chartorune(r++, (char*)s);
          708     return hdata1(t, a, buf, r-buf);
          709 }
          710 
          711 int
          712 hdatarune(int m, int64_t a, wchar_t *r, int len)
          713 {
          714     Text *t = whichtext(m);
          715 
          716     if(t->lock)
          717         --t->lock;
          718     if(len == 0)
          719         return 0;
          720     return hdata1(t, a, r, len);
          721 }
          722 
          723 void
          724 hcut(int m, int64_t a, int64_t old)
          725 {
          726     Flayer *l;
          727     Text *t = whichtext(m);
          728     int i;
          729     int64_t o, b;
          730 
          731     if(t->lock)
          732         --t->lock;
          733     for(l = &t->l[0], i = 0; i<NL; i++, l++){
          734         if(l->textfn == 0)
          735             continue;
          736         o = l->origin;
          737         b = a-o-rmissing(&t->rasp, o, a);
          738         /* must prevent b temporarily becoming unsigned */
          739         if((b<0 || b<l->f.nchars) && a+old>=o){
          740             fldelete(l, b<0? o : o+b,
          741                 a+old-rmissing(&t->rasp, o, a+old));
          742         }
          743         if(a+old<o)
          744             l->origin-=old;
          745         else if(a<=o)
          746             l->origin = a;
          747         if(a+old<l->p0)
          748             l->p0-=old;
          749         else if(a<=l->p0)
          750             l->p0 = a;
          751         if(a+old<l->p1)
          752             l->p1-=old;
          753         else if(a<=l->p1)
          754             l->p1 = a;
          755     }
          756     rresize(&t->rasp, a, old, 0L);
          757     rclean(&t->rasp);
          758 }