-/* $NetBSD: screen.c,v 1.2 1995/04/22 07:42:41 cgd Exp $ */
+/* $NetBSD: screen.c,v 1.28 2014/06/11 16:47:39 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
* 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 <term.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)();
-
-char *tgetstr(), *tgoto();
-
-
-/*
- * Capabilities from TERMCAP.
- */
-char PC, *BC, *UP; /* tgoto requires globals: ugh! */
-short ospeed;
-
-static char
- *bcstr, /* backspace char */
- *CEstr, /* clear to end of line */
- *CLstr, /* clear screen */
- *CMstr, /* cursor motion string */
-#ifdef unneeded
- *CRstr, /* "\r" equivalent */
-#endif
- *HOstr, /* cursor home */
- *LLstr, /* last line, first column */
- *pcstr, /* pad character */
- *TEstr, /* end cursor motion mode */
- *TIstr; /* begin cursor motion mode */
-char
- *SEstr, /* end standout mode */
- *SOstr; /* begin standout mode */
-static int
- COnum, /* co# value */
- LInum, /* li# value */
- MSflag; /* can move in standout mode */
-
-
-struct tcsinfo { /* termcap string info; some abbrevs above */
- char tcname[3];
- char **tcaddr;
-} tcstrings[] = {
- "bc", &bcstr,
- "ce", &CEstr,
- "cl", &CLstr,
- "cm", &CMstr,
-#ifdef unneeded
- "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
-};
+static struct termios oldtt;
+static void (*tstp)(int);
-/* This is where we will actually stuff the information */
-
-static char combuf[1024], tbuf[1024];
+static void scr_stop(int);
+static void stopset(int) __dead;
/*
* Routine used by tputs().
*/
int
-put(c)
- int c;
+put(int c)
{
return (putchar(c));
* count=1. (See screen.h for putpad().)
*/
#define putstr(s) (void)fputs(s, stdout)
-#define moveto(r, c) putpad(tgoto(CMstr, c, r))
+
+static void
+moveto(int r, int c)
+{
+ char *buf;
+
+ buf = tiparm(cursor_address, r, c);
+ if (buf != NULL)
+ putpad(buf);
+}
+
+static void
+setcolor(int c)
+{
+ char *buf;
+ if (set_a_foreground == NULL)
+ return;
+
+ buf = tiparm(set_a_foreground, c == 7 ? 0 : c);
+ if (buf != NULL)
+ putpad(buf);
+}
/*
* Set up from termcap.
*/
void
-scr_init()
+scr_init(void)
{
- static int bsflag, xsflag, sgnum;
-#ifdef unneeded
- static int ncflag;
-#endif
- char *term, *fill;
- static struct tcninfo { /* termcap numeric and flag info */
- char tcname[3];
- int *tcaddr;
- } tcflags[] = {
- "bs", &bsflag,
- "ms", &MSflag,
-#ifdef unneeded
- "nc", &ncflag,
-#endif
- "xs", &xsflag,
- 0
- }, tcnums[] = {
- "co", &COnum,
- "li", &LInum,
- "sg", &sgnum,
- 0
- };
-
- if ((term = getenv("TERM")) == NULL)
- stop("you must set the TERM environment variable");
- if (tgetent(tbuf, term) <= 0)
- stop("cannot find your termcap");
- fill = combuf;
- {
- register struct tcsinfo *p;
-
- for (p = tcstrings; p->tcaddr; p++)
- *p->tcaddr = tgetstr(p->tcname, &fill);
- }
- {
- register struct tcninfo *p;
- for (p = tcflags; p->tcaddr; p++)
- *p->tcaddr = tgetflag(p->tcname);
- for (p = tcnums; p->tcaddr; p++)
- *p->tcaddr = tgetnum(p->tcname);
- }
- if (bsflag)
- BC = "\b";
- else if (BC == NULL && bcstr != NULL)
- BC = bcstr;
- if (CLstr == NULL)
+ setupterm(NULL, 0, NULL);
+ if (clear_screen == NULL)
stop("cannot clear screen");
- if (CMstr == NULL || UP == NULL || BC == NULL)
- stop("cannot do random cursor positioning via tgoto()");
- PC = pcstr ? *pcstr : 0;
- if (sgnum >= 0 || xsflag)
- SOstr = SEstr = NULL;
-#ifdef unneeded
- if (ncflag)
- CRstr = NULL;
- else if (CRstr == NULL)
- CRstr = "\r";
-#endif
+ if (cursor_address == NULL || cursor_up == NULL)
+ stop("cannot do random cursor positioning");
}
/* 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;
+stopset(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(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);
}
* Set up screen mode.
*/
void
-scr_set()
+scr_set(void)
{
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 = ws.ws_col;
}
if (Rows == 0)
- Rows = LInum;
+ Rows = lines;
if (Cols == 0)
- Cols = COnum;
+ Cols = columns;
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
* (which we will fix immediately).
*/
- if (TIstr)
- putstr(TIstr); /* termcap(5) says this is not padded */
+ if (enter_ca_mode)
+ putstr(enter_ca_mode);
+ if (cursor_invisible)
+ putstr(cursor_invisible);
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();
}
* End screen mode.
*/
void
-scr_end()
+scr_end(void)
{
- 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 (cursor_to_ll)
+ putstr(cursor_to_ll);
else
moveto(Rows - 1, 0);
/* exit screen mode */
- if (TEstr)
- putstr(TEstr); /* termcap(5) says this is not padded */
+ if (exit_ca_mode)
+ putstr(exit_ca_mode);
+ if (cursor_normal)
+ putstr(cursor_normal);
(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;
+stop(const char *why)
{
if (isset)
* Clear the screen, forgetting the current contents in the process.
*/
void
-scr_clear()
+scr_clear(void)
{
- putpad(CLstr);
+ putpad(clear_screen);
curscore = -1;
- bzero((char *)curscreen, sizeof(curscreen));
+ memset((char *)curscreen, 0, sizeof(curscreen));
}
#if vax && !__GNUC__
* Update the screen.
*/
void
-scr_update()
+scr_update(void)
{
- 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;
if (score != curscore) {
- if (HOstr)
- putpad(HOstr);
+ if (cursor_home)
+ putpad(cursor_home);
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(exit_standout_mode);
+ 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(enter_standout_mode);
+ setcolor(nextshape->color);
+ 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(exit_standout_mode);
+ }
+
bp = &board[D_FIRST * B_COLS];
sp = &curscreen[D_FIRST * B_COLS];
for (j = D_FIRST; j < D_LAST; j++) {
continue;
*sp = so;
if (i != ccol) {
- if (cur_so && MSflag) {
- putpad(SEstr);
+ if (cur_so && move_standout_mode) {
+ putpad(exit_standout_mode);
cur_so = 0;
}
moveto(RTOD(j), CTOD(i));
}
- if (SOstr) {
+ if (enter_standout_mode) {
if (so != cur_so) {
- putpad(so ? SOstr : SEstr);
+ putpad(so ?
+ enter_standout_mode :
+ exit_standout_mode);
cur_so = so;
}
+ setcolor(so);
+#ifdef DEBUG
+ char buf[3];
+ snprintf(buf, sizeof(buf), "%d%d", so, so);
+ putstr(buf);
+#else
putstr(" ");
+#endif
} else
putstr(so ? "XX" : " ");
ccol = i + 1;
}
}
if (cur_so)
- putpad(SEstr);
+ putpad(exit_standout_mode);
(void) fflush(stdout);
- (void) sigsetmask(omask);
+ (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
}
/*
* (We need its length in case we have to overwrite with blanks.)
*/
void
-scr_msg(s, set)
- register char *s;
- int set;
+scr_msg(char *s, int set)
{
- if (set || CEstr == NULL) {
- register int l = strlen(s);
+ if (set || clr_eol == NULL) {
+ int l = strlen(s);
moveto(Rows - 2, ((Cols - l) >> 1) - 1);
if (set)
(void) putchar(' ');
} else {
moveto(Rows - 2, 0);
- putpad(CEstr);
+ putpad(clr_eol);
}
}