Subversion Repositories HelenOS

Rev

Rev 1419 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1419 jermar 1
/*	$OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray Exp $	*/
2
/*	$NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft Exp $	*/
3
 
4
/*-
5
 * Copyright (c) 1992, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Chris Torek and Darren F. Provine.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 *
35
 *	@(#)screen.c	8.1 (Berkeley) 5/31/93
36
 */
37
 
38
/*
39
 * Tetris screen control.
40
 */
41
 
42
#include <sys/ioctl.h>
43
 
44
#include <err.h>
1472 palkovsky 45
//#include <setjmp.h>
46
//#include <signal.h>
1419 jermar 47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <term.h>
51
#include <termios.h>
52
#include <unistd.h>
53
 
54
#include "screen.h"
55
#include "tetris.h"
56
 
57
static cell curscreen[B_SIZE];	/* 1 => standout (or otherwise marked) */
58
static int curscore;
59
static int isset;		/* true => terminal is in game mode */
60
static struct termios oldtt;
61
static void (*tstp)(int);
62
 
63
static void	scr_stop(int);
64
static void	stopset(int);
65
 
66
/*
67
 * Capabilities from TERMCAP.
68
 */
69
char	PC, *BC, *UP;		/* tgoto requires globals: ugh! */
70
 
71
static char
72
	*bcstr,			/* backspace char */
73
	*CEstr,			/* clear to end of line */
74
	*CLstr,			/* clear screen */
75
	*CMstr,			/* cursor motion string */
76
#ifdef unneeded
77
	*CRstr,			/* "\r" equivalent */
78
#endif
79
	*HOstr,			/* cursor home */
80
	*LLstr,			/* last line, first column */
81
	*pcstr,			/* pad character */
82
	*TEstr,			/* end cursor motion mode */
83
	*TIstr;			/* begin cursor motion mode */
84
char
85
	*SEstr,			/* end standout mode */
86
	*SOstr;			/* begin standout mode */
87
static int
88
	COnum,			/* co# value */
89
	LInum,			/* li# value */
90
	MSflag;			/* can move in standout mode */
91
 
92
 
93
struct tcsinfo {		/* termcap string info; some abbrevs above */
94
	char tcname[3];
95
	char **tcaddr;
96
} tcstrings[] = {
97
	{"bc", &bcstr},
98
	{"ce", &CEstr},
99
	{"cl", &CLstr},
100
	{"cm", &CMstr},
101
#ifdef unneeded
102
	{"cr", &CRstr},
103
#endif
104
	{"le", &BC},		/* move cursor left one space */
105
	{"pc", &pcstr},
106
	{"se", &SEstr},
107
	{"so", &SOstr},
108
	{"te", &TEstr},
109
	{"ti", &TIstr},
110
	{"up", &UP},		/* cursor up */
111
	{ {0}, NULL}
112
};
113
 
114
/* This is where we will actually stuff the information */
115
 
116
static char combuf[1024], tbuf[1024];
117
 
118
 
119
/*
120
 * Routine used by tputs().
121
 */
122
int
123
put(int c)
124
{
125
 
126
	return (putchar(c));
127
}
128
 
129
/*
130
 * putstr() is for unpadded strings (either as in termcap(5) or
131
 * simply literal strings); putpad() is for padded strings with
132
 * count=1.  (See screen.h for putpad().)
133
 */
134
#define	putstr(s)	(void)fputs(s, stdout)
135
#define	moveto(r, c)	putpad(tgoto(CMstr, c, r))
136
 
137
/*
138
 * Set up from termcap.
139
 */
140
void
141
scr_init(void)
142
{
143
	static int bsflag, xsflag, sgnum;
144
#ifdef unneeded
145
	static int ncflag;
146
#endif
147
	char *term, *fill;
148
	static struct tcninfo {	/* termcap numeric and flag info */
149
		char tcname[3];
150
		int *tcaddr;
151
	} tcflags[] = {
152
		{"bs", &bsflag},
153
		{"ms", &MSflag},
154
#ifdef unneeded
155
		{"nc", &ncflag},
156
#endif
157
		{"xs", &xsflag},
158
		{ {0}, NULL}
159
	}, tcnums[] = {
160
		{"co", &COnum},
161
		{"li", &LInum},
162
		{"sg", &sgnum},
163
		{ {0}, NULL}
164
	};
165
 
166
	if ((term = getenv("TERM")) == NULL)
167
		stop("you must set the TERM environment variable");
168
	if (tgetent(tbuf, term) <= 0)
169
		stop("cannot find your termcap");
170
	fill = combuf;
171
	{
172
		struct tcsinfo *p;
173
 
174
		for (p = tcstrings; p->tcaddr; p++)
175
			*p->tcaddr = tgetstr(p->tcname, &fill);
176
	}
177
	if (classic)
178
		SOstr = SEstr = NULL;
179
	{
180
		struct tcninfo *p;
181
 
182
		for (p = tcflags; p->tcaddr; p++)
183
			*p->tcaddr = tgetflag(p->tcname);
184
		for (p = tcnums; p->tcaddr; p++)
185
			*p->tcaddr = tgetnum(p->tcname);
186
	}
187
	if (bsflag)
188
		BC = "\b";
189
	else if (BC == NULL && bcstr != NULL)
190
		BC = bcstr;
191
	if (CLstr == NULL)
192
		stop("cannot clear screen");
193
	if (CMstr == NULL || UP == NULL || BC == NULL)
194
		stop("cannot do random cursor positioning via tgoto()");
195
	PC = pcstr ? *pcstr : 0;
196
	if (sgnum > 0 || xsflag)
197
		SOstr = SEstr = NULL;
198
#ifdef unneeded
199
	if (ncflag)
200
		CRstr = NULL;
201
	else if (CRstr == NULL)
202
		CRstr = "\r";
203
#endif
204
}
205
 
206
/* this foolery is needed to modify tty state `atomically' */
1472 palkovsky 207
//static jmp_buf scr_onstop;
1419 jermar 208
 
1472 palkovsky 209
/* static void */
210
/* stopset(int sig) */
211
/* { */
212
/* 	sigset_t sigset; */
1419 jermar 213
 
1472 palkovsky 214
/* 	(void) signal(sig, SIG_DFL); */
215
/* 	(void) kill(getpid(), sig); */
216
/* 	sigemptyset(&sigset); */
217
/* 	sigaddset(&sigset, sig); */
218
/* 	(void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0); */
219
/* 	longjmp(scr_onstop, 1); */
220
/* } */
1419 jermar 221
 
222
static void
223
scr_stop(int sig)
224
{
1472 palkovsky 225
//	sigset_t sigset;
1419 jermar 226
 
227
	scr_end();
1472 palkovsky 228
/* 	(void) kill(getpid(), sig); */
229
/* 	sigemptyset(&sigset); */
230
/* 	sigaddset(&sigset, sig); */
231
/* 	(void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0); */
1419 jermar 232
	scr_set();
233
	scr_msg(key_msg, 1);
234
}
235
 
236
/*
237
 * Set up screen mode.
238
 */
239
void
240
scr_set(void)
241
{
242
	struct winsize ws;
243
	struct termios newtt;
1472 palkovsky 244
//	sigset_t sigset, osigset;
1419 jermar 245
	void (*ttou)(int);
246
 
1472 palkovsky 247
/* 	sigemptyset(&sigset); */
248
/* 	sigaddset(&sigset, SIGTSTP); */
249
/* 	sigaddset(&sigset, SIGTTOU); */
250
/* 	(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
251
/* 	if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN) */
252
/* 		(void) signal(SIGTSTP, SIG_IGN); */
253
/* 	if ((ttou = signal(SIGTTOU, stopset)) == SIG_IGN) */
254
/* 		(void) signal(SIGTTOU, SIG_IGN); */
255
/* 	/\* */
256
/* 	 * At last, we are ready to modify the tty state.  If */
257
/* 	 * we stop while at it, stopset() above will longjmp back */
258
/* 	 * to the setjmp here and we will start over. */
259
/* 	 *\/ */
260
/* 	(void) setjmp(scr_onstop); */
261
/* 	(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); */
1419 jermar 262
	Rows = 0, Cols = 0;
263
	if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
264
		Rows = ws.ws_row;
265
		Cols = ws.ws_col;
266
	}
267
	if (Rows == 0)
268
		Rows = LInum;
269
	if (Cols == 0)
270
	Cols = COnum;
271
	if (Rows < MINROWS || Cols < MINCOLS) {
272
		char smallscr[55];
273
 
274
		(void)snprintf(smallscr, sizeof(smallscr),
275
		    "the screen is too small (must be at least %dx%d)",
276
		    MINROWS, MINCOLS);
277
		stop(smallscr);
278
	}
279
	if (tcgetattr(0, &oldtt) < 0)
280
		stop("tcgetattr() fails");
281
	newtt = oldtt;
282
	newtt.c_lflag &= ~(ICANON|ECHO);
283
	newtt.c_oflag &= ~OXTABS;
284
	if (tcsetattr(0, TCSADRAIN, &newtt) < 0)
285
		stop("tcsetattr() fails");
1472 palkovsky 286
/* 	(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
1419 jermar 287
 
288
	/*
289
	 * We made it.  We are now in screen mode, modulo TIstr
290
	 * (which we will fix immediately).
291
	 */
292
	if (TIstr)
293
		putstr(TIstr);	/* termcap(5) says this is not padded */
1472 palkovsky 294
/* 	if (tstp != SIG_IGN) */
295
/* 		(void) signal(SIGTSTP, scr_stop); */
296
/* 	if (ttou != SIG_IGN) */
297
/* 		(void) signal(SIGTTOU, ttou); */
1419 jermar 298
 
299
	isset = 1;
1472 palkovsky 300
//	(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
1419 jermar 301
	scr_clear();
302
}
303
 
304
/*
305
 * End screen mode.
306
 */
307
void
308
scr_end(void)
309
{
1472 palkovsky 310
//	sigset_t sigset, osigset;
1419 jermar 311
 
1472 palkovsky 312
/* 	sigemptyset(&sigset); */
313
/* 	sigaddset(&sigset, SIGTSTP); */
314
/* 	sigaddset(&sigset, SIGTTOU); */
315
/* 	(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
1419 jermar 316
	/* move cursor to last line */
317
	if (LLstr)
318
		putstr(LLstr);	/* termcap(5) says this is not padded */
319
	else
320
		moveto(Rows - 1, 0);
321
	/* exit screen mode */
322
	if (TEstr)
323
		putstr(TEstr);	/* termcap(5) says this is not padded */
1472 palkovsky 324
//	(void) fflush(stdout);
1419 jermar 325
	(void) tcsetattr(0, TCSADRAIN, &oldtt);
326
	isset = 0;
327
	/* restore signals */
1472 palkovsky 328
/* 	(void) signal(SIGTSTP, tstp); */
329
/* 	(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); */
1419 jermar 330
}
331
 
332
void
333
stop(char *why)
334
{
335
 
336
	if (isset)
337
		scr_end();
338
	errx(1, "aborting: %s", why);
339
}
340
 
341
/*
342
 * Clear the screen, forgetting the current contents in the process.
343
 */
344
void
345
scr_clear(void)
346
{
347
 
348
	putpad(CLstr);
349
	curscore = -1;
350
	memset((char *)curscreen, 0, sizeof(curscreen));
351
}
352
 
353
#if vax && !__GNUC__
354
typedef int regcell;	/* pcc is bad at `register char', etc */
355
#else
356
typedef cell regcell;
357
#endif
358
 
359
/*
360
 * Update the screen.
361
 */
362
void
363
scr_update(void)
364
{
365
	cell *bp, *sp;
366
	regcell so, cur_so = 0;
367
	int i, ccol, j;
1472 palkovsky 368
//	sigset_t sigset, osigset;
1419 jermar 369
	static const struct shape *lastshape;
370
 
1472 palkovsky 371
/* 	sigemptyset(&sigset); */
372
/* 	sigaddset(&sigset, SIGTSTP); */
373
/* 	(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
1419 jermar 374
 
375
	/* always leave cursor after last displayed point */
376
	curscreen[D_LAST * B_COLS - 1] = -1;
377
 
378
	if (score != curscore) {
379
		if (HOstr)
380
			putpad(HOstr);
381
		else
382
			moveto(0, 0);
383
		(void) printf("Score: %d", score);
384
		curscore = score;
385
	}
386
 
387
	/* draw preview of next pattern */
388
	if (showpreview && (nextshape != lastshape)) {
389
		int i;
390
		static int r=5, c=2;
391
		int tr, tc, t;
392
 
393
		lastshape = nextshape;
394
 
395
		/* clean */
396
		putpad(SEstr);
397
		moveto(r-1, c-1); putstr("          ");
398
		moveto(r,   c-1); putstr("          ");
399
		moveto(r+1, c-1); putstr("          ");
400
		moveto(r+2, c-1); putstr("          ");
401
 
402
		moveto(r-3, c-2);
403
		putstr("Next shape:");
404
 
405
		/* draw */
406
		if (SOstr)
407
			putpad(SOstr);
408
		moveto(r, 2 * c);
409
		putstr(SOstr ? "  " : "[]");
410
		for (i = 0; i < 3; i++) {
411
			t = c + r * B_COLS;
412
			t += nextshape->off[i];
413
 
414
			tr = t / B_COLS;
415
			tc = t % B_COLS;
416
 
417
			moveto(tr, 2*tc);
418
			putstr(SOstr ? "  " : "[]");
419
		}
420
		putpad(SEstr);
421
	}
422
 
423
	bp = &board[D_FIRST * B_COLS];
424
	sp = &curscreen[D_FIRST * B_COLS];
425
	for (j = D_FIRST; j < D_LAST; j++) {
426
		ccol = -1;
427
		for (i = 0; i < B_COLS; bp++, sp++, i++) {
428
			if (*sp == (so = *bp))
429
				continue;
430
			*sp = so;
431
			if (i != ccol) {
432
				if (cur_so && MSflag) {
433
					putpad(SEstr);
434
					cur_so = 0;
435
				}
436
				moveto(RTOD(j), CTOD(i));
437
			}
438
			if (SOstr) {
439
				if (so != cur_so) {
440
					putpad(so ? SOstr : SEstr);
441
					cur_so = so;
442
				}
443
				putstr("  ");
444
			} else
445
				putstr(so ? "[]" : "  ");
446
			ccol = i + 1;
447
			/*
448
			 * Look ahead a bit, to avoid extra motion if
449
			 * we will be redrawing the cell after the next.
450
			 * Motion probably takes four or more characters,
451
			 * so we save even if we rewrite two cells
452
			 * `unnecessarily'.  Skip it all, though, if
453
			 * the next cell is a different color.
454
			 */
455
#define	STOP (B_COLS - 3)
456
			if (i > STOP || sp[1] != bp[1] || so != bp[1])
457
				continue;
458
			if (sp[2] != bp[2])
459
				sp[1] = -1;
460
			else if (i < STOP && so == bp[2] && sp[3] != bp[3]) {
461
				sp[2] = -1;
462
				sp[1] = -1;
463
			}
464
		}
465
	}
466
	if (cur_so)
467
		putpad(SEstr);
1472 palkovsky 468
/* 	(void) fflush(stdout); */
469
/* 	(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); */
1419 jermar 470
}
471
 
472
/*
473
 * Write a message (set!=0), or clear the same message (set==0).
474
 * (We need its length in case we have to overwrite with blanks.)
475
 */
476
void
477
scr_msg(char *s, int set)
478
{
479
 
480
	if (set || CEstr == NULL) {
481
		int l = strlen(s);
482
 
483
		moveto(Rows - 2, ((Cols - l) >> 1) - 1);
484
		if (set)
485
			putstr(s);
486
		else
487
			while (--l >= 0)
488
				(void) putchar(' ');
489
	} else {
490
		moveto(Rows - 2, 0);
491
		putpad(CEstr);
492
	}
493
}