]> git.pond.sub.org Git - empserver/blob - src/lib/subs/nstr.c
Update copyright notice.
[empserver] / src / lib / subs / nstr.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  nstr.c: compile and execute the item selections on sectors
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 1997
33  *     Markus Armbruster, 2004
34  */
35
36 #include "misc.h"
37 #include "file.h"
38 #include "match.h"
39 #include "nsc.h"
40
41 static int nstr_promote(int valtype);
42
43 /*
44  * Compile conditions into array NP[LEN].
45  * Return number of conditions, or -1 on error.
46  * It is an error if there are more than LEN conditions.
47  * TYPE is the context type, a file type.
48  * STR is the condition string, in Empire syntax, without the leading
49  * '?'.
50  */
51 int
52 nstr_comp(struct nscstr *np, int len, int type, char *str)
53 {
54     char *cond;
55     char *tail;
56     int i;
57     struct nscstr dummy;
58     int lft_type, rgt_type;
59
60     cond = str;
61     for (i = 0; ; ++i, ++np) {
62         if (i >= len)
63             np = &dummy;
64
65         /* left operand */
66         tail = nstr_comp_val(cond, &np->lft, type);
67         if (!tail)
68             return -1;
69
70         /* operator */
71         if (*tail != '<' && *tail != '=' && *tail != '>' && *tail != '#') {
72             if (*tail)
73                 pr("%s -- expected condition operator\n", cond);
74             else
75                 pr("%s -- missing condition operator\n", cond);
76             return -1;
77         }
78         np->operator = *tail;
79         ++tail;
80
81         /* right operand */
82         tail = nstr_comp_val(tail, &np->rgt, type);
83         if (!tail)
84             return -1;
85
86         /* find operator type, coerce operands */
87         lft_type = nstr_promote(np->lft.val_type);
88         rgt_type = nstr_promote(np->rgt.val_type);
89         np->optype = NSC_NOTYPE;
90         if (lft_type == NSC_TYPEID) {
91             if (!nstr_coerce_val(&np->rgt, NSC_TYPEID, str))
92                 np->optype = NSC_TYPEID;
93         } else if (rgt_type == NSC_TYPEID) {
94             if (!nstr_coerce_val(&np->lft, NSC_TYPEID, str))
95                 np->optype = NSC_TYPEID;
96         } else if (lft_type == NSC_STRING) {
97             if (!nstr_coerce_val(&np->rgt, NSC_STRING, str))
98                 np->optype = NSC_STRING;
99         } else if (rgt_type == NSC_STRING) {
100             if (!nstr_coerce_val(&np->lft, NSC_STRING, str))
101                 np->optype = NSC_STRING;
102         } else if (lft_type == NSC_DOUBLE) {
103             if (!nstr_coerce_val(&np->rgt, NSC_DOUBLE, str))
104                 np->optype = NSC_DOUBLE;
105         } else if (rgt_type == NSC_DOUBLE) {
106             if (!nstr_coerce_val(&np->lft, NSC_DOUBLE, str))
107                 np->optype = NSC_DOUBLE;
108         } else {
109             if (!nstr_coerce_val(&np->lft, NSC_LONG, str)
110                 && !nstr_coerce_val(&np->rgt, NSC_LONG, str))
111                 np->optype = NSC_LONG;
112         }
113         if (np->optype == NSC_NOTYPE)
114             return -1;
115
116         /* another condition? */
117         if (*tail == 0)
118             break;
119         if (*tail != '&') {
120             pr("%s -- expected `&'\n", cond);
121             return -1;
122         }
123         cond = tail + 1;
124     }
125
126     if (i >= len) {
127         /* could just return I and let caller gripe or enlarge buffer */
128         pr("%s -- too many conditions\n", str);
129         return -1;
130     }
131
132     return i + 1;
133 }
134
135 #define EVAL(op, lft, rgt)                      \
136     ((op) == '<' ? (lft) < (rgt)                \
137      : (op) == '=' ? (lft) == (rgt)             \
138      : (op) == '>' ? (lft) > (rgt)              \
139      : (op) == '#' ? (lft) != (rgt)             \
140      : 0)
141
142 /*
143  * Evaluate compiled conditions in array NP[NCOND].
144  * Return non-zero iff they are all true.
145  * PTR points to a context object of the type that was used to compile
146  * the conditions.
147  */
148 int
149 nstr_exec(struct nscstr *np, int ncond, void *ptr)
150 {
151     int i, op, optype, cmp;
152     struct valstr lft, rgt;
153
154     for (i = 0; i < ncond; ++i) {
155         op = np[i].operator;
156         optype = np[i].optype;
157         if (np[i].lft.val_cat == NSC_NOCAT || np[i].rgt.val_cat == NSC_NOCAT)
158             return 0;
159         lft = np[i].lft;
160         nstr_exec_val(&lft, player->cnum, ptr, optype);
161         rgt = np[i].rgt;
162         nstr_exec_val(&rgt, player->cnum, ptr, optype);
163         switch (optype) {
164         case NSC_TYPEID:
165         case NSC_LONG:
166             if (!EVAL(op, lft.val_as.lng, rgt.val_as.lng))
167                 return 0;
168             break;
169         case NSC_DOUBLE:
170             if (!EVAL(op, lft.val_as.dbl, rgt.val_as.dbl))
171                 return 0;
172             break;
173         case NSC_STRING:
174             cmp = strcmp(lft.val_as.str, rgt.val_as.str);
175             if (!EVAL(op, cmp, 0))
176                 return 0;
177             break;
178         default:
179             CANT_HAPPEN("bad OPTYPE");
180             return 0;
181         }
182     }
183
184     return 1;
185 }
186
187 /*
188  * Compile a value in STR into VAL.
189  * Return a pointer to the first character after the value on success,
190  * NULL on error.
191  * TYPE is the context type, a file type.
192  * If STR names an array, VAL simply refers to the element with index
193  * zero.
194  */
195 char *
196 nstr_comp_val(char *str, struct valstr*val, int type)
197 {
198     char id[32];
199     long l;
200     double d;
201     char *tail, *tail2;
202     struct castr *cap;
203     unsigned i;
204     int j;
205
206     val->val_type = NSC_NOTYPE;
207     val->val_cat = NSC_NOCAT;
208     val->val_as_type = -1;
209
210     if (isalpha(str[0])) {
211         /* identifier */
212         for (i = 0; isalnum(str[i]) || str[i] == '_'; ++i) {
213             if (i < sizeof(id) - 1)
214                 id[i] = str[i];
215         }
216         tail = str + i;
217         if (i < sizeof(id)) {
218             id[i] = 0;
219
220             val->val_as_type = typematch(id, type);
221
222             cap = ef_cadef(type);
223             if (cap) {
224                 j = stmtch(id, cap, offsetof(struct castr, ca_name),
225                            sizeof(struct castr));
226                 if (j >= 0
227                     && (!(cap[j].ca_flags & NSC_DEITY) || player->god)) {
228                     if (cap[j].ca_type == NSC_TYPEID && val->val_as_type >= 0)
229                         /*
230                          * Got two matches of type NSC_TYPEID, need to
231                          * choose.  Prefer typematch(), because ?des=n
232                          * would be interpreted as ?des=newdes
233                          * otherwise
234                          */
235                         ;
236                     else {
237                         val->val_type = cap[j].ca_type;
238                         val->val_cat = NSC_OFF;
239                         val->val_as.sym.off = cap[j].ca_off;
240                         val->val_as.sym.idx = 0;
241                     }
242                 }
243             } else
244                 j = M_NOTFOUND;
245         } else
246             j = M_NOTFOUND;
247
248         if (val->val_type == NSC_NOTYPE) {
249             if (val->val_as_type >= 0) {
250                 val->val_type = NSC_TYPEID;
251                 val->val_cat = NSC_VAL;
252                 val->val_as.lng = val->val_as_type;
253             } else if (j >= 0)
254                 pr("%s -- selector access denied\n", id);
255             else if (j == M_NOTUNIQUE)
256                 pr("%s -- ambiguous selector name\n", id);
257             else
258                 pr("%s -- unknown selector name\n", id);
259         }
260
261         return val->val_type == NSC_NOTYPE ? NULL : tail;
262     }
263
264     /* single character type */
265     id[0] = str[0];
266     id[1] = 0;
267     val->val_as_type = typematch(id, type);
268
269     /* literals */
270     l = strtol(str, &tail, 0);
271     d = strtod(str, &tail2);
272     if (tail2 > tail) {
273         val->val_type = NSC_DOUBLE;
274         val->val_cat = NSC_VAL;
275         val->val_as.dbl = d;
276         return tail2;
277     }
278     if (tail != str) {
279         val->val_type = NSC_LONG;
280         val->val_cat = NSC_VAL;
281         val->val_as.lng = l;
282         return tail;
283     }
284     /* FIXME implement NSC_STRING literals */
285
286     CANT_HAPPEN(val->val_type != NSC_NOTYPE);
287     if (val->val_as_type >= 0) {
288         val->val_type = NSC_TYPEID;
289         val->val_cat = NSC_VAL;
290         val->val_as.lng = val->val_as_type;
291         return str + 1;
292     }
293
294     pr("%s -- invalid value for condition\n", str);
295     return NULL;
296 }
297
298 /*
299  * Promote VALTYPE.
300  * If VALTYPE is an integer type, return NSC_LONG.
301  * If VALTYPE is a floating-point type, return NSC_DOUBLE.
302  * If VALTYPE is NSC_STRINGY, return NSC_STRING.
303  * If VALTYPE is NSC_NOTYPE, NSC_STRING or NSC_TYPEID, return VALTYPE.
304  */
305 static int
306 nstr_promote(int valtype)
307 {
308     switch (valtype) {
309     case NSC_NOTYPE:
310     case NSC_LONG:
311     case NSC_DOUBLE:
312     case NSC_STRING:
313     case NSC_TYPEID:
314         break;
315     case NSC_CHAR:
316     case NSC_UCHAR:
317     case NSC_SHORT:
318     case NSC_USHORT:
319     case NSC_INT:
320     case NSC_XCOORD:
321     case NSC_YCOORD:
322     case NSC_TIME:
323         valtype = NSC_LONG;
324         break;
325     case NSC_FLOAT:
326         valtype = NSC_DOUBLE;
327         break;
328     case NSC_STRINGY:
329         valtype = NSC_STRING;
330         break;
331     default:
332         CANT_HAPPEN("bad VALTYPE");
333         valtype = NSC_NOTYPE;
334     }
335     return valtype;
336 }
337
338 static int
339 cond_type_mismatch(char *str)
340 {
341     if (str)
342         pr("%s -- condition operand type mismatch\n", str);
343     return -1;
344 }
345
346 /*
347  * Coerce VAL to promoted value type TO.
348  * Return 0 on success, -1 on error.
349  * If VAL is evaluated, convert it, else only check.
350  * STR is the condition text to be used for error messages.  Suppress
351  * messages if it is a null pointer.
352  */
353 int
354 nstr_coerce_val(struct valstr *val, nsc_type to, char *str)
355 {
356     /* FIXME get rid of promotion?  */
357     nsc_type from = nstr_promote(val->val_type);
358
359     if (from == NSC_NOTYPE)
360         return 0;
361
362     if (from != to) {
363         switch (to) {
364         case NSC_TYPEID:
365             if (val->val_as_type >= 0) {
366                 val->val_cat = NSC_VAL;
367                 val->val_as.lng = val->val_as_type;
368             } else
369                 return cond_type_mismatch(str);
370             break;
371         case NSC_STRING:
372             return cond_type_mismatch(str); /* FIXME implement */
373         case NSC_DOUBLE:
374             if (from == NSC_LONG) {
375                 if (val->val_cat == NSC_VAL)
376                     val->val_as.dbl = val->val_as.lng;
377             } else
378                 return cond_type_mismatch(str);
379             break;
380         case NSC_LONG:
381             return cond_type_mismatch(str);
382         default:
383             CANT_HAPPEN("bad TO argument");
384             to = from;
385         }
386     }
387
388     if (val->val_cat == NSC_VAL) {
389         /* coord literals don't occur, conversion not implemented */
390         CANT_HAPPEN(val->val_type == NSC_XCOORD
391                     || val->val_type == NSC_YCOORD);
392         val->val_type = to;
393     }
394
395     return 0;
396 }
397
398 /*
399  * Evaluate VAL.
400  * If VAL is symbolic, evaluate it into a promoted value type.
401  * Use coordinate system of country CNUM.
402  * PTR points to a context object of the type that was used to compile
403  * the value.
404  * Unless WANT is NSC_NOTYPE, coerce the value to promoted value type
405  * WANT.  VAL must be coercible.  That's the case if a previous
406  * nstr_coerce_val(VAL, WANT, STR) succeeded.
407  */
408 void
409 nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
410 {
411     char *memb_ptr;
412     nsc_type valtype = NSC_LONG;
413     int idx;
414
415     switch (val->val_cat) {
416     default:
417         CANT_HAPPEN("Bad VAL category");
418         /* fall through */
419     case NSC_VAL:
420         valtype = val->val_type;
421         break;
422     case NSC_OFF:
423         memb_ptr = ptr;
424         memb_ptr += val->val_as.sym.off;
425         idx = val->val_as.sym.idx;
426         switch (val->val_type) {
427         case NSC_CHAR:
428             val->val_as.lng = ((signed char *)memb_ptr)[idx];
429             break;
430         case NSC_UCHAR:
431             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
432             break;
433         case NSC_SHORT:
434             val->val_as.lng = ((short *)memb_ptr)[idx];
435             break;
436         case NSC_USHORT:
437             val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
438             break;
439         case NSC_INT:
440             val->val_as.lng = ((int *)memb_ptr)[idx];
441             break;
442         case NSC_LONG:
443             val->val_as.lng = ((long *)memb_ptr)[idx];
444             break;
445         case NSC_XCOORD:
446             val->val_as.lng = xrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
447             break;
448         case NSC_YCOORD:
449             val->val_as.lng = yrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
450             break;
451         case NSC_FLOAT:
452             val->val_as.dbl = ((float *)memb_ptr)[idx];
453             valtype = NSC_DOUBLE;
454             break;
455         case NSC_DOUBLE:
456             val->val_as.dbl = ((double *)memb_ptr)[idx];
457             valtype = NSC_DOUBLE;
458             break;
459         case NSC_STRINGY:
460             CANT_HAPPEN(idx);
461             val->val_as.str = (char *)memb_ptr;
462             valtype = NSC_STRING;
463             break;
464         case NSC_STRING:
465             val->val_as.str = ((char **)memb_ptr)[idx];
466             valtype = NSC_STRING;
467             break;
468         case NSC_TIME:
469             val->val_as.lng = ((time_t *)memb_ptr)[idx];
470             break;
471         case NSC_TYPEID:
472             val->val_as.lng = ((signed char *)memb_ptr)[idx];
473             valtype = NSC_TYPEID;
474             break;
475         default:
476             CANT_HAPPEN("Bad VAL type");
477             val->val_as.lng = 0;
478         }
479         val->val_cat = NSC_VAL;
480     }
481
482     if (valtype == want)
483         ;
484     else if (want == NSC_DOUBLE) {
485         if (valtype == NSC_LONG) {
486             valtype = want;
487             val->val_as.dbl = val->val_as.lng;
488         }
489     } else if (want == NSC_STRING)
490         CANT_HAPPEN("unimplemented WANT"); /* FIXME */
491     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
492         valtype = want;
493         switch (want) {
494         case NSC_TYPEID:
495         case NSC_LONG: val->val_as.lng = 0; break;
496         case NSC_DOUBLE: val->val_as.dbl = 0.0; break;
497         case NSC_STRING: val->val_as.str = ""; break;
498         default:
499             CANT_HAPPEN("bad WANT argument");
500         }
501     }
502
503     val->val_type = valtype;
504 }