]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/nstr.c
Virtual selectors
[empserver] / src / lib / subs / nstr.c
index 768ff0fc8ec369c03bf684634e6d2b0d13dc518a..b4fb7828b7bf5855e52ef64cd89ece113473c8df 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,9 @@
  *
  *  ---
  *
- *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- *  related information and legal notices. It is expected that any future
- *  projects/authors will amend these files as needed.
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
  *
  *  ---
  *
  *  Known contributors to this file:
  *     Dave Pare, 1989
  *     Steve McClure, 1997
- *     Markus Armbruster, 2004
+ *     Markus Armbruster, 2004-2006
  */
 
 #include <config.h>
 
+#include <ctype.h>
 #include <limits.h>
-#include "misc.h"
 #include "file.h"
 #include "match.h"
-#include "nsc.h"
+#include "player.h"
 #include "prototypes.h"
 
 static char *nstr_parse_val(char *, struct valstr *);
 static int nstr_match_ca(struct valstr *, struct castr *);
-static int nstr_match_val(struct valstr *, int, struct castr *, int);
+static int nstr_match_val(struct valstr *, struct castr *, int);
 static int nstr_string_ok(struct castr *ca, int idx);
 static struct valstr *nstr_resolve_sel(struct valstr *, struct castr *);
 static struct valstr *nstr_mkselval(struct valstr *, int, struct castr *);
 static struct valstr *nstr_resolve_id(struct valstr *, struct castr *, int, int);
-static int nstr_promote(int);
-
 
 /*
  * Compile conditions into array NP[LEN].
@@ -105,8 +103,8 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
         * possible.  Example: n<n for sectors could mean newdes<n or
         * n<newdes.
         */
-       lft_val = nstr_match_val(&np->lft, type, ca, rgt_caidx);
-       rgt_val = nstr_match_val(&np->rgt, type, ca, lft_caidx);
+       lft_val = nstr_match_val(&np->lft, ca, rgt_caidx);
+       rgt_val = nstr_match_val(&np->rgt, ca, lft_caidx);
        /*
         * if lft_val >= 0, then rhs names a selector and lhs names
         * one of its values.  Likewise for rgt_val.
@@ -141,13 +139,7 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
        lft_type = nstr_promote(np->lft.val_type);
        rgt_type = nstr_promote(np->rgt.val_type);
        np->optype = NSC_NOTYPE;
-       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 (lft_type == NSC_STRING) {
            if (!nstr_coerce_val(&np->rgt, NSC_STRING, str))
                np->optype = NSC_STRING;
        } else if (rgt_type == NSC_STRING) {
@@ -202,7 +194,7 @@ strnncmp(char *s1, size_t sz1, char *s2, size_t sz2)
      : (op) == '=' ? (lft) == (rgt)            \
      : (op) == '>' ? (lft) > (rgt)             \
      : (op) == '#' ? (lft) != (rgt)            \
-     : 0)
+     : (CANT_REACH(), 0))
 
 /*
  * Evaluate compiled conditions in array NP[NCOND].
@@ -226,7 +218,6 @@ nstr_exec(struct nscstr *np, int ncond, void *ptr)
        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;
@@ -242,7 +233,7 @@ nstr_exec(struct nscstr *np, int ncond, void *ptr)
                return 0;
            break;
        default:
-           CANT_HAPPEN("bad OPTYPE");
+           CANT_REACH();
            return 0;
        }
     }
@@ -253,7 +244,8 @@ nstr_exec(struct nscstr *np, int ncond, void *ptr)
 /*
  * Parse a value in STR into VAL.
  * Return a pointer to the first character after the value.
- * Value is either evaluated (but not NSC_TYPEID) or an identifier.
+ * Value is either evaluated into NSC_STRING, NSC_DOUBLE or NSC_LONG,
+ * or an identifier.
  */
 static char *
 nstr_parse_val(char *str, struct valstr *val)
@@ -271,6 +263,7 @@ nstr_parse_val(char *str, struct valstr *val)
        val->val_as.str.base = str + 1;
        val->val_as.str.maxsz = tail - (str + 1);
        if (*tail) ++tail;
+       /* FIXME else unclosed string */
        return tail;
     }
 
@@ -336,31 +329,28 @@ nstr_match_ca(struct valstr *val, struct castr *ca)
 
 /*
  * Match VAL in a selector's values, return its (non-negative) value.
- * TYPE is the context type, a file type.
- * CA is ef_cadef(TYPE).  If it is null, then IDX must be negative.
  * Match values of selector descriptor CA[IDX], provided IDX is not
- * negative.
+ * negative.  CA may be null when IDX is negative.
  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
  * several.
- * TODO: This is just a stub and works only for NSC_TYPEID.
- * Generalize: give struct castr enough info to find values, remove
- * parameter `type'.
  */
 static int
-nstr_match_val(struct valstr *val, int type, struct castr *ca, int idx)
+nstr_match_val(struct valstr *val, struct castr *ca, int idx)
 {
     char id[32];
 
     if (val->val_cat != NSC_ID || val->val_as.str.maxsz >= sizeof(id))
        return M_NOTFOUND;
 
-    if (idx < 0 || ca[idx].ca_type != NSC_TYPEID)
+    if (idx < 0 || ca[idx].ca_table == EF_BAD)
+       return M_NOTFOUND;
+    if (CANT_HAPPEN(nstr_promote(ca[idx].ca_type) != NSC_LONG))
        return M_NOTFOUND;
 
     memcpy(id, val->val_as.str.base, val->val_as.str.maxsz);
     id[val->val_as.str.maxsz] = 0;
 
-    return typematch(id, type);
+    return ef_elt_byname(ca[idx].ca_table, id);
 }
 
 /*
@@ -388,24 +378,28 @@ nstr_resolve_id(struct valstr *val, struct castr *ca, int idx, int string_ok)
     if (val->val_cat != NSC_ID)
        return val;
 
-    if (idx == M_NOTUNIQUE) {
+    if (idx == M_NOTUNIQUE && !string_ok) {
        pr("%.*s -- ambiguous name\n",
           (int)val->val_as.str.maxsz, val->val_as.str.base);
        val->val_cat = NSC_NOCAT;
        return NULL;
     }
 
+    if (idx == M_NOTFOUND && !string_ok) {
+       pr("%.*s -- unknown name\n",
+          (int)val->val_as.str.maxsz, val->val_as.str.base);
+       val->val_cat = NSC_NOCAT;
+       return NULL;
+    }
+
     if (idx < 0) {
-       CANT_HAPPEN(idx != M_NOTFOUND);
-       if (!string_ok) {
-           pr("%.*s -- unknown name\n",
-              (int)val->val_as.str.maxsz, val->val_as.str.base);
-           val->val_cat = NSC_NOCAT;
-           return NULL;
-       }
-       /* interpret unbound identifier as string */
+       CANT_HAPPEN(!string_ok);
+       /* interpret unresolvable identifier as string */
        val->val_type = NSC_STRING;
        val->val_cat = NSC_VAL;
+       /* map identifier ~ to empty string, like some commands do */
+       if (val->val_as.str.maxsz == 1 && val->val_as.str.base[0] == '~')
+           val->val_as.str.maxsz = 0;
        return val;
     }
 
@@ -438,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;
 }
 
@@ -447,7 +442,8 @@ nstr_resolve_sel(struct valstr *val, struct castr *ca)
 static struct valstr *
 nstr_mkselval(struct valstr *val, int selval, struct castr *ca)
 {
-    if (CANT_HAPPEN(ca->ca_type != NSC_TYPEID)) {
+    if (CANT_HAPPEN(nstr_promote(ca->ca_type) != NSC_LONG
+                   || ca->ca_table == EF_BAD)) {
        val->val_type = NSC_NOTYPE;
        val->val_cat = NSC_NOCAT;
        return val;
@@ -472,48 +468,9 @@ nstr_comp_val(char *str, struct valstr *val, int type)
 {
     struct castr *ca = ef_cadef(type);
     char *tail = nstr_parse_val(str, val);
-    return nstr_resolve_id(val, ca, nstr_match_ca(val, ca), 0) ? tail : 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_STRINGY, return NSC_STRING.
- * If VALTYPE is NSC_NOTYPE, NSC_STRING or NSC_TYPEID, return VALTYPE.
- */
-static int
-nstr_promote(int valtype)
-{
-    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;
-    case NSC_STRINGY:
-       valtype = NSC_STRING;
-       break;
-    default:
-       CANT_HAPPEN("bad VALTYPE");
-       valtype = NSC_NOTYPE;
-    }
-    return valtype;
+    if (!nstr_resolve_id(val, ca, nstr_match_ca(val, ca), 0))
+       return NULL;
+    return tail;
 }
 
 static int
@@ -542,8 +499,6 @@ nstr_coerce_val(struct valstr *val, nsc_type to, char *str)
 
     if (from != to) {
        switch (to) {
-       case NSC_TYPEID:
-           return cond_type_mismatch(str);
        case NSC_STRING:
            return cond_type_mismatch(str); /* FIXME implement */
        case NSC_DOUBLE:
@@ -556,141 +511,18 @@ nstr_coerce_val(struct valstr *val, nsc_type to, char *str)
        case NSC_LONG:
            return cond_type_mismatch(str);
        default:
-           CANT_HAPPEN("bad TO argument");
+           CANT_REACH();
            to = from;
        }
     }
 
     if (val->val_cat == NSC_VAL) {
-       /* coord literals don't occur, conversion not implemented */
+       /* unimplemented conversions; don't currently occur here */
        CANT_HAPPEN(val->val_type == NSC_XCOORD
-                   || val->val_type == NSC_YCOORD);
+                   || val->val_type == NSC_YCOORD
+                   || val->val_type == NSC_HIDDEN);
        val->val_type = to;
     }
 
     return 0;
 }
-
-/*
- * Evaluate VAL.
- * If VAL is symbolic, evaluate it into a promoted value type.
- * Use coordinate system of country CNUM.
- * PTR points to a context object of the type that was used to compile
- * the value.
- * Unless WANT is NSC_NOTYPE, 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;
-    int idx;
-
-    switch (val->val_cat) {
-    default:
-       CANT_HAPPEN("Bad VAL category");
-       /* fall through */
-    case NSC_VAL:
-       valtype = val->val_type;
-       break;
-    case NSC_OFF:
-       valtype = NSC_LONG;
-       memb_ptr = ptr;
-       memb_ptr += val->val_as.sym.off;
-       idx = val->val_as.sym.idx;
-       switch (val->val_type) {
-       case NSC_CHAR:
-           val->val_as.lng = ((signed char *)memb_ptr)[idx];
-           break;
-       case NSC_UCHAR:
-           val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
-           break;
-       case NSC_SHORT:
-           val->val_as.lng = ((short *)memb_ptr)[idx];
-           break;
-       case NSC_USHORT:
-           val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
-           break;
-       case NSC_INT:
-           val->val_as.lng = ((int *)memb_ptr)[idx];
-           break;
-       case NSC_LONG:
-           val->val_as.lng = ((long *)memb_ptr)[idx];
-           break;
-       case NSC_XCOORD:
-           val->val_as.lng = xrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
-           break;
-       case NSC_YCOORD:
-           val->val_as.lng = yrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
-           break;
-       case NSC_FLOAT:
-           val->val_as.dbl = ((float *)memb_ptr)[idx];
-           valtype = NSC_DOUBLE;
-           break;
-       case NSC_DOUBLE:
-           val->val_as.dbl = ((double *)memb_ptr)[idx];
-           valtype = NSC_DOUBLE;
-           break;
-       case NSC_STRINGY:
-           CANT_HAPPEN(idx);
-           val->val_as.str.maxsz = val->val_as.sym.len;
-           val->val_as.str.base = (char *)memb_ptr;
-           valtype = NSC_STRING;
-           break;
-       case NSC_STRING:
-           val->val_as.str.base = ((char **)memb_ptr)[idx];
-           val->val_as.str.maxsz = INT_MAX;
-           valtype = NSC_STRING;
-           break;
-       case NSC_TIME:
-           val->val_as.lng = ((time_t *)memb_ptr)[idx];
-           break;
-       case NSC_TYPEID:
-           val->val_as.lng = ((signed char *)memb_ptr)[idx];
-           valtype = NSC_TYPEID;
-           break;
-       default:
-           CANT_HAPPEN("Bad VAL type");
-           val->val_as.lng = 0;
-       }
-       val->val_cat = NSC_VAL;
-    }
-
-    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)
-       CANT_HAPPEN("unimplemented WANT"); /* FIXME */
-
-    if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
-       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.base = NULL; break;
-       default:
-           CANT_HAPPEN("bad WANT argument");
-       }
-    }
-
-    val->val_type = valtype;
-}
-
-char *
-symbol_by_value(int key, struct symbol *table)
-{
-    int i;
-
-    for (i = 0; table[i].name; i++)
-       if (key == table[i].value)
-           return table[i].name;
-
-    return NULL;
-}