1 | /*
2 | * $Log: dipent.c,v $
3 | * Revision 1.20 2003/07/17 22:59:29 millis
4 | * Bug 185
5 | *
6 | * Revision 1.19 2003/07/16 14:50:56 millis
7 | * Used D_X2FLAGS to allow default setting for X2FLAGS for games (if desired)
8 | *
9 | * Revision 1.18 2003/06/20 00:21:02 millis
10 | * Tried to fix it correctly!
11 | *
12 | * Revision 1.17 2003/06/19 23:43:18 millis
13 | * Added a repeat test flag.
14 | *
15 | * Revision 1.16 2003/06/19 23:27:55 millis
16 | * Bug 181, bailout recovery only for control game, and adjust deadlines
17 | * for non-control games.
18 | *
19 | * Revision 1.15 2003/05/14 19:01:22 millis
20 | * Don't adjust mach files in 'A' season on bailout
21 | *
22 | * Revision 1.14 2003/05/13 00:07:26 millis
23 | * Bug 110, move on process deadline by 24 hours on bailout recovery
24 | *
25 | * Revision 1.13 2003/05/12 23:47:59 millis
26 | * Fix bug 110, shift process time out on a timewarp.
27 | *
28 | * Revision 1.12 2003/04/16 04:31:32 millis
29 | * Fixed a bug that zapped the x/x2/flags settings on getdipent calls
30 | *
31 | * Revision 1.11 2003/01/13 22:38:51 millis
32 | * merged in from ustv
33 | *
34 | * Revision 1.10 2002/08/27 22:27:50 millis
35 | * Updated for automake/autoconf functionality
36 | *
37 | * Revision 1.9 2001/10/20 12:11:11 miller
38 | * Merged in changes from DEMA and USTV
39 | *
40 | * Revision 1.8.2.2 2001/10/19 23:29:08 dema
41 | * Allow powers with spaces in their names to be used
42 | *
43 | * Revision 1.8.2.1 2001/10/15 00:00:24 ustv
44 | * Added reading/writing of dipent.x2flags
45 | *
46 | * Revision 1.8 2001/07/15 09:14:18 greg
47 | * added support for game directories in a sub directory
48 | *
49 | * Revision 1.7 2001/07/08 22:54:49 miller
50 | * Set default correctly for rrded, and add TIME_TOLERANCE usage from dip.conf
51 | *
52 | * Revision 1.6 2001/07/01 23:19:29 miller
53 | * Default for XF_COASTAL
54 | *
55 | * Revision 1.5 2001/06/24 05:30:29 nzmb
56 | * Added read/write capability for new dipent variables (dedapplied, orded,
57 | * rrded) used in the plyrdata and new deadline systems.
58 | *
59 | * Revision 1.4 2001/05/26 11:20:34 miller
60 | * Do not notify time-warp for shifts < 1 minute
61 | *
62 | * Revision 1.3 2001/01/05 22:27:53 miller
63 | * Fix to test using '==' not '='
64 | * (made all games erroneously of Chaos variant when upgrading from older dip.master format.
65 | *
66 | * Revision 1.2 2000/11/14 14:27:37 miller
67 | * Added handling of new XF_:FLAGS , and absence data elements in master.dip
68 | * Used gerenric flags to handle variants (not specificif tests)
69 | *
70 | * Revision 1.1 1998/02/28 17:49:42 david
71 | * Initial revision
72 | *
73 | * Revision 1.2 1997/02/16 20:43:18 davidn
74 | * Additions to dipent structure and associated code, to allow duplex variants.
75 | * Command is "set players n".
76 | *
77 | * Revision 1.1 1996/10/20 12:29:45 rpaar
78 | * Morrolan v9.0
79 | */
80 |
81 | /*
82 | * dipent.c * Copyright 1987, Lowe. * * Diplomacy is a trademark of the
83 | * Avalon Hill Game Company, Baltimore, * Maryland, all rights reserved;
84 | * used with permission. * * Redistribution and use in source and binary
85 | * forms are permitted * provided that it is for non-profit purposes,
86 | * that this and the * above notices are preserved and that due credit
87 | * is given to Mr. * Lowe. * * DATE NAME REASON *
88 | * ----------- ------------ ----------------------------------------- *
89 | * ?? ??? 1987 Ken Lowe He wrote it * 29 Dec 1996 David Norman
90 | * Addition of dipent.no_of_players * 29 Dec 1996 David Norman Protection
91 | * against killing dip.master added
92 | * 26 Nov 1999 Millis Miller Added player late_count to payer structure
93 | * Also added use of xflags structure.
94 | * 26 May 2001 Mario Becroft Added code for dipent.orded,dipent.rrded,
95 | * Tim Miller and dipent.dedapplied, all part of the new
96 | * dedication systems.
97 | */
98 |
99 | #include <fcntl.h>
100 | #include <stdlib.h>
101 | #include <string.h>
102 | #include <sys/stat.h>
103 | #include <sys/types.h>
104 | #include <time.h>
105 | #include <unistd.h>
106 |
107 | #include "config.h"
108 | #include "dip.h"
109 | #include "defaults.h"
110 | #include "functions.h"
111 | #include "diplog.h"
112 |
113 | extern int Dflg;
114 |
115 | char *ctime();
116 | char *lookfor();
117 |
118 | void putseq(FILE * fp, char *s, sequence * seq);
119 | void gettime(char *line, long *time);
120 | void getplay(char *line, Player * p);
121 | void putplay(FILE * fp, Player * p, int dopw);
122 |
123 | int time_warp = 0; /* Set to 1 when a time warp was detected */
124 | /************************************************************************/
125 |
126 | int getdipent(FILE * fp)
127 | {
128 |
129 | /*
130 | * Read the next game entry from the master file.
131 | */
132 |
133 | int i, j, tempvp, tempplayers;
134 | int old_flags, old_xflags, old_x2flags; /* Remember flags settings! */
135 | time_t now;
136 | unsigned char line[1000];
137 | char *s;
138 | char *malloc();
139 | static int recover_print = 0;
140 |
141 | memset(&dipent, 0, sizeof(dipent));
142 | if (!fgets(line, sizeof(line), fp))
143 | return 0;
144 | i = sscanf(line, "%s%s%s%d%d%d%d%x%d%d%x%d%x%d", dipent.name, dipent.seq, dipent.phase,
145 | &dipent.access, &dipent.variant,
146 | &dipent.level, &dipent.dedicate,
147 | &dipent.flags, &tempvp, &tempplayers,
148 | &dipent.xflags, &dipent.max_absence_delay,
149 | &dipent.x2flags, &dipent.num_homes);
150 |
151 | if (i == 7) {
152 | dipent.flags = F_NONMR;
153 | i = 8;
154 | }
155 | if (i == 8) {
156 | tempvp = 0;
157 | i = 9;
158 | }
159 | if (i == 9) {
160 | tempplayers = 0;
161 | i = 10;
162 | }
163 | if (i == 10) {
164 | dipent.xflags = 0;
165 | if ((dipent.variant == V_h31)
166 | || (dipent.variant == V_h32)
167 | || (dipent.variant == V_classical)
168 | || (dipent.variant == V_chaos)) {
169 | dipent.xflags |= XF_BUILD_ANYCENTRES;
170 | }
171 | if (dipent.variant == V_aberration) dipent.xflags |= XF_BUILD_ONECENTRE;
172 | i = 11;
173 | }
174 | if (i == 11) {
175 | dipent.max_absence_delay = 0;
176 | dipent.rrded = 1.000;
177 | dipent.orded = 0.000; /* Set ded settings for migrated games */
178 | i = 12;
179 | }
180 |
181 | if (i == 12) {
182 | if (dipent.variant == V_machiavelli)
183 | dipent.xflags |= XF_COASTAL_CONVOYS;
184 | i = 13;
185 | dipent.x2flags = 0;
186 | }
187 | if (i == 13) {
188 | dipent.num_homes = 0;
189 | i = 14;
190 | }
191 |
192 | if (i != 14) {
193 | fprintf(stderr, "Bad header in master file (returned %d).\n%s\n", i ,line);
194 | bailout(E_FATAL);
195 | }
196 | /* tempcentres will remember centres setting */
197 | old_flags = dipent.flags;
198 | old_xflags = dipent.xflags;
199 | old_x2flags = dipent.x2flags;
200 | SETNP(dipent.variant);
201 | dipent.xflags = old_xflags;
202 | dipent.x2flags = old_x2flags;
203 | dipent.flags = old_flags;
204 | dipent.has_natives = GetNativeIndex();
205 |
206 | if (tempvp != 0)
207 | dipent.vp = tempvp;
208 |
209 | if (tempplayers != 0) {
210 | dipent.no_of_players = tempplayers;
211 | } else {
212 | dipent.no_of_players = dipent.np;
213 | }
214 |
215 | while (fgets(line, sizeof(line), fp) && *line != '-') {
216 | switch (*line) {
217 |
218 | case 'A':
219 | case 'B':
220 | memset(&dipent.builds, 0, sizeof(sequence));
221 | if (getseq(stderr, line, &dipent.builds))
222 | bailout(E_FATAL);
223 | break;
224 |
225 | case 'C':
226 | line[strlen(line) - 1] = '\0';
227 | for (s = line; !isspace(*s); s++);
228 | while (isspace(*s))
229 | s++;
230 | strncpy(dipent.comment, s, sizeof(dipent.comment) - 1);
231 | break;
232 |
233 | case 'D':
234 | gettime(line, &dipent.deadline);
235 | break;
236 |
237 | case 'E':
238 | line[strlen(line) - 1] = '\0';
239 | for (s = line; !isspace(*s); s++);
240 | while (isspace(*s))
241 | s++;
242 | strncpy(dipent.epnum, s, sizeof(dipent.epnum) - 1);
243 | break;
244 |
245 | case 'G':
246 | gettime(line, &dipent.grace);
247 | break;
248 |
249 | case 'M':
250 | memset(&dipent.movement, 0, sizeof(sequence));
251 | if (getseq(stderr, line, &dipent.movement))
252 | bailout(E_FATAL);
253 | break;
254 |
255 | case 'N':
256 | line[strlen(line) - 1] = '\0';
257 | for (s = line; !isspace(*s); s++);
258 | while (isspace(*s))
259 | s++;
260 | strncpy(dipent.bn_mnnum, s, sizeof(dipent.bn_mnnum) - 1);
261 | break;
262 |
263 | case 'P':
264 | gettime(line, &dipent.process);
265 | break;
266 |
267 | case 'R':
268 | memset(&dipent.retreat, 0, sizeof(sequence));
269 | if (getseq(stderr, line, &dipent.retreat))
270 | bailout(E_FATAL);
271 | break;
272 |
273 | case 'S':
274 | gettime(line, &dipent.start);
275 | break;
276 |
277 | case 'Y':
278 | dipent.dedapplied = strtol( &(line[22]), NULL, 10);
279 | break;
280 | case 'O':
281 | sscanf( &(line[16]),"%f", &dipent.orded);
282 | break;
283 |
284 | case 'T':
285 | sscanf( &(line[26]),"%f", &dipent.rrded);
286 | break;
287 |
288 | case '_':
289 | if (dipent.n > 0) {
290 | line[strlen(line) - 1] = '\0';
291 | for (s = line; !isspace(*s); s++);
292 | while (isspace(*s))
293 | s++;
294 | strcpy(dipent.players[dipent.n - 1].pref, s);
295 | }
296 | break;
297 |
298 | default:
299 | if (dipent.n >= MAXPLAYERS) {
300 | fprintf(stderr, "Too many players for game '%s'.\n", dipent.name);
301 | bailout(E_FATAL);
302 | }
303 | *dipent.players[dipent.n].pref = '\0';
304 | getplay(line, &dipent.players[dipent.n++]);
305 | }
306 | }
307 | if (Dflg > 1)
308 | fprintf(log_fp, "Getdipent returns: '%s'.\n", dipent.name);
309 |
310 | if (!strcmp(dipent.name, "control")) {
311 | time(&now);
312 | /* MLM 26/5/2001 only notify warp on shift more than TIME_TOLERANCE */
313 | if (dipent.process && (dipent.start > (now +TIME_TOLERANCE) ||
314 | now > (TIME_TOLERANCE + dipent.process))) {
315 | fprintf(stderr, "Current date %24.24s should be between...\n", ctime(&now));
316 | fprintf(stderr, "Control dates %24.24s ", ctime(&dipent.start));
317 | fprintf(stderr, "< %24.24s.\n", ctime(&dipent.process));
318 | fprintf(stderr, "Time warp indicated. GM notified.\n");
319 | sprintf(line, "/dev/null 'Diplomacy time warp'");
320 | MailOut(line, GAMES_MASTER);
321 | /* bailout(E_FATAL); */
322 | /* Try to fix time warp by advancing deadline */
323 | deadline(NULL, 1);
324 | time_warp = 1;
325 | DIPNOTICE("TimeWarp detected.");
326 |
327 | /* If recovering from bailout, notify the GAMES_MASTER */
328 | if (bailout_recovery && !recover_print) {
329 | sprintf(line, "/dev/null 'Bailout recovery initiated'");
330 | MailOut(line, GAMES_MASTER);
331 | recover_print = 1;
332 | }
333 |
334 | } else {
335 | time_warp = 0;
336 | }
337 | dipent.start = now - 1;
338 | dipent.process = now + 168 * HRS2SECS;
339 | for (j = i = 0; i < dipent.n; i++)
340 | j += strlen(dipent.players[i].address) + 2;
341 | if ((s = notifies = malloc(j + 1))) {
342 | for (i = 0; i < dipent.n; i++) {
343 | if (dipent.players[i].power == MASTER)
344 | *s++ = '+';
345 | strcpy(s, dipent.players[i].address);
346 | s += strlen(s) + 1;
347 | }
348 | *s = '\0';
349 | } else {
350 | notifies = "*";
351 | }
352 |
353 | } else {
354 | /* Non control game, check for a time-warp or bailout recovery set */
355 | if ((time_warp || bailout_recovery) && dipent.phase[5] != 'A') {
356 | /* Try to fix the warp/recovery by adjusting deadline */
357 | /* Rather simplistic, but will do for now */
358 | deadline(NULL,1);
359 |
360 | /* Bug 110: Also, shift out the process date by 24 hours if sooner */
361 | #define PROCESS_SHIFT (24*60*60)
362 | if (dipent.process && (dipent.process < now + PROCESS_SHIFT))
363 | dipent.process += PROCESS_SHIFT;
364 | }
365 |
366 | }
367 | return 1;
368 | }
369 |
370 | /***********************************************************************/
371 |
372 | void putdipent(FILE * fp, int dopw)
373 | {
374 |
375 | /*
376 | * Write the current entry out to the master file.
377 | */
378 |
379 | int i;
380 | char line[1000];
381 |
382 | fprintf(fp, "%-8.8s %-8.8s %-8.8s %d %d %d %d %x %d %d %x %d %x %d\n",
383 | dipent.name, dipent.seq,
384 | dipent.phase, dipent.access, dipent.variant,
385 | dipent.level, dipent.dedicate, dipent.flags, dipent.vp,
386 | dipent.no_of_players, dipent.xflags,
387 | dipent.max_absence_delay,
388 | dipent.x2flags, /* This indicates version 0.8.9 onwards */
389 | dipent.num_homes /* This indicates version 1.1.1 onwards */
390 | );
391 |
392 | if (dipent.process)
393 | fprintf(fp, "Process %24.24s (%ld)\n",
394 | ctime(&dipent.process), dipent.process);
395 | if (dipent.deadline)
396 | fprintf(fp, "Deadline %24.24s (%ld)\n",
397 | ctime(&dipent.deadline), dipent.deadline);
398 | if (dipent.start)
399 | fprintf(fp, "Start %24.24s (%ld)\n",
400 | ctime(&dipent.start), dipent.start);
401 | if (dipent.grace)
402 | fprintf(fp, "Grace %24.24s (%ld)\n",
403 | ctime(&dipent.grace), dipent.grace);
404 | fprintf(fp, "Ontime rat. min %.3f\n",dipent.orded);
405 | fprintf(fp, "T = resignation ratio max %.3f\n",dipent.rrded);
406 | fprintf (fp,"Yet_Applied_deadline? %d\n",
407 | dipent.dedapplied);
408 | if (*dipent.comment)
409 | fprintf(fp, "Comment %s\n", dipent.comment);
410 | if (*dipent.epnum)
411 | fprintf(fp, "EP_number %s\n", dipent.epnum);
412 | if (*dipent.bn_mnnum)
413 | fprintf(fp, "Number_BM %s\n", dipent.bn_mnnum);
414 |
415 | putseq(fp, "Moves ", &dipent.movement);
416 | putseq(fp, "Retreat", &dipent.retreat);
417 | putseq(fp, "Adjust ", &dipent.builds);
418 |
419 | for (i = 0; i < dipent.n; i++) {
420 | putplay(fp, &dipent.players[i], dopw);
421 | }
422 | if (fprintf(fp, "-\n") == 0) {
423 | fprintf(stderr, "Error writing to dip.master. Disk error suspected. Bailing out\n");
424 | sprintf(line, "/dev/null 'File error writing dip.master'");
425 | MailOut(line, GAMES_MASTER);
426 | bailout(E_FATAL);
427 | }
428 | }
429 |
430 | /***********************************************************************/
431 |
432 | void newdipent(char *name, int variant)
433 | {
434 |
435 | /*
436 | * Build a new diplomacy master file entry.
437 | */
438 |
439 | char dir[50];
440 |
441 | /* TODO allow an arbitrary prefix. E.g. "games/" */
442 | /* done - greg :-) */
443 | sprintf(dir, "%s%s", GAME_DIR, name);
444 | mkdir(dir, 0777);
445 | strncpy(dipent.name, name, sizeof(dipent.name));
446 | strcpy(dipent.seq, "x0");
447 | strcpy(dipent.phase, sphase[variant]);
448 | dipent.access = D_ACCESS;
449 | dipent.level = D_LEVEL;
450 | dipent.flags = D_FLAGS;
451 | dipent.xflags = D_XFLAGS;
452 | dipent.x2flags = D_X2FLAGS;
453 | dipent.dedicate = D_DEDICATE;
454 | dipent.variant = variant;
455 | SETNP(variant);
456 | dipent.process = 0;
457 | dipent.deadline = 0;
458 | dipent.start = 0;
459 | dipent.grace = 0;
460 | dipent.movement.clock = D_MOVE_CLOCK;
461 | dipent.movement.mint = D_MOVE_MINT;
462 | dipent.movement.next = D_MOVE_NEXT;
463 | dipent.movement.grace = D_MOVE_GRACE;
464 | dipent.movement.delay = D_MOVE_DELAY;
465 | strcpy(dipent.movement.days, D_MOVE_DAYS);
466 | dipent.retreat.clock = D_RETREAT_CLOCK;
467 | dipent.retreat.mint = D_RETREAT_MINT;
468 | dipent.retreat.next = D_RETREAT_NEXT;
469 | dipent.retreat.grace = D_RETREAT_GRACE;
470 | dipent.retreat.delay = D_RETREAT_DELAY;
471 | strcpy(dipent.retreat.days, D_RETREAT_DAYS);
472 | dipent.builds.clock = D_BUILDS_CLOCK;
473 | dipent.builds.mint = D_BUILDS_MINT;
474 | dipent.builds.next = D_BUILDS_NEXT;
475 | dipent.builds.grace = D_BUILDS_GRACE;
476 | dipent.builds.delay = D_BUILDS_DELAY;
477 | strcpy(dipent.builds.days, D_BUILDS_DAYS);
478 | dipent.n = 0;
479 | dipent.orded = 0.000;
480 | dipent.rrded = 1.000;
481 | dipent.dedapplied = 0;
482 | dipent.no_of_players = dipent.np;
483 | dipent.max_absence_delay = D_MAX_ABSENCE_DELAY;
484 | dipent.has_natives = GetNativeIndex();
485 | }
486 |
487 | /***********************************************************************/
488 |
489 | void testdipent(int seq, int variant)
490 | {
491 |
492 | /*
493 | * Initialize the dipent structure for the test case.
494 | */
495 |
496 | int i;
497 | long now;
498 |
499 | time(&now);
500 |
501 | newdipent("test", variant);
502 | sprintf(dipent.seq, "%03d", seq);
503 | strcpy(dipent.phase, "?1901?");
504 |
505 | dipent.process = now - 1;
506 | dipent.deadline = now - 1;
507 | dipent.start = now - 1;
508 | dipent.grace = now - 1;
509 | dipent.n = WILD_PLAYER;
510 | for (i = 0; i < dipent.n; i++) {
511 | dipent.players[i].power = i;
512 | dipent.players[i].status = 0;
513 | dipent.players[i].siteid = 0;
514 | dipent.players[i].userid = 0;
515 | dipent.players[i].late_count = 0;
516 | dipent.players[i].centres_blockaded = 0;
517 | strcpy(dipent.players[i].password, "spud");
518 | strcpy(dipent.players[i].address, "*");
519 | }
520 | dipent.players[0].power = power('o');
521 | strcpy(dipent.players[0].password, "spud");
522 | strcpy(dipent.players[0].address, GAMES_MASTER);
523 | }
524 |
525 | /***********************************************************************/
526 |
527 | int getseq(FILE * fp, char *line, sequence * seq)
528 | {
529 |
530 | static char *keys[] =
531 | {"", "clock", "c", "min", "m", "next", "n",
532 | "grace", "g", "delay", "de", "days", "day", "da"};
533 | static char action[] =
534 | {'x', 'c', 'c', 'm', 'm', 'n', 'n',
535 | 'g', 'g', 'd', 'd', 'D', 'D', 'D'};
536 | int i;
537 | char *p, *s, *t, word[30];
538 | float f;
539 |
540 | for (s = line; !isspace(*s); s++);
541 | while (isspace(*s))
542 | s++;
543 |
544 | while (*s) {
545 | s = lookfor(s, keys, nentry(keys), &i);
546 | switch (action[i]) {
547 | case 'c':
548 | if (sscanf(s, "%d", &i) != 1 || i > 1440) {
549 | fprintf(fp, "%sBad clock specification.\n", line);
550 | return 1;
551 | }
552 | seq->clock = i;
553 | break;
554 |
555 | case 'm':
556 | if (sscanf(s, "%f", &f) != 1 || f < 0) {
557 | fprintf(fp, "%sBad minimum time specification.\n", line);
558 | return 1;
559 | }
560 | seq->mint = f;
561 | break;
562 |
563 | case 'n':
564 | if (sscanf(s, "%f", &f) != 1 || f < 0) {
565 | fprintf(fp, "%sBad next time specification.\n", line);
566 | return 1;
567 | }
568 | seq->next = f;
569 | break;
570 |
571 | case 'g':
572 | if (sscanf(s, "%f", &f) != 1 || f < 0) {
573 | fprintf(fp, "%sBad grace time specification.\n", line);
574 | return 1;
575 | }
576 | seq->grace = f;
577 | break;
578 |
579 | case 'd':
580 | if (sscanf(s, "%f", &f) != 1 || f < 0) {
581 | fprintf(fp, "%sBad delay time specification.\n", line);
582 | return 1;
583 | }
584 | seq->delay = f;
585 | break;
586 |
587 | case 'D':
588 | if (sscanf(s, "%10s", word) != 1) {
589 | fprintf(fp, "%s,Bad list of days specification.\n", line);
590 | return 1;
591 | }
592 | for (p = word, t = "SMTWTFS"; *t; t++, p++) {
593 | if (*p != *t && *p != tolower(*t) && *p != '-') {
594 | fprintf(fp, "%sBad list of days specified.\n", line);
595 | return 1;
596 | }
597 | }
598 | *p = '\0';
599 | strcpy(seq->days, word);
600 | if (!strcmp(seq->days, "-------")) {
601 | fprintf(fp, "%sAt least one day of the week must be allowed.\n", line);
602 | return 1;
603 | }
604 | break;
605 |
606 | default:
607 | sscanf(s, "%s", word);
608 | fprintf(fp, "Invalid keyword %s.\n", word);
609 | return 1;
610 | break;
611 | }
612 |
613 | while (*s && !isspace(*s))
614 | s++;
615 | while (isspace(*s))
616 | s++;
617 | }
618 | return 0;
619 | }
620 |
621 | /***********************************************************************/
622 |
623 | void putseq(FILE * fp, char *s, sequence * seq)
624 | {
625 | if (*seq->days)
626 | fprintf(fp,
627 | "%-9.9s clock %4d min %5.2f next %6.2f grace %6.2f delay %.2f days %s\n",
628 | s, seq->clock, seq->mint, seq->next, seq->grace, seq->delay, seq->days);
629 | }
630 |
631 | /***********************************************************************/
632 |
633 | void gettime(char *line, long *time)
634 | {
635 |
636 | char *s, *t;
637 |
638 | for (s = line; !isspace(*s); s++);
639 | while (isspace(*s))
640 | s++;
641 |
642 | for (t = s; *t && *t != '('; t++);
643 | if (*t == '(' && (*time = atol(t + 1)))
644 | return;
645 |
646 | if (jm(s, time)) {
647 | fprintf(stderr, "Error processing '%s' %s", dipent.name, line);
648 | bailout(E_FATAL);
649 | }
650 | }
651 |
652 | /***********************************************************************/
653 |
654 | void getplay(char *line, Player * p)
655 | {
656 |
657 | int i;
658 | char c;
659 |
660 | *p->pref = '\0';
661 | /* You'd better be really sure you've not messed with absence array limit! */
662 | i = sscanf(line, "%c%*s %x %d %d %d %d %s %s %d %d %d %ld %ld %ld %ld %ld %ldi %ld", &c, &p->status,
663 | &p->units, &p->centers, &p->userid, &p->siteid,
664 | p->password, p->address, &p->late_count, &p->centres_blockaded,
665 | &p->absence_count,
666 | &p->absence_start[0], &p->absence_end[0],
667 | &p->absence_start[1], &p->absence_end[1],
668 | &p->absence_start[2], &p->absence_end[2],
669 | &p->absence_total);
670 | switch (i)
671 | {
672 | case 8: {
673 | /* versions prior to 0.8.7 which had no late count */
674 | p->late_count = 0; /* initialise it to something! */
675 | }
676 | case 9: {
677 | p->centres_blockaded = 0;
678 | }
679 | case 10: {
680 | /* versions 0.8.7 and up are fine here! */
681 | p->absence_count = 0;
682 | p->absence_start[0] = p->absence_end[0] = 0;
683 | p->absence_start[1] = p->absence_end[1] = 0;
684 | p->absence_start[2] = p->absence_end[2] = 0;
685 | }
686 | case 17: {
687 | /* versions 0.8.7 and up are fine here! */
688 | p->absence_total = 0;
689 | break;
690 | }
691 | case 18: {
692 | /* OK, this is the latest one! */
693 | }
694 |
695 |
696 | default: {
697 | /* OK, we've got a problem: bailout */
698 | fprintf(stderr, "Bad player entry for '%s'. Only found %d items.\n%s\n",
699 | dipent.name, i, line);
700 | bailout(E_FATAL);
701 | }
702 | }
703 | /*
704 | * The following 2 lines are to intended to cover the removal of the
705 | * alternate from the judge code. This code will automatically
706 | * replace alternates that might still be in the dip.master file and
707 | * make them observers.
708 | */
709 | if (c == '%')
710 | c = 'o';
711 | if (!(p->power = power(c))) {
712 | fprintf(stderr, "Invalid power character: %s\n", line);
713 | bailout(E_FATAL);
714 | }
715 | }
716 |
717 | void putplay(FILE * fp, Player * p, int dopw)
718 | {
719 | #define MAX_OUTPOWER 9
720 | char c;
721 | /* Outpower will allow powers with spaces in names to be used */
722 | char out_power[MAX_OUTPOWER];
723 | int i;
724 |
725 | if (p->power >= 0) {
726 | strncpy(out_power, powers[p->power], MAX_OUTPOWER - 1);
727 | out_power[MAX_OUTPOWER-1] = '\0';
728 | for (i=0; out_power[i] != '\0' && i < MAX_OUTPOWER; i++) {
729 | /* Substitute space with '_' to prevent crash on fscanf */
730 | if (out_power[i] == ' ') out_power[i] = '_';
731 | }
732 |
733 | if (isupper(c = dipent.pl[p->power]))
734 | c = tolower(c);
735 | fprintf(fp, "%c%-8s %4x %2d %2d %3d %5d %-12s %s %4d %2d %d %ld %ld %ld %ld %ld %ld %ld\n",
736 | c, &out_power[1],
737 | p->status, p->units, p->centers, p->userid, p->siteid,
738 | dopw ? p->password : "xxx", p->address,p->late_count, p->centres_blockaded,
739 | p->absence_count,
740 | p->absence_start[0], p->absence_end[0],
741 | p->absence_start[1], p->absence_end[1],
742 | p->absence_start[2], p->absence_end[2],
743 | p->absence_total);
744 | if (*(p->pref))
745 | fprintf(fp, "_pref: %s\n", p->pref);
746 | }
747 | }
748 |
749 | int countgames(void)
750 | {
751 | FILE *mf;
752 | char line[1024];
753 | int gamecount = 0;
754 | int len;
755 |
756 | if (!(mf = fopen(MASTER_FILE, "r"))) {
757 | perror(MASTER_FILE);
758 | }
759 | do {
760 | fgets(line, sizeof(line), mf);
761 | if (feof(mf))
762 | break;
763 | /* TODO check for an error */
764 | len = strlen(line);
765 | if (len && line[len - 1] == '\n') {
766 | line[len - 1] = '\0';
767 | }
768 | if (!strcmp("-", line)) {
769 | gamecount++;
770 | }
771 | } while (!feof(mf));
772 |
773 | fclose(mf);
774 |
775 | /* the control game will be counted by above */
776 | return gamecount - 1;
777 | }