Subversion Repositories HelenOS-historic

Rev

Rev 1419 | Rev 1519 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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