code duplication
[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 ///////////// RANDOM /////////////
85
86 /*
87  * My really crappy random number generator follows
88  * Should be more than sufficient for our purposes though
89  */
90 void SRandom(int seed)
91 {
92         Game.seed = seed;
93         myRandSeed = seed % 31751 + 1;
94 }
95
96 int Random(int min, int max1)
97 { //return a random value
98         myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
99         return myRandSeed % (max1 - min) + min;
100 }
101
102 ///////////// I/O /////////////
103
104 int MyRead(int fd, void *data, int len)
105 {
106         int result, left;
107
108         left = len;
109         while (left > 0) {
110                 result = read(fd, data, left);
111                 if (result > 0) {
112                         data = ((char *)data) + result;
113                         left -= result;
114                 }
115                 else if (errno != EINTR)
116                         return result;
117         }
118         return len;
119 }
120
121 int MyWrite(int fd, void *data, int len)
122 {
123         int result, left;
124
125         left = len;
126         while (left > 0) {
127                 result = write(fd, data, left);
128                 if (result > 0) {
129                         data = ((char *)data) + result;
130                         left -= result;
131                 }
132                 else if (errno != EINTR)
133                         return result;
134         }
135         return len;
136 }
137
138 ///////////// CONFIG /////////////
139
140 void WriteConf(void)
141 {
142         FILE *file_out;
143
144         file_out = fopen(CONFIG_FILE, "w");
145         if (file_out == NULL) {
146                 perror("Error writing config file");
147                 exit(1);
148         }
149
150         fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string);
151
152         fclose(file_out);
153         fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
154 }
155
156 ///////////// TIME /////////////
157
158 void NormalizeTime(struct timeval *tv)
159 {
160         tv->tv_sec += tv->tv_usec / 1000000;
161         tv->tv_usec %= 1000000;
162         if (tv->tv_usec < 0) {
163                 tv->tv_usec += 1000000;
164                 --tv->tv_sec;
165         }
166 }
167
168 void CatchAlarm(int sig)
169 {
170         alarmGen.ready = 1;
171         signal(SIGALRM, CatchAlarm);
172 }
173
174 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
175 {
176         return E_alarm;
177 }
178
179 void SetTimeval(struct timeval *tv, long usec)
180 {
181         tv->tv_sec = usec / 1000000;
182         tv->tv_usec = usec % 1000000;
183 }
184
185 long GetTimeval(struct timeval *tv)
186 {
187         return tv->tv_sec * 1000000 + tv->tv_usec;
188 }
189
190 long AbsTimeval(void)
191 {
192         struct timeval tv;
193
194         gettimeofday(&tv, NULL);
195         return GetTimeval(&tv);
196 }
197
198 void ResetBaseTime(void)
199 { //Reset the timer
200         baseTimeval = AbsTimeval();
201 }
202
203 void PauseTime(void)
204 { //Pause the timer
205         baseTimeval -= AbsTimeval();
206 }
207
208 void ResumeTime(void)
209 { //Unpause timer
210         baseTimeval += AbsTimeval();
211 }
212
213 long CurTimeval(void)
214 {
215         return AbsTimeval() - baseTimeval;
216 }
217
218 static long SetITimer1(long interval, long value)
219 {
220         struct itimerval it, old;
221
222         SetTimeval(&it.it_interval, interval);
223         SetTimeval(&it.it_value, value);
224         if (setitimer(ITIMER_REAL, &it, &old) < 0)
225                 die("setitimer");
226         signal(SIGALRM, CatchAlarm);
227         return GetTimeval(&old.it_value);
228 }
229
230 long SetITimer(long interval, long value)
231 {
232         long old;
233
234         old = SetITimer1(0, 0);
235         alarmGen.ready = 0;
236         SetITimer1(interval, value);
237         return old;
238 }
239
240 ///////////// ... /////////////
241
242 volatile void die(char *msg)
243 {
244         perror(msg);
245         exit(1);
246 }
247
248 volatile void fatal(char *msg)
249 {
250         fprintf(stderr, "%s\n", msg);
251         exit(1);
252 }
253
254 void BlockSignals(MySigSet *saved, ...)
255 {
256         MySigSet set;
257         va_list args;
258         int sig;
259
260         va_start(args, saved);
261 #ifdef HAS_SIGPROCMASK
262         sigemptyset(&set);
263 #else
264         set = 0;
265 #endif
266         while ((sig = va_arg(args, int))) {
267 #ifdef HAS_SIGPROCMASK
268                 sigaddset(&set, sig);
269 #else
270                 sig |= sigmask(sig);
271 #endif
272         }
273 #ifdef HAS_SIGPROCMASK
274         sigprocmask(SIG_BLOCK, &set, saved);
275 #else
276         *saved = sigblock(set);
277 #endif
278         va_end(args);
279 }
280
281 void RestoreSignals(MySigSet *saved, MySigSet *set)
282 {
283 #ifdef HAS_SIGPROCMASK
284         sigprocmask(SIG_SETMASK, set, saved);
285 #else
286         if (saved)
287                 *saved = sigsetmask(*set);
288         else
289                 sigsetmask(*set);
290 #endif
291 }
292
293 ///////////// EVENTS /////////////
294
295 void AddEventGen(EventGenRec *gen)
296 {
297         assert(gen->next == NULL);
298         gen->next = nextGen->next;
299         nextGen->next = gen;
300 }
301
302 void RemoveEventGen(EventGenRec *gen)
303 {
304         // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
305         if (gen->next) {
306                 while (nextGen->next != gen)
307                         nextGen = nextGen->next;
308                 nextGen->next = gen->next;
309                 gen->next = NULL;
310         }
311 }
312
313 MyEventType WaitMyEvent(MyEvent *event, int mask)
314 { //poll
315         int i, retry = 0;
316         fd_set fds[FT_len];
317         EventGenRec *gen;
318         int result, anyReady, anySet;
319         struct timeval tv;
320
321         for (;;) {
322                 for (i = 0; i < FT_len; ++i)
323                         FD_ZERO(&fds[i]);
324                 anyReady = anySet = 0;
325                 gen = nextGen;
326                 do {
327                         if (gen->mask & mask) {
328                                 if (gen->ready)
329                                         anyReady = 1;
330                                 if (gen->fd >= 0) {
331                                         FD_SET(gen->fd, &fds[gen->fdType]);
332                                         anySet = 1;
333                                 }
334                         }
335                         gen = gen->next;
336                 } while (gen != nextGen);
337                 if (anySet) {
338                         tv.tv_sec = 0;
339                         tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
340                         result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
341                                         &fds[FT_except], anyReady ? &tv : NULL);
342                 }
343                 else {
344                         if (retry && !anyReady)
345                                 sleep(1);
346                         result = 0;
347                 }
348                 gen = nextGen;
349                 do {
350                         if ((gen->mask & mask) && (gen->ready || (
351                                 result > 0 && gen->fd >= 0
352                                 && FD_ISSET(gen->fd, &fds[gen->fdType])
353                         ))) {
354                                 gen->ready = 0;
355                                 event->type = gen->func(gen, event);
356                                 if (event->type != E_none) {
357                                         nextGen = gen->next;
358                                         return event->type;
359                                 }
360                         }
361                         gen = gen->next;
362                 } while (gen != nextGen);
363                 retry = 1;
364         }
365 }
366