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 <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <event.h>
5
#include <bio.h>
6
#include <keyboard.h>
7
#include "cons.h"
8
 
9
enum{
10
	Ehost		= 4,
11
};
12
 
13
char	*menutext2[] = {
14
	"backup",
15
	"forward",
16
	"reset",
17
	"clear",
18
	"send",
19
	"page",
20
 
21
};
22
 
23
char	*menutext3[] = {
24
	"24x80",
25
	"crnl",
26
	"nl",
27
	"raw",
28
	"exit",
29
 
30
};
31
 
32
/* variables associated with the screen */
33
 
34
int	x, y;	/* character positions */
35
char	*backp;
36
int	backc;
37
int	atend;
38
int	nbacklines;
39
int	xmax, ymax;
40
int	blocked;
41
int	resize_flag;
42
int	pagemode;
43
int	olines;
44
int	peekc;
45
int	cursoron = 1;
46
Menu	menu2;
47
Menu	menu3;
48
char	*histp;
49
char	hist[HISTSIZ];
50
int	yscrmin, yscrmax;
51
int	attr, defattr;
52
int	wctlout;
53
 
54
Image	*bordercol;
55
Image	*cursback;
56
Image	*colors[8];
57
Image	*hicolors[8];
58
Image	*red;
59
Image	*fgcolor;
60
Image	*bgcolor;
61
Image	*fgdefault;
62
Image	*bgdefault;
63
 
64
uint rgbacolors[8] = {
65
	0x000000FF,	/* black */
66
	0xAA0000FF,	/* red */
67
	0x00AA00FF,	/* green */
68
	0xFF5500FF,	/* brown */
69
	0x0000FFFF,	/* blue */
70
	0xAA00AAFF,	/* purple */
71
	0x00AAAAFF,	/* cyan */
72
	0x7F7F7FFF,	/* white */
73
};
74
 
75
ulong rgbahicolors[8] = {
76
	0x555555FF,	/* light black aka grey */
77
	0xFF5555FF,	/* light red */
78
	0x55FF55FF,	/* light green */
79
	0xFFFF55FF,	/* light brown aka yellow */
80
	0x5555FFFF,	/* light blue */
81
	0xFF55FFFF,	/* light purple */
82
	0x55FFFFFF,	/* light cyan */
83
	0xFFFFFFFF,	/* light grey aka white */
84
};
85
 
86
/* terminal control */
87
struct ttystate ttystate[2] = { {0, 1}, {0, 1} };
88
 
89
int	NS;
90
int	CW;
91
Consstate *cs;
92
Mouse	mouse;
93
 
94
int	debug;
95
int	nocolor;
96
int	logfd = -1;
97
int	outfd = -1;
98
Biobuf	*snarffp = 0;
99
 
100
char	*host_buf;
101
char	*hostp;				/* input from host */
102
int	host_bsize = 2*BSIZE;
103
int	hostlength;			/* amount of input from host */
104
char	echo_input[BSIZE];
105
char	*echop = echo_input;		/* characters to echo, after canon */
106
char	sendbuf[BSIZE];	/* hope you can't type ahead more than BSIZE chars */
107
char	*sendp = sendbuf;
108
 
109
char *term;
110
struct funckey *fk;
111
 
112
/* functions */
113
void	initialize(int, char **);
114
void	ebegin(int);
115
int	waitchar(void);
116
int	rcvchar(void);
117
void	set_input(char *);
118
void	set_host(Event *);
119
void	bigscroll(void);
120
void	readmenu(void);
121
void	eresized(int);
122
void	resize(void);
123
void	send_interrupt(void);
124
int	alnum(int);
125
void	escapedump(int,uchar *,int);
126
 
127
void
128
main(int argc, char **argv)
129
{
130
	initialize(argc, argv);
131
	emulate();
132
}
133
 
134
void
135
usage(void)
136
{
137
	fprint(2, "usage: %s [-2abcx] [-f font] [-l logfile]\n", argv0);
138
	exits("usage");
139
}
140
 
141
void
142
initialize(int argc, char **argv)
143
{
144
	int i, blkbg;
145
	char *fontname, *p;
146
 
147
	rfork(RFNAMEG|RFNOTEG);
148
 
149
	fontname = nil;
150
	term = "vt100";
151
	fk = vt100fk;
152
	blkbg = nocolor = 0;
153
	ARGBEGIN{
154
	case '2':
155
		term = "vt220";
156
		fk = vt220fk;
157
		break;
158
	case 'a':
159
		term = "ansi";
160
		fk = ansifk;
161
		break;
162
	case 'b':
163
		blkbg = 1;		/* e.g., for linux colored output */
164
		break;
165
	case 'c':
166
		nocolor = 1;
167
		break;
168
	case 'f':
169
		fontname = EARGF(usage());
170
		break;
171
	case 'l':
172
		p = EARGF(usage());
173
		logfd = create(p, OWRITE, 0666);
174
		if(logfd < 0)
175
			sysfatal("could not create log file: %s: %r", p);
176
		break;
177
	case 'x':
178
		fk = xtermfk;
179
		term = "xterm";
180
		break;
181
	default:
182
		usage();
183
		break;
184
	}ARGEND;
185
 
186
	host_buf = malloc(host_bsize);
187
	hostp = host_buf;
188
	hostlength = 0;
189
 
190
	if(initdraw(0, fontname, term) < 0){
191
		fprint(2, "%s: initdraw failed: %r\n", term);
192
		exits("initdraw");
193
	}
194
	werrstr("");		/* clear spurious error messages */
195
	ebegin(Ehost);
196
 
197
	histp = hist;
198
	menu2.item = menutext2;
199
	menu3.item = menutext3;
200
	pagemode = 0;
201
	blocked = 0;
202
	NS = font->height;
203
	CW = stringwidth(font, "m");
204
 
205
	red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
206
	bordercol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCCC);
207
	cursback = allocimage(display, Rect(0, 0, CW+1, NS+1), screen->chan, 0, DNofill);
208
 
209
	for(i=0; i<8; i++){
210
		colors[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1,
211
			rgbacolors[i]);
212
		hicolors[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1,
213
			rgbahicolors[i]);
214
	}
215
 
216
	bgdefault = (blkbg? display->black: display->white);
217
	fgdefault = (blkbg? display->white: display->black);
218
	bgcolor = bgdefault;
219
	fgcolor = fgdefault;
220
 
221
	resize();
222
 
223
	if(argc > 0) {
224
		sendnchars(strlen(argv[0]),argv[0]);
225
		sendnchars(1,"\n");
226
	}
227
}
228
 
229
void
230
clear(Rectangle r)
231
{
232
	draw(screen, r, bgcolor, nil, ZP);
233
}
234
 
235
void
236
newline(void)
237
{
238
	nbacklines--;
239
	if(y >= yscrmax) {
240
		y = yscrmax;
241
		if(pagemode && olines >= yscrmax) {
242
			blocked = 1;
243
			return;
244
		}
245
		scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
246
	} else
247
		y++;
248
	olines++;
249
}
250
 
251
void
252
cursoff(void)
253
{
254
	draw(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))), 
255
		cursback, nil, cursback->r.min);
256
}
257
 
258
void
259
curson(int bl)
260
{
261
	Image *col;
262
 
263
	if(!cursoron){
264
		cursoff();
265
		return;
266
	}
267
 
268
	draw(cursback, cursback->r, screen, nil, pt(x, y));
269
	if(bl)
270
		col = red;
271
	else
272
		col = bordercol;
273
	border(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))), 2, col, ZP);
274
}
275
 
276
int
277
get_next_char(void)
278
{
279
	int c = peekc;
280
	uchar buf[1];
281
	peekc = 0;
282
	if(c > 0)
283
		return(c);
284
	while(c <= 0) {
285
		if(backp) {
286
			c = *backp;
287
			if(c && nbacklines >= 0) {
288
				backp++;
289
				if(backp >= &hist[HISTSIZ])
290
					backp = hist;
291
				return(c);
292
			}
293
			backp = 0;
294
		}
295
		c = (uchar)waitchar();
296
		if(c > 0 && logfd >= 0) {
297
			buf[0] = c;
298
			write(logfd, buf, 1);
299
		}
300
	}
301
	*histp++ = c;
302
	if(histp >= &hist[HISTSIZ])
303
		histp = hist;
304
	*histp = '\0';
305
	return(c);
306
}
307
 
308
int
309
canon(char *ep, int c)
310
{
311
	if(c&0200)
312
		return(SCROLL);
313
	switch(c) {
314
		case '\b':
315
			if(sendp > sendbuf)
316
				sendp--;
317
			*ep++ = '\b';
318
			*ep++ = ' ';
319
			*ep++ = '\b';
320
			break;
321
		case 0x15:	/* ^U line kill */
322
			sendp = sendbuf;
323
			*ep++ = '^';
324
			*ep++ = 'U';
325
			*ep++ = '\n';
326
			break;
327
		case 0x17:	/* ^W word kill */
328
			while(sendp > sendbuf && !alnum(*sendp)) {
329
				*ep++ = '\b';
330
				*ep++ = ' ';
331
				*ep++ = '\b';
332
				sendp--;
333
			}
334
			while(sendp > sendbuf && alnum(*sendp)) {
335
				*ep++ = '\b';
336
				*ep++ = ' ';
337
				*ep++ = '\b';
338
				sendp--;
339
			}
340
			break;
341
		case '\177':	/* interrupt */
342
			sendp = sendbuf;
343
			send_interrupt();
344
			return(NEWLINE);
345
		case '\021':	/* quit */
346
		case '\r':
347
		case '\n':
348
			if(sendp < &sendbuf[512])
349
				*sendp++ = '\n';
350
			sendnchars((int)(sendp-sendbuf), sendbuf);
351
			sendp = sendbuf;
352
			if(c == '\n' || c == '\r') {
353
				*ep++ = '\n';
354
			}
355
			*ep = 0;
356
			return(NEWLINE);
357
		case '\004':	/* EOT */
358
			if(sendp == sendbuf) {
359
				sendnchars(0,sendbuf);
360
				*ep = 0;
361
				return(NEWLINE);
362
			}
363
			/* fall through */
364
		default:
365
			if(sendp < &sendbuf[512])
366
				*sendp++ = c;
367
			*ep++ = c;
368
			break;
369
 
370
	}
371
	*ep = 0;
372
	return(OTHER);
373
}
374
 
375
void
376
sendfk(char *name)
377
{
378
	int i;
379
	static int fd;
380
 
381
	for(i=0; fk[i].name; i++)
382
		if(strcmp(name, fk[i].name)==0){
383
			sendnchars2(strlen(fk[i].sequence), fk[i].sequence);
384
			return;
385
		}
386
}
387
 
388
int
389
waitchar(void)
390
{
391
	Event e;
392
	int c;
393
	char c2;
394
	int newmouse;
395
	int wasblocked;
396
	int kbdchar = -1;
397
	char echobuf[3*BSIZE];
398
	static int lastc = -1;
399
 
400
 
401
	for(;;) {
402
		if(resize_flag)
403
			resize();
404
		wasblocked = blocked;
405
		if(backp)
406
			return(0);
407
		if(ecanmouse() && (button2() || button3()))
408
			readmenu();
409
		if(snarffp) {
410
			if((c = Bgetc(snarffp)) < 0) {
411
				if(lastc != '\n')
412
					write(outfd,"\n",1);
413
				Bterm(snarffp);
414
				snarffp = 0;
415
				if(lastc != '\n') {
416
					lastc = -1;
417
					return('\n');
418
				}
419
				lastc = -1;
420
				continue;
421
			}
422
			lastc = c;
423
			c2 = c;
424
			write(outfd, &c2, 1);
425
			return(c);
426
		}
427
		if(!blocked && host_avail())
428
			return(rcvchar());
429
		if(kbdchar > 0) {
430
			if(blocked)
431
				resize();
432
			if(cs->raw) {
433
				switch(kbdchar){
434
				case Kup:
435
					sendfk("up key");
436
					break;
437
				case Kdown:
438
					sendfk("down key");
439
					break;
440
				case Kleft:
441
					sendfk("left key");
442
					break;
443
				case Kright:
444
					sendfk("right key");
445
					break;
446
				case Kpgup:
447
					sendfk("page up");
448
					break;
449
				case Kpgdown:
450
					sendfk("page down");
451
					break;
452
				case KF|1:
453
					sendfk("F1");
454
					break;
455
				case KF|2:
456
					sendfk("F2");
457
					break;
458
				case KF|3:
459
					sendfk("F3");
460
					break;
461
				case KF|4:
462
					sendfk("F4");
463
					break;
464
				case KF|5:
465
					sendfk("F5");
466
					break;
467
				case KF|6:
468
					sendfk("F6");
469
					break;
470
				case KF|7:
471
					sendfk("F7");
472
					break;
473
				case KF|8:
474
					sendfk("F8");
475
					break;
476
				case KF|9:
477
					sendfk("F9");
478
					break;
479
				case KF|10:
480
					sendfk("F10");
481
					break;
482
				case KF|11:
483
					sendfk("F11");
484
					break;
485
				case KF|12:
486
					sendfk("F12");
487
					break;
488
				case '\n':
489
					echobuf[0] = '\r';
490
					sendnchars(1, echobuf);
491
					break;
492
				case '\r':
493
					echobuf[0] = '\n';
494
					sendnchars(1, echobuf);
495
					break;
496
				default:
497
					echobuf[0] = kbdchar;
498
					sendnchars(1, echobuf);
499
					break;
500
				}
501
			} else if(canon(echobuf,kbdchar) == SCROLL) {
502
				if(!blocked)
503
					bigscroll();
504
			} else
505
				strcat(echo_input,echobuf);
506
			blocked = 0;
507
			kbdchar = -1;
508
			continue;
509
		}
510
		curson(wasblocked);	/* turn on cursor while we're waiting */
511
		do {
512
			newmouse = 0;
513
			switch(eread(blocked ? Emouse|Ekeyboard : 
514
					       Emouse|Ekeyboard|Ehost, &e)) {
515
			case Emouse:
516
				mouse = e.mouse;
517
				if(button2() || button3())
518
					readmenu();
519
				else if(resize_flag == 0) {
520
					/* eresized() is triggered by special mouse event */
521
					newmouse = 1;
522
				}
523
				break;
524
			case Ekeyboard:
525
				kbdchar = e.kbdc;
526
				break;
527
			case Ehost:
528
				set_host(&e);
529
				break;
530
			default:
531
				perror("protocol violation");
532
				exits("protocol violation");
533
			}
534
		} while(newmouse == 1);
535
		cursoff();	/* turn cursor back off */
536
	}
537
}
538
 
539
void
540
eresized(int new)
541
{
542
	resize_flag = 1+new;
543
}
544
 
545
void
546
putenvint(char *name, int x)
547
{
548
	char buf[20];
549
 
550
	snprint(buf, sizeof buf, "%d", x);
551
	putenv(name, buf);
552
}
553
 
554
void
555
exportsize(void)
556
{
557
	putenvint("XPIXELS", Dx(screen->r)-2*XMARGIN);
558
	putenvint("YPIXELS", Dy(screen->r)-2*XMARGIN);
559
	putenvint("LINES", ymax+1);
560
	putenvint("COLS", xmax+1);
561
	putenv("TERM", term);
562
}
563
 
564
void
565
resize(void)
566
{
567
	if(resize_flag > 1 && getwindow(display, Refnone) < 0){
568
		fprint(2, "can't reattach to window: %r\n");
569
		exits("can't reattach to window");
570
	}
571
	xmax = (Dx(screen->r)-2*XMARGIN)/CW-1;
572
	ymax = (Dy(screen->r)-2*YMARGIN)/NS-1;
573
	if(xmax == 0 || ymax == 0)
574
		exits("window gone");
575
	x = 0;
576
	y = 0;
577
	yscrmin = 0;
578
	yscrmax = ymax;
579
	olines = 0;
580
	exportsize();
581
	clear(screen->r);
582
	resize_flag = 0;
583
	werrstr("");		/* clear spurious error messages */
584
}
585
 
586
void
587
setdim(int ht, int wid)
588
{
589
	int fd;
590
	Rectangle r;
591
 
592
	if(ht != -1)
593
		ymax = ht-1;
594
	if(wid != -1)
595
		xmax = wid-1;
596
 
597
	r.min = screen->r.min;
598
	r.max = addpt(screen->r.min,
599
			Pt((xmax+1)*CW+2*XMARGIN+2*INSET,
600
				(ymax+1)*NS+2*YMARGIN+2*INSET));
601
	fd = open("/dev/wctl", OWRITE);
602
	if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r)+2*Borderwidth,
603
	    Dy(r)+2*Borderwidth) < 0){
604
		border(screen, r, INSET, bordercol, ZP);
605
		exportsize();
606
	}
607
	if(fd >= 0)
608
		close(fd);
609
}
610
 
611
void
612
readmenu(void)
613
{
614
	if(button3()) {
615
		menu3.item[1] = ttystate[cs->raw].crnl ? "cr" : "crnl";
616
		menu3.item[2] = ttystate[cs->raw].nlcr ? "nl" : "nlcr";
617
		menu3.item[3] = cs->raw ? "cooked" : "raw";
618
 
619
		switch(emenuhit(3, &mouse, &menu3)) {
620
		case 0:		/* 24x80 */
621
			setdim(24, 80);
622
			return;
623
		case 1:		/* newline after cr? */
624
			ttystate[cs->raw].crnl = !ttystate[cs->raw].crnl;
625
			return;
626
		case 2:		/* cr after newline? */
627
			ttystate[cs->raw].nlcr = !ttystate[cs->raw].nlcr;
628
			return;
629
		case 3:		/* switch raw mode */
630
			cs->raw = !cs->raw;
631
			return;
632
		case 4:
633
			exits(0);
634
		}
635
		return;
636
	}
637
 
638
	menu2.item[5] = pagemode? "scroll": "page";
639
 
640
	switch(emenuhit(2, &mouse, &menu2)) {
641
 
642
	case 0:		/* back up */
643
		if(atend == 0) {
644
			backc++;
645
			backup(backc);
646
		}
647
		return;
648
 
649
	case 1:		/* move forward */
650
		backc--;
651
		if(backc >= 0)
652
			backup(backc);
653
		else
654
			backc = 0;
655
		return;
656
 
657
	case 2:		/* reset */
658
		backc = 0;
659
		backup(0);
660
		return;
661
 
662
	case 3:		/* clear screen */
663
		eresized(0);
664
		return;
665
 
666
	case 4:		/* send the snarf buffer */
667
		snarffp = Bopen("/dev/snarf",OREAD);
668
		return;
669
 
670
	case 5:		/* pause and clear at end of screen */
671
		pagemode = 1-pagemode;
672
		if(blocked && !pagemode) {
673
			eresized(0);
674
			blocked = 0;
675
		}
676
		return;
677
	}
678
}
679
 
680
void
681
backup(int count)
682
{
683
	register n;
684
	register char *cp;
685
 
686
	eresized(0);
687
	n = 3*(count+1)*ymax/4;
688
	cp = histp;
689
	atend = 0;
690
	while (n >= 0) {
691
		cp--;
692
		if(cp < hist)
693
			cp = &hist[HISTSIZ-1];
694
		if(*cp == '\0') {
695
			atend = 1;
696
			break;
697
		}
698
		if(*cp == '\n')
699
			n--;
700
	}
701
	cp++;
702
	if(cp >= &hist[HISTSIZ])
703
		cp = hist;
704
	backp = cp;
705
	nbacklines = ymax-2;
706
}
707
 
708
Point
709
pt(int x, int y)
710
{
711
	return addpt(screen->r.min, Pt(x*CW+XMARGIN,y*NS+YMARGIN));
712
}
713
 
714
void
715
scroll(int sy, int ly, int dy, int cy)	/* source, limit, dest, which line to clear */
716
{
717
	draw(screen, Rpt(pt(0, dy), pt(xmax+1, dy+ly-sy)), screen, nil, pt(0, sy));
718
	clear(Rpt(pt(0, cy), pt(xmax+1, cy+1)));
719
	flushimage(display, 1);
720
}
721
 
722
void
723
bigscroll(void)			/* scroll up half a page */
724
{
725
	int half = ymax/3;
726
 
727
	if(x == 0 && y == 0)
728
		return;
729
	if(y < half) {
730
		clear(Rpt(pt(0,0),pt(xmax+1,ymax+1)));
731
		x = y = 0;
732
		return;
733
	}
734
	draw(screen, Rpt(pt(0, 0), pt(xmax+1, ymax+1)), screen, nil, pt(0, half));
735
	clear(Rpt(pt(0,y-half+1),pt(xmax+1,ymax+1)));
736
	y -= half;
737
	if(olines)
738
		olines -= half;
739
	flushimage(display, 1);
740
}
741
 
742
int
743
number(char *p, int *got)
744
{
745
	int c, n = 0;
746
 
747
	if(got)
748
		*got = 0;
749
	while ((c = get_next_char()) >= '0' && c <= '9'){
750
		if(got)
751
			*got = 1;
752
		n = n*10 + c - '0';
753
	}
754
	*p = c;
755
	return(n);
756
}
757
 
758
/* stubs */
759
 
760
void
761
sendnchars(int n,char *p)
762
{
763
	sendnchars2(n, p);
764
	p[n+1] = 0;
765
}
766
 
767
void
768
sendnchars2(int n,char *p)
769
{
770
	if(write(outfd,p,n) < 0) {
771
		close(outfd);
772
		close(0);
773
		close(1);
774
		close(2);
775
		exits("write");
776
	}
777
}
778
 
779
int
780
host_avail(void)
781
{
782
	return(*echop || ((hostp - host_buf) < hostlength));
783
}
784
 
785
int
786
rcvchar(void)
787
{
788
	int c;
789
	if(*echop) {
790
		c = *echop++;
791
		if(!*echop) {
792
			echop = echo_input;	
793
			*echop = 0;
794
		}
795
		return c;
796
	}
797
	return *hostp++;
798
}
799
 
800
void
801
set_host(Event *e)
802
{
803
	hostlength = e->n;
804
	if(hostlength > host_bsize) {
805
		host_bsize *= 2;
806
		host_buf = realloc(host_buf,host_bsize);
807
	}
808
	hostp = host_buf;
809
	memmove(host_buf,e->data,hostlength);
810
	host_buf[hostlength]=0;
811
}
812
 
813
void
814
ringbell(void){
815
}
816
 
817
int
818
alnum(int c)
819
{
820
	if(c >= 'a' && c <= 'z')
821
		return 1;
822
	if(c >= 'A' && c <= 'Z')
823
		return 1;
824
	if(c >= '0' && c <= '9')
825
		return 1;
826
	return 0;
827
}
828
 
829
void
830
escapedump(int fd,uchar *str,int len)
831
{
832
	int i;
833
 
834
	for(i = 0; i < len; i++) {
835
		if((str[i] < ' ' || str[i] > '\177') && 
836
			str[i] != '\n' && str[i] != '\t') fprint(fd,"^%c",str[i]+64);
837
		else if(str[i] == '\177') fprint(fd,"^$");
838
		else if(str[i] == '\n') fprint(fd,"^J\n");
839
		else fprint(fd,"%c",str[i]);
840
	}
841
}
842
 
843
void
844
funckey(int key)
845
{
846
	if(key >= NKEYS)
847
		return;
848
	if(fk[key].name == 0)
849
		return;
850
	sendnchars2(strlen(fk[key].sequence), fk[key].sequence);
851
}
852
 
853
 
854
void
855
drawstring(Point p, char *str, int attr)
856
{
857
	int i;
858
	Image *txt, *bg, *tmp;
859
 
860
	txt = fgcolor;
861
	bg = bgcolor;
862
	if(attr & TReverse){
863
		tmp = txt;
864
		txt = bg;
865
		bg = tmp;
866
	}
867
	if(attr & THighIntensity){
868
		for(i=0; i<8; i++)
869
			if(txt == colors[i])
870
				txt = hicolors[i];
871
	}
872
 
873
	draw(screen, Rpt(p, addpt(p, stringsize(font, str))), bg, nil, p);
874
	string(screen, p, txt, ZP, font, str);
875
}