]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
f0566af07576314023717bceb6e0f7e8fc4fb489
[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
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 (fldca[fldno]->ca_flags & NSC_CONST) || caseen[i];
405 }
406
407 static void *
408 getobj(struct castr *ca, int altid)
409 {
410     struct empfile *ep = &empfile[cur_type];
411     int need_sentinel = !EF_IS_GAME_STATE(cur_type);
412
413     if (!cur_obj) {
414         if (ca->ca_table == cur_type)
415             cur_id = altid;
416         if (cur_id >= ep->fids) {
417             /* TODO grow cache (and posssibly file) unless EFF_STATIC */
418             if (cur_id < ep->csize - !!need_sentinel)
419                 ep->cids = ep->fids = cur_id + 1;
420             /* else: ef_ptr() will fail */
421         }
422         cur_obj = ef_ptr(cur_type, cur_id);
423         if (!cur_obj)
424             gripe("Can't put ID %d into table %s, it holds only 0..%d.",
425                   cur_id, ep->name, ep->fids - 1);
426     }
427
428     return cur_obj;
429 }
430
431 static int
432 setnum(int fldno, double dbl)
433 {
434     struct castr *ca;
435     int idx;
436     char *memb_ptr;
437     double old;
438
439     ca = getfld(fldno, &idx);
440     if (!ca)
441         return -1;
442
443     memb_ptr = getobj(ca, (int)dbl);
444     if (!memb_ptr)
445         return -1;
446     memb_ptr += ca->ca_off;
447
448     switch (ca->ca_type) {
449     case NSC_CHAR:
450     case NSC_TYPEID:
451         old = ((signed char *)memb_ptr)[idx];
452         ((signed char *)memb_ptr)[idx] = (signed char)dbl;
453         break;
454     case NSC_UCHAR:
455     case NSC_HIDDEN:
456         old = ((unsigned char *)memb_ptr)[idx];
457         ((unsigned char *)memb_ptr)[idx] = (unsigned char)dbl;
458         break;
459     case NSC_SHORT:
460         old = ((short *)memb_ptr)[idx];
461         ((short *)memb_ptr)[idx] = (short)dbl;
462         break;
463     case NSC_USHORT:
464         old = ((unsigned short *)memb_ptr)[idx];
465         ((unsigned short *)memb_ptr)[idx] = (unsigned short)dbl;
466         break;
467     case NSC_INT:
468         old = ((int *)memb_ptr)[idx];
469         ((int *)memb_ptr)[idx] = (int)dbl;
470         break;
471     case NSC_LONG:
472         old = ((long *)memb_ptr)[idx];
473         ((long *)memb_ptr)[idx] = (long)dbl;
474         break;
475     case NSC_XCOORD:
476         old = ((coord *)memb_ptr)[idx];
477         /* FIXME use variant of xrel() that takes orig instead of nation */
478         if (old >= WORLD_X / 2)
479             old -= WORLD_X;
480         ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
481         break;
482     case NSC_YCOORD:
483         old = ((coord *)memb_ptr)[idx];
484         /* FIXME use variant of yrel() that takes orig instead of nation */
485         if (old >= WORLD_Y / 2)
486             old -= WORLD_Y;
487         ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
488         break;
489     case NSC_FLOAT:
490         old = ((float *)memb_ptr)[idx];
491         ((float *)memb_ptr)[idx] = (float)dbl;
492         break;
493     case NSC_DOUBLE:
494         old = ((double *)memb_ptr)[idx];
495         ((double *)memb_ptr)[idx] = dbl;
496         break;
497     case NSC_TIME:
498         old = ((time_t *)memb_ptr)[idx];
499         ((time_t *)memb_ptr)[idx] = (time_t)dbl;
500         break;
501     default:
502         return gripe("Field %d doesn't take numbers", fldno + 1);
503     }
504
505     if (fldval_must_match(fldno) && old != dbl)
506         return gripe("Value for field %d must be %g", fldno + 1, old);
507
508     return 1;
509 }
510
511 static int
512 setstr(int fldno, char *str)
513 {
514     struct castr *ca;
515     int must_match, idx;
516     size_t len;
517     char *memb_ptr, *old;
518
519     ca = getfld(fldno, &idx);
520     if (!ca)
521         return -1;
522     must_match = fldval_must_match(fldno);
523
524     memb_ptr = getobj(ca, cur_id);
525     if (!memb_ptr)
526         return -1;
527     memb_ptr += ca->ca_off;
528
529     switch (ca->ca_type) {
530     case NSC_STRING:
531         old = ((char **)memb_ptr)[idx];
532         if (!must_match)
533             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
534         len = 65535;            /* really SIZE_MAX, but that's C99 */
535         break;
536     case NSC_STRINGY:
537         if (CANT_HAPPEN(idx))
538             return -1;
539         if (!str)
540             return gripe("Field %d doesn't take nil", fldno + 1);
541         len = ca->ca_len;
542         if (strlen(str) > len)
543             return gripe("Field %d takes at most %d characters",
544                          fldno + 1, len);
545         old = memb_ptr;
546         if (!must_match)
547             strncpy(memb_ptr, str, len);
548         break;
549     default:
550         return gripe("Field %d doesn't take strings", fldno + 1);
551     }
552
553     if (must_match) {
554         if (old && (!str || strncmp(old, str, len)))
555             return gripe("Value for field %d must be \"%.*s\"",
556                          fldno + 1, len, old);
557         if (!old && str)
558             return gripe("Value for field %d must be nil", fldno + 1);
559     }
560
561     return 1;
562 }
563
564 static int
565 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
566 {
567     int i = stmtch(id, symtab, offsetof(struct symbol, name),
568                    sizeof(struct symbol));
569     if (i < 0)
570         return gripe("%s %s symbol `%s' in field %d",
571                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
572                      ca->ca_name, id, n);
573     return i;
574 }
575
576 static int
577 setsym(int fldno, char *sym)
578 {
579     struct castr *ca;
580     struct symbol *symtab;
581     int i;
582
583     ca = getfld(fldno, NULL);
584     if (!ca)
585         return -1;
586
587     symtab = get_symtab(ca);
588     if (!symtab || (ca->ca_flags & NSC_BITS))
589         return gripe("Field %d doesn't take symbols", fldno + 1);
590
591     i = xunsymbol1(sym, symtab, ca, fldno);
592     if (i < 0)
593         return -1;
594     return setnum(fldno, symtab[i].value);
595 }
596
597 static int
598 mtsymset(int fldno, long *set)
599 {
600     struct castr *ca;
601     struct symbol *symtab;
602
603     ca = getfld(fldno, NULL);
604     if (!ca)
605         return -1;
606
607     symtab = get_symtab(ca);
608     if (!symtab || !(ca->ca_flags & NSC_BITS)) {
609         return gripe("Field %d doesn't take symbol sets", fldno + 1);
610     }
611     *set = 0;
612     return 0;
613 }
614
615 static int
616 add2symset(int fldno, long *set, char *sym)
617 {
618     struct castr *ca;
619     struct symbol *symtab;
620     int i;
621
622     ca = getfld(fldno, NULL);
623     if (!ca)
624         return -1;
625
626     symtab = get_symtab(ca);
627     i = xunsymbol1(sym, symtab, ca, fldno);
628     if (i < 0)
629         return -1;
630     *set |= symtab[i].value;
631     return 0;
632 }
633
634 static struct symbol *
635 get_symtab(struct castr *ca)
636 {
637     int symtype = ca->ca_table;
638     struct symbol *symtab;
639
640     if (symtype == EF_BAD || ef_cadef(symtype) != symbol_ca)
641         return NULL;
642
643     symtab = ef_ptr(symtype, 0);
644     CANT_HAPPEN(!symtab);
645     return symtab;
646 }
647
648 static int
649 xuheader(FILE *fp, int expected_table)
650 {
651     char name[64];
652     int res, ch;
653     int type;
654
655     while ((ch = skipfs(fp)) == '\n')
656         lineno++;
657     if (ch == EOF && expected_table == EF_BAD)
658         return -2;
659     ungetc(ch, fp);
660
661     human = ch == 'c';
662     res = -1;
663     if ((human
664          ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
665          : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
666                   name, &res) != 1) || res < 0)
667         return gripe("Expected xdump header");
668
669     type = ef_byname(name);
670     if (type < 0)
671         return gripe("Unknown table `%s'", name);
672     if (expected_table != EF_BAD && expected_table != type)
673         return gripe("Expected table `%s', not `%s'",
674                      ef_nameof(expected_table), name);
675
676     if (!ef_cadef(type) || !(ef_flags(type) & EFF_MEM)) {
677         CANT_HAPPEN(expected_table != EF_BAD);
678         return gripe("Table `%s' is not permitted here", name);
679     }
680
681     if (skipfs(fp) != '\n')
682         return gripe("Junk after xdump header");
683     lineno++;
684
685     return type;
686 }
687
688 static int
689 xuheader1(FILE *fp, int type, struct castr ca[])
690 {
691     struct castr **fca;
692     int *fidx;
693     int ch, i, j, n;
694
695     if (human) {
696         while ((ch = skipfs(fp)) == '\n')
697             lineno++;
698         ungetc(ch, fp);
699         ellipsis = 0;
700         nflds = xuflds(fp, xufldname);
701         if (nflds < 0)
702             return -1;
703         nflds -= ellipsis != 0;
704     } else {
705         fca = fldca;
706         fidx = fldidx;
707
708         for (i = 0; ca[i].ca_name; i++) {
709             if ((ca[i].ca_flags & NSC_EXTRA))
710                 continue;
711             n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
712             j = 0;
713             do {
714                 *fca++ = &ca[i];
715                 *fidx++ = j;
716             } while (++j < n);
717         }
718
719         nflds = fidx - fldidx;
720     }
721
722     return 0;
723 }
724
725 static int
726 xutrailer(FILE *fp, int type, int row)
727 {
728     int rows, res;
729
730     res = -1;
731     if (human) {
732         if (fscanf(fp, "config%n",  &res) != 0 || res < 0)
733             return gripe("Malformed table footer");
734     } else {
735         if (fscanf(fp, "%d", &rows) != 1)
736             return gripe("Malformed table footer");
737         if (row != rows)
738             return gripe("Read %d rows, which doesn't match footer "
739                          "%d rows", row, rows);
740     }
741     if (skipfs(fp) != '\n')
742         return gripe("Junk after table footer");
743     lineno++;
744
745     return 0;
746 }
747
748 int
749 xundump(FILE *fp, char *file, int expected_table)
750 {
751     struct castr *ca;
752     int type, nca, nf, i, ch;
753
754     if (fname != file) {
755         fname = file;
756         lineno = 1;
757     }
758
759     if ((type = xuheader(fp, expected_table)) < 0)
760         return type;
761
762     ca = ef_cadef(type);
763     if (CANT_HAPPEN(!ca))
764         return -1;
765
766     nca = nf = 0;
767     for (i = 0; ca[i].ca_name; i++) {
768         nca++;
769         if (!(ca[i].ca_flags & NSC_EXTRA))
770             nf += MAX(1, ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0);
771     }
772     fldca = calloc(nf, sizeof(*fldca));
773     fldidx = calloc(nf, sizeof(*fldidx));
774     caflds = calloc(nca, sizeof(*caflds));
775     caseen = calloc(nca, sizeof(*caseen));
776     cur_type = type;
777
778     if (xundump2(fp, type, ca) < 0)
779         type = EF_BAD;
780
781     free(caseen);
782     free(caflds);
783     free(fldidx);
784     free(fldca);
785
786     /* Skip empty lines so that callers can easily check for EOF */
787     while ((ch = skipfs(fp)) == '\n')
788         lineno++;
789     ungetc(ch, fp);
790
791     return type;
792 }
793
794 static int
795 xundump2(FILE *fp, int type, struct castr *ca)
796 {
797     int i;
798
799     is_partial = 0;
800     for (;;) {
801         if (xuheader1(fp, type, ca) < 0)
802             return -1;
803         if (xundump1(fp, type, ca) < 0)
804             return -1;
805         if (!ellipsis)
806             return 0;
807         for (i = 0; ca[i].ca_name; i++)
808             caseen[i] = caflds[i] != 0;
809         if (xuheader(fp, type) < 0)
810             return -1;
811     }
812 }
813
814 static int
815 xundump1(FILE *fp, int type, struct castr *ca)
816 {
817     struct empfile *ep = &empfile[type];
818     int need_sentinel = !EF_IS_GAME_STATE(type);
819     int row, n, ch;
820
821     n = 0;
822     for (row = 0;; ++row) {
823         while ((ch = skipfs(fp)) == '\n')
824             lineno++;
825         if (ch == '/')
826             break;
827         ungetc(ch, fp);
828         cur_obj = NULL;
829         cur_id = row;
830         if (xuflds(fp, xufld) < 0)
831             return -1;
832         n = MAX(n, cur_id + 1);
833     }
834
835     if (CANT_HAPPEN(n > ep->fids))
836         n = ep->fids;
837     if (n < ep->fids) {
838         if (EF_IS_GAME_STATE(type) && n != ep->csize)
839             /* TODO truncate file */
840             gripe("Warning: should resize table %s from %d to %d, not implemented",
841                   ef_nameof(type), ep->csize, n);
842         else if (type >= EF_SHIP_CHR && type <= EF_NUKE_CHR)
843             ep->cids = ep->fids = n;
844         else
845             return gripe("Table %s requires %d rows, got %d",
846                          ef_nameof(type), ep->fids, n);
847     }
848
849     if (need_sentinel) {
850         if (CANT_HAPPEN(n >= ep->csize))
851             return gripe("No space for sentinel");
852         memset(ep->cache + ep->size * n, 0, ep->size);
853     }
854
855     if (xutrailer(fp, type, row) < 0)
856         return -1;
857
858     return 0;
859 }