9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | 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 }