/*
* Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2012, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure, Markus Armbruster
*
* Empire is free software: you can redistribute it and/or modify
* Known contributors to this file:
* Dave Pare, 1989
* Steve McClure, 1997
- * Markus Armbruster, 2004-2010
+ * Markus Armbruster, 2004-2014
*/
#include <config.h>
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
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);
++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);
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)
{
: (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) {
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))
}
/*
- * 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.
}
/* 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;
}
/*
- * 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
}
/*
- * 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)
/*
* 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
}
/*
- * 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.
*/
}
/*
- * 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 *
return NULL;
}
+ 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 NULL;
+ }
+
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);
}
/*
- * 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)
}
/*
- * 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)
}
/*
- * 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)