]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
(xundump): Rev. 1.44 broke ef_load(). Fix.
[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         ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
361         break;
362     case NSC_YCOORD:
363         old = ((coord *)memb_ptr)[idx];
364         ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
365         break;
366     case NSC_FLOAT:
367         old = ((float *)memb_ptr)[idx];
368         ((float *)memb_ptr)[idx] = (float)dbl;
369         break;
370     case NSC_DOUBLE:
371         old = ((double *)memb_ptr)[idx];
372         ((double *)memb_ptr)[idx] = dbl;
373         break;
374     case NSC_TIME:
375         old = ((time_t *)memb_ptr)[idx];
376         ((time_t *)memb_ptr)[idx] = (time_t)dbl;
377         break;
378     default:
379         return gripe("Field %d doesn't take numbers", fldno + 1);
380     }
381
382     if ((ca->ca_flags & NSC_CONST) && old != dbl)
383         return gripe("Value for field %d must be %g", fldno + 1, old);
384
385     return 1;
386 }
387
388 static int
389 setstr(int fldno, char *str)
390 {
391     struct castr *ca;
392     int idx;
393     char *memb_ptr, *old;
394
395     ca = getfld(fldno, &idx);
396     if (!ca)
397         return -1;
398
399     memb_ptr = cur_obj;
400     memb_ptr += ca->ca_off;
401     switch (ca->ca_type) {
402     case NSC_STRING:
403         old = ((char **)memb_ptr)[idx];
404         if (!(ca->ca_flags & NSC_CONST))
405             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
406         break;
407     case NSC_STRINGY:
408         if (CANT_HAPPEN(idx))
409             return -1;
410         if (!str)
411             return gripe("Field doesn't take nil");
412         if (strlen(str) > ca->ca_len)
413             return gripe("Field %d takes at most %d characters",
414                          fldno + 1, ca->ca_len);
415         old = memb_ptr;
416         if (!(ca->ca_flags & NSC_CONST))
417             strncpy(memb_ptr, str, ca->ca_len);
418         break;
419     default:
420         return gripe("Field %d doesn't take strings", fldno + 1);
421     }
422
423     if (ca->ca_flags & NSC_CONST) {
424         if (old && (!str || strcmp(old, str)))
425             return gripe("Value for field %d must be \"%s\"", fldno + 1, old);
426         if (!old && str)
427             return gripe("Value for field %d must be nil", fldno + 1);
428     }
429
430     return 1;
431 }
432
433 static int
434 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
435 {
436     int i = stmtch(id, symtab, offsetof(struct symbol, name),
437                    sizeof(struct symbol));
438     if (i < 0)
439         return gripe("%s %s symbol `%s' in field %d",
440                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
441                      ca->ca_name, id, n);
442     return i;
443 }
444
445 static int
446 setsym(int fldno, char *sym)
447 {
448     struct castr *ca;
449     struct symbol *symtab;
450     int i;
451
452     ca = getfld(fldno, NULL);
453     if (!ca)
454         return -1;
455
456     symtab = get_symtab(ca);
457     if (!symtab || (ca->ca_flags & NSC_BITS))
458         return gripe("Field %d doesn't take symbols", fldno + 1);
459
460     i = xunsymbol1(sym, symtab, ca, fldno);
461     if (i < 0)
462         return -1;
463     return setnum(fldno, symtab[i].value);
464 }
465
466 static int
467 has_const(struct castr ca[])
468 {
469     int i;
470
471     for (i = 0; ca[i].ca_name; i++) {
472         if (ca[i].ca_flags & NSC_CONST)
473             return 1;
474     }
475     return 0;
476 }
477
478 static int
479 mtsymset(int fldno, long *set)
480 {
481     struct castr *ca;
482     struct symbol *symtab;
483
484     ca = getfld(fldno, NULL);
485     if (!ca)
486         return -1;
487
488     symtab = get_symtab(ca);
489     if (!symtab || !(ca->ca_flags & NSC_BITS)) {
490         return gripe("Field %d doesn't take symbol sets", fldno + 1);
491     }
492     *set = 0;
493     return 0;
494 }
495
496 static int
497 add2symset(int fldno, long *set, char *sym)
498 {
499     struct castr *ca;
500     struct symbol *symtab;
501     int i;
502
503     ca = getfld(fldno, NULL);
504     if (!ca)
505         return -1;
506
507     symtab = get_symtab(ca);
508     i = xunsymbol1(sym, symtab, ca, fldno);
509     if (i < 0)
510         return -1;
511     *set |= symtab[i].value;
512     return 0;
513 }
514
515 static struct symbol *
516 get_symtab(struct castr *ca)
517 {
518     int symtype = ca->ca_table;
519     struct symbol *symtab;
520
521     if (symtype == EF_BAD || ef_cadef(symtype) != symbol_ca)
522         return NULL;
523
524     symtab = ef_ptr(symtype, 0);
525     CANT_HAPPEN(!symtab);
526     return symtab;
527 }
528
529 static int
530 xuheader(FILE *fp, int expected_table)
531 {
532     char name[64];
533     int res, ch;
534     int type;
535
536     while ((ch = skipfs(fp)) == '\n')
537         lineno++;
538     if (ch == EOF && expected_table == EF_BAD)
539         return -1;
540     ungetc(ch, fp);
541
542     human = ch == 'c';
543     res = -1;
544     if ((human
545          ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
546          : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
547                   name, &res) != 1) || res < 0)
548         return gripe("Expected xdump header");
549
550     type = ef_byname(name);
551     if (type < 0)
552         return gripe("Unknown table `%s'", name);
553     if (expected_table != EF_BAD && expected_table != type)
554         return gripe("Expected table `%s', not `%s'",
555                      ef_nameof(expected_table), name);
556
557     if (!ef_cadef(type) || !(ef_flags(type) & EFF_MEM)) {
558         CANT_HAPPEN(expected_table != EF_BAD);
559         return gripe("Undumping of table `%s' not implemented", name);
560     }
561
562     if (skipfs(fp) != '\n')
563         return gripe("Junk after xdump header");
564     lineno++;
565
566     return type;
567 }
568
569 static int
570 xutrailer(FILE *fp, int type, int row)
571 {
572     int rows, res;
573
574     res = -1;
575     if (human) {
576         if (fscanf(fp, "config%n",  &res) != 0 || res < 0)
577             return gripe("Malformed table footer");
578     } else {
579         if (fscanf(fp, "%d", &rows) != 1)
580             return gripe("Malformed table footer");
581         if (row != rows)
582             return gripe("Read %d rows, which doesn't match footer "
583                          "%d rows", row, rows);
584     }
585     if (skipfs(fp) != '\n')
586         return gripe("Junk after table footer");
587     lineno++;
588
589     return 0;
590 }
591
592 int
593 xundump(FILE *fp, char *file, int expected_table)
594 {
595     struct castr *ca;
596     int type, nca, i, ch;
597
598     if (fname != file) {
599         fname = file;
600         lineno = 1;
601     }
602
603     if ((type = xuheader(fp, expected_table)) < 0)
604         return -1;
605
606     ca = ef_cadef(type);
607     if (CANT_HAPPEN(!ca))
608         return -1;
609
610     nca = nflds = 0;
611     for (i = 0; ca[i].ca_name; i++) {
612         nca++;
613         if (!(ca[i].ca_flags & NSC_EXTRA))
614             nflds += MAX(1, ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0);
615     }
616     fldca = calloc(nflds, sizeof(*fldca));
617     fldidx = calloc(nflds, sizeof(*fldidx));
618     caflds = calloc(nca, sizeof(*caflds));
619
620     cur_type = type;
621     if (human) {
622         while ((ch = skipfs(fp)) == '\n')
623             lineno++;
624         ungetc(ch, fp);
625         if (xuflds(fp, xufldname) < 0)
626             type = EF_BAD;
627     } else {
628         struct castr **fca = fldca;
629         int *fidx = fldidx;
630         int i, j, n;
631         for (i = 0; ca[i].ca_name; i++) {
632             if ((ca[i].ca_flags & NSC_EXTRA))
633                 continue;
634             n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
635             j = 0;
636             do {
637                 *fca++ = &ca[i];
638                 *fidx++ = j;
639             } while (++j < n);
640         }
641     }
642
643     if (type >= 0 && xundump1(fp, type, ca) < 0)
644         type = EF_BAD;
645
646     free(caflds);
647     free(fldidx);
648     free(fldca);
649
650     /* Skip empty lines so that callers can easily check for EOF */
651     while ((ch = skipfs(fp)) == '\n')
652         lineno++;
653     ungetc(ch, fp);
654
655     return type;
656 }
657
658 static int
659 xundump1(FILE *fp, int type, struct castr *ca)
660 {
661     struct empfile *ep = &empfile[type];
662     int fixed_rows = has_const(ca);
663     int need_sentinel = !EF_IS_GAME_STATE(type);
664     int row, ch;
665
666     for (row = 0;; ++row) {
667         while ((ch = skipfs(fp)) == '\n')
668             lineno++;
669         if (ch == '/')
670             break;
671         ungetc(ch, fp);
672         /* TODO ability to skip records */
673         if (!fixed_rows) {
674             if (row >= ep->csize - !!need_sentinel)
675                 /* TODO grow cache unless EFF_STATIC */
676                 return gripe("Too many rows for table %s", ef_nameof(type));
677             if (row >= ep->cids)
678                 /* TODO grow file */
679                 ep->cids = ep->fids = row + 1;
680         }
681         cur_obj = ef_ptr(type, row);
682         if (!cur_obj)
683             return gripe("Too many rows for table %s", ef_nameof(type));
684         if (xuflds(fp, xufld) < 0)
685             return -1;
686     }
687     if (row != ep->fids) {
688         if (fixed_rows)
689             return gripe("Table %s requires %d rows, got %d",
690                          ef_nameof(type), ep->fids, row);
691         else {
692             ep->cids = ep->fids = row;
693             if (EF_IS_GAME_STATE(type) && row != ep->csize)
694                 /* TODO truncate file */
695                 gripe("Warning: should resize table %s from %d to %d, not implemented",
696                       ef_nameof(type), ep->csize, row);
697         }
698     }
699
700     if (need_sentinel) {
701         if (CANT_HAPPEN(row >= ep->csize))
702             return gripe("No space for sentinel");
703         memset(ep->cache + ep->size * row, 0, ep->size);
704     }
705
706     if (xutrailer(fp, type, row) < 0)
707         return -1;
708
709     return 0;
710 }