]> git.pond.sub.org Git - empserver/commitdiff
Selector rewrite: values other than long, interpret identifiers
authorMarkus Armbruster <armbru@pond.sub.org>
Fri, 2 Apr 2004 19:02:12 +0000 (19:02 +0000)
committerMarkus Armbruster <armbru@pond.sub.org>
Fri, 2 Apr 2004 19:02:12 +0000 (19:02 +0000)
according to context, to make `lstat * ?type#spy&spy>1' work.  Closes
bug#825363, #905809, #905814 and #922968.
(nsc_type, packed_nsc_type, nsc_cat, packed_nsc_cat, nsc_flags): New.
(valstr): New.  Old code encoded values in type long, which was
somewhat hard to read and could only support signed integer values.
(nscstr): Redesign.  Use valstr.  Typed operator.
(castr): Split ca_code into ca_type, ca_flags, ca_off.  Tables
changed.
(nstr_comp, nstr_exec): Redesign and rewrite.  Callers changed.  They
used the old design incorrectly, which let players smash the stack
by supplying more than NCOND conditions.
(encode, nstr_comp_val, decode, nstr_exec_val): Rename, redesign, and
rewrite.  Callers changed.
(nstr_coerce_val): New.
(var_ca, sect_ca, ship_ca, land_ca): Checking both var_ca[] and the
object's ca complicates proper recognition of unique abbreviations.
Copy contents of var_ca[] into the ca of objects, remove var_ca[].

(surv): Reject values with category other than NSC_OFF and types that
can't be coerced to NSC_LONG.  Old code happily passed values with
category NSC_VAL to code_char().  The previous version interpreted
them correctly, but earlier versions interpreted them as NSC_OFF, then
logged `bad type in decode: 0' and evaluated them into zero.

(code_char): Used to test category NSC_VAR to decide whether to
display tens or hundreds.  NSC_VAR no longer exists.  Test type
instead.  Makes more sense anyway.

13 files changed:
include/nsc.h
src/lib/commands/rout.c
src/lib/commands/sect.c
src/lib/commands/surv.c
src/lib/commands/tend.c
src/lib/global/nsc.c
src/lib/subs/nstr.c
src/lib/subs/nxtitem.c
src/lib/subs/nxtsct.c
src/lib/subs/snxtitem.c
src/lib/subs/snxtsct.c
src/lib/update/nxtitemp.c
src/scripts/indent-emp

index 92c8584eb6585a41e9676f2fce82e5c056327c47..b5d241b6c3c17fb82b0b01549287cc29bc78b7f9 100644 (file)
  * 
  *  Known contributors to this file:
  *     Dave Pare, 1989
+ *     Markus Armbruster, 2004
  */
 
 #ifndef _NSC_H_
 #define _NSC_H_
 
+#include <stddef.h>
 #include "xy.h"
 
 #define NS_LSIZE       128
 #define NS_NCOND       16
 
-enum {                         /* masks for struct nscstr member oper */
-    NSC_OPMASK = 0x0ff,                /* operator */
-    NSC_ISNUM1 = 0x100,                /* is left operand a number? */
-    NSC_ISNUM2 = 0x200         /* is right operand a number? */
+/* Value type */
+enum nsc_type {
+    NSC_NOTYPE,
+    /* promoted types */
+    NSC_LONG,                  /* long */
+    NSC_DOUBLE,                        /* double */
+    NSC_STRING,                        /* char *, zero-terminated string */
+    NSC_TYPEID,                        /* signed char, index into chr table */
+    /* unpromoted types */
+    NSC_CHAR,                  /* signed char */
+    NSC_UCHAR,                 /* unsigned char */
+    NSC_SHORT,                 /* short */
+    NSC_USHORT,                        /* unsigned short */
+    NSC_INT,                   /* int */
+    NSC_XCOORD,                        /* coord that needs x conversion */
+    NSC_YCOORD,                        /* coord that needs y conversion */
+    NSC_TIME,                  /* time_t */
+    NSC_FLOAT                  /* float */
+};
+typedef enum nsc_type nsc_type;
+typedef char packed_nsc_type;
+
+/* Value category */
+enum nsc_cat {
+    NSC_NOCAT,
+    NSC_VAL,                   /* evaluated value */
+    NSC_OFF                    /* symbolic value: at offset in object */
+};
+typedef enum nsc_cat nsc_cat;
+typedef char packed_nsc_cat;
+
+enum {
+    NSC_DEITY = 1              /* access restricted to deity */
+};
+typedef unsigned char nsc_flags;
+
+/*
+ * Value, possibly symbolic.
+ * If type is NSC_NOTYPE, it's an error value.
+ * If category is NSC_OFF, the value is at offset val_as.off in the
+ * context object.
+ * If category is NSC_VAL, the value is in val_as, and the type is a
+ * promoted type.
+ * Some values can also be interpreted as an object type.  The values
+ * consumer chooses how to interpret it, depending on context.
+ */
+struct valstr {
+    packed_nsc_type val_type;  /* type of value */
+    packed_nsc_cat val_cat;    /* category of value */
+    signed char val_as_type;   /* value interpreted as object type */
+    union {
+       ptrdiff_t off;          /* cat NSC_OFF */
+       double dbl;             /* cat NSC_VAL, types NSC_DOUBLE */
+       char *str;              /* cat NSC_VAL, type NSC_STRING */
+       long lng;               /* cat NSC_VAL, type NSC_LONG */
+    } val_as;
 };
 
+/* Compiled condition */
 struct nscstr {
-    long fld1;                 /* first commodity or number */
-    long fld2;                 /* second commodity or number */
-    int oper;                  /* required relationship operator */
+    char operator;             /* '<', '=', '>', '#' */
+    packed_nsc_type optype;    /* operator type */
+    struct valstr lft;         /* left operand */
+    struct valstr rgt;         /* right operand */
 };
 
 struct nstr_sect {
@@ -92,57 +148,19 @@ struct nstr_item {
 #define NS_GROUP       6
 
 /*
- * codes looks like this:
- * D: is access restricted to deity?
- * T: type of member addressed by offset, if category NSC_OFF
- * C: category of value
- * V: value
- *
- * 2 2  1 1    1
- * 2 0  8 6    2    8    4    0
- * xxx xxxx xxxx xxxx xxxx xxxx
- * DTT TTCC VVVV VVVV VVVV VVVV
- */
-
-/*
- * categories
+ * Selector descriptor.
+ * Value is at offset CA_OFF in the context object.
  */
-#define NSC_VAL                (0)     /* value is plain number */
-#define NSC_VAR                (1<<16) /* value is a vtype */
-#define NSC_OFF                (2<<16) /* value is an offset */
-#define NSC_CMASK      (3<<16)
-
-/*
- * how to interpret "offset" fields
- */
-#define NSC_CHAR       (1<<18) /* offset of s_char member */
-#define NSC_UCHAR      (2<<18) /* offset of unsigned char member */
-#define NSC_SHORT      (3<<18) /* offset of short */
-#define NSC_USHORT     (4<<18) /* offset of unsigned short member */
-#define NSC_INT                (5<<18) /* offset of int member */
-#define NSC_LONG       (6<<18) /* offset of long member */
-#define NSC_XCOORD     (7<<18) /* offset of coord that needs x conversion */
-#define NSC_YCOORD     (8<<18) /* offset of coord that needs y conversion */
-#define NSC_FLOAT      (9<<18) /* offset of float member */
-#define NSC_CHARP      (10<<18) /* offset of char *member */
-#define NSC_TIME       (11<<18) /* offset of time_t member */
-#define NSC_TMASK      (15<<18)
-
-#define NSC_NATID      NSC_UCHAR /* must match natid */
-
-#define NSC_MASK       (0xffff0000)
-
-#define NSC_DEITY      (1<<22)
-
 struct castr {
-    long ca_code;              /* encoded form */
-    s_char *ca_name;           /* name used for matches */
-    u_short ca_len;            /* Used for arrays */
+    packed_nsc_type ca_type;   /* type of value */
+    nsc_flags ca_flags;
+    unsigned short ca_len;     /* non-zero: is an array; #array elements */
+    ptrdiff_t ca_off;
+    char *ca_name;
 };
 
 /* variables using the above */
 
-extern struct castr var_ca[];
 extern struct castr sect_ca[];
 extern struct castr ship_ca[];
 extern struct castr plane_ca[];
@@ -158,12 +176,10 @@ extern struct castr lost_ca[];
 extern struct castr commodity_ca[];
 
 /* src/lib/subs/nstr.c */
-extern s_char *nstr_comp(struct nscstr *, int *, int, s_char *);
-extern int encode(register s_char *, long *, int);
-
-
-extern s_char *decodep(long, void *);
-extern int decode(natid, long, void *, int);
-extern int nstr_exec(struct nscstr *, register int, void *, int);
+extern int nstr_comp(struct nscstr *np, int len, int type, char *str);
+extern char *nstr_comp_val(char *, struct valstr*, int);
+extern int nstr_coerce_val(struct valstr *, nsc_type, char *);
+extern int nstr_exec(struct nscstr *, int, void *);
+extern void nstr_exec_val(struct valstr *, natid, void *, nsc_type);
 
 #endif /* _NSC_H_ */
index b881e73c82ddfd80a5cd8a78e47ac73130a508bb..947ec5d87bd043bec36c450ac0f17012814dc699 100644 (file)
@@ -123,7 +123,7 @@ rout(void)
            continue;
        p = &map[ns.dy][ns.dx * 2];
        if ((dir = sect.sct_del[i_del] & 0x7) &&
-           nstr_exec(cond, ncond, (s_char *)&sect, EF_SECTOR))
+           nstr_exec(cond, ncond, &sect))
            memcpy(p, routech[dir][0], 3);
        p[1] = dchr[sect.sct_type].d_mnem;
     }
index a9ca1e96eab9d538829d4af3d927e20d11ee8abc..2877a31b5974c6b57fd0f420e0c80221fe79ae15 100644 (file)
@@ -111,7 +111,7 @@ sct(void)
            continue;
        ptr = &map[ns.dy][ns.dx];
        *ptr = dchr[sect.sct_type].d_mnem;
-       if (nstr_exec(cond, ncond, (s_char *)&sect, EF_SECTOR)) {
+       if (nstr_exec(cond, ncond, &sect)) {
            ++nsect;
            *ptr |= 0x80;
        }
index dd93f1a91f8f7e50cbe77c8f77b97209204b0e5e..49ebd97cfeac899113e1532a0bbf15dc83e39487 100644 (file)
@@ -31,6 +31,7 @@
  *     Dave Pare, 1986
  */
 
+#include <ctype.h>
 #include "misc.h"
 #include "player.h"
 #include "var.h"
@@ -43,7 +44,7 @@
 #include "commands.h"
 #include "optlist.h"
 
-static s_char code_char(long int coding, struct sctstr *sp);
+static char code_char(struct valstr, struct sctstr *sp);
 
 /*
  * survey type <sarg> ?cond
@@ -55,7 +56,7 @@ surv(void)
     int nsect;
     struct nstr_sect nstr;
     int y;
-    long coding;
+    struct valstr val;
     struct natstr *np;
     struct sctstr sect;
     struct range range;
@@ -72,10 +73,17 @@ surv(void)
     static s_char **map = (s_char **)0;
 
     nsect = 0;
-    if ((ptr =
-        getstarg(player->argp[1], "commodity or variable? ", buf)) == 0)
+    if ((ptr = getstarg(player->argp[1], "commodity or variable? ", buf)) == 0)
        return RET_SYN;
-    if (encode(ptr, &coding, EF_SECTOR) < 0)
+    ptr = nstr_comp_val(ptr, &val, EF_SECTOR);
+    if (!ptr)
+       return RET_SYN;
+    if (val.val_cat != NSC_OFF || nstr_coerce_val(&val, NSC_LONG, NULL) < 0) {
+       pr("Can't survey this\n");
+       return RET_SYN;
+    }
+    for (; isspace(*ptr); ++ptr) ;
+    if (*ptr)
        return RET_SYN;
     if (player->argp[2] == (s_char *)0) {
        if ((str = getstring("(sects)? ", buf)) == 0)
@@ -92,10 +100,9 @@ surv(void)
     } else if (!snxtsct(&nstr, str))
        return RET_SYN;
     if (!mapbuf)
-       mapbuf =
-           (s_char *)malloc((WORLD_Y * MAPWIDTH(1)) * sizeof(s_char));
+       mapbuf = malloc((WORLD_Y * MAPWIDTH(1)) * sizeof(s_char));
     if (!map) {
-       map = (s_char **)malloc(WORLD_Y * sizeof(s_char *));
+       map = malloc(WORLD_Y * sizeof(s_char *));
        if (map && mapbuf) {
            for (i = 0; i < WORLD_Y; i++)
                map[i] = &mapbuf[MAPWIDTH(1) * i];
@@ -120,9 +127,9 @@ surv(void)
        if (!player->owner)
            continue;
        ptr = &map[nstr.dy][nstr.dx];
-       if (nstr_exec(cond, ncond, (s_char *)&sect, EF_SECTOR)) {
+       if (nstr_exec(cond, ncond, &sect)) {
            ++nsect;
-           *ptr = 0x80 | code_char(coding, &sect);
+           *ptr = 0x80 | code_char(val, &sect);
        } else {
            *ptr = dchr[sect.sct_type].d_mnem;
        }
@@ -141,22 +148,19 @@ surv(void)
     return RET_OK;
 }
 
-static s_char
-code_char(long int coding, struct sctstr *sp)
+static char
+code_char(struct valstr val, struct sctstr *sp)
 {
     int amt;
     int n;
+    int large = val.val_type != NSC_CHAR && val.val_type != NSC_UCHAR;
 
-    amt = decode(player->cnum, coding, (s_char *)sp, EF_SECTOR);
-    n = 0;
-    if ((coding & NSC_CMASK) == NSC_VAR) {
-       if (amt != 0)
-           n = (amt / 100) + 1;
-    } else if (amt != 0)
-       n = (amt / 10) + 1;
-    if (n > 11)
-       n = 11;
-    if (n < 0)
-       n = 0;
-    return " 0123456789$"[n];
+    nstr_exec_val(&val, player->cnum, sp, NSC_LONG);
+    amt = val.val_as.lng;
+    if (amt <= 0)
+       return ' ';
+    n = amt / (large ? 100 : 10);
+    if (n >= 10)
+       return '$';
+    return "0123456789"[n];
 }
index 31800f0a554a467e4b6ced9ecf5ad68e699ceccd..db3618fedb391e0b2dd871a0c59352395e0a57db 100644 (file)
@@ -268,7 +268,7 @@ tend_nxtitem(struct nstr_item *np, caddr_t ptr)
        }
        if (selected && np->ncond) {
            /* nstr_exec is expensive, so we do it last */
-           if (!nstr_exec(np->cond, np->ncond, ptr, np->type))
+           if (!nstr_exec(np->cond, np->ncond, ptr))
                selected = 0;
        }
     } while (!selected);
index 211edc5aaecc00d5e5df8031f719004434b9d8b1..33fb5cc558b95268727b644b1204185d11793206 100644 (file)
  *
  *  ---
  *
- *  nscglb.c: Empire selection global structures
+ *  nsc.c: Empire selection global structures
  * 
  *  Known contributors to this file:
+ *     Markus Armbruster, 2004
  *  
  */
 
 #include "commodity.h"
 #include "lost.h"
 
-struct castr var_ca[] = {
-    {NSC_VAR | V_CIVIL, "civil", 0},
-    {NSC_VAR | V_MILIT, "milit", 0},
-    {NSC_VAR | V_SHELL, "shell", 0},
-    {NSC_VAR | V_GUN, "gun", 0},
-    {NSC_VAR | V_PETROL, "petrol", 0},
-    {NSC_VAR | V_IRON, "iron", 0},
-    {NSC_VAR | V_DUST, "dust", 0},
-    {NSC_VAR | V_BAR, "bar", 0},
-    {NSC_VAR | V_FOOD, "food", 0},
-    {NSC_VAR | V_OIL, "oil", 0},
-    {NSC_VAR | V_LCM, "lcm", 0},
-    {NSC_VAR | V_HCM, "hcm", 0},
-    {NSC_VAR | V_UW, "uw", 0},
-    {NSC_VAR | V_RAD, "rad", 0},
-    {0, 0, 0}
-};
+#define NSC_IELT(name, pfx, sfx, base, itype)          \
+{NSC_USHORT, 0, 0, ((base) + (itype)*sizeof(u_short)), \
+sizeof(sfx) == 1 ? name : pfx 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),    \
+NSC_IELT("gun", "g", sfx, base, I_GUN),                \
+NSC_IELT("petrol", "p", sfx, base, I_PETROL),  \
+NSC_IELT("iron", "i", sfx, base, I_IRON),      \
+NSC_IELT("dust", "d", sfx, base, I_DUST),      \
+NSC_IELT("bar", "b", sfx, base, I_BAR),                \
+NSC_IELT("food", "f", sfx, base, I_FOOD),      \
+NSC_IELT("oil", "o", sfx, base, I_OIL),                \
+NSC_IELT("lcm", "l", sfx, base, I_LCM),                \
+NSC_IELT("hcm", "h", sfx, base, I_HCM),                \
+NSC_IELT("uw", "u", sfx, base, I_UW),          \
+NSC_IELT("rad", "r", sfx, base, I_RAD)
 
 struct castr sect_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_own), "owner", 0},
-    {NSC_XCOORD | NSC_OFF | fldoff(sctstr, sct_x), "xloc", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(sctstr, sct_y), "yloc", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_type), "des", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_effic), "effic", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(sctstr, sct_mobil), "mobil", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_terr), "terr", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_terr), "terr0", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_terr1), "terr1", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_terr2), "terr2", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_terr3), "terr3", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_work), "work", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_coastal), "coastal", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_newtype), "newdes", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_min), "min", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_gmin), "gold", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_fertil), "fert", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_oil), "ocontent", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_uran), "uran", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_oldown), "oldown", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_off), "off", 0},
-    {NSC_XCOORD | NSC_OFF | fldoff(sctstr, sct_dist_x), "xdist", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(sctstr, sct_dist_y), "ydist", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(sctstr, sct_avail), "avail", 0},
-#define distoff(itype) (fldoff(sctstr, sct_dist) + (itype)*sizeof(u_short))
-    {NSC_USHORT | NSC_OFF | distoff(I_CIVIL), "c_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_MILIT), "m_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_UW), "u_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_SHELL), "s_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_GUN), "g_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_PETROL), "p_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_IRON), "i_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_DUST), "d_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_BAR), "b_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_FOOD), "f_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_OIL), "o_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_LCM), "l_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_HCM), "h_dist", 0},
-    {NSC_USHORT | NSC_OFF | distoff(I_RAD), "r_dist", 0},
-#undef distoff
-#define deloff(itype) (fldoff(sctstr, sct_del) + (itype)*sizeof(u_short))
-    {NSC_USHORT | NSC_OFF | deloff(I_CIVIL), "c_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_MILIT), "m_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_UW), "u_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_SHELL), "s_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_GUN), "g_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_PETROL), "p_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_IRON), "i_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_DUST), "d_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_BAR), "b_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_FOOD), "f_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_OIL), "o_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_LCM), "l_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_HCM), "h_del", 0},
-    {NSC_USHORT | NSC_OFF | deloff(I_RAD), "r_del", 0},
-#undef deloff
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_mines), "mines", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_pstage), "pstage", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_ptime), "ptime", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_che), "che", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_che_target), "che_target", 0},
-    {NSC_USHORT | NSC_OFF | fldoff(sctstr, sct_fallout), "fallout", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_road), "road", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_rail), "rail", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(sctstr, sct_defense), "dfense", 0},
-    {NSC_TIME | NSC_OFF | fldoff(sctstr, sct_timestamp), "timestamp", 0},
-    {0, 0, 0}
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_own), "owner"},
+    {NSC_XCOORD, 0, 0, fldoff(sctstr, sct_x), "xloc"},
+    {NSC_YCOORD, 0, 0, fldoff(sctstr, sct_y), "yloc"},
+    {NSC_TYPEID, 0, 0, fldoff(sctstr, sct_type), "des"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_effic), "effic"},
+    {NSC_SHORT, 0, 0, fldoff(sctstr, sct_mobil), "mobil"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_terr), "terr"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_terr), "terr0"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_terr1), "terr1"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_terr2), "terr2"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_terr3), "terr3"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_work), "work"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_coastal), "coastal"},
+    {NSC_TYPEID, 0, 0, fldoff(sctstr, sct_newtype), "newdes"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_min), "min"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_gmin), "gold"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_fertil), "fert"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_oil), "ocontent"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_uran), "uran"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_oldown), "oldown"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_off), "off"},
+    {NSC_XCOORD, 0, 0, fldoff(sctstr, sct_dist_x), "xdist"},
+    {NSC_YCOORD, 0, 0, fldoff(sctstr, sct_dist_y), "ydist"},
+    {NSC_SHORT, 0, 0, fldoff(sctstr, sct_avail), "avail"},
+    NSC_IVEC(fldoff(sctstr, sct_item), ""),
+    NSC_IVEC(fldoff(sctstr, sct_dist), "_dist"),
+    NSC_IVEC(fldoff(sctstr, sct_del), "_del"),
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(sctstr, sct_mines), "mines"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(sctstr, sct_pstage), "pstage"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(sctstr, sct_ptime), "ptime"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(sctstr, sct_che), "che"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(sctstr, sct_che_target), "che_target"},
+    {NSC_USHORT, 0, 0, fldoff(sctstr, sct_fallout), "fallout"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_road), "road"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_rail), "rail"},
+    {NSC_UCHAR, 0, 0, fldoff(sctstr, sct_defense), "dfense"},
+    {NSC_TIME, 0, 0, fldoff(sctstr, sct_timestamp), "timestamp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 #define NSC_GENITEM \
-{ NSC_UCHAR | NSC_OFF | fldoff(genitem, own), "owner", 0},\
-{ NSC_SHORT | NSC_OFF | fldoff(genitem, uid), "uid", 0},\
-{ NSC_XCOORD | NSC_OFF | fldoff(genitem, x), "xloc", 0},\
-{ NSC_YCOORD | NSC_OFF | fldoff(genitem, y), "yloc", 0},\
-{ NSC_UCHAR | NSC_OFF | fldoff(genitem, type), "type", 0},\
-{ NSC_UCHAR | NSC_OFF | fldoff(genitem, effic), "effic", 0},\
-{ NSC_CHAR  | NSC_OFF | fldoff(genitem, mobil), "mobil", 0},\
-{ NSC_SHORT | NSC_OFF | fldoff(genitem, tech), "tech", 0},\
-{ NSC_CHAR | NSC_OFF | fldoff(genitem, group), "group", 0},\
-{ NSC_XCOORD | NSC_OFF | fldoff(genitem, opx), "opx", 0},\
-{ NSC_YCOORD | NSC_OFF | fldoff(genitem, opy), "opy", 0},\
-{ NSC_SHORT | NSC_OFF | fldoff(genitem, mission), "mission", 0}
-
-struct castr genitem_ca[] = {
-    NSC_GENITEM,
-    {0, 0, 0}
-};
+{ NSC_UCHAR, 0, 0, fldoff(genitem, own), "owner"},     \
+{ NSC_SHORT, 0, 0, fldoff(genitem, uid), "uid"},       \
+{ NSC_XCOORD, 0, 0, fldoff(genitem, x), "xloc"},       \
+{ NSC_YCOORD, 0, 0, fldoff(genitem, y), "yloc"},       \
+{ NSC_TYPEID, 0, 0, fldoff(genitem, type), "type"},    \
+{ NSC_UCHAR, 0, 0, fldoff(genitem, effic), "effic"},   \
+{ NSC_CHAR , 0, 0, fldoff(genitem, mobil), "mobil"},   \
+{ NSC_SHORT, 0, 0, fldoff(genitem, tech), "tech"},     \
+{ NSC_CHAR, 0, 0, fldoff(genitem, group), "group"},    \
+{ NSC_XCOORD, 0, 0, fldoff(genitem, opx), "opx"},      \
+{ NSC_YCOORD, 0, 0, fldoff(genitem, opy), "opy"},      \
+{ NSC_SHORT, 0, 0, fldoff(genitem, mission), "mission"}
 
 struct castr ship_ca[] = {
     NSC_GENITEM,
-    {NSC_CHAR | NSC_OFF | fldoff(shpstr, shp_fleet), "fleet", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(shpstr, shp_nplane), "nplane", 0},
-    {NSC_TIME | NSC_OFF | fldoff(shpstr, shp_timestamp), "timestamp", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(shpstr, shp_fuel), "fuel", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(shpstr, shp_nxlight), "nxlight", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(shpstr, shp_nchoppers), "nchoppers", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(shpstr, shp_autonav), "autonav", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(shpstr, shp_pstage), "pstage", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(shpstr, shp_ptime), "ptime", 0},
-    {0, 0, 0}
+    {NSC_CHAR, 0, 0, fldoff(shpstr, shp_fleet), "fleet"},
+    {NSC_CHAR, 0, 0, fldoff(shpstr, shp_nplane), "nplane"},
+    {NSC_TIME, 0, 0, fldoff(shpstr, shp_timestamp), "timestamp"},
+    {NSC_UCHAR, 0, 0, fldoff(shpstr, shp_fuel), "fuel"},
+    {NSC_UCHAR, 0, 0, fldoff(shpstr, shp_nxlight), "nxlight"},
+    {NSC_UCHAR, 0, 0, fldoff(shpstr, shp_nchoppers), "nchoppers"},
+    {NSC_UCHAR, 0, 0, fldoff(shpstr, shp_autonav), "autonav"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(shpstr, shp_pstage), "pstage"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(shpstr, shp_ptime), "ptime"},
+    NSC_IVEC(fldoff(shpstr, shp_item), ""),
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr plane_ca[] = {
     NSC_GENITEM,
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_wing), "wing", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_range), "range", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(plnstr, pln_ship), "ship", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_att), "att", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_def), "def", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_harden), "harden", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_nuketype), "nuketype", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(plnstr, pln_flags), "flags", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(plnstr, pln_land), "land", 0},
-    {NSC_TIME | NSC_OFF | fldoff(plnstr, pln_timestamp), "timestamp", 0},
-    {0, 0, 0}
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_wing), "wing"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_range), "range"},
+    {NSC_SHORT, 0, 0, fldoff(plnstr, pln_ship), "ship"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_att), "att"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_def), "def"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_harden), "harden"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_nuketype), "nuketype"},
+    {NSC_UCHAR, 0, 0, fldoff(plnstr, pln_flags), "flags"},
+    {NSC_SHORT, 0, 0, fldoff(plnstr, pln_land), "land"},
+    {NSC_TIME, 0, 0, fldoff(plnstr, pln_timestamp), "timestamp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr land_ca[] = {
     NSC_GENITEM,
-    {NSC_CHAR | NSC_OFF | fldoff(lndstr, lnd_army), "army", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(lndstr, lnd_ship), "ship", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(lndstr, lnd_land), "land", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(lndstr, lnd_harden), "harden", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(lndstr, lnd_retreat), "retreat", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lndstr, lnd_fuel), "fuel", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lndstr, lnd_nxlight), "nxlight", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(lndstr, lnd_pstage), "pstage", 0},
-    {NSC_DEITY | NSC_USHORT | NSC_OFF | fldoff(lndstr, lnd_ptime), "ptime", 0},
-    {NSC_FLOAT | NSC_OFF | fldoff(lndstr, lnd_att), "att", 0},
-    {NSC_FLOAT | NSC_OFF | fldoff(lndstr, lnd_def), "def", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_vul), "vul", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_spd), "spd", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_vis), "vis", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_spy), "spy", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_rad), "rad", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_frg), "frg", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_acc), "acc", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_dam), "dam", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_ammo), "ammo", 0},
-    {NSC_INT | NSC_OFF | fldoff(lndstr, lnd_aaf), "aaf", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lndstr, lnd_fuelc), "fuelc", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lndstr, lnd_fuelu), "fuelu", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lndstr, lnd_maxlight), "maxlight", 0},
-    {NSC_TIME | NSC_OFF | fldoff(lndstr, lnd_timestamp), "timestamp", 0},
-    {0, 0, 0}
+    {NSC_CHAR, 0, 0, fldoff(lndstr, lnd_army), "army"},
+    {NSC_SHORT, 0, 0, fldoff(lndstr, lnd_ship), "ship"},
+    {NSC_SHORT, 0, 0, fldoff(lndstr, lnd_land), "land"},
+    {NSC_CHAR, 0, 0, fldoff(lndstr, lnd_harden), "harden"},
+    {NSC_SHORT, 0, 0, fldoff(lndstr, lnd_retreat), "retreat"},
+    {NSC_UCHAR, 0, 0, fldoff(lndstr, lnd_fuel), "fuel"},
+    {NSC_UCHAR, 0, 0, fldoff(lndstr, lnd_nxlight), "nxlight"},
+    NSC_IVEC(fldoff(lndstr, lnd_item), ""),
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(lndstr, lnd_pstage), "pstage"},
+    {NSC_USHORT, NSC_DEITY, 0, fldoff(lndstr, lnd_ptime), "ptime"},
+    {NSC_FLOAT, 0, 0, fldoff(lndstr, lnd_att), "att"},
+    {NSC_FLOAT, 0, 0, fldoff(lndstr, lnd_def), "def"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_vul), "vul"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_spd), "spd"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_vis), "vis"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_spy), "spy"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_rad), "rad"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_frg), "frg"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_acc), "acc"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_dam), "dam"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_ammo), "ammo"},
+    {NSC_INT, 0, 0, fldoff(lndstr, lnd_aaf), "aaf"},
+    {NSC_UCHAR, 0, 0, fldoff(lndstr, lnd_fuelc), "fuelc"},
+    {NSC_UCHAR, 0, 0, fldoff(lndstr, lnd_fuelu), "fuelu"},
+    {NSC_UCHAR, 0, 0, fldoff(lndstr, lnd_maxlight), "maxlight"},
+    {NSC_TIME, 0, 0, fldoff(lndstr, lnd_timestamp), "timestamp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr nuke_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(nukstr, nuk_own), "owner", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(nukstr, nuk_uid), "uid", 0},
-    {NSC_XCOORD | NSC_OFF | fldoff(nukstr, nuk_x), "xloc", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(nukstr, nuk_y), "yloc", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(nukstr, nuk_n), "number", 0},
+    {NSC_UCHAR, 0, 0, fldoff(nukstr, nuk_own), "owner"},
+    {NSC_SHORT, 0, 0, fldoff(nukstr, nuk_uid), "uid"},
+    {NSC_XCOORD, 0, 0, fldoff(nukstr, nuk_x), "xloc"},
+    {NSC_YCOORD, 0, 0, fldoff(nukstr, nuk_y), "yloc"},
+    {NSC_CHAR, 0, 0, fldoff(nukstr, nuk_n), "number"},
 #if !defined(_WIN32)
-    {NSC_CHAR | NSC_OFF | fldoff(nukstr, nuk_types[0]), "types", N_MAXNUKE},
+    {NSC_CHAR, 0, N_MAXNUKE, fldoff(nukstr, nuk_types[0]), "types"},
 #else
-    {NSC_CHAR | NSC_OFF | fldoff(nukstr, nuk_types), "types", N_MAXNUKE},
+    {NSC_CHAR, 0, N_MAXNUKE, fldoff(nukstr, nuk_types), "types"},
 #endif
-    {NSC_TIME | NSC_OFF | fldoff(nukstr, nuk_timestamp), "timestamp", 0},
-    {0, 0, 0}
+    {NSC_TIME, 0, 0, fldoff(nukstr, nuk_timestamp), "timestamp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr treaty_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(trtstr, trt_cna), "cna", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(trtstr, trt_cnb), "cnb", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(trtstr, trt_status), "status", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(trtstr, trt_acond), "acond", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(trtstr, trt_bcond), "bcond", 0},
-    {NSC_LONG | NSC_OFF | fldoff(trtstr, trt_exp), "exp", 0},
-    {0, 0, 0}
+    {NSC_UCHAR, 0, 0, fldoff(trtstr, trt_cna), "cna"},
+    {NSC_UCHAR, 0, 0, fldoff(trtstr, trt_cnb), "cnb"},
+    {NSC_UCHAR, 0, 0, fldoff(trtstr, trt_status), "status"},
+    {NSC_SHORT, 0, 0, fldoff(trtstr, trt_acond), "acond"},
+    {NSC_SHORT, 0, 0, fldoff(trtstr, trt_bcond), "bcond"},
+    {NSC_LONG, 0, 0, fldoff(trtstr, trt_exp), "exp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr loan_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(lonstr, l_loner), "loaner", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(lonstr, l_uid), "uid", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(lonstr, l_lonee), "loanee", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(lonstr, l_status), "status", 0},
-    {NSC_INT | NSC_OFF | fldoff(lonstr, l_irate), "irate", 0},
-    {NSC_INT | NSC_OFF | fldoff(lonstr, l_ldur), "ldur", 0},
-    {NSC_LONG | NSC_OFF | fldoff(lonstr, l_amtpaid), "amtpaid", 0},
-    {NSC_LONG | NSC_OFF | fldoff(lonstr, l_amtdue), "amtdue", 0},
-    {NSC_TIME | NSC_OFF | fldoff(lonstr, l_lastpay), "lastpay", 0},
-    {NSC_TIME | NSC_OFF | fldoff(lonstr, l_duedate), "duedate", 0},
-    {0, 0, 0}
+    {NSC_UCHAR, 0, 0, fldoff(lonstr, l_loner), "loaner"},
+    {NSC_SHORT, 0, 0, fldoff(lonstr, l_uid), "uid"},
+    {NSC_UCHAR, 0, 0, fldoff(lonstr, l_lonee), "loanee"},
+    {NSC_CHAR, 0, 0, fldoff(lonstr, l_status), "status"},
+    {NSC_INT, 0, 0, fldoff(lonstr, l_irate), "irate"},
+    {NSC_INT, 0, 0, fldoff(lonstr, l_ldur), "ldur"},
+    {NSC_LONG, 0, 0, fldoff(lonstr, l_amtpaid), "amtpaid"},
+    {NSC_LONG, 0, 0, fldoff(lonstr, l_amtdue), "amtdue"},
+    {NSC_TIME, 0, 0, fldoff(lonstr, l_lastpay), "lastpay"},
+    {NSC_TIME, 0, 0, fldoff(lonstr, l_duedate), "duedate"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr news_ca[] = {
-    {NSC_CHAR | NSC_OFF | fldoff(nwsstr, nws_ano), "actor", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(nwsstr, nws_vrb), "action", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(nwsstr, nws_vno), "victim", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(nwsstr, nws_ntm), "times", 0},
-    {NSC_LONG | NSC_OFF | fldoff(nwsstr, nws_when), "time", 0},
-    {0, 0, 0}
+    {NSC_CHAR, 0, 0, fldoff(nwsstr, nws_ano), "actor"},
+    {NSC_CHAR, 0, 0, fldoff(nwsstr, nws_vrb), "action"},
+    {NSC_CHAR, 0, 0, fldoff(nwsstr, nws_vno), "victim"},
+    {NSC_CHAR, 0, 0, fldoff(nwsstr, nws_ntm), "times"},
+    {NSC_LONG, 0, 0, fldoff(nwsstr, nws_when), "time"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr lost_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(loststr, lost_owner), "owner", 0},
-    {NSC_INT | NSC_OFF | fldoff(loststr, lost_uid), "uid", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(loststr, lost_type), "type", 0},
-    {NSC_XCOORD | NSC_OFF | fldoff(loststr, lost_x), "x", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(loststr, lost_y), "y", 0},
-    {NSC_TIME | NSC_OFF | fldoff(loststr, lost_timestamp), "timestamp", 0},
-    {0, 0, 0}
+    {NSC_UCHAR, 0, 0, fldoff(loststr, lost_owner), "owner"},
+    {NSC_INT, 0, 0, fldoff(loststr, lost_uid), "uid"},
+    {NSC_UCHAR, 0, 0, fldoff(loststr, lost_type), "type"},
+    {NSC_XCOORD, 0, 0, fldoff(loststr, lost_x), "x"},
+    {NSC_YCOORD, 0, 0, fldoff(loststr, lost_y), "y"},
+    {NSC_TIME, 0, 0, fldoff(loststr, lost_timestamp), "timestamp"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr commodity_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(comstr, com_owner), "owner", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(comstr, com_uid), "uid", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(comstr, com_type), "type", 0},
-    {NSC_INT | NSC_OFF | fldoff(comstr, com_amount), "amount", 0},
-    {NSC_INT | NSC_OFF | fldoff(comstr, com_maxbidder), "maxbidder", 0},
-    {NSC_TIME | NSC_OFF | fldoff(comstr, com_markettime), "markettime", 0},
+    {NSC_UCHAR, 0, 0, fldoff(comstr, com_owner), "owner"},
+    {NSC_SHORT, 0, 0, fldoff(comstr, com_uid), "uid"},
+    {NSC_UCHAR, 0, 0, fldoff(comstr, com_type), "type"},
+    {NSC_INT, 0, 0, fldoff(comstr, com_amount), "amount"},
+    {NSC_INT, 0, 0, fldoff(comstr, com_maxbidder), "maxbidder"},
+    {NSC_TIME, 0, 0, fldoff(comstr, com_markettime), "markettime"},
     /* could let maxbidder access these, but we can't express that yet: */
-    {NSC_DEITY | NSC_INT | NSC_OFF | fldoff(comstr, com_x), "xbuy", 0},
-    {NSC_DEITY | NSC_INT | NSC_OFF | fldoff(comstr, com_y), "ybuy", 0},
+    {NSC_INT, NSC_DEITY, 0, fldoff(comstr, com_x), "xbuy"},
+    {NSC_INT, NSC_DEITY, 0, fldoff(comstr, com_y), "ybuy"},
     /* could let the owner access these, but we can't express that yet: */
-    {NSC_DEITY | NSC_XCOORD | NSC_OFF | fldoff(comstr, sell_x), "xsell", 0},
-    {NSC_DEITY | NSC_YCOORD | NSC_OFF | fldoff(comstr, sell_y), "ysell", 0},
-    {NSC_DEITY | NSC_FLOAT | NSC_OFF | fldoff(comstr, com_price), "price", 0},
-    {0, 0, 0}
+    {NSC_XCOORD, NSC_DEITY, 0, fldoff(comstr, sell_x), "xsell"},
+    {NSC_YCOORD, NSC_DEITY, 0, fldoff(comstr, sell_y), "ysell"},
+    {NSC_FLOAT, NSC_DEITY, 0, fldoff(comstr, com_price), "price"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr trade_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(trdstr, trd_owner), "owner", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(trdstr, trd_uid), "uid", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(trdstr, trd_type), "type", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(trdstr, trd_unitid), "unitid", 0},
-    {NSC_LONG | NSC_OFF | fldoff(trdstr, trd_price), "price", 0},
-    {NSC_INT | NSC_OFF | fldoff(trdstr, trd_maxbidder), "maxbidder", 0},
-    {NSC_TIME | NSC_OFF | fldoff(trdstr, trd_markettime), "markettime", 0},
+    {NSC_UCHAR, 0, 0, fldoff(trdstr, trd_owner), "owner"},
+    {NSC_SHORT, 0, 0, fldoff(trdstr, trd_uid), "uid"},
+    {NSC_UCHAR, 0, 0, fldoff(trdstr, trd_type), "type"},
+    {NSC_SHORT, 0, 0, fldoff(trdstr, trd_unitid), "unitid"},
+    {NSC_LONG, 0, 0, fldoff(trdstr, trd_price), "price"},
+    {NSC_INT, 0, 0, fldoff(trdstr, trd_maxbidder), "maxbidder"},
+    {NSC_TIME, 0, 0, fldoff(trdstr, trd_markettime), "markettime"},
     /* could let the owner access these, but we can't express that yet: */
-    {NSC_DEITY | NSC_XCOORD | NSC_OFF | fldoff(trdstr, trd_x), "xloc", 0},
-    {NSC_DEITY | NSC_YCOORD | NSC_OFF | fldoff(trdstr, trd_y), "yloc", 0},
-    {0, 0, 0}
+    {NSC_XCOORD, NSC_DEITY, 0, fldoff(trdstr, trd_x), "xloc"},
+    {NSC_YCOORD, NSC_DEITY, 0, fldoff(trdstr, trd_y), "yloc"},
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
 
 struct castr nat_ca[] = {
-    {NSC_UCHAR | NSC_OFF | fldoff(natstr, nat_cnum), "cnum", 0},
+    {NSC_UCHAR, 0, 0, fldoff(natstr, nat_cnum), "cnum"},
 #if !defined(_WIN32)
-    {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_cnam[0]), "cnam", 20},
-    {NSC_DEITY | NSC_CHAR | NSC_OFF | fldoff(natstr, nat_pnam[0]), "pnam", 20},
+    {NSC_CHAR, 0, 20, fldoff(natstr, nat_cnam[0]), "cnam"},
+    {NSC_CHAR, NSC_DEITY, 20, fldoff(natstr, nat_pnam[0]), "pnam"},
 #else
-    {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_cnam), "cnam", 20},
-    {NSC_DEITY | NSC_CHAR | NSC_OFF | fldoff(natstr, nat_pnam), "pnam", 20},
+    {NSC_CHAR, 0, 20, fldoff(natstr, nat_cnam), "cnam"},
+    {NSC_CHAR, NSC_DEITY, 20, fldoff(natstr, nat_pnam), "pnam"},
 #endif
-    {NSC_XCOORD | NSC_OFF | fldoff(natstr, nat_xstart), "xstart", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(natstr, nat_ystart), "ystart", 0},
-    {NSC_XCOORD | NSC_OFF | fldoff(natstr, nat_xcap), "xcap", 0},
-    {NSC_YCOORD | NSC_OFF | fldoff(natstr, nat_ycap), "ycap", 0},
-    {NSC_DEITY | NSC_XCOORD | NSC_OFF | fldoff(natstr, nat_xorg), "xorg", 0},
-    {NSC_DEITY | NSC_YCOORD | NSC_OFF | fldoff(natstr, nat_yorg), "yorg", 0},
+    {NSC_XCOORD, 0, 0, fldoff(natstr, nat_xstart), "xstart"},
+    {NSC_YCOORD, 0, 0, fldoff(natstr, nat_ystart), "ystart"},
+    {NSC_XCOORD, 0, 0, fldoff(natstr, nat_xcap), "xcap"},
+    {NSC_YCOORD, 0, 0, fldoff(natstr, nat_ycap), "ycap"},
+    {NSC_XCOORD, NSC_DEITY, 0, fldoff(natstr, nat_xorg), "xorg"},
+    {NSC_YCOORD, NSC_DEITY, 0, fldoff(natstr, nat_yorg), "yorg"},
 #ifdef MAYBE_LATER
-    {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_stat), "stat", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_dayno), "dayno", 0},
-    {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_update), "update", 0},
-    {NSC_UCHAR | NSC_OFF | fldoff(natstr, nat_missed), "missed", 0},
+    {NSC_CHAR, 0, 0, fldoff(natstr, nat_stat), "stat"},
+    {NSC_CHAR, 0, 0, fldoff(natstr, nat_dayno), "dayno"},
+    {NSC_CHAR, 0, 0, fldoff(natstr, nat_update), "update"},
+    {NSC_UCHAR, 0, 0, fldoff(natstr, nat_missed), "missed"},
 #endif /* MAYBE_LATER */
-    {NSC_USHORT | NSC_OFF | fldoff(natstr, nat_tgms), "tgms", 0},
-    {NSC_USHORT | NSC_OFF | fldoff(natstr, nat_ann), "ann", 0},
-    {NSC_USHORT | NSC_OFF | fldoff(natstr, nat_minused), "minused", 0},
-    {NSC_SHORT | NSC_OFF | fldoff(natstr, nat_btu), "btu", 0},
-    {NSC_LONG | NSC_OFF | fldoff(natstr, nat_reserve), "reserve", 0},
-    {NSC_LONG | NSC_OFF | fldoff(natstr, nat_money), "money", 0},
+    {NSC_USHORT, 0, 0, fldoff(natstr, nat_tgms), "tgms"},
+    {NSC_USHORT, 0, 0, fldoff(natstr, nat_ann), "ann"},
+    {NSC_USHORT, 0, 0, fldoff(natstr, nat_minused), "minused"},
+    {NSC_SHORT, 0, 0, fldoff(natstr, nat_btu), "btu"},
+    {NSC_LONG, 0, 0, fldoff(natstr, nat_reserve), "reserve"},
+    {NSC_LONG, 0, 0, fldoff(natstr, nat_money), "money"},
 #ifdef MAYBE_LATER
-    {NSC_LONG | NSC_OFF | fldoff(natstr, nat_last_login), "last_login", 0},
-    {NSC_LONG | NSC_OFF | fldoff(natstr, nat_last_logout), "last_logout", 0},
-    {NSC_LONG | NSC_OFF | fldoff(natstr, nat_newstim), "newstim", 0},
+    {NSC_LONG, 0, 0, fldoff(natstr, nat_last_login), "last_login"},
+    {NSC_LONG, 0, 0, fldoff(natstr, nat_last_logout), "last_logout"},
+    {NSC_LONG, 0, 0, fldoff(natstr, nat_newstim), "newstim"},
 #endif /* MAYBE_LATER */
 #if !defined(_WIN32)
-    {NSC_FLOAT | NSC_OFF | fldoff(natstr, nat_level[0]), "level", 4},
+    {NSC_FLOAT, 0, 4, fldoff(natstr, nat_level[0]), "level"},
 #else
-    {NSC_FLOAT | NSC_OFF | fldoff(natstr, nat_level), "level", 4},
+    {NSC_FLOAT, 0, 4, fldoff(natstr, nat_level), "level"},
 #endif
-/* {NSC_SHORT | NSC_OFF | fldoff(natstr, nat_relate[0]),"relate",MAXNOC}, */
-/* {NSC_CHAR | NSC_OFF | fldoff(natstr, nat_priorities[0]),"priorities",39}, */
-/* {NSC_LONG | NSC_OFF | fldoff(natstr, nat_flags),"flags",0}, */
-    {0, 0, 0}
+/* {NSC_SHORT, 0, 0, fldoff(natstr, nat_relate[0]),"relate",MAXNOC}, */
+/* {NSC_CHAR, 0, 0, fldoff(natstr, nat_priorities[0]),"priorities",39}, */
+/* {NSC_LONG, 0, 0, fldoff(natstr, nat_flags),"flags",0}, */
+    {NSC_NOTYPE, 0, 0, 0, NULL}
 };
index 6b3da7eecbf9eed45b9ea38f9726808341d005f5..338f4b780fb54e79295e5372af2405a55b82e6cb 100644 (file)
  *  Known contributors to this file:
  *     Dave Pare, 1989
  *     Steve McClure, 1997
+ *     Markus Armbruster, 2004
  */
 
-#include <ctype.h>
-#include "struct.h"
 #include "misc.h"
-#include "var.h"
-#include "xy.h"
-#include "sect.h"
-#include "nsc.h"
-#include "nat.h"
-#include "match.h"
 #include "file.h"
-#include "player.h"
-#include "prototypes.h"
+#include "match.h"
+#include "nsc.h"
 
-static int legal_val(s_char *str, int val);
+static int nstr_promote(int valtype);
 
 /*
- * Compiles and adds "str" to the list of conditionals.
- * type is the EF typename of the item type we're selecting.
- * returns amount of "str" used by nstr_comp (i.e. how far
- * the pointer was advanced).  The last is only meaningful
- * if several conditionals are expected in one string.
+ * Compile conditions into array NP[LEN].
+ * Return number of conditions, or -1 on error.
+ * It is an error if there are more than LEN conditions.
+ * TYPE is the context type, a file type.
+ * STR is the condition string, in Empire syntax, without the leading
+ * '?'.
  */
-s_char *
-nstr_comp(struct nscstr *np, int *size, int type, s_char *str)
+int
+nstr_comp(struct nscstr *np, int len, int type, char *str)
 {
-    register s_char *bp;
-    register s_char *cp;
-    register int c;
-    s_char ident[80];
-    s_char arg[255];
-    int val;
-
-    strncpy(arg, str, sizeof(arg) - 1);
-    arg[sizeof(arg) - 1] = 0;
-    cp = arg;
-    bp = ident;
-    while ((c = *cp++) && bp < &ident[sizeof(ident) - 1]) {
-       if (c == '<' || c == '=' || c == '>' || c == '#')
+    char *cond;
+    char *tail;
+    int i;
+    struct nscstr dummy;
+    int lft_type, rgt_type;
+
+    cond = str;
+    for (i = 0; ; ++i, ++np) {
+       if (i >= len)
+           np = &dummy;
+
+       /* left operand */
+       tail = nstr_comp_val(cond, &np->lft, type);
+       if (!tail)
+           return -1;
+
+       /* operator */
+       if (*tail != '<' && *tail != '=' && *tail != '>' && *tail != '#') {
+           if (*tail)
+               pr("%s -- expected condition operator\n", cond);
+           else
+               pr("%s -- missing condition operator\n", cond);
+           return -1;
+       }
+       np->operator = *tail;
+       ++tail;
+
+       /* right operand */
+       tail = nstr_comp_val(tail, &np->rgt, type);
+       if (!tail)
+           return -1;
+
+       /* find operator type, coerce operands */
+       lft_type = nstr_promote(np->lft.val_type);
+       rgt_type = nstr_promote(np->rgt.val_type);
+       if (lft_type == NSC_TYPEID) {
+           if (!nstr_coerce_val(&np->rgt, NSC_TYPEID, str))
+               np->optype = NSC_TYPEID;
+       } else if (rgt_type == NSC_TYPEID) {
+           if (!nstr_coerce_val(&np->lft, NSC_TYPEID, str))
+               np->optype = NSC_TYPEID;
+       } else if (lft_type == NSC_STRING) {
+           if (!nstr_coerce_val(&np->rgt, NSC_STRING, str))
+               np->optype = NSC_STRING;
+       } else if (rgt_type == NSC_STRING) {
+           if (!nstr_coerce_val(&np->lft, NSC_STRING, str))
+               np->optype = NSC_STRING;
+       } else if (lft_type == NSC_DOUBLE) {
+           if (!nstr_coerce_val(&np->rgt, NSC_DOUBLE, str))
+               np->optype = NSC_DOUBLE;
+       } else if (rgt_type == NSC_DOUBLE) {
+           if (!nstr_coerce_val(&np->lft, NSC_DOUBLE, str))
+               np->optype = NSC_DOUBLE;
+       } else {
+           if (!nstr_coerce_val(&np->lft, NSC_LONG, str)
+               && !nstr_coerce_val(&np->rgt, NSC_LONG, str))
+               np->optype = NSC_LONG;
+       }
+
+       /* another condition? */
+       if (*tail == 0)
            break;
-       *bp++ = c;
-    }
-    *bp = 0;
-    if (c == 0) {
-       pr("'%s'? -- meaningless condition?\n", arg);
-       return 0;
+       if (*tail != '&') {
+           pr("%s -- expected `&'\n", cond);
+           return -1;
+       }
+       cond = tail + 1;
     }
-    np[*size].oper = c & NSC_OPMASK;
-    if ((val = encode(ident, &np[*size].fld1, type)) < 0)
-       return 0;
-    if (val == 2)
-       np[*size].oper |= NSC_ISNUM1;
-    bp = ident;
-    while ((c = *cp++) && bp < &ident[sizeof(ident) - 1]) {
-       if (c == '&')
-           break;
-       *bp++ = c;
+
+    if (i >= len) {
+       /* could just return I and let caller gripe or enlarge buffer */
+       pr("%s -- too many conditions\n", str);
+       return -1;
     }
-    *bp = 0;
-    if ((val = encode(ident, &np[*size].fld2, type)) < 0)
-       return 0;
-    if (val == 2)
-       np[*size].oper |= NSC_ISNUM2;
-    if (c == 0)
-       cp--;
-    (*size)++;
-    return str + (cp - arg);
+
+    return i + 1;
 }
 
+#define EVAL(op, lft, rgt)                     \
+    ((op) == '<' ? (lft) < (rgt)               \
+     : (op) == '=' ? (lft) == (rgt)            \
+     : (op) == '>' ? (lft) > (rgt)             \
+     : (op) == '#' ? (lft) != (rgt)            \
+     : 0)
+
 /*
- * return true if the conditions on this item
- * are all true.
+ * Evaluate compiled conditions in array NP[NCOND].
+ * Return non-zero iff they are all true.
+ * PTR points to a context object of the type that was used to compile
+ * the conditions.
  */
 int
-nstr_exec(struct nscstr *conds, register int ncond, void *ptr, int type)
+nstr_exec(struct nscstr *np, int ncond, void *ptr)
 {
-    register struct nscstr *nsc;
-    register int op;
-    register int lhs;
-    register int rhs;
-    register int oper;
-
-    for (nsc = conds; --ncond >= 0; nsc++) {
-       oper = nsc->oper;
-       if (oper & NSC_ISNUM2) {
-           rhs = nsc->fld2;
-       } else
-           rhs = decode(player->cnum, nsc->fld2, ptr, type);
+    int i, op, optype;
+    struct valstr lft, rgt;
 
-       if (oper & NSC_ISNUM1) {
-           lhs = nsc->fld1;
-       } else
-           lhs = decode(player->cnum, nsc->fld1, ptr, type);
-
-       op = oper & NSC_OPMASK;
-       if ((op == '<' && lhs >= rhs)
-           || (op == '=' && lhs != rhs)
-           || (op == '>' && lhs <= rhs)
-           || (op == '#' && lhs == rhs))
+    for (i = 0; i < ncond; ++i) {
+       op = np[i].operator;
+       optype = np[i].optype;
+       if (np[i].lft.val_cat == NSC_NOCAT || np[i].rgt.val_cat == NSC_NOCAT)
+           return 0;
+       lft = np[i].lft;
+       nstr_exec_val(&lft, player->cnum, ptr, optype);
+       rgt = np[i].rgt;
+       nstr_exec_val(&rgt, player->cnum, ptr, optype);
+       switch (optype) {
+       case NSC_TYPEID:
+       case NSC_LONG:
+           if (!EVAL(op, lft.val_as.lng, rgt.val_as.lng))
+               return 0;
+           break;
+       case NSC_DOUBLE:
+           if (!EVAL(op, lft.val_as.dbl, rgt.val_as.dbl))
+               return 0;
+           break;
+       case NSC_STRING:
+           return 0;           /* FIXME */
+       default:
+           CANT_HAPPEN("bad OPTYPE");
            return 0;
+       }
     }
+
     return 1;
 }
 
-int
-encode(register s_char *str, long int *val, int type)
+/*
+ * Compile a value in STR into VAL.
+ * Return a pointer to the first character after the value on success,
+ * NULL on error.
+ * TYPE is the context type, a file type.
+ */
+char *
+nstr_comp_val(char *str, struct valstr*val, int type)
 {
-    register int i;
+    char id[32];
+    long l;
+    double d;
+    char *tail, *tail2;
     struct castr *cap;
+    unsigned i;
+    int j;
 
-    if (str == 0) {
-       *val = 0;
-       return 0;
-    }
-    if (isdigit(*str) || ((*str == '-') && isdigit(str[1]))) {
-       *val = atoi(str);
-       return 2;
-    }
-    /*
-     * FIXME This accepts the first match found, even if there are
-     * more matches in other tables, i.e. it quietly accepts ambiguous
-     * matches (matches in multiple tables), and fails to prefer an
-     * exact match to partial match in an earlier table.
-     */
-    if ((i = typematch(str, type)) >= 0) {
-       *val = i;
-       return 1;
-    }
-    if ((cap = ef_cadef(type)) != 0) {
-       i = stmtch(str, (caddr_t)cap, fldoff(castr, ca_name),
-                  sizeof(struct castr));
-       if (i >= 0) {
-           *val = cap[i].ca_code;
-           return legal_val(str, *val);
+    val->val_type = NSC_NOTYPE;
+    val->val_cat = NSC_NOCAT;
+    val->val_as_type = -1;
+
+    if (isalpha(str[0])) {
+       /* identifier */
+       for (i = 0; isalnum(str[i]) || str[i] == '_'; ++i) {
+           if (i < sizeof(id) - 1)
+               id[i] = str[i];
        }
-       if (i == M_NOTUNIQUE) {
-           pr("%s -- ambiguous type selector\n", str);
-           return 0;
+       tail = str + i;
+       if (i < sizeof(id)) {
+           id[i] = 0;
+
+           val->val_as_type = typematch(id, type);
+
+           cap = ef_cadef(type);
+           if (cap) {
+               j = stmtch(id, cap, offsetof(struct castr, ca_name),
+                          sizeof(struct castr));
+               if (j >= 0
+                   && (!(cap[j].ca_flags & NSC_DEITY) || player->god)) {
+                   val->val_type = cap[j].ca_type;
+                   val->val_cat = NSC_OFF;
+                   val->val_as.off = cap[j].ca_off;
+               }
+           } else
+               j = M_NOTFOUND;
+       } else
+           j = M_NOTFOUND;
+
+       if (val->val_type == NSC_NOTYPE) {
+           if (val->val_as_type >= 0) {
+               val->val_type = NSC_TYPEID;
+               val->val_cat = NSC_VAL;
+               val->val_as.lng = val->val_as_type;
+           } else if (j >= 0)
+               pr("%s -- selector access denied\n", id);
+           else if (j == M_NOTUNIQUE)
+               pr("%s -- ambiguous selector name\n", id);
+           else
+               pr("%s -- unknown selector name\n", id);
        }
+
+       return val->val_type == NSC_NOTYPE ? NULL : tail;
     }
-    /*
-     * Only check for commodity selectors on objects which
-     * are allowed to have commodities.
-     */
-    if (ef_flags(type) & EFF_COM) {
-       i = stmtch(str, (caddr_t)var_ca, fldoff(castr, ca_name),
-                  sizeof(struct castr));
-       if (i >= 0) {
-           *val = var_ca[i].ca_code;
-           return legal_val(str, *val);
-       }
-       if (i == M_NOTUNIQUE) {
-           pr("%s -- ambiguous commodity selector\n", str);
-           return 0;
-       }
+
+    /* literals */
+    l = strtol(str, &tail, 0);
+    d = strtod(str, &tail2);
+    if (tail2 > tail) {
+       val->val_type = NSC_DOUBLE;
+       val->val_cat = NSC_VAL;
+       val->val_as.dbl = d;
+       return tail2;
     }
-    pr("%s -- not a valid selector\n", str);
-    return 0;
+    if (tail != str) {
+       val->val_type = NSC_LONG;
+       val->val_cat = NSC_VAL;
+       val->val_as.lng = l;
+       return tail;
+    }
+    /* FIXME NSC_STRING */
+
+    /* single character type */
+    id[0] = str[0];
+    id[1] = 0;
+    val->val_as_type = typematch(id, type);
+    if (val->val_as_type >= 0) {
+       val->val_type = NSC_TYPEID;
+       val->val_cat = NSC_VAL;
+       val->val_as.lng = val->val_as_type;
+       return str + 1;
+    }
+
+    pr("%s -- invalid value for condition\n", str);
+    return NULL;
 }
 
+/*
+ * Promote VALTYPE.
+ * If VALTYPE is an integer type, return NSC_LONG.
+ * If VALTYPE is a floating-point type, return NSC_DOUBLE.
+ * If VALTYPE is NSC_NOTYPE, NSC_STRING or NSC_TYPEID, return VALTYPE.
+ */
 static int
-legal_val(s_char *str, int val)
+nstr_promote(int valtype)
 {
-    if (val & NSC_DEITY && !player->god) {
-       pr("%s -- permission denied\n", str);
-       return -1;
+    switch (valtype) {
+    case NSC_NOTYPE:
+    case NSC_LONG:
+    case NSC_DOUBLE:
+    case NSC_STRING:
+    case NSC_TYPEID:
+       break;
+    case NSC_CHAR:
+    case NSC_UCHAR:
+    case NSC_SHORT:
+    case NSC_USHORT:
+    case NSC_INT:
+    case NSC_XCOORD:
+    case NSC_YCOORD:
+    case NSC_TIME:
+       valtype = NSC_LONG;
+       break;
+    case NSC_FLOAT:
+       valtype = NSC_DOUBLE;
+       break;
+    default:
+       CANT_HAPPEN("bad VALTYPE");
+       valtype = NSC_NOTYPE;
     }
-    return 1;
+    return valtype;
 }
 
+static int
+cond_type_mismatch(char *str)
+{
+    if (str)
+       pr("%s -- condition type mismatch\n", str);
+    return -1;
+}
+
+/*
+ * Coerce VAL to promoted value type TO.
+ * Return 0 on success, -1 on error.
+ * If VAL is evaluated, convert it, else only check.
+ * STR is the condition text to be used for error messages.  Suppress
+ * messages if it is a null pointer.
+ */
 int
-decode(natid cnum, long int code, void *addr, int type)
+nstr_coerce_val(struct valstr *val, nsc_type to, char *str)
 {
-    register int val;
-    register int nsc_code;
-    struct natstr *np;
-    long code_type = (code & NSC_TMASK);
-
-    val = (code & ~NSC_MASK) & 0xffff;
-
-    /* handle negative numbers properly */
-    /* this assumes a binary two's complement number representation */
-    if (val >= 0x8000)
-       val -= 0x10000;
-
-    nsc_code = code & NSC_CMASK;
-    if (nsc_code == NSC_VAR) {
-       u_short *item = ef_items(type, addr);
-       val = item ? item[val] : 0;
-    } else if (nsc_code == NSC_OFF) {
-       /*
-        * add offset to value
-        */
-       addr = (s_char *)addr + val;
-       switch (code_type) {
-       case NSC_TIME:
-           val = *((time_t *) addr);
+    /* FIXME get rid of promotion?  */
+    nsc_type from = nstr_promote(val->val_type);
+
+    if (from == NSC_NOTYPE)
+       return 0;
+
+    if (from != to) {
+       switch (to) {
+       case NSC_TYPEID:
+           if (val->val_as_type >= 0) {
+               val->val_cat = NSC_VAL;
+               val->val_as.lng = val->val_as_type;
+           } else
+               return cond_type_mismatch(str);
+           break;
+       case NSC_STRING:
+           return cond_type_mismatch(str); /* FIXME */
+       case NSC_DOUBLE:
+           if (from == NSC_LONG) {
+               if (val->val_cat == NSC_VAL)
+                   val->val_as.dbl = val->val_as.lng;
+           } else
+               return cond_type_mismatch(str);
            break;
+       case NSC_LONG:
+           return cond_type_mismatch(str);
+       default:
+           CANT_HAPPEN("bad TO argument");
+           to = from;
+       }
+    }
+
+    if (val->val_cat == NSC_VAL) {
+       /* coord literals don't occur, conversion not implemented */
+       CANT_HAPPEN(val->val_type == NSC_XCOORD
+                   || val->val_type == NSC_YCOORD);
+       val->val_type = to;
+    }
+
+    return 0;
+}
+
+/*
+ * Evaluate VAL.
+ * Use coordinate system of country CNUM.
+ * PTR points to a context object of the type that was used to compile
+ * the value.
+ * If WANT is not zero, coerce the value to promoted value type WANT.
+ * VAL must be coercible.  That's the case if a previous
+ * nstr_coerce_val(VAL, WANT, STR) succeeded.
+ */
+void
+nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
+{
+    char *memb_ptr;
+    nsc_type valtype = NSC_LONG;
+
+    switch (val->val_cat) {
+    default:
+       CANT_HAPPEN("Bad VAL category");
+       /* fall through */
+    case NSC_VAL:
+       valtype = val->val_type;
+       break;
+    case NSC_OFF:
+       memb_ptr = ptr;
+       memb_ptr += val->val_as.off;
+       switch (val->val_type) {
        case NSC_CHAR:
-           val = *((s_char *)addr);
+           val->val_as.lng = *(signed char *)memb_ptr;
            break;
        case NSC_UCHAR:
-           val = (int)*((unsigned char *)addr);
+           val->val_as.lng = *(unsigned char *)memb_ptr;
            break;
        case NSC_SHORT:
-           val = *((short *)addr);
+           val->val_as.lng = *(short *)memb_ptr;
            break;
        case NSC_USHORT:
-           val = *((u_short *)addr);
+           val->val_as.lng = *(unsigned short *)memb_ptr;
            break;
        case NSC_INT:
-           val = *((int *)addr);
+           val->val_as.lng = *(int *)memb_ptr;
            break;
        case NSC_LONG:
-           val = *((long *)addr);
+           val->val_as.lng = *(long *)memb_ptr;
            break;
        case NSC_XCOORD:
-           val = *((short *)addr);
-           np = getnatp(cnum);
-           val = xrel(np, val);
+           val->val_as.lng = xrel(getnatp(cnum), *(short *)memb_ptr);
            break;
        case NSC_YCOORD:
-           val = *((short *)addr);
-           np = getnatp(cnum);
-           val = yrel(np, val);
+           val->val_as.lng = yrel(getnatp(cnum), *(short *)memb_ptr);
            break;
-       default:
-           logerror("bad type in decode: %lx!\n", code & NSC_TMASK);
-           val = 0;
+       case NSC_FLOAT:
+           val->val_as.dbl = *(float *)memb_ptr;
+           valtype = NSC_DOUBLE;
+           break;
+       case NSC_DOUBLE:
+           val->val_as.dbl = *(double *)memb_ptr;
+           valtype = NSC_DOUBLE;
+           break;
+       case NSC_STRING:
+           val->val_as.str = *(char **)memb_ptr;
+           valtype = NSC_STRING;
+           break;
+       case NSC_TIME:
+           val->val_as.lng = *(time_t *)memb_ptr;
            break;
+       case NSC_TYPEID:
+           val->val_as.lng = *(signed char *)memb_ptr;
+           valtype = NSC_TYPEID;
+           break;
+       default:
+           CANT_HAPPEN("Bad VAL type");
+           val->val_as.lng = 0;
        }
     }
-    return val;
-}
 
-s_char *
-decodep(long int code, void *addr)
-{
-    addr = (char *)addr + ((code & ~NSC_MASK) & 0xffff);
+    if (want) {
+       if (valtype == want)
+           ;
+       else if (want == NSC_DOUBLE) {
+           if (valtype == NSC_LONG) {
+               valtype = want;
+               val->val_as.dbl = val->val_as.lng;
+           }
+       } else if (want == NSC_STRING)
+           ;                   /* FIXME */
+       if (CANT_HAPPEN(valtype != want)) {
+           valtype = want;
+           switch (want) {
+           case NSC_TYPEID:
+           case NSC_LONG: val->val_as.lng = 0; break;
+           case NSC_DOUBLE: val->val_as.dbl = 0.0; break;
+           case NSC_STRING: val->val_as.str = ""; break;
+           default:
+               CANT_HAPPEN("bad WANT argument");
+           }
+       }
+    }
 
-    if ((code & NSC_TMASK) == NSC_CHARP)
-       return *(s_char **)addr ? *((s_char **)addr) : (s_char *)"";
-    return addr;
+    val->val_type = valtype;
 }
index a498000fee0c9edf864580896afd95b070dabfe3..93c7b093e16f60faa1103a8e51acd4a4c0d97bda 100644 (file)
@@ -110,7 +110,7 @@ nxtitem(struct nstr_item *np, caddr_t ptr)
        }
        if (selected && np->ncond) {
            /* nstr_exec is expensive, so we do it last */
-           if (!nstr_exec(np->cond, np->ncond, ptr, np->type))
+           if (!nstr_exec(np->cond, np->ncond, ptr))
                selected = 0;
        }
     } while (!selected);
index 0de03716925dbed89a1be7ca300a486818c3e849..00f2f70cda39145e9ff35d5e60dec4dd59f0fb61 100644 (file)
@@ -74,7 +74,7 @@ nxtsct(register struct nstr_sect *np, struct sctstr *sp)
            continue;
        if (np->ncond == 0)
            return 1;
-       if (nstr_exec(np->cond, np->ncond, (caddr_t)sp, EF_SECTOR))
+       if (nstr_exec(np->cond, np->ncond, sp))
            return 1;
     }
     /*NOTREACHED*/
index 4c525cd72321787d59fc51f0d45a88e2fb174426..ca18c35efcc0ce158c3fea7124d5ba5c4bbf9db4 100644 (file)
@@ -50,7 +50,6 @@
 int
 snxtitem(register struct nstr_item *np, int type, s_char *str)
 {
-    register s_char *cp;
     struct range range;
     int list[NS_LSIZE];
     int n;
@@ -120,11 +119,10 @@ snxtitem(register struct nstr_item *np, int type, s_char *str)
     np->flags = flags;
     if (player->condarg == 0)
        return 1;
-    cp = player->condarg;
-    while ((cp = nstr_comp(np->cond, &np->ncond, type, cp)) && *cp) ;
-    if (cp == 0)
-       return 0;
-    return 1;
+    n = nstr_comp(np->cond, sizeof(np->cond) / sizeof(*np->cond), type,
+                 player->condarg);
+    np->ncond = n >= 0 ? n : 0;
+    return n >= 0;
 }
 
 void
index b369e62aa99f58723e4df7d8ce6424128a2a7b88..49ff82079e567d84c0f94081e91aaad2d0421f7b 100644 (file)
 int
 snxtsct(register struct nstr_sect *np, s_char *str)
 {
-    register s_char *cp;
     struct range range;
     coord cx, cy;
-    int dist;
+    int dist, n;
     s_char buf[1024];
     struct range wr;
 
@@ -87,11 +86,10 @@ snxtsct(register struct nstr_sect *np, s_char *str)
     }
     if (player->condarg == 0)
        return 1;
-    cp = player->condarg;
-    while ((cp = nstr_comp(np->cond, &np->ncond, EF_SECTOR, cp)) && *cp) ;
-    if (cp == 0)
-       return 0;
-    return 1;
+    n = nstr_comp(np->cond, sizeof(np->cond) / sizeof(*np->cond),
+                 EF_SECTOR, player->condarg);
+    np->ncond = n >= 0 ? n : 0;
+    return n >= 0;
 }
 
 void
index f2106122ecf04dd09bc27682a9f77aebf9609228..9825c400bd86cc86798c63ee234a9111b28828ac 100644 (file)
@@ -111,7 +111,7 @@ nxtitemp(struct nstr_item *np, int owner)
        }
        if (selected && np->ncond) {
            /* nstr_exec is expensive, so we do it last */
-           if (!nstr_exec(np->cond, np->ncond, (s_char *)gp, np->type))
+           if (!nstr_exec(np->cond, np->ncond, gp))
                selected = 0;
        }
     } while (!selected);
index b84cb6ee2027ee4872caef24c2b26f1621f20b4e..a16273fc7470907568397ceff58fb4f16eae1942 100755 (executable)
@@ -2,7 +2,7 @@
 
 # indent needs to know type names do to a proper job.
 # Type names located with grep typedef, then extracted by hand:
-types="bit_fdmask bit_mask caddr_t coord ef_fileinit emp_sig_t empth_sem_t empth_t intp iop_t iovec_t loc_Sem_t loc_Thread_t natid plate_e pointer qsort_func_t s_char stkalign_t u_char u_int u_short vf_ptr voidfunc"
+types="bit_fdmask bit_mask caddr_t coord ef_fileinit emp_sig_t empth_sem_t empth_t intp iop_t iovec_t loc_Sem_t loc_Thread_t natid nsc_cat nsc_flags nsc_type packed_nsc_cat packed_nsc_type plate_e pointer qsort_func_t s_char stkalign_t u_char u_int u_short vf_ptr voidfunc"
 
 opts="-kr -cdw -cp8 -ncs -psl -ss"
 for t in $types