+/* $NetBSD: screen.c,v 1.22 2008/01/28 01:38:59 dholland Exp $ */
+
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Tetris screen control.
*/
-#include <sgtty.h>
+#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termcap.h>
+#include <termios.h>
#include <unistd.h>
#ifndef sigmask
#include "screen.h"
#include "tetris.h"
-/*
- * XXX - need a <termcap.h>
- */
-int tgetent __P((char *, const char *));
-int tgetflag __P((const char *));
-int tgetnum __P((const char *));
-int tputs __P((const char *, int, int (*)(int)));
-
static cell curscreen[B_SIZE]; /* 1 => standout (or otherwise marked) */
static int curscore;
static int isset; /* true => terminal is in game mode */
-static struct sgttyb oldtt;
-static void (*tstp)();
+static struct termios oldtt;
+static void (*tstp)(int);
-char *tgetstr(), *tgoto();
+static void scr_stop(int);
+static void stopset(int) __dead;
/*
* Capabilities from TERMCAP.
*/
-char PC, *BC, *UP; /* tgoto requires globals: ugh! */
short ospeed;
static char
char tcname[3];
char **tcaddr;
} tcstrings[] = {
- "bc", &bcstr,
- "ce", &CEstr,
- "cl", &CLstr,
- "cm", &CMstr,
+ {"bc", &bcstr},
+ {"ce", &CEstr},
+ {"cl", &CLstr},
+ {"cm", &CMstr},
#ifdef unneeded
- "cr", &CRstr,
+ {"cr", &CRstr},
#endif
- "le", &BC, /* move cursor left one space */
- "pc", &pcstr,
- "se", &SEstr,
- "so", &SOstr,
- "te", &TEstr,
- "ti", &TIstr,
- "up", &UP, /* cursor up */
- 0
+ {"le", &BC}, /* move cursor left one space */
+ {"pc", &pcstr},
+ {"se", &SEstr},
+ {"so", &SOstr},
+ {"te", &TEstr},
+ {"ti", &TIstr},
+ {"up", &UP}, /* cursor up */
+ { {0}, NULL}
};
/* This is where we will actually stuff the information */
-static char combuf[1024], tbuf[1024];
-
+static struct tinfo *info;
/*
* Routine used by tputs().
* count=1. (See screen.h for putpad().)
*/
#define putstr(s) (void)fputs(s, stdout)
-#define moveto(r, c) putpad(tgoto(CMstr, c, r))
+
+void
+moveto(int r, int c)
+{
+ char buf[256];
+
+ if (t_goto(info, CMstr, c, r, buf, 255) == 0)
+ putpad(buf);
+}
/*
* Set up from termcap.
#ifdef unneeded
static int ncflag;
#endif
- char *term, *fill;
+ char *term;
static struct tcninfo { /* termcap numeric and flag info */
char tcname[3];
int *tcaddr;
} tcflags[] = {
- "bs", &bsflag,
- "ms", &MSflag,
+ {"bs", &bsflag},
+ {"ms", &MSflag},
#ifdef unneeded
- "nc", &ncflag,
+ {"nc", &ncflag},
#endif
- "xs", &xsflag,
- 0
+ {"xs", &xsflag},
+ { {0}, NULL}
}, tcnums[] = {
- "co", &COnum,
- "li", &LInum,
- "sg", &sgnum,
- 0
+ {"co", &COnum},
+ {"li", &LInum},
+ {"sg", &sgnum},
+ { {0}, NULL}
};
-
+ static char backspace[] = "\b";
+
if ((term = getenv("TERM")) == NULL)
stop("you must set the TERM environment variable");
- if (tgetent(tbuf, term) <= 0)
+ if (t_getent(&info, term) <= 0)
stop("cannot find your termcap");
- fill = combuf;
{
- register struct tcsinfo *p;
+ struct tcsinfo *p;
for (p = tcstrings; p->tcaddr; p++)
- *p->tcaddr = tgetstr(p->tcname, &fill);
+ *p->tcaddr = t_agetstr(info, p->tcname);
}
{
- register struct tcninfo *p;
+ struct tcninfo *p;
for (p = tcflags; p->tcaddr; p++)
- *p->tcaddr = tgetflag(p->tcname);
+ *p->tcaddr = t_getflag(info, p->tcname);
for (p = tcnums; p->tcaddr; p++)
- *p->tcaddr = tgetnum(p->tcname);
+ *p->tcaddr = t_getnum(info, p->tcname);
}
if (bsflag)
- BC = "\b";
+ BC = backspace;
else if (BC == NULL && bcstr != NULL)
BC = bcstr;
if (CLstr == NULL)
/* this foolery is needed to modify tty state `atomically' */
static jmp_buf scr_onstop;
-#define sigunblock(mask) sigsetmask(sigblock(0) & ~(mask))
-
static void
stopset(sig)
int sig;
{
+ sigset_t set;
+
(void) signal(sig, SIG_DFL);
(void) kill(getpid(), sig);
- (void) sigunblock(sigmask(sig));
+ sigemptyset(&set);
+ sigaddset(&set, sig);
+ (void) sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0);
longjmp(scr_onstop, 1);
}
static void
-scr_stop()
+scr_stop(sig)
+ int sig;
{
+ sigset_t set;
+
scr_end();
- (void) kill(getpid(), SIGTSTP);
- (void) sigunblock(sigmask(SIGTSTP));
+ (void) kill(getpid(), sig);
+ sigemptyset(&set);
+ sigaddset(&set, sig);
+ (void) sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0);
scr_set();
scr_msg(key_msg, 1);
}
scr_set()
{
struct winsize ws;
- struct sgttyb newtt;
- volatile int omask;
- void (*ttou)();
-
- omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU));
+ struct termios newtt;
+ sigset_t nsigset, osigset;
+ void (*ttou)(int);
+
+ sigemptyset(&nsigset);
+ sigaddset(&nsigset, SIGTSTP);
+ sigaddset(&nsigset, SIGTTOU);
+ (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN)
(void) signal(SIGTSTP, SIG_IGN);
- if ((ttou = signal(SIGTSTP, stopset)) == SIG_IGN)
- (void) signal(SIGTSTP, SIG_IGN);
+ if ((ttou = signal(SIGTTOU, stopset)) == SIG_IGN)
+ (void) signal(SIGTTOU, SIG_IGN);
/*
* At last, we are ready to modify the tty state. If
* we stop while at it, stopset() above will longjmp back
* to the setjmp here and we will start over.
*/
(void) setjmp(scr_onstop);
- (void) sigsetmask(omask);
+ (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
Rows = 0, Cols = 0;
if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
Rows = ws.ws_row;
Cols = COnum;
if (Rows < MINROWS || Cols < MINCOLS) {
(void) fprintf(stderr,
- "the screen is too small: must be at least %d x %d",
- MINROWS, MINCOLS);
+ "the screen is too small: must be at least %dx%d, ",
+ MINCOLS, MINROWS);
stop(""); /* stop() supplies \n */
}
- if (ioctl(0, TIOCGETP, &oldtt))
- stop("ioctl(TIOCGETP) fails");
+ if (tcgetattr(0, &oldtt) < 0)
+ stop("tcgetattr() fails");
newtt = oldtt;
- newtt.sg_flags = (newtt.sg_flags | CBREAK) & ~(CRMOD | ECHO);
- if ((newtt.sg_flags & TBDELAY) == XTABS)
- newtt.sg_flags &= ~TBDELAY;
- if (ioctl(0, TIOCSETN, &newtt))
- stop("ioctl(TIOCSETN) fails");
- ospeed = newtt.sg_ospeed;
- omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU));
+ newtt.c_lflag &= ~(ICANON|ECHO);
+ newtt.c_oflag &= ~OXTABS;
+ if (tcsetattr(0, TCSADRAIN, &newtt) < 0)
+ stop("tcsetattr() fails");
+ ospeed = cfgetospeed(&newtt);
+ (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
/*
* We made it. We are now in screen mode, modulo TIstr
putstr(TIstr); /* termcap(5) says this is not padded */
if (tstp != SIG_IGN)
(void) signal(SIGTSTP, scr_stop);
- (void) signal(SIGTTOU, ttou);
+ if (ttou != SIG_IGN)
+ (void) signal(SIGTTOU, ttou);
isset = 1;
- (void) sigsetmask(omask);
+ (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
scr_clear();
}
void
scr_end()
{
- int omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU));
+ sigset_t nsigset, osigset;
+ sigemptyset(&nsigset);
+ sigaddset(&nsigset, SIGTSTP);
+ sigaddset(&nsigset, SIGTTOU);
+ (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
/* move cursor to last line */
if (LLstr)
putstr(LLstr); /* termcap(5) says this is not padded */
if (TEstr)
putstr(TEstr); /* termcap(5) says this is not padded */
(void) fflush(stdout);
- (void) ioctl(0, TIOCSETN, &oldtt);
+ (void) tcsetattr(0, TCSADRAIN, &oldtt);
isset = 0;
/* restore signals */
(void) signal(SIGTSTP, tstp);
- (void) sigsetmask(omask);
+ (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
}
void
stop(why)
- char *why;
+ const char *why;
{
if (isset)
putpad(CLstr);
curscore = -1;
- bzero((char *)curscreen, sizeof(curscreen));
+ memset((char *)curscreen, 0, sizeof(curscreen));
}
#if vax && !__GNUC__
void
scr_update()
{
- register cell *bp, *sp;
- register regcell so, cur_so = 0;
- register int i, ccol, j;
- int omask = sigblock(sigmask(SIGTSTP));
+ cell *bp, *sp;
+ regcell so, cur_so = 0;
+ int i, ccol, j;
+ sigset_t nsigset, osigset;
+ static const struct shape *lastshape;
+
+ sigemptyset(&nsigset);
+ sigaddset(&nsigset, SIGTSTP);
+ (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
/* always leave cursor after last displayed point */
curscreen[D_LAST * B_COLS - 1] = -1;
putpad(HOstr);
else
moveto(0, 0);
- (void) printf("%d", score);
+ (void) printf("Score: %d", score);
curscore = score;
}
+ /* draw preview of nextpattern */
+ if (showpreview && (nextshape != lastshape)) {
+ static int r=5, c=2;
+ int tr, tc, t;
+
+ lastshape = nextshape;
+
+ /* clean */
+ putpad(SEstr);
+ moveto(r-1, c-1); putstr(" ");
+ moveto(r, c-1); putstr(" ");
+ moveto(r+1, c-1); putstr(" ");
+ moveto(r+2, c-1); putstr(" ");
+
+ moveto(r-3, c-2);
+ putstr("Next shape:");
+
+ /* draw */
+ putpad(SOstr);
+ moveto(r, 2*c);
+ putstr(" ");
+ for(i=0; i<3; i++) {
+ t = c + r*B_COLS;
+ t += nextshape->off[i];
+
+ tr = t / B_COLS;
+ tc = t % B_COLS;
+
+ moveto(tr, 2*tc);
+ putstr(" ");
+ }
+ putpad(SEstr);
+ }
+
bp = &board[D_FIRST * B_COLS];
sp = &curscreen[D_FIRST * B_COLS];
for (j = D_FIRST; j < D_LAST; j++) {
if (cur_so)
putpad(SEstr);
(void) fflush(stdout);
- (void) sigsetmask(omask);
+ (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
}
/*
*/
void
scr_msg(s, set)
- register char *s;
+ char *s;
int set;
{
if (set || CEstr == NULL) {
- register int l = strlen(s);
+ int l = strlen(s);
moveto(Rows - 2, ((Cols - l) >> 1) - 1);
if (set)