1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42: #include <sys/ioctl.h>
43:
44: #include <setjmp.h>
45: #include <signal.h>
46: #include <stdio.h>
47: #include <stdlib.h>
48: #include <string.h>
49: #include <termcap.h>
50: #include <termios.h>
51: #include <unistd.h>
52:
53: #ifndef sigmask
54: #define sigmask(s) (1 << ((s) - 1))
55: #endif
56:
57: #include "screen.h"
58: #include "tetris.h"
59:
60: static cell curscreen[B_SIZE];
61: static int curscore;
62: static int isset;
63: static struct termios oldtt;
64: static void (*tstp)(int);
65:
66: static void scr_stop(int);
67: static void stopset(int) __attribute__((__noreturn__));
68:
69:
70:
71:
72:
73: extern char PC, *BC, *UP;
74: static char BCdefault[] = "\b";
75: #ifndef NCURSES_VERSION
76: short ospeed;
77: #endif
78:
79: static char
80: *bcstr,
81: *CEstr,
82: *CLstr,
83: *CMstr,
84: #ifdef unneeded
85: *CRstr,
86: #endif
87: *HOstr,
88: *LLstr,
89: *pcstr,
90: *TEstr,
91: *TIstr;
92: char
93: *SEstr,
94: *SOstr;
95: static int
96: COnum,
97: LInum,
98: MSflag;
99:
100:
101: struct tcsinfo {
102: char tcname[3];
103: char **tcaddr;
104: } tcstrings[] = {
105: {"bc", &bcstr},
106: {"ce", &CEstr},
107: {"cl", &CLstr},
108: {"cm", &CMstr},
109: #ifdef unneeded
110: {"cr", &CRstr},
111: #endif
112: {"le", &BC},
113: {"pc", &pcstr},
114: {"se", &SEstr},
115: {"so", &SOstr},
116: {"te", &TEstr},
117: {"ti", &TIstr},
118: {"up", &UP},
119: { {0}, NULL}
120: };
121:
122:
123:
124: static char combuf[1024], tbuf[1024];
125:
126:
127:
128:
129:
130: int
131: put(c)
132: int c;
133: {
134:
135: return (putchar(c));
136: }
137:
138:
139:
140:
141:
142:
143: #define putstr(s) (void)fputs(s, stdout)
144: #define moveto(r, c) putpad(tgoto(CMstr, c, r))
145:
146:
147:
148:
149: void
150: scr_init()
151: {
152: static int bsflag, xsflag, sgnum;
153: #ifdef unneeded
154: static int ncflag;
155: #endif
156: char *term, *fill;
157: static struct tcninfo {
158: char tcname[3];
159: int *tcaddr;
160: } tcflags[] = {
161: {"bs", &bsflag},
162: {"ms", &MSflag},
163: #ifdef unneeded
164: {"nc", &ncflag},
165: #endif
166: {"xs", &xsflag},
167: { {0}, NULL}
168: }, tcnums[] = {
169: {"co", &COnum},
170: {"li", &LInum},
171: {"sg", &sgnum},
172: { {0}, NULL}
173: };
174:
175: if ((term = getenv("TERM")) == NULL)
176: stop("you must set the TERM environment variable");
177: if (tgetent(tbuf, term) <= 0)
178: stop("cannot find your termcap");
179: fill = combuf;
180: {
181: struct tcsinfo *p;
182:
183: for (p = tcstrings; p->tcaddr; p++)
184: *p->tcaddr = tgetstr(p->tcname, &fill);
185: }
186: {
187: struct tcninfo *p;
188:
189: for (p = tcflags; p->tcaddr; p++)
190: *p->tcaddr = tgetflag(p->tcname);
191: for (p = tcnums; p->tcaddr; p++)
192: *p->tcaddr = tgetnum(p->tcname);
193: }
194: if (bsflag)
195: BC = BCdefault;
196: else if (BC == NULL && bcstr != NULL)
197: BC = bcstr;
198: if (CLstr == NULL)
199: stop("cannot clear screen");
200: if (CMstr == NULL || UP == NULL || BC == NULL)
201: stop("cannot do random cursor positioning via tgoto()");
202: PC = pcstr ? *pcstr : 0;
203: if (sgnum >= 0 || xsflag)
204: SOstr = SEstr = NULL;
205: #ifdef unneeded
206: if (ncflag)
207: CRstr = NULL;
208: else if (CRstr == NULL)
209: CRstr = "\r";
210: #endif
211: }
212:
213:
214: static jmp_buf scr_onstop;
215:
216: static void
217: stopset(sig)
218: int sig;
219: {
220: sigset_t sigset;
221:
222: (void) signal(sig, SIG_DFL);
223: (void) kill(getpid(), sig);
224: sigemptyset(&sigset);
225: sigaddset(&sigset, sig);
226: (void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0);
227: longjmp(scr_onstop, 1);
228: }
229:
230: static void
231: scr_stop(sig)
232: int sig;
233: {
234: sigset_t sigset;
235:
236: scr_end();
237: (void) kill(getpid(), sig);
238: sigemptyset(&sigset);
239: sigaddset(&sigset, sig);
240: (void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0);
241: scr_set();
242: scr_msg(key_msg, 1);
243: }
244:
245:
246:
247:
248: void
249: scr_set()
250: {
251: struct winsize ws;
252: struct termios newtt;
253: sigset_t sigset, osigset;
254: void (*ttou)(int);
255:
256: sigemptyset(&sigset);
257: sigaddset(&sigset, SIGTSTP);
258: sigaddset(&sigset, SIGTTOU);
259: (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
260: if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN)
261: (void) signal(SIGTSTP, SIG_IGN);
262: if ((ttou = signal(SIGTTOU, stopset)) == SIG_IGN)
263: (void) signal(SIGTTOU, SIG_IGN);
264:
265:
266:
267:
268:
269: (void) setjmp(scr_onstop);
270: (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
271: Rows = 0, Cols = 0;
272: if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
273: Rows = ws.ws_row;
274: Cols = ws.ws_col;
275: }
276: if (Rows == 0)
277: Rows = LInum;
278: if (Cols == 0)
279: Cols = COnum;
280: if (Rows < MINROWS || Cols < MINCOLS) {
281: (void) fprintf(stderr,
282: "the screen is too small: must be at least %dx%d, ",
283: MINCOLS, MINROWS);
284: stop("");
285: }
286: if (tcgetattr(0, &oldtt) < 0)
287: stop("tcgetattr() fails");
288: newtt = oldtt;
289: newtt.c_lflag &= ~(ICANON|ECHO);
290: newtt.c_oflag &= ~OXTABS;
291: newtt.c_cc[VMIN] = 1;
292: newtt.c_cc[VTIME] = 0;
293: if (tcsetattr(0, TCSADRAIN, &newtt) < 0)
294: stop("tcsetattr() fails");
295: ospeed = cfgetospeed(&newtt);
296: (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
297:
298:
299:
300:
301:
302: if (TIstr)
303: putstr(TIstr);
304: if (tstp != SIG_IGN)
305: (void) signal(SIGTSTP, scr_stop);
306: if (ttou != SIG_IGN)
307: (void) signal(SIGTTOU, ttou);
308:
309: isset = 1;
310: (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
311: scr_clear();
312: }
313:
314:
315:
316:
317: void
318: scr_end()
319: {
320: sigset_t sigset, osigset;
321:
322: sigemptyset(&sigset);
323: sigaddset(&sigset, SIGTSTP);
324: sigaddset(&sigset, SIGTTOU);
325: (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
326:
327: if (LLstr)
328: putstr(LLstr);
329: else
330: moveto(Rows - 1, 0);
331:
332: if (TEstr)
333: putstr(TEstr);
334: (void) fflush(stdout);
335: (void) tcsetattr(0, TCSADRAIN, &oldtt);
336: isset = 0;
337:
338: (void) signal(SIGTSTP, tstp);
339: (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
340: }
341:
342: void
343: stop(why)
344: const char *why;
345: {
346:
347: if (isset)
348: scr_end();
349: (void) fprintf(stderr, "aborting: %s\n", why);
350: exit(1);
351: }
352:
353:
354:
355:
356: void
357: scr_clear()
358: {
359:
360: putpad(CLstr);
361: curscore = -1;
362: memset((char *)curscreen, 0, sizeof(curscreen));
363: }
364:
365: #if vax && !__GNUC__
366: typedef int regcell;
367: #else
368: typedef cell regcell;
369: #endif
370:
371:
372:
373:
374: void
375: scr_update()
376: {
377: cell *bp, *sp;
378: regcell so, cur_so = 0;
379: int i, ccol, j;
380: sigset_t sigset, osigset;
381: static const struct shape *lastshape;
382:
383: sigemptyset(&sigset);
384: sigaddset(&sigset, SIGTSTP);
385: (void) sigprocmask(SIG_BLOCK, &sigset, &osigset);
386:
387:
388: curscreen[D_LAST * B_COLS - 1] = -1;
389:
390: if (score != curscore) {
391: if (HOstr)
392: putpad(HOstr);
393: else
394: moveto(0, 0);
395: (void) printf("Score: %d", score);
396: curscore = score;
397: }
398:
399:
400: if (showpreview && (nextshape != lastshape)) {
401: int i;
402: static int r=5, c=2;
403: int tr, tc, t;
404:
405: lastshape = nextshape;
406:
407:
408: putpad(SEstr);
409: moveto(r-1, c-1); putstr(" ");
410: moveto(r, c-1); putstr(" ");
411: moveto(r+1, c-1); putstr(" ");
412: moveto(r+2, c-1); putstr(" ");
413:
414: moveto(r-3, c-2);
415: putstr("Next shape:");
416:
417:
418: putpad(SOstr);
419: moveto(r, 2*c);
420: putstr(" ");
421: for(i=0; i<3; i++) {
422: t = c + r*B_COLS;
423: t += nextshape->off[i];
424:
425: tr = t / B_COLS;
426: tc = t % B_COLS;
427:
428: moveto(tr, 2*tc);
429: putstr(" ");
430: }
431: putpad(SEstr);
432: }
433:
434: bp = &board[D_FIRST * B_COLS];
435: sp = &curscreen[D_FIRST * B_COLS];
436: for (j = D_FIRST; j < D_LAST; j++) {
437: ccol = -1;
438: for (i = 0; i < B_COLS; bp++, sp++, i++) {
439: if (*sp == (so = *bp))
440: continue;
441: *sp = so;
442: if (i != ccol) {
443: if (cur_so && MSflag) {
444: putpad(SEstr);
445: cur_so = 0;
446: }
447: moveto(RTOD(j), CTOD(i));
448: }
449: if (SOstr) {
450: if (so != cur_so) {
451: putpad(so ? SOstr : SEstr);
452: cur_so = so;
453: }
454: putstr(" ");
455: } else
456: putstr(so ? "XX" : " ");
457: ccol = i + 1;
458:
459:
460:
461:
462:
463:
464:
465:
466: #define STOP (B_COLS - 3)
467: if (i > STOP || sp[1] != bp[1] || so != bp[1])
468: continue;
469: if (sp[2] != bp[2])
470: sp[1] = -1;
471: else if (i < STOP && so == bp[2] && sp[3] != bp[3]) {
472: sp[2] = -1;
473: sp[1] = -1;
474: }
475: }
476: }
477: if (cur_so)
478: putpad(SEstr);
479: (void) fflush(stdout);
480: (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
481: }
482:
483:
484:
485:
486:
487: void
488: scr_msg(s, set)
489: char *s;
490: int set;
491: {
492:
493: if (set || CEstr == NULL) {
494: int l = strlen(s);
495:
496: moveto(Rows - 2, ((Cols - l) >> 1) - 1);
497: if (set)
498: putstr(s);
499: else
500: while (--l >= 0)
501: (void) putchar(' ');
502: } else {
503: moveto(Rows - 2, 0);
504: putpad(CEstr);
505: }
506: }