billr@saab.CNA.TEK.COM (Bill Randle) (06/21/89)
Submitted-by: Mike Taylor <mirk@cs.warwick.ac.uk>
Posting-number: Volume 6, Issue 81
Archive-name: tt/Part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 2)."
# Contents: Logo Makefile game.h pieces.h screen.h tt.h ttscores
# utils.c utils.h
# Wrapped by billr@saab on Wed Jun 21 07:25:47 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Logo' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Logo'\"
else
echo shar: Extracting \"'Logo'\" \(804 characters\)
sed "s/^X//" >'Logo' <<'END_OF_FILE'
XNew from Mirksoft ... "tt" ... An Implementation for Terminals of ...
X
X ________ ________ ________ _______ ________ _______
X %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%_ %%%%%%%% _%%%%%%%
X %% %% %% %% %% %% %%
X %% %%___ %% %%____%% %% %%_____
X %% %%%%% %% %%%%%%_ %% %%%%%%_
X %% %% %% %% %%_ %% %%
X %% %%______ %% %% %% ___%%___ ______%%
X %% %%%%%%%% %% %% %% %%%%%%%% %%%%%%%
X // //////// // // // //////// ///////
X // // // // // // //
X // ///// // ////// // //////
X // // // // // // //
X //////// //////// //////// /////// //////// ///////
X
X (Thanks to the Chief Slime Monster for the Logo)
END_OF_FILE
if test 804 -ne `wc -c <'Logo'`; then
echo shar: \"'Logo'\" unpacked with wrong size!
fi
# end of 'Logo'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1170 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for "tt" - Tetris for Terminals (ie. not just workstations)
X# ====================================================================
X
XSOURCES = tt.c utils.c screen.c pieces.c game.c
XHEADERS = tt.h utils.h screen.h pieces.h game.h
XOBJECTS = tt.o utils.o screen.o pieces.o game.o
X
XLDFLAGS =
XCFLAGS =
XLINTFLAGS = -abh -DLINT
XLIBRARIES = -lcurses -ltermcap
XTIDYUP = | egrep -v 'possible pointer alignment problem' \
X | egrep -v 'long assignment may lose accuracy'
X
X# ---------------------------------------------------------------------------
X
Xtt : $(OBJECTS)
X $(CC) $(LDFLAGS) $(CFLAGS) $(OBJECTS) -o tt $(LIBRARIES)
X
Xttl :
X lint $(LINTFLAGS) $(SOURCES) $(TIDYUP)
X
Xlint :
X lint $(LINTFLAGS) $(SOURCES)
X
Xtags :
X etags *.[ch]
X
Xclean :
X rm -f *.o tt a.out core
X
X# --------------------------------------------------------------------------
X
Xtt.o : tt.c tt.h utils.h screen.h game.h
X
Xutils.o : utils.c utils.h tt.h screen.h
X
Xscreen.o : screen.c screen.h tt.h pieces.h utils.h
X
Xpieces.o : pieces.c pieces.h tt.h
X
Xgame.o : game.c game.h tt.h screen.h pieces.h utils.h
X
X# --------------------------------------------------------------------------
END_OF_FILE
if test 1170 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'game.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'game.h'\"
else
echo shar: Extracting \"'game.h'\" \(2019 characters\)
sed "s/^X//" >'game.h' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* game.h: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This is the module that *|
X|* actually plays the game, (ie. moves things down the *|
X|* screen, select(2)s on the keyboard, and so on) *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
X#define LEFT_KEY ',' /* Move piece left */
X#define RIGHT_KEY '/' /* Move piece right */
X#define ROTATE_KEY '.' /* Rotate piece anticlockwise */
X#define DROP_KEY ' ' /* Drop piece to bottom of screen */
X#define SUSP_KEY 's' /* Suspend. I'm sorry if its confusing */
X#define QUIT_KEY 'q' /* Quit. I'm sorry if its confusing */
X#define CHEAT_KEY 'Z' /* Cheat (a bit) -- Might not help! */
X
X#define REFRESH_KEY '\014' /* Control-L; refreshes screen */
X /* This is hard-coded in. It can't */
X /* be changed by setting TTKEYS, since */
X /* the peasants couldn't handle all that */
X /* "setenv TTKEYS `echo | tr`" carp(anag) */
X
X#define NO_MOVES 4 /* Number of moves allowed per fall */
X
X/*-------------------------------------------------------------------------*/
X
Xextern char left_key; /* Move piece left */
Xextern char right_key; /* Move piece right */
Xextern char rotate_key; /* Rotate piece anticlockwise */
Xextern char drop_key; /* Drop piece to bottom of screen */
Xextern char susp_key; /* Suspend. I'm sorry if its confusing */
Xextern char quit_key; /* Quit. I'm sorry if its confusing */
Xextern char cheat_key; /* Frogging identical comments :-P */
X
X/*-------------------------------------------------------------------------*/
X
Xextern void clear_board ();
Xextern void play_game ();
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 2019 -ne `wc -c <'game.h'`; then
echo shar: \"'game.h'\" unpacked with wrong size!
fi
# end of 'game.h'
fi
if test -f 'pieces.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pieces.h'\"
else
echo shar: Extracting \"'pieces.h'\" \(843 characters\)
sed "s/^X//" >'pieces.h' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* pieces.h: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This module contains the *|
X|* definitions of the pieces. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
Xstruct piece {
X char app[3];
X int points;
X int index[NO_ORIENTS][NO_SQUARES][NO_DIMS];
X};
X
X/*-------------------------------------------------------------------------*/
X
Xextern struct piece pieces[NO_PIECES];
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 843 -ne `wc -c <'pieces.h'`; then
echo shar: \"'pieces.h'\" unpacked with wrong size!
fi
# end of 'pieces.h'
fi
if test -f 'screen.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'screen.h'\"
else
echo shar: Extracting \"'screen.h'\" \(1347 characters\)
sed "s/^X//" >'screen.h' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* screen.h: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This module handles all *|
X|* the icky curses(3x) bits. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
X#define WALL_CHAR '|' /* Character used for sides of pay-area */
X#define FLOOR_CHAR '=' /* Character used for base-line */
X#define CORNER_CHAR '+' /* Character used bottom left and right */
X#define BLANK_CHAR ' ' /* Character used elsewhere */
X
X#define PD_DRAW 0 /* Code to draw piece */
X#define PD_ERASE 1 /* Code to erase piece */
X
X/*-------------------------------------------------------------------------*/
X
Xextern void myrefresh ();
Xextern void hoopy_refresh ();
Xextern void print_msg ();
Xextern void clear_area ();
Xextern void setup_screen ();
Xextern void setup_curses ();
Xextern void update_scores ();
Xextern void draw_board ();
Xextern void draw_piece ();
Xextern void place_piece ();
Xextern int can_place ();
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 1347 -ne `wc -c <'screen.h'`; then
echo shar: \"'screen.h'\" unpacked with wrong size!
fi
# end of 'screen.h'
fi
if test -f 'tt.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tt.h'\"
else
echo shar: Extracting \"'tt.h'\" \(6693 characters\)
sed "s/^X//" >'tt.h' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* tt.h: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X/***************************************************************************\
X|* *|
X|* The following macro, if defined, causes the exclusive high-score *|
X|* file-locking to be done using lockf(3) instead of the O_EXCL flag *|
X|* on open(2). This means that no temporary file need be created, and *|
X|* thus, that no write-permission is needed on a lockfile-directory. *|
X|* This should probably be used in preference to open(O_EXCL) when it *|
X|* exists and is bugless. WARNING: on some machines, buggy versions *|
X|* of lockf(3) can crash the machine, (eg. Sun3/4s running SunOS 4.0.1) *|
X|* *|
X\***************************************************************************/
X
X#define LOCKF /* Use lockf(3) instead of open(O_EXCL) */
X
X/***************************************************************************\
X|* *|
X|* File in which high-scores will be stored. I'm not gonna muck *|
X|* about encrypting them or anything, so you can either make tt *|
X|* setuid, or just run the risk of stupid people editing the high- *|
X|* score table by hand. *|
X|* *|
X\***************************************************************************/
X
X#define LOCK_FILE "/poppy/ma/ujf/open/lib/junk/ttlock"
X#define SCORE_FILE "/poppy/ma/ujf/open/lib/ttscores"
X
X/*-------------------------------------------------------------------------*/
X
X#define NO_HISCORES 100 /* Size of high-score table */
X#define NO_SHOWN 10 /* Default number to print */
X#define LINELEN 160 /* Maximum length of a line of text */
X#define NAMELEN 24 /* Multiple of four for struct-padding */
X#define CODELEN 12 /* Multiple of four for struct-padding */
X
X#define GAME_WIDTH 10 /* Number of squares across board */
X#define GAME_DEPTH 20 /* Number of squares down board */
X#define STAT_WIDTH 37 /* Number of characters for messages */
X
X#define NO_PIECES 7 /* Number of different pieces */
X#define NO_ORIENTS 4 /* Number of orientations possible */
X#define NO_SQUARES 4 /* Max. number of squares per piece */
X#define NO_DIMS 2 /* Number of dimensions of screen */
X
X#define PI_EMPTY -1 /* Position of board is empty */
X#define PI_SQUARE 0 /* Square piece */
X#define PI_LONG 1 /* Long piece */
X#define PI_ELL1 2 /* L-shaped piece */
X#define PI_ELL2 3 /* Backwards L-shaped piece */
X#define PI_TEE 4 /* T-shaped piece */
X#define PI_ESS1 5 /* S-shaped piece */
X#define PI_ESS2 6 /* Backwards S-shaped piece */
X
X/***************************************************************************\
X|* *|
X|* The following #defines, (the LE_* ones) are local errors, in the *|
X|* sense of being local to this program, as distinct from the system *|
X|* errors, (ENOENT, EINTR and friends). They should be used as exit *|
X|* statuses, as the first argument to die(), defined in utils.c *|
X|* *|
X\***************************************************************************/
X
X#define LE_OK 0 /* No problems, me ole' fruit-bat */
X#define LE_USAGE 1 /* Command-line syntax was wrong */
X#define LE_ENV 2 /* Couldn't get environment variable */
X#define LE_TERMCAP 3 /* Couldn't get a termcap entry */
X#define LE_SCREEN 4 /* Screen was too small for game */
X#define LE_SIGNAL 5 /* Signal(3) call failed */
X#define LE_SELECT 6 /* Select(2) call failed */
X#define LE_READ 7 /* Read(2) call failed */
X#define LE_MALLOC 8 /* Couldn't allocate memory */
X#define LE_LEVEL 9 /* User wanted to play on a silly level */
X#define LE_OPEN 10 /* Open(2) call failed */
X#define LE_STAT 11 /* {f,l,}stat(2) call failed */
X#define LE_WRITE 12 /* write(2) call failed */
X#define LE_GETUID 13 /* getuid(2) call failed */
X#define LE_GETPW 14 /* getpwuid(3) call failed */
X
X/***************************************************************************\
X|* *|
X|* This is the structure of which the high-score table is composed. *|
X|* I'm gonna make everything a muliple of four bytes in an attempt *|
X|* to maintain file-compatibility between sun3s and 4s (and maybe *|
X|* other things, who knows?) This is also why all the integers are *|
X|* long -- this helps to ensure that they will be four bytes long on *|
X|* most architectures, (ie. including some that have 2-byte integers) *|
X|* thus making struct-compatibility more likely. *|
X|* *|
X\***************************************************************************/
X
Xstruct score_ent {
X char name[NAMELEN]; /* Name of player (from environment) */
X char code[CODELEN]; /* Code of player (from getpwuid()) */
X long int score; /* Total score (5 for an "S" etc.) */
X long int no_pieces; /* Number of pieces dropped in */
X long int no_levels; /* Number of levels completed */
X long int game_level; /* Number of free pieces at start */
X};
X
X/*-------------------------------------------------------------------------*/
X
Xextern int screen_depth; /* To be calculated by termcap(3) */
Xextern int screen_width; /* To be calculated by termcap(3) */
Xextern int so_gunk; /* To be calculated by termcap(3) */
Xextern int in_curses; /* Set to 1 after initialisation */
Xextern int rotate_backwards; /* If set non-zero, rotate clockwise */
Xextern int no_hiscores; /* Number of hi-scores in the table */
Xextern int game_level; /* Number of free pieces */
Xextern int score; /* Accumulated game score */
Xextern int no_pieces; /* Number of pieces dropped so far */
Xextern int no_levels; /* Number of levels filled & deleted */
Xextern char prog_name[LINELEN]; /* Will be the basename of argv[0] */
Xextern char user_name[NAMELEN]; /* From environment: TTNAME or NAME */
Xextern char user_code[CODELEN]; /* From getpwuid(getuid())->pw_name */
Xextern int board[GAME_DEPTH+4][GAME_WIDTH];
Xextern struct score_ent hi_scores[NO_HISCORES];
X
Xextern char tc_string[LINELEN]; /* Static, filled by termcap(3) */
Xextern char *so_str; /* Points at things found by termcap(3) */
Xextern char *se_str; /* Points at things found by termcap(3) */
X
X/*-------------------------------------------------------------------------*/
X
Xextern void signal_die (); /* When CTRL-C etc. is pressed */
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 6693 -ne `wc -c <'tt.h'`; then
echo shar: \"'tt.h'\" unpacked with wrong size!
fi
# end of 'tt.h'
fi
if test -f 'ttscores' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'ttscores'\"
else
echo shar: Extracting \"'ttscores'\" \(7172 characters\)
sed "s/^X//" >'ttscores' <<'END_OF_FILE'
XRuth 'Vashti' GlassboroXPaul CapperXXS ShipwayXHector the SpectreXMirk the ProgrammerXPaul 'Freddy' CapperXWarwick University EvanEND_OF_FILE
Xecho shar: 1 control character may be missing from \"'ttscores'\"
Xif test 3796 -ne `wc -c <'ttscores'`; then
X echo shar: \"'ttscores'\" unpacked with wrong size!
Xfi
X# end of 'ttscores'
Xfi
Xif test -f 'utils.c' -a "${1}" != "-c" ; then
X echo shar: Will not clobber existing file \"'utils.c'\"
Xelse
Xecho shar: Extracting \"'utils.c'\" \(6633 characters\)
Xsed "s/^X//" >'utils.c' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* utils.c: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This module supplies all *|
X|* the function that I will need, but which are not *|
X|* intrinsically a part of Tetris itself. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
X#include <varargs.h>
X#include <curses.h>
X#include <strings.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <errno.h>
X
X#include "tt.h"
X#include "utils.h"
X#include "screen.h"
X
X/*-------------------------------------------------------------------------*/
X
Xextern char *rindex ();
Xextern char *getenv ();
X
X/***************************************************************************\
X|* *|
X|* The function basename() acts like the UNIX(tm) command of the same *|
X|* name. It takes as its argument a string, and returns the last path- *|
X|* component of that string, (ie, the section after the last '/'), or *|
X|* the whole string if it has no '/'. *|
X|* *|
X\***************************************************************************/
X
Xchar *basename (name)
X char *name;
X{
X char *slash;
X if (slash = rindex (name, '/'))
X return (slash+1);
X else
X return (name);
X}
X
X/***************************************************************************\
X|* *|
X|* This is my home-made varargs-based version of C++'s neat function of *|
X|* the same name. It saves all that tedious mucking about with static *|
X|* buffers which you sprintf into, then forget all about, by basically *|
X|* being a sprintf with its own statis storage. It takes as arguments *|
X|* exactly the same things as printf(3), and returns a pointer to the *|
X|* resultant string. *|
X|* *|
X\***************************************************************************/
X
X/*VARARGS*/
Xchar *form (va_alist)
X va_dcl
X{
X va_list pvar;
X char *fmt_string;
X static char result[LINELEN];
X
X va_start (pvar);
X fmt_string = va_arg (pvar, char*);
X (void) vsprintf (result, fmt_string, pvar);
X va_end (pvar);
X return (result);
X}
X
X/***************************************************************************\
X|* *|
X|* This is yer bog-standard "print a message and quit" function, except *|
X|* that it checks to see if we are in curses(3x), and if so, takes us *|
X|* out before doing its stuff. The arguments are an integer, the exit *|
X|* status, and a string containing an error report, to which will be *|
X|* prepended the program name when it is printed. If the status code *|
X|* is LE_OK, (ie. nothing went wrong), no message is printed. *|
X|* *|
X\***************************************************************************/
X
Xvoid die (status, line)
X int status;
X char *line;
X{
X if (in_curses) {
X myrefresh ();
X#ifndef LINT
X nocbreak ();
X echo ();
X#endif /* LINT */
X endwin ();
X }
X
X if (status != LE_OK)
X (void) printf ("%s: %s\n", prog_name, line);
X
X#ifndef LOCKF
X (void) unlink (LOCK_FILE); /* Just in case :-) */
X#endif /* LOCKF */
X exit (status);
X}
X
X/***************************************************************************\
X|* *|
X|* The function get_termcap extracts the information we need from the *|
X|* UNIX terminal capability database. It has been (correctly) pointed *|
X|* out that most of what I do in this function is already done for me *|
X|* by curses(3x), but (A) curses behaves stupidly on terminals with *|
X|* termcap's "sg" non-zero, (ie. refuses to enter standout mode, so *|
X|* you *have* to do it manually), and (B) I wanted to prove a point to *|
X|* Sunny and others, who said it was impossible. Tgets() sucks :-P *|
X|* *|
X\***************************************************************************/
X
Xvoid get_termcap ()
X{
X static char bp[1024]; /* Seems odd to hardwire the 1024, but ... */
X char *term_name; /* ... the manual entry told me to do it! */
X int status; /* Success/failure of tgetent here */
X char *tmp_ptr = tc_string; /* Pointer to be advanced by tgetstr() */
X
X if ((term_name = getenv ("TERM")) == NULL)
X die (LE_ENV, "couldn't get TERM from environment");
X
X if ((status = tgetent (bp, term_name)) == -1)
X die (LE_TERMCAP, "couldn't open TERMCAP file");
X
X if (status == 0)
X die (LE_TERMCAP, "couldn't find your terminal in TERMCAP file");
X
X if ((screen_depth = tgetnum ("li")) == -1)
X die (LE_TERMCAP, "couldn't get screen-depth from termcap");
X
X if ((screen_width = tgetnum ("co")) == -1)
X die (LE_TERMCAP, "couldn't get screen-width from termcap");
X
X if ((so_gunk = tgetnum ("sg")) == -1)
X so_gunk = 0; /* Default value */
X
X so_str = tmp_ptr;
X if (tgetstr ("so", &tmp_ptr) == NULL)
X die (LE_TERMCAP, "couldn't get standout code from termcap");
X
X se_str = tmp_ptr;
X if (tgetstr ("se", &tmp_ptr) == NULL)
X die (LE_TERMCAP, "couldn't get standend code from termcap");
X}
X
X/***************************************************************************\
X|* *|
X|* The function flush_keybord() checks to see whether there are any *|
X|* keystrokes waiting to be read, and if so reads them and throws *|
X|* them away. Surprising how complex this needs to be, but the only *|
X|* alternative I can think of is to ioctl() stdin to be non-blocking, *|
X|* read() until it returns 0, then ioctl() it back, which is scarcely *|
X|* an improvement. *|
X|* *|
X\***************************************************************************/
X
Xvoid flush_keyboard ()
X{
X fd_set fds; /* Will contain only stdin */
X struct timeval timeout; /* Will contain a zero timeout (poll) */
X static char buffer[LINELEN]; /* Will be used as the buffer to read(2) */
X int status; /* Contains select(2)'s return value */
X
X while (1) {
X FD_ZERO (&fds);
X FD_SET (0, &fds);
X timeout.tv_sec = 0L;
X timeout.tv_usec = 0L;
X if (((status = select (1, &fds, (fd_set*) NULL, (fd_set*) NULL,
X &timeout)) == -1) && (errno != EINTR))
X die (LE_SELECT, "select(2) failed in flush_keybord()");
X if ((status == 0) || (status == -1))
X break; /* Can only be -1 if errno == EINTR */
X (void) read (0, buffer, LINELEN);
X }
X}
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 7172 -ne `wc -c <'ttscores'`; then
echo shar: \"'ttscores'\" unpacked with wrong size!
fi
# end of 'ttscores'
fi
if test -f 'utils.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'utils.c'\"
else
echo shar: Extracting \"'utils.c'\" \(6633 characters\)
sed "s/^X//" >'utils.c' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* utils.c: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This module supplies all *|
X|* the function that I will need, but which are not *|
X|* intrinsically a part of Tetris itself. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
X#include <varargs.h>
X#include <curses.h>
X#include <strings.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <errno.h>
X
X#include "tt.h"
X#include "utils.h"
X#include "screen.h"
X
X/*-------------------------------------------------------------------------*/
X
Xextern char *rindex ();
Xextern char *getenv ();
X
X/***************************************************************************\
X|* *|
X|* The function basename() acts like the UNIX(tm) command of the same *|
X|* name. It takes as its argument a string, and returns the last path- *|
X|* component of that string, (ie, the section after the last '/'), or *|
X|* the whole string if it has no '/'. *|
X|* *|
X\***************************************************************************/
X
Xchar *basename (name)
X char *name;
X{
X char *slash;
X if (slash = rindex (name, '/'))
X return (slash+1);
X else
X return (name);
X}
X
X/***************************************************************************\
X|* *|
X|* This is my home-made varargs-based version of C++'s neat function of *|
X|* the same name. It saves all that tedious mucking about with static *|
X|* buffers which you sprintf into, then forget all about, by basically *|
X|* being a sprintf with its own statis storage. It takes as arguments *|
X|* exactly the same things as printf(3), and returns a pointer to the *|
X|* resultant string. *|
X|* *|
X\***************************************************************************/
X
X/*VARARGS*/
Xchar *form (va_alist)
X va_dcl
X{
X va_list pvar;
X char *fmt_string;
X static char result[LINELEN];
X
X va_start (pvar);
X fmt_string = va_arg (pvar, char*);
X (void) vsprintf (result, fmt_string, pvar);
X va_end (pvar);
X return (result);
X}
X
X/***************************************************************************\
X|* *|
X|* This is yer bog-standard "print a message and quit" function, except *|
X|* that it checks to see if we are in curses(3x), and if so, takes us *|
X|* out before doing its stuff. The arguments are an integer, the exit *|
X|* status, and a string containing an error report, to which will be *|
X|* prepended the program name when it is printed. If the status code *|
X|* is LE_OK, (ie. nothing went wrong), no message is printed. *|
X|* *|
X\***************************************************************************/
X
Xvoid die (status, line)
X int status;
X char *line;
X{
X if (in_curses) {
X myrefresh ();
X#ifndef LINT
X nocbreak ();
X echo ();
X#endif /* LINT */
X endwin ();
X }
X
X if (status != LE_OK)
X (void) printf ("%s: %s\n", prog_name, line);
X
X#ifndef LOCKF
X (void) unlink (LOCK_FILE); /* Just in case :-) */
X#endif /* LOCKF */
X exit (status);
X}
X
X/***************************************************************************\
X|* *|
X|* The function get_termcap extracts the information we need from the *|
X|* UNIX terminal capability database. It has been (correctly) pointed *|
X|* out that most of what I do in this function is already done for me *|
X|* by curses(3x), but (A) curses behaves stupidly on terminals with *|
X|* termcap's "sg" non-zero, (ie. refuses to enter standout mode, so *|
X|* you *have* to do it manually), and (B) I wanted to prove a point to *|
X|* Sunny and others, who said it was impossible. Tgets() sucks :-P *|
X|* *|
X\***************************************************************************/
X
Xvoid get_termcap ()
X{
X static char bp[1024]; /* Seems odd to hardwire the 1024, but ... */
X char *term_name; /* ... the manual entry told me to do it! */
X int status; /* Success/failure of tgetent here */
X char *tmp_ptr = tc_string; /* Pointer to be advanced by tgetstr() */
X
X if ((term_name = getenv ("TERM")) == NULL)
X die (LE_ENV, "couldn't get TERM from environment");
X
X if ((status = tgetent (bp, term_name)) == -1)
X die (LE_TERMCAP, "couldn't open TERMCAP file");
X
X if (status == 0)
X die (LE_TERMCAP, "couldn't find your terminal in TERMCAP file");
X
X if ((screen_depth = tgetnum ("li")) == -1)
X die (LE_TERMCAP, "couldn't get screen-depth from termcap");
X
X if ((screen_width = tgetnum ("co")) == -1)
X die (LE_TERMCAP, "couldn't get screen-width from termcap");
X
X if ((so_gunk = tgetnum ("sg")) == -1)
X so_gunk = 0; /* Default value */
X
X so_str = tmp_ptr;
X if (tgetstr ("so", &tmp_ptr) == NULL)
X die (LE_TERMCAP, "couldn't get standout code from termcap");
X
X se_str = tmp_ptr;
X if (tgetstr ("se", &tmp_ptr) == NULL)
X die (LE_TERMCAP, "couldn't get standend code from termcap");
X}
X
X/***************************************************************************\
X|* *|
X|* The function flush_keybord() checks to see whether there are any *|
X|* keystrokes waiting to be read, and if so reads them and throws *|
X|* them away. Surprising how complex this needs to be, but the only *|
X|* alternative I can think of is to ioctl() stdin to be non-blocking, *|
X|* read() until it returns 0, then ioctl() it back, which is scarcely *|
X|* an improvement. *|
X|* *|
X\***************************************************************************/
X
Xvoid flush_keyboard ()
X{
X fd_set fds; /* Will contain only stdin */
X struct timeval timeout; /* Will contain a zero timeout (poll) */
X static char buffer[LINELEN]; /* Will be used as the buffer to read(2) */
X int status; /* Contains select(2)'s return value */
X
X while (1) {
X FD_ZERO (&fds);
X FD_SET (0, &fds);
X timeout.tv_sec = 0L;
X timeout.tv_usec = 0L;
X if (((status = select (1, &fds, (fd_set*) NULL, (fd_set*) NULL,
X &timeout)) == -1) && (errno != EINTR))
X die (LE_SELECT, "select(2) failed in flush_keybord()");
X if ((status == 0) || (status == -1))
X break; /* Can only be -1 if errno == EINTR */
X (void) read (0, buffer, LINELEN);
X }
X}
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 6633 -ne `wc -c <'utils.c'`; then
echo shar: \"'utils.c'\" unpacked with wrong size!
fi
# end of 'utils.c'
fi
if test -f 'utils.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'utils.h'\"
else
echo shar: Extracting \"'utils.h'\" \(827 characters\)
sed "s/^X//" >'utils.h' <<'END_OF_FILE'
X/***************************************************************************\
X|* *|
X|* utils.h: A version of Tetris to run on ordinary terminals, *|
X|* (ie., not needing a workstation, so should available *|
X|* to peasant Newwords+ users. This module supplies all *|
X|* the function that I will need, but which are not *|
X|* intrinsically a part of Tetris itself. *|
X|* *|
X|* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *|
X|* Started: Fri May 26 12:26:05 BST 1989 *|
X|* *|
X\***************************************************************************/
X
Xextern char *basename ();
Xextern char *form ();
Xextern void die ();
Xextern void get_termcap ();
Xextern void flush_keyboard ();
X
X/*-------------------------------------------------------------------------*/
END_OF_FILE
if test 827 -ne `wc -c <'utils.h'`; then
echo shar: \"'utils.h'\" unpacked with wrong size!
fi
# end of 'utils.h'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0