]> git.pond.sub.org Git - empserver/blob - src/lib/common/nstreval.c
Update copyright notice
[empserver] / src / lib / common / nstreval.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2015, 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-2014
33  */
34
35 #include <config.h>
36
37 #include <limits.h>
38 #include <string.h>
39 #include "file.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 *
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 *
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
83     if (CANT_HAPPEN(want != NSC_NOTYPE && !NSC_IS_PROMOTED(want)))
84         want = nstr_promote(want);
85
86     switch (val->val_cat) {
87     case NSC_VAL:
88         valtype = val->val_type;
89         if (CANT_HAPPEN(!NSC_IS_PROMOTED(valtype)))
90             valtype = nstr_promote(valtype);
91         break;
92     case NSC_OFF:
93         if (val->val_as.sym.get) {
94             natp = getnatp(cnum);
95             do {
96                 ptr = val->val_as.sym.get(val, natp, ptr);
97             } while (ptr && val->val_as.sym.get);
98             if (!ptr) {
99                 valtype = val->val_type;
100                 val->val_cat = NSC_VAL;
101                 break;
102             }
103         }
104
105         valtype = NSC_LONG;
106         memb_ptr = ptr;
107         memb_ptr += val->val_as.sym.off;
108         idx = val->val_as.sym.idx;
109         hidden = val->val_as.sym.hidden;
110         val->val_cat = NSC_VAL;
111         switch (val->val_type) {
112         case NSC_CHAR:
113             val->val_as.lng = ((signed char *)memb_ptr)[idx];
114             break;
115         case NSC_UCHAR:
116             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
117             break;
118         case NSC_SHORT:
119             val->val_as.lng = ((short *)memb_ptr)[idx];
120             break;
121         case NSC_USHORT:
122             val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
123             break;
124         case NSC_INT:
125             val->val_as.lng = ((int *)memb_ptr)[idx];
126             break;
127         case NSC_LONG:
128             val->val_as.lng = ((long *)memb_ptr)[idx];
129             break;
130         case NSC_XCOORD:
131             c = ((short *)memb_ptr)[idx];
132             if (cnum == NATID_BAD) {
133                 /* FIXME use variant of xrel() that takes orig instead of nation */
134                 if (c >= WORLD_X / 2)
135                     c -= WORLD_X;
136             } else
137                 c = xrel(getnatp(cnum), c);
138             val->val_as.lng = c;
139             break;
140         case NSC_YCOORD:
141             c = ((short *)memb_ptr)[idx];
142             if (cnum == NATID_BAD) {
143                 /* FIXME use variant of yrel() that takes orig instead of nation */
144                 if (c >= WORLD_Y / 2)
145                     c -= WORLD_Y;
146             } else
147                 c = yrel(getnatp(cnum), c);
148             val->val_as.lng = c;
149             break;
150         case NSC_FLOAT:
151             val->val_as.dbl = ((float *)memb_ptr)[idx];
152             valtype = NSC_DOUBLE;
153             break;
154         case NSC_DOUBLE:
155             val->val_as.dbl = ((double *)memb_ptr)[idx];
156             valtype = NSC_DOUBLE;
157             break;
158         case NSC_STRINGY:
159             CANT_HAPPEN(idx);
160             val->val_as.str.maxsz = val->val_as.sym.len;
161             val->val_as.str.base = (char *)memb_ptr;
162             valtype = NSC_STRING;
163             break;
164         case NSC_STRING:
165             val->val_as.str.base = ((char **)memb_ptr)[idx];
166             val->val_as.str.maxsz = INT_MAX;
167                                 /* really SIZE_MAX, but that's C99 */
168             valtype = NSC_STRING;
169             break;
170         case NSC_TIME:
171             val->val_as.lng = ((time_t *)memb_ptr)[idx];
172             break;
173         default:
174             CANT_REACH();
175             valtype = NSC_NOTYPE;
176         }
177
178         if (hidden) {
179             if (CANT_HAPPEN(hidden && valtype != NSC_LONG))
180                 break;          /* not implemented */
181             if (CANT_HAPPEN(((struct natstr *)ptr)->ef_type != EF_NATION))
182                 break;          /* only defined for nation selectors */
183             if (!opt_HIDDEN || cnum == NATID_BAD)
184                 break;
185             natp = getnatp(cnum);
186             if (natp->nat_stat != STAT_GOD
187                 && !(getcontact(natp, idx) && getcontact(ptr, idx)))
188                 val->val_as.lng = -1;
189         }
190         break;
191     default:
192         CANT_REACH();
193         valtype = NSC_NOTYPE;
194     }
195
196     /* coerce */
197     if (valtype == want)
198         ;
199     else if (want == NSC_DOUBLE) {
200         if (valtype == NSC_LONG) {
201             valtype = want;
202             val->val_as.dbl = val->val_as.lng;
203         }
204     }
205
206     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE))
207         valtype = NSC_NOTYPE;
208
209     val->val_type = valtype;
210     return val;
211 }
212
213 /*
214  * Promote VALTYPE.
215  * If VALTYPE is an integer type, return NSC_LONG.
216  * If VALTYPE is a floating-point type, return NSC_DOUBLE.
217  * If VALTYPE is a string type, return NSC_STRING.
218  */
219 int
220 nstr_promote(int valtype)
221 {
222     switch (valtype) {
223     case NSC_LONG:
224     case NSC_DOUBLE:
225     case NSC_STRING:
226         break;
227     case NSC_CHAR:
228     case NSC_UCHAR:
229     case NSC_SHORT:
230     case NSC_USHORT:
231     case NSC_INT:
232     case NSC_XCOORD:
233     case NSC_YCOORD:
234     case NSC_TIME:
235         valtype = NSC_LONG;
236         break;
237     case NSC_FLOAT:
238         valtype = NSC_DOUBLE;
239         break;
240     case NSC_STRINGY:
241         valtype = NSC_STRING;
242         break;
243     default:
244         CANT_REACH();
245         valtype = NSC_NOTYPE;
246     }
247     return valtype;
248 }
249
250 char *
251 symbol_by_value(int key, struct symbol *table)
252 {
253     int i;
254
255     for (i = 0; table[i].name; i++)
256         if (key == table[i].value)
257             return table[i].name;
258
259     return NULL;
260 }