move client usage help from shared code
[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
20 #include "netris.h"
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <netdb.h>
28 #include <errno.h>
29 #include <setjmp.h>
30
31 #include "util.h"
32
33 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
34 static EventGenRec alarmGen = {
35         &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm
36 };
37 static EventGenRec *nextGen = &alarmGen;
38
39 static int myRandSeed = 1;
40
41 static long baseTimeval;
42
43
44 void AtExit(void (*handler)(void))
45 {
46 #ifdef HAS_ON_EXIT
47         on_exit((void *)handler, NULL);
48 #else
49         atexit(handler);
50 #endif
51 }
52
53 ///////////// HELP MESSAGES /////////////
54
55 void Header(void)
56 {
57         fprintf(stderr,
58                 "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
59                 "          \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
60                 version_string
61         );
62 }
63
64 void DistInfo(void)
65 {
66         fprintf(stderr,
67                 "This program is free software; you can redistribute it and/or modify\n"
68                 "it under the terms of the GNU General Public License as published by\n"
69                 "the Free Software Foundation; either version 2 of the License, or\n"
70                 "(at your option) any later version.\n"
71                 "\n"
72                 "This program is distributed in the hope that it will be useful,\n"
73                 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
74                 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
75                 "GNU General Public License for more details.\n"
76                 "\n"
77                 "You should have received a copy of the GNU General Public License\n"
78                 "along with this program; if not, write to the Free Software\n"
79                 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
80                 "\n"
81         );
82 }
83
84 void Rules(void)
85 {
86         Header();
87         fprintf(stderr,
88                 "One player mode\n"
89                 "---------------\n"
90                 "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
91                 "remove as many lines at once as you can). After removing ten lines\n"
92                 "you go to the next level, which will be faster thus making the game\n"
93                 "harder to play.\n"
94                 "\n"
95                 "Two player mode\n"
96                 "---------------\n"
97                 "It's just like normal T*tris except that when you clear more than\n"
98                 "one row with a single piece, the other player receives penalty lines\n"
99                 "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
100                 "be added to the bottom of your opponent's board respectively.\n"
101                 "The junk rows have exactly one empty column, which will line up for\n"
102                 "multiple rows.\n"
103                 "\n"
104                 "The longest surviving player wins the game.\n"
105                 "\n"
106         );
107 }
108
109 ///////////// RANDOM /////////////
110
111 /*
112  * My really crappy random number generator follows
113  * Should be more than sufficient for our purposes though
114  */
115 void SRandom(int seed)
116 {
117         Game.seed = seed;
118         myRandSeed = seed % 31751 + 1;
119 }
120
121 int Random(int min, int max1)
122 { //return a random value
123         myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
124         return myRandSeed % (max1 - min) + min;
125 }
126
127 ///////////// I/O /////////////
128
129 int MyRead(int fd, void *data, int len)
130 {
131         int result, left;
132
133         left = len;
134         while (left > 0) {
135                 result = read(fd, data, left);
136                 if (result > 0) {
137                         data = ((char *)data) + result;
138                         left -= result;
139                 }
140                 else if (errno != EINTR)
141                         return result;
142         }
143         return len;
144 }
145
146 int MyWrite(int fd, void *data, int len)
147 {
148         int result, left;
149
150         left = len;
151         while (left > 0) {
152                 result = write(fd, data, left);
153                 if (result > 0) {
154                         data = ((char *)data) + result;
155                         left -= result;
156                 }
157                 else if (errno != EINTR)
158                         return result;
159         }
160         return len;
161 }
162
163 ///////////// TIME /////////////
164
165 void NormalizeTime(struct timeval *tv)
166 {
167         tv->tv_sec += tv->tv_usec / 1000000;
168         tv->tv_usec %= 1000000;
169         if (tv->tv_usec < 0) {
170                 tv->tv_usec += 1000000;
171                 --tv->tv_sec;
172         }
173 }
174
175 void CatchAlarm(int sig)
176 {
177         alarmGen.ready = 1;
178         signal(SIGALRM, CatchAlarm);
179 }
180
181 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
182 {
183         return E_alarm;
184 }
185
186 void SetTimeval(struct timeval *tv, long usec)
187 {
188         tv->tv_sec = usec / 1000000;
189         tv->tv_usec = usec % 1000000;
190 }
191
192 long GetTimeval(struct timeval *tv)
193 {
194         return tv->tv_sec * 1000000 + tv->tv_usec;
195 }
196
197 long AbsTimeval(void)
198 {
199         struct timeval tv;
200
201         gettimeofday(&tv, NULL);
202         return GetTimeval(&tv);
203 }
204
205 void ResetBaseTime(void)
206 { //Reset the timer
207         baseTimeval = AbsTimeval();
208 }
209
210 void PauseTime(void)
211 { //Pause the timer
212         baseTimeval -= AbsTimeval();
213 }
214
215 void ResumeTime(void)
216 { //Unpause timer
217         baseTimeval += AbsTimeval();
218 }
219
220 long CurTimeval(void)
221 {
222         struct timeval tv;
223
224         gettimeofday(&tv, NULL);
225         return GetTimeval(&tv) - baseTimeval;
226 }
227
228 static long SetITimer1(long interval, long value)
229 {
230         struct itimerval it, old;
231
232         SetTimeval(&it.it_interval, interval);
233         SetTimeval(&it.it_value, value);
234         if (setitimer(ITIMER_REAL, &it, &old) < 0)
235                 die("setitimer");
236         signal(SIGALRM, CatchAlarm);
237         return GetTimeval(&old.it_value);
238 }
239
240 long SetITimer(long interval, long value)
241 {
242         long old;
243
244         old = SetITimer1(0, 0);
245         alarmGen.ready = 0;
246         SetITimer1(interval, value);
247         return old;
248 }
249
250 ///////////// ... /////////////
251
252 volatile void die(char *msg)
253 {
254         perror(msg);
255         exit(1);
256 }
257
258 volatile void fatal(char *msg)
259 {
260         fprintf(stderr, "%s\n", msg);
261         exit(1);
262 }
263
264 void BlockSignals(MySigSet *saved, ...)
265 {
266         MySigSet set;
267         va_list args;
268         int sig;
269
270         va_start(args, saved);
271 #ifdef HAS_SIGPROCMASK
272         sigemptyset(&set);
273 #else
274         set = 0;
275 #endif
276         while ((sig = va_arg(args, int))) {
277 #ifdef HAS_SIGPROCMASK
278                 sigaddset(&set, sig);
279 #else
280                 sig |= sigmask(sig);
281 #endif
282         }
283 #ifdef HAS_SIGPROCMASK
284         sigprocmask(SIG_BLOCK, &set, saved);
285 #else
286         *saved = sigblock(set);
287 #endif
288         va_end(args);
289 }
290
291 void RestoreSignals(MySigSet *saved, MySigSet *set)
292 {
293 #ifdef HAS_SIGPROCMASK
294         sigprocmask(SIG_SETMASK, set, saved);
295 #else
296         if (saved)
297                 *saved = sigsetmask(*set);
298         else
299                 sigsetmask(*set);
300 #endif
301 }
302
303 ///////////// EVENTS /////////////
304
305 void AddEventGen(EventGenRec *gen)
306 {
307         assert(gen->next == NULL);
308         gen->next = nextGen->next;
309         nextGen->next = gen;
310 }
311
312 void RemoveEventGen(EventGenRec *gen)
313 {
314         // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
315         if (gen->next) {
316                 while (nextGen->next != gen)
317                         nextGen = nextGen->next;
318                 nextGen->next = gen->next;
319                 gen->next = NULL;
320         }
321 }
322
323 MyEventType WaitMyEvent(MyEvent *event, int mask)
324 { //poll
325         int i, retry = 0;
326         fd_set fds[FT_len];
327         EventGenRec *gen;
328         int result, anyReady, anySet;
329         struct timeval tv;
330
331         for (;;) {
332                 for (i = 0; i < FT_len; ++i)
333                         FD_ZERO(&fds[i]);
334                 anyReady = anySet = 0;
335                 gen = nextGen;
336                 do {
337                         if (gen->mask & mask) {
338                                 if (gen->ready)
339                                         anyReady = 1;
340                                 if (gen->fd >= 0) {
341                                         FD_SET(gen->fd, &fds[gen->fdType]);
342                                         anySet = 1;
343                                 }
344                         }
345                         gen = gen->next;
346                 } while (gen != nextGen);
347                 if (anySet) {
348                         tv.tv_sec = 0;
349                         tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
350                         result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
351                                         &fds[FT_except], anyReady ? &tv : NULL);
352                 }
353                 else {
354                         if (retry && !anyReady)
355                                 sleep(1);
356                         result = 0;
357                 }
358                 gen = nextGen;
359                 do {
360                         if ((gen->mask & mask) && (gen->ready || (
361                                 result > 0 && gen->fd >= 0
362                                 && FD_ISSET(gen->fd, &fds[gen->fdType])
363                         ))) {
364                                 gen->ready = 0;
365                                 event->type = gen->func(gen, event);
366                                 if (event->type != E_none) {
367                                         nextGen = gen->next;
368                                         return event->type;
369                                 }
370                         }
371                         gen = gen->next;
372                 } while (gen != nextGen);
373                 retry = 1;
374         }
375 }
376