Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/acme/bin/source/win/main.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <thread.h>
5
#include <fcall.h>
6
#include <9p.h>
7
#include <ctype.h>
8
#include "dat.h"
9
 
10
void	mainctl(void*);
11
void	startcmd(char *[], int*);
12
void	stdout2body(void*);
13
 
14
int	debug;
15
int	notepg;
16
int	eraseinput;
17
int	dirty = 0;
18
 
19
Window *win;		/* the main window */
20
 
21
void
22
usage(void)
23
{
24
	fprint(2, "usage: win [command]\n");
25
	threadexitsall("usage");
26
}
27
 
28
void
29
threadmain(int argc, char *argv[])
30
{
31
	int i, j;
32
	char *dir, *tag, *name;
33
	char buf[1024], **av;
34
 
35
	quotefmtinstall();
36
	rfork(RFNAMEG);
37
	ARGBEGIN{
38
	case 'd':
39
		debug = 1;
40
		chatty9p++;
41
		break;
42
	case 'e':
43
		eraseinput = 1;
44
		break;
45
	case 'D':
46
{extern int _threaddebuglevel;
47
		_threaddebuglevel = 1<<20;
48
}
49
	}ARGEND
50
 
51
	if(argc == 0){
52
		av = emalloc(3*sizeof(char*));
53
		av[0] = "rc";
54
		av[1] = "-i";
55
		name = getenv("sysname");
56
	}else{
57
		av = argv;
58
		name = utfrrune(av[0], '/');
59
		if(name)
60
			name++;
61
		else
62
			name = av[0];
63
	}
64
 
65
	if(getwd(buf, sizeof buf) == 0)
66
		dir = "/";
67
	else
68
		dir = buf;
69
	dir = estrdup(dir);
70
	tag = estrdup(dir);
71
	tag = eappend(estrdup(tag), "/-", name);
72
	win = newwindow();
73
	snprint(buf, sizeof buf, "%d", win->id);
74
	putenv("winid", buf);
75
	winname(win, tag);
76
	wintagwrite(win, "Send Noscroll", 5+8);
77
	threadcreate(mainctl, win, STACK);
78
	mountcons();
79
	threadcreate(fsloop, nil, STACK);
80
	startpipe();
81
	startcmd(av, &notepg);
82
 
83
	strcpy(buf, "win");
84
	j = 3;
85
	for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){
86
		strcpy(buf+j, " ");
87
		strcpy(buf+j+1, argv[i]);
88
		j += 1+strlen(argv[i]);
89
	}
90
 
91
	ctlprint(win->ctl, "scroll");
92
	winsetdump(win, dir, buf);
93
}
94
 
95
int
96
EQUAL(char *s, char *t)
97
{
98
	while(tolower(*s) == tolower(*t++))
99
		if(*s++ == '\0')
100
			return 1;
101
	return 0;
102
}
103
 
104
int
105
command(Window *w, char *s)
106
{
107
	while(*s==' ' || *s=='\t' || *s=='\n')
108
		s++;
109
	if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){
110
		write(notepg, "hangup", 6);
111
		windel(w, 1);
112
		threadexitsall(nil);
113
		return 1;
114
	}
115
	if(EQUAL(s, "scroll")){
116
		ctlprint(w->ctl, "scroll\nshow");
117
		return 1;
118
	}
119
	if(EQUAL(s, "noscroll")){
120
		ctlprint(w->ctl, "noscroll");
121
		return 1;
122
	}
123
	return 0;
124
}
125
 
126
static long
127
utfncpy(char *to, char *from, int n)
128
{
129
	char *end, *e;
130
 
131
	e = to+n;
132
	if(to >= e)
133
		return 0;
134
	end = memccpy(to, from, '\0', e - to);
135
	if(end == nil){
136
		end = e;
137
		if(end[-1]&0x80){
138
			if(end-2>=to && (end[-2]&0xE0)==0xC0)
139
				return end-to;
140
			if(end-3>=to && (end[-3]&0xF0)==0xE0)
141
				return end-to;
142
			while(end>to && (*--end&0xC0)==0x80)
143
				;
144
		}
145
	}else
146
		end--;
147
	return end - to;
148
}
149
 
150
/* sendinput and fsloop run in the same proc (can't interrupt each other). */
151
static Req *q;
152
static Req **eq;
153
static int
154
__sendinput(Window *w, ulong q0, ulong q1)
155
{
156
	char *s, *t;
157
	int n, nb, eofchar;
158
	static int partial;
159
	static char tmp[UTFmax];
160
	Req *r;
161
	Rune rune;
162
 
163
	if(!q)
164
		return 0;
165
 
166
	r = q;
167
	n = 0;
168
	if(partial){
169
	Partial:
170
		nb = partial;
171
		if(nb > r->ifcall.count)
172
			nb = r->ifcall.count;
173
		memmove(r->ofcall.data, tmp, nb);
174
		if(nb!=partial)
175
			memmove(tmp, tmp+nb, partial-nb);
176
		partial -= nb;
177
		q = r->aux;
178
		if(q == nil)
179
			eq = &q;
180
		r->aux = nil;
181
		r->ofcall.count = nb;
182
		if(debug)
183
			fprint(2, "satisfy read with partial\n");
184
		respond(r, nil);
185
		return n;
186
	}
187
	if(q0==q1)
188
		return 0;
189
	s = emalloc((q1-q0)*UTFmax+1);
190
	n = winread(w, q0, q1, s);
191
	s[n] = '\0';
192
	t = strpbrk(s, "\n\004");
193
	if(t == nil){
194
		free(s);
195
		return 0;
196
	}
197
	r = q;
198
	eofchar = 0;
199
	if(*t == '\004'){
200
		eofchar = 1;
201
		*t = '\0';
202
	}else
203
		*++t = '\0';
204
	nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count);
205
	if(nb==0 && s<t && r->ifcall.count > 0){
206
		partial = utfncpy(tmp, s, UTFmax);
207
		assert(partial > 0);
208
		chartorune(&rune, tmp);
209
		partial = runelen(rune);
210
		free(s);
211
		n = 1;
212
		goto Partial;
213
	}
214
	n = utfnlen(r->ofcall.data, nb);
215
	if(nb==strlen(s) && eofchar)
216
		n++;
217
	r->ofcall.count = nb;
218
	q = r->aux;
219
	if(q == nil)
220
		eq = &q;
221
	r->aux = nil;
222
	if(debug)
223
		fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data);
224
	respond(r, nil);
225
	return n;
226
}
227
 
228
static int
229
_sendinput(Window *w, ulong q0, ulong *q1)
230
{
231
	char buf[32];
232
	int n;
233
 
234
	n = __sendinput(w, q0, *q1);
235
	if(!n || !eraseinput)
236
		return n;
237
	/* erase q0 to q0+n */
238
	sprint(buf, "#%lud,#%lud", q0, q0+n);
239
	winsetaddr(w, buf, 0);
240
	write(w->data, buf, 0);
241
	*q1 -= n;
242
	return 0;
243
}
244
 
245
int
246
sendinput(Window *w, ulong q0, ulong *q1)
247
{
248
	ulong n;
249
	Req *oq;
250
 
251
	n = 0;
252
	do {
253
		oq = q;
254
		n += _sendinput(w, q0+n, q1);
255
	} while(q != oq);
256
	return n;
257
}
258
 
259
Event esendinput;
260
void
261
fsloop(void*)
262
{
263
	Fsevent e;
264
	Req **l, *r;
265
 
266
	eq = &q;
267
	memset(&esendinput, 0, sizeof esendinput);
268
	esendinput.c1 = 'C';
269
	for(;;){
270
		while(recv(fschan, &e) == -1)
271
			;
272
		r = e.r;
273
		switch(e.type){
274
		case 'r':
275
			*eq = r;
276
			r->aux = nil;
277
			eq = &r->aux;
278
			/* call sendinput with hostpt and endpt */
279
			sendp(win->cevent, &esendinput);
280
			break;
281
		case 'f':
282
			for(l=&q; *l; l=&(*l)->aux){
283
				if(*l == r->oldreq){
284
					*l = (*l)->aux;
285
					if(*l == nil)
286
						eq = l;
287
					respond(r->oldreq, "interrupted");
288
					break;
289
				}
290
			}
291
			respond(r, nil);
292
			break;
293
		}
294
	}
295
}	
296
 
297
void
298
sendit(char *s)
299
{
300
//	char tmp[32];
301
 
302
	write(win->body, s, strlen(s));
303
/*
304
 * RSC: The problem here is that other procs can call sendit,
305
 * so we lose our single-threadedness if we call sendinput.
306
 * In fact, we don't even have the right queue memory,
307
 * I think that we'll get a write event from the body write above,
308
 * and we can do the sendinput then, from our single thread.
309
 *
310
 * I still need to figure out how to test this assertion for
311
 * programs that use /srv/win*
312
 *
313
	winselect(win, "$", 0);
314
	seek(win->addr, 0UL, 0);
315
	if(read(win->addr, tmp, 2*12) == 2*12)
316
		hostpt += sendinput(win, hostpt, atol(tmp), );
317
 */
318
}
319
 
320
void
321
execevent(Window *w, Event *e, int (*command)(Window*, char*))
322
{
323
	Event *ea, *e2;
324
	int n, na, len, needfree;
325
	char *s, *t;
326
 
327
	ea = nil;
328
	e2 = nil;
329
	if(e->flag & 2)
330
		e2 = recvp(w->cevent);
331
	if(e->flag & 8){
332
		ea = recvp(w->cevent);
333
		na = ea->nb;
334
		recvp(w->cevent);
335
	}else
336
		na = 0;
337
 
338
	needfree = 0;
339
	s = e->b;
340
	if(e->nb==0 && (e->flag&2)){
341
		s = e2->b;
342
		e->q0 = e2->q0;
343
		e->q1 = e2->q1;
344
		e->nb = e2->nb;
345
	}
346
	if(e->nb==0 && e->q0<e->q1){
347
		/* fetch data from window */
348
		s = emalloc((e->q1-e->q0)*UTFmax+2);
349
		n = winread(w, e->q0, e->q1, s);
350
		s[n] = '\0';
351
		needfree = 1;
352
	}else 
353
	if(na){
354
		t = emalloc(strlen(s)+1+na+2);
355
		sprint(t, "%s %s", s, ea->b);
356
		if(needfree)
357
			free(s);
358
		s = t;
359
		needfree = 1;
360
	}
361
 
362
	/* if it's a known command, do it */
363
	/* if it's a long message, it can't be for us anyway */
364
	if(!command(w, s) && s[0]!='\0'){	/* send it as typed text */
365
		/* if it's a built-in from the tag, send it back */
366
		if(e->flag & 1)
367
			fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
368
		else{	/* send text to main window */
369
			len = strlen(s);
370
			if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){
371
				if(!needfree){
372
					/* if(needfree), we left room for a newline before */
373
					t = emalloc(len+2);
374
					strcpy(t, s);
375
					s = t;
376
					needfree = 1;
377
				}
378
				s[len++] = '\n';
379
				s[len] = '\0';
380
			}
381
			sendit(s);
382
		}
383
	}
384
	if(needfree)
385
		free(s);
386
}
387
 
388
int
389
hasboundary(Rune *r, int nr)
390
{
391
	int i;
392
 
393
	for(i=0; i<nr; i++)
394
		if(r[i]=='\n' || r[i]=='\004')
395
			return 1;
396
	return 0;
397
}
398
 
399
void
400
mainctl(void *v)
401
{
402
	Window *w;
403
	Event *e;
404
	int delta, pendingS, pendingK;
405
	ulong hostpt, endpt;
406
	char tmp[32];
407
 
408
	w = v;
409
	proccreate(wineventproc, w, STACK);
410
 
411
	hostpt = 0;
412
	endpt = 0;
413
	winsetaddr(w, "0", 0);
414
	pendingS = 0;
415
	pendingK = 0;
416
	for(;;){
417
		if(debug)
418
			fprint(2, "input range %lud-%lud\n", hostpt, endpt);
419
		e = recvp(w->cevent);
420
		if(debug)
421
			fprint(2, "msg: %C %C %d %d %d %d %q\n",
422
				e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b);
423
		switch(e->c1){
424
		default:
425
		Unknown:
426
			fprint(2, "unknown message %c%c\n", e->c1, e->c2);
427
			break;
428
 
429
		case 'C':	/* input needed for /dev/cons */
430
			if(pendingS)
431
				pendingK = 1;
432
			else
433
				hostpt += sendinput(w, hostpt, &endpt);
434
			break;
435
 
436
		case 'S':	/* output to stdout */
437
			sprint(tmp, "#%lud", hostpt);
438
			winsetaddr(w, tmp, 0);
439
			write(w->data, e->b, e->nb);
440
			pendingS += e->nr;
441
			break;
442
 
443
		case 'E':	/* write to tag or body; body happens due to sendit */
444
			delta = e->q1-e->q0;
445
			if(e->c2=='I'){
446
				endpt += delta;
447
				if(e->q0 < hostpt)
448
					hostpt += delta;
449
				else
450
					hostpt += sendinput(w, hostpt, &endpt);
451
				break;
452
			}
453
			if(!islower(e->c2))
454
				fprint(2, "win msg: %C %C %d %d %d %d %q\n",
455
					e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
456
			break;
457
 
458
		case 'F':	/* generated by our actions (specifically case 'S' above) */
459
			delta = e->q1-e->q0;
460
			if(e->c2=='D'){
461
				/* we know about the delete by _sendinput */
462
				break;
463
			}
464
			if(e->c2=='I'){
465
				pendingS -= e->q1 - e->q0;
466
				if(pendingS < 0)
467
					fprint(2, "win: pendingS = %d\n", pendingS);
468
				if(e->q0 != hostpt)
469
					fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt);
470
				endpt += delta;
471
				hostpt += delta;
472
				sendp(writechan, nil);
473
				if(pendingS == 0 && pendingK){
474
					pendingK = 0;
475
					hostpt += sendinput(w, hostpt, &endpt);
476
				}
477
				break;
478
			}
479
			if(!islower(e->c2))
480
				fprint(2, "win msg: %C %C %d %d %d %d %q\n",
481
					e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
482
			break;
483
 
484
		case 'K':
485
			delta = e->q1-e->q0;
486
			switch(e->c2){
487
			case 'D':
488
				endpt -= delta;
489
				if(e->q1 < hostpt)
490
					hostpt -= delta;
491
				else if(e->q0 < hostpt)
492
					hostpt = e->q0;
493
				break;
494
			case 'I':
495
				delta = e->q1 - e->q0;
496
				endpt += delta;
497
				if(endpt < e->q1)	/* just in case */
498
					endpt = e->q1;
499
				if(e->q0 < hostpt)
500
					hostpt += delta;
501
				if(e->nr>0 && e->r[e->nr-1]==0x7F){
502
					write(notepg, "interrupt", 9);
503
					hostpt = endpt;
504
					break;
505
				}
506
				if(e->q0 >= hostpt
507
				&& hasboundary(e->r, e->nr)){
508
					/*
509
					 * If we are between the S message (which
510
					 * we processed by inserting text in the
511
					 * window) and the F message notifying us
512
					 * that the text has been inserted, then our
513
					 * impression of the hostpt and acme's
514
					 * may be different.  This could be seen if you
515
					 * hit enter a bunch of times in a con
516
					 * session.  To work around the unreliability,
517
					 * only send input if we don't have an S pending.
518
					 * The same race occurs between when a character
519
					 * is typed and when we get notice of it, but
520
					 * since characters tend to be typed at the end
521
					 * of the buffer, we don't run into it.  There's
522
					 * no workaround possible for this typing race,
523
					 * since we can't tell when the user has typed
524
					 * something but we just haven't been notified.
525
					 */
526
					if(pendingS)
527
						pendingK = 1;
528
					else
529
						hostpt += sendinput(w, hostpt, &endpt);
530
				}
531
				break;
532
			}
533
			break;
534
 
535
		case 'M':	/* mouse */
536
			delta = e->q1-e->q0;
537
			switch(e->c2){
538
			case 'x':
539
			case 'X':
540
				execevent(w, e, command);
541
				break;
542
 
543
			case 'l':	/* reflect all searches back to acme */
544
			case 'L':
545
				if(e->flag & 2)
546
					recvp(w->cevent);
547
				winwriteevent(w, e);
548
				break;
549
 
550
			case 'I':
551
				endpt += delta;
552
				if(e->q0 < hostpt)
553
					hostpt += delta;
554
				else
555
					hostpt += sendinput(w, hostpt, &endpt);
556
				break;
557
 
558
			case 'D':
559
				endpt -= delta;
560
				if(e->q1 < hostpt)
561
					hostpt -= delta;
562
				else if(e->q0 < hostpt)
563
					hostpt = e->q0;
564
				break;
565
			case 'd':	/* modify away; we don't care */
566
			case 'i':
567
				break;
568
 
569
			default:
570
				goto Unknown;
571
			}
572
		}
573
	}
574
}
575
 
576
enum
577
{
578
	NARGS		= 100,
579
	NARGCHAR	= 8*1024,
580
	EXECSTACK 	= STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
581
};
582
 
583
struct Exec
584
{
585
	char		**argv;
586
	Channel	*cpid;
587
};
588
 
589
int
590
lookinbin(char *s)
591
{
592
	if(s[0] == '/')
593
		return 0;
594
	if(s[0]=='.' && s[1]=='/')
595
		return 0;
596
	if(s[0]=='.' && s[1]=='.' && s[2]=='/')
597
		return 0;
598
	return 1;
599
}
600
 
601
/* adapted from mail.  not entirely free of details from that environment */
602
void
603
execproc(void *v)
604
{
605
	struct Exec *e;
606
	char *cmd, **av;
607
	Channel *cpid;
608
 
609
	e = v;
610
	rfork(RFCFDG|RFNOTEG);
611
	av = e->argv;
612
	close(0);
613
	open("/dev/cons", OREAD);
614
	close(1);
615
	open("/dev/cons", OWRITE);
616
	dup(1, 2);
617
	cpid = e->cpid;
618
	free(e);
619
	procexec(cpid, av[0], av);
620
	if(lookinbin(av[0])){
621
		cmd = estrstrdup("/bin/", av[0]);
622
		procexec(cpid, cmd, av);
623
	}
624
	error("can't exec %s: %r", av[0]);
625
}
626
 
627
void
628
startcmd(char *argv[], int *notepg)
629
{
630
	struct Exec *e;
631
	Channel *cpid;
632
	char buf[64];
633
	int pid;
634
 
635
	e = emalloc(sizeof(struct Exec));
636
	e->argv = argv;
637
	cpid = chancreate(sizeof(ulong), 0);
638
	e->cpid = cpid;
639
	sprint(buf, "/mnt/wsys/%d", win->id);
640
	bind(buf, "/dev/acme", MREPL);
641
	proccreate(execproc, e, EXECSTACK);
642
	do
643
		pid = recvul(cpid);
644
	while(pid == -1);
645
	sprint(buf, "/proc/%d/notepg", pid);
646
	*notepg = open(buf, OWRITE);
647
}