+#include "product.h"
+#include "xdump.h"
+
+static void verify_fail(int, int, struct castr *, int, char *, ...)
+ ATTRIBUTE((format (printf, 5, 6)));
+
+static void
+verify_fail(int type, int row, struct castr *ca, int idx, char *fmt, ...)
+{
+ int base = empfile[type].base < 0 ? type : empfile[type].base;
+ va_list ap;
+
+ fprintf(stderr, "%s %s uid %d",
+ EF_IS_GAME_STATE(base) ? "File" : "Config",
+ ef_nameof(type), row);
+ if (ca) {
+ fprintf(stderr, " field %s", ca->ca_name);
+ if (CA_IS_ARRAY(ca))
+ fprintf(stderr, "(%d)", idx);
+ }
+ fprintf(stderr, ": ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+}
+
+static int
+verify_ca(int type)
+{
+ struct castr *ca = ef_cadef(type);
+ int i;
+
+ for (i = 0; ca && ca[i].ca_name; i++) {
+ /*
+ * Virtual selectors can't be used in xundump, since we lack a
+ * setter to go with ca_get().
+ */
+ if (CANT_HAPPEN(xundumpable(type)
+ && ca[i].ca_get
+ && ca[i].ca_dump <= CA_DUMP_CONST))
+ ca[i].ca_dump = CA_DUMP_ONLY;
+ }
+ return 0;
+}
+
+static int
+verify_tabref(int type, int row, struct castr *ca, int idx, long val)
+{
+ int tabno = ca->ca_table;
+ struct castr *ca_sym = ef_cadef(tabno);
+ int i;
+
+ if (ca->ca_flags & NSC_BITS) {
+ /* symbol set */
+ if (CANT_HAPPEN(ca_sym != symbol_ca))
+ return -1;
+ for (i = 0; i < (int)sizeof(long) * 8; i++) {
+ if (val & (1UL << i)) {
+ if (!symbol_by_value(1L << i, ef_ptr(tabno, 0))) {
+ verify_fail(type, row, ca, idx,
+ "bit %d is not in symbol table %s",
+ i, ef_nameof(tabno));
+ return -1;
+ }
+ }
+ }
+ } else if (ca_sym == symbol_ca) {
+ /* symbol */
+ if (!symbol_by_value(val, ef_ptr(tabno, 0))) {
+ verify_fail(type, row, ca, idx,
+ "value %ld is not in symbol table %s",
+ val, ef_nameof(tabno));
+ return -1;
+ }
+ } else {
+ /* table index */
+ if (val >= ef_nelem(tabno) || val < -1) {
+ verify_fail(type, row, ca, idx,
+ "value %ld indexes table %s out of bounds 0..%d",
+ val, ef_nameof(tabno), ef_nelem(tabno));
+ return -1;
+ }
+ /* laziness: assumes TABNO is EFF_MEM */
+ if (val >= 0 && !empobj_in_use(tabno, ef_ptr(tabno, val))) {
+ verify_fail(type, row, ca, idx,
+ "value %ld refers to missing element of table %s",
+ val, ef_nameof(tabno));
+ return -1;
+ }
+ }
+ return 0;
+}