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 xuflds(FILE *fp, struct value values[])
155 values[i].v_type = VAL_NOTUSED;
156 if (i >= MAX_NUM_COLUMNS)
157 return gripe("Too many columns");
162 return gripe("Unexpected EOF");
165 case '+': case '-': case '.':
166 case '0': case '1': case '2': case '3': case '4':
167 case '5': case '6': case '7': case '8': case '9':
169 if (fscanf(fp, "%lg", &values[i].v_field.v_double) != 1)
170 return gripe("Malformed number in field %d", i + 1);
171 values[i].v_type = VAL_DOUBLE;
179 if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
180 return gripe("Malformed string in field %d", i + 1);
182 return gripe("Invalid escape sequence in field %d",
185 values[i].v_type = VAL_STRING;
186 values[i].v_field.v_string = strdup(buf);
193 if (ch == EOF || ch == '\n')
194 return gripe("Unmatched '(' in field %d", i + 1);
200 return gripe("Junk in field %d", i + 1);
201 p = realloc(p, len + l1 + 2);
202 strcpy(p + len, buf);
203 strcpy(p + len + l1, " ");
208 values[i].v_type = VAL_SYMBOL_SET;
209 values[i].v_field.v_string = p;
213 if (getid(fp, buf) < 0) {
214 return gripe("Junk in field %d", i + 1);
222 if (isdigit(ch) || ch == '-') {
223 if (fscanf(fp, "%d", &values[i].v_field.v_int) != 1) {
224 return gripe("Malformed number in index field %d", i + 1);
226 values[i].v_index_name = strdup(buf);
227 values[i].v_type = VAL_INDEX_ID;
229 values[i].v_index_name = strdup(buf);
230 if (getid(fp, buf) < 0) {
231 free(values[i].v_index_name);
232 values[i].v_index_name = NULL;
233 return gripe("Malformed string in index field %d", i + 1);
235 values[i].v_field.v_string = strdup(buf);
236 values[i].v_type = VAL_INDEX_SYMBOL;
240 free(values[i].v_index_name);
241 values[i].v_index_name = NULL;
242 if (values[i].v_type == VAL_INDEX_SYMBOL)
243 free(values[i].v_field.v_string);
244 values[i].v_type = VAL_NOTUSED;
245 return gripe("Malformed index field %d", i + 1);
247 } else if (!strcmp(buf, "nil")) {
248 values[i].v_type = VAL_STRING;
249 values[i].v_field.v_string = NULL;
251 values[i].v_type = VAL_SYMBOL;
252 values[i].v_field.v_string = strdup(buf);
258 else if (ch != ' ' && ch != '\t') {
259 values[i].v_type = VAL_NOTUSED;
260 return gripe("Bad field separator after field %d", i + 1);
266 freeflds(struct value values[])
270 for (vp = values; vp->v_type != VAL_NOTUSED; vp++) {
271 if (vp->v_type != VAL_DOUBLE && vp->v_type != VAL_INDEX_ID)
272 free(vp->v_field.v_string);
274 free(vp->v_index_name);
275 vp->v_index_name = NULL;
279 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
281 int i = stmtch(id, symtab, offsetof(struct symbol, name),
282 sizeof(struct symbol));
284 return gripe("%s %s symbol `%s' in field %d",
285 i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
291 xunsymbol(struct castr *ca, struct value *vp, int n)
293 struct symbol *symtab = (struct symbol *)empfile[ca->ca_table].cache;
294 char *buf = vp->v_field.v_string;
299 if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca)
300 return gripe("%s doesn't take a symbol or symbol set in field %d",
303 if (vp->v_type == VAL_SYMBOL_SET) {
304 if (!(ca->ca_flags & NSC_BITS))
305 return gripe("%s doesn't take a symbol set in field %d",
308 for (token = strtok(buf, " "); token; token = strtok(NULL, " ")) {
309 i = xunsymbol1(token, symtab, ca, n);
312 value |= symtab[i].value;
314 } else if (vp->v_type == VAL_SYMBOL) {
315 if (ca->ca_flags & NSC_BITS)
316 return gripe("%s doesn't take a symbol in field %d",
318 i = xunsymbol1(buf, symtab, ca, n);
321 value = symtab[i].value;
325 vp->v_type = VAL_DOUBLE;
326 vp->v_field.v_double = value;
331 has_const(struct castr ca[])
335 for (i = 0; ca[i].ca_name; i++) {
336 if (ca[i].ca_flags & NSC_CONST)
343 xuinitrow(int type, int row)
345 struct empfile *ep = &empfile[type];
346 char *ptr = ep->cache + ep->size * row;
348 memset(ptr, 0, ep->size);
355 xuloadrow(int type, int row, struct value values[])
358 struct empfile *ep = &empfile[type];
359 char *ptr = ep->cache + ep->size * row;
360 struct castr *ca = ep->cadef;
365 while (ca[i].ca_type != NSC_NOTYPE &&
366 values[j].v_type != VAL_NOTUSED) {
367 if (ca[i].ca_flags & NSC_EXTRA) {
371 row_ref = (char *)ptr + ca[i].ca_off;
376 * factor out NSC_CONST comparsion
378 switch (values[j].v_type) {
381 if (xunsymbol(&ca[i], &values[j], j) < 0)
385 switch (ca[i].ca_type) {
387 if (ca[i].ca_flags & NSC_CONST) {
388 if (((int *)row_ref)[k] != (int)
389 values[j].v_field.v_double)
390 gripe("Field %s must be same, "
391 "read %d != expected %d",
394 (int)values[j].v_field.v_double);
397 ((int *)row_ref)[k] =
398 (int)values[j].v_field.v_double;
401 if (ca[i].ca_flags & NSC_CONST) {
402 if (((long *)row_ref)[k] != (long)
403 values[j].v_field.v_double)
404 gripe("Field %s must be same, "
405 "read %ld != expected %ld",
407 ((long *)row_ref)[k],
408 (long)values[j].v_field.v_double);
410 ((long *)row_ref)[k] = (long)
411 values[j].v_field.v_double;
414 if (ca[i].ca_flags & NSC_CONST) {
415 if (((short *)row_ref)[k] !=
416 (short)values[j].v_field.v_double)
417 gripe("Field %s must be same, "
418 "read %d != expected %d",
420 ((short *)row_ref)[k],
421 (short)values[j].v_field.v_double);
423 ((short *)row_ref)[k] = (short)
424 values[j].v_field.v_double;
427 if (ca[i].ca_flags & NSC_CONST) {
428 if (((unsigned short *)row_ref)[k] !=
429 (unsigned short)values[j].v_field.v_double)
430 gripe("Field %s must be same, "
431 "read %d != expected %d",
433 ((unsigned short *)row_ref)[k],
434 (unsigned short)values[j].v_field.v_double);
436 ((unsigned short *)row_ref)[k] = (unsigned short)
437 values[j].v_field.v_double;
440 if (ca[i].ca_flags & NSC_CONST) {
441 if (((unsigned char *)row_ref)[k] != (unsigned char)
442 values[j].v_field.v_double)
443 gripe("Field %s must be same, "
444 "read %d != expected %d",
446 ((unsigned char *)row_ref)[k],
447 (unsigned char)values[j].v_field.v_double);
449 ((unsigned char *)row_ref)[k] = (unsigned char)
450 values[j].v_field.v_double;
453 if (ca[i].ca_flags & NSC_CONST) {
454 if (((float *)row_ref)[k] != (float)
455 values[j].v_field.v_double)
456 gripe("Field %s must be same, "
457 "read %g != expected %g",
459 ((float *)row_ref)[k],
460 (float)values[j].v_field.v_double);
462 ((float *)row_ref)[k] = (float)
463 values[j].v_field.v_double;
466 return gripe("Field %s is a string type, "
467 "but %lg was read which is a number",
468 ca[i].ca_name, values[j].v_field.v_double);
470 return gripe("Field %s's type %d is not supported",
471 ca[i].ca_name, ca[i].ca_type);
475 switch(ca[i].ca_type) {
477 if (ca[i].ca_flags & NSC_CONST) {
478 if (strcmp(((char **)row_ref)[k],
479 values[j].v_field.v_string) != 0)
480 gripe("Field %s must be same, "
481 "read %s != expected %s",
483 ((char **)row_ref)[k],
484 values[j].v_field.v_string);
486 ((char **)row_ref)[k]
487 = strdup(values[j].v_field.v_string);
495 return gripe("Field %s is a number type %d, "
496 "but %s was read which is a string",
497 ca[i].ca_name, ca[i].ca_type,
498 values[j].v_field.v_string);
500 return gripe("Field %s's type %d is not supported",
501 ca[i].ca_name, ca[i].ca_type);
505 return gripe("Missing column %s in file", ca[i].ca_name);
507 case VAL_INDEX_SYMBOL:
508 return gripe("Index fields not supported in data rows in %s file",
511 return gripe("Unknown value type %d", values[j].v_type);
515 } while (k < ca[i].ca_len);
518 if (ca[i].ca_type != NSC_NOTYPE)
519 return gripe("Missing column %s in file", ca[i].ca_name);
520 switch (values[j].v_type) {
526 return gripe("Extra junk after the last column, read %s",
527 values[j].v_field.v_string);
529 return gripe("Extra junk after the last column, read %lg",
530 values[j].v_field.v_double);
532 return gripe("Extra junk after the last column, "
533 "unknown value type %d", values[j].v_type);
539 xuheader(FILE *fp, int expected_table)
546 while ((ch = skipfs(fp)) == '\n')
548 if (ch == EOF && expected_table == EF_BAD)
555 ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
556 : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
557 name, &res) != 1) || res < 0)
558 return gripe("Expected xdump header");
560 if (skipfs(fp) != '\n')
561 return gripe("Junk after xdump header");
563 type = ef_byname(name);
565 return gripe("Unknown table `%s'", name);
567 if (CANT_HAPPEN(!(ep->flags & EFF_MEM)))
568 return -1; /* not implemented */
570 if (expected_table != EF_BAD && expected_table != type)
571 return gripe("Expected table `%s', not `%s'",
572 ef_nameof(expected_table), name);
577 xucolumnheader(FILE *fp, int type, struct value values[])
580 struct empfile *ep = &empfile[type];
581 struct castr *ca = ep->cadef;
587 while ((ch = skipfs(fp)) == '\n');
590 /* FIXME parse column header */
591 if (xuflds(fp, values) <= 0) {
596 * check column count form xuflds()
600 for (i = 0; ca[i].ca_name; i++) {
601 if (ca[i].ca_flags & NSC_EXTRA)
605 if (values[j].v_type == VAL_NOTUSED) {
607 return gripe("Not enough columns in the header for table %s",
610 switch(values[j].v_type) {
612 if (ca[i].ca_len != 0) {
614 return gripe("Column %s is a not index format for table %s",
615 ca[i].ca_name, ef_nameof(type));
617 if (strcmp(values[j].v_field.v_string, ca[i].ca_name) != 0) {
618 gripe("Column name (%s) does not match header name (%s)",
619 ca[i].ca_name, values[j].v_field.v_string);
624 case VAL_INDEX_SYMBOL:
625 return gripe("Column %s is does not currently support index symbol format for table %s",
626 ca[i].ca_name, ef_nameof(type));
628 if (ca[i].ca_len == 0) {
630 return gripe("Column %s is in index format and should not be for table %s",
631 ca[i].ca_name, ef_nameof(type));
633 if (values[j].v_field.v_int != k) {
635 return gripe("Column Array index %d does not match %d",
636 values[j].v_field.v_int, k);
638 if (strcmp(values[j].v_index_name, ca[i].ca_name) != 0) {
639 gripe("Column name (%s) does not match header name (%s)",
640 ca[i].ca_name, values[j].v_field.v_string);
647 return gripe("Column %s is a not string for table %s",
648 ca[i].ca_name, ef_nameof(type));
652 } while (k < ca[i].ca_len);
654 if (values[j].v_type != VAL_NOTUSED) {
656 return gripe("Too many columns in the header for table %s",
665 xutrailer(FILE *fp, int type, int row)
671 if (fscanf(fp, "config%n", &res) != 0) {
672 return gripe("Malformed table footer");
677 if (ch != '\n' || !human)
678 return gripe("Malformed table footer");
681 if (fscanf(fp, "%d", &rows) != 1)
682 return gripe("Malformed table footer");
684 return gripe("Read %d rows, which doesn't match footer "
685 "%d rows", row, rows);
687 if (skipfs(fp) != '\n')
688 return gripe("Junk after table footer");
690 while ((ch = skipfs(fp)) == '\n') ;
697 xundump(FILE *fp, char *file, int expected_table)
702 struct value values[MAX_NUM_COLUMNS + 1];
706 memset(values, 0, sizeof(values));
708 if (strcmp(fname, file) != 0) {
714 if ((type = xuheader(fp, expected_table)) == -1)
718 fixed_rows = has_const(ef_cadef(type));
719 need_sentinel = !fixed_rows; /* FIXME only approximation */
721 if (xucolumnheader(fp, type, values) == -1)
733 * Add column count check to the return value of xuflds()
735 res = xuflds(fp, values);
736 if (res > 0 && row >= ep->csize - 1) {
737 /* TODO grow cache unless EFF_STATIC */
738 gripe("Too many rows for table %s", ef_nameof(type));
743 xuinitrow(type, row);
744 res = xuloadrow(type, row, values);
751 if (fixed_rows && row != ep->csize -1)
752 return gripe("Table %s requires %d rows, got %d",
753 ef_nameof(type), ep->csize - 1, row);
756 xuinitrow(type, row);
758 if (xutrailer(fp, type, row) == -1)
761 ep->fids = ep->cids = row;