source: mainline/tetris/screen.c@ c594489

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c594489 was c594489, checked in by Ondrej Palkovsky <ondrap@…>, 19 years ago

More things to make tetris helenos compatibile.

  • Property mode set to 100644
File size: 11.4 KB
Line 
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>
45//#include <setjmp.h>
46//#include <signal.h>
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
57static cell curscreen[B_SIZE]; /* 1 => standout (or otherwise marked) */
58static int curscore;
59static int isset; /* true => terminal is in game mode */
60static struct termios oldtt;
61static void (*tstp)(int);
62
63static void scr_stop(int);
64static void stopset(int);
65
66/*
67 * Capabilities from TERMCAP.
68 */
69char PC, *BC, *UP; /* tgoto requires globals: ugh! */
70
71static 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 */
84char
85 *SEstr, /* end standout mode */
86 *SOstr; /* begin standout mode */
87static int
88 COnum, /* co# value */
89 LInum, /* li# value */
90 MSflag; /* can move in standout mode */
91
92
93struct 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
116static char combuf[1024], tbuf[1024];
117
118
119/*
120 * Routine used by tputs().
121 */
122int
123put(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 */
140void
141scr_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' */
207//static jmp_buf scr_onstop;
208
209/* static void */
210/* stopset(int sig) */
211/* { */
212/* sigset_t sigset; */
213
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/* } */
221
222static void
223scr_stop(int sig)
224{
225// sigset_t sigset;
226
227 scr_end();
228/* (void) kill(getpid(), sig); */
229/* sigemptyset(&sigset); */
230/* sigaddset(&sigset, sig); */
231/* (void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0); */
232 scr_set();
233 scr_msg(key_msg, 1);
234}
235
236/*
237 * Set up screen mode.
238 */
239void
240scr_set(void)
241{
242 struct winsize ws;
243 struct termios newtt;
244// sigset_t sigset, osigset;
245 void (*ttou)(int);
246
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); */
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");
286/* (void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
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 */
294/* if (tstp != SIG_IGN) */
295/* (void) signal(SIGTSTP, scr_stop); */
296/* if (ttou != SIG_IGN) */
297/* (void) signal(SIGTTOU, ttou); */
298
299 isset = 1;
300// (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
301 scr_clear();
302}
303
304/*
305 * End screen mode.
306 */
307void
308scr_end(void)
309{
310// sigset_t sigset, osigset;
311
312/* sigemptyset(&sigset); */
313/* sigaddset(&sigset, SIGTSTP); */
314/* sigaddset(&sigset, SIGTTOU); */
315/* (void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
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 */
324// (void) fflush(stdout);
325 (void) tcsetattr(0, TCSADRAIN, &oldtt);
326 isset = 0;
327 /* restore signals */
328/* (void) signal(SIGTSTP, tstp); */
329/* (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); */
330}
331
332void
333stop(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 */
344void
345scr_clear(void)
346{
347
348 putpad(CLstr);
349 curscore = -1;
350 memset((char *)curscreen, 0, sizeof(curscreen));
351}
352
353#if vax && !__GNUC__
354typedef int regcell; /* pcc is bad at `register char', etc */
355#else
356typedef cell regcell;
357#endif
358
359/*
360 * Update the screen.
361 */
362void
363scr_update(void)
364{
365 cell *bp, *sp;
366 regcell so, cur_so = 0;
367 int i, ccol, j;
368// sigset_t sigset, osigset;
369 static const struct shape *lastshape;
370
371/* sigemptyset(&sigset); */
372/* sigaddset(&sigset, SIGTSTP); */
373/* (void) sigprocmask(SIG_BLOCK, &sigset, &osigset); */
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);
468/* (void) fflush(stdout); */
469/* (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); */
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 */
476void
477scr_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}
Note: See TracBrowser for help on using the repository browser.