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