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