]> 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-2012, 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-2008
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     return val;
58 }
59
60 /*
61  * Evaluate VAL.
62  * If VAL is symbolic, evaluate it into a promoted value type.
63  * Translate it for country CNUM (coordinate system and contact
64  * status), except when CNUM is NATID_BAD.
65  * PTR points to a context object of the type that was used to compile
66  * the value.
67  * Unless WANT is NSC_NOTYPE, coerce the value to promoted value type
68  * WANT.  VAL must be coercible.
69  */
70 struct valstr *
71 nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
72 {
73     char *memb_ptr;
74     enum nsc_type valtype;
75     int idx;
76     coord c;
77     struct natstr *natp;
78
79     if (CANT_HAPPEN(want != NSC_NOTYPE && !NSC_IS_PROMOTED(want)))
80         want = nstr_promote(want);
81
82     switch (val->val_cat) {
83     case NSC_VAL:
84         valtype = val->val_type;
85         break;
86     case NSC_OFF:
87         if (val->val_as.sym.get) {
88             natp = getnatp(cnum);
89             do {
90                 ptr = val->val_as.sym.get(val, natp, ptr);
91             } while (ptr && val->val_as.sym.get);
92             if (!ptr) {
93                 valtype = val->val_type;
94                 val->val_cat = NSC_VAL;
95                 break;
96             }
97         }
98
99         valtype = NSC_LONG;
100         memb_ptr = ptr;
101         memb_ptr += val->val_as.sym.off;
102         idx = val->val_as.sym.idx;
103         switch (val->val_type) {
104         case NSC_CHAR:
105             val->val_as.lng = ((signed char *)memb_ptr)[idx];
106             break;
107         case NSC_UCHAR:
108             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
109             break;
110         case NSC_SHORT:
111             val->val_as.lng = ((short *)memb_ptr)[idx];
112             break;
113         case NSC_USHORT:
114             val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
115             break;
116         case NSC_INT:
117             val->val_as.lng = ((int *)memb_ptr)[idx];
118             break;
119         case NSC_LONG:
120             val->val_as.lng = ((long *)memb_ptr)[idx];
121             break;
122         case NSC_XCOORD:
123             c = ((short *)memb_ptr)[idx];
124             if (cnum == NATID_BAD) {
125                 /* FIXME use variant of xrel() that takes orig instead of nation */
126                 if (c >= WORLD_X / 2)
127                     c -= WORLD_X;
128             } else
129                 c = xrel(getnatp(cnum), c);
130             val->val_as.lng = c;
131             break;
132         case NSC_YCOORD:
133             c = ((short *)memb_ptr)[idx];
134             if (cnum == NATID_BAD) {
135                 /* FIXME use variant of yrel() that takes orig instead of nation */
136                 if (c >= WORLD_Y / 2)
137                     c -= WORLD_Y;
138             } else
139                 c = yrel(getnatp(cnum), c);
140             val->val_as.lng = c;
141             break;
142         case NSC_HIDDEN:
143             val->val_as.lng = -1;
144             if (CANT_HAPPEN(((struct natstr *)ptr)->ef_type != EF_NATION))
145                 break;
146             if (opt_HIDDEN && cnum != NATID_BAD) {
147                 natp = getnatp(cnum);
148                 if (natp->nat_stat != STAT_GOD
149                     && !(getcontact(natp, idx) && getcontact(ptr, idx)))
150                     break;
151             }
152             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
153             break;
154         case NSC_FLOAT:
155             val->val_as.dbl = ((float *)memb_ptr)[idx];
156             valtype = NSC_DOUBLE;
157             break;
158         case NSC_DOUBLE:
159             val->val_as.dbl = ((double *)memb_ptr)[idx];
160             valtype = NSC_DOUBLE;
161             break;
162         case NSC_STRINGY:
163             CANT_HAPPEN(idx);
164             val->val_as.str.maxsz = val->val_as.sym.len;
165             val->val_as.str.base = (char *)memb_ptr;
166             valtype = NSC_STRING;
167             break;
168         case NSC_STRING:
169             val->val_as.str.base = ((char **)memb_ptr)[idx];
170             val->val_as.str.maxsz = INT_MAX;
171             valtype = NSC_STRING;
172             break;
173         case NSC_TIME:
174             val->val_as.lng = ((time_t *)memb_ptr)[idx];
175             break;
176         default:
177             CANT_REACH();
178             val->val_as.lng = 0;
179         }
180         val->val_cat = NSC_VAL;
181         break;
182     default:
183         CANT_REACH();
184         valtype = NSC_NOTYPE;
185     }
186
187     /* coerce */
188     if (valtype == want)
189         ;
190     else if (want == NSC_DOUBLE) {
191         if (valtype == NSC_LONG) {
192             valtype = want;
193             val->val_as.dbl = val->val_as.lng;
194         }
195     }
196
197     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
198         /* make up an error value */
199         valtype = want;
200         memset(&val->val_as, 0, sizeof(val->val_as));
201     }
202
203     val->val_type = valtype;
204     return val;
205 }
206
207 /*
208  * Promote VALTYPE.
209  * If VALTYPE is an integer type, return NSC_LONG.
210  * If VALTYPE is a floating-point type, return NSC_DOUBLE.
211  * If VALTYPE is a string type, return NSC_STRING.
212  */
213 int
214 nstr_promote(int valtype)
215 {
216     switch (valtype) {
217     case NSC_LONG:
218     case NSC_DOUBLE:
219     case NSC_STRING:
220         break;
221     case NSC_CHAR:
222     case NSC_UCHAR:
223     case NSC_SHORT:
224     case NSC_USHORT:
225     case NSC_INT:
226     case NSC_XCOORD:
227     case NSC_YCOORD:
228     case NSC_HIDDEN:
229     case NSC_TIME:
230         valtype = NSC_LONG;
231         break;
232     case NSC_FLOAT:
233         valtype = NSC_DOUBLE;
234         break;
235     case NSC_STRINGY:
236         valtype = NSC_STRING;
237         break;
238     default:
239         CANT_REACH();
240         valtype = NSC_NOTYPE;
241     }
242     return valtype;
243 }
244
245 char *
246 symbol_by_value(int key, struct symbol *table)
247 {
248     int i;
249
250     for (i = 0; table[i].name; i++)
251         if (key == table[i].value)
252             return table[i].name;
253
254     return NULL;
255 }