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.
71 enum enum_value v_type;
78 static int gripe(char *fmt, ...) ATTRIBUTE((format (printf, 1, 2)));
85 fprintf(stderr, "%s:%d: ", fname, lineno);
87 vfprintf(stderr, fmt, ap);
101 } while (ch == ' ' || ch == '\t');
106 } while (ch != EOF && ch != '\n');
113 getid(FILE *fp, char *buf)
116 if (fscanf(fp, "%1023[^#() \t\n]%n", buf, &n) != 1 || !isalpha(buf[0]))
131 if (sscanf(++src, "%3o%n", &octal_chr, &n) != 1 || n != 3)
133 *dst++ = (char)octal_chr;
143 xuflds(FILE *fp, struct value values[])
151 values[i].v_type = VAL_NOTUSED;
152 if (i >= MAX_NUM_COLUMNS)
153 return gripe("Too many columns");
158 return gripe("Unexpected EOF");
161 case '+': case '-': case '.':
162 case '0': case '1': case '2': case '3': case '4':
163 case '5': case '6': case '7': case '8': case '9':
165 if (fscanf(fp, "%lg", &values[i].v_field.v_double) != 1)
166 return gripe("Malformed number in field %d", i + 1);
167 values[i].v_type = VAL_DOUBLE;
175 if (fscanf(fp, "%1023[^\"\n]", buf) != 1 || getc(fp) != '"')
176 return gripe("Malformed string in field %d", i + 1);
178 return gripe("Invalid escape sequence in field %d",
181 values[i].v_type = VAL_STRING;
182 values[i].v_field.v_string = strdup(buf);
189 if (ch == EOF || ch == '\n')
190 return gripe("Unmatched '(' in field %d", i + 1);
196 return gripe("Junk in field %d", i + 1);
197 p = realloc(p, len + l1 + 2);
198 strcpy(p + len, buf);
199 strcpy(p + len + l1, " ");
204 values[i].v_type = VAL_SYMBOL_SET;
205 values[i].v_field.v_string = p;
209 if (getid(fp, buf) < 0) {
210 return gripe("Junk in field %d", i + 1);
212 if (!strcmp(buf, "nil")) {
213 values[i].v_type = VAL_STRING;
214 values[i].v_field.v_string = NULL;
217 values[i].v_type = VAL_SYMBOL;
218 values[i].v_field.v_string = strdup(buf);
224 else if (ch != ' ' && ch != '\t')
225 return gripe("Bad field separator after field %d", i + 1);
230 freeflds(struct value values[])
234 for (vp = values; vp->v_type != VAL_NOTUSED; vp++) {
235 if (vp->v_type != VAL_DOUBLE)
236 free(vp->v_field.v_string);
241 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
243 int i = stmtch(id, symtab, offsetof(struct symbol, name),
244 sizeof(struct symbol));
246 return gripe("%s %s symbol `%s' in field %d",
247 i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
253 xunsymbol(struct castr *ca, struct value *vp, int n)
255 struct symbol *symtab = (struct symbol *)empfile[ca->ca_table].cache;
256 char *buf = vp->v_field.v_string;
261 if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca)
262 return gripe("%s doesn't take a symbol or symbol set in field %d",
265 if (vp->v_type == VAL_SYMBOL_SET) {
266 if (!(ca->ca_flags & NSC_BITS))
267 return gripe("%s doesn't take a symbol set in field %d",
270 for (token = strtok(buf, " "); token; token = strtok(NULL, " ")) {
271 i = xunsymbol1(token, symtab, ca, n);
274 value |= symtab[i].value;
276 } else if (vp->v_type == VAL_SYMBOL) {
277 if (ca->ca_flags & NSC_BITS)
278 return gripe("%s doesn't take a symbol in field %d",
280 i = xunsymbol1(buf, symtab, ca, n);
283 value = symtab[i].value;
287 vp->v_type = VAL_DOUBLE;
288 vp->v_field.v_double = value;
293 has_const(struct castr ca[])
297 for (i = 0; ca[i].ca_name; i++) {
298 if (ca[i].ca_flags & NSC_CONST)
305 xuinitrow(int type, int row)
307 struct empfile *ep = &empfile[type];
308 char *ptr = ep->cache + ep->size * row;
310 memset(ptr, 0, ep->size);
317 xuloadrow(int type, int row, struct value values[])
320 struct empfile *ep = &empfile[type];
321 char *ptr = ep->cache + ep->size * row;
322 struct castr *ca = ep->cadef;
327 while (ca[i].ca_type != NSC_NOTYPE &&
328 values[j].v_type != VAL_NOTUSED) {
329 if (ca[i].ca_flags & NSC_EXTRA) {
333 row_ref = (char *)ptr + ca[i].ca_off;
338 * factor out NSC_CONST comparsion
340 switch (values[j].v_type) {
343 if (xunsymbol(&ca[i], &values[j], j) < 0)
347 switch (ca[i].ca_type) {
349 if (ca[i].ca_flags & NSC_CONST) {
350 if (((int *)row_ref)[k] != (int)
351 values[j].v_field.v_double)
352 gripe("Field %s must be same, "
353 "read %d != expected %d",
356 (int)values[j].v_field.v_double);
359 ((int *)row_ref)[k] =
360 (int)values[j].v_field.v_double;
363 if (ca[i].ca_flags & NSC_CONST) {
364 if (((long *)row_ref)[k] != (long)
365 values[j].v_field.v_double)
366 gripe("Field %s must be same, "
367 "read %ld != expected %ld",
369 ((long *)row_ref)[k],
370 (long)values[j].v_field.v_double);
372 ((long *)row_ref)[k] = (long)
373 values[j].v_field.v_double;
376 if (ca[i].ca_flags & NSC_CONST) {
377 if (((short *)row_ref)[k] !=
378 (short)values[j].v_field.v_double)
379 gripe("Field %s must be same, "
380 "read %d != expected %d",
382 ((short *)row_ref)[k],
383 (short)values[j].v_field.v_double);
385 ((short *)row_ref)[k] = (short)
386 values[j].v_field.v_double;
389 if (ca[i].ca_flags & NSC_CONST) {
390 if (((unsigned short *)row_ref)[k] !=
391 (unsigned short)values[j].v_field.v_double)
392 gripe("Field %s must be same, "
393 "read %d != expected %d",
395 ((unsigned short *)row_ref)[k],
396 (unsigned short)values[j].v_field.v_double);
398 ((unsigned short *)row_ref)[k] = (unsigned short)
399 values[j].v_field.v_double;
402 if (ca[i].ca_flags & NSC_CONST) {
403 if (((unsigned char *)row_ref)[k] != (unsigned char)
404 values[j].v_field.v_double)
405 gripe("Field %s must be same, "
406 "read %d != expected %d",
408 ((unsigned char *)row_ref)[k],
409 (unsigned char)values[j].v_field.v_double);
411 ((unsigned char *)row_ref)[k] = (unsigned char)
412 values[j].v_field.v_double;
415 if (ca[i].ca_flags & NSC_CONST) {
416 if (((float *)row_ref)[k] != (float)
417 values[j].v_field.v_double)
418 gripe("Field %s must be same, "
419 "read %g != expected %g",
421 ((float *)row_ref)[k],
422 (float)values[j].v_field.v_double);
424 ((float *)row_ref)[k] = (float)
425 values[j].v_field.v_double;
428 return gripe("Field %s is a string type, "
429 "but %lg was read which is a number",
430 ca[i].ca_name, values[j].v_field.v_double);
432 return gripe("Field %s's type %d is not supported",
433 ca[i].ca_name, ca[i].ca_type);
437 switch(ca[i].ca_type) {
439 if (ca[i].ca_flags & NSC_CONST) {
440 if (strcmp(((char **)row_ref)[k],
441 values[j].v_field.v_string) != 0)
442 gripe("Field %s must be same, "
443 "read %s != expected %s",
445 ((char **)row_ref)[k],
446 values[j].v_field.v_string);
448 ((char **)row_ref)[k]
449 = strdup(values[j].v_field.v_string);
457 return gripe("Field %s is a number type %d, "
458 "but %s was read which is a string",
459 ca[i].ca_name, ca[i].ca_type,
460 values[j].v_field.v_string);
462 return gripe("Field %s's type %d is not supported",
463 ca[i].ca_name, ca[i].ca_type);
467 return gripe("Missing column %s in file", ca[i].ca_name);
469 return gripe("Unknown value type %d", values[j].v_type);
473 } while (k < ca[i].ca_len);
476 if (ca[i].ca_type != NSC_NOTYPE)
477 return gripe("Missing column %s in file", ca[i].ca_name);
478 switch (values[j].v_type) {
484 return gripe("Extra junk after the last column, read %s",
485 values[j].v_field.v_string);
487 return gripe("Extra junk after the last column, read %lg",
488 values[j].v_field.v_double);
490 return gripe("Extra junk after the last column, "
491 "unknown value type %d", values[j].v_type);
497 xuheader(FILE *fp, int expected_table, struct value values[])
504 while ((ch = skipfs(fp)) == '\n')
506 if (ch == EOF && expected_table == EF_BAD)
513 ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
514 : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
515 name, &res) != 1) || res < 0)
516 return gripe("Expected xdump header");
518 if (skipfs(fp) != '\n')
519 return gripe("Junk after xdump header");
521 type = ef_byname(name);
523 return gripe("Unknown table `%s'", name);
525 if (CANT_HAPPEN(!(ep->flags & EFF_MEM)))
526 return -1; /* not implemented */
528 if (expected_table != EF_BAD && expected_table != type)
529 return gripe("Expected table `%s', not `%s'",
530 ef_nameof(expected_table), name);
535 xucolumnheader(FILE *fp, int type)
542 while ((ch = skipfs(fp)) == '\n');
545 /* FIXME parse column header */
546 if (fscanf(fp, "%*[^\n]\n") == -1)
547 return gripe("Invalid Column Header for table %s",
555 xutrailer(FILE *fp, int type, int row)
561 if (fscanf(fp, "config%n", &res) != 0) {
562 return gripe("Malformed table footer");
567 if (ch != '\n' || !human)
568 return gripe("Malformed table footer");
571 if (fscanf(fp, "%d", &rows) != 1)
572 return gripe("Malformed table footer");
574 return gripe("Read %d rows, which doesn't match footer "
575 "%d rows", row, rows);
577 if (skipfs(fp) != '\n')
578 return gripe("Junk after table footer");
580 while ((ch = skipfs(fp)) == '\n') ;
587 xundump(FILE *fp, char *file, int expected_table)
592 struct value values[MAX_NUM_COLUMNS + 1];
596 if (strcmp(fname, file) != 0) {
602 if ((type = xuheader(fp, expected_table, values)) == -1)
606 fixed_rows = has_const(ef_cadef(type));
607 need_sentinel = !fixed_rows; /* FIXME only approximation */
609 if (xucolumnheader(fp, type) == -1)
621 * Add column count check to the return value of xuflds()
623 res = xuflds(fp, values);
624 if (res > 0 && row >= ep->csize - 1) {
625 /* TODO grow cache unless EFF_STATIC */
626 gripe("Too many rows for table %s", ef_nameof(type));
631 xuinitrow(type, row);
632 res = xuloadrow(type, row, values);
639 if (fixed_rows && row != ep->csize -1)
640 return gripe("Table %s requires %d rows, got %d",
641 ef_nameof(type), ep->csize - 1, row);
644 xuinitrow(type, row);
646 if (xutrailer(fp, type, row) == -1)
649 ep->fids = ep->cids = row;