mesg.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       mesg.c (14442B)
       ---
            1 #include "sam.h"
            2 Header        h;
            3 uchar        indata[DATASIZE];
            4 uchar        outdata[2*DATASIZE+3];        /* room for overflow message */
            5 uchar        *inp;
            6 uchar        *outp;
            7 uchar        *outmsg = outdata;
            8 Posn        cmdpt;
            9 Posn        cmdptadv;
           10 Buffer        snarfbuf;
           11 int        waitack;
           12 int        outbuffered;
           13 int        tversion;
           14 
           15 int        inshort(void);
           16 long        inlong(void);
           17 vlong        invlong(void);
           18 int        inmesg(Tmesg);
           19 
           20 void        outshort(int);
           21 void        outlong(long);
           22 void        outvlong(vlong);
           23 void        outcopy(int, void*);
           24 void        outsend(void);
           25 void        outstart(Hmesg);
           26 
           27 void        setgenstr(File*, Posn, Posn);
           28 
           29 #ifdef DEBUG
           30 char *hname[] = {
           31         [Hversion]        "Hversion",
           32         [Hbindname]        "Hbindname",
           33         [Hcurrent]        "Hcurrent",
           34         [Hnewname]        "Hnewname",
           35         [Hmovname]        "Hmovname",
           36         [Hgrow]                "Hgrow",
           37         [Hcheck0]        "Hcheck0",
           38         [Hcheck]        "Hcheck",
           39         [Hunlock]        "Hunlock",
           40         [Hdata]                "Hdata",
           41         [Horigin]        "Horigin",
           42         [Hunlockfile]        "Hunlockfile",
           43         [Hsetdot]        "Hsetdot",
           44         [Hgrowdata]        "Hgrowdata",
           45         [Hmoveto]        "Hmoveto",
           46         [Hclean]        "Hclean",
           47         [Hdirty]        "Hdirty",
           48         [Hcut]                "Hcut",
           49         [Hsetpat]        "Hsetpat",
           50         [Hdelname]        "Hdelname",
           51         [Hclose]        "Hclose",
           52         [Hsetsnarf]        "Hsetsnarf",
           53         [Hsnarflen]        "Hsnarflen",
           54         [Hack]                "Hack",
           55         [Hexit]                "Hexit",
           56 //        [Hplumb]                "Hplumb"
           57 };
           58 
           59 char *tname[] = {
           60         [Tversion]        "Tversion",
           61         [Tstartcmdfile]        "Tstartcmdfile",
           62         [Tcheck]        "Tcheck",
           63         [Trequest]        "Trequest",
           64         [Torigin]        "Torigin",
           65         [Tstartfile]        "Tstartfile",
           66         [Tworkfile]        "Tworkfile",
           67         [Ttype]                "Ttype",
           68         [Tcut]                "Tcut",
           69         [Tpaste]        "Tpaste",
           70         [Tsnarf]        "Tsnarf",
           71         [Tstartnewfile]        "Tstartnewfile",
           72         [Twrite]        "Twrite",
           73         [Tclose]        "Tclose",
           74         [Tlook]                "Tlook",
           75         [Tsearch]        "Tsearch",
           76         [Tsend]                "Tsend",
           77         [Tdclick]        "Tdclick",
           78         [Tstartsnarf]        "Tstartsnarf",
           79         [Tsetsnarf]        "Tsetsnarf",
           80         [Tack]                "Tack",
           81         [Texit]                "Texit",
           82 //        [Tplumb]                "Tplumb"
           83 };
           84 
           85 void
           86 journal(int out, char *s)
           87 {
           88         static int fd = 0;
           89 
           90         if(fd <= 0)
           91                 fd = create("/tmp/sam.out", 1, 0666L);
           92         fprint(fd, "%s%s\n", out? "out: " : "in:  ", s);
           93 }
           94 
           95 void
           96 journaln(int out, long n)
           97 {
           98         char buf[32];
           99 
          100         snprint(buf, sizeof buf, "%ld", n);
          101         journal(out, buf);
          102 }
          103 
          104 void
          105 journalv(int out, vlong v)
          106 {
          107         char buf[32];
          108 
          109         snprint(buf, sizeof buf, "%lld", v);
          110         journal(out, buf);
          111 }
          112 
          113 #else
          114 #define        journal(a, b)
          115 #define journaln(a, b)
          116 #endif
          117 
          118 int
          119 rcvchar(void){
          120         static uchar buf[64];
          121         static int i, nleft = 0;
          122 
          123         if(nleft <= 0){
          124                 nleft = read(0, (char *)buf, sizeof buf);
          125                 if(nleft <= 0)
          126                         return -1;
          127                 i = 0;
          128         }
          129         --nleft;
          130         return buf[i++];
          131 }
          132 
          133 int
          134 rcv(void){
          135         int c;
          136         static int state = 0;
          137         static int count = 0;
          138         static int i = 0;
          139 
          140         while((c=rcvchar()) != -1)
          141                 switch(state){
          142                 case 0:
          143                         h.type = c;
          144                         state++;
          145                         break;
          146 
          147                 case 1:
          148                         h.count0 = c;
          149                         state++;
          150                         break;
          151 
          152                 case 2:
          153                         h.count1 = c;
          154                         count = h.count0|(h.count1<<8);
          155                         i = 0;
          156                         if(count > DATASIZE)
          157                                 panic("count>DATASIZE");
          158                         if(count == 0)
          159                                 goto zerocount;
          160                         state++;
          161                         break;
          162 
          163                 case 3:
          164                         indata[i++] = c;
          165                         if(i == count){
          166                 zerocount:
          167                                 indata[i] = 0;
          168                                 state = count = 0;
          169                                 return inmesg(h.type);
          170                         }
          171                         break;
          172                 }
          173         return 0;
          174 }
          175 
          176 File *
          177 whichfile(int tag)
          178 {
          179         int i;
          180 
          181         for(i = 0; i<file.nused; i++)
          182                 if(file.filepptr[i]->tag==tag)
          183                         return file.filepptr[i];
          184         hiccough((char *)0);
          185         return 0;
          186 }
          187 
          188 int
          189 inmesg(Tmesg type)
          190 {
          191         Rune buf[1025];
          192         char cbuf[64];
          193         int i, m;
          194         short s;
          195         long l, l1;
          196         vlong v;
          197         File *f;
          198         Posn p0, p1, p;
          199         Range r;
          200         String *str;
          201         char *c, *wdir;
          202         Rune *rp;
          203         Plumbmsg *pm;
          204 
          205         if(type > TMAX)
          206                 panic("inmesg");
          207 
          208         journal(0, tname[type]);
          209 
          210         inp = indata;
          211         switch(type){
          212         case -1:
          213                 panic("rcv error");
          214 
          215         default:
          216                 fprint(2, "unknown type %d\n", type);
          217                 panic("rcv unknown");
          218 
          219         case Tversion:
          220                 tversion = inshort();
          221                 journaln(0, tversion);
          222                 break;
          223 
          224         case Tstartcmdfile:
          225                 v = invlong();                /* for 64-bit pointers */
          226                 journaln(0, v);
          227                 Strdupl(&genstr, samname);
          228                 cmd = newfile();
          229                 cmd->unread = 0;
          230                 outTsv(Hbindname, cmd->tag, v);
          231                 outTs(Hcurrent, cmd->tag);
          232                 logsetname(cmd, &genstr);
          233                 cmd->rasp = listalloc('P');
          234                 cmd->mod = 0;
          235                 if(cmdstr.n){
          236                         loginsert(cmd, 0L, cmdstr.s, cmdstr.n);
          237                         Strdelete(&cmdstr, 0L, (Posn)cmdstr.n);
          238                 }
          239                 fileupdate(cmd, FALSE, TRUE);
          240                 outT0(Hunlock);
          241                 break;
          242 
          243         case Tcheck:
          244                 /* go through whichfile to check the tag */
          245                 outTs(Hcheck, whichfile(inshort())->tag);
          246                 break;
          247 
          248         case Trequest:
          249                 f = whichfile(inshort());
          250                 p0 = inlong();
          251                 p1 = p0+inshort();
          252                 journaln(0, p0);
          253                 journaln(0, p1-p0);
          254                 if(f->unread)
          255                         panic("Trequest: unread");
          256                 if(p1>f->b.nc)
          257                         p1 = f->b.nc;
          258                 if(p0>f->b.nc) /* can happen e.g. scrolling during command */
          259                         p0 = f->b.nc;
          260                 if(p0 == p1){
          261                         i = 0;
          262                         r.p1 = r.p2 = p0;
          263                 }else{
          264                         r = rdata(f->rasp, p0, p1-p0);
          265                         i = r.p2-r.p1;
          266                         bufread(&f->b, r.p1, buf, i);
          267                 }
          268                 buf[i]=0;
          269                 outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1));
          270                 break;
          271 
          272         case Torigin:
          273                 s = inshort();
          274                 l = inlong();
          275                 l1 = inlong();
          276                 journaln(0, l1);
          277                 lookorigin(whichfile(s), l, l1);
          278                 break;
          279 
          280         case Tstartfile:
          281                 termlocked++;
          282                 f = whichfile(inshort());
          283                 if(!f->rasp)        /* this might be a duplicate message */
          284                         f->rasp = listalloc('P');
          285                 current(f);
          286                 outTsv(Hbindname, f->tag, invlong());        /* for 64-bit pointers */
          287                 outTs(Hcurrent, f->tag);
          288                 journaln(0, f->tag);
          289                 if(f->unread)
          290                         load(f);
          291                 else{
          292                         if(f->b.nc>0){
          293                                 rgrow(f->rasp, 0L, f->b.nc);
          294                                 outTsll(Hgrow, f->tag, 0L, f->b.nc);
          295                         }
          296                         outTs(Hcheck0, f->tag);
          297                         moveto(f, f->dot.r);
          298                 }
          299                 break;
          300 
          301         case Tworkfile:
          302                 i = inshort();
          303                 f = whichfile(i);
          304                 current(f);
          305                 f->dot.r.p1 = inlong();
          306                 f->dot.r.p2 = inlong();
          307                 f->tdot = f->dot.r;
          308                 journaln(0, i);
          309                 journaln(0, f->dot.r.p1);
          310                 journaln(0, f->dot.r.p2);
          311                 break;
          312 
          313         case Ttype:
          314                 f = whichfile(inshort());
          315                 p0 = inlong();
          316                 journaln(0, p0);
          317                 journal(0, (char*)inp);
          318                 str = tmpcstr((char*)inp);
          319                 i = str->n;
          320                 loginsert(f, p0, str->s, str->n);
          321                 if(fileupdate(f, FALSE, FALSE))
          322                         seq++;
          323                 if(f==cmd && p0==f->b.nc-i && i>0 && str->s[i-1]=='\n'){
          324                         freetmpstr(str);
          325                         termlocked++;
          326                         termcommand();
          327                 }else
          328                         freetmpstr(str);
          329                 f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this already */
          330                 f->tdot = f->dot.r;
          331                 break;
          332 
          333         case Tcut:
          334                 f = whichfile(inshort());
          335                 p0 = inlong();
          336                 p1 = inlong();
          337                 journaln(0, p0);
          338                 journaln(0, p1);
          339                 logdelete(f, p0, p1);
          340                 if(fileupdate(f, FALSE, FALSE))
          341                         seq++;
          342                 f->dot.r.p1 = f->dot.r.p2 = p0;
          343                 f->tdot = f->dot.r;   /* terminal knows the value of dot already */
          344                 break;
          345 
          346         case Tpaste:
          347                 f = whichfile(inshort());
          348                 p0 = inlong();
          349                 journaln(0, p0);
          350                 for(l=0; l<snarfbuf.nc; l+=m){
          351                         m = snarfbuf.nc-l;
          352                         if(m>BLOCKSIZE)
          353                                 m = BLOCKSIZE;
          354                         bufread(&snarfbuf, l, genbuf, m);
          355                         loginsert(f, p0, tmprstr(genbuf, m)->s, m);
          356                 }
          357                 if(fileupdate(f, FALSE, TRUE))
          358                         seq++;
          359                 f->dot.r.p1 = p0;
          360                 f->dot.r.p2 = p0+snarfbuf.nc;
          361                 f->tdot.p1 = -1; /* force telldot to tell (arguably a BUG) */
          362                 telldot(f);
          363                 outTs(Hunlockfile, f->tag);
          364                 break;
          365 
          366         case Tsnarf:
          367                 i = inshort();
          368                 p0 = inlong();
          369                 p1 = inlong();
          370                 snarf(whichfile(i), p0, p1, &snarfbuf, 0);
          371                 break;
          372 
          373         case Tstartnewfile:
          374                 v = invlong();
          375                 Strdupl(&genstr, empty);
          376                 f = newfile();
          377                 f->rasp = listalloc('P');
          378                 outTsv(Hbindname, f->tag, v);
          379                 logsetname(f, &genstr);
          380                 outTs(Hcurrent, f->tag);
          381                 current(f);
          382                 load(f);
          383                 break;
          384 
          385         case Twrite:
          386                 termlocked++;
          387                 i = inshort();
          388                 journaln(0, i);
          389                 f = whichfile(i);
          390                 addr.r.p1 = 0;
          391                 addr.r.p2 = f->b.nc;
          392                 if(f->name.s[0] == 0)
          393                         error(Enoname);
          394                 Strduplstr(&genstr, &f->name);
          395                 writef(f);
          396                 break;
          397 
          398         case Tclose:
          399                 termlocked++;
          400                 i = inshort();
          401                 journaln(0, i);
          402                 f = whichfile(i);
          403                 current(f);
          404                 trytoclose(f);
          405                 /* if trytoclose fails, will error out */
          406                 delete(f);
          407                 break;
          408 
          409         case Tlook:
          410                 f = whichfile(inshort());
          411                 termlocked++;
          412                 p0 = inlong();
          413                 p1 = inlong();
          414                 journaln(0, p0);
          415                 journaln(0, p1);
          416                 setgenstr(f, p0, p1);
          417                 for(l = 0; l<genstr.n; l++){
          418                         i = genstr.s[l];
          419                         if(utfrune(".*+?(|)\\[]^$", i)){
          420                                 str = tmpcstr("\\");
          421                                 Strinsert(&genstr, str, l++);
          422                                 freetmpstr(str);
          423                         }
          424                 }
          425                 Straddc(&genstr, '\0');
          426                 nextmatch(f, &genstr, p1, 1);
          427                 moveto(f, sel.p[0]);
          428                 break;
          429 
          430         case Tsearch:
          431                 termlocked++;
          432                 if(curfile == 0)
          433                         error(Enofile);
          434                 if(lastpat.s[0] == 0)
          435                         panic("Tsearch");
          436                 nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);
          437                 moveto(curfile, sel.p[0]);
          438                 break;
          439 
          440         case Tsend:
          441                 termlocked++;
          442                 inshort();        /* ignored */
          443                 p0 = inlong();
          444                 p1 = inlong();
          445                 setgenstr(cmd, p0, p1);
          446                 bufreset(&snarfbuf);
          447                 bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n);
          448                 outTl(Hsnarflen, genstr.n);
          449                 if(genstr.s[genstr.n-1] != '\n')
          450                         Straddc(&genstr, '\n');
          451                 loginsert(cmd, cmd->b.nc, genstr.s, genstr.n);
          452                 fileupdate(cmd, FALSE, TRUE);
          453                 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;
          454                 telldot(cmd);
          455                 termcommand();
          456                 break;
          457 
          458         case Tdclick:
          459                 f = whichfile(inshort());
          460                 p1 = inlong();
          461                 doubleclick(f, p1);
          462                 f->tdot.p1 = f->tdot.p2 = p1;
          463                 telldot(f);
          464                 outTs(Hunlockfile, f->tag);
          465                 break;
          466 
          467         case Tstartsnarf:
          468                 if (snarfbuf.nc <= 0) {        /* nothing to export */
          469                         outTs(Hsetsnarf, 0);
          470                         break;
          471                 }
          472                 c = 0;
          473                 i = 0;
          474                 m = snarfbuf.nc;
          475                 if(m > SNARFSIZE) {
          476                         m = SNARFSIZE;
          477                         dprint("?warning: snarf buffer truncated\n");
          478                 }
          479                 rp = malloc(m*sizeof(Rune));
          480                 if(rp){
          481                         bufread(&snarfbuf, 0, rp, m);
          482                         c = Strtoc(tmprstr(rp, m));
          483                         free(rp);
          484                         i = strlen(c);
          485                 }
          486                 outTs(Hsetsnarf, i);
          487                 if(c){
          488                         Write(1, c, i);
          489                         free(c);
          490                 } else
          491                         dprint("snarf buffer too long\n");
          492                 break;
          493 
          494         case Tsetsnarf:
          495                 m = inshort();
          496                 if(m > SNARFSIZE)
          497                         error(Etoolong);
          498                 c = malloc(m+1);
          499                 if(c){
          500                         for(i=0; i<m; i++)
          501                                 c[i] = rcvchar();
          502                         c[m] = 0;
          503                         str = tmpcstr(c);
          504                         free(c);
          505                         bufreset(&snarfbuf);
          506                         bufinsert(&snarfbuf, (Posn)0, str->s, str->n);
          507                         freetmpstr(str);
          508                         outT0(Hunlock);
          509                 }
          510                 break;
          511 
          512         case Tack:
          513                 waitack = 0;
          514                 break;
          515 #if 0
          516         case Tplumb:
          517                 f = whichfile(inshort());
          518                 p0 = inlong();
          519                 p1 = inlong();
          520                 pm = emalloc(sizeof(Plumbmsg));
          521                 pm->src = strdup("sam");
          522                 pm->dst = 0;
          523                 /* construct current directory */
          524                 c = Strtoc(&f->name);
          525                 if(c[0] == '/')
          526                         pm->wdir = c;
          527                 else{
          528                         wdir = emalloc(1024);
          529                         getwd(wdir, 1024);
          530                         pm->wdir = emalloc(1024);
          531                         snprint(pm->wdir, 1024, "%s/%s", wdir, c);
          532                         cleanname(pm->wdir);
          533                         free(wdir);
          534                         free(c);
          535                 }
          536                 c = strrchr(pm->wdir, '/');
          537                 if(c)
          538                         *c = '\0';
          539                 pm->type = strdup("text");
          540                 if(p1 > p0)
          541                         pm->attr = nil;
          542                 else{
          543                         p = p0;
          544                         while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n')
          545                                 p0--;
          546                         while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n')
          547                                 p1++;
          548                         sprint(cbuf, "click=%ld", p-p0);
          549                         pm->attr = plumbunpackattr(cbuf);
          550                 }
          551                 if(p0==p1 || p1-p0>=BLOCKSIZE){
          552                         plumbfree(pm);
          553                         break;
          554                 }
          555                 setgenstr(f, p0, p1);
          556                 pm->data = Strtoc(&genstr);
          557                 pm->ndata = strlen(pm->data);
          558                 c = plumbpack(pm, &i);
          559                 if(c != 0){
          560                         outTs(Hplumb, i);
          561                         Write(1, c, i);
          562                         free(c);
          563                 }
          564                 plumbfree(pm);
          565                 break;
          566 #endif
          567         case Texit:
          568                 exits(0);
          569         }
          570         return TRUE;
          571 }
          572 
          573 void
          574 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
          575 {
          576         Posn l;
          577         int i;
          578 
          579         if(!emptyok && p1==p2)
          580                 return;
          581         bufreset(buf);
          582         /* Stage through genbuf to avoid compaction problems (vestigial) */
          583         if(p2 > f->b.nc){
          584                 fprint(2, "bad snarf addr p1=%ld p2=%ld f->b.nc=%d\n", p1, p2, f->b.nc); /*ZZZ should never happen, can remove */
          585                 p2 = f->b.nc;
          586         }
          587         for(l=p1; l<p2; l+=i){
          588                 i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;
          589                 bufread(&f->b, l, genbuf, i);
          590                 bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i);
          591         }
          592 }
          593 
          594 int
          595 inshort(void)
          596 {
          597         ushort n;
          598 
          599         n = inp[0] | (inp[1]<<8);
          600         inp += 2;
          601         return n;
          602 }
          603 
          604 long
          605 inlong(void)
          606 {
          607         ulong n;
          608 
          609         n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
          610         inp += 4;
          611         return n;
          612 }
          613 
          614 vlong
          615 invlong(void)
          616 {
          617         vlong v;
          618         
          619         v = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];
          620         v = (v<<16) | (inp[3]<<8) | inp[2];
          621         v = (v<<16) | (inp[1]<<8) | inp[0];
          622         inp += 8;
          623         return v;
          624 }
          625 
          626 void
          627 setgenstr(File *f, Posn p0, Posn p1)
          628 {
          629         if(p0 != p1){
          630                 if(p1-p0 >= TBLOCKSIZE)
          631                         error(Etoolong);
          632                 Strinsure(&genstr, p1-p0);
          633                 bufread(&f->b, p0, genbuf, p1-p0);
          634                 memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));
          635                 genstr.n = p1-p0;
          636         }else{
          637                 if(snarfbuf.nc == 0)
          638                         error(Eempty);
          639                 if(snarfbuf.nc > TBLOCKSIZE)
          640                         error(Etoolong);
          641                 bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc);
          642                 Strinsure(&genstr, snarfbuf.nc);
          643                 memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc);
          644                 genstr.n = snarfbuf.nc;
          645         }
          646 }
          647 
          648 void
          649 outT0(Hmesg type)
          650 {
          651         outstart(type);
          652         outsend();
          653 }
          654 
          655 void
          656 outTl(Hmesg type, long l)
          657 {
          658         outstart(type);
          659         outlong(l);
          660         outsend();
          661 }
          662 
          663 void
          664 outTs(Hmesg type, int s)
          665 {
          666         outstart(type);
          667         journaln(1, s);
          668         outshort(s);
          669         outsend();
          670 }
          671 
          672 void
          673 outS(String *s)
          674 {
          675         char *c;
          676         int i;
          677 
          678         c = Strtoc(s);
          679         i = strlen(c);
          680         outcopy(i, c);
          681         if(i > 99)
          682                 c[99] = 0;
          683         journaln(1, i);
          684         journal(1, c);
          685         free(c);
          686 }
          687 
          688 void
          689 outTsS(Hmesg type, int s1, String *s)
          690 {
          691         outstart(type);
          692         outshort(s1);
          693         outS(s);
          694         outsend();
          695 }
          696 
          697 void
          698 outTslS(Hmesg type, int s1, Posn l1, String *s)
          699 {
          700         outstart(type);
          701         outshort(s1);
          702         journaln(1, s1);
          703         outlong(l1);
          704         journaln(1, l1);
          705         outS(s);
          706         outsend();
          707 }
          708 
          709 void
          710 outTS(Hmesg type, String *s)
          711 {
          712         outstart(type);
          713         outS(s);
          714         outsend();
          715 }
          716 
          717 void
          718 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
          719 {
          720         outstart(type);
          721         outshort(s1);
          722         outlong(l1);
          723         outlong(l2);
          724         journaln(1, l1);
          725         journaln(1, l2);
          726         outS(s);
          727         outsend();
          728 }
          729 
          730 void
          731 outTsll(Hmesg type, int s, Posn l1, Posn l2)
          732 {
          733         outstart(type);
          734         outshort(s);
          735         outlong(l1);
          736         outlong(l2);
          737         journaln(1, l1);
          738         journaln(1, l2);
          739         outsend();
          740 }
          741 
          742 void
          743 outTsl(Hmesg type, int s, Posn l)
          744 {
          745         outstart(type);
          746         outshort(s);
          747         outlong(l);
          748         journaln(1, l);
          749         outsend();
          750 }
          751 
          752 void
          753 outTsv(Hmesg type, int s, vlong v)
          754 {
          755         outstart(type);
          756         outshort(s);
          757         outvlong(v);
          758         journaln(1, v);
          759         outsend();
          760 }
          761 
          762 void
          763 outstart(Hmesg type)
          764 {
          765         journal(1, hname[type]);
          766         outmsg[0] = type;
          767         outp = outmsg+3;
          768 }
          769 
          770 void
          771 outcopy(int count, void *data)
          772 {
          773         memmove(outp, data, count);
          774         outp += count;
          775 }
          776 
          777 void
          778 outshort(int s)
          779 {
          780         *outp++ = s;
          781         *outp++ = s>>8; 
          782 }
          783 
          784 void
          785 outlong(long l)
          786 {
          787         *outp++ = l;
          788         *outp++ = l>>8;
          789         *outp++ = l>>16;
          790         *outp++ = l>>24;
          791 }
          792 
          793 void
          794 outvlong(vlong v)
          795 {
          796         int i;
          797 
          798         for(i = 0; i < 8; i++){
          799                 *outp++ = v;
          800                 v >>= 8;
          801         }
          802 }
          803 
          804 void
          805 outsend(void)
          806 {
          807         int outcount;
          808 
          809         if(outp >= outdata+nelem(outdata))
          810                 panic("outsend");
          811         outcount = outp-outmsg;
          812         outcount -= 3;
          813         outmsg[1] = outcount;
          814         outmsg[2] = outcount>>8;
          815         outmsg = outp;
          816         if(!outbuffered){
          817                 outcount = outmsg-outdata;
          818                 if (write(1, (char*) outdata, outcount) != outcount)
          819                         rescue();
          820                 outmsg = outdata;
          821                 return;
          822         }
          823 }
          824 
          825 int
          826 needoutflush(void)
          827 {
          828         return outmsg >= outdata+DATASIZE;
          829 }
          830 
          831 void
          832 outflush(void)
          833 {
          834         if(outmsg == outdata)
          835                 return;
          836         outbuffered = 0;
          837         /* flow control */
          838         outT0(Hack);
          839         waitack = 1;
          840         do
          841                 if(rcv() == 0){
          842                         rescue();
          843                         exits("eof");
          844                 }
          845         while(waitack);
          846         outmsg = outdata;
          847         outbuffered = 1;
          848 }