]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
(xundump1): Don't suppress table growth just because it has NSC_CONST
[empserver] / src / lib / common / xundump.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  xundump.c: Load back xdump output
29  * 
30  *  Known contributors to this file:
31  *     Ron Koenderink, 2005
32  *     Markus Armbruster, 2005
33  */
34
35 /* FIXME normalize terminology: table/rows/columns or file/records/fields */
36
37 #include <config.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 #include <ctype.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include <time.h>
46
47 #include "file.h"
48 #include "match.h"
49 #include "nsc.h"
50 #include "optlist.h"
51 #include "prototypes.h"
52
53 static char *fname;
54 static int lineno;
55 static int human;
56 static int cur_type;
57 static void *cur_obj;
58 static int nflds;
59 static struct castr **fldca;
60 static int *fldidx;
61 static int *caflds;
62
63 static int gripe(char *, ...) ATTRIBUTE((format (printf, 1, 2)));
64 static int deffld(int, char *, int);
65 static int setnum(int, double);
66 static int setstr(int, char *);
67 static int xunsymbol1(char *, struct symbol *, struct castr *, int);
68 static int setsym(int, char *);
69 static int mtsymset(int, long *);
70 static int add2symset(int, long *, char *);
71 static struct symbol *get_symtab(struct castr *);
72 static int xundump1(FILE *, int, struct castr *);
73
74 static int
75 gripe(char *fmt, ...)
76 {
77     va_list ap;
78
79     fprintf(stderr, "%s:%d: ", fname, lineno);
80     va_start(ap, fmt);
81     vfprintf(stderr, fmt, ap);
82     va_end(ap);
83     putc('\n', stderr);
84
85     return -1;
86 }
87
88 static int
89 skipfs(FILE *fp)
90 {
91     int ch;
92
93     do {
94         ch = getc(fp);
95     } while (ch == ' ' || ch == '\t');
96
97     if (ch == '#') {
98         do {
99             ch = getc(fp);
100         } while (ch != EOF && ch != '\n');
101     }
102
103     return ch;
104 }
105
106 static int
107 getid(FILE *fp, char *buf)
108 {
109     int n;
110     if (fscanf(fp, "%1023[^#() \t\n]%n", buf, &n) != 1 || !isalpha(buf[0]))
111         return -1;
112     return n;
113 }
114
115 static char *
116 xuesc(char *buf)
117 {
118     char *src, *dst;
119     int octal_chr, n;
120
121     dst = buf;
122     src = buf;
123     while (*src) {
124         if (*src == '\\') {
125             if (sscanf(++src, "%3o%n", &octal_chr, &n) != 1 || n != 3)
126                 return NULL;
127             *dst++ = (char)octal_chr;
128             src += 3;
129         } else
130             *dst++ = *src++;
131     }
132     *dst = '\0';
133     return buf;
134 }
135
136 static int
137 xufldname(FILE *fp, int i)
138 {
139     int ch, idx;
140     char buf[1024];
141
142     ch = skipfs(fp);
143     switch (ch) {
144     case EOF:
145         return gripe("Unexpected EOF");
146     case '\n':
147         if (i != nflds)
148             return gripe("Header fields missing"); /* TODO which? */
149         lineno++;
150         return 0;
151     default:
152         ungetc(ch, fp);
153         if (getid(fp, buf) < 0)
154             return gripe("Junk in header field %d", i + 1);
155         ch = getc(fp);
156         if (ch != '(') {
157             ungetc(ch, fp);
158             return deffld(i, buf, -1);
159         }
160         ch = getc(fp);
161         ungetc(ch, fp);
162         if (isdigit(ch) || ch == '-' || ch == '+') {
163             if (fscanf(fp, "%d", &idx) != 1)
164                 return gripe("Malformed number in index of header field %d",
165                              i + 1);
166             if (idx < 0)
167                 return gripe("Index must not be negative in header field %d",
168                              i + 1);
169         } else {
170             if (getid(fp, buf) < 0)
171                 return gripe("Malformed index in header field %d", i + 1);
172             return gripe("Symbolic index in header field %d not yet implemented",
173                          i + 1);
174         }
175         ch = getc(fp);
176         if (ch != ')')
177             return gripe("Malformed index in header field %d", i + 1);
178         return deffld(i, buf, idx);
179     }
180 }
181
182 static int
183 xufld(FILE *fp, int i)
184 {
185     int ch;
186     char buf[1024];
187     double dbl;
188     long set;
189
190     ch = skipfs(fp);
191     switch (ch) {
192     case EOF:
193         return gripe("Unexpected EOF");
194     case '\n':
195         if (i != nflds)
196             return gripe("Field %s missing", fldca[i]->ca_name);
197         lineno++;
198         return 0;
199     case '+': case '-': case '.':
200     case '0': case '1': case '2': case '3': case '4':
201     case '5': case '6': case '7': case '8': case '9':
202         ungetc(ch, fp);
203         if (fscanf(fp, "%lg", &dbl) != 1)
204             return gripe("Malformed number in field %d", i + 1);
205         return setnum(i, dbl);
206     case '"':
207         ch = getc(fp);
208         if (ch == '"')
209             buf[0] = 0;
210         else {
211             ungetc(ch, fp);
212             if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
213                 return gripe("Malformed string in field %d", i + 1);
214             if (!xuesc(buf))
215                 return gripe("Invalid escape sequence in field %d",
216                              i + 1);
217         }
218         return setstr(i, buf);
219     case '(':
220         if (mtsymset(i, &set) < 0)
221             return -1;
222         for (;;) {
223             ch = skipfs(fp);
224             if (ch == EOF || ch == '\n')
225                 return gripe("Unmatched '(' in field %d", i + 1);
226             if (ch == ')')
227                 break;
228             ungetc(ch, fp);
229             if (getid(fp, buf) < 0)
230                 return gripe("Junk in field %d", i + 1);
231             if (add2symset(i, &set, buf) < 0)
232                 return -1;
233         }
234         return setnum(i, set);
235     default:
236         ungetc(ch, fp);
237         if (getid(fp, buf) < 0)
238             return gripe("Junk in field %d", i + 1);
239         if (!strcmp(buf, "nil"))
240             return setstr(i, NULL);
241         else
242             return setsym(i, buf);
243     }
244 }
245
246 static int
247 xuflds(FILE *fp, int (*parse)(FILE *, int))
248 {
249     int i, ch, res;
250
251     for (i = 0; ; i++) {
252         res = parse(fp, i);
253         if (res < 0)
254             return -1;
255         if (res == 0)
256             return i;
257         ch = getc(fp);
258         if (ch == '\n')
259             ungetc(ch, fp);
260         else if (ch != ' ' && ch != '\t')
261             return gripe("Bad field separator after field %d", i + 1);
262     }
263 }
264
265 static int
266 deffld(int fldno, char *name, int idx)
267 {
268     struct castr *ca = ef_cadef(cur_type);
269     int res;
270
271     res = stmtch(name, ca, offsetof(struct castr, ca_name),
272                      sizeof(struct castr));
273     if (res < 0)
274         return gripe("Header %s of field %d is %s", name, fldno + 1,
275                      res == M_NOTUNIQUE ? "ambiguous" : "unknown");
276     if (ca[res].ca_type != NSC_STRINGY && ca[res].ca_len != 0) {
277         if (idx < 0)
278             return gripe("Header %s requires an index in field %d",
279                          ca[res].ca_name, fldno + 1);
280         if (idx >= ca[res].ca_len)
281             return gripe("Header %s(%d) index out of bounds in field %d",
282                          ca[res].ca_name, idx, fldno + 1);
283         if (idx < caflds[res])
284             return gripe("Duplicate header %s(%d) in field %d",
285                          ca[res].ca_name, idx, fldno + 1);
286         if (idx > caflds[res])
287             return gripe("Expected header %s(%d) in field %d",
288                          ca[res].ca_name, caflds[res], fldno + 1);
289     } else {
290         if (idx >= 0)
291             return gripe("Header %s doesn't take an index in field %d",
292                          ca[res].ca_name, fldno + 1);
293         idx = 0;
294         if (caflds[res])
295             return gripe("Duplicate header %s in field %d",
296                          ca[res].ca_name, fldno + 1);
297     }
298     fldca[fldno] = &ca[res];
299     fldidx[fldno] = idx;
300     caflds[res]++;
301     return 1;
302 }
303
304 static struct castr *
305 getfld(int fldno, int *idx)
306 {
307     if (fldno >= nflds) {
308         gripe("Too many fields, expected only %d", nflds);
309         return NULL;
310     }
311     if (CANT_HAPPEN(fldno < 0))
312         return NULL;
313     if (idx)
314         *idx = fldidx[fldno];
315     return fldca[fldno];
316 }
317
318 static int
319 setnum(int fldno, double dbl)
320 {
321     struct castr *ca;
322     int idx;
323     char *memb_ptr;
324     double old;
325
326     ca = getfld(fldno, &idx);
327     if (!ca)
328         return -1;
329
330     memb_ptr = cur_obj;
331     memb_ptr += ca->ca_off;
332     switch (ca->ca_type) {
333     case NSC_CHAR:
334     case NSC_TYPEID:
335         old = ((signed char *)memb_ptr)[idx];
336         ((signed char *)memb_ptr)[idx] = (signed char)dbl;
337         break;
338     case NSC_UCHAR:
339         old = ((unsigned char *)memb_ptr)[idx];
340         ((unsigned char *)memb_ptr)[idx] = (unsigned char)dbl;
341         break;
342     case NSC_SHORT:
343         old = ((short *)memb_ptr)[idx];
344         ((short *)memb_ptr)[idx] = (short)dbl;
345         break;
346     case NSC_USHORT:
347         old = ((unsigned short *)memb_ptr)[idx];
348         ((unsigned short *)memb_ptr)[idx] = (unsigned short)dbl;
349         break;
350     case NSC_INT:
351         old = ((int *)memb_ptr)[idx];
352         ((int *)memb_ptr)[idx] = (int)dbl;
353         break;
354     case NSC_LONG:
355         old = ((long *)memb_ptr)[idx];
356         ((long *)memb_ptr)[idx] = (long)dbl;
357         break;
358     case NSC_XCOORD:
359         old = ((coord *)memb_ptr)[idx];
360         /* FIXME use variant of xrel() that takes orig instead of nation */
361         if (old >= WORLD_X / 2)
362             old -= WORLD_X;
363         ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
364         break;
365     case NSC_YCOORD:
366         old = ((coord *)memb_ptr)[idx];
367         /* FIXME use variant of yrel() that takes orig instead of nation */
368         if (old >= WORLD_Y / 2)
369             old -= WORLD_Y;
370         ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
371         break;
372     case NSC_FLOAT:
373         old = ((float *)memb_ptr)[idx];
374         ((float *)memb_ptr)[idx] = (float)dbl;
375         break;
376     case NSC_DOUBLE:
377         old = ((double *)memb_ptr)[idx];
378         ((double *)memb_ptr)[idx] = dbl;
379         break;
380     case NSC_TIME:
381         old = ((time_t *)memb_ptr)[idx];
382         ((time_t *)memb_ptr)[idx] = (time_t)dbl;
383         break;
384     default:
385         return gripe("Field %d doesn't take numbers", fldno + 1);
386     }
387
388     if ((ca->ca_flags & NSC_CONST) && old != dbl)
389         return gripe("Value for field %d must be %g", fldno + 1, old);
390
391     return 1;
392 }
393
394 static int
395 setstr(int fldno, char *str)
396 {
397     struct castr *ca;
398     int idx;
399     size_t len;
400     char *memb_ptr, *old;
401
402     ca = getfld(fldno, &idx);
403     if (!ca)
404         return -1;
405
406     memb_ptr = cur_obj;
407     memb_ptr += ca->ca_off;
408     switch (ca->ca_type) {
409     case NSC_STRING:
410         old = ((char **)memb_ptr)[idx];
411         if (!(ca->ca_flags & NSC_CONST))
412             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
413         len = 65535;            /* really SIZE_MAX, but it's C99 */
414         break;
415     case NSC_STRINGY:
416         if (CANT_HAPPEN(idx))
417             return -1;
418         if (!str)
419             return gripe("Field doesn't take nil");
420         len = ca->ca_len;
421         if (strlen(str) > len)
422             return gripe("Field %d takes at most %d characters",
423                          fldno + 1, len);
424         old = memb_ptr;
425         if (!(ca->ca_flags & NSC_CONST))
426             strncpy(memb_ptr, str, len);
427         break;
428     default:
429         return gripe("Field %d doesn't take strings", fldno + 1);
430     }
431
432     if (ca->ca_flags & NSC_CONST) {
433         if (old && (!str || strncmp(old, str, len)))
434             return gripe("Value for field %d must be \"%.*s\"",
435                          fldno + 1, len, old);
436         if (!old && str)
437             return gripe("Value for field %d must be nil", fldno + 1);
438     }
439
440     return 1;
441 }
442
443 static int
444 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
445 {
446     int i = stmtch(id, symtab, offsetof(struct symbol, name),
447                    sizeof(struct symbol));
448     if (i < 0)
449         return gripe("%s %s symbol `%s' in field %d",
450                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
451                      ca->ca_name, id, n);
452     return i;
453 }
454
455 static int
456 setsym(int fldno, char *sym)
457 {
458     struct castr *ca;
459     struct symbol *symtab;
460     int i;
461
462     ca = getfld(fldno, NULL);
463     if (!ca)
464         return -1;
465
466     symtab = get_symtab(ca);
467     if (!symtab || (ca->ca_flags & NSC_BITS))
468         return gripe("Field %d doesn't take symbols", fldno + 1);
469
470     i = xunsymbol1(sym, symtab, ca, fldno);
471     if (i < 0)
472         return -1;
473     return setnum(fldno, symtab[i].value);
474 }
475
476 static int
477 mtsymset(int fldno, long *set)
478 {
479     struct castr *ca;
480     struct symbol *symtab;
481
482     ca = getfld(fldno, NULL);
483     if (!ca)
484         return -1;
485
486     symtab = get_symtab(ca);
487     if (!symtab || !(ca->ca_flags & NSC_BITS)) {
488         return gripe("Field %d doesn't take symbol sets", fldno + 1);
489     }
490     *set = 0;
491     return 0;
492 }
493
494 static int
495 add2symset(int fldno, long *set, char *sym)
496 {
497     struct castr *ca;
498     struct symbol *symtab;
499     int i;
500
501     ca = getfld(fldno, NULL);
502     if (!ca)
503         return -1;
504
505     symtab = get_symtab(ca);
506     i = xunsymbol1(sym, symtab, ca, fldno);
507     if (i < 0)
508         return -1;
509     *set |= symtab[i].value;
510     return 0;
511 }
512
513 static struct symbol *
514 get_symtab(struct castr *ca)
515 {
516     int symtype = ca->ca_table;
517     struct symbol *symtab;
518
519     if (symtype == EF_BAD || ef_cadef(symtype) != symbol_ca)
520         return NULL;
521
522     symtab = ef_ptr(symtype, 0);
523     CANT_HAPPEN(!symtab);
524     return symtab;
525 }
526
527 static int
528 xuheader(FILE *fp, int expected_table)
529 {
530     char name[64];
531     int res, ch;
532     int type;
533
534     while ((ch = skipfs(fp)) == '\n')
535         lineno++;
536     if (ch == EOF && expected_table == EF_BAD)
537         return -2;
538     ungetc(ch, fp);
539
540     human = ch == 'c';
541     res = -1;
542     if ((human
543          ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
544          : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
545                   name, &res) != 1) || res < 0)
546         return gripe("Expected xdump header");
547
548     type = ef_byname(name);
549     if (type < 0)
550         return gripe("Unknown table `%s'", name);
551     if (expected_table != EF_BAD && expected_table != type)
552         return gripe("Expected table `%s', not `%s'",
553                      ef_nameof(expected_table), name);
554
555     if (!ef_cadef(type) || !(ef_flags(type) & EFF_MEM)) {
556         CANT_HAPPEN(expected_table != EF_BAD);
557         return gripe("Undumping of table `%s' not implemented", name);
558     }
559
560     if (skipfs(fp) != '\n')
561         return gripe("Junk after xdump header");
562     lineno++;
563
564     return type;
565 }
566
567 static int
568 xuheader1(FILE *fp, int type, struct castr ca[])
569 {
570     struct castr **fca;
571     int *fidx;
572     int ch, i, j, n;
573
574     cur_type = type;
575
576     if (human) {
577         while ((ch = skipfs(fp)) == '\n')
578             lineno++;
579         ungetc(ch, fp);
580         if (xuflds(fp, xufldname) < 0)
581             return -1;
582     } else {
583         fca = fldca;
584         fidx = fldidx;
585
586         for (i = 0; ca[i].ca_name; i++) {
587             if ((ca[i].ca_flags & NSC_EXTRA))
588                 continue;
589             n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
590             j = 0;
591             do {
592                 *fca++ = &ca[i];
593                 *fidx++ = j;
594             } while (++j < n);
595         }
596     }
597
598     return 0;
599 }
600
601 static int
602 xutrailer(FILE *fp, int type, int row)
603 {
604     int rows, res;
605
606     res = -1;
607     if (human) {
608         if (fscanf(fp, "config%n",  &res) != 0 || res < 0)
609             return gripe("Malformed table footer");
610     } else {
611         if (fscanf(fp, "%d", &rows) != 1)
612             return gripe("Malformed table footer");
613         if (row != rows)
614             return gripe("Read %d rows, which doesn't match footer "
615                          "%d rows", row, rows);
616     }
617     if (skipfs(fp) != '\n')
618         return gripe("Junk after table footer");
619     lineno++;
620
621     return 0;
622 }
623
624 int
625 xundump(FILE *fp, char *file, int expected_table)
626 {
627     struct castr *ca;
628     int type, nca, i, ch;
629
630     if (fname != file) {
631         fname = file;
632         lineno = 1;
633     }
634
635     if ((type = xuheader(fp, expected_table)) < 0)
636         return type;
637
638     ca = ef_cadef(type);
639     if (CANT_HAPPEN(!ca))
640         return -1;
641
642     nca = nflds = 0;
643     for (i = 0; ca[i].ca_name; i++) {
644         nca++;
645         if (!(ca[i].ca_flags & NSC_EXTRA))
646             nflds += MAX(1, ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0);
647     }
648     fldca = calloc(nflds, sizeof(*fldca));
649     fldidx = calloc(nflds, sizeof(*fldidx));
650     caflds = calloc(nca, sizeof(*caflds));
651
652     if (xuheader1(fp, type, ca) < 0 || xundump1(fp, type, ca) < 0)
653         type = EF_BAD;
654
655     free(caflds);
656     free(fldidx);
657     free(fldca);
658
659     /* Skip empty lines so that callers can easily check for EOF */
660     while ((ch = skipfs(fp)) == '\n')
661         lineno++;
662     ungetc(ch, fp);
663
664     return type;
665 }
666
667 static int
668 xundump1(FILE *fp, int type, struct castr *ca)
669 {
670     struct empfile *ep = &empfile[type];
671     int need_sentinel = !EF_IS_GAME_STATE(type);
672     int row, ch;
673
674     cur_type = type;
675
676     for (row = 0;; ++row) {
677         while ((ch = skipfs(fp)) == '\n')
678             lineno++;
679         if (ch == '/')
680             break;
681         ungetc(ch, fp);
682         /* TODO ability to skip records */
683         if (row >= ep->fids) {
684             /* TODO grow cache (and posssibly file) unless EFF_STATIC */
685             if (row < ep->csize - !!need_sentinel)
686                 ep->cids = ep->fids = row + 1;
687             /* else: ef_ptr() will fail */
688         }
689         cur_obj = ef_ptr(type, row);
690         if (!cur_obj)
691             return gripe("Too many rows for table %s", ef_nameof(type));
692         if (xuflds(fp, xufld) < 0)
693             return -1;
694     }
695
696     if (CANT_HAPPEN(row > ep->fids))
697         row = ep->fids;
698     if (row < ep->fids) {
699         if (EF_IS_GAME_STATE(type) && row != ep->csize)
700             /* TODO truncate file */
701             gripe("Warning: should resize table %s from %d to %d, not implemented",
702                   ef_nameof(type), ep->csize, row);
703         else if (type >= EF_SHIP_CHR && type <= EF_NUKE_CHR)
704             ;                   /* shrinking these is okay */
705         else
706             return gripe("Table %s requires %d rows, got %d",
707                          ef_nameof(type), ep->fids, row);
708     }
709
710     if (need_sentinel) {
711         if (CANT_HAPPEN(row >= ep->csize))
712             return gripe("No space for sentinel");
713         memset(ep->cache + ep->size * row, 0, ep->size);
714     }
715
716     if (xutrailer(fp, type, row) < 0)
717         return -1;
718
719     return 0;
720 }