]> git.deb.at Git - pkg/netris.git/blob - util.c
Imported Debian patch 0.52-6
[pkg/netris.git] / util.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id: util.c,v 1.29 1999/05/16 06:56:33 mhw Exp $
20  */
21
22 #include "netris.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <netdb.h>
30 #include <errno.h>
31
32 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
33
34 static EventGenRec alarmGen =
35                 { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
36 static EventGenRec *nextGen = &alarmGen;
37
38 static myRandSeed = 1;
39
40 static struct timeval baseTimeval;
41
42 ExtFunc void InitUtil(void)
43 {
44         if (initSeed)
45                 SRandom(initSeed);
46         else
47                 SRandom(time(0));
48         signal(SIGINT, CatchInt);
49         ResetBaseTime();
50 }
51
52 ExtFunc void ResetBaseTime(void)
53 {
54         gettimeofday(&baseTimeval, NULL);
55 }
56
57 ExtFunc void AtExit(void (*handler)(void))
58 {
59 #ifdef HAS_ON_EXIT
60         on_exit((void *)handler, NULL);
61 #else
62         atexit(handler);
63 #endif
64 }
65
66 ExtFunc void Usage(void)
67 {
68         fprintf(stderr,
69           "Netris version %s (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>\n"
70           "Usage: netris <options>\n"
71           "  -h         Print usage information\n"
72           "  -w         Wait for connection\n"
73           "  -c <host>  Initiate connection\n"
74           "  -p <port>  Set port number (default is %d)\n"
75           "  -k <keys>  Remap keys.  The argument is a prefix of the string\n"
76           "               containing the keys in order: left, rotate, right, drop,\n"
77           "               down-faster, toggle-spying, pause, faster, redraw, new.\n"
78           "               \"^\" prefixes controls.  (default is \"%s\")\n"
79           "  -i <sec>   Set the step-down interval, in seconds\n"
80           "  -r <robot> Execute <robot> (a command) as a robot controlling\n"
81           "               the game instead of the keyboard\n"
82           "  -F         Use fair robot interface\n"
83           "  -s <seed>  Start with given random seed\n"
84           "  -D         Drops go into drop mode\n"
85           "               This means that sliding off a cliff after a drop causes\n"
86           "               another drop automatically\n"
87           "  -S         Disable inverse/bold/color for slow terminals\n"
88           "  -C         Disable color\n"
89           "  -H         Show distribution and warranty information\n"
90           "  -R         Show rules\n",
91           version_string, DEFAULT_PORT, DEFAULT_KEYS);
92 }
93
94 ExtFunc void DistInfo(void)
95 {
96         fprintf(stderr,
97           "Netris version %s (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>\n"
98           "\n"
99           "This program is free software; you can redistribute it and/or modify\n"
100           "it under the terms of the GNU General Public License as published by\n"
101           "the Free Software Foundation; either version 2 of the License, or\n"
102           "(at your option) any later version.\n"
103           "\n"
104           "This program is distributed in the hope that it will be useful,\n"
105           "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
106           "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
107           "GNU General Public License for more details.\n"
108           "\n"
109           "You should have received a copy of the GNU General Public License\n"
110           "along with this program; if not, write to the Free Software\n"
111           "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n",
112           version_string);
113 }
114
115 ExtFunc void Rules(void)
116 {
117         fprintf(stderr,
118           "Netris version %s rules\n"
119           "\n"
120           "Two player mode\n"
121           "---------------\n"
122           "It's just like normal T*tris except that when you clear more than\n"
123           "one row with a single piece, the other player's board is moved up\n"
124           "and junk rows are added to the bottom.  If you clear 2, 3 or 4\n"
125           "rows, 1, 2 or 4 junk rows are added to your opponent's board,\n"
126           "respectively.  The junk rows have exactly one empty column.\n"
127           "For each group of junk rows given, the empty columns will line\n"
128           "up.  This is intentional.\n"
129           "\n"
130           "The longest surviving player wins the game.\n"
131           "\n"
132           "One player mode\n"
133           "---------------\n"
134           "This mode is currently very boring, because there's no scoring\n"
135           "and it never gets any faster.  This will be rectified at some point.\n"
136           "I'm not very motivated to do it right now because I'm sick of one\n"
137           "player T*tris.  For now, use the \"f\" key (by default) to make the\n"
138           "game go faster.  Speedups cannot be reversed for the remainder of\n"
139           "the game.\n",
140           version_string);
141 }
142
143 /*
144  * My really crappy random number generator follows
145  * Should be more than sufficient for our purposes though
146  */
147 ExtFunc void SRandom(int seed)
148 {
149         initSeed = seed;
150         myRandSeed = seed % 31751 + 1;
151 }
152
153 ExtFunc int Random(int min, int max1)
154 {
155         myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
156         return myRandSeed % (max1 - min) + min;
157 }
158
159 ExtFunc int MyRead(int fd, void *data, int len)
160 {
161         int result, left;
162
163         left = len;
164         while (left > 0) {
165                 result = read(fd, data, left);
166                 if (result > 0) {
167                         data = ((char *)data) + result;
168                         left -= result;
169                 }
170                 else if (errno != EINTR)
171                         return result;
172         }
173         return len;
174 }
175
176 ExtFunc int MyWrite(int fd, void *data, int len)
177 {
178         int result, left;
179
180         left = len;
181         while (left > 0) {
182                 result = write(fd, data, left);
183                 if (result > 0) {
184                         data = ((char *)data) + result;
185                         left -= result;
186                 }
187                 else if (errno != EINTR)
188                         return result;
189         }
190         return len;
191 }
192
193 ExtFunc void NormalizeTime(struct timeval *tv)
194 {
195         tv->tv_sec += tv->tv_usec / 1000000;
196         tv->tv_usec %= 1000000;
197         if (tv->tv_usec < 0) {
198                 tv->tv_usec += 1000000;
199                 --tv->tv_sec;
200         }
201 }
202
203 ExtFunc void CatchInt(int sig)
204 {
205         exit(0);
206 }
207
208 ExtFunc void CatchAlarm(int sig)
209 {
210         alarmGen.ready = 1;
211         signal(SIGALRM, CatchAlarm);
212 }
213
214 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
215 {
216         return E_alarm;
217 }
218
219 ExtFunc long CurTimeval(void)
220 {
221         struct timeval tv;
222
223         gettimeofday(&tv, NULL);
224         tv.tv_sec -= baseTimeval.tv_sec;
225         tv.tv_usec -= baseTimeval.tv_usec;
226         return GetTimeval(&tv);
227 }
228
229 ExtFunc void SetTimeval(struct timeval *tv, long usec)
230 {
231         tv->tv_sec = usec / 1000000;
232         tv->tv_usec = usec % 1000000;
233 }
234
235 ExtFunc long GetTimeval(struct timeval *tv)
236 {
237         return tv->tv_sec * 1000000 + tv->tv_usec;
238 }
239
240 static long SetITimer1(long interval, long value)
241 {
242         struct itimerval it, old;
243
244         SetTimeval(&it.it_interval, interval);
245         SetTimeval(&it.it_value, value);
246         if (setitimer(ITIMER_REAL, &it, &old) < 0)
247                 die("setitimer");
248         signal(SIGALRM, CatchAlarm);
249         return GetTimeval(&old.it_value);
250 }
251
252 ExtFunc long SetITimer(long interval, long value)
253 {
254         long old;
255
256         old = SetITimer1(0, 0);
257         alarmGen.ready = 0;
258         SetITimer1(interval, value);
259         return old;
260 }
261
262 ExtFunc volatile void die(char *msg)
263 {
264         perror(msg);
265         exit(1);
266 }
267
268 ExtFunc volatile void fatal(char *msg)
269 {
270         CleanupScreens ();
271         fprintf(stderr, "%s\n", msg);
272         exit(1);
273 }
274
275 ExtFunc void BlockSignals(MySigSet *saved, ...)
276 {
277         MySigSet set;
278         va_list args;
279         int sig;
280
281         va_start(args, saved);
282 #ifdef HAS_SIGPROCMASK
283         sigemptyset(&set);
284 #else
285         set = 0;
286 #endif
287         while ((sig = va_arg(args, int))) {
288 #ifdef HAS_SIGPROCMASK
289                 sigaddset(&set, sig);
290 #else
291                 sig |= sigmask(sig);
292 #endif
293         }
294 #ifdef HAS_SIGPROCMASK
295         sigprocmask(SIG_BLOCK, &set, saved);
296 #else
297         *saved = sigblock(set);
298 #endif
299         va_end(args);
300 }
301
302 ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
303 {
304 #ifdef HAS_SIGPROCMASK
305         sigprocmask(SIG_SETMASK, set, saved);
306 #else
307         if (saved)
308                 *saved = sigsetmask(*set);
309         else
310                 sigsetmask(*set);
311 #endif
312 }
313
314 ExtFunc void AddEventGen(EventGenRec *gen)
315 {
316         assert(gen->next == NULL);
317         gen->next = nextGen->next;
318         nextGen->next = gen;
319 }
320
321 ExtFunc void RemoveEventGen(EventGenRec *gen)
322 {
323         /* assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
324         if (gen->next) {
325                 while (nextGen->next != gen)
326                         nextGen = nextGen->next;
327                 nextGen->next = gen->next;
328                 gen->next = NULL;
329         }
330 }
331
332 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
333 {
334         int i, retry = 0;
335         fd_set fds[FT_len];
336         EventGenRec *gen;
337         int result, anyReady, anySet;
338         struct timeval tv;
339
340         /* XXX In certain circumstances, this routine does polling */
341         for (;;) {
342                 for (i = 0; i < FT_len; ++i)
343                         FD_ZERO(&fds[i]);
344                 anyReady = anySet = 0;
345                 gen = nextGen;
346                 do {
347                         if (gen->mask & mask) {
348                                 if (gen->ready)
349                                         anyReady = 1;
350                                 if (gen->fd >= 0) {
351                                         FD_SET(gen->fd, &fds[gen->fdType]);
352                                         anySet = 1;
353                                 }
354                         }
355                         gen = gen->next;
356                 } while (gen != nextGen);
357                 if (anySet) {
358                         tv.tv_sec = 0;
359                         tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
360                         result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
361                                         &fds[FT_except], anyReady ? &tv : NULL);
362                 }
363                 else {
364                         if (retry && !anyReady)
365                                 sleep(1);
366                         result = 0;
367                 }
368                 gen = nextGen;
369                 do {
370                         if ((gen->mask & mask)
371                                         && (gen->ready || (result > 0 && gen->fd >= 0
372                                                 && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
373                                 gen->ready = 0;
374                                 event->type = gen->func(gen, event);
375                                 if (event->type != E_none) {
376                                         nextGen = gen->next;
377                                         return event->type;
378                                 }
379                         }
380                         gen = gen->next;
381                 } while (gen != nextGen);
382                 retry = 1;
383         }
384 }
385
386 /*
387  * vi: ts=4 ai
388  * vim: noai si
389  */