]> git.pond.sub.org Git - empserver/blob - src/lib/common/xundump.c
Update copyright notice
[empserver] / src / lib / common / xundump.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  xundump.c: Load back xdump output
28  *
29  *  Known contributors to this file:
30  *     Ron Koenderink, 2005
31  *     Markus Armbruster, 2005-2011
32  */
33
34 /*
35  * See doc/xdump!  And keep it up-to-date.
36  *
37  * Parsing of machine-readable xdump is not precise: it recognizes
38  * comments, accepts whitespace in place of single space, and accepts
39  * the full human-readable field syntax instead of its machine-
40  * readable subset.
41  *
42  * FIXME:
43  * - Normalize terminology: table/rows/columns or file/records/fields
44  * - Loading tables with NSC_STRING elements more than once leaks memory
45  * TODO:
46  * - Symbolic array indexes
47  * - Option to treat missing and unknown fields as warning, not error
48  * TODO, but hardly worth the effort:
49  * - Permit reordering of array elements
50  */
51
52 #include <config.h>
53
54 #include <ctype.h>
55 #include <stdarg.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <time.h>
60 #include "file.h"
61 #include "match.h"
62 #include "nsc.h"
63 #include "optlist.h"
64 #include "xdump.h"
65
66 static char *fname;             /* Name of file being read */
67 static int lineno;              /* Current line number */
68
69 static int cur_type;            /* Current table's file type */
70 static int partno;              /* Counts from 0..#parts-1 */
71 static void *cur_obj;           /* The object being read into */
72 static int cur_id;              /* and its index in the table */
73 static int old_nelem;
74 static unsigned char *idgap;    /* idgap && idgap[ID] iff part#0 lacks ID */
75 static int idgap_len;           /* #elements in idgap[] */
76
77 static int human;               /* Reading human-readable syntax? */
78 static int ellipsis;            /* Header ended with ...? */
79 static int nflds;               /* #fields in input records */
80 static struct castr **fldca;    /* Map field number to selector */
81 static int *fldidx;             /* Map field number to index */
82 static int *caflds;             /* Map selector number to #fields seen */
83 static int *cafldspp;           /* ditto, in previous parts */
84 static int may_omit_id;         /* Okay to omit IDs? */
85 static int may_trunc;           /* Okay to truncate? */
86
87 static int gripe(char *, ...) ATTRIBUTE((format (printf, 1, 2)));
88 static int deffld(int, char *, int);
89 static int defellipsis(void);
90 static int chkflds(void);
91 static int setnum(int, double);
92 static int setstr(int, char *);
93 static int setsym(int, char *);
94 static int mtsymset(int, long *);
95 static int add2symset(int, long *, char *);
96 static int xubody(FILE *);
97 static int xutail(FILE *, struct castr *);
98
99 /*
100  * Gripe about the current line to stderr, return -1.
101  */
102 static int
103 gripe(char *fmt, ...)
104 {
105     va_list ap;
106
107     fprintf(stderr, "%s:%d: ", fname, lineno);
108     va_start(ap, fmt);
109     vfprintf(stderr, fmt, ap);
110     va_end(ap);
111     putc('\n', stderr);
112
113     return -1;
114 }
115
116 /* Make TYPE the current table.  */
117 static void
118 tbl_start(int type)
119 {
120     cur_type = type;
121     partno = 0;
122     cur_id = -1;
123     cur_obj = NULL;
124     old_nelem = type == EF_BAD ? 0 : ef_nelem(type);
125     idgap = NULL;
126     idgap_len = 0;
127 }
128
129 /* End the current table.  */
130 static void
131 tbl_end(void)
132 {
133     free(idgap);
134     tbl_start(EF_BAD);
135 }
136
137 /*
138  * Seek to current table's ID-th record.
139  * ID must be acceptable.
140  * Store it in cur_obj, and set cur_id accordingly.
141  * Return 0 on success, -1 on failure.
142  */
143 static int
144 tbl_seek(int id)
145 {
146     struct empfile *ep = &empfile[cur_type];
147
148     if (id >= ef_nelem(cur_type)) {
149         if (!ef_ensure_space(cur_type, id, 1))
150             return gripe("Can't put ID %d into table %s", id, ep->name);
151     }
152
153     cur_obj = ef_ptr(cur_type, id);
154     if (CANT_HAPPEN(!cur_obj))
155         return -1;
156     cur_id = id;
157     return 0;
158 }
159
160 /*
161  * Get the next object.
162  * Must not have a record index.
163  * Store it in cur_obj, and set cur_id accordingly.
164  * Return 0 on success, -1 on failure.
165  */
166 static int
167 tbl_next_obj(void)
168 {
169     int max_id = ef_id_limit(cur_type);
170
171     if (cur_id >= max_id)
172         return gripe("Too many rows");
173     return tbl_seek(cur_id + 1);
174 }
175
176 /*
177  * Omit ID1..ID2-1.
178  * Reset the omitted objects to default state.
179  */
180 static void
181 omit_ids(int id1, int id2)
182 {
183     int i;
184
185     if (id1 >= id2)
186         return;
187
188     idgap = realloc(idgap, id2 * sizeof(*idgap));
189     for (i = idgap_len; i < id1; i++)
190         idgap[i] = 0;
191     for (i = id1; i < id2; i++) {
192         ef_blank(cur_type, i, ef_ptr(cur_type, i));
193         idgap[i] = 1;
194     }
195     idgap_len = id2;
196 }
197
198 /*
199  * Return the smallest non-omitted ID in ID1..ID2-1 if any, else -1.
200  */
201 static int
202 expected_id(int id1, int id2)
203 {
204     int i;
205
206     for (i = id1; i < id2; i++) {
207         if (i >= idgap_len || !idgap[i])
208             return i;
209     }
210     return -1;
211 }
212
213 /*
214  * Get the next object, it has record index ID.
215  * Store it in cur_obj, and set cur_id accordingly.
216  * Ensure we're omitting the same objects as the previous parts.
217  * Reset any omitted objects to default state.
218  * Return 0 on success, -1 on failure.
219  */
220 static int
221 tbl_skip_to_obj(int id)
222 {
223     struct empfile *ep = &empfile[cur_type];
224     int prev_id = cur_id;
225     int max_id, exp_id;
226
227     if (partno == 0) {
228         if (!may_omit_id && id != cur_id + 1)
229             return gripe("Expected %d in field %d", cur_id + 1, 1);
230         if (id <= cur_id)
231             return gripe("Field %d must be > %d", 1, cur_id);
232         max_id = ef_id_limit(cur_type);
233         if (id > max_id)
234             return gripe("Field %d must be <= %d", 1, max_id);
235     } else {
236         exp_id = expected_id(cur_id + 1, ep->fids);
237         if (exp_id < 0)
238             return gripe("Table's first part doesn't have this row");
239         else if (id != exp_id)
240             return gripe("Expected %d in field %d,"
241                          " like in table's first part",
242                          exp_id, 1);
243     }
244
245     if (tbl_seek(id) < 0)
246         return -1;
247
248     if (partno == 0)
249         omit_ids(prev_id + 1, id);
250     return 0;
251 }
252
253 /*
254  * Finish table part.
255  * If the table has variable length, truncate it.
256  * Else ensure we're omitting the same objects as the previous parts.
257  * Reset any omitted objects to default state.
258  * Return 0 on success, -1 on failure.
259  */
260 static int
261 tbl_part_done(void)
262 {
263     struct empfile *ep = &empfile[cur_type];
264     int exp_id;
265
266     if (cur_id + 1 < ep->fids) {
267         if (partno == 0) {
268             if (may_trunc) {
269                 if (!ef_truncate(cur_type, cur_id + 1))
270                     return -1;
271             } else {
272                 if (!may_omit_id)
273                     return gripe("Expected %d more rows",
274                                  ep->fids - (cur_id + 1));
275                 omit_ids(cur_id + 1, ep->fids);
276             }
277         } else {
278             exp_id = expected_id(cur_id + 1, ep->fids);
279             if (exp_id >= 0)
280                 return gripe("Expected row with %d in field %d,"
281                              " like in table's first part",
282                              exp_id, 1);
283         }
284     }
285
286     partno++;
287     cur_id = -1;
288     cur_obj = NULL;
289     return 0;
290 }
291
292 /*
293  * Read and ignore field separators from FP.
294  * Return first character that is not a field separator.
295  */
296 static int
297 skipfs(FILE *fp)
298 {
299     int ch;
300
301     do {
302         ch = getc(fp);
303     } while (ch == ' ' || ch == '\t');
304
305     if (ch == '#') {
306         do {
307             ch = getc(fp);
308         } while (ch != EOF && ch != '\n');
309     }
310
311     return ch;
312 }
313
314 /*
315  * Decode escape sequences in BUF.
316  * Return BUF on success, null pointer on failure.
317  */
318 static char *
319 xuesc(char *buf)
320 {
321     char *src, *dst;
322     int octal_chr, n;
323
324     dst = buf;
325     src = buf;
326     while (*src) {
327         if (*src == '\\') {
328             if (sscanf(++src, "%3o%n", &octal_chr, &n) != 1 || n != 3)
329                 return NULL;
330             *dst++ = (char)octal_chr;
331             src += 3;
332         } else
333             *dst++ = *src++;
334     }
335     *dst = '\0';
336     return buf;
337 }
338
339 /*
340  * Read an identifier from FP into BUF.
341  * BUF must have space for 1024 characters.
342  * Return number of characters read on success, -1 on failure.
343  */
344 static int
345 getid(FILE *fp, char *buf)
346 {
347     int n;
348     if (fscanf(fp, "%1023[^\"#()<>= \t\n]%n", buf, &n) != 1
349         || !isalpha(buf[0]))
350         return -1;
351     xuesc(buf);
352     return n;
353 }
354
355 /*
356  * Try to read a field name from FP.
357  * I is the field number, counting from zero.
358  * If a name is read, set fldca[I] and fldidx[I] for it, and update
359  * caflds[].
360  * Return 1 if a name or ... was read, 0 on end of line, -1 on error.
361  */
362 static int
363 xufldname(FILE *fp, int i)
364 {
365     int ch, idx;
366     char buf[1024];
367
368     ch = skipfs(fp);
369     switch (ch) {
370     case EOF:
371         return gripe("Unexpected EOF");
372     case '\n':
373         if (chkflds() < 0)
374             return -1;
375         lineno++;
376         return 0;
377     case '.':
378         if (getc(fp) != '.' || getc(fp) != '.')
379             return gripe("Junk in header field %d", i + 1);
380         if (defellipsis() < 0)
381             return -1;
382         ch = skipfs(fp);
383         if (ch != EOF && ch != '\n')
384             return gripe("Junk after ...");
385         ungetc(ch, fp);
386         return 1;
387     default:
388         ungetc(ch, fp);
389         if (getid(fp, buf) < 0)
390             return gripe("Junk in header field %d", i + 1);
391         ch = getc(fp);
392         if (ch != '(') {
393             ungetc(ch, fp);
394             return deffld(i, buf, -1);
395         }
396         ch = getc(fp);
397         ungetc(ch, fp);
398         if (isdigit(ch) || ch == '-' || ch == '+') {
399             if (fscanf(fp, "%d", &idx) != 1)
400                 return gripe("Malformed number in index of header field %d",
401                              i + 1);
402             if (idx < 0)
403                 return gripe("Index must not be negative in header field %d",
404                              i + 1);
405         } else {
406             if (getid(fp, buf) < 0)
407                 return gripe("Malformed index in header field %d", i + 1);
408             return gripe("Symbolic index in header field %d not yet implemented",
409                          i + 1);
410         }
411         ch = getc(fp);
412         if (ch != ')')
413             return gripe("Malformed index in header field %d", i + 1);
414         return deffld(i, buf, idx);
415     }
416 }
417
418 /*
419  * Try to read a field value from FP.
420  * I is the field number, counting from zero.
421  * Return 1 if a value was read, 0 on end of line, -1 on error.
422  */
423 static int
424 xufld(FILE *fp, int i)
425 {
426     int ch;
427     char buf[1024];
428     double dbl;
429     long set;
430
431     ch = skipfs(fp);
432     switch (ch) {
433     case EOF:
434         return gripe("Unexpected EOF");
435     case '\n':
436         CANT_HAPPEN(i > nflds);
437         if (i < nflds) {
438             if (fldca[i]->ca_type != NSC_STRINGY && fldca[i]->ca_len)
439                 return gripe("Field %s(%d) missing",
440                              fldca[i]->ca_name, fldidx[i]);
441             return gripe("Field %s missing", fldca[i]->ca_name);
442         }
443         lineno++;
444         return 0;
445     case '+': case '-': case '.':
446     case '0': case '1': case '2': case '3': case '4':
447     case '5': case '6': case '7': case '8': case '9':
448         ungetc(ch, fp);
449         if (fscanf(fp, "%lg", &dbl) != 1)
450             return gripe("Malformed number in field %d", i + 1);
451         return setnum(i, dbl);
452     case '"':
453         ch = getc(fp);
454         if (ch == '"')
455             buf[0] = 0;
456         else {
457             ungetc(ch, fp);
458             if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
459                 return gripe("Malformed string in field %d", i + 1);
460             if (!xuesc(buf))
461                 return gripe("Invalid escape sequence in field %d",
462                              i + 1);
463         }
464         return setstr(i, buf);
465     case '(':
466         if (mtsymset(i, &set) < 0)
467             return -1;
468         for (;;) {
469             ch = skipfs(fp);
470             if (ch == EOF || ch == '\n')
471                 return gripe("Unmatched '(' in field %d", i + 1);
472             if (ch == ')')
473                 break;
474             ungetc(ch, fp);
475             if (getid(fp, buf) < 0)
476                 return gripe("Junk in field %d", i + 1);
477             if (add2symset(i, &set, buf) < 0)
478                 return -1;
479         }
480         return setnum(i, set);
481     default:
482         ungetc(ch, fp);
483         if (getid(fp, buf) < 0)
484             return gripe("Junk in field %d", i + 1);
485         if (!strcmp(buf, "nil"))
486             return setstr(i, NULL);
487         else
488             return setsym(i, buf);
489     }
490 }
491
492 /*
493  * Read fields from FP.
494  * Use PARSE() to read each field.
495  * Return number of fields read on success, -1 on error.
496  */
497 static int
498 xuflds(FILE *fp, int (*parse)(FILE *, int))
499 {
500     int i, ch, res;
501
502     for (i = 0; ; i++) {
503         res = parse(fp, i);
504         if (res < 0)
505             return -1;
506         if (res == 0)
507             return i;
508         ch = getc(fp);
509         if (ch == '\n')
510             ungetc(ch, fp);
511         else if (ch != ' ' && ch != '\t')
512             return gripe("Bad field separator after field %d", i + 1);
513     }
514 }
515
516 /*
517  * Define the FLDNO-th field.
518  * If IDX is negative, define as selector NAME, else as NAME(IDX).
519  * Set fldca[FLDNO] and fldidx[FLDNO] accordingly.
520  * Update caflds[].
521  * Return 1 on success, -1 on error.
522  */
523 static int
524 deffld(int fldno, char *name, int idx)
525 {
526     struct castr *ca = ef_cadef(cur_type);
527     int res;
528
529     res = stmtch(name, ca, offsetof(struct castr, ca_name),
530                  sizeof(struct castr));
531     if (res < 0)
532         return gripe("Header %s of field %d is %s", name, fldno + 1,
533                      res == M_NOTUNIQUE ? "ambiguous" : "unknown");
534     if ((ca[res].ca_flags & NSC_EXTRA) || CANT_HAPPEN(ca[res].ca_get))
535         return gripe("Extraneous header %s in field %d", name, fldno + 1);
536     if (ca[res].ca_type != NSC_STRINGY && ca[res].ca_len != 0) {
537         if (idx < 0)
538             return gripe("Header %s requires an index in field %d",
539                          ca[res].ca_name, fldno + 1);
540         if (idx >= ca[res].ca_len)
541             return gripe("Header %s(%d) index out of bounds in field %d",
542                          ca[res].ca_name, idx, fldno + 1);
543         if (idx < caflds[res])
544             return gripe("Duplicate header %s(%d) in field %d",
545                          ca[res].ca_name, idx, fldno + 1);
546         if (idx > caflds[res])
547             return gripe("Expected header %s(%d) in field %d",
548                          ca[res].ca_name, caflds[res], fldno + 1);
549     } else {
550         if (idx >= 0)
551             return gripe("Header %s doesn't take an index in field %d",
552                          ca[res].ca_name, fldno + 1);
553         idx = 0;
554         if (caflds[res])
555             return gripe("Duplicate header %s in field %d",
556                          ca[res].ca_name, fldno + 1);
557     }
558     fldca[fldno] = &ca[res];
559     fldidx[fldno] = idx;
560     caflds[res]++;
561     return 1;
562 }
563
564 /*
565  * Record that header ends with ...
566  * Set ellipsis and is_partial.
567  * Return 0 on success, -1 on error.
568  */
569 static int
570 defellipsis(void)
571 {
572     struct castr *ca = ef_cadef(cur_type);
573
574     if (ca[0].ca_table != cur_type || (ca[0].ca_flags & NSC_EXTRA))
575         return gripe("Table %s doesn't support ...", ef_nameof(cur_type));
576     ellipsis = 1;
577     return 0;
578 }
579
580 /* Is table split into parts? */
581 static int
582 is_partial(void)
583 {
584     return ellipsis || partno;
585 }
586
587 /*
588  * Check fields in xdump are sane.
589  * Return 0 on success, -1 on error.
590  */
591 static int
592 chkflds(void)
593 {
594     struct castr *ca = ef_cadef(cur_type);
595     int i, len, cafldsmax, res = 0;
596
597     /* Record index must come first, to make cur_id work, see setnum() */
598     if (ca[0].ca_table == cur_type && caflds[0] && fldca[0] != &ca[0])
599         res = gripe("Header field %s must come first", ca[0].ca_name);
600
601     if (is_partial()) {
602         /* Need a join field, use 0-th selector */
603         if (!caflds[0])
604             res = gripe("Header field %s required in each table part",
605                         ca[0].ca_name);
606     }
607
608     if (ellipsis)
609         return res;             /* table is split, another part expected */
610
611     /* Check for missing fields */
612     for (i = 0; ca[i].ca_name; i++) {
613         cafldsmax = MAX(caflds[i], cafldspp[i]);
614         if (ca[i].ca_flags & NSC_EXTRA)
615             continue;
616         len = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
617         if (!len && !cafldsmax)
618             res = gripe("Header field %s missing", ca[i].ca_name);
619         else if (len && cafldsmax == len - 1)
620             res = gripe("Header field %s(%d) missing",
621                         ca[i].ca_name, len - 1);
622         else if (len && cafldsmax < len - 1)
623             res = gripe("Header fields %s(%d) ... %s(%d) missing",
624                         ca[i].ca_name, cafldsmax, ca[i].ca_name, len - 1);
625     }
626
627     return res;
628 }
629
630 /*
631  * Get selector for field FLDNO.
632  * Assign the field's selector index to *IDX, unless it is null.
633  * Return the selector on success, null pointer on error.
634  */
635 static struct castr *
636 getfld(int fldno, int *idx)
637 {
638     if (fldno >= nflds) {
639         gripe("Too many fields, expected only %d", nflds);
640         return NULL;
641     }
642     if (CANT_HAPPEN(fldno < 0))
643         return NULL;
644     if (idx)
645         *idx = fldidx[fldno];
646     return fldca[fldno];
647 }
648
649 /*
650  * Is a new value for field FLDNO required to match the old one?
651  */
652 static int
653 fldval_must_match(int fldno)
654 {
655     struct castr *ca = ef_cadef(cur_type);
656     int i = fldca[fldno] - ca;
657
658     /*
659      * Value must match if:
660      * it's for a const selector, unless the object is still blank, or
661      * it was already given in a previous part of a split table.
662      */
663     return (cur_id < old_nelem && (fldca[fldno]->ca_flags & NSC_CONST))
664         || fldidx[fldno] < cafldspp[i];
665 }
666
667 /*
668  * Set value of field FLDNO in current object to DBL.
669  * Return 1 on success, -1 on error.
670  */
671 static int
672 setnum(int fldno, double dbl)
673 {
674     struct castr *ca;
675     int next_id, idx;
676     char *memb_ptr;
677     double old, new;
678
679     ca = getfld(fldno, &idx);
680     if (!ca)
681         return -1;
682
683     if (fldno == 0) {
684         if (ca->ca_table == cur_type) {
685             /* Got record index */
686             next_id = (int)dbl;
687             if (next_id != dbl)
688                 return gripe("Field %d can't hold this value", fldno + 1);
689             if (tbl_skip_to_obj(next_id) < 0)
690                 return -1;
691         } else {
692             if (tbl_next_obj() < 0)
693                 return -1;
694         }
695     }
696     memb_ptr = cur_obj;
697     memb_ptr += ca->ca_off;
698
699     switch (ca->ca_type) {
700     case NSC_CHAR:
701         old = ((signed char *)memb_ptr)[idx];
702         new = ((signed char *)memb_ptr)[idx] = (signed char)dbl;
703         break;
704     case NSC_UCHAR:
705     case NSC_HIDDEN:
706         old = ((unsigned char *)memb_ptr)[idx];
707         new = ((unsigned char *)memb_ptr)[idx] = (unsigned char)dbl;
708         break;
709     case NSC_SHORT:
710         old = ((short *)memb_ptr)[idx];
711         new = ((short *)memb_ptr)[idx] = (short)dbl;
712         break;
713     case NSC_USHORT:
714         old = ((unsigned short *)memb_ptr)[idx];
715         new = ((unsigned short *)memb_ptr)[idx] = (unsigned short)dbl;
716         break;
717     case NSC_INT:
718         old = ((int *)memb_ptr)[idx];
719         new = ((int *)memb_ptr)[idx] = (int)dbl;
720         break;
721     case NSC_LONG:
722         old = ((long *)memb_ptr)[idx];
723         new = ((long *)memb_ptr)[idx] = (long)dbl;
724         break;
725     case NSC_XCOORD:
726         old = ((coord *)memb_ptr)[idx];
727         /* FIXME use variant of xrel() that takes orig instead of nation */
728         if (old >= WORLD_X / 2)
729             old -= WORLD_X;
730         new = ((coord *)memb_ptr)[idx] = XNORM((coord)dbl);
731         if (new >= WORLD_X / 2)
732             new -= WORLD_X;
733         break;
734     case NSC_YCOORD:
735         old = ((coord *)memb_ptr)[idx];
736         /* FIXME use variant of yrel() that takes orig instead of nation */
737         if (old >= WORLD_Y / 2)
738             old -= WORLD_Y;
739         new = ((coord *)memb_ptr)[idx] = YNORM((coord)dbl);
740         if (new >= WORLD_Y / 2)
741             new -= WORLD_Y;
742         break;
743     case NSC_FLOAT:
744         old = ((float *)memb_ptr)[idx];
745         ((float *)memb_ptr)[idx] = (float)dbl;
746         new = dbl;              /* suppress new != dbl check */
747         break;
748     case NSC_DOUBLE:
749         old = ((double *)memb_ptr)[idx];
750         ((double *)memb_ptr)[idx] = dbl;
751         new = dbl;              /* suppress new != dbl check */
752         break;
753     case NSC_TIME:
754         old = ((time_t *)memb_ptr)[idx];
755         new = ((time_t *)memb_ptr)[idx] = (time_t)dbl;
756         break;
757     default:
758         return gripe("Field %d doesn't take numbers", fldno + 1);
759     }
760
761     if (fldval_must_match(fldno) && old != dbl)
762         return gripe("Value for field %d must be %g", fldno + 1, old);
763     if (new != dbl)
764         return gripe("Field %d can't hold this value", fldno + 1);
765
766     return 1;
767 }
768
769 /*
770  * Set value of field FLDNO in current object to STR.
771  * Return 1 on success, -1 on error.
772  */
773 static int
774 setstr(int fldno, char *str)
775 {
776     struct castr *ca;
777     int must_match, idx;
778     size_t len;
779     char *memb_ptr, *old;
780
781     ca = getfld(fldno, &idx);
782     if (!ca)
783         return -1;
784
785     if (fldno == 0) {
786         if (tbl_next_obj() < 0)
787             return -1;
788     }
789     memb_ptr = cur_obj;
790     memb_ptr += ca->ca_off;
791     must_match = fldval_must_match(fldno);
792
793     switch (ca->ca_type) {
794     case NSC_STRING:
795         old = ((char **)memb_ptr)[idx];
796         if (!must_match)
797             /* FIXME may leak old value */
798             ((char **)memb_ptr)[idx] = str ? strdup(str) : NULL;
799         len = 65535;            /* really SIZE_MAX, but that's C99 */
800         break;
801     case NSC_STRINGY:
802         if (CANT_HAPPEN(idx))
803             return -1;
804         if (!str)
805             return gripe("Field %d doesn't take nil", fldno + 1);
806         len = ca->ca_len;
807         if (strlen(str) > len)
808             return gripe("Field %d takes at most %d characters",
809                          fldno + 1, (int)len);
810         old = memb_ptr;
811         if (!must_match)
812             strncpy(memb_ptr, str, len);
813         break;
814     default:
815         return gripe("Field %d doesn't take strings", fldno + 1);
816     }
817
818     if (must_match) {
819         if (old && (!str || strncmp(old, str, len)))
820             return gripe("Value for field %d must be \"%.*s\"",
821                          fldno + 1, (int)len, old);
822         if (!old && str)
823             return gripe("Value for field %d must be nil", fldno + 1);
824     }
825
826     return 1;
827 }
828
829 /*
830  * Resolve symbol name ID in table referred to by CA.
831  * Use field number N for error messages.
832  * Return index in referred table on success, -1 on failure.
833  */
834 static int
835 xunsymbol(char *id, struct castr *ca, int n)
836 {
837     int i = ef_elt_byname(ca->ca_table, id);
838     if (i < 0)
839         return gripe("%s %s symbol `%s' in field %d",
840                      i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
841                      ca->ca_name, id, n + 1);
842     return i;
843 }
844
845 /*
846  * Map symbol index to symbol value.
847  * CA is the table, and I is the index in it.
848  */
849 static int
850 symval(struct castr *ca, int i)
851 {
852     int type = ca->ca_table;
853
854     if (type != EF_BAD && ef_cadef(type) == symbol_ca)
855         /* symbol table, value is in the table */
856         return ((struct symbol *)ef_ptr(type, i))->value;
857     /* value is the table index */
858     return i;
859 }
860
861 /*
862  * Set value of field FLDNO in current object to value of symbol SYM.
863  * Return 1 on success, -1 on error.
864  */
865 static int
866 setsym(int fldno, char *sym)
867 {
868     struct castr *ca;
869     int i;
870
871     ca = getfld(fldno, NULL);
872     if (!ca)
873         return -1;
874
875     if (ca->ca_table == EF_BAD || (ca->ca_flags & NSC_BITS))
876         return gripe("Field %d doesn't take symbols", fldno + 1);
877
878     i = xunsymbol(sym, ca, fldno);
879     if (i < 0)
880         return -1;
881     return setnum(fldno, symval(ca, i));
882 }
883
884 /*
885  * Create an empty symbol set for field FLDNO in *SET.
886  * Return 1 on success, -1 on error.
887  */
888 static int
889 mtsymset(int fldno, long *set)
890 {
891     struct castr *ca;
892
893     ca = getfld(fldno, NULL);
894     if (!ca)
895         return -1;
896
897     if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca
898         || !(ca->ca_flags & NSC_BITS))
899         return gripe("Field %d doesn't take symbol sets", fldno + 1);
900     *set = 0;
901     return 0;
902 }
903
904 /*
905  * Add a symbol to a symbol set for field FLDNO in *SET.
906  * SYM is the name of the symbol to add.
907  * Return 1 on success, -1 on error.
908  */
909 static int
910 add2symset(int fldno, long *set, char *sym)
911 {
912     struct castr *ca;
913     int i;
914
915     ca = getfld(fldno, NULL);
916     if (!ca)
917         return -1;
918
919     i = xunsymbol(sym, ca, fldno);
920     if (i < 0)
921         return -1;
922     *set |= symval(ca, i);
923     return 0;
924 }
925
926 /*
927  * Read an xdump table header line from FP.
928  * Expect header for EXPECTED_TABLE, unless it is EF_BAD.
929  * Recognize header for machine- and human-readable syntax, and set
930  * human accordingly.
931  * Return table type on success, -2 on EOF before header, -1 on failure.
932  */
933 static int
934 xuheader(FILE *fp, int expected_table)
935 {
936     char name[64];
937     int res, ch;
938     int type;
939
940     while ((ch = skipfs(fp)) == '\n')
941         lineno++;
942     if (ch == EOF && expected_table == EF_BAD)
943         return -2;
944     ungetc(ch, fp);
945
946     human = ch == 'c';
947     res = -1;
948     if ((human
949          ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
950          : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
951                   name, &res) != 1) || res < 0)
952         return gripe("Expected xdump header");
953
954     type = ef_byname(name);
955     if (type < 0)
956         return gripe("Unknown table `%s'", name);
957     if (expected_table != EF_BAD && expected_table != type)
958         return gripe("Expected table `%s', not `%s'",
959                      ef_nameof(expected_table), name);
960
961     if (!empfile[type].file
962         || !ef_cadef(type) || !(ef_flags(type) & EFF_MEM)) {
963         CANT_HAPPEN(expected_table != EF_BAD);
964         return gripe("Table `%s' is not permitted here", name);
965     }
966
967     if (skipfs(fp) != '\n')
968         return gripe("Junk after xdump header");
969     lineno++;
970
971     return type;
972 }
973
974 /*
975  * Find fields in this xdump.
976  * If reading human-readable syntax, read a field header line from FP.
977  * Else take fields from the table's selectors in CA[].
978  * Set ellipsis, nflds, fldca[], fldidx[] and caflds[] accordingly.
979  * Return 0 on success, -1 on failure.
980  */
981 static int
982 xufldhdr(FILE *fp, struct castr ca[])
983 {
984     struct castr **fca;
985     int *fidx;
986     int ch, i, j, n;
987
988     for (i = 0; ca[i].ca_name; i++)
989         caflds[i] = 0;
990     ellipsis = 0;
991
992     if (human) {
993         while ((ch = skipfs(fp)) == '\n')
994             lineno++;
995         ungetc(ch, fp);
996         nflds = xuflds(fp, xufldname);
997         if (nflds < 0)
998             return -1;
999         nflds -= ellipsis != 0;
1000     } else {
1001         fca = fldca;
1002         fidx = fldidx;
1003
1004         for (i = 0; ca[i].ca_name; i++) {
1005             if ((ca[i].ca_flags & NSC_EXTRA))
1006                 continue;
1007             n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
1008             j = 0;
1009             do {
1010                 *fca++ = &ca[i];
1011                 *fidx++ = j;
1012             } while (++j < n);
1013         }
1014
1015         nflds = fidx - fldidx;
1016     }
1017
1018     return 0;
1019 }
1020
1021 /*
1022  * Read xdump footer from FP.
1023  * CA[] contains the table's selectors.
1024  * The body had RECS records.
1025  * Update cafldspp[] from caflds[].
1026  * Return 0 on success, -1 on failure.
1027  */
1028 static int
1029 xufooter(FILE *fp, struct castr ca[], int recs)
1030 {
1031     int res, n, i;
1032
1033     res = -1;
1034     if (human) {
1035         if (fscanf(fp, "config%n", &res) != 0 || res < 0)
1036             return gripe("Malformed table footer");
1037     } else {
1038         if (fscanf(fp, "%d", &n) != 1)
1039             return gripe("Malformed table footer");
1040         if (recs != n)
1041             return gripe("Read %d rows, which doesn't match footer "
1042                          "%d rows", recs, n);
1043     }
1044     if (skipfs(fp) != '\n')
1045         return gripe("Junk after table footer");
1046     if (tbl_part_done() < 0)
1047         return -1;
1048     lineno++;
1049
1050     for (i = 0; ca[i].ca_name; i++) {
1051         if (cafldspp[i] < caflds[i])
1052             cafldspp[i] = caflds[i];
1053     }
1054
1055     return 0;
1056 }
1057
1058 /*
1059  * Read an xdump table from FP.
1060  * Both machine- and human-readable xdump syntax are recognized.
1061  * Expect table EXPECTED_TABLE, unless it is EF_BAD.
1062  * Report errors to stderr.
1063  * Messages assume FP starts in the file FILE at line *PLNO.
1064  * Update *PLNO to reflect lines read from FP.
1065  * Return table type on success, -2 on EOF before header, -1 on failure.
1066  */
1067 int
1068 xundump(FILE *fp, char *file, int *plno, int expected_table)
1069 {
1070     struct castr *ca;
1071     int type, nca, nf, i, ch;
1072
1073     fname = file;
1074     lineno = *plno;
1075
1076     if ((type = xuheader(fp, expected_table)) < 0)
1077         return type;
1078
1079     ca = ef_cadef(type);
1080     if (CANT_HAPPEN(!ca))
1081         return -1;
1082
1083     nca = nf = 0;
1084     may_omit_id = 1;
1085     may_trunc = empfile[type].nent < 0;
1086     for (i = 0; ca[i].ca_name; i++) {
1087         nca++;
1088         if (!(ca[i].ca_flags & NSC_EXTRA)) {
1089             nf += MAX(1, ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0);
1090             if (ca[i].ca_flags & NSC_CONST)
1091                 may_omit_id = may_trunc = 0;
1092         }
1093     }
1094     fldca = malloc(nf * sizeof(*fldca));
1095     fldidx = malloc(nf * sizeof(*fldidx));
1096     caflds = malloc(nca * sizeof(*caflds));
1097     cafldspp = calloc(nca, sizeof(*cafldspp));
1098
1099     tbl_start(type);
1100     if (xutail(fp, ca) < 0)
1101         type = EF_BAD;
1102     tbl_end();
1103
1104     free(cafldspp);
1105     free(caflds);
1106     free(fldidx);
1107     free(fldca);
1108
1109     /* Skip empty lines so that callers can easily check for EOF */
1110     while ((ch = skipfs(fp)) == '\n')
1111         lineno++;
1112     ungetc(ch, fp);
1113
1114     *plno = lineno;
1115     return type;
1116 }
1117
1118 /*
1119  * Read the remainder of an xdump after the table header line from FP.
1120  * CA[] contains the table's selectors.
1121  * Return 0 on success, -1 on failure.
1122  */
1123 static int
1124 xutail(FILE *fp, struct castr *ca)
1125 {
1126     int recs;
1127
1128     for (;;) {
1129         if (xufldhdr(fp, ca) < 0)
1130             return -1;
1131         if ((recs = xubody(fp)) < 0)
1132             return -1;
1133         if (xufooter(fp, ca, recs) < 0)
1134             return -1;
1135         if (!ellipsis)
1136             return 0;
1137         if (xuheader(fp, cur_type) < 0)
1138             return -1;
1139     }
1140 }
1141
1142 /*
1143  * Read the body of an xdump table from FP.
1144  * Return number of rows read on success, -1 on failure.
1145  */
1146 static int
1147 xubody(FILE *fp)
1148 {
1149     int i, ch;
1150
1151     for (i = 0;; ++i) {
1152         while ((ch = skipfs(fp)) == '\n')
1153             lineno++;
1154         if (ch == '/')
1155             break;
1156         ungetc(ch, fp);
1157         if (xuflds(fp, xufld) < 0)
1158             return -1;
1159     }
1160     return i;
1161 }