Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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 *
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
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
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
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
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
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
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
650
outT0(Hmesg type)
651
{
652
	outstart(type);
653
	outsend();
654
}
655
 
656
void
657
outTl(Hmesg type, long l)
658
{
659
	outstart(type);
660
	outlong(l);
661
	outsend();
662
}
663
 
664
void
665
outTs(Hmesg type, int s)
666
{
667
	outstart(type);
668
	journaln(1, s);
669
	outshort(s);
670
	outsend();
671
}
672
 
673
void
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
690
outTsS(Hmesg type, int s1, String *s)
691
{
692
	outstart(type);
693
	outshort(s1);
694
	outS(s);
695
	outsend();
696
}
697
 
698
void
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
711
outTS(Hmesg type, String *s)
712
{
713
	outstart(type);
714
	outS(s);
715
	outsend();
716
}
717
 
718
void
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
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
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
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
764
outstart(Hmesg type)
765
{
766
	journal(1, hname[type]);
767
	outmsg[0] = type;
768
	outp = outmsg+3;
769
}
770
 
771
void
772
outcopy(int count, void *data)
773
{
774
	memmove(outp, data, count);
775
	outp += count;
776
}
777
 
778
void
779
outshort(int s)
780
{
781
	*outp++ = s;
782
	*outp++ = s>>8; 
783
}
784
 
785
void
786
outlong(long l)
787
{
788
	*outp++ = l;
789
	*outp++ = l>>8;
790
	*outp++ = l>>16;
791
	*outp++ = l>>24;
792
}
793
 
794
void
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
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
827
needoutflush(void)
828
{
829
	return outmsg >= outdata+DATASIZE;
830
}
831
 
832
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
}