]> git.pond.sub.org Git - empserver/blobdiff - src/lib/subs/nstr.c
Update copyright notice
[empserver] / src / lib / subs / nstr.c
index 8beb07094a612284655d506e467ae6e530346ce4..439665a221fb63dc56f66b20eebcf4a7190e21f2 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                Ken Stevens, Steve McClure, Markus Armbruster
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  Empire is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  *  ---
  *
@@ -30,7 +29,7 @@
  *  Known contributors to this file:
  *     Dave Pare, 1989
  *     Steve McClure, 1997
- *     Markus Armbruster, 2004-2008
+ *     Markus Armbruster, 2004-2014
  */
 
 #include <config.h>
@@ -39,6 +38,7 @@
 #include <limits.h>
 #include "file.h"
 #include "match.h"
+#include "nsc.h"
 #include "player.h"
 #include "prototypes.h"
 
@@ -48,16 +48,15 @@ static int nstr_is_name_of_ca(struct valstr *, struct castr *, int);
 static int nstr_ca_comparable(struct castr *, int, int);
 static int nstr_match_val(struct valstr *, struct castr *, int);
 static struct valstr *nstr_resolve_id(struct valstr *, struct castr *, int);
-static struct valstr *nstr_resolve_sel(struct valstr *, struct castr *);
 static struct valstr *nstr_resolve_val(struct valstr *, int, struct castr *);
 static int nstr_optype(enum nsc_type, enum nsc_type);
 
 /*
- * Compile conditions into array NP[LEN].
+ * 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
+ * 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
  * '?'.
  */
 int
@@ -78,6 +77,10 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
            np = &dummy;
 
        /* left operand */
+       if (!*cond) {
+           pr("%s -- %scondition expected\n", str, i ? "another " : "");
+           return -1;
+       }
        tail = nstr_parse_val(cond, &np->lft);
        lft_caidx = nstr_match_ca(&np->lft, ca);
 
@@ -93,6 +96,10 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
        ++tail;
 
        /* right operand */
+       if (!*tail) {
+           pr("%s -- operand expected\n", cond);
+           return -1;
+       }
        tail = nstr_parse_val(tail, &np->rgt);
        rgt_caidx = nstr_match_ca(&np->rgt, ca);
 
@@ -195,13 +202,15 @@ nstr_comp(struct nscstr *np, int len, int type, char *str)
     return i + 1;
 }
 
-/* Like strcmp(S1, S2), but limit length of S1 to SZ1 and of S2 to SZ2.  */
+/* Like strcmp(S1, S2), but limit length of S1 to SZ1 and of S2 to SZ2. */
 static int
 strnncmp(char *s1, size_t sz1, char *s2, size_t sz2)
 {
     int res;
-    if (sz1 == sz2) return strncmp(s1, s2, sz2);
-    if (sz1 < sz2) return -strnncmp(s2, sz2, s1, sz1);
+    if (sz1 == sz2)
+       return strncmp(s1, s2, sz2);
+    if (sz1 < sz2)
+       return -strnncmp(s2, sz2, s1, sz1);
     res = strncmp(s1, s2, sz2);
     return res ? res : s1[sz2];
 }
@@ -214,15 +223,16 @@ strnncmp(char *s1, size_t sz1, char *s2, size_t sz2)
      : (CANT_REACH(), 0))
 
 /*
- * Evaluate compiled conditions in array NP[NCOND].
+ * 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
+ * @ptr points to a context object of the type that was used to compile
  * the conditions.
  */
 int
 nstr_exec(struct nscstr *np, int ncond, void *ptr)
 {
-    int i, op, optype, cmp;
+    int i, op, cmp;
+    enum nsc_type optype;
     struct valstr lft, rgt;
 
     for (i = 0; i < ncond; ++i) {
@@ -231,9 +241,11 @@ nstr_exec(struct nscstr *np, int ncond, void *ptr)
        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);
+       nstr_eval(&lft, player->cnum, ptr, optype);
        rgt = np[i].rgt;
-       nstr_exec_val(&rgt, player->cnum, ptr, optype);
+       nstr_eval(&rgt, player->cnum, ptr, optype);
+       if (CANT_HAPPEN(lft.val_type != optype || rgt.val_type != optype))
+           return 0;
        switch (optype) {
        case NSC_LONG:
            if (!EVAL(op, lft.val_as.lng, rgt.val_as.lng))
@@ -259,7 +271,7 @@ nstr_exec(struct nscstr *np, int ncond, void *ptr)
 }
 
 /*
- * Parse a value in STR into VAL.
+ * Parse a value in @str into @val.
  * Return a pointer to the first character after the value.
  * Value is either evaluated into NSC_STRING, NSC_DOUBLE or NSC_LONG,
  * or an identifier.
@@ -279,7 +291,8 @@ nstr_parse_val(char *str, struct valstr *val)
        val->val_cat = NSC_VAL;
        val->val_as.str.base = str + 1;
        val->val_as.str.maxsz = tail - (str + 1);
-       if (*tail) ++tail;
+       if (*tail)
+           ++tail;
        /* FIXME else unclosed string */
        return tail;
     }
@@ -311,7 +324,7 @@ nstr_parse_val(char *str, struct valstr *val)
     }
 
     /* funny character, interpret as identifier */
-    tail = str+1;
+    tail = CANT_HAPPEN(!*str) ? str : str + 1;
     val->val_type = NSC_NOTYPE;
     val->val_cat = NSC_ID;
     val->val_as.str.base = str;
@@ -320,10 +333,10 @@ nstr_parse_val(char *str, struct valstr *val)
 }
 
 /*
- * Match VAL in table of selector descriptors CA, return index.
+ * Match @val in table of selector descriptors @ca, return index.
  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
  * several.
- * A VAL that is not an identifier doesn't match anything.  A null CA
+ * A @val that is not an identifier doesn't match anything.  A null @ca
  * is considered empty.
  */
 static int
@@ -345,23 +358,23 @@ nstr_match_ca(struct valstr *val, struct castr *ca)
 }
 
 /*
- * Is identifier VAL the name of the selector given by CA and IDX?
- * Return non-zero if and only if IDX is non-negative and VAL is the
- * name of CA[IDX].
- * IDX must have been obtained from nstr_match_ca(VAL, CA).
+ * Is identifier @val the name of the selector given by @ca and @idx?
+ * Return non-zero if and only if @idx is non-negative and @val is the
+ * name of @ca[@idx].
+ * @idx must have been obtained from nstr_match_ca(@val, @ca).
  */
 static int
 nstr_is_name_of_ca(struct valstr *val, struct castr *ca, int idx)
 {
     if (CANT_HAPPEN(val->val_cat != NSC_ID && idx >= 0))
-       return 0;
+       return 0;
     return idx >= 0 && strlen(ca[idx].ca_name) == val->val_as.str.maxsz;
 }
 
 /*
  * Do we have two comparable selectors?
- * Check selector descriptors CA[LFT_IDX] (unless LFT_IDX is negative)
- * and CA[RGT_IDX] (unless RGT_IDX is negative).  CA may be null when
+ * Check selector descriptors @ca[@lft_idx] (unless @lft_idx is negative)
+ * and @ca[@rgt_idx] (unless @rgt_idx is negative).  @ca may be null when
  * both are negative.
  */
 static int
@@ -376,9 +389,9 @@ nstr_ca_comparable(struct castr *ca, int lft_idx, int rgt_idx)
 }
 
 /*
- * Match VAL in a selector's values, return its (non-negative) value.
- * Match values of selector descriptor CA[IDX], provided IDX is not
- * negative.  CA may be null when IDX is negative.
+ * Match @val in a selector's values, return its (non-negative) value.
+ * Match values of selector descriptor @ca[@idx], provided @idx is not
+ * negative.  @ca may be null when @idx is negative.
  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
  * several.
  */
@@ -406,10 +419,10 @@ nstr_match_val(struct valstr *val, struct castr *ca, int idx)
 }
 
 /*
- * Change VAL to resolve identifier to selector.
- * Return VAL on success, NULL on error.
- * No change if VAL is not an identifier.
- * Else change VAL into symbolic value for selector CA[IDX] if IDX >=
+ * Change @val to resolve identifier to selector.
+ * Return @val on success, NULL on error.
+ * No change if @val is not an identifier.
+ * Else change @val into symbolic value for selector @ca[@idx] if @idx >=
  * 0, and error if not.
  */
 static struct valstr *
@@ -432,38 +445,28 @@ nstr_resolve_id(struct valstr *val, struct castr *ca, int idx)
        return NULL;
     }
 
-    return nstr_resolve_sel(val, &ca[idx]);
-}
-
-/*
- * Change VAL to resolve identifier to selector CA.
- * Return VAL on success, NULL if the player is denied access to the
- * selector.
- * VAL must be an identifier.
- */
-static struct valstr *
-nstr_resolve_sel(struct valstr *val, struct castr *ca)
-{
-    if (CANT_HAPPEN(val->val_cat != NSC_ID)) {
+    if (CA_IS_ARRAY(&ca[idx])) {
+       pr("%.*s -- not usable here\n",
+          (int)val->val_as.str.maxsz, val->val_as.str.base);
        val->val_cat = NSC_NOCAT;
-       return val;
+       return NULL;
     }
 
-    if ((ca->ca_flags & NSC_DEITY) && !player->god) {
+    if ((ca[idx].ca_flags & NSC_DEITY) && !player->god) {
        pr("%.*s -- not accessible to mortals\n",
           (int)val->val_as.str.maxsz, val->val_as.str.base);
        val->val_cat = NSC_NOCAT;
        return NULL;
     }
 
-    return nstr_mksymval(val, ca, 0);
+    return nstr_mksymval(val, &ca[idx], 0);
 }
 
 /*
- * Change VAL to resolve identifier to value SELVAL for selector CA.
- * Return VAL.
- * VAL must be an identifier, and SELVAL must have been obtained from
- * nstr_match_val(VAL, CA0, IDX), where CA = &CA0[IDX].
+ * Change @val to resolve identifier to value @selval for selector @ca.
+ * Return @val.
+ * @val must be an identifier, and @selval must have been obtained from
+ * nstr_match_val(@val, CA0, @idx), where @ca = &CA0[@IDX].
  */
 static struct valstr *
 nstr_resolve_val(struct valstr *val, int selval, struct castr *ca)
@@ -497,7 +500,7 @@ nstr_resolve_val(struct valstr *val, int selval, struct castr *ca)
 }
 
 /*
- * Return operator type for operand types LFT, RGT.
+ * Return operator type for operand types @lft, @rgt.
  */
 static int
 nstr_optype(enum nsc_type lft, enum nsc_type rgt)
@@ -505,21 +508,19 @@ nstr_optype(enum nsc_type lft, enum nsc_type rgt)
     lft = nstr_promote(lft);
     rgt = nstr_promote(rgt);
     if (lft == rgt)
-       return lft;
+       return lft;
     if (lft == NSC_DOUBLE && rgt == NSC_LONG)
-       return NSC_DOUBLE;
+       return NSC_DOUBLE;
     if (rgt == NSC_DOUBLE && lft == NSC_LONG)
-       return NSC_DOUBLE;
+       return NSC_DOUBLE;
     return NSC_NOTYPE;
 }
 
 /*
- * Compile a value in STR into VAL.
+ * 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.
- * If STR names an array, VAL simply refers to the element with index
- * zero.
+ * @type is the context type, a file type.
  */
 char *
 nstr_comp_val(char *str, struct valstr *val, int type)