Subversion Repositories HelenOS

Rev

Rev 1419 | Rev 1519 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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