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