]> git.pond.sub.org Git - empserver/commitdiff
Virtual selectors
authorMarkus Armbruster <armbru@pond.sub.org>
Tue, 4 Mar 2008 20:02:00 +0000 (21:02 +0100)
committerMarkus Armbruster <armbru@pond.sub.org>
Fri, 14 Mar 2008 19:25:41 +0000 (20:25 +0100)
Where ordinary selectors specify a value stored in some object,
virtual selectors specify a function to call to compute a value
associated with some object.

Use them to replace the special case xdump ver by new table
EF_VERSION.

Move configkeys[] to lib/common because nsc_init() needs it to
initialize empfile[EF_VERSION].cadef.

12 files changed:
doc/xdump
include/file.h
include/nsc.h
info/xdump.t
src/lib/commands/xdump.c
src/lib/common/ef_verify.c
src/lib/common/emp_config.c
src/lib/common/nstreval.c
src/lib/global/constants.c
src/lib/global/file.c
src/lib/global/nsc.c
src/lib/subs/nstr.c

index 673a307eccf4c72d3c5ae53e1cdb7e00c6f49aa3..ec2c8777f82ac02d7a7cb72750c6bd865ec9b492 100644 (file)
--- a/doc/xdump
+++ b/doc/xdump
@@ -158,9 +158,6 @@ Without such a key, you need to count records to find the record
 index, and that works only if you can see a prefix of the complete
 table.
 
-The special table "ver" collects all scalar configuration parameters
-in a single record.  It does not occur in the table of tables.
-
 
 Syntax of xdump command
 
@@ -368,8 +365,7 @@ table itself.  Let's try it:
 [...]
     /45
 
-It worked!  Mind that the special table "ver" is not in the table of
-tables.
+It worked!
 
 Now dump the two symbol tables we postponed.  Because xdump accepts
 table IDs as well as names, we don't have to know their names:
index c0eca3ade69b56b56a6fd93e1f547f835af08c22..f4d8453e0d0212bb5f3eb69d33ba054e25bba1e3 100644 (file)
@@ -142,6 +142,7 @@ enum {
     EF_INFRASTRUCTURE,
     EF_UPDATES,                        /* not actually static */
     EF_TABLE,
+    EF_VERSION,
     EF_META,                   /* not really configuration */
     /* Symbol tables */
     EF_AGREEMENT_STATUS,
index b2b0a18b4102fdd80f44debec1af41e063071148..de29c3ac49683c4511659e22e962d99784c4e084 100644 (file)
@@ -95,14 +95,21 @@ typedef char packed_nsc_cat;
  * promoted type.
  * If category is NSC_OFF, the value is in a context object, and
  * val_as.sym specifies how to get it, as follows.
- * If type is NSC_STRINGY, the value is an array of sym.len characters
- * starting at sym.offs in the context object.  sym.idx must be zero.
- * Else if sym.len is zero, the value is in the context object at offset
- * sym.off.  sym.idx must be zero.
- * Else sym.len is non-zero, and the value has index sym.idx in an
- * array of sym.len elements at offset sym.off in in the context
- * object.  I.e. the value is at sym.off + sym.idx * SZ, where SZ is
- * the size of the value.
+ * If sym.get is null, and type is NSC_STRINGY, the value is an array
+ * of sym.len characters starting at sym.offs in the context object.
+ * sym.idx must be zero.
+ * Else if sym.get is null, and sym.len is zero, the value is in the
+ * context object at offset sym.off.  sym.idx must be zero.
+ * Else if sym.get is null, sym.len is non-zero, and the value has
+ * index sym.idx in an array of sym.len elements at offset sym.off in
+ * in the context object.  I.e. the value is at sym.off + sym.idx *
+ * SZ, where SZ is the size of the value.
+ * If sym.get is not null, you obtain the value by calling get() like
+ * VAL->get(VAL, CNUM, CTXO), where CNUM is the country to use for
+ * coordinate translation and access control, and CTXO is the context
+ * object.  get() either returns a null pointer and sets VAL->val_as
+ * to the value, as appropriate for the type.  Or it returns another
+ * context object and sets VAL->val_as.sym for it.
  */
 struct valstr {
     packed_nsc_type val_type;  /* type of value */
@@ -112,6 +119,7 @@ struct valstr {
            ptrdiff_t off;
            int len;
            int idx;
+           void *(*get)(struct valstr *, natid, void *);
        } sym;
        double dbl;             /* cat NSC_VAL, type NSC_DOUBLE */
        struct {                /* cat NSC_VAL, type NSC_STRING, cat NSC_ID */
@@ -197,11 +205,16 @@ typedef unsigned char nsc_flags;
  *
  * A selector describes an attribute of some context object.
  * A selector with ca_type NSC_NOTYPE is invalid.
- * A valid selector describes a datum of type ca_type at offset
- * ca_offs in the context object.
+ * If ca_get is null, the selector describes a datum of type ca_type
+ * at offset ca_offs in the context object.
  * A datum of type NSC_STRINGY is an array of ca_len characters.
  * A datum of any other type is either a scalar of that type (if
  * ca_len is zero), or an array of ca_len elements of that type.
+ * If ca_get is not null, the selector is virtual.  Values can be
+ * obtained by calling ca_get(VAL, CNUM, CTXO), where VAL has been
+ * initialized from the selector and an index, CNUM is the country to
+ * use for coordinate translation and access control, and CTXO is the
+ * context object.  See struct valstr for details.
  * If flag NSC_DEITY is set, only to deities can use this selector.
  * If flag NSC_EXTRA is set, xdump ignores this selector.
  * If flag NSC_CONST is set, the datum can't be changed from its
@@ -216,6 +229,7 @@ struct castr {
     ptrdiff_t ca_off;
     packed_nsc_type ca_type;
     unsigned short ca_len;
+    void *(*ca_get)(struct valstr *, natid, void *);
     int ca_table;
     nsc_flags ca_flags;
 };
index c105fd449b6033aba5cdb2c6ff3c01843be9667a..26a5b3a426fd8313c9d137797eca5ed219f404e8 100644 (file)
@@ -3,8 +3,6 @@
 .LV Expert
 .SY "xdump <TYPE|NUMBER> <RECORDS>"
 .SY "xdump meta <TYPE|NUMBER>"
-.SY "xdump ver"
-.SY "xdump meta ver"
 The xdump command displays information on game configuration and state
 in machine readable format.  It is intended for use by clients and
 tools.  This info page gives an overview; see doc/xdump in the source
index ccffcc168cffaacba2e624a53195169c7b3982a3..31e651aeaeb3a66161edffe1c5b8927a55948ac2 100644 (file)
 
 /*
  * Evaluate a attribute of an object into VAL, return VAL.
- * TYPE is the attribute's type.
+ * CA describes the attribute.
  * PTR points to the context object.
- * The attribute is stored there at offset OFF + IDX * S, where S is
- * its size.
- * LEN is the #array elements if it is an array, else zero.
+ * IDX is the index within the attribute.
  */
 static struct valstr *
-xdeval(struct valstr *val,
-       nsc_type type, void *ptr, ptrdiff_t off, int idx, int len)
+xdeval(struct valstr *val, struct castr *ca, void *ptr, int idx)
 {
-    val->val_type = type;
+    val->val_type = ca->ca_type;
     val->val_cat = NSC_OFF;
-    val->val_as.sym.off = off;
-    val->val_as.sym.len = len;
+    val->val_as.sym.off = ca->ca_off;
+    val->val_as.sym.len = ca->ca_len;
     val->val_as.sym.idx = idx;
+    val->val_as.sym.get = ca->ca_get;
     return nstr_exec_val(val, player->cnum, ptr, NSC_NOTYPE);
 }
 
@@ -175,7 +173,7 @@ xdflds(struct castr ca[], void *ptr)
        n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
        j = 0;
        do {
-           xdeval(&val, ca[i].ca_type, ptr, ca[i].ca_off, j, ca[i].ca_len);
+           xdeval(&val, &ca[i], ptr, j);
            sep = xdprval(&val, sep);
        } while (++j < n);
     }
@@ -337,62 +335,7 @@ xdmeta(int type)
     return RET_OK;
 }
 
-/*
- * Dump configkeys[], return RET_OK.
- * If META, dump meta-data rather than data.
- */
-static int
-xdver(int meta)
-{
-    static struct castr vers_ca = {
-       "version", 0, NSC_STRINGY, sizeof(PACKAGE_STRING), EF_BAD, 0
-    };
-    struct keymatch *kp;
-    char *sep;
-    int n;
-    struct castr ca;
-    struct valstr val;
-
-    xdhdr("version", meta);
-
-    if (meta) {
-       n = 0;
-       xdflds(mdchr_ca, &vers_ca);
-       pr("\n");
-       n++;
-       for (kp = configkeys; kp->km_key; ++kp) {
-           if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL)) {
-               ca.ca_type = kp->km_type;
-               ca.ca_flags = 0;
-               ca.ca_len = 0;
-               ca.ca_off = 0;
-               ca.ca_name = kp->km_key;
-               ca.ca_table = EF_BAD;
-               xdflds(mdchr_ca, &ca);
-               pr("\n");
-               n++;
-           }
-       }
-       xdftr(n);
-       return RET_OK;
-    }
-
-    xdeval(&val, vers_ca.ca_type, version, vers_ca.ca_off, 0, vers_ca.ca_len);
-    sep = xdprval(&val, "");
-    for (kp = configkeys; kp->km_key; ++kp) {
-       if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL)) {
-           xdeval(&val, kp->km_type, kp->km_data, 0, 0, 0);
-           sep = xdprval(&val, sep);
-       }
-    }
-    pr("\n");
-
-    xdftr(1);
-
-    return RET_OK;
-}
-
-/* Experimental extended dump command */
+/* Extended dump command */
 int
 xdump(void)
 {
@@ -412,18 +355,17 @@ xdump(void)
 
     natp = getnatp(player->cnum);
     type = isdigit(p[0]) ? atoi(p) : ef_byname(p);
-    if (type >= 0 && type < EF_MAX) {
-       if (meta)
-           return xdmeta(type);
-       else if ((EF_IS_GAME_STATE(type) || EF_IS_VIEW(type))
-                && !(natp->nat_stat == STAT_ACTIVE || player->god)) {
-           pr("Access to table %s denied\n", ef_nameof(type));
-           return RET_FAIL;
-       } else
-           return xditem(type, player->argp[2]);
-    } else if (!strncmp(p, "ver", strlen(p))) {
-       return xdver(meta);
-    }
+    if (type < 0 || type >= EF_MAX)
+       return RET_SYN;
 
-    return RET_SYN;
+    if (meta)
+       return xdmeta(type);
+    if ((EF_IS_GAME_STATE(type) || EF_IS_VIEW(type))
+       && !(natp->nat_stat == STAT_ACTIVE || player->god)) {
+       pr("Access to table %s denied\n", ef_nameof(type));
+       return RET_FAIL;
+    }
+    if (type == EF_VERSION && !player->argp[2])
+       return xditem(type, "*"); /* backward compatibility */
+    return xditem(type, player->argp[2]);
 }
index c8e699dba30a26a2ede3146a188601a98352f690..3ecaeaa0a9374eeccd005382f728396de3609ab8 100644 (file)
@@ -107,6 +107,7 @@ verify_row(int type, int row)
            val.val_as.sym.off = ca[i].ca_off;
            val.val_as.sym.len = ca[i].ca_len;
            val.val_as.sym.idx = j;
+           val.val_as.sym.get = ca[i].ca_get;
            nstr_exec_val(&val, 0, row_ref, NSC_NOTYPE);
            if (val.val_type != NSC_LONG)
                continue;
index 5366a399a100db1d7807fa1b6210e89770f3bf82..0c61c570f7f5f706cec311d1b2350e23ae85bc4a 100644 (file)
 #include "optlist.h"
 #include "prototypes.h"
 
-/* Dummy one */
-static int emp_config_dummy;
-
-/* things that can be changed */
-struct keymatch configkeys[] = {
-#define        EMP_CONFIG_C_OUTPUT
-#include "econfig-spec.h"
-#undef EMP_CONFIG_C_OUTPUT
-};
-
 static struct keymatch *keylookup(char *key, struct keymatch tbl[]);
 static int set_paths(char *);
 
index 550a6847bee4fa694c8a434582f1b7fe0b621421..ab49f84196c80f2ab0f65aa689858baef7aafe98 100644 (file)
@@ -69,6 +69,17 @@ nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
        valtype = val->val_type;
        break;
     case NSC_OFF:
+       if (val->val_as.sym.get) {
+           do {
+               ptr = val->val_as.sym.get(val, cnum, ptr);
+           } while (ptr && val->val_as.sym.get);
+           if (!ptr) {
+               valtype = val->val_type;
+               val->val_cat = NSC_VAL;
+               break;
+           }
+       }
+
        valtype = NSC_LONG;
        memb_ptr = ptr;
        memb_ptr += val->val_as.sym.off;
index 94fcbd353d9cebc7164a36e0238f470d54197a94..ddc1b2bcd2855fc3c8d9db2f5142dff3beffaf38 100644 (file)
@@ -221,3 +221,11 @@ float start_education = 0.0;
 float start_happiness = 0.0;
 float start_technology = 0.0;
 float start_research = 0.0;
+
+/* econfig keys */
+static int emp_config_dummy;
+struct keymatch configkeys[] = {
+#define        EMP_CONFIG_C_OUTPUT
+#include "econfig-spec.h"
+#undef EMP_CONFIG_C_OUTPUT
+};
index dd3da3b44a689c2df4b2fcf4644c23b0eee0e8e6..b60e2c1701874fb08e650946b19f4e42335ccfb4 100644 (file)
@@ -53,6 +53,7 @@
 #include "server.h"
 #include "trade.h"
 #include "treaty.h"
+#include "version.h"
 #include "xy.h"
 
 /* Number of elements in ARRAY.  */
@@ -102,7 +103,8 @@ struct empfile empfile[] = {
      * that can be changed by users.
      *
      * Whatever of the above can't be done here must be done in
-     * empfile_init() or empfile_fixup().
+     * empfile_init() or empfile_fixup().  Except cadef may be set in
+     * nsc_init() instead.
      */
 
     /*
@@ -187,10 +189,13 @@ struct empfile empfile[] = {
      ARRAY_TABLE(update_time, EFF_CFG)},
     /*
      * Special tables.  EF_META gets bogus size, cids and fids here.
-     * Fixed up by empfile_init().
+     * Fixed up by empfile_init().  EF_VERSION's cadef is set by
+     * nsc_init().
      */
     {EF_TABLE, "table", NULL, empfile_ca,
      ARRAY_TABLE(empfile, EFF_CFG)},
+    {EF_VERSION, "version", NULL, NULL,
+     sizeof(PACKAGE_STRING), 0, version, 0, 0, 1, 1, -1, NULL, NULL},
     {EF_META, "meta", NULL, mdchr_ca,
      PTR_CACHE(mdchr_ca, EFF_CFG)},
 
index c1b2971fc35711d17bce397f780a23479295d322..84f0dc64d53200488856f4081cefe5523ec02073 100644 (file)
 
 #include <config.h>
 
-#include <stddef.h>
+#include <stdlib.h>
 #include "empobj.h"
 #include "file.h"
+#include "optlist.h"
 #include "nsc.h"
 #include "product.h"
 
+static void *nsc_ver(struct valstr *, natid, void *);
+
 /* Ugly hack to improve legibility by avoid long lines */
 #define fldoff(fld) offsetof(CURSTR, fld)
 #define empobjoff(fld) offsetof(struct empobj, fld)
@@ -51,9 +54,9 @@
 #define NSC_IELT(name, pfx, sfx, base, itype)  \
     {sizeof(sfx) == 1 ? name : pfx sfx,                \
      ((base) + (itype)*sizeof(unsigned short)),        \
-     NSC_SHORT, 0, EF_BAD, 0}
+     NSC_SHORT, 0, NULL, EF_BAD, 0}
 
-#define NSC_IVEC(base, sfx)            \
+#define NSC_IVEC(base, sfx)                    \
 NSC_IELT("civil", "c", sfx, base, I_CIVIL),    \
 NSC_IELT("milit", "m", sfx, base, I_MILIT),    \
 NSC_IELT("shell", "s", sfx, base, I_SHELL),    \
@@ -71,410 +74,443 @@ NSC_IELT("rad", "r", sfx, base, I_RAD)
 
 struct castr ichr_ca[] = {
 #define CURSTR struct ichrstr
-    {"uid", fldoff(i_uid), NSC_SITYPE(i_type), 0, EF_ITEM, 0},
-    {"name", fldoff(i_name), NSC_STRING, 0, EF_BAD, 0},
-    {"mnem", fldoff(i_mnem), NSC_STRINGY, 1, EF_BAD, NSC_CONST},
-    {"value", fldoff(i_value), NSC_INT, 0, EF_BAD, 0},
-    {"sell", fldoff(i_sell), NSC_INT, 0, EF_BAD, 0},
-    {"lbs", fldoff(i_lbs), NSC_INT, 0, EF_BAD, 0},
-    {"pkg", fldoff(i_pkg), NSC_INT, NUMPKG, EF_BAD, 0},
-    {"melt_denom", fldoff(i_melt_denom), NSC_INT, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(i_uid), NSC_SITYPE(i_type), 0, NULL, EF_ITEM, 0},
+    {"name", fldoff(i_name), NSC_STRING, 0, NULL, EF_BAD, 0},
+    {"mnem", fldoff(i_mnem), NSC_STRINGY, 1, NULL, EF_BAD, NSC_CONST},
+    {"value", fldoff(i_value), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"sell", fldoff(i_sell), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"lbs", fldoff(i_lbs), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"pkg", fldoff(i_pkg), NSC_INT, NUMPKG, NULL, EF_BAD, 0},
+    {"melt_denom", fldoff(i_melt_denom), NSC_INT, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr pchr_ca[] = {
 #define CURSTR struct pchrstr
-    {"uid", fldoff(p_uid), NSC_INT, 0, EF_PRODUCT, 0},
-    {"name", fldoff(p_name), NSC_STRING, 0, EF_BAD, 0},
-    {"sname", fldoff(p_sname), NSC_STRING, 0, EF_BAD, NSC_CONST},
-    {"ctype", fldoff(p_ctype), NSC_SITYPE(i_type), MAXPRCON, EF_ITEM, 0},
-    {"camt", fldoff(p_camt), NSC_USHORT, MAXPRCON, EF_BAD, 0},
-    {"type", fldoff(p_type), NSC_SITYPE(i_type), 0, EF_ITEM, 0},
-    {"level", fldoff(p_level), NSC_INT, 0, EF_LEVEL, 0},
-    {"cost", fldoff(p_cost), NSC_INT, 0, EF_BAD, 0},
-    {"nrndx", fldoff(p_nrndx), NSC_INT, 0, EF_RESOURCES, 0},
-    {"nrdep", fldoff(p_nrdep), NSC_INT, 0, EF_BAD, 0},
-    {"nlndx", fldoff(p_nlndx), NSC_INT, 0, EF_LEVEL, 0},
-    {"nlmin", fldoff(p_nlmin), NSC_INT, 0, EF_BAD, 0},
-    {"nllag", fldoff(p_nllag), NSC_INT, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(p_uid), NSC_INT, 0, NULL, EF_PRODUCT, 0},
+    {"name", fldoff(p_name), NSC_STRING, 0, NULL, EF_BAD, 0},
+    {"sname", fldoff(p_sname), NSC_STRING, 0, NULL, EF_BAD, NSC_CONST},
+    {"ctype", fldoff(p_ctype), NSC_SITYPE(i_type), MAXPRCON, NULL,
+     EF_ITEM, 0},
+    {"camt", fldoff(p_camt), NSC_USHORT, MAXPRCON, NULL, EF_BAD, 0},
+    {"type", fldoff(p_type), NSC_SITYPE(i_type), 0, NULL, EF_ITEM, 0},
+    {"level", fldoff(p_level), NSC_INT, 0, NULL, EF_LEVEL, 0},
+    {"cost", fldoff(p_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"nrndx", fldoff(p_nrndx), NSC_INT, 0, NULL, EF_RESOURCES, 0},
+    {"nrdep", fldoff(p_nrdep), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"nlndx", fldoff(p_nlndx), NSC_INT, 0, NULL, EF_LEVEL, 0},
+    {"nlmin", fldoff(p_nlmin), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"nllag", fldoff(p_nllag), NSC_INT, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr sect_ca[] = {
 #define CURSTR struct sctstr
     /* uid needs to be NSC_DEITY because it discloses true origin */
-    {"uid", fldoff(sct_uid), NSC_SHORT, 0, EF_SECTOR, NSC_DEITY | NSC_EXTRA},
-    {"owner", fldoff(sct_own), NSC_NATID, 0, EF_NATION, 0},
-    {"xloc", fldoff(sct_x), NSC_XCOORD, 0, EF_BAD, NSC_CONST},
-    {"yloc", fldoff(sct_y), NSC_YCOORD, 0, EF_BAD, NSC_CONST},
-    {"des", fldoff(sct_type), NSC_CHAR, 0, EF_SECTOR_CHR, 0},
-    {"effic", fldoff(sct_effic), NSC_UCHAR, 0, EF_BAD, 0},
-    {"mobil", fldoff(sct_mobil), NSC_SHORT, 0, EF_BAD, 0},
-    {"loyal", fldoff(sct_loyal), NSC_UCHAR, 0, EF_BAD, NSC_DEITY},
-    {"terr", fldoff(sct_terr), NSC_UCHAR, 0, EF_BAD, 0},
-    {"terr0", fldoff(sct_terr), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"terr1", fldoff(sct_terr1), NSC_UCHAR, 0, EF_BAD, 0},
-    {"terr2", fldoff(sct_terr2), NSC_UCHAR, 0, EF_BAD, 0},
-    {"terr3", fldoff(sct_terr3), NSC_UCHAR, 0, EF_BAD, 0},
-    {"dterr", fldoff(sct_dterr), NSC_UCHAR, 0, EF_BAD, NSC_DEITY},
-    {"xdist", fldoff(sct_dist_x), NSC_XCOORD, 0, EF_BAD, 0},
-    {"ydist", fldoff(sct_dist_y), NSC_YCOORD, 0, EF_BAD, 0},
-    {"avail", fldoff(sct_avail), NSC_SHORT, 0, EF_BAD, 0},
-    {"elev", fldoff(sct_elev), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"work", fldoff(sct_work), NSC_UCHAR, 0, EF_BAD, 0},
-    {"coastal", fldoff(sct_coastal), NSC_UCHAR, 0, EF_BAD, 0},
-    {"newdes", fldoff(sct_newtype), NSC_CHAR, 0, EF_SECTOR_CHR, 0},
-    {"min", fldoff(sct_min), NSC_UCHAR, 0, EF_BAD, 0},
-    {"gold", fldoff(sct_gmin), NSC_UCHAR, 0, EF_BAD, 0},
-    {"fert", fldoff(sct_fertil), NSC_UCHAR, 0, EF_BAD, 0},
-    {"ocontent", fldoff(sct_oil), NSC_UCHAR, 0, EF_BAD, 0},
-    {"uran", fldoff(sct_uran), NSC_UCHAR, 0, EF_BAD, 0},
-    {"oldown", fldoff(sct_oldown), NSC_NATID, 0, EF_NATION, 0},
-    {"off", fldoff(sct_off), NSC_UCHAR, 0, EF_BAD, 0},
+    {"uid", fldoff(sct_uid), NSC_SHORT, 0, NULL,
+     EF_SECTOR, NSC_DEITY | NSC_EXTRA},
+    {"owner", fldoff(sct_own), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"xloc", fldoff(sct_x), NSC_XCOORD, 0, NULL, EF_BAD, NSC_CONST},
+    {"yloc", fldoff(sct_y), NSC_YCOORD, 0, NULL, EF_BAD, NSC_CONST},
+    {"des", fldoff(sct_type), NSC_CHAR, 0, NULL, EF_SECTOR_CHR, 0},
+    {"effic", fldoff(sct_effic), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"mobil", fldoff(sct_mobil), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"loyal", fldoff(sct_loyal), NSC_UCHAR, 0, NULL, EF_BAD, NSC_DEITY},
+    {"terr", fldoff(sct_terr), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"terr0", fldoff(sct_terr), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"terr1", fldoff(sct_terr1), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"terr2", fldoff(sct_terr2), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"terr3", fldoff(sct_terr3), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"dterr", fldoff(sct_dterr), NSC_UCHAR, 0, NULL, EF_BAD, NSC_DEITY},
+    {"xdist", fldoff(sct_dist_x), NSC_XCOORD, 0, NULL, EF_BAD, 0},
+    {"ydist", fldoff(sct_dist_y), NSC_YCOORD, 0, NULL, EF_BAD, 0},
+    {"avail", fldoff(sct_avail), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"elev", fldoff(sct_elev), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"work", fldoff(sct_work), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"coastal", fldoff(sct_coastal), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"newdes", fldoff(sct_newtype), NSC_CHAR, 0, NULL, EF_SECTOR_CHR, 0},
+    {"min", fldoff(sct_min), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"gold", fldoff(sct_gmin), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"fert", fldoff(sct_fertil), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"ocontent", fldoff(sct_oil), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"uran", fldoff(sct_uran), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"oldown", fldoff(sct_oldown), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"off", fldoff(sct_off), NSC_UCHAR, 0, NULL, EF_BAD, 0},
     NSC_IVEC(fldoff(sct_item), ""),
     NSC_IVEC(fldoff(sct_dist), "_dist"),
     NSC_IVEC(fldoff(sct_del), "_del"),
     /* should let old owner access mines, but can't express that: */
-    {"mines", fldoff(sct_mines), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"pstage", fldoff(sct_pstage), NSC_SHORT, 0, EF_PLAGUE_STAGES, NSC_DEITY},
-    {"ptime", fldoff(sct_ptime), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"che", fldoff(sct_che), NSC_UCHAR, 0, EF_BAD, NSC_DEITY},
-    {"che_target", fldoff(sct_che_target), NSC_NATID, 0, EF_NATION, NSC_DEITY},
-    {"fallout", fldoff(sct_fallout), NSC_USHORT, 0, EF_BAD, 0},
-    {"access", fldoff(sct_access), NSC_SHORT, 0, EF_BAD, 0},
-    {"road", fldoff(sct_road), NSC_UCHAR, 0, EF_BAD, 0},
-    {"rail", fldoff(sct_rail), NSC_UCHAR, 0, EF_BAD, 0},
-    {"dfense", fldoff(sct_defense), NSC_UCHAR, 0, EF_BAD, 0},
-    {"timestamp", fldoff(sct_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"mines", fldoff(sct_mines), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"pstage", fldoff(sct_pstage), NSC_SHORT, 0, NULL,
+     EF_PLAGUE_STAGES, NSC_DEITY},
+    {"ptime", fldoff(sct_ptime), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"che", fldoff(sct_che), NSC_UCHAR, 0, NULL, EF_BAD, NSC_DEITY},
+    {"che_target", fldoff(sct_che_target), NSC_NATID, 0, NULL,
+     EF_NATION, NSC_DEITY},
+    {"fallout", fldoff(sct_fallout), NSC_USHORT, 0, NULL, EF_BAD, 0},
+    {"access", fldoff(sct_access), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"road", fldoff(sct_road), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"rail", fldoff(sct_rail), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"dfense", fldoff(sct_defense), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(sct_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr dchr_ca[] = {
 #define CURSTR struct dchrstr
-    {"uid", fldoff(d_uid), NSC_UCHAR, 0, EF_SECTOR_CHR, 0},
-    {"name", fldoff(d_name), NSC_STRING, 0, EF_BAD, 0},
-    {"mnem", fldoff(d_mnem), NSC_STRINGY, 1, EF_BAD, NSC_CONST},
-    {"prd", fldoff(d_prd), NSC_INT, 0, EF_PRODUCT, 0},
-    {"peffic", fldoff(d_peffic), NSC_INT, 0, EF_BAD, 0},
-    {"mob0", fldoff(d_mob0), NSC_FLOAT, 0, EF_BAD, 0},
-    {"mob1", fldoff(d_mob1), NSC_FLOAT, 0, EF_BAD, 0},
-    {"nav", fldoff(d_nav), NSC_SITYPE(d_navigation), 0, EF_SECTOR_NAVIGATION, 0},
-    {"pkg", fldoff(d_pkg), NSC_SITYPE(i_packing), 0, EF_PACKING, 0},
-    {"ostr", fldoff(d_ostr), NSC_FLOAT, 0, EF_BAD, 0},
-    {"dstr", fldoff(d_dstr), NSC_FLOAT, 0, EF_BAD, 0},
-    {"value", fldoff(d_value), NSC_INT, 0, EF_BAD, 0},
-    {"cost", fldoff(d_cost), NSC_INT, 0, EF_BAD, 0},
-    {"build", fldoff(d_build), NSC_INT, 0, EF_BAD, 0},
-    {"lcms", fldoff(d_lcms), NSC_INT, 0, EF_BAD, 0},
-    {"hcms", fldoff(d_hcms), NSC_INT, 0, EF_BAD, 0},
-    {"maxpop", fldoff(d_maxpop), NSC_INT, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(d_uid), NSC_UCHAR, 0, NULL, EF_SECTOR_CHR, 0},
+    {"name", fldoff(d_name), NSC_STRING, 0, NULL, EF_BAD, 0},
+    {"mnem", fldoff(d_mnem), NSC_STRINGY, 1, NULL, EF_BAD, NSC_CONST},
+    {"prd", fldoff(d_prd), NSC_INT, 0, NULL, EF_PRODUCT, 0},
+    {"peffic", fldoff(d_peffic), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"mob0", fldoff(d_mob0), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"mob1", fldoff(d_mob1), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"nav", fldoff(d_nav), NSC_SITYPE(d_navigation), 0, NULL,
+     EF_SECTOR_NAVIGATION, 0},
+    {"pkg", fldoff(d_pkg), NSC_SITYPE(i_packing), 0, NULL, EF_PACKING, 0},
+    {"ostr", fldoff(d_ostr), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"dstr", fldoff(d_dstr), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"value", fldoff(d_value), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"cost", fldoff(d_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"build", fldoff(d_build), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"lcms", fldoff(d_lcms), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"hcms", fldoff(d_hcms), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"maxpop", fldoff(d_maxpop), NSC_INT, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 #define NSC_GENITEM(ef_type, ef_chr)                                   \
-    {"uid", empobjoff(uid),  NSC_SHORT, 0, ef_type, 0},                        \
-    {"owner", empobjoff(own),  NSC_NATID, 0, EF_NATION, 0},            \
-    {"xloc", empobjoff(x),  NSC_XCOORD, 0, EF_BAD, 0},                 \
-    {"yloc", empobjoff(y),  NSC_YCOORD, 0, EF_BAD, 0},                 \
-    {"type", empobjoff(type),  NSC_CHAR, 0, ef_chr, 0},                        \
-    {"effic", empobjoff(effic),  NSC_CHAR, 0, EF_BAD, 0},              \
-    {"mobil", empobjoff(mobil),  NSC_CHAR , 0, EF_BAD, 0},             \
-    {"off", empobjoff(off),  NSC_UCHAR , 0, EF_BAD, 0},                        \
-    {"tech", empobjoff(tech),  NSC_SHORT, 0, EF_BAD, 0},               \
-    {"group", empobjoff(group),  NSC_STRINGY, 1, EF_BAD, NSC_EXTRA},   \
-    {"opx", empobjoff(opx),  NSC_XCOORD, 0, EF_BAD, 0},                        \
-    {"opy", empobjoff(opy),  NSC_YCOORD, 0, EF_BAD, 0},                        \
-    {"mission", empobjoff(mission),  NSC_SHORT, 0, EF_MISSIONS, 0},    \
-    {"radius", empobjoff(radius),  NSC_SHORT, 0, EF_BAD, 0}
+    {"uid", empobjoff(uid),  NSC_SHORT, 0, NULL, ef_type, 0},          \
+    {"owner", empobjoff(own),  NSC_NATID, 0, NULL, EF_NATION, 0},      \
+    {"xloc", empobjoff(x),  NSC_XCOORD, 0, NULL, EF_BAD, 0},           \
+    {"yloc", empobjoff(y),  NSC_YCOORD, 0, NULL, EF_BAD, 0},           \
+    {"type", empobjoff(type),  NSC_CHAR, 0, NULL, ef_chr, 0},          \
+    {"effic", empobjoff(effic),  NSC_CHAR, 0, NULL, EF_BAD, 0},                \
+    {"mobil", empobjoff(mobil),  NSC_CHAR , 0, NULL, EF_BAD, 0},       \
+    {"off", empobjoff(off),  NSC_UCHAR , 0, NULL, EF_BAD, 0},          \
+    {"tech", empobjoff(tech),  NSC_SHORT, 0, NULL, EF_BAD, 0},         \
+    {"group", empobjoff(group),  NSC_STRINGY, 1, NULL, EF_BAD, NSC_EXTRA}, \
+    {"opx", empobjoff(opx),  NSC_XCOORD, 0, NULL, EF_BAD, 0},          \
+    {"opy", empobjoff(opy),  NSC_YCOORD, 0, NULL, EF_BAD, 0},          \
+    {"mission", empobjoff(mission),  NSC_SHORT, 0, NULL, EF_MISSIONS, 0}, \
+    {"radius", empobjoff(radius),  NSC_SHORT, 0, NULL, EF_BAD, 0}
 
 struct castr ship_ca[] = {
 #define CURSTR struct shpstr
     NSC_GENITEM(EF_SHIP, EF_SHIP_CHR),
-    {"fleet", fldoff(shp_fleet), NSC_STRINGY, 1, EF_BAD, 0},
-    {"nplane", fldoff(shp_nplane), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"nland", fldoff(shp_nland), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"xstart", fldoff(shp_destx[0]), NSC_XCOORD, 0, EF_BAD, 0},
-    {"xend", fldoff(shp_destx[1]), NSC_XCOORD, 0, EF_BAD, 0},
-    {"ystart", fldoff(shp_desty[0]), NSC_YCOORD, 0, EF_BAD, 0},
-    {"yend", fldoff(shp_desty[1]), NSC_YCOORD, 0, EF_BAD, 0},
-    {"cargostart", fldoff(shp_tstart), NSC_SITYPE(i_type), TMAX, EF_ITEM, 0},
-    {"cargoend", fldoff(shp_tend), NSC_SITYPE(i_type), TMAX, EF_ITEM, 0},
-    {"amtstart", fldoff(shp_lstart), NSC_SHORT, TMAX, EF_BAD, 0},
-    {"amtend", fldoff(shp_lend), NSC_SHORT, TMAX, EF_BAD, 0},
-    {"autonav", fldoff(shp_autonav), NSC_UCHAR, 0, EF_BAD, 0},
+    {"fleet", fldoff(shp_fleet), NSC_STRINGY, 1, NULL, EF_BAD, 0},
+    {"nplane", fldoff(shp_nplane), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"nland", fldoff(shp_nland), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"xstart", fldoff(shp_destx[0]), NSC_XCOORD, 0, NULL, EF_BAD, 0},
+    {"xend", fldoff(shp_destx[1]), NSC_XCOORD, 0, NULL, EF_BAD, 0},
+    {"ystart", fldoff(shp_desty[0]), NSC_YCOORD, 0, NULL, EF_BAD, 0},
+    {"yend", fldoff(shp_desty[1]), NSC_YCOORD, 0, NULL, EF_BAD, 0},
+    {"cargostart", fldoff(shp_tstart), NSC_SITYPE(i_type), TMAX, NULL,
+     EF_ITEM, 0},
+    {"cargoend", fldoff(shp_tend), NSC_SITYPE(i_type), TMAX, NULL,
+     EF_ITEM, 0},
+    {"amtstart", fldoff(shp_lstart), NSC_SHORT, TMAX, NULL, EF_BAD, 0},
+    {"amtend", fldoff(shp_lend), NSC_SHORT, TMAX, NULL, EF_BAD, 0},
+    {"autonav", fldoff(shp_autonav), NSC_UCHAR, 0, NULL, EF_BAD, 0},
     NSC_IVEC(fldoff(shp_item), ""),
-    {"pstage", fldoff(shp_pstage), NSC_SHORT, 0, EF_PLAGUE_STAGES, NSC_DEITY},
-    {"ptime", fldoff(shp_ptime), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"access", fldoff(shp_access), NSC_SHORT, 0, EF_BAD, 0},
-    {"timestamp", fldoff(shp_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {"mquota", fldoff(shp_mobquota), NSC_UCHAR, 0, EF_BAD, 0},
-    {"path", fldoff(shp_path), NSC_STRINGY, MAXSHPPATH, EF_BAD, 0},
-    {"follow", fldoff(shp_follow), NSC_SHORT, 0, EF_BAD, 0},
-    {"name", fldoff(shp_name), NSC_STRINGY, MAXSHPNAMLEN, EF_BAD, 0},
-    {"fuel", fldoff(shp_fuel), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nchoppers", fldoff(shp_nchoppers), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"nxlight", fldoff(shp_nxlight), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
+    {"pstage", fldoff(shp_pstage), NSC_SHORT, 0, NULL,
+     EF_PLAGUE_STAGES, NSC_DEITY},
+    {"ptime", fldoff(shp_ptime), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"access", fldoff(shp_access), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(shp_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {"mquota", fldoff(shp_mobquota), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"path", fldoff(shp_path), NSC_STRINGY, MAXSHPPATH, NULL, EF_BAD, 0},
+    {"follow", fldoff(shp_follow), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"name", fldoff(shp_name), NSC_STRINGY, MAXSHPNAMLEN, NULL,
+     EF_BAD, 0},
+    {"fuel", fldoff(shp_fuel), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nchoppers", fldoff(shp_nchoppers), NSC_UCHAR, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {"nxlight", fldoff(shp_nxlight), NSC_UCHAR, 0, NULL,
+     EF_BAD, NSC_EXTRA},
     /* should let builder access xbuilt, ybuilt, but can't express that: */
-    {"xbuilt", fldoff(shp_orig_x), NSC_XCOORD, 0, EF_BAD, NSC_DEITY},
-    {"ybuilt", fldoff(shp_orig_y), NSC_YCOORD, 0, EF_BAD, NSC_DEITY},
-    {"builder", fldoff(shp_orig_own), NSC_NATID, 0, EF_NATION, NSC_DEITY},
-    {"rflags", fldoff(shp_rflags), NSC_INT, 0, EF_RETREAT_FLAGS, NSC_BITS},
-    {"rpath", fldoff(shp_rpath), NSC_STRINGY, RET_LEN, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"xbuilt", fldoff(shp_orig_x), NSC_XCOORD, 0, NULL,
+     EF_BAD, NSC_DEITY},
+    {"ybuilt", fldoff(shp_orig_y), NSC_YCOORD, 0, NULL,
+     EF_BAD, NSC_DEITY},
+    {"builder", fldoff(shp_orig_own), NSC_NATID, 0, NULL,
+     EF_NATION, NSC_DEITY},
+    {"rflags", fldoff(shp_rflags), NSC_INT, 0, NULL,
+     EF_RETREAT_FLAGS, NSC_BITS},
+    {"rpath", fldoff(shp_rpath), NSC_STRINGY, RET_LEN, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr mchr_ca[] = {
 #define CURSTR struct mchrstr
-    {"type", fldoff(m_type), NSC_CHAR, 0, EF_SHIP_CHR, 0},
-    {"name", fldoff(m_name), NSC_STRING, 0, EF_BAD, 0},
+    {"type", fldoff(m_type), NSC_CHAR, 0, NULL, EF_SHIP_CHR, 0},
+    {"name", fldoff(m_name), NSC_STRING, 0, NULL, EF_BAD, 0},
     NSC_IVEC(fldoff(m_item), ""),
-    {"l_build", fldoff(m_lcm), NSC_INT, 0, EF_BAD, 0},
-    {"h_build", fldoff(m_hcm), NSC_INT, 0, EF_BAD, 0},
-    {"armor", fldoff(m_armor), NSC_INT, 0, EF_BAD, 0},
-    {"speed", fldoff(m_speed), NSC_INT, 0, EF_BAD, 0},
-    {"visib", fldoff(m_visib), NSC_INT, 0, EF_BAD, 0},
-    {"vrnge", fldoff(m_vrnge), NSC_INT, 0, EF_BAD, 0},
-    {"frnge", fldoff(m_frnge), NSC_INT, 0, EF_BAD, 0},
-    {"glim", fldoff(m_glim), NSC_INT, 0, EF_BAD, 0},
-    {"nxlight", fldoff(m_nxlight), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nchoppers", fldoff(m_nchoppers), NSC_UCHAR, 0, EF_BAD, 0},
-    {"fuelc", fldoff(m_fuelc), NSC_UCHAR, 0, EF_BAD, 0},
-    {"fuelu", fldoff(m_fuelu), NSC_UCHAR, 0, EF_BAD, 0},
-    {"tech", fldoff(m_tech), NSC_INT, 0, EF_BAD, 0},
-    {"cost", fldoff(m_cost), NSC_INT, 0, EF_BAD, 0},
-    {"flags", fldoff(m_flags), NSC_LONG, 0, EF_SHIP_CHR_FLAGS, NSC_BITS},
-    {"nplanes", fldoff(m_nplanes), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nland", fldoff(m_nland), NSC_UCHAR, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"l_build", fldoff(m_lcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"h_build", fldoff(m_hcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"armor", fldoff(m_armor), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"speed", fldoff(m_speed), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"visib", fldoff(m_visib), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"vrnge", fldoff(m_vrnge), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"frnge", fldoff(m_frnge), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"glim", fldoff(m_glim), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"nxlight", fldoff(m_nxlight), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nchoppers", fldoff(m_nchoppers), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"fuelc", fldoff(m_fuelc), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"fuelu", fldoff(m_fuelu), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"tech", fldoff(m_tech), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"cost", fldoff(m_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"flags", fldoff(m_flags), NSC_LONG, 0, NULL,
+     EF_SHIP_CHR_FLAGS, NSC_BITS},
+    {"nplanes", fldoff(m_nplanes), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nland", fldoff(m_nland), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr plane_ca[] = {
 #define CURSTR struct plnstr
     NSC_GENITEM(EF_PLANE, EF_PLANE_CHR),
-    {"wing", fldoff(pln_wing), NSC_STRINGY, 1, EF_BAD, 0},
-    {"range", fldoff(pln_range), NSC_UCHAR, 0, EF_BAD, 0},
-    {"ship", fldoff(pln_ship), NSC_SHORT, 0, EF_BAD, 0},
-    {"land", fldoff(pln_land), NSC_SHORT, 0, EF_BAD, 0},
-    {"att", fldoff(pln_att), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"def", fldoff(pln_def), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"harden", fldoff(pln_harden), NSC_CHAR, 0, EF_BAD, 0},
-    {"nuketype", fldoff(pln_nuketype), NSC_CHAR, 0, EF_BAD, 0},
-    {"flags", fldoff(pln_flags), NSC_CHAR, 0, EF_PLANE_FLAGS, NSC_BITS},
-    {"access", fldoff(pln_access), NSC_SHORT, 0, EF_BAD, 0},
-    {"timestamp", fldoff(pln_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {"theta", fldoff(pln_theta), NSC_FLOAT, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"wing", fldoff(pln_wing), NSC_STRINGY, 1, NULL, EF_BAD, 0},
+    {"range", fldoff(pln_range), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"ship", fldoff(pln_ship), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"land", fldoff(pln_land), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"att", fldoff(pln_att), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"def", fldoff(pln_def), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"harden", fldoff(pln_harden), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"nuketype", fldoff(pln_nuketype), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"flags", fldoff(pln_flags), NSC_CHAR, 0, NULL,
+     EF_PLANE_FLAGS, NSC_BITS},
+    {"access", fldoff(pln_access), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(pln_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {"theta", fldoff(pln_theta), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr plchr_ca[] = {
 #define CURSTR struct plchrstr
-    {"type", fldoff(pl_type), NSC_CHAR, 0, EF_PLANE_CHR, 0},
-    {"name", fldoff(pl_name), NSC_STRING, 0, EF_BAD, 0},
-    {"l_build", fldoff(pl_lcm), NSC_INT, 0, EF_BAD, 0},
-    {"h_build", fldoff(pl_hcm), NSC_INT, 0, EF_BAD, 0},
-    {"cost", fldoff(pl_cost), NSC_INT, 0, EF_BAD, 0},
-    {"tech", fldoff(pl_tech), NSC_INT, 0, EF_BAD, 0},
-    {"acc", fldoff(pl_acc), NSC_INT, 0, EF_BAD, 0},
-    {"load", fldoff(pl_load), NSC_INT, 0, EF_BAD, 0},
-    {"att", fldoff(pl_att), NSC_INT, 0, EF_BAD, 0},
-    {"def", fldoff(pl_def), NSC_INT, 0, EF_BAD, 0},
-    {"range", fldoff(pl_range), NSC_INT, 0, EF_BAD, 0},
-    {"crew", fldoff(pl_crew), NSC_INT, 0, EF_BAD, 0},
-    {"fuel", fldoff(pl_fuel), NSC_INT, 0, EF_BAD, 0},
-    {"stealth", fldoff(pl_stealth), NSC_INT, 0, EF_BAD, 0},
-    {"flags", fldoff(pl_flags), NSC_INT, 0, EF_PLANE_CHR_FLAGS, NSC_BITS},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"type", fldoff(pl_type), NSC_CHAR, 0, NULL, EF_PLANE_CHR, 0},
+    {"name", fldoff(pl_name), NSC_STRING, 0, NULL, EF_BAD, 0},
+    {"l_build", fldoff(pl_lcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"h_build", fldoff(pl_hcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"cost", fldoff(pl_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"tech", fldoff(pl_tech), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"acc", fldoff(pl_acc), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"load", fldoff(pl_load), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"att", fldoff(pl_att), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"def", fldoff(pl_def), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"range", fldoff(pl_range), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"crew", fldoff(pl_crew), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"fuel", fldoff(pl_fuel), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"stealth", fldoff(pl_stealth), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"flags", fldoff(pl_flags), NSC_INT, 0, NULL,
+     EF_PLANE_CHR_FLAGS, NSC_BITS},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr land_ca[] = {
 #define CURSTR struct lndstr
     NSC_GENITEM(EF_LAND, EF_LAND_CHR),
-    {"army", fldoff(lnd_army), NSC_STRINGY, 1, EF_BAD, 0},
-    {"ship", fldoff(lnd_ship), NSC_SHORT, 0, EF_BAD, 0},
-    {"harden", fldoff(lnd_harden), NSC_CHAR, 0, EF_BAD, 0},
-    {"retreat", fldoff(lnd_retreat), NSC_SHORT, 0, EF_BAD, 0},
-    {"fuel", fldoff(lnd_fuel), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nxlight", fldoff(lnd_nxlight), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"rflags", fldoff(lnd_rflags), NSC_INT, 0, EF_RETREAT_FLAGS, NSC_BITS},
-    {"rpath", fldoff(lnd_rpath), NSC_STRINGY, RET_LEN, EF_BAD, 0},
-    {"react", fldoff(lnd_rad_max), NSC_UCHAR, 0, EF_BAD, 0},
+    {"army", fldoff(lnd_army), NSC_STRINGY, 1, NULL, EF_BAD, 0},
+    {"ship", fldoff(lnd_ship), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"harden", fldoff(lnd_harden), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"retreat", fldoff(lnd_retreat), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"fuel", fldoff(lnd_fuel), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nxlight", fldoff(lnd_nxlight), NSC_UCHAR, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {"rflags", fldoff(lnd_rflags), NSC_INT, 0, NULL,
+     EF_RETREAT_FLAGS, NSC_BITS},
+    {"rpath", fldoff(lnd_rpath), NSC_STRINGY, RET_LEN, NULL, EF_BAD, 0},
+    {"react", fldoff(lnd_rad_max), NSC_UCHAR, 0, NULL, EF_BAD, 0},
     NSC_IVEC(fldoff(lnd_item), ""),
-    {"pstage", fldoff(lnd_pstage), NSC_SHORT, 0, EF_PLAGUE_STAGES, NSC_DEITY},
-    {"ptime", fldoff(lnd_ptime), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"land", fldoff(lnd_land), NSC_SHORT, 0, EF_BAD, 0},
-    {"nland", fldoff(lnd_nland), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"access", fldoff(lnd_access), NSC_SHORT, 0, EF_BAD, 0},
-    {"att", fldoff(lnd_att), NSC_FLOAT, 0, EF_BAD, NSC_EXTRA},
-    {"def", fldoff(lnd_def), NSC_FLOAT, 0, EF_BAD, NSC_EXTRA},
-    {"vul", fldoff(lnd_vul), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"spd", fldoff(lnd_spd), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"vis", fldoff(lnd_vis), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"spy", fldoff(lnd_spy), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"rmax", fldoff(lnd_rad), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"frg", fldoff(lnd_frg), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"acc", fldoff(lnd_acc), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"dam", fldoff(lnd_dam), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"ammo", fldoff(lnd_ammo), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"aaf", fldoff(lnd_aaf), NSC_INT, 0, EF_BAD, NSC_EXTRA},
-    {"fuelc", fldoff(lnd_fuelc), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"fuelu", fldoff(lnd_fuelu), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"maxlight", fldoff(lnd_maxlight), NSC_UCHAR, 0, EF_BAD, NSC_EXTRA},
-    {"timestamp", fldoff(lnd_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"pstage", fldoff(lnd_pstage), NSC_SHORT, 0, NULL,
+     EF_PLAGUE_STAGES, NSC_DEITY},
+    {"ptime", fldoff(lnd_ptime), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"land", fldoff(lnd_land), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"nland", fldoff(lnd_nland), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"access", fldoff(lnd_access), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"att", fldoff(lnd_att), NSC_FLOAT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"def", fldoff(lnd_def), NSC_FLOAT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"vul", fldoff(lnd_vul), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"spd", fldoff(lnd_spd), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"vis", fldoff(lnd_vis), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"spy", fldoff(lnd_spy), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"rmax", fldoff(lnd_rad), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"frg", fldoff(lnd_frg), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"acc", fldoff(lnd_acc), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"dam", fldoff(lnd_dam), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"ammo", fldoff(lnd_ammo), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"aaf", fldoff(lnd_aaf), NSC_INT, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"fuelc", fldoff(lnd_fuelc), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"fuelu", fldoff(lnd_fuelu), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
+    {"maxlight", fldoff(lnd_maxlight), NSC_UCHAR, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {"timestamp", fldoff(lnd_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr lchr_ca[] = {
 #define CURSTR struct lchrstr
-    {"type", fldoff(l_type), NSC_CHAR, 0, EF_LAND_CHR, 0},
-    {"name", fldoff(l_name), NSC_STRING, 0, EF_BAD, 0},
+    {"type", fldoff(l_type), NSC_CHAR, 0, NULL, EF_LAND_CHR, 0},
+    {"name", fldoff(l_name), NSC_STRING, 0, NULL, EF_BAD, 0},
     NSC_IVEC(fldoff(l_item), ""),
-    {"l_build", fldoff(l_lcm), NSC_INT, 0, EF_BAD, 0},
-    {"h_build", fldoff(l_hcm), NSC_INT, 0, EF_BAD, 0},
-    {"tech", fldoff(l_tech), NSC_INT, 0, EF_BAD, 0},
-    {"cost", fldoff(l_cost), NSC_INT, 0, EF_BAD, 0},
-    {"att", fldoff(l_att), NSC_FLOAT, 0, EF_BAD, 0},
-    {"def", fldoff(l_def), NSC_FLOAT, 0, EF_BAD, 0},
-    {"vul", fldoff(l_vul), NSC_INT, 0, EF_BAD, 0},
-    {"spd", fldoff(l_spd), NSC_INT, 0, EF_BAD, 0},
-    {"vis", fldoff(l_vis), NSC_INT, 0, EF_BAD, 0},
-    {"spy", fldoff(l_spy), NSC_INT, 0, EF_BAD, 0},
-    {"rmax", fldoff(l_rad), NSC_INT, 0, EF_BAD, 0},
-    {"frg", fldoff(l_frg), NSC_INT, 0, EF_BAD, 0},
-    {"acc", fldoff(l_acc), NSC_INT, 0, EF_BAD, 0},
-    {"dam", fldoff(l_dam), NSC_INT, 0, EF_BAD, 0},
-    {"ammo", fldoff(l_ammo), NSC_INT, 0, EF_BAD, 0},
-    {"aaf", fldoff(l_aaf), NSC_INT, 0, EF_BAD, 0},
-    {"fuelc", fldoff(l_fuelc), NSC_UCHAR, 0, EF_BAD, 0},
-    {"fuelu", fldoff(l_fuelu), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nxlight", fldoff(l_nxlight), NSC_UCHAR, 0, EF_BAD, 0},
-    {"nland", fldoff(l_nland), NSC_UCHAR, 0, EF_BAD, 0},
-    {"flags", fldoff(l_flags), NSC_LONG, 0, EF_LAND_CHR_FLAGS, NSC_BITS},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"l_build", fldoff(l_lcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"h_build", fldoff(l_hcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"tech", fldoff(l_tech), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"cost", fldoff(l_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"att", fldoff(l_att), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"def", fldoff(l_def), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"vul", fldoff(l_vul), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"spd", fldoff(l_spd), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"vis", fldoff(l_vis), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"spy", fldoff(l_spy), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"rmax", fldoff(l_rad), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"frg", fldoff(l_frg), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"acc", fldoff(l_acc), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"dam", fldoff(l_dam), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"ammo", fldoff(l_ammo), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"aaf", fldoff(l_aaf), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"fuelc", fldoff(l_fuelc), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"fuelu", fldoff(l_fuelu), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nxlight", fldoff(l_nxlight), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"nland", fldoff(l_nland), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"flags", fldoff(l_flags), NSC_LONG, 0, NULL,
+     EF_LAND_CHR_FLAGS, NSC_BITS},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr nuke_ca[] = {
 #define CURSTR struct nukstr
     NSC_GENITEM(EF_NUKE, EF_NUKE_CHR),
-    {"plane", fldoff(nuk_plane), NSC_SHORT, 0, EF_BAD, 0},
-    {"timestamp", fldoff(nuk_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"plane", fldoff(nuk_plane), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(nuk_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr nchr_ca[] = {
 #define CURSTR struct nchrstr
-    {"type", fldoff(n_type), NSC_CHAR, 0, EF_NUKE_CHR, 0},
-    {"name", fldoff(n_name), NSC_STRING, 0, EF_BAD, 0},
-    {"l_build", fldoff(n_lcm), NSC_INT, 0, EF_BAD, 0},
-    {"h_build", fldoff(n_hcm), NSC_INT, 0, EF_BAD, 0},
-    {"o_build", fldoff(n_oil), NSC_INT, 0, EF_BAD, 0},
-    {"r_build", fldoff(n_rad), NSC_INT, 0, EF_BAD, 0},
-    {"blast", fldoff(n_blast), NSC_INT, 0, EF_BAD, 0},
-    {"dam", fldoff(n_dam), NSC_INT, 0, EF_BAD, 0},
-    {"cost", fldoff(n_cost), NSC_INT, 0, EF_BAD, 0},
-    {"tech", fldoff(n_tech), NSC_INT, 0, EF_BAD, 0},
-    {"weight", fldoff(n_weight), NSC_INT, 0, EF_BAD, 0},
-    {"flags", fldoff(n_flags), NSC_INT, 0, EF_NUKE_CHR_FLAGS, NSC_BITS},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"type", fldoff(n_type), NSC_CHAR, 0, NULL, EF_NUKE_CHR, 0},
+    {"name", fldoff(n_name), NSC_STRING, 0, NULL, EF_BAD, 0},
+    {"l_build", fldoff(n_lcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"h_build", fldoff(n_hcm), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"o_build", fldoff(n_oil), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"r_build", fldoff(n_rad), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"blast", fldoff(n_blast), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"dam", fldoff(n_dam), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"cost", fldoff(n_cost), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"tech", fldoff(n_tech), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"weight", fldoff(n_weight), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"flags", fldoff(n_flags), NSC_INT, 0, NULL,
+     EF_NUKE_CHR_FLAGS, NSC_BITS},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr treaty_ca[] = {
 #define CURSTR struct trtstr
-    {"uid", fldoff(trt_uid), NSC_SHORT, 0, EF_TREATY, 0},
-    {"cna", fldoff(trt_cna), NSC_NATID, 0, EF_NATION, 0},
-    {"cnb", fldoff(trt_cnb), NSC_NATID, 0, EF_NATION, 0},
-    {"status", fldoff(trt_status), NSC_CHAR, 0, EF_AGREEMENT_STATUS, 0},
-    {"acond", fldoff(trt_acond), NSC_SHORT, 0, EF_TREATY_FLAGS, NSC_BITS},
-    {"bcond", fldoff(trt_bcond), NSC_SHORT, 0, EF_TREATY_FLAGS, NSC_BITS},
-    {"exp", fldoff(trt_exp), NSC_TIME, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(trt_uid), NSC_SHORT, 0, NULL, EF_TREATY, 0},
+    {"cna", fldoff(trt_cna), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"cnb", fldoff(trt_cnb), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"status", fldoff(trt_status), NSC_CHAR, 0, NULL,
+     EF_AGREEMENT_STATUS, 0},
+    {"acond", fldoff(trt_acond), NSC_SHORT, 0, NULL,
+     EF_TREATY_FLAGS, NSC_BITS},
+    {"bcond", fldoff(trt_bcond), NSC_SHORT, 0, NULL,
+     EF_TREATY_FLAGS, NSC_BITS},
+    {"exp", fldoff(trt_exp), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr loan_ca[] = {
 #define CURSTR struct lonstr
-    {"uid", fldoff(l_uid), NSC_SHORT, 0, EF_LOAN, 0},
-    {"loaner", fldoff(l_loner), NSC_NATID, 0, EF_NATION, 0},
-    {"loanee", fldoff(l_lonee), NSC_NATID, 0, EF_NATION, 0},
-    {"status", fldoff(l_status), NSC_CHAR, 0, EF_AGREEMENT_STATUS, 0},
-    {"irate", fldoff(l_irate), NSC_INT, 0, EF_BAD, 0},
-    {"ldur", fldoff(l_ldur), NSC_INT, 0, EF_BAD, 0},
-    {"amtpaid", fldoff(l_amtpaid), NSC_LONG, 0, EF_BAD, 0},
-    {"amtdue", fldoff(l_amtdue), NSC_LONG, 0, EF_BAD, 0},
-    {"lastpay", fldoff(l_lastpay), NSC_TIME, 0, EF_BAD, 0},
-    {"duedate", fldoff(l_duedate), NSC_TIME, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(l_uid), NSC_SHORT, 0, NULL, EF_LOAN, 0},
+    {"loaner", fldoff(l_loner), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"loanee", fldoff(l_lonee), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"status", fldoff(l_status), NSC_CHAR, 0, NULL,
+     EF_AGREEMENT_STATUS, 0},
+    {"irate", fldoff(l_irate), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"ldur", fldoff(l_ldur), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"amtpaid", fldoff(l_amtpaid), NSC_LONG, 0, NULL, EF_BAD, 0},
+    {"amtdue", fldoff(l_amtdue), NSC_LONG, 0, NULL, EF_BAD, 0},
+    {"lastpay", fldoff(l_lastpay), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {"duedate", fldoff(l_duedate), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr news_ca[] = {
 #define CURSTR struct nwsstr
     /* no need for uid as long as it's not referenced from other tables */
-    {"actor", fldoff(nws_ano), NSC_NATID, 0, EF_NATION, 0},
-    {"action", fldoff(nws_vrb), NSC_UCHAR, 0, EF_NEWS_CHR, 0},
-    {"victim", fldoff(nws_vno), NSC_NATID, 0, EF_NATION, 0},
-    {"times", fldoff(nws_ntm), NSC_CHAR, 0, EF_BAD, 0},
-    {"time", fldoff(nws_when), NSC_TIME, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"actor", fldoff(nws_ano), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"action", fldoff(nws_vrb), NSC_UCHAR, 0, NULL, EF_NEWS_CHR, 0},
+    {"victim", fldoff(nws_vno), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"times", fldoff(nws_ntm), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"time", fldoff(nws_when), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr lost_ca[] = {
 #define CURSTR struct loststr
    /* no need for uid as long as it's not referenced from other tables */
-    {"owner", fldoff(lost_owner), NSC_NATID, 0, EF_NATION, 0},
-    {"type", fldoff(lost_type), NSC_CHAR, 0, EF_TABLE, 0},
-    {"id", fldoff(lost_id), NSC_SHORT, 0, EF_BAD, 0},
-    {"x", fldoff(lost_x), NSC_XCOORD, 0, EF_BAD, 0},
-    {"y", fldoff(lost_y), NSC_YCOORD, 0, EF_BAD, 0},
-    {"timestamp", fldoff(lost_timestamp), NSC_TIME, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"owner", fldoff(lost_owner), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"type", fldoff(lost_type), NSC_CHAR, 0, NULL, EF_TABLE, 0},
+    {"id", fldoff(lost_id), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"x", fldoff(lost_x), NSC_XCOORD, 0, NULL, EF_BAD, 0},
+    {"y", fldoff(lost_y), NSC_YCOORD, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(lost_timestamp), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr commodity_ca[] = {
 #define CURSTR struct comstr
-    {"uid", fldoff(com_uid), NSC_SHORT, 0, EF_COMM, 0},
-    {"owner", fldoff(com_owner), NSC_NATID, 0, EF_NATION, 0},
-    {"type", fldoff(com_type), NSC_SITYPE(i_type), 0, EF_ITEM, 0},
-    {"amount", fldoff(com_amount), NSC_INT, 0, EF_BAD, 0},
-    {"price", fldoff(com_price), NSC_FLOAT, 0, EF_BAD, 0},
-    {"maxbidder", fldoff(com_maxbidder), NSC_INT, 0, EF_NATION, 0},
-    {"markettime", fldoff(com_markettime), NSC_TIME, 0, EF_BAD, 0},
+    {"uid", fldoff(com_uid), NSC_SHORT, 0, NULL, EF_COMM, 0},
+    {"owner", fldoff(com_owner), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"type", fldoff(com_type), NSC_SITYPE(i_type), 0, NULL, EF_ITEM, 0},
+    {"amount", fldoff(com_amount), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"price", fldoff(com_price), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"maxbidder", fldoff(com_maxbidder), NSC_INT, 0, NULL, EF_NATION, 0},
+    {"markettime", fldoff(com_markettime), NSC_TIME, 0, NULL, EF_BAD, 0},
     /* should let maxbidder access xbuy, ybuy, but can't express that: */
-    {"xbuy", fldoff(com_x), NSC_XCOORD, 0, EF_BAD, NSC_DEITY},
-    {"ybuy", fldoff(com_y), NSC_XCOORD, 0, EF_BAD, NSC_DEITY},
+    {"xbuy", fldoff(com_x), NSC_XCOORD, 0, NULL, EF_BAD, NSC_DEITY},
+    {"ybuy", fldoff(com_y), NSC_XCOORD, 0, NULL, EF_BAD, NSC_DEITY},
     /* should let owner access xsell, ysell, but can't express that: */
-    {"xsell", fldoff(sell_x), NSC_XCOORD, 0, EF_BAD, NSC_DEITY},
-    {"ysell", fldoff(sell_y), NSC_YCOORD, 0, EF_BAD, NSC_DEITY},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"xsell", fldoff(sell_x), NSC_XCOORD, 0, NULL, EF_BAD, NSC_DEITY},
+    {"ysell", fldoff(sell_y), NSC_YCOORD, 0, NULL, EF_BAD, NSC_DEITY},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr trade_ca[] = {
 #define CURSTR struct trdstr
-    {"uid", fldoff(trd_uid), NSC_SHORT, 0, EF_TRADE, 0},
-    {"owner", fldoff(trd_owner), NSC_NATID, 0, EF_NATION, 0},
-    {"type", fldoff(trd_type), NSC_CHAR, 0, EF_TABLE, 0},
-    {"unitid", fldoff(trd_unitid), NSC_SHORT, 0, EF_BAD, 0},
-    {"price", fldoff(trd_price), NSC_LONG, 0, EF_BAD, 0},
-    {"maxbidder", fldoff(trd_maxbidder), NSC_INT, 0, EF_NATION, 0},
-    {"markettime", fldoff(trd_markettime), NSC_TIME, 0, EF_BAD, 0},
+    {"uid", fldoff(trd_uid), NSC_SHORT, 0, NULL, EF_TRADE, 0},
+    {"owner", fldoff(trd_owner), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"type", fldoff(trd_type), NSC_CHAR, 0, NULL, EF_TABLE, 0},
+    {"unitid", fldoff(trd_unitid), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"price", fldoff(trd_price), NSC_LONG, 0, NULL, EF_BAD, 0},
+    {"maxbidder", fldoff(trd_maxbidder), NSC_INT, 0, NULL, EF_NATION, 0},
+    {"markettime", fldoff(trd_markettime), NSC_TIME, 0, NULL, EF_BAD, 0},
     /* should let maxbidder access xloc, yloc, but can't express that: */
-    {"xloc", fldoff(trd_x), NSC_XCOORD, 0, EF_BAD, NSC_DEITY},
-    {"yloc", fldoff(trd_y), NSC_YCOORD, 0, EF_BAD, NSC_DEITY},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"xloc", fldoff(trd_x), NSC_XCOORD, 0, NULL, EF_BAD, NSC_DEITY},
+    {"yloc", fldoff(trd_y), NSC_YCOORD, 0, NULL, EF_BAD, NSC_DEITY},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
@@ -490,40 +526,51 @@ struct castr cou_ca[] = {
      * happiness available, but we can't express the obfuscation
      * necessary for foreign levels.
      */
-    {"cnum", fldoff(nat_cnum), NSC_NATID, 0, EF_NATION, 0},
-    {"stat", fldoff(nat_stat), NSC_SITYPE(nat_status), 0, EF_NATION_STATUS, NSC_EXTRA},
-    {"cname", fldoff(nat_cnam), NSC_STRINGY, 20, EF_BAD, NSC_EXTRA},
-    {"passwd", fldoff(nat_pnam), NSC_STRINGY, 20, EF_BAD, NSC_DEITY | NSC_EXTRA},
-    {"ip", fldoff(nat_hostaddr), NSC_STRINGY, 32, EF_BAD, 0},
-    {"hostname", fldoff(nat_hostname), NSC_STRINGY, 512, EF_BAD, 0},
-    {"userid", fldoff(nat_userid), NSC_STRINGY, 32, EF_BAD, 0},
-    {"xcap", fldoff(nat_xcap), NSC_XCOORD, 0, EF_BAD, 0},
-    {"ycap", fldoff(nat_ycap), NSC_YCOORD, 0, EF_BAD, 0},
-    {"xorg", fldoff(nat_xorg), NSC_XCOORD, 0, EF_BAD, NSC_DEITY | NSC_EXTRA},
-    {"yorg", fldoff(nat_yorg), NSC_YCOORD, 0, EF_BAD, NSC_DEITY | NSC_EXTRA},
-    {"dayno", fldoff(nat_dayno), NSC_CHAR, 0, EF_BAD, 0},
-    {"update", fldoff(nat_update), NSC_CHAR, 0, EF_BAD, 0},
-    {"tgms", fldoff(nat_tgms), NSC_USHORT, 0, EF_BAD, 0},
-    {"ann", fldoff(nat_ann), NSC_USHORT, 0, EF_BAD, 0},
-    {"minused", fldoff(nat_minused), NSC_USHORT, 0, EF_BAD, 0},
-    {"btu", fldoff(nat_btu), NSC_SHORT, 0, EF_BAD, 0},
-    {"access", fldoff(nat_access), NSC_SHORT, 0, EF_BAD, 0},
-    {"milreserve", fldoff(nat_reserve), NSC_LONG, 0, EF_BAD, 0},
-    {"money", fldoff(nat_money), NSC_LONG, 0, EF_BAD, 0},
-    {"login", fldoff(nat_last_login), NSC_TIME, 0, EF_BAD, 0},
-    {"logout", fldoff(nat_last_logout), NSC_TIME, 0, EF_BAD, 0},
-    {"newstim", fldoff(nat_newstim), NSC_TIME, 0, EF_BAD, 0},
-    {"annotim", fldoff(nat_annotim), NSC_TIME, 0, EF_BAD, 0},
-    {"tech", fldoff(nat_level[NAT_TLEV]), NSC_FLOAT, 0, EF_BAD, 0},
-    {"research", fldoff(nat_level[NAT_RLEV]), NSC_FLOAT, 0, EF_BAD, 0},
-    {"education", fldoff(nat_level[NAT_ELEV]), NSC_FLOAT, 0, EF_BAD, 0},
-    {"happiness", fldoff(nat_level[NAT_HLEV]), NSC_FLOAT, 0, EF_BAD, 0},
-    {"relations", fldoff(nat_relate), NSC_HIDDEN, MAXNOC, EF_NATION_RELATIONS, NSC_EXTRA},
+    {"cnum", fldoff(nat_cnum), NSC_NATID, 0, NULL, EF_NATION, 0},
+    {"stat", fldoff(nat_stat), NSC_SITYPE(nat_status), 0, NULL,
+     EF_NATION_STATUS, NSC_EXTRA},
+    {"cname", fldoff(nat_cnam), NSC_STRINGY, 20, NULL, EF_BAD, NSC_EXTRA},
+    {"passwd", fldoff(nat_pnam), NSC_STRINGY, 20, NULL,
+     EF_BAD, NSC_DEITY | NSC_EXTRA},
+    {"ip", fldoff(nat_hostaddr), NSC_STRINGY, 32, NULL, EF_BAD, 0},
+    {"hostname", fldoff(nat_hostname), NSC_STRINGY, 512, NULL, EF_BAD, 0},
+    {"userid", fldoff(nat_userid), NSC_STRINGY, 32, NULL, EF_BAD, 0},
+    {"xcap", fldoff(nat_xcap), NSC_XCOORD, 0, NULL, EF_BAD, 0},
+    {"ycap", fldoff(nat_ycap), NSC_YCOORD, 0, NULL, EF_BAD, 0},
+    {"xorg", fldoff(nat_xorg), NSC_XCOORD, 0, NULL,
+     EF_BAD, NSC_DEITY | NSC_EXTRA},
+    {"yorg", fldoff(nat_yorg), NSC_YCOORD, 0, NULL,
+     EF_BAD, NSC_DEITY | NSC_EXTRA},
+    {"dayno", fldoff(nat_dayno), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"update", fldoff(nat_update), NSC_CHAR, 0, NULL, EF_BAD, 0},
+    {"tgms", fldoff(nat_tgms), NSC_USHORT, 0, NULL, EF_BAD, 0},
+    {"ann", fldoff(nat_ann), NSC_USHORT, 0, NULL, EF_BAD, 0},
+    {"minused", fldoff(nat_minused), NSC_USHORT, 0, NULL, EF_BAD, 0},
+    {"btu", fldoff(nat_btu), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"access", fldoff(nat_access), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"milreserve", fldoff(nat_reserve), NSC_LONG, 0, NULL, EF_BAD, 0},
+    {"money", fldoff(nat_money), NSC_LONG, 0, NULL, EF_BAD, 0},
+    {"login", fldoff(nat_last_login), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {"logout", fldoff(nat_last_logout), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {"newstim", fldoff(nat_newstim), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {"annotim", fldoff(nat_annotim), NSC_TIME, 0, NULL, EF_BAD, 0},
+    {"tech", fldoff(nat_level[NAT_TLEV]), NSC_FLOAT, 0, NULL, EF_BAD, 0},
+    {"research", fldoff(nat_level[NAT_RLEV]), NSC_FLOAT, 0, NULL,
+     EF_BAD, 0},
+    {"education", fldoff(nat_level[NAT_ELEV]), NSC_FLOAT, 0, NULL,
+     EF_BAD, 0},
+    {"happiness", fldoff(nat_level[NAT_HLEV]), NSC_FLOAT, 0, NULL,
+     EF_BAD, 0},
+    {"relations", fldoff(nat_relate), NSC_HIDDEN, MAXNOC, NULL,
+     EF_NATION_RELATIONS, NSC_EXTRA},
     /* mortals know there's contact (relations show), but not how strong */
-    {"contacts", fldoff(nat_contact), NSC_UCHAR, MAXNOC, EF_BAD, NSC_DEITY | NSC_EXTRA},
-    {"rejects", fldoff(nat_rejects), NSC_UCHAR, MAXNOC, EF_NATION_REJECTS, NSC_EXTRA | NSC_BITS},
-    {"flags", fldoff(nat_flags), NSC_LONG, 0, EF_NATION_FLAGS, NSC_BITS},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"contacts", fldoff(nat_contact), NSC_UCHAR, MAXNOC, NULL,
+     EF_BAD, NSC_DEITY | NSC_EXTRA},
+    {"rejects", fldoff(nat_rejects), NSC_UCHAR, MAXNOC, NULL,
+     EF_NATION_REJECTS, NSC_EXTRA | NSC_BITS},
+    {"flags", fldoff(nat_flags), NSC_LONG, 0, NULL,
+     EF_NATION_FLAGS, NSC_BITS},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
@@ -533,61 +580,65 @@ struct castr nat_ca[sizeof(cou_ca) / sizeof(*cou_ca)];
 struct castr realm_ca[] = {
 #define CURSTR struct realmstr
     /* uid is encoded in cnum, realm */
-    {"cnum", fldoff(r_cnum), NSC_NATID, 0, EF_NATION, NSC_CONST},
-    {"realm", fldoff(r_realm), NSC_USHORT, 0, EF_BAD, NSC_CONST},
-    {"xl", fldoff(r_xl), NSC_SHORT, 0, EF_BAD, 0},
-    {"xh", fldoff(r_xh), NSC_SHORT, 0, EF_BAD, 0},
-    {"yl", fldoff(r_yl), NSC_SHORT, 0, EF_BAD, 0},
-    {"yh", fldoff(r_yh), NSC_SHORT, 0, EF_BAD, 0},
-    {"timestamp", fldoff(r_timestamp), NSC_TIME, 0, EF_BAD, NSC_EXTRA},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"cnum", fldoff(r_cnum), NSC_NATID, 0, NULL, EF_NATION, NSC_CONST},
+    {"realm", fldoff(r_realm), NSC_USHORT, 0, NULL, EF_BAD, NSC_CONST},
+    {"xl", fldoff(r_xl), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"xh", fldoff(r_xh), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"yl", fldoff(r_yl), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"yh", fldoff(r_yh), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"timestamp", fldoff(r_timestamp), NSC_TIME, 0, NULL,
+     EF_BAD, NSC_EXTRA},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr game_ca[] = {
 #define CURSTR struct gamestr
     /* no need for uid */
-    {"upd_disable", fldoff(game_upd_disable), NSC_CHAR, 0, EF_BAD, 0},
-    {"turn", fldoff(game_turn), NSC_SHORT, 0, EF_BAD, 0},
-    {"tick", fldoff(game_tick), NSC_SHORT, 0, EF_BAD, NSC_DEITY},
-    {"rt", fldoff(game_rt), NSC_TIME, 0, EF_BAD, NSC_DEITY},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"upd_disable", fldoff(game_upd_disable), NSC_CHAR, 0, NULL,
+     EF_BAD, 0},
+    {"turn", fldoff(game_turn), NSC_SHORT, 0, NULL, EF_BAD, 0},
+    {"tick", fldoff(game_tick), NSC_SHORT, 0, NULL, EF_BAD, NSC_DEITY},
+    {"rt", fldoff(game_rt), NSC_TIME, 0, NULL, EF_BAD, NSC_DEITY},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr intrchr_ca[] = {
 #define CURSTR struct sctintrins
     /* no need for uid as long as it's not referenced from other tables */
-    {"name", fldoff(in_name), NSC_STRING, 0, EF_BAD, NSC_CONST},
-    {"lcms", fldoff(in_lcms), NSC_UCHAR, 0, EF_BAD, 0},
-    {"hcms", fldoff(in_hcms), NSC_UCHAR, 0, EF_BAD, 0},
-    {"dcost", fldoff(in_dcost), NSC_UCHAR, 0, EF_BAD, 0},
-    {"mcost", fldoff(in_mcost), NSC_UCHAR, 0, EF_BAD, 0},
-    {"enable", fldoff(in_enable), NSC_UCHAR, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"name", fldoff(in_name), NSC_STRING, 0, NULL, EF_BAD, NSC_CONST},
+    {"lcms", fldoff(in_lcms), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"hcms", fldoff(in_hcms), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"dcost", fldoff(in_dcost), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"mcost", fldoff(in_mcost), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {"enable", fldoff(in_enable), NSC_UCHAR, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr rpt_ca[] = {
 #define CURSTR struct rptstr
-    {"uid", fldoff(r_uid), NSC_CHAR, 0, EF_NEWS_CHR, 0},
-    {"newstory", fldoff(r_newstory), NSC_STRING, NUM_RPTS, EF_BAD, 0},
-    {"good_will", fldoff(r_good_will), NSC_INT, 0, EF_BAD, 0},
-    {"newspage", fldoff(r_newspage), NSC_INT, 0, EF_PAGE_HEADINGS, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(r_uid), NSC_CHAR, 0, NULL, EF_NEWS_CHR, 0},
+    {"newstory", fldoff(r_newstory), NSC_STRING, NUM_RPTS, NULL,
+     EF_BAD, 0},
+    {"good_will", fldoff(r_good_will), NSC_INT, 0, NULL, EF_BAD, 0},
+    {"newspage", fldoff(r_newspage), NSC_INT, 0, NULL,
+     EF_PAGE_HEADINGS, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 struct castr update_ca[] = {
-    {"time", 0, NSC_TIME, 0, EF_BAD, 0},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"time", 0, NSC_TIME, 0, NULL, EF_BAD, 0},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 };
 
 struct castr empfile_ca[] = {
 #define CURSTR struct empfile
-    {"uid", fldoff(uid), NSC_INT, 0, EF_TABLE, 0},
-    {"name", fldoff(name), NSC_STRING, 0, EF_BAD, NSC_CONST},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"uid", fldoff(uid), NSC_INT, 0, NULL, EF_TABLE, 0},
+    {"name", fldoff(name), NSC_STRING, 0, NULL, EF_BAD, NSC_CONST},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
@@ -597,9 +648,9 @@ struct castr symbol_ca[] = {
      * value is is const because it has to match what is compiled into
      * the server.  name is const because clients key on it.
      */
-    {"value", fldoff(value), NSC_INT, 0, EF_BAD, NSC_CONST},
-    {"name", fldoff(name), NSC_STRING, 0, EF_BAD, NSC_CONST},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"value", fldoff(value), NSC_INT, 0, NULL, EF_BAD, NSC_CONST},
+    {"name", fldoff(name), NSC_STRING, 0, NULL, EF_BAD, NSC_CONST},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
@@ -607,21 +658,49 @@ struct castr mdchr_ca[] = {
 #define CURSTR struct castr
     /* no need for uid */
     /* name must come first, clients may rely on it */
-    {"name", fldoff(ca_name), NSC_STRING, 0, EF_BAD, NSC_CONST},
-    {"type", fldoff(ca_type), NSC_CHAR, 0, EF_META_TYPE, NSC_CONST},
-    {"flags", fldoff(ca_flags), NSC_UCHAR, 0, EF_META_FLAGS, NSC_CONST | NSC_BITS},
-    {"len", fldoff(ca_len), NSC_USHORT, 0, EF_BAD, NSC_CONST},
-    {"table", fldoff(ca_table), NSC_INT, 0, EF_BAD, NSC_CONST},
-    {NULL, 0, NSC_NOTYPE, 0, EF_BAD, 0}
+    {"name", fldoff(ca_name), NSC_STRING, 0, NULL, EF_BAD, NSC_CONST},
+    {"type", fldoff(ca_type), NSC_CHAR, 0, NULL, EF_META_TYPE, NSC_CONST},
+    {"flags", fldoff(ca_flags), NSC_UCHAR, 0, NULL,
+     EF_META_FLAGS, NSC_CONST | NSC_BITS},
+    {"len", fldoff(ca_len), NSC_USHORT, 0, NULL, EF_BAD, NSC_CONST},
+    {"table", fldoff(ca_table), NSC_INT, 0, NULL, EF_BAD, NSC_CONST},
+    {NULL, 0, NSC_NOTYPE, 0, NULL, EF_BAD, 0}
 #undef CURSTR
 };
 
 void
 nsc_init(void)
 {
-    int i;
+    static struct castr version_ca0 = {
+       "version", 0, NSC_STRINGY, sizeof(PACKAGE_STRING), NULL, EF_BAD, 0
+    };
+    static struct castr *ca;
+    struct keymatch *kp;
+    int n, i;
     unsigned flags;
 
+    /* derive empfile[EF_VERSION].cadef from configkeys[] */
+    n = 0;
+    for (kp = configkeys; kp->km_key; ++kp) {
+       if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL))
+           n++;
+    }
+    ca = calloc(n + 2, sizeof(*ca));
+    ca[0] = version_ca0;
+    i = 1;
+    for (kp = configkeys; kp->km_key; ++kp) {
+       if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL)) {
+           ca[i].ca_type = kp->km_type;
+           ca[i].ca_off = kp - configkeys;
+           ca[i].ca_name = kp->km_key;
+           ca[i].ca_table = EF_BAD;
+           ca[i].ca_get = nsc_ver;
+           i++;
+       }
+    }
+    empfile[EF_VERSION].cadef = ca;
+
+    /* derive nat_ca[] from cou_ca[] */
     for (i = 0; cou_ca[i].ca_name; i++) {
        nat_ca[i] = cou_ca[i];
        flags = nat_ca[i].ca_flags;
@@ -633,3 +712,16 @@ nsc_init(void)
     }
     nat_ca[i] = cou_ca[i];
 }
+
+/*
+ * Virtual selectors
+ */
+
+static void *
+nsc_ver(struct valstr *val, natid cnum, void *ptr)
+{
+    struct keymatch *kp = &configkeys[val->val_as.sym.off];
+    val->val_as.sym.off = 0;
+    val->val_as.sym.get = NULL;
+    return kp->km_data;
+}
index 59607e0630d504e19809eb69c5caf1da5e03c7cf..b4fb7828b7bf5855e52ef64cd89ece113473c8df 100644 (file)
@@ -432,6 +432,7 @@ nstr_resolve_sel(struct valstr *val, struct castr *ca)
     val->val_as.sym.off = ca->ca_off;
     val->val_as.sym.len = ca->ca_len;
     val->val_as.sym.idx = 0;
+    val->val_as.sym.get = ca->ca_get;
     return val;
 }