]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
(nsc_type): New member NSC_HIDDEN.
[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     case NSC_HIDDEN:
451         old = ((unsigned char *)memb_ptr)[idx];
452         ((unsigned char *)memb_ptr)[idx] = (unsigned char)dbl;
453         break;
454     case NSC_SHORT:
455         old = ((short *)memb_ptr)[idx];
456         ((short *)memb_ptr)[idx] = (short)dbl;
457         break;
458     case NSC_USHORT:
459         old = ((unsigned short *)memb_ptr)[idx];
460         ((unsigned short *)memb_ptr)[idx] = (unsigned short)dbl;
461         break;
462     case NSC_INT:
463         old = ((int *)memb_ptr)[idx];
464         ((int *)memb_ptr)[idx] = (int)dbl;
465         break;
466     case NSC_LONG:
467         old = ((long *)memb_ptr)[idx];
468         ((long *)memb_ptr)[idx] = (long)dbl;
469         break;
470     case NSC_XCOORD:
471         old = ((coord *)memb_ptr)[idx];
472         /* FIXME use variant of xrel() that takes orig instead of nation */
473         if (old >= WORLD_X / 2)
474             old -= WORLD_X;
475         ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
476         break;
477     case NSC_YCOORD:
478         old = ((coord *)memb_ptr)[idx];
479         /* FIXME use variant of yrel() that takes orig instead of nation */
480         if (old >= WORLD_Y / 2)
481             old -= WORLD_Y;
482         ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
483         break;
484     case NSC_FLOAT:
485         old = ((float *)memb_ptr)[idx];
486         ((float *)memb_ptr)[idx] = (float)dbl;
487         break;
488     case NSC_DOUBLE:
489         old = ((double *)memb_ptr)[idx];
490         ((double *)memb_ptr)[idx] = dbl;
491         break;
492     case NSC_TIME:
493         old = ((time_t *)memb_ptr)[idx];
494         ((time_t *)memb_ptr)[idx] = (time_t)dbl;
495         break;
496     default:
497         return gripe("Field %d doesn't take numbers", fldno + 1);
498     }
499
500     if (fldval_must_match(fldno) && old != dbl)
501         return gripe("Value for field %d must be %g", fldno + 1, old);
502
503     return 1;
504 }
505
506 static int
507 setstr(int fldno, char *str)
508 {
509     struct castr *ca;
510     int must_match, idx;
511     size_t len;
512     char *memb_ptr, *old;
513
514     ca = getfld(fldno, &idx);
515     if (!ca)
516         return -1;
517     must_match = fldval_must_match(fldno);
518
519     memb_ptr = getobj(ca, cur_id);
520     if (!memb_ptr)
521         return -1;
522     memb_ptr += ca->ca_off;
523
524     switch (ca->ca_type) {
525     case NSC_STRING:
526         old = ((char **)memb_ptr)[idx];
527         if (!must_match)
528             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
529         len = 65535;            /* really SIZE_MAX, but that's C99 */
530         break;
531     case NSC_STRINGY:
532         if (CANT_HAPPEN(idx))
533             return -1;
534         if (!str)
535             return gripe("Field doesn't take nil");
536         len = ca->ca_len;
537         if (strlen(str) > len)
538             return gripe("Field %d takes at most %d characters",
539                          fldno + 1, len);
540         old = memb_ptr;
541         if (!must_match)
542             strncpy(memb_ptr, str, len);
543         break;
544     default:
545         return gripe("Field %d doesn't take strings", fldno + 1);
546     }
547
548     if (must_match) {
549         if (old && (!str || strncmp(old, str, len)))
550             return gripe("Value for field %d must be \"%.*s\"",
551                          fldno + 1, len, old);
552         if (!old && str)
553             return gripe("Value for field %d must be nil", fldno + 1);
554     }
555
556     return 1;
557 }
558
559 static int
560 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
561 {
562     int i = stmtch(id, symtab, offsetof(struct symbol, name),
563                    sizeof(struct symbol));
564     if (i < 0)
565         return gripe("%s %s symbol `%s' in field %d",
566                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
567                      ca->ca_name, id, n);
568     return i;
569 }
570
571 static int
572 setsym(int fldno, char *sym)
573 {
574     struct castr *ca;
575     struct symbol *symtab;
576     int i;
577
578     ca = getfld(fldno, NULL);
579     if (!ca)
580         return -1;
581
582     symtab = get_symtab(ca);
583     if (!symtab || (ca->ca_flags & NSC_BITS))
584         return gripe("Field %d doesn't take symbols", fldno + 1);
585
586     i = xunsymbol1(sym, symtab, ca, fldno);
587     if (i < 0)
588         return -1;
589     return setnum(fldno, symtab[i].value);
590 }
591
592 static int
593 mtsymset(int fldno, long *set)
594 {
595     struct castr *ca;
596     struct symbol *symtab;
597
598     ca = getfld(fldno, NULL);
599     if (!ca)
600         return -1;
601
602     symtab = get_symtab(ca);
603     if (!symtab || !(ca->ca_flags & NSC_BITS)) {
604         return gripe("Field %d doesn't take symbol sets", fldno + 1);
605     }
606     *set = 0;
607     return 0;
608 }
609
610 static int
611 add2symset(int fldno, long *set, char *sym)
612 {
613     struct castr *ca;
614     struct symbol *symtab;
615     int i;
616
617     ca = getfld(fldno, NULL);
618     if (!ca)
619         return -1;
620
621     symtab = get_symtab(ca);
622     i = xunsymbol1(sym, symtab, ca, fldno);
623     if (i < 0)
624         return -1;
625     *set |= symtab[i].value;
626     return 0;
627 }
628
629 static struct symbol *
630 get_symtab(struct castr *ca)
631 {
632     int symtype = ca->ca_table;
633     struct symbol *symtab;
634
635     if (symtype == EF_BAD || ef_cadef(symtype) != symbol_ca)
636         return NULL;
637
638     symtab = ef_ptr(symtype, 0);
639     CANT_HAPPEN(!symtab);
640     return symtab;
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 }