Selector rewrite: values other than long, interpret identifiers
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.
This commit is contained in:
parent
47c8a32ae3
commit
4366c5ac6e
13 changed files with 726 additions and 544 deletions
|
@ -30,248 +30,443 @@
|
|||
* 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.
|
||||
*/
|
||||
s_char *
|
||||
nstr_comp(struct nscstr *np, int *size, int type, s_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 == '#')
|
||||
break;
|
||||
*bp++ = c;
|
||||
}
|
||||
*bp = 0;
|
||||
if (c == 0) {
|
||||
pr("'%s'? -- meaningless condition?\n", arg);
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
*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 true if the conditions on this item
|
||||
* are all true.
|
||||
* 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
|
||||
* '?'.
|
||||
*/
|
||||
int
|
||||
nstr_exec(struct nscstr *conds, register int ncond, void *ptr, int type)
|
||||
nstr_comp(struct nscstr *np, int len, int type, char *str)
|
||||
{
|
||||
register struct nscstr *nsc;
|
||||
register int op;
|
||||
register int lhs;
|
||||
register int rhs;
|
||||
register int oper;
|
||||
char *cond;
|
||||
char *tail;
|
||||
int i;
|
||||
struct nscstr dummy;
|
||||
int lft_type, rgt_type;
|
||||
|
||||
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);
|
||||
cond = str;
|
||||
for (i = 0; ; ++i, ++np) {
|
||||
if (i >= len)
|
||||
np = &dummy;
|
||||
|
||||
if (oper & NSC_ISNUM1) {
|
||||
lhs = nsc->fld1;
|
||||
} else
|
||||
lhs = decode(player->cnum, nsc->fld1, ptr, type);
|
||||
/* left operand */
|
||||
tail = nstr_comp_val(cond, &np->lft, type);
|
||||
if (!tail)
|
||||
return -1;
|
||||
|
||||
op = oper & NSC_OPMASK;
|
||||
if ((op == '<' && lhs >= rhs)
|
||||
|| (op == '=' && lhs != rhs)
|
||||
|| (op == '>' && lhs <= rhs)
|
||||
|| (op == '#' && lhs == rhs))
|
||||
return 0;
|
||||
/* 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;
|
||||
if (*tail != '&') {
|
||||
pr("%s -- expected `&'\n", cond);
|
||||
return -1;
|
||||
}
|
||||
cond = tail + 1;
|
||||
}
|
||||
|
||||
if (i >= len) {
|
||||
/* could just return I and let caller gripe or enlarge buffer */
|
||||
pr("%s -- too many conditions\n", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
#define EVAL(op, lft, rgt) \
|
||||
((op) == '<' ? (lft) < (rgt) \
|
||||
: (op) == '=' ? (lft) == (rgt) \
|
||||
: (op) == '>' ? (lft) > (rgt) \
|
||||
: (op) == '#' ? (lft) != (rgt) \
|
||||
: 0)
|
||||
|
||||
/*
|
||||
* 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 *np, int ncond, void *ptr)
|
||||
{
|
||||
int i, op, optype;
|
||||
struct valstr lft, rgt;
|
||||
|
||||
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
|
||||
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;
|
||||
default:
|
||||
CANT_HAPPEN("bad VALTYPE");
|
||||
valtype = NSC_NOTYPE;
|
||||
}
|
||||
return valtype;
|
||||
}
|
||||
|
||||
static int
|
||||
legal_val(s_char *str, int val)
|
||||
cond_type_mismatch(char *str)
|
||||
{
|
||||
if (val & NSC_DEITY && !player->god) {
|
||||
pr("%s -- permission denied\n", str);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
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);
|
||||
/* FIXME get rid of promotion? */
|
||||
nsc_type from = nstr_promote(val->val_type);
|
||||
|
||||
val = (code & ~NSC_MASK) & 0xffff;
|
||||
if (from == NSC_NOTYPE)
|
||||
return 0;
|
||||
|
||||
/* 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);
|
||||
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_CHAR:
|
||||
val = *((s_char *)addr);
|
||||
break;
|
||||
case NSC_UCHAR:
|
||||
val = (int)*((unsigned char *)addr);
|
||||
break;
|
||||
case NSC_SHORT:
|
||||
val = *((short *)addr);
|
||||
break;
|
||||
case NSC_USHORT:
|
||||
val = *((u_short *)addr);
|
||||
break;
|
||||
case NSC_INT:
|
||||
val = *((int *)addr);
|
||||
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:
|
||||
val = *((long *)addr);
|
||||
break;
|
||||
case NSC_XCOORD:
|
||||
val = *((short *)addr);
|
||||
np = getnatp(cnum);
|
||||
val = xrel(np, val);
|
||||
break;
|
||||
case NSC_YCOORD:
|
||||
val = *((short *)addr);
|
||||
np = getnatp(cnum);
|
||||
val = yrel(np, val);
|
||||
break;
|
||||
return cond_type_mismatch(str);
|
||||
default:
|
||||
logerror("bad type in decode: %lx!\n", code & NSC_TMASK);
|
||||
val = 0;
|
||||
break;
|
||||
CANT_HAPPEN("bad TO argument");
|
||||
to = from;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
s_char *
|
||||
decodep(long int code, void *addr)
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
addr = (char *)addr + ((code & ~NSC_MASK) & 0xffff);
|
||||
char *memb_ptr;
|
||||
nsc_type valtype = NSC_LONG;
|
||||
|
||||
if ((code & NSC_TMASK) == NSC_CHARP)
|
||||
return *(s_char **)addr ? *((s_char **)addr) : (s_char *)"";
|
||||
return addr;
|
||||
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->val_as.lng = *(signed char *)memb_ptr;
|
||||
break;
|
||||
case NSC_UCHAR:
|
||||
val->val_as.lng = *(unsigned char *)memb_ptr;
|
||||
break;
|
||||
case NSC_SHORT:
|
||||
val->val_as.lng = *(short *)memb_ptr;
|
||||
break;
|
||||
case NSC_USHORT:
|
||||
val->val_as.lng = *(unsigned short *)memb_ptr;
|
||||
break;
|
||||
case NSC_INT:
|
||||
val->val_as.lng = *(int *)memb_ptr;
|
||||
break;
|
||||
case NSC_LONG:
|
||||
val->val_as.lng = *(long *)memb_ptr;
|
||||
break;
|
||||
case NSC_XCOORD:
|
||||
val->val_as.lng = xrel(getnatp(cnum), *(short *)memb_ptr);
|
||||
break;
|
||||
case NSC_YCOORD:
|
||||
val->val_as.lng = yrel(getnatp(cnum), *(short *)memb_ptr);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val->val_type = valtype;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue