remove --rules
[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         struct timeval tv;
216
217         gettimeofday(&tv, NULL);
218         return GetTimeval(&tv) - baseTimeval;
219 }
220
221 static long SetITimer1(long interval, long value)
222 {
223         struct itimerval it, old;
224
225         SetTimeval(&it.it_interval, interval);
226         SetTimeval(&it.it_value, value);
227         if (setitimer(ITIMER_REAL, &it, &old) < 0)
228                 die("setitimer");
229         signal(SIGALRM, CatchAlarm);
230         return GetTimeval(&old.it_value);
231 }
232
233 long SetITimer(long interval, long value)
234 {
235         long old;
236
237         old = SetITimer1(0, 0);
238         alarmGen.ready = 0;
239         SetITimer1(interval, value);
240         return old;
241 }
242
243 ///////////// ... /////////////
244
245 volatile void die(char *msg)
246 {
247         perror(msg);
248         exit(1);
249 }
250
251 volatile void fatal(char *msg)
252 {
253         fprintf(stderr, "%s\n", msg);
254         exit(1);
255 }
256
257 void BlockSignals(MySigSet *saved, ...)
258 {
259         MySigSet set;
260         va_list args;
261         int sig;
262
263         va_start(args, saved);
264 #ifdef HAS_SIGPROCMASK
265         sigemptyset(&set);
266 #else
267         set = 0;
268 #endif
269         while ((sig = va_arg(args, int))) {
270 #ifdef HAS_SIGPROCMASK
271                 sigaddset(&set, sig);
272 #else
273                 sig |= sigmask(sig);
274 #endif
275         }
276 #ifdef HAS_SIGPROCMASK
277         sigprocmask(SIG_BLOCK, &set, saved);
278 #else
279         *saved = sigblock(set);
280 #endif
281         va_end(args);
282 }
283
284 void RestoreSignals(MySigSet *saved, MySigSet *set)
285 {
286 #ifdef HAS_SIGPROCMASK
287         sigprocmask(SIG_SETMASK, set, saved);
288 #else
289         if (saved)
290                 *saved = sigsetmask(*set);
291         else
292                 sigsetmask(*set);
293 #endif
294 }
295
296 ///////////// EVENTS /////////////
297
298 void AddEventGen(EventGenRec *gen)
299 {
300         assert(gen->next == NULL);
301         gen->next = nextGen->next;
302         nextGen->next = gen;
303 }
304
305 void RemoveEventGen(EventGenRec *gen)
306 {
307         // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
308         if (gen->next) {
309                 while (nextGen->next != gen)
310                         nextGen = nextGen->next;
311                 nextGen->next = gen->next;
312                 gen->next = NULL;
313         }
314 }
315
316 MyEventType WaitMyEvent(MyEvent *event, int mask)
317 { //poll
318         int i, retry = 0;
319         fd_set fds[FT_len];
320         EventGenRec *gen;
321         int result, anyReady, anySet;
322         struct timeval tv;
323
324         for (;;) {
325                 for (i = 0; i < FT_len; ++i)
326                         FD_ZERO(&fds[i]);
327                 anyReady = anySet = 0;
328                 gen = nextGen;
329                 do {
330                         if (gen->mask & mask) {
331                                 if (gen->ready)
332                                         anyReady = 1;
333                                 if (gen->fd >= 0) {
334                                         FD_SET(gen->fd, &fds[gen->fdType]);
335                                         anySet = 1;
336                                 }
337                         }
338                         gen = gen->next;
339                 } while (gen != nextGen);
340                 if (anySet) {
341                         tv.tv_sec = 0;
342                         tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
343                         result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
344                                         &fds[FT_except], anyReady ? &tv : NULL);
345                 }
346                 else {
347                         if (retry && !anyReady)
348                                 sleep(1);
349                         result = 0;
350                 }
351                 gen = nextGen;
352                 do {
353                         if ((gen->mask & mask) && (gen->ready || (
354                                 result > 0 && gen->fd >= 0
355                                 && FD_ISSET(gen->fd, &fds[gen->fdType])
356                         ))) {
357                                 gen->ready = 0;
358                                 event->type = gen->func(gen, event);
359                                 if (event->type != E_none) {
360                                         nextGen = gen->next;
361                                         return event->type;
362                                 }
363                         }
364                         gen = gen->next;
365                 } while (gen != nextGen);
366                 retry = 1;
367         }
368 }
369