Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / games / sail / sync.c
1 /*-
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)sync.c   8.1 (Berkeley) 5/31/93
30  * $FreeBSD: src/games/sail/sync.c,v 1.9 1999/11/30 03:49:38 billf Exp $
31  */
32
33 #include <sys/file.h>
34 #include <sys/errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include "externs.h"
38
39 #define BUFSIZE 4096
40
41 static int sync_update(int, struct ship *, const char *,
42                        long, long, long, long);
43
44 static char sync_buf[BUFSIZE];
45 static char *sync_bp = sync_buf;
46 static char sync_lock[25];
47 static char sync_file[25];
48 static long sync_seek;
49 static FILE *sync_fp;
50 #define SF "/tmp/#sailsink.%d"
51 #define LF "/tmp/#saillock.%d"
52
53
54 void
55 fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
56 {
57         while (*fmt) {
58                 if (len-- == 0) {
59                         *buf = '\0';
60                         return;
61                 }
62                 if (*fmt == '$' && fmt[1] == '$') {
63                         size_t l = snprintf(buf, len, "%s (%c%c)",
64                             ship->shipname, colours(ship), sterncolour(ship));
65                         buf += l;
66                         len -= l - 1;
67                         fmt += 2;
68                 }
69                 else
70                         *buf++ = *fmt++;
71         }
72
73         if (len > 0)
74                 *buf = '\0';
75 }
76
77 /*VARARGS3*/
78 void
79 makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
80 {
81         char message[80];
82         char format[BUFSIZ];
83         va_list ap;
84
85         va_start(ap, ship);
86         if (ship == NULL)
87                 vsprintf(message, fmt, ap);
88         else {
89                 fmtship(format, sizeof(format), fmt, ship);
90                 vsprintf(message, format, ap);
91         }
92         va_end(ap);
93         Writestr(W_SIGNAL, from, message);
94 }
95
96 bool
97 sync_exists(int lgame)
98 {
99         char buf[sizeof sync_file];
100         struct stat s;
101         time_t t;
102
103         sprintf(buf, SF, game);
104         time(&t);
105         if (stat(buf, &s) < 0)
106                 return 0;
107         if (s.st_mtime < t - 60*60*2) {         /* 2 hours */
108                 unlink(buf);
109                 sprintf(buf, LF, lgame);
110                 unlink(buf);
111                 return 0;
112         } else
113                 return 1;
114 }
115
116 int
117 sync_open(void)
118 {
119         if (sync_fp != NULL)
120                 fclose(sync_fp);
121         sprintf(sync_lock, LF, game);
122         sprintf(sync_file, SF, game);
123         if (access(sync_file, 0) < 0) {
124                 int omask = umask(issetuid ? 077 : 011);
125                 sync_fp = fopen(sync_file, "w+");
126                 umask(omask);
127         } else
128                 sync_fp = fopen(sync_file, "r+");
129         if (sync_fp == NULL)
130                 return -1;
131         sync_seek = 0;
132         return 0;
133 }
134
135 void
136 sync_close(char rm)
137 {
138         if (sync_fp != NULL)
139                 fclose(sync_fp);
140         if (rm)
141                 unlink(sync_file);
142 }
143
144 void
145 Write(int type, struct ship *ship, int a, int b, int c, int d)
146 {
147         sprintf(sync_bp, "%d %d 0 %d %d %d %d\n",
148                 type, ship->file->index, a, b, c, d);
149         while (*sync_bp++)
150                 ;
151         sync_bp--;
152         if (sync_bp >= &sync_buf[sizeof sync_buf])
153                 abort();
154         sync_update(type, ship, NULL, a, b, c, d);
155 }
156
157 void
158 Writestr(int type, struct ship *ship, const char *a)
159 {
160         sprintf(sync_bp, "%d %d 1 %s\n", type, ship->file->index, a);
161         while (*sync_bp++)
162                 ;
163         sync_bp--;
164         if (sync_bp >= &sync_buf[sizeof sync_buf])
165                 abort();
166         sync_update(type, ship, a, 0, 0, 0, 0);
167 }
168
169 int
170 Sync(void)
171 {
172         sig_t sighup, sigint;
173         int n;
174         int type, shipnum, isstr, a, b, c, d;
175         char *astr;
176         char buf[80];
177         char erred = 0;
178         sighup = signal(SIGHUP, SIG_IGN);
179         sigint = signal(SIGINT, SIG_IGN);
180         for (n = TIMEOUT; --n >= 0;) {
181 #ifdef LOCK_EX
182                 if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
183                         break;
184                 if (errno != EWOULDBLOCK)
185                         return -1;
186 #else
187                 if (link(sync_file, sync_lock) >= 0)
188                         break;
189                 if (errno != EEXIST)
190                         return -1;
191 #endif
192                 sleep(1);
193         }
194         if (n <= 0)
195                 return -1;
196         fseek(sync_fp, sync_seek, SEEK_SET);
197         for (;;) {
198                 switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
199                 case 3:
200                         break;
201                 case EOF:
202                         goto out;
203                 default:
204                         goto bad;
205                 }
206                 if (shipnum < 0 || shipnum >= cc->vessels)
207                         goto bad;
208                 if (isstr != 0 && isstr != 1)
209                         goto bad;
210                 if (isstr) {
211                         char *p;
212                         for (p = buf;;) {
213                                 switch (*p++ = getc(sync_fp)) {
214                                 case '\n':
215                                         p--;
216                                 case EOF:
217                                         break;
218                                 default:
219                                         if (p >= buf + sizeof buf)
220                                                 p--;
221                                         continue;
222                                 }
223                                 break;
224                         }
225                         *p = 0;
226                         for (p = buf; *p == ' '; p++)
227                                 ;
228                         astr = p;
229                         a = b = c = d = 0;
230                 } else {
231                         if (fscanf(sync_fp, "%d%d%d%d", &a, &b, &c, &d) != 4)
232                                 goto bad;
233                         astr = NULL;
234                 }
235                 if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
236                         goto bad;
237         }
238 bad:
239         erred++;
240 out:
241         if (!erred && sync_bp != sync_buf) {
242                 fseek(sync_fp, 0L, SEEK_END);
243                 fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
244                         sync_fp);
245                 fflush(sync_fp);
246                 sync_bp = sync_buf;
247         }
248         sync_seek = ftell(sync_fp);
249 #ifdef LOCK_EX
250         flock(fileno(sync_fp), LOCK_UN);
251 #else
252         unlink(sync_lock);
253 #endif
254         signal(SIGHUP, sighup);
255         signal(SIGINT, sigint);
256         return erred ? -1 : 0;
257 }
258
259 static int
260 sync_update(int type, struct ship *ship, const char *astr, long a, long b,
261             long c, long d)
262 {
263         switch (type) {
264         case W_DBP: {
265                 struct BP *p = &ship->file->DBP[a];
266                 p->turnsent = b;
267                 p->toship = SHIP(c);
268                 p->mensent = d;
269                 break;
270                 }
271         case W_OBP: {
272                 struct BP *p = &ship->file->OBP[a];
273                 p->turnsent = b;
274                 p->toship = SHIP(c);
275                 p->mensent = d;
276                 break;
277                 }
278         case W_FOUL: {
279                 struct snag *p = &ship->file->foul[a];
280                 if (SHIP(a)->file->dir == 0)
281                         break;
282                 if (p->sn_count++ == 0)
283                         p->sn_turn = turn;
284                 ship->file->nfoul++;
285                 break;
286                 }
287         case W_GRAP: {
288                 struct snag *p = &ship->file->grap[a];
289                 if (SHIP(a)->file->dir == 0)
290                         break;
291                 if (p->sn_count++ == 0)
292                         p->sn_turn = turn;
293                 ship->file->ngrap++;
294                 break;
295                 }
296         case W_UNFOUL: {
297                 struct snag *p = &ship->file->foul[a];
298                 if (p->sn_count > 0) {
299                         if (b) {
300                                 ship->file->nfoul -= p->sn_count;
301                                 p->sn_count = 0;
302                         } else {
303                                 ship->file->nfoul--;
304                                 p->sn_count--;
305                         }
306                 }
307                 break;
308                 }
309         case W_UNGRAP: {
310                 struct snag *p = &ship->file->grap[a];
311                 if (p->sn_count > 0) {
312                         if (b) {
313                                 ship->file->ngrap -= p->sn_count;
314                                 p->sn_count = 0;
315                         } else {
316                                 ship->file->ngrap--;
317                                 p->sn_count--;
318                         }
319                 }
320                 break;
321                 }
322         case W_SIGNAL:
323                 if (mode == MODE_PLAYER) {
324                         if (nobells)
325                                 Signal("%s (%c%c): %s", ship, astr);
326                         else
327                                 Signal("\7%s (%c%c): %s", ship, astr);
328                 }
329                 break;
330         case W_CREW: {
331                 struct shipspecs *s = ship->specs;
332                 s->crew1 = a;
333                 s->crew2 = b;
334                 s->crew3 = c;
335                 break;
336                 }
337         case W_CAPTAIN:
338                 strncpy(ship->file->captain, astr,
339                         sizeof ship->file->captain - 1);
340                 ship->file->captain[sizeof ship->file->captain - 1] = 0;
341                 break;
342         case W_CAPTURED:
343                 if (a < 0)
344                         ship->file->captured = 0;
345                 else
346                         ship->file->captured = SHIP(a);
347                 break;
348         case W_CLASS:
349                 ship->specs->class = a;
350                 break;
351         case W_DRIFT:
352                 ship->file->drift = a;
353                 break;
354         case W_EXPLODE:
355                 if ((ship->file->explode = a) == 2)
356                         ship->file->dir = 0;
357                 break;
358         case W_FS:
359                 ship->file->FS = a;
360                 break;
361         case W_GUNL: {
362                 struct shipspecs *s = ship->specs;
363                 s->gunL = a;
364                 s->carL = b;
365                 break;
366                 }
367         case W_GUNR: {
368                 struct shipspecs *s = ship->specs;
369                 s->gunR = a;
370                 s->carR = b;
371                 break;
372                 }
373         case W_HULL:
374                 ship->specs->hull = a;
375                 break;
376         case W_MOVE:
377                 strncpy(ship->file->movebuf, astr,
378                         sizeof ship->file->movebuf - 1);
379                 ship->file->movebuf[sizeof ship->file->movebuf - 1] = 0;
380                 break;
381         case W_PCREW:
382                 ship->file->pcrew = a;
383                 break;
384         case W_POINTS:
385                 ship->file->points = a;
386                 break;
387         case W_QUAL:
388                 ship->specs->qual = a;
389                 break;
390         case W_RIGG: {
391                 struct shipspecs *s = ship->specs;
392                 s->rig1 = a;
393                 s->rig2 = b;
394                 s->rig3 = c;
395                 s->rig4 = d;
396                 break;
397                 }
398         case W_RIG1:
399                 ship->specs->rig1 = a;
400                 break;
401         case W_RIG2:
402                 ship->specs->rig2 = a;
403                 break;
404         case W_RIG3:
405                 ship->specs->rig3 = a;
406                 break;
407         case W_RIG4:
408                 ship->specs->rig4 = a;
409                 break;
410         case W_COL:
411                 ship->file->col = a;
412                 break;
413         case W_DIR:
414                 ship->file->dir = a;
415                 break;
416         case W_ROW:
417                 ship->file->row = a;
418                 break;
419         case W_SINK:
420                 if ((ship->file->sink = a) == 2)
421                         ship->file->dir = 0;
422                 break;
423         case W_STRUCK:
424                 ship->file->struck = a;
425                 break;
426         case W_TA:
427                 ship->specs->ta = a;
428                 break;
429         case W_ALIVE:
430                 alive = 1;
431                 break;
432         case W_TURN:
433                 turn = a;
434                 break;
435         case W_WIND:
436                 winddir = a;
437                 windspeed = b;
438                 break;
439         case W_BEGIN:
440                 strcpy(ship->file->captain, "begin");
441                 people++;
442                 break;
443         case W_END:
444                 *ship->file->captain = 0;
445                 ship->file->points = 0;
446                 people--;
447                 break;
448         case W_DDEAD:
449                 hasdriver = 0;
450                 break;
451         default:
452                 fprintf(stderr, "sync_update: unknown type %d\r\n", type);
453                 return -1;
454         }
455         return 0;
456 }