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
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.
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.
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
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.
28 * xundump.c: Load back xdump output
30 * Known contributors to this file:
31 * Ron Koenderink, 2005
32 * Markus Armbruster, 2005
35 /* FIXME normalize terminology: table/rows/columns or file/records/fields */
47 #include "prototypes.h"
52 #define MAX_NUM_COLUMNS 256
54 static char *fname = "";
55 static int lineno = 0;
60 * This structure could be replaced with struct valstr.
64 VAL_STRING, /* uses v_string */
65 VAL_SYMBOL, /* uses v_string */
66 VAL_SYMBOL_SET, /* uses v_string */
67 VAL_INDEX_ID, /* uses v_index_name and v_int */
68 VAL_INDEX_SYMBOL, /* uses v_index_name and v_string */
69 VAL_DOUBLE /* uses v_double */
73 enum enum_value v_type;
82 static int gripe(char *fmt, ...) ATTRIBUTE((format (printf, 1, 2)));
89 fprintf(stderr, "%s:%d: ", fname, lineno);
91 vfprintf(stderr, fmt, ap);
105 } while (ch == ' ' || ch == '\t');
110 } while (ch != EOF && ch != '\n');
117 getid(FILE *fp, char *buf)
120 if (fscanf(fp, "%1023[^#() \t\n]%n", buf, &n) != 1 || !isalpha(buf[0]))
135 if (sscanf(++src, "%3o%n", &octal_chr, &n) != 1 || n != 3)
137 *dst++ = (char)octal_chr;
147 xufldname(FILE *fp, struct value values[], int i)
152 values[i].v_type = VAL_NOTUSED;
157 return gripe("Unexpected EOF");
162 if (getid(fp, buf) < 0)
163 return gripe("Junk in field %d", i + 1);
167 values[i].v_type = VAL_SYMBOL;
168 values[i].v_field.v_string = strdup(buf);
173 if (isdigit(ch) || ch == '-' || ch == '+') {
174 if (fscanf(fp, "%d", &values[i].v_field.v_int) != 1) {
175 return gripe("Malformed number in index field %d", i + 1);
178 if (getid(fp, buf) < 0)
179 return gripe("Malformed string in index field %d", i + 1);
180 return gripe("Symbolic index in field %d not yet implemented",
185 return gripe("Malformed index field %d", i + 1);
186 values[i].v_index_name = strdup(buf);
187 values[i].v_type = VAL_INDEX_ID;
193 xufld(FILE *fp, struct value values[], int i)
200 values[i].v_type = VAL_NOTUSED;
205 return gripe("Unexpected EOF");
208 case '+': case '-': case '.':
209 case '0': case '1': case '2': case '3': case '4':
210 case '5': case '6': case '7': case '8': case '9':
212 if (fscanf(fp, "%lg", &values[i].v_field.v_double) != 1)
213 return gripe("Malformed number in field %d", i + 1);
214 values[i].v_type = VAL_DOUBLE;
222 if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
223 return gripe("Malformed string in field %d", i + 1);
225 return gripe("Invalid escape sequence in field %d",
228 values[i].v_type = VAL_STRING;
229 values[i].v_field.v_string = strdup(buf);
236 if (ch == EOF || ch == '\n')
237 return gripe("Unmatched '(' in field %d", i + 1);
243 return gripe("Junk in field %d", i + 1);
244 p = realloc(p, len + l1 + 2);
245 strcpy(p + len, buf);
246 strcpy(p + len + l1, " ");
251 values[i].v_type = VAL_SYMBOL_SET;
252 values[i].v_field.v_string = p;
256 if (getid(fp, buf) < 0)
257 return gripe("Junk in field %d", i + 1);
258 if (!strcmp(buf, "nil")) {
259 values[i].v_type = VAL_STRING;
260 values[i].v_field.v_string = NULL;
262 values[i].v_type = VAL_SYMBOL;
263 values[i].v_field.v_string = strdup(buf);
270 xuflds(FILE *fp, struct value values[],
271 int (*parse)(FILE *, struct value values[], int))
276 if (i >= MAX_NUM_COLUMNS)
277 return gripe("Too many columns");
278 res = parse(fp, values, i);
286 else if (ch != ' ' && ch != '\t')
287 return gripe("Bad field separator after field %d", i + 1);
292 freeflds(struct value values[])
296 for (vp = values; vp->v_type != VAL_NOTUSED; vp++) {
297 if (vp->v_type != VAL_DOUBLE && vp->v_type != VAL_INDEX_ID)
298 free(vp->v_field.v_string);
300 free(vp->v_index_name);
301 vp->v_index_name = NULL;
305 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
307 int i = stmtch(id, symtab, offsetof(struct symbol, name),
308 sizeof(struct symbol));
310 return gripe("%s %s symbol `%s' in field %d",
311 i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
317 xunsymbol(struct castr *ca, struct value *vp, int n)
319 struct symbol *symtab = (struct symbol *)empfile[ca->ca_table].cache;
320 char *buf = vp->v_field.v_string;
325 if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca)
326 return gripe("%s doesn't take a symbol or symbol set in field %d",
329 if (vp->v_type == VAL_SYMBOL_SET) {
330 if (!(ca->ca_flags & NSC_BITS))
331 return gripe("%s doesn't take a symbol set in field %d",
334 for (token = strtok(buf, " "); token; token = strtok(NULL, " ")) {
335 i = xunsymbol1(token, symtab, ca, n);
338 value |= symtab[i].value;
340 } else if (vp->v_type == VAL_SYMBOL) {
341 if (ca->ca_flags & NSC_BITS)
342 return gripe("%s doesn't take a symbol in field %d",
344 i = xunsymbol1(buf, symtab, ca, n);
347 value = symtab[i].value;
351 vp->v_type = VAL_DOUBLE;
352 vp->v_field.v_double = value;
357 has_const(struct castr ca[])
361 for (i = 0; ca[i].ca_name; i++) {
362 if (ca[i].ca_flags & NSC_CONST)
369 xuinitrow(int type, int row)
371 struct empfile *ep = &empfile[type];
372 char *ptr = ep->cache + ep->size * row;
374 memset(ptr, 0, ep->size);
381 xuloadrow(int type, int row, struct value values[])
384 struct empfile *ep = &empfile[type];
385 char *ptr = ep->cache + ep->size * row;
386 struct castr *ca = ep->cadef;
391 while (ca[i].ca_type != NSC_NOTYPE &&
392 values[j].v_type != VAL_NOTUSED) {
393 if (ca[i].ca_flags & NSC_EXTRA) {
397 row_ref = (char *)ptr + ca[i].ca_off;
402 * factor out NSC_CONST comparsion
404 switch (values[j].v_type) {
407 if (xunsymbol(&ca[i], &values[j], j) < 0)
411 switch (ca[i].ca_type) {
413 if (ca[i].ca_flags & NSC_CONST) {
414 if (((int *)row_ref)[k] != (int)
415 values[j].v_field.v_double)
416 gripe("Field %s must be same, "
417 "read %d != expected %d",
420 (int)values[j].v_field.v_double);
423 ((int *)row_ref)[k] =
424 (int)values[j].v_field.v_double;
427 if (ca[i].ca_flags & NSC_CONST) {
428 if (((long *)row_ref)[k] != (long)
429 values[j].v_field.v_double)
430 gripe("Field %s must be same, "
431 "read %ld != expected %ld",
433 ((long *)row_ref)[k],
434 (long)values[j].v_field.v_double);
436 ((long *)row_ref)[k] = (long)
437 values[j].v_field.v_double;
440 if (ca[i].ca_flags & NSC_CONST) {
441 if (((short *)row_ref)[k] !=
442 (short)values[j].v_field.v_double)
443 gripe("Field %s must be same, "
444 "read %d != expected %d",
446 ((short *)row_ref)[k],
447 (short)values[j].v_field.v_double);
449 ((short *)row_ref)[k] = (short)
450 values[j].v_field.v_double;
453 if (ca[i].ca_flags & NSC_CONST) {
454 if (((unsigned short *)row_ref)[k] !=
455 (unsigned short)values[j].v_field.v_double)
456 gripe("Field %s must be same, "
457 "read %d != expected %d",
459 ((unsigned short *)row_ref)[k],
460 (unsigned short)values[j].v_field.v_double);
462 ((unsigned short *)row_ref)[k] = (unsigned short)
463 values[j].v_field.v_double;
466 if (ca[i].ca_flags & NSC_CONST) {
467 if (((unsigned char *)row_ref)[k] != (unsigned char)
468 values[j].v_field.v_double)
469 gripe("Field %s must be same, "
470 "read %d != expected %d",
472 ((unsigned char *)row_ref)[k],
473 (unsigned char)values[j].v_field.v_double);
475 ((unsigned char *)row_ref)[k] = (unsigned char)
476 values[j].v_field.v_double;
479 if (ca[i].ca_flags & NSC_CONST) {
480 if (((float *)row_ref)[k] != (float)
481 values[j].v_field.v_double)
482 gripe("Field %s must be same, "
483 "read %g != expected %g",
485 ((float *)row_ref)[k],
486 (float)values[j].v_field.v_double);
488 ((float *)row_ref)[k] = (float)
489 values[j].v_field.v_double;
492 return gripe("Field %s is a string type, "
493 "but %lg was read which is a number",
494 ca[i].ca_name, values[j].v_field.v_double);
496 return gripe("Field %s's type %d is not supported",
497 ca[i].ca_name, ca[i].ca_type);
501 switch(ca[i].ca_type) {
503 if (ca[i].ca_flags & NSC_CONST) {
504 if (strcmp(((char **)row_ref)[k],
505 values[j].v_field.v_string) != 0)
506 gripe("Field %s must be same, "
507 "read %s != expected %s",
509 ((char **)row_ref)[k],
510 values[j].v_field.v_string);
512 ((char **)row_ref)[k]
513 = strdup(values[j].v_field.v_string);
521 return gripe("Field %s is a number type %d, "
522 "but %s was read which is a string",
523 ca[i].ca_name, ca[i].ca_type,
524 values[j].v_field.v_string);
526 return gripe("Field %s's type %d is not supported",
527 ca[i].ca_name, ca[i].ca_type);
531 return gripe("Missing column %s in file", ca[i].ca_name);
533 case VAL_INDEX_SYMBOL:
534 return gripe("Index fields not supported in data rows in %s file",
537 return gripe("Unknown value type %d", values[j].v_type);
541 } while (k < ca[i].ca_len);
544 if (ca[i].ca_type != NSC_NOTYPE)
545 return gripe("Missing column %s in file", ca[i].ca_name);
546 switch (values[j].v_type) {
552 return gripe("Extra junk after the last column, read %s",
553 values[j].v_field.v_string);
555 return gripe("Extra junk after the last column, read %lg",
556 values[j].v_field.v_double);
558 return gripe("Extra junk after the last column, "
559 "unknown value type %d", values[j].v_type);
565 xuheader(FILE *fp, int expected_table)
571 while ((ch = skipfs(fp)) == '\n')
573 if (ch == EOF && expected_table == EF_BAD)
580 ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
581 : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
582 name, &res) != 1) || res < 0)
583 return gripe("Expected xdump header");
585 if (skipfs(fp) != '\n')
586 return gripe("Junk after xdump header");
588 type = ef_byname(name);
590 return gripe("Unknown table `%s'", name);
591 if (expected_table != EF_BAD && expected_table != type)
592 return gripe("Expected table `%s', not `%s'",
593 ef_nameof(expected_table), name);
595 if (CANT_HAPPEN(!(ef_flags(type) & EFF_MEM)))
602 xucolumnheader(FILE *fp, int type, struct value values[])
605 struct empfile *ep = &empfile[type];
606 struct castr *ca = ep->cadef;
612 while ((ch = skipfs(fp)) == '\n');
615 /* FIXME parse column header */
616 if (xuflds(fp, values, xufldname) <= 0) {
621 * check column count form xuflds()
625 for (i = 0; ca[i].ca_name; i++) {
626 if (ca[i].ca_flags & NSC_EXTRA)
630 if (values[j].v_type == VAL_NOTUSED) {
632 return gripe("Not enough columns in the header for table %s",
635 switch(values[j].v_type) {
637 if (ca[i].ca_len != 0) {
639 return gripe("Column %s is a not index format for table %s",
640 ca[i].ca_name, ef_nameof(type));
642 if (strcmp(values[j].v_field.v_string, ca[i].ca_name) != 0) {
643 gripe("Column name (%s) does not match header name (%s)",
644 ca[i].ca_name, values[j].v_field.v_string);
649 case VAL_INDEX_SYMBOL:
650 return gripe("Column %s is does not currently support index symbol format for table %s",
651 ca[i].ca_name, ef_nameof(type));
653 if (ca[i].ca_len == 0) {
655 return gripe("Column %s is in index format and should not be for table %s",
656 ca[i].ca_name, ef_nameof(type));
658 if (values[j].v_field.v_int != k) {
660 return gripe("Column Array index %d does not match %d",
661 values[j].v_field.v_int, k);
663 if (strcmp(values[j].v_index_name, ca[i].ca_name) != 0) {
664 gripe("Column name (%s) does not match header name (%s)",
665 ca[i].ca_name, values[j].v_field.v_string);
672 return gripe("Column %s is a not string for table %s",
673 ca[i].ca_name, ef_nameof(type));
677 } while (k < ca[i].ca_len);
679 if (values[j].v_type != VAL_NOTUSED) {
681 return gripe("Too many columns in the header for table %s",
690 xutrailer(FILE *fp, int type, int row)
696 if (fscanf(fp, "config%n", &res) != 0 || res < 0)
697 return gripe("Malformed table footer");
699 if (fscanf(fp, "%d", &rows) != 1)
700 return gripe("Malformed table footer");
702 return gripe("Read %d rows, which doesn't match footer "
703 "%d rows", row, rows);
705 if (skipfs(fp) != '\n')
706 return gripe("Junk after table footer");
713 xundump(FILE *fp, char *file, int expected_table)
718 struct value values[MAX_NUM_COLUMNS + 1];
722 memset(values, 0, sizeof(values));
724 if (strcmp(fname, file) != 0) {
730 if ((type = xuheader(fp, expected_table)) == -1)
734 fixed_rows = has_const(ef_cadef(type));
735 need_sentinel = !fixed_rows; /* FIXME only approximation */
737 if (xucolumnheader(fp, type, values) == -1)
749 * Add column count check to the return value of xuflds()
751 res = xuflds(fp, values, xufld);
752 if (res > 0 && row >= ep->csize - 1) {
753 /* TODO grow cache unless EFF_STATIC */
754 gripe("Too many rows for table %s", ef_nameof(type));
759 xuinitrow(type, row);
760 res = xuloadrow(type, row, values);
767 if (fixed_rows && row != ep->csize -1)
768 return gripe("Table %s requires %d rows, got %d",
769 ef_nameof(type), ep->csize - 1, row);
772 xuinitrow(type, row);
774 if (xutrailer(fp, type, row) == -1)
777 ep->fids = ep->cids = row;