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 values[i].v_type = VAL_NOTUSED;
226 return gripe("Bad field separator after field %d", i + 1);
232 freeflds(struct value values[])
236 for (vp = values; vp->v_type != VAL_NOTUSED; vp++) {
237 if (vp->v_type != VAL_DOUBLE)
238 free(vp->v_field.v_string);
243 xunsymbol1(char *id, struct symbol *symtab, struct castr *ca, int n)
245 int i = stmtch(id, symtab, offsetof(struct symbol, name),
246 sizeof(struct symbol));
248 return gripe("%s %s symbol `%s' in field %d",
249 i == M_NOTUNIQUE ? "Ambiguous" : "Unknown",
255 xunsymbol(struct castr *ca, struct value *vp, int n)
257 struct symbol *symtab = (struct symbol *)empfile[ca->ca_table].cache;
258 char *buf = vp->v_field.v_string;
263 if (ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca)
264 return gripe("%s doesn't take a symbol or symbol set in field %d",
267 if (vp->v_type == VAL_SYMBOL_SET) {
268 if (!(ca->ca_flags & NSC_BITS))
269 return gripe("%s doesn't take a symbol set in field %d",
272 for (token = strtok(buf, " "); token; token = strtok(NULL, " ")) {
273 i = xunsymbol1(token, symtab, ca, n);
276 value |= symtab[i].value;
278 } else if (vp->v_type == VAL_SYMBOL) {
279 if (ca->ca_flags & NSC_BITS)
280 return gripe("%s doesn't take a symbol in field %d",
282 i = xunsymbol1(buf, symtab, ca, n);
285 value = symtab[i].value;
289 vp->v_type = VAL_DOUBLE;
290 vp->v_field.v_double = value;
295 has_const(struct castr ca[])
299 for (i = 0; ca[i].ca_name; i++) {
300 if (ca[i].ca_flags & NSC_CONST)
307 xuinitrow(int type, int row)
309 struct empfile *ep = &empfile[type];
310 char *ptr = ep->cache + ep->size * row;
312 memset(ptr, 0, ep->size);
319 xuloadrow(int type, int row, struct value values[])
322 struct empfile *ep = &empfile[type];
323 char *ptr = ep->cache + ep->size * row;
324 struct castr *ca = ep->cadef;
329 while (ca[i].ca_type != NSC_NOTYPE &&
330 values[j].v_type != VAL_NOTUSED) {
331 if (ca[i].ca_flags & NSC_EXTRA) {
335 row_ref = (char *)ptr + ca[i].ca_off;
340 * factor out NSC_CONST comparsion
342 switch (values[j].v_type) {
345 if (xunsymbol(&ca[i], &values[j], j) < 0)
349 switch (ca[i].ca_type) {
351 if (ca[i].ca_flags & NSC_CONST) {
352 if (((int *)row_ref)[k] != (int)
353 values[j].v_field.v_double)
354 gripe("Field %s must be same, "
355 "read %d != expected %d",
358 (int)values[j].v_field.v_double);
361 ((int *)row_ref)[k] =
362 (int)values[j].v_field.v_double;
365 if (ca[i].ca_flags & NSC_CONST) {
366 if (((long *)row_ref)[k] != (long)
367 values[j].v_field.v_double)
368 gripe("Field %s must be same, "
369 "read %ld != expected %ld",
371 ((long *)row_ref)[k],
372 (long)values[j].v_field.v_double);
374 ((long *)row_ref)[k] = (long)
375 values[j].v_field.v_double;
378 if (ca[i].ca_flags & NSC_CONST) {
379 if (((short *)row_ref)[k] !=
380 (short)values[j].v_field.v_double)
381 gripe("Field %s must be same, "
382 "read %d != expected %d",
384 ((short *)row_ref)[k],
385 (short)values[j].v_field.v_double);
387 ((short *)row_ref)[k] = (short)
388 values[j].v_field.v_double;
391 if (ca[i].ca_flags & NSC_CONST) {
392 if (((unsigned short *)row_ref)[k] !=
393 (unsigned short)values[j].v_field.v_double)
394 gripe("Field %s must be same, "
395 "read %d != expected %d",
397 ((unsigned short *)row_ref)[k],
398 (unsigned short)values[j].v_field.v_double);
400 ((unsigned short *)row_ref)[k] = (unsigned short)
401 values[j].v_field.v_double;
404 if (ca[i].ca_flags & NSC_CONST) {
405 if (((unsigned char *)row_ref)[k] != (unsigned char)
406 values[j].v_field.v_double)
407 gripe("Field %s must be same, "
408 "read %d != expected %d",
410 ((unsigned char *)row_ref)[k],
411 (unsigned char)values[j].v_field.v_double);
413 ((unsigned char *)row_ref)[k] = (unsigned char)
414 values[j].v_field.v_double;
417 if (ca[i].ca_flags & NSC_CONST) {
418 if (((float *)row_ref)[k] != (float)
419 values[j].v_field.v_double)
420 gripe("Field %s must be same, "
421 "read %g != expected %g",
423 ((float *)row_ref)[k],
424 (float)values[j].v_field.v_double);
426 ((float *)row_ref)[k] = (float)
427 values[j].v_field.v_double;
430 return gripe("Field %s is a string type, "
431 "but %lg was read which is a number",
432 ca[i].ca_name, values[j].v_field.v_double);
434 return gripe("Field %s's type %d is not supported",
435 ca[i].ca_name, ca[i].ca_type);
439 switch(ca[i].ca_type) {
441 if (ca[i].ca_flags & NSC_CONST) {
442 if (strcmp(((char **)row_ref)[k],
443 values[j].v_field.v_string) != 0)
444 gripe("Field %s must be same, "
445 "read %s != expected %s",
447 ((char **)row_ref)[k],
448 values[j].v_field.v_string);
450 ((char **)row_ref)[k]
451 = strdup(values[j].v_field.v_string);
459 return gripe("Field %s is a number type %d, "
460 "but %s was read which is a string",
461 ca[i].ca_name, ca[i].ca_type,
462 values[j].v_field.v_string);
464 return gripe("Field %s's type %d is not supported",
465 ca[i].ca_name, ca[i].ca_type);
469 return gripe("Missing column %s in file", ca[i].ca_name);
471 return gripe("Unknown value type %d", values[j].v_type);
475 } while (k < ca[i].ca_len);
478 if (ca[i].ca_type != NSC_NOTYPE)
479 return gripe("Missing column %s in file", ca[i].ca_name);
480 switch (values[j].v_type) {
486 return gripe("Extra junk after the last column, read %s",
487 values[j].v_field.v_string);
489 return gripe("Extra junk after the last column, read %lg",
490 values[j].v_field.v_double);
492 return gripe("Extra junk after the last column, "
493 "unknown value type %d", values[j].v_type);
499 xuheader(FILE *fp, int expected_table)
506 while ((ch = skipfs(fp)) == '\n')
508 if (ch == EOF && expected_table == EF_BAD)
515 ? fscanf(fp, "config%*[ \t]%63[^ \t#\n]%n", name, &res) != 1
516 : fscanf(fp, "XDUMP%*[ \t]%63[^ \t#\n]%*[ \t]%*[^ \t#\n]%n",
517 name, &res) != 1) || res < 0)
518 return gripe("Expected xdump header");
520 if (skipfs(fp) != '\n')
521 return gripe("Junk after xdump header");
523 type = ef_byname(name);
525 return gripe("Unknown table `%s'", name);
527 if (CANT_HAPPEN(!(ep->flags & EFF_MEM)))
528 return -1; /* not implemented */
530 if (expected_table != EF_BAD && expected_table != type)
531 return gripe("Expected table `%s', not `%s'",
532 ef_nameof(expected_table), name);
537 xucolumnheader(FILE *fp, int type)
544 while ((ch = skipfs(fp)) == '\n');
547 /* FIXME parse column header */
548 if (fscanf(fp, "%*[^\n]\n") == -1)
549 return gripe("Invalid Column Header for table %s",
557 xutrailer(FILE *fp, int type, int row)
563 if (fscanf(fp, "config%n", &res) != 0) {
564 return gripe("Malformed table footer");
569 if (ch != '\n' || !human)
570 return gripe("Malformed table footer");
573 if (fscanf(fp, "%d", &rows) != 1)
574 return gripe("Malformed table footer");
576 return gripe("Read %d rows, which doesn't match footer "
577 "%d rows", row, rows);
579 if (skipfs(fp) != '\n')
580 return gripe("Junk after table footer");
582 while ((ch = skipfs(fp)) == '\n') ;
589 xundump(FILE *fp, char *file, int expected_table)
594 struct value values[MAX_NUM_COLUMNS + 1];
598 if (strcmp(fname, file) != 0) {
604 if ((type = xuheader(fp, expected_table)) == -1)
608 fixed_rows = has_const(ef_cadef(type));
609 need_sentinel = !fixed_rows; /* FIXME only approximation */
611 if (xucolumnheader(fp, type) == -1)
623 * Add column count check to the return value of xuflds()
625 res = xuflds(fp, values);
626 if (res > 0 && row >= ep->csize - 1) {
627 /* TODO grow cache unless EFF_STATIC */
628 gripe("Too many rows for table %s", ef_nameof(type));
633 xuinitrow(type, row);
634 res = xuloadrow(type, row, values);
641 if (fixed_rows && row != ep->csize -1)
642 return gripe("Table %s requires %d rows, got %d",
643 ef_nameof(type), ep->csize - 1, row);
646 xuinitrow(type, row);
648 if (xutrailer(fp, type, row) == -1)
651 ep->fids = ep->cids = row;