]> git.pond.sub.org Git - empserver/blob - src/lib/common/nstreval.c
Make nstr_exec_val() more robust
[empserver] / src / lib / common / nstreval.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program 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 2 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, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  nstreval.c: evaluate compiled values
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 1997
33  *     Markus Armbruster, 2004-2006
34  */
35
36 #include <config.h>
37
38 #include <limits.h>
39 #include <string.h>
40 #include "file.h"
41 #include "nat.h"
42 #include "nsc.h"
43 #include "optlist.h"
44
45
46 /*
47  * Evaluate VAL.
48  * If VAL is symbolic, evaluate it into a promoted value type.
49  * Use country CNUM's coordinate system and access control.
50  * PTR points to a context object of the type that was used to compile
51  * the value.
52  * Unless WANT is NSC_NOTYPE, coerce the value to promoted value type
53  * WANT.  VAL must be coercible.  That's the case if a previous
54  * nstr_coerce_val(VAL, WANT, STR) succeeded.
55  */
56 void
57 nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
58 {
59     char *memb_ptr;
60     nsc_type valtype;
61     int idx;
62     struct natstr *natp;
63
64     if (CANT_HAPPEN(want != NSC_NOTYPE && !NSC_IS_PROMOTED(want)))
65         want = nstr_promote(want);
66
67     switch (val->val_cat) {
68     case NSC_VAL:
69         valtype = val->val_type;
70         break;
71     case NSC_OFF:
72         valtype = NSC_LONG;
73         memb_ptr = ptr;
74         memb_ptr += val->val_as.sym.off;
75         idx = val->val_as.sym.idx;
76         switch (val->val_type) {
77         case NSC_CHAR:
78             val->val_as.lng = ((signed char *)memb_ptr)[idx];
79             break;
80         case NSC_UCHAR:
81             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
82             break;
83         case NSC_SHORT:
84             val->val_as.lng = ((short *)memb_ptr)[idx];
85             break;
86         case NSC_USHORT:
87             val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
88             break;
89         case NSC_INT:
90             val->val_as.lng = ((int *)memb_ptr)[idx];
91             break;
92         case NSC_LONG:
93             val->val_as.lng = ((long *)memb_ptr)[idx];
94             break;
95         case NSC_XCOORD:
96             val->val_as.lng = xrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
97             break;
98         case NSC_YCOORD:
99             val->val_as.lng = yrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
100             break;
101         case NSC_HIDDEN:
102             val->val_as.lng = -1;
103             if (CANT_HAPPEN(((struct natstr *)ptr)->ef_type != EF_NATION))
104                 break;
105             natp = getnatp(cnum);
106             if (!opt_HIDDEN
107                 || natp->nat_stat == STAT_GOD
108                 || (getcontact(natp, idx) && getcontact(ptr, idx)))
109                 val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
110             break;
111         case NSC_FLOAT:
112             val->val_as.dbl = ((float *)memb_ptr)[idx];
113             valtype = NSC_DOUBLE;
114             break;
115         case NSC_DOUBLE:
116             val->val_as.dbl = ((double *)memb_ptr)[idx];
117             valtype = NSC_DOUBLE;
118             break;
119         case NSC_STRINGY:
120             CANT_HAPPEN(idx);
121             val->val_as.str.maxsz = val->val_as.sym.len;
122             val->val_as.str.base = (char *)memb_ptr;
123             valtype = NSC_STRING;
124             break;
125         case NSC_STRING:
126             val->val_as.str.base = ((char **)memb_ptr)[idx];
127             val->val_as.str.maxsz = INT_MAX;
128             valtype = NSC_STRING;
129             break;
130         case NSC_TIME:
131             val->val_as.lng = ((time_t *)memb_ptr)[idx];
132             break;
133         default:
134             CANT_REACH();
135             val->val_as.lng = 0;
136         }
137         val->val_cat = NSC_VAL;
138         break;
139     default:
140         CANT_REACH();
141         valtype = NSC_NOTYPE;
142     }
143
144     if (valtype == want)
145         ;
146     else if (want == NSC_DOUBLE) {
147         if (valtype == NSC_LONG) {
148             valtype = want;
149             val->val_as.dbl = val->val_as.lng;
150         }
151     } else if (want == NSC_STRING)
152         CANT_REACH();           /* FIXME implement */
153
154     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
155         /* make up an error value */
156         valtype = want;
157         memset(&val->val_as, 0, sizeof(val->val_as));
158     }
159
160     val->val_type = valtype;
161 }
162
163 /*
164  * Promote VALTYPE.
165  * If VALTYPE is an integer type, return NSC_LONG.
166  * If VALTYPE is a floating-point type, return NSC_DOUBLE.
167  * If VALTYPE is a string type, return NSC_STRING.
168  */
169 int
170 nstr_promote(int valtype)
171 {
172     switch (valtype) {
173     case NSC_LONG:
174     case NSC_DOUBLE:
175     case NSC_STRING:
176         break;
177     case NSC_CHAR:
178     case NSC_UCHAR:
179     case NSC_SHORT:
180     case NSC_USHORT:
181     case NSC_INT:
182     case NSC_XCOORD:
183     case NSC_YCOORD:
184     case NSC_HIDDEN:
185     case NSC_TIME:
186         valtype = NSC_LONG;
187         break;
188     case NSC_FLOAT:
189         valtype = NSC_DOUBLE;
190         break;
191     case NSC_STRINGY:
192         valtype = NSC_STRING;
193         break;
194     default:
195         CANT_REACH();
196         valtype = NSC_NOTYPE;
197     }
198     return valtype;
199 }
200
201 char *
202 symbol_by_value(int key, struct symbol *table)
203 {
204     int i;
205
206     for (i = 0; table[i].name; i++)
207         if (key == table[i].value)
208             return table[i].name;
209
210     return NULL;
211 }