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