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