1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  nstreval.c: evaluate compiled values
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1989
31  *     Steve McClure, 1997
32  *     Markus Armbruster, 2004-2016
33  */
34 
35 #include <config.h>
36 
37 #include <limits.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include "nat.h"
41 #include "nsc.h"
42 #include "optlist.h"
43 
44 /*
45  * Initialize @val to symbolic value for selector @ca with index @idx.
46  * Return @val.
47  */
48 struct valstr *
nstr_mksymval(struct valstr * val,struct castr * ca,int idx)49 nstr_mksymval(struct valstr *val, struct castr *ca, int idx)
50 {
51     val->val_type = ca->ca_type;
52     val->val_cat = NSC_OFF;
53     val->val_as.sym.off = ca->ca_off;
54     val->val_as.sym.len = ca->ca_len;
55     val->val_as.sym.idx = idx;
56     val->val_as.sym.get = ca->ca_get;
57     val->val_as.sym.hidden = ca->ca_flags & NSC_HIDDEN;
58     return val;
59 }
60 
61 /*
62  * Evaluate @val.
63  * If @val has category NSC_OFF, read the value from the context object
64  * @ptr, and translate it for country @cnum (coordinate system and
65  * contact status).  No translation when @cnum is NATID_BAD.
66  * @ptr points to a context object of the type that was used to compile
67  * the value.
68  * Unless @want is NSC_NOTYPE, coerce the value to promoted value type
69  * @want.  @val must be coercible.
70  * The result's type is promoted on success, NSC_NOTYPE on error.
71  * In either case, the category is NSC_VAL.
72  * Return @val.
73  */
74 struct valstr *
nstr_eval(struct valstr * val,natid cnum,void * ptr,enum nsc_type want)75 nstr_eval(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
76 {
77     char *memb_ptr;
78     enum nsc_type valtype;
79     int idx, hidden;
80     coord c;
81     struct natstr *natp;
82     struct relatstr *relp;
83 
84     if (CANT_HAPPEN(want != NSC_NOTYPE && !NSC_IS_PROMOTED(want)))
85 	want = nstr_promote(want);
86 
87     switch (val->val_cat) {
88     case NSC_VAL:
89 	valtype = val->val_type;
90 	if (CANT_HAPPEN(!NSC_IS_PROMOTED(valtype)))
91 	    valtype = nstr_promote(valtype);
92 	break;
93     case NSC_OFF:
94 	if (val->val_as.sym.get) {
95 	    natp = getnatp(cnum);
96 	    do {
97 		ptr = val->val_as.sym.get(val, natp, ptr);
98 	    } while (ptr && val->val_as.sym.get);
99 	    if (!ptr) {
100 		valtype = val->val_type;
101 		val->val_cat = NSC_VAL;
102 		break;
103 	    }
104 	}
105 
106 	valtype = NSC_LONG;
107 	memb_ptr = ptr;
108 	memb_ptr += val->val_as.sym.off;
109 	idx = val->val_as.sym.idx;
110 	hidden = val->val_as.sym.hidden;
111 	val->val_cat = NSC_VAL;
112 	switch (val->val_type) {
113 	case NSC_CHAR:
114 	    val->val_as.lng = ((signed char *)memb_ptr)[idx];
115 	    break;
116 	case NSC_UCHAR:
117 	    val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
118 	    break;
119 	case NSC_SHORT:
120 	    val->val_as.lng = ((short *)memb_ptr)[idx];
121 	    break;
122 	case NSC_USHORT:
123 	    val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
124 	    break;
125 	case NSC_INT:
126 	    val->val_as.lng = ((int *)memb_ptr)[idx];
127 	    break;
128 	case NSC_LONG:
129 	    val->val_as.lng = ((long *)memb_ptr)[idx];
130 	    break;
131 	case NSC_XCOORD:
132 	    c = ((short *)memb_ptr)[idx];
133 	    if (cnum == NATID_BAD) {
134 		/* FIXME use variant of xrel() that takes orig instead of nation */
135 		if (c >= WORLD_X / 2)
136 		    c -= WORLD_X;
137 	    } else
138 		c = xrel(getnatp(cnum), c);
139 	    val->val_as.lng = c;
140 	    break;
141 	case NSC_YCOORD:
142 	    c = ((short *)memb_ptr)[idx];
143 	    if (cnum == NATID_BAD) {
144 		/* FIXME use variant of yrel() that takes orig instead of nation */
145 		if (c >= WORLD_Y / 2)
146 		    c -= WORLD_Y;
147 	    } else
148 		c = yrel(getnatp(cnum), c);
149 	    val->val_as.lng = c;
150 	    break;
151 	case NSC_FLOAT:
152 	    val->val_as.dbl = ((float *)memb_ptr)[idx];
153 	    valtype = NSC_DOUBLE;
154 	    break;
155 	case NSC_DOUBLE:
156 	    val->val_as.dbl = ((double *)memb_ptr)[idx];
157 	    valtype = NSC_DOUBLE;
158 	    break;
159 	case NSC_STRINGY:
160 	    CANT_HAPPEN(idx);
161 	    val->val_as.str.maxsz = val->val_as.sym.len;
162 	    val->val_as.str.base = (char *)memb_ptr;
163 	    valtype = NSC_STRING;
164 	    break;
165 	case NSC_STRING:
166 	    val->val_as.str.base = ((char **)memb_ptr)[idx];
167 	    val->val_as.str.maxsz = INT_MAX;
168 				/* really SIZE_MAX, but that's C99 */
169 	    valtype = NSC_STRING;
170 	    break;
171 	case NSC_TIME:
172 	    val->val_as.lng = ((time_t *)memb_ptr)[idx];
173 	    break;
174 	default:
175 	    CANT_REACH();
176 	    valtype = NSC_NOTYPE;
177 	}
178 
179 	if (hidden) {
180 	    if (CANT_HAPPEN(hidden && valtype != NSC_LONG))
181 		break;		/* not implemented */
182 	    relp = ptr;
183 	    if (CANT_HAPPEN(relp->ef_type != EF_RELAT))
184 		break;		/* only defined for nation selectors */
185 	    if (!opt_HIDDEN || cnum == NATID_BAD
186 		|| getnatp(cnum)->nat_stat == STAT_GOD)
187 		break;
188 	    if (!in_contact(cnum, idx) || !in_contact(relp->rel_uid, idx))
189 		val->val_as.lng = -1;
190 	}
191 	break;
192     default:
193 	CANT_REACH();
194 	valtype = NSC_NOTYPE;
195     }
196 
197     /* coerce */
198     if (valtype == want)
199 	;
200     else if (want == NSC_DOUBLE) {
201 	if (valtype == NSC_LONG) {
202 	    valtype = want;
203 	    val->val_as.dbl = val->val_as.lng;
204 	}
205     }
206 
207     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE))
208 	valtype = NSC_NOTYPE;
209 
210     val->val_type = valtype;
211     return val;
212 }
213 
214 /*
215  * Promote @valtype.
216  * If @valtype is an integer type, return NSC_LONG.
217  * If @valtype is a floating-point type, return NSC_DOUBLE.
218  * If @valtype is a string type, return NSC_STRING.
219  */
220 int
nstr_promote(int valtype)221 nstr_promote(int valtype)
222 {
223     switch (valtype) {
224     case NSC_LONG:
225     case NSC_DOUBLE:
226     case NSC_STRING:
227 	break;
228     case NSC_CHAR:
229     case NSC_UCHAR:
230     case NSC_SHORT:
231     case NSC_USHORT:
232     case NSC_INT:
233     case NSC_XCOORD:
234     case NSC_YCOORD:
235     case NSC_TIME:
236 	valtype = NSC_LONG;
237 	break;
238     case NSC_FLOAT:
239 	valtype = NSC_DOUBLE;
240 	break;
241     case NSC_STRINGY:
242 	valtype = NSC_STRING;
243 	break;
244     default:
245 	CANT_REACH();
246 	valtype = NSC_NOTYPE;
247     }
248     return valtype;
249 }
250 
251 char *
symbol_by_value(int key,struct symbol * table)252 symbol_by_value(int key, struct symbol *table)
253 {
254     int i;
255 
256     for (i = 0; table[i].name; i++)
257 	if (key == table[i].value)
258 	    return table[i].name;
259 
260     return NULL;
261 }
262 
263 int
symbol_set_fmt(char * buf,size_t sz,int flags,struct symbol symtab[],char * sep,int all)264 symbol_set_fmt(char *buf, size_t sz, int flags, struct symbol symtab[],
265 	       char *sep, int all)
266 {
267     char *pfx = "";
268     int n, i;
269     char *p;
270 
271     if (buf && sz)
272 	buf[0] = 0;
273     n = 0;
274     for (i = 0; i < 32; i++) {
275 	if (!(flags & bit(i)))
276 	    continue;
277 	p = symbol_by_value(bit(i), symtab);
278 	if (p)
279 	    n += snprintf(buf + n, sz - n, "%s%s", pfx, p);
280 	else if (all)
281 	    n += snprintf(buf + n, sz - n, "%s#%d", pfx, i);
282 	if ((size_t)n >= sz)
283 	    sz = n;
284 	pfx = sep;
285     }
286 
287     CANT_HAPPEN((size_t)n >= sz && buf);
288     return n;
289 }
290