]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
Rewrite rev. 1.69 to suppress immutable field match check when
[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-2006
33  */
34
35 /*
36  * FIXME:
37  * - Normalize terminology: table/rows/columns or file/records/fields
38  * - Loading tables with NSC_STRING elements more than once leaks memory
39  * TODO:
40  * - Check each partial table supplies the same rows
41  * - Check EFF_CFG tables are dense
42  * - Symbolic references to non-symbol tables
43  * - Symbolic array indexes
44  * TODO, but hardly worth the effort:
45  * - Permit reordering of array elements
46  * - Permit repetition of array elements in split tables
47  */
48
49 #include <config.h>
50
51 #include <stdio.h>
52 #include <stdlib.h>
53
54 #include <ctype.h>
55 #include <string.h>
56 #include <stdarg.h>
57 #include <time.h>
58
59 #include "file.h"
60 #include "match.h"
61 #include "nsc.h"
62 #include "optlist.h"
63 #include "prototypes.h"
64
65 static char *fname;
66 static int lineno;
67 static int human;
68 static int ellipsis, is_partial;
69 static int cur_type, cur_id;
70 static void *cur_obj;
71 static int cur_obj_is_blank;
72 static int nflds;
73 static struct castr **fldca;
74 static int *fldidx;
75 static int *caflds;
76 static unsigned char *caseen;
77
78 static int gripe(char *, ...) ATTRIBUTE((format (printf, 1, 2)));
79 static int deffld(int, char *, int);
80 static int defellipsis(int fldno);
81 static int chkflds(void);
82 static int setnum(int, double);
83 static int setstr(int, char *);
84 static int xunsymbol(char *, struct castr *, int);
85 static int setsym(int, char *);
86 static int mtsymset(int, long *);
87 static int add2symset(int, long *, char *);
88 static int xundump1(FILE *, int, struct castr *);
89 static int xundump2(FILE *, int, struct castr *);
90
91 static int
92 gripe(char *fmt, ...)
93 {
94     va_list ap;
95
96     fprintf(stderr, "%s:%d: ", fname, lineno);
97     va_start(ap, fmt);
98     vfprintf(stderr, fmt, ap);
99     va_end(ap);
100     putc('\n', stderr);
101
102     return -1;
103 }
104
105 static int
106 skipfs(FILE *fp)
107 {
108     int ch;
109
110     do {
111         ch = getc(fp);
112     } while (ch == ' ' || ch == '\t');
113
114     if (ch == '#') {
115         do {
116             ch = getc(fp);
117         } while (ch != EOF && ch != '\n');
118     }
119
120     return ch;
121 }
122
123 static int
124 getid(FILE *fp, char *buf)
125 {
126     int n;
127     if (fscanf(fp, "%1023[^#()<>=#\" \t\n]%n", buf, &n) != 1
128         || !isalpha(buf[0]))
129         return -1;
130     return n;
131 }
132
133 static char *
134 xuesc(char *buf)
135 {
136     char *src, *dst;
137     int octal_chr, n;
138
139     dst = buf;
140     src = buf;
141     while (*src) {
142         if (*src == '\\') {
143             if (sscanf(++src, "%3o%n", &octal_chr, &n) != 1 || n != 3)
144                 return NULL;
145             *dst++ = (char)octal_chr;
146             src += 3;
147         } else
148             *dst++ = *src++;
149     }
150     *dst = '\0';
151     return buf;
152 }
153
154 static int
155 xufldname(FILE *fp, int i)
156 {
157     int ch, idx;
158     char buf[1024];
159
160     ch = skipfs(fp);
161     switch (ch) {
162     case EOF:
163         return gripe("Unexpected EOF");
164     case '\n':
165         if (chkflds() < 0)
166             return -1;
167         lineno++;
168         return 0;
169     case '.':
170         if (getc(fp) != '.' || getc(fp) != '.')
171             return gripe("Junk in header field %d", i + 1);
172         if (i == 0)
173             return gripe("... not allowed in field 1");
174         if (defellipsis(i) < 0)
175             return -1;
176         ch = skipfs(fp);
177         if (ch != EOF && ch != '\n')
178             return gripe("Junk after ...");
179         ungetc(ch, fp);
180         return 1;
181     default:
182         ungetc(ch, fp);
183         if (getid(fp, buf) < 0)
184             return gripe("Junk in header field %d", i + 1);
185         ch = getc(fp);
186         if (ch != '(') {
187             ungetc(ch, fp);
188             return deffld(i, buf, -1);
189         }
190         ch = getc(fp);
191         ungetc(ch, fp);
192         if (isdigit(ch) || ch == '-' || ch == '+') {
193             if (fscanf(fp, "%d", &idx) != 1)
194                 return gripe("Malformed number in index of header field %d",
195                              i + 1);
196             if (idx < 0)
197                 return gripe("Index must not be negative in header field %d",
198                              i + 1);
199         } else {
200             if (getid(fp, buf) < 0)
201                 return gripe("Malformed index in header field %d", i + 1);
202             return gripe("Symbolic index in header field %d not yet implemented",
203                          i + 1);
204         }
205         ch = getc(fp);
206         if (ch != ')')
207             return gripe("Malformed index in header field %d", i + 1);
208         return deffld(i, buf, idx);
209     }
210 }
211
212 static int
213 xufld(FILE *fp, int i)
214 {
215     int ch;
216     char buf[1024];
217     double dbl;
218     long set;
219
220     ch = skipfs(fp);
221     switch (ch) {
222     case EOF:
223         return gripe("Unexpected EOF");
224     case '\n':
225         if (i != nflds) {
226             if (fldca[i]->ca_type != NSC_STRINGY && fldca[i]->ca_len)
227                 return gripe("Field %s(%d) missing",
228                              fldca[i]->ca_name, fldidx[i]);
229             return gripe("Field %s missing", fldca[i]->ca_name);
230         }
231         lineno++;
232         return 0;
233     case '+': case '-': case '.':
234     case '0': case '1': case '2': case '3': case '4':
235     case '5': case '6': case '7': case '8': case '9':
236         ungetc(ch, fp);
237         if (fscanf(fp, "%lg", &dbl) != 1)
238             return gripe("Malformed number in field %d", i + 1);
239         return setnum(i, dbl);
240     case '"':
241         ch = getc(fp);
242         if (ch == '"')
243             buf[0] = 0;
244         else {
245             ungetc(ch, fp);
246             if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
247                 return gripe("Malformed string in field %d", i + 1);
248             if (!xuesc(buf))
249                 return gripe("Invalid escape sequence in field %d",
250                              i + 1);
251         }
252         return setstr(i, buf);
253     case '(':
254         if (mtsymset(i, &set) < 0)
255             return -1;
256         for (;;) {
257             ch = skipfs(fp);
258             if (ch == EOF || ch == '\n')
259                 return gripe("Unmatched '(' in field %d", i + 1);
260             if (ch == ')')
261                 break;
262             ungetc(ch, fp);
263             if (getid(fp, buf) < 0)
264                 return gripe("Junk in field %d", i + 1);
265             if (add2symset(i, &set, buf) < 0)
266                 return -1;
267         }
268         return setnum(i, set);
269     default:
270         ungetc(ch, fp);
271         if (getid(fp, buf) < 0)
272             return gripe("Junk in field %d", i + 1);
273         if (!strcmp(buf, "nil"))
274             return setstr(i, NULL);
275         else
276             return setsym(i, buf);
277     }
278 }
279
280 static int
281 xuflds(FILE *fp, int (*parse)(FILE *, int))
282 {
283     int i, ch, res;
284
285     for (i = 0; ; i++) {
286         res = parse(fp, i);
287         if (res < 0)
288             return -1;
289         if (res == 0)
290             return i;
291         ch = getc(fp);
292         if (ch == '\n')
293             ungetc(ch, fp);
294         else if (ch != ' ' && ch != '\t')
295             return gripe("Bad field separator after field %d", i + 1);
296     }
297 }
298
299 static int
300 deffld(int fldno, char *name, int idx)
301 {
302     struct castr *ca = ef_cadef(cur_type);
303     int res;
304
305     res = stmtch(name, ca, offsetof(struct castr, ca_name),
306                      sizeof(struct castr));
307     if (res < 0)
308         return gripe("Header %s of field %d is %s", name, fldno + 1,
309                      res == M_NOTUNIQUE ? "ambiguous" : "unknown");
310     if (ca[res].ca_type != NSC_STRINGY && ca[res].ca_len != 0) {
311         if (idx < 0)
312             return gripe("Header %s requires an index in field %d",
313                          ca[res].ca_name, fldno + 1);
314         if (idx >= ca[res].ca_len)
315             return gripe("Header %s(%d) index out of bounds in field %d",
316                          ca[res].ca_name, idx, fldno + 1);
317         if (idx < caflds[res])
318             return gripe("Duplicate header %s(%d) in field %d",
319                          ca[res].ca_name, idx, fldno + 1);
320         if (idx > caflds[res])
321             return gripe("Expected header %s(%d) in field %d",
322                          ca[res].ca_name, caflds[res], fldno + 1);
323     } else {
324         if (idx >= 0)
325             return gripe("Header %s doesn't take an index in field %d",
326                          ca[res].ca_name, fldno + 1);
327         idx = 0;
328         if (caflds[res] && !caseen[res])
329             /* FIXME doesn't catch dupes within table part when caseen[res] */
330             return gripe("Duplicate header %s in field %d",
331                          ca[res].ca_name, fldno + 1);
332     }
333     fldca[fldno] = &ca[res];
334     fldidx[fldno] = idx;
335     if (!caseen[res])
336         caflds[res]++;
337     return 1;
338 }
339
340 static int
341 defellipsis(int fldno)
342 {
343     struct castr *ca = ef_cadef(cur_type);
344
345     if (ca[0].ca_table != cur_type)
346         return gripe("Table %s doesn't support ...", ef_nameof(cur_type));
347     ellipsis = fldno;
348     is_partial = 1;
349     return 0;
350 }
351
352 static int
353 chkflds(void)
354 {
355     struct castr *ca = ef_cadef(cur_type);
356     int i, len, res = 0;
357
358     if (is_partial) {
359         /* Require index field */
360         if (!caflds[0])
361             return gripe("Header field %s required with ...", ca[0].ca_name);
362         /* Want the index field again in continued table: */
363         caflds[0] = 0;
364         return 0;
365     }
366
367     for (i = 0; ca[i].ca_name; i++) {
368         if (ca[i].ca_flags & NSC_EXTRA)
369             continue;
370         len = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
371         if (!len && !caflds[i])
372             res = gripe("Header field %s missing", ca[i].ca_name);
373         else if (len && caflds[i] == len - 1)
374             res = gripe("Header field %s(%d) missing",
375                         ca[i].ca_name, len - 1);
376         else if (len && caflds[i] < len - 1)
377             res = gripe("Header fields %s(%d) ... %s(%d) missing",
378                         ca[i].ca_name, caflds[i], ca[i].ca_name, len - 1);
379     }
380
381     return res;
382 }
383
384 static struct castr *
385 getfld(int fldno, int *idx)
386 {
387     if (fldno >= nflds) {
388         gripe("Too many fields, expected only %d", nflds);
389         return NULL;
390     }
391     if (CANT_HAPPEN(fldno < 0))
392         return NULL;
393     if (idx)
394         *idx = fldidx[fldno];
395     return fldca[fldno];
396 }
397
398 static int
399 fldval_must_match(int fldno)
400 {
401     struct castr *ca = ef_cadef(cur_type);
402     int i = fldca[fldno] - ca;
403
404     return (!cur_obj_is_blank && (fldca[fldno]->ca_flags & NSC_CONST))
405         || caseen[i];
406 }
407
408 static void *
409 getobj(struct castr *ca, int altid)
410 {
411     struct empfile *ep = &empfile[cur_type];
412     int need_sentinel = !EF_IS_GAME_STATE(cur_type);
413
414     if (!cur_obj) {
415         if (ca->ca_table == cur_type)
416             cur_id = altid;
417         cur_obj_is_blank = cur_id >= ep->fids;
418         if (cur_obj_is_blank) {
419             /* TODO grow cache (and posssibly file) unless EFF_STATIC */
420             if (cur_id < ep->csize - !!need_sentinel)
421                 ep->cids = ep->fids = cur_id + 1;
422             /* else: ef_ptr() will fail */
423         }
424         cur_obj = ef_ptr(cur_type, cur_id);
425         if (!cur_obj)
426             gripe("Can't put ID %d into table %s, it holds only 0..%d.",
427                   cur_id, ep->name, ep->fids - 1);
428     }
429
430     return cur_obj;
431 }
432
433 static int
434 setnum(int fldno, double dbl)
435 {
436     struct castr *ca;
437     int idx;
438     char *memb_ptr;
439     double old;
440
441     ca = getfld(fldno, &idx);
442     if (!ca)
443         return -1;
444
445     memb_ptr = getobj(ca, (int)dbl);
446     if (!memb_ptr)
447         return -1;
448     memb_ptr += ca->ca_off;
449
450     /* FIXME check assignment preserves value */
451     switch (ca->ca_type) {
452     case NSC_CHAR:
453         old = ((signed char *)memb_ptr)[idx];
454         ((signed char *)memb_ptr)[idx] = (signed char)dbl;
455         break;
456     case NSC_UCHAR:
457     case NSC_HIDDEN:
458         old = ((unsigned char *)memb_ptr)[idx];
459         ((unsigned char *)memb_ptr)[idx] = (unsigned char)dbl;
460         break;
461     case NSC_SHORT:
462         old = ((short *)memb_ptr)[idx];
463         ((short *)memb_ptr)[idx] = (short)dbl;
464         break;
465     case NSC_USHORT:
466         old = ((unsigned short *)memb_ptr)[idx];
467         ((unsigned short *)memb_ptr)[idx] = (unsigned short)dbl;
468         break;
469     case NSC_INT:
470         old = ((int *)memb_ptr)[idx];
471         ((int *)memb_ptr)[idx] = (int)dbl;
472         break;
473     case NSC_LONG:
474         old = ((long *)memb_ptr)[idx];
475         ((long *)memb_ptr)[idx] = (long)dbl;
476         break;
477     case NSC_XCOORD:
478         old = ((coord *)memb_ptr)[idx];
479         /* FIXME use variant of xrel() that takes orig instead of nation */
480         if (old >= WORLD_X / 2)
481             old -= WORLD_X;
482         ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
483         break;
484     case NSC_YCOORD:
485         old = ((coord *)memb_ptr)[idx];
486         /* FIXME use variant of yrel() that takes orig instead of nation */
487         if (old >= WORLD_Y / 2)
488             old -= WORLD_Y;
489         ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
490         break;
491     case NSC_FLOAT:
492         old = ((float *)memb_ptr)[idx];
493         ((float *)memb_ptr)[idx] = (float)dbl;
494         break;
495     case NSC_DOUBLE:
496         old = ((double *)memb_ptr)[idx];
497         ((double *)memb_ptr)[idx] = dbl;
498         break;
499     case NSC_TIME:
500         old = ((time_t *)memb_ptr)[idx];
501         ((time_t *)memb_ptr)[idx] = (time_t)dbl;
502         break;
503     default:
504         return gripe("Field %d doesn't take numbers", fldno + 1);
505     }
506
507     if (fldval_must_match(fldno) && old != dbl)
508         return gripe("Value for field %d must be %g", fldno + 1, old);
509
510     return 1;
511 }
512
513 static int
514 setstr(int fldno, char *str)
515 {
516     struct castr *ca;
517     int must_match, idx;
518     size_t len;
519     char *memb_ptr, *old;
520
521     ca = getfld(fldno, &idx);
522     if (!ca)
523         return -1;
524
525     memb_ptr = getobj(ca, cur_id);
526     if (!memb_ptr)
527         return -1;
528     memb_ptr += ca->ca_off;
529     must_match = fldval_must_match(fldno);
530
531     switch (ca->ca_type) {
532     case NSC_STRING:
533         old = ((char **)memb_ptr)[idx];
534         if (!must_match)
535             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
536         len = 65535;            /* really SIZE_MAX, but that's C99 */
537         break;
538     case NSC_STRINGY:
539         if (CANT_HAPPEN(idx))
540             return -1;
541         if (!str)
542             return gripe("Field %d doesn't take nil", fldno + 1);
543         len = ca->ca_len;
544         if (strlen(str) > len)
545             return gripe("Field %d takes at most %d characters",
546                          fldno + 1, len);
547         old = memb_ptr;
548         if (!must_match)
549             strncpy(memb_ptr, str, len);
550         break;
551     default:
552         return gripe("Field %d doesn't take strings", fldno + 1);
553     }
554
555     if (must_match) {
556         if (old && (!str || strncmp(old, str, len)))
557             return gripe("Value for field %d must be \"%.*s\"",
558                          fldno + 1, len, old);
559         if (!old && str)
560             return gripe("Value for field %d must be nil", fldno + 1);
561     }
562
563     return 1;
564 }
565
566 static int
567 xunsymbol(char *id, struct castr *ca, int n)
568 {
569     int i = ef_elt_byname(ca->ca_table, id);
570     if (i < 0)
571         return gripe("%s %s symbol `%s' in field %d",
572                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
573                      ca->ca_name, id, n + 1);
574     return i;
575 }
576
577 static int
578 symval(struct castr *ca, int i)
579 {
580     int type = ca->ca_table;
581
582     if (ef_check(type) < 0)
583         return -1;
584     if (ef_cadef(type) == symbol_ca)
585         /* symbol table, value is in the table */
586         return ((struct symbol *)ef_ptr(type, i))->value;
587     /* value is the table index */
588     return i;
589 }
590
591 static int
592 setsym(int fldno, char *sym)
593 {
594     struct castr *ca;
595     int i;
596
597     ca = getfld(fldno, NULL);
598     if (!ca)
599         return -1;
600
601     if (ca->ca_table == EF_BAD || (ca->ca_flags & NSC_BITS))
602         return gripe("Field %d doesn't take symbols", fldno + 1);
603
604     i = xunsymbol(sym, ca, fldno);
605     if (i < 0)
606         return -1;
607     return setnum(fldno, symval(ca, i));
608 }
609
610 static int
611 mtsymset(int fldno, long *set)
612 {
613     struct castr *ca;
614
615     ca = getfld(fldno, NULL);
616     if (!ca)
617         return -1;
618
619     if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca
620         || !(ca->ca_flags & NSC_BITS))
621         return gripe("Field %d doesn't take symbol sets", fldno + 1);
622     *set = 0;
623     return 0;
624 }
625
626 static int
627 add2symset(int fldno, long *set, char *sym)
628 {
629     struct castr *ca;
630     int i;
631
632     ca = getfld(fldno, NULL);
633     if (!ca)
634         return -1;
635
636     i = xunsymbol(sym, ca, fldno);
637     if (i < 0)
638         return -1;
639     *set |= symval(ca, i);
640     return 0;
641 }
642
643 static int
644 xuheader(FILE *fp, int expected_table)
645 {
646     char name[64];
647     int res, ch;
648     int type;
649
650     while ((ch = skipfs(fp)) == '\n')
651         lineno++;
652     if (ch == EOF && expected_table == EF_BAD)
653         return -2;
654     ungetc(ch, fp);
655
656     human = ch == 'c';
657     res = -1;
658     if ((human
659          ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
660          : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
661                   name, &res) != 1) || res < 0)
662         return gripe("Expected xdump header");
663
664     type = ef_byname(name);
665     if (type < 0)
666         return gripe("Unknown table `%s'", name);
667     if (expected_table != EF_BAD && expected_table != type)
668         return gripe("Expected table `%s', not `%s'",
669                      ef_nameof(expected_table), name);
670
671     if (!ef_cadef(type) || !(ef_flags(type) & EFF_MEM)) {
672         CANT_HAPPEN(expected_table != EF_BAD);
673         return gripe("Table `%s' is not permitted here", name);
674     }
675
676     if (skipfs(fp) != '\n')
677         return gripe("Junk after xdump header");
678     lineno++;
679
680     return type;
681 }
682
683 static int
684 xuheader1(FILE *fp, int type, struct castr ca[])
685 {
686     struct castr **fca;
687     int *fidx;
688     int ch, i, j, n;
689
690     if (human) {
691         while ((ch = skipfs(fp)) == '\n')
692             lineno++;
693         ungetc(ch, fp);
694         ellipsis = 0;
695         nflds = xuflds(fp, xufldname);
696         if (nflds < 0)
697             return -1;
698         nflds -= ellipsis != 0;
699     } else {
700         fca = fldca;
701         fidx = fldidx;
702
703         for (i = 0; ca[i].ca_name; i++) {
704             if ((ca[i].ca_flags & NSC_EXTRA))
705                 continue;
706             n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
707             j = 0;
708             do {
709                 *fca++ = &ca[i];
710                 *fidx++ = j;
711             } while (++j < n);
712         }
713
714         nflds = fidx - fldidx;
715     }
716
717     return 0;
718 }
719
720 static int
721 xutrailer(FILE *fp, int type, int row)
722 {
723     int rows, res;
724
725     res = -1;
726     if (human) {
727         if (fscanf(fp, "config%n",  &res) != 0 || res < 0)
728             return gripe("Malformed table footer");
729     } else {
730         if (fscanf(fp, "%d", &rows) != 1)
731             return gripe("Malformed table footer");
732         if (row != rows)
733             return gripe("Read %d rows, which doesn't match footer "
734                          "%d rows", row, rows);
735     }
736     if (skipfs(fp) != '\n')
737         return gripe("Junk after table footer");
738     lineno++;
739
740     return 0;
741 }
742
743 int
744 xundump(FILE *fp, char *file, int expected_table)
745 {
746     struct castr *ca;
747     int type, nca, nf, i, ch;
748
749     if (fname != file) {
750         fname = file;
751         lineno = 1;
752     }
753
754     if ((type = xuheader(fp, expected_table)) < 0)
755         return type;
756
757     ca = ef_cadef(type);
758     if (CANT_HAPPEN(!ca))
759         return -1;
760
761     nca = nf = 0;
762     for (i = 0; ca[i].ca_name; i++) {
763         nca++;
764         if (!(ca[i].ca_flags & NSC_EXTRA))
765             nf += MAX(1, ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0);
766     }
767     fldca = calloc(nf, sizeof(*fldca));
768     fldidx = calloc(nf, sizeof(*fldidx));
769     caflds = calloc(nca, sizeof(*caflds));
770     caseen = calloc(nca, sizeof(*caseen));
771     cur_type = type;
772
773     if (xundump2(fp, type, ca) < 0)
774         type = EF_BAD;
775
776     free(caseen);
777     free(caflds);
778     free(fldidx);
779     free(fldca);
780
781     /* Skip empty lines so that callers can easily check for EOF */
782     while ((ch = skipfs(fp)) == '\n')
783         lineno++;
784     ungetc(ch, fp);
785
786     return type;
787 }
788
789 static int
790 xundump2(FILE *fp, int type, struct castr *ca)
791 {
792     int i;
793
794     is_partial = 0;
795     for (;;) {
796         if (xuheader1(fp, type, ca) < 0)
797             return -1;
798         if (xundump1(fp, type, ca) < 0)
799             return -1;
800         if (!ellipsis)
801             return 0;
802         for (i = 0; ca[i].ca_name; i++)
803             caseen[i] = caflds[i] != 0;
804         if (xuheader(fp, type) < 0)
805             return -1;
806     }
807 }
808
809 static int
810 xundump1(FILE *fp, int type, struct castr *ca)
811 {
812     struct empfile *ep = &empfile[type];
813     int need_sentinel = !EF_IS_GAME_STATE(type);
814     int row, n, ch;
815
816     n = 0;
817     for (row = 0;; ++row) {
818         while ((ch = skipfs(fp)) == '\n')
819             lineno++;
820         if (ch == '/')
821             break;
822         ungetc(ch, fp);
823         cur_obj = NULL;
824         cur_id = row;
825         if (xuflds(fp, xufld) < 0)
826             return -1;
827         n = MAX(n, cur_id + 1);
828     }
829
830     if (CANT_HAPPEN(n > ep->fids))
831         n = ep->fids;
832     if (n < ep->fids) {
833         if (EF_IS_GAME_STATE(type) && n != ep->csize)
834             /* TODO truncate file */
835             gripe("Warning: should resize table %s from %d to %d, not implemented",
836                   ef_nameof(type), ep->csize, n);
837         else if (type >= EF_SHIP_CHR && type <= EF_NUKE_CHR)
838             ep->cids = ep->fids = n;
839         else
840             return gripe("Table %s requires %d rows, got %d",
841                          ef_nameof(type), ep->fids, n);
842     }
843
844     if (need_sentinel) {
845         if (CANT_HAPPEN(n >= ep->csize))
846             return gripe("No space for sentinel");
847         memset(ep->cache + ep->size * n, 0, ep->size);
848     }
849
850     if (xutrailer(fp, type, row) < 0)
851         return -1;
852
853     return 0;
854 }