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