]> git.pond.sub.org Git - empserver/blob - src/lib/subs/nstr.c
(nstr_comp): Interpret identifiers as strings only when the
[empserver] / src / lib / subs / nstr.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2005, 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 #include "prototypes.h"
42
43 static char *nstr_parse_val(char *, struct valstr *);
44 static int nstr_match_ca(struct valstr *, struct castr *);
45 static int nstr_match_val(struct valstr *, int, struct castr *, int);
46 static struct valstr *nstr_resolve_sel(struct valstr *, struct castr *);
47 static struct valstr *nstr_mkselval(struct valstr *, int, struct castr *);
48 static struct valstr *nstr_resolve_id(struct valstr *, struct castr *, int, int);
49 static int nstr_promote(int);
50
51
52 /*
53  * Compile conditions into array NP[LEN].
54  * Return number of conditions, or -1 on error.
55  * It is an error if there are more than LEN conditions.
56  * TYPE is the context type, a file type.
57  * STR is the condition string, in Empire syntax, without the leading
58  * '?'.
59  */
60 int
61 nstr_comp(struct nscstr *np, int len, int type, char *str)
62 {
63     struct castr *ca = ef_cadef(type);
64     char *cond;
65     char *tail;
66     int i;
67     struct nscstr dummy;
68     int lft_caidx, rgt_caidx;
69     int lft_val, rgt_val;
70     int lft_type, rgt_type;
71
72     cond = str;
73     for (i = 0; ; ++i, ++np) {
74         if (i >= len)
75             np = &dummy;
76
77         /* left operand */
78         tail = nstr_parse_val(cond, &np->lft);
79         lft_caidx = nstr_match_ca(&np->lft, ca);
80
81         /* operator */
82         if (*tail != '<' && *tail != '=' && *tail != '>' && *tail != '#') {
83             if (*tail)
84                 pr("%s -- expected condition operator\n", cond);
85             else
86                 pr("%s -- missing condition operator\n", cond);
87             return -1;
88         }
89         np->operator = *tail;
90         ++tail;
91
92         /* right operand */
93         tail = nstr_parse_val(tail, &np->rgt);
94         rgt_caidx = nstr_match_ca(&np->rgt, ca);
95
96         /*
97          * Resolve identifiers
98          *
99          * An identifier can name a selector or, if the other operand
100          * is a selector, a value for that.  The condition is
101          * ambiguous if both selector x value and value x selector are
102          * possible.  Example: n<n for sectors could mean newdes<n or
103          * n<newdes.
104          */
105         lft_val = nstr_match_val(&np->lft, type, ca, rgt_caidx);
106         rgt_val = nstr_match_val(&np->rgt, type, ca, lft_caidx);
107         /*
108          * if lft_val >= 0, then rhs names a selector and lhs names
109          * one of its values.  Likewise for rgt_val.
110          */
111         if (lft_val >= 0 && rgt_val >= 0) {
112             pr("%.*s -- condition ambiguous\n", (int)(tail-cond), cond);
113             return -1;
114         } else if (rgt_val >= 0) {
115             /* selector x value */
116             if (!nstr_resolve_sel(&np->lft, &ca[lft_caidx]))
117                 return -1;
118             nstr_mkselval(&np->rgt, rgt_val, &ca[lft_caidx]);
119         } else if (lft_val >= 0) {
120             /* value x selector */
121             nstr_mkselval(&np->lft, lft_val, &ca[rgt_caidx]);
122             if (!nstr_resolve_sel(&np->rgt, &ca[rgt_caidx]))
123                 return -1;
124         } else {
125             /*
126              * Neither side works as selector value; any identifiers
127              * must name selectors.
128              */
129             if (!nstr_resolve_id(&np->lft, ca, lft_caidx,
130                                  nstr_promote(ca[rgt_caidx].ca_type)
131                                  == NSC_STRING))
132                 return -1;
133             if (!nstr_resolve_id(&np->rgt, ca, rgt_caidx,
134                                  nstr_promote(ca[lft_caidx].ca_type)
135                                  == NSC_STRING))
136                 return -1;
137         }
138
139         /* find operator type, coerce operands */
140         lft_type = nstr_promote(np->lft.val_type);
141         rgt_type = nstr_promote(np->rgt.val_type);
142         np->optype = NSC_NOTYPE;
143         if (lft_type == NSC_TYPEID) {
144             if (!nstr_coerce_val(&np->rgt, NSC_TYPEID, str))
145                 np->optype = NSC_TYPEID;
146         } else if (rgt_type == NSC_TYPEID) {
147             if (!nstr_coerce_val(&np->lft, NSC_TYPEID, str))
148                 np->optype = NSC_TYPEID;
149         } else if (lft_type == NSC_STRING) {
150             if (!nstr_coerce_val(&np->rgt, NSC_STRING, str))
151                 np->optype = NSC_STRING;
152         } else if (rgt_type == NSC_STRING) {
153             if (!nstr_coerce_val(&np->lft, NSC_STRING, str))
154                 np->optype = NSC_STRING;
155         } else if (lft_type == NSC_DOUBLE) {
156             if (!nstr_coerce_val(&np->rgt, NSC_DOUBLE, str))
157                 np->optype = NSC_DOUBLE;
158         } else if (rgt_type == NSC_DOUBLE) {
159             if (!nstr_coerce_val(&np->lft, NSC_DOUBLE, str))
160                 np->optype = NSC_DOUBLE;
161         } else {
162             if (!nstr_coerce_val(&np->lft, NSC_LONG, str)
163                 && !nstr_coerce_val(&np->rgt, NSC_LONG, str))
164                 np->optype = NSC_LONG;
165         }
166         if (np->optype == NSC_NOTYPE)
167             return -1;
168
169         /* another condition? */
170         if (*tail == 0)
171             break;
172         if (*tail != '&') {
173             pr("%s -- expected `&'\n", cond);
174             return -1;
175         }
176         cond = tail + 1;
177     }
178
179     if (i >= len) {
180         /* could just return I and let caller gripe or enlarge buffer */
181         pr("%s -- too many conditions\n", str);
182         return -1;
183     }
184
185     return i + 1;
186 }
187
188 /* Like strcmp(S1, S2), but limit length of S1 to SZ1 and of S2 to SZ2.  */
189 static int
190 strnncmp(char *s1, size_t sz1, char *s2, size_t sz2)
191 {
192     int res;
193     if (sz1 == sz2) return strncmp(s1, s2, sz2);
194     if (sz1 < sz2) return -strnncmp(s2, sz2, s1, sz1);
195     res = strncmp(s1, s2, sz2);
196     return res ? res : s1[sz2];
197 }
198
199 #define EVAL(op, lft, rgt)                      \
200     ((op) == '<' ? (lft) < (rgt)                \
201      : (op) == '=' ? (lft) == (rgt)             \
202      : (op) == '>' ? (lft) > (rgt)              \
203      : (op) == '#' ? (lft) != (rgt)             \
204      : 0)
205
206 /*
207  * Evaluate compiled conditions in array NP[NCOND].
208  * Return non-zero iff they are all true.
209  * PTR points to a context object of the type that was used to compile
210  * the conditions.
211  */
212 int
213 nstr_exec(struct nscstr *np, int ncond, void *ptr)
214 {
215     int i, op, optype, cmp;
216     struct valstr lft, rgt;
217
218     for (i = 0; i < ncond; ++i) {
219         op = np[i].operator;
220         optype = np[i].optype;
221         if (np[i].lft.val_cat == NSC_NOCAT || np[i].rgt.val_cat == NSC_NOCAT)
222             return 0;
223         lft = np[i].lft;
224         nstr_exec_val(&lft, player->cnum, ptr, optype);
225         rgt = np[i].rgt;
226         nstr_exec_val(&rgt, player->cnum, ptr, optype);
227         switch (optype) {
228         case NSC_TYPEID:
229         case NSC_LONG:
230             if (!EVAL(op, lft.val_as.lng, rgt.val_as.lng))
231                 return 0;
232             break;
233         case NSC_DOUBLE:
234             if (!EVAL(op, lft.val_as.dbl, rgt.val_as.dbl))
235                 return 0;
236             break;
237         case NSC_STRING:
238             cmp = strnncmp(lft.val_as.str.base, lft.val_as.str.maxsz,
239                            rgt.val_as.str.base, rgt.val_as.str.maxsz);
240             if (!EVAL(op, cmp, 0))
241                 return 0;
242             break;
243         default:
244             CANT_HAPPEN("bad OPTYPE");
245             return 0;
246         }
247     }
248
249     return 1;
250 }
251
252 /*
253  * Parse a value in STR into VAL.
254  * Return a pointer to the first character after the value.
255  * Value is either evaluated (but not NSC_TYPEID) or an identifier.
256  */
257 static char *
258 nstr_parse_val(char *str, struct valstr *val)
259 {
260     long l;
261     double d;
262     char *tail, *tail2;
263
264     /* string */
265     if (str[0] == '\'') {
266         for (tail = str + 1; *tail && *tail != '\''; ++tail) ;
267         /* FIXME implement \ quoting */
268         val->val_type = NSC_STRING;
269         val->val_cat = NSC_VAL;
270         val->val_as.str.base = str + 1;
271         val->val_as.str.maxsz = tail - (str + 1);
272         if (*tail) ++tail;
273         return tail;
274     }
275
276     /* identifier */
277     if (isalpha(str[0])) {
278         for (tail = str+1; isalnum(*tail) || *tail == '_'; ++tail) ;
279         val->val_type = NSC_NOTYPE;
280         val->val_cat = NSC_ID;
281         val->val_as.str.base = str;
282         val->val_as.str.maxsz = tail - str;
283         return tail;
284     }
285
286     /* number */
287     l = strtol(str, &tail, 0);
288     d = strtod(str, &tail2);
289     if (tail2 > tail) {
290         val->val_type = NSC_DOUBLE;
291         val->val_cat = NSC_VAL;
292         val->val_as.dbl = d;
293         return tail2;
294     }
295     if (tail != str) {
296         val->val_type = NSC_LONG;
297         val->val_cat = NSC_VAL;
298         val->val_as.lng = l;
299         return tail;
300     }
301
302     /* funny character, interpret as identifier */
303     tail = str+1;
304     val->val_type = NSC_NOTYPE;
305     val->val_cat = NSC_ID;
306     val->val_as.str.base = str;
307     val->val_as.str.maxsz = tail - str;
308     return tail;
309 }
310
311 /*
312  * Match VAL in table of selector descriptors CA, return index.
313  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
314  * several.
315  * A VAL that is not an identifier doesn't match anything.  A null CA
316  * is considered empty.
317  */
318 static int
319 nstr_match_ca(struct valstr *val, struct castr *ca)
320 {
321     char id[32];
322
323     if (val->val_cat != NSC_ID || val->val_as.str.maxsz >= sizeof(id))
324         return M_NOTFOUND;
325
326     if (!ca)
327         return M_NOTFOUND;
328
329     memcpy(id, val->val_as.str.base, val->val_as.str.maxsz);
330     id[val->val_as.str.maxsz] = 0;
331
332     return stmtch(id, ca, offsetof(struct castr, ca_name),
333                   sizeof(struct castr));
334 }
335
336 /*
337  * Match VAL in a selector's values, return its (non-negative) value.
338  * TYPE is the context type, a file type.
339  * CA is ef_cadef(TYPE).
340  * Match values of selector descriptor CA[IDX], provided CA is not
341  * null and IDX is not negative.
342  * Return M_NOTFOUND if there are no matches, M_NOTUNIQUE if there are
343  * several.
344  * TODO: This is just a stub and works only for NSC_TYPEID.
345  * Generalize: give struct castr enough info to find values, remove
346  * parameter `type'.
347  */
348 static int
349 nstr_match_val(struct valstr *val, int type, struct castr *ca, int idx)
350 {
351     char id[32];
352
353     if (val->val_cat != NSC_ID || val->val_as.str.maxsz >= sizeof(id))
354         return M_NOTFOUND;
355
356     if (idx < 0 || ca[idx].ca_type != NSC_TYPEID)
357         return M_NOTFOUND;
358
359     memcpy(id, val->val_as.str.base, val->val_as.str.maxsz);
360     id[val->val_as.str.maxsz] = 0;
361
362     return typematch(id, type);
363 }
364
365 /*
366  * Change VAL to resolve identifier to selector or string.
367  * Return VAL on success, NULL on error.
368  * No change if VAL is not an identifier.  Otherwise, change it as
369  * follows.
370  * Error if IDX == M_NOTUNIQUE or IDX == M_NOTFOUND and !STRING_OK.
371  * Change into string if IDX == M_NOTFOUND and STRING_OK.
372  * Change into selector CA[IDX] if IDX >= 0.
373  */
374 static struct valstr *
375 nstr_resolve_id(struct valstr *val, struct castr *ca, int idx, int string_ok)
376 {
377     if (val->val_cat != NSC_ID)
378         return val;
379
380     if (idx == M_NOTUNIQUE) {
381         pr("%.*s -- ambiguous name\n",
382            (int)val->val_as.str.maxsz, val->val_as.str.base);
383         val->val_cat = NSC_NOCAT;
384         return NULL;
385     }
386
387     if (idx < 0) {
388         CANT_HAPPEN(idx != M_NOTFOUND);
389         if (!string_ok) {
390             pr("%.*s -- unkown name\n",
391                (int)val->val_as.str.maxsz, val->val_as.str.base);
392             val->val_cat = NSC_NOCAT;
393             return NULL;
394         }
395         /* interpret unbound identifier as string */
396         val->val_type = NSC_STRING;
397         val->val_cat = NSC_VAL;
398         return val;
399     }
400
401     return nstr_resolve_sel(val, &ca[idx]);
402 }
403
404 /*
405  * Change VAL to resolve identifier to selector CA.
406  * Return VAL on success, NULL if the player is denied access to the
407  * selector.
408  * VAL must be an identifier.
409  */
410 static struct valstr *
411 nstr_resolve_sel(struct valstr *val, struct castr *ca)
412 {
413     if (CANT_HAPPEN(val->val_cat != NSC_ID)) {
414         val->val_cat = NSC_NOCAT;
415         return val;
416     }
417
418     if ((ca->ca_flags & NSC_DEITY) && !player->god) {
419         pr("%.*s -- not accessible to mortals\n",
420            (int)val->val_as.str.maxsz, val->val_as.str.base);
421         val->val_cat = NSC_NOCAT;
422         return NULL;
423     }
424
425     val->val_type = ca->ca_type;
426     val->val_cat = NSC_OFF;
427     val->val_as.sym.off = ca->ca_off;
428     val->val_as.sym.len = ca->ca_len;
429     val->val_as.sym.idx = 0;
430     return val;
431 }
432
433 /*
434  * Initialize VAL to value SELVAL for selector CA, return VAL.
435  */
436 static struct valstr *
437 nstr_mkselval(struct valstr *val, int selval, struct castr *ca)
438 {
439     if (CANT_HAPPEN(ca->ca_type != NSC_TYPEID)) {
440         val->val_type = NSC_NOTYPE;
441         val->val_cat = NSC_NOCAT;
442         return val;
443     }
444
445     val->val_type = ca->ca_type;
446     val->val_cat = NSC_VAL;
447     val->val_as.lng = selval;
448     return val;
449 }
450
451 /*
452  * Compile a value in STR into VAL.
453  * Return a pointer to the first character after the value on success,
454  * NULL on error.
455  * TYPE is the context type, a file type.
456  * If STR names an array, VAL simply refers to the element with index
457  * zero.
458  */
459 char *
460 nstr_comp_val(char *str, struct valstr *val, int type)
461 {
462     struct castr *ca = ef_cadef(type);
463     char *tail = nstr_parse_val(str, val);
464     return nstr_resolve_id(val, ca, nstr_match_ca(val, ca), 0) ? tail : NULL;
465 }
466
467
468 /*
469  * Promote VALTYPE.
470  * If VALTYPE is an integer type, return NSC_LONG.
471  * If VALTYPE is a floating-point type, return NSC_DOUBLE.
472  * If VALTYPE is NSC_STRINGY, return NSC_STRING.
473  * If VALTYPE is NSC_NOTYPE, NSC_STRING or NSC_TYPEID, return VALTYPE.
474  */
475 static int
476 nstr_promote(int valtype)
477 {
478     switch (valtype) {
479     case NSC_NOTYPE:
480     case NSC_LONG:
481     case NSC_DOUBLE:
482     case NSC_STRING:
483     case NSC_TYPEID:
484         break;
485     case NSC_CHAR:
486     case NSC_UCHAR:
487     case NSC_SHORT:
488     case NSC_USHORT:
489     case NSC_INT:
490     case NSC_XCOORD:
491     case NSC_YCOORD:
492     case NSC_TIME:
493         valtype = NSC_LONG;
494         break;
495     case NSC_FLOAT:
496         valtype = NSC_DOUBLE;
497         break;
498     case NSC_STRINGY:
499         valtype = NSC_STRING;
500         break;
501     default:
502         CANT_HAPPEN("bad VALTYPE");
503         valtype = NSC_NOTYPE;
504     }
505     return valtype;
506 }
507
508 static int
509 cond_type_mismatch(char *str)
510 {
511     if (str)
512         pr("%s -- condition operand type mismatch\n", str);
513     return -1;
514 }
515
516 /*
517  * Coerce VAL to promoted value type TO.
518  * Return 0 on success, -1 on error.
519  * If VAL is evaluated, convert it, else only check.
520  * STR is the condition text to be used for error messages.  Suppress
521  * messages if it is a null pointer.
522  */
523 int
524 nstr_coerce_val(struct valstr *val, nsc_type to, char *str)
525 {
526     /* FIXME get rid of promotion?  */
527     nsc_type from = nstr_promote(val->val_type);
528
529     if (from == NSC_NOTYPE)
530         return 0;
531
532     if (from != to) {
533         switch (to) {
534         case NSC_TYPEID:
535             return cond_type_mismatch(str);
536         case NSC_STRING:
537             return cond_type_mismatch(str); /* FIXME implement */
538         case NSC_DOUBLE:
539             if (from == NSC_LONG) {
540                 if (val->val_cat == NSC_VAL)
541                     val->val_as.dbl = val->val_as.lng;
542             } else
543                 return cond_type_mismatch(str);
544             break;
545         case NSC_LONG:
546             return cond_type_mismatch(str);
547         default:
548             CANT_HAPPEN("bad TO argument");
549             to = from;
550         }
551     }
552
553     if (val->val_cat == NSC_VAL) {
554         /* coord literals don't occur, conversion not implemented */
555         CANT_HAPPEN(val->val_type == NSC_XCOORD
556                     || val->val_type == NSC_YCOORD);
557         val->val_type = to;
558     }
559
560     return 0;
561 }
562
563 /*
564  * Evaluate VAL.
565  * If VAL is symbolic, evaluate it into a promoted value type.
566  * Use coordinate system of country CNUM.
567  * PTR points to a context object of the type that was used to compile
568  * the value.
569  * Unless WANT is NSC_NOTYPE, coerce the value to promoted value type
570  * WANT.  VAL must be coercible.  That's the case if a previous
571  * nstr_coerce_val(VAL, WANT, STR) succeeded.
572  */
573 void
574 nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
575 {
576     char *memb_ptr;
577     nsc_type valtype;
578     int idx;
579
580     switch (val->val_cat) {
581     default:
582         CANT_HAPPEN("Bad VAL category");
583         /* fall through */
584     case NSC_VAL:
585         valtype = val->val_type;
586         break;
587     case NSC_OFF:
588         valtype = NSC_LONG;
589         memb_ptr = ptr;
590         memb_ptr += val->val_as.sym.off;
591         idx = val->val_as.sym.idx;
592         switch (val->val_type) {
593         case NSC_CHAR:
594             val->val_as.lng = ((signed char *)memb_ptr)[idx];
595             break;
596         case NSC_UCHAR:
597             val->val_as.lng = ((unsigned char *)memb_ptr)[idx];
598             break;
599         case NSC_SHORT:
600             val->val_as.lng = ((short *)memb_ptr)[idx];
601             break;
602         case NSC_USHORT:
603             val->val_as.lng = ((unsigned short *)memb_ptr)[idx];
604             break;
605         case NSC_INT:
606             val->val_as.lng = ((int *)memb_ptr)[idx];
607             break;
608         case NSC_LONG:
609             val->val_as.lng = ((long *)memb_ptr)[idx];
610             break;
611         case NSC_XCOORD:
612             val->val_as.lng = xrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
613             break;
614         case NSC_YCOORD:
615             val->val_as.lng = yrel(getnatp(cnum), ((short *)memb_ptr)[idx]);
616             break;
617         case NSC_FLOAT:
618             val->val_as.dbl = ((float *)memb_ptr)[idx];
619             valtype = NSC_DOUBLE;
620             break;
621         case NSC_DOUBLE:
622             val->val_as.dbl = ((double *)memb_ptr)[idx];
623             valtype = NSC_DOUBLE;
624             break;
625         case NSC_STRINGY:
626             CANT_HAPPEN(idx);
627             val->val_as.str.maxsz = val->val_as.sym.len;
628             val->val_as.str.base = (char *)memb_ptr;
629             valtype = NSC_STRING;
630             break;
631         case NSC_STRING:
632             val->val_as.str.base = ((char **)memb_ptr)[idx];
633             val->val_as.str.maxsz = INT_MAX;
634             valtype = NSC_STRING;
635             break;
636         case NSC_TIME:
637             val->val_as.lng = ((time_t *)memb_ptr)[idx];
638             break;
639         case NSC_TYPEID:
640             val->val_as.lng = ((signed char *)memb_ptr)[idx];
641             valtype = NSC_TYPEID;
642             break;
643         default:
644             CANT_HAPPEN("Bad VAL type");
645             val->val_as.lng = 0;
646         }
647         val->val_cat = NSC_VAL;
648     }
649
650     if (valtype == want)
651         ;
652     else if (want == NSC_DOUBLE) {
653         if (valtype == NSC_LONG) {
654             valtype = want;
655             val->val_as.dbl = val->val_as.lng;
656         }
657     } else if (want == NSC_STRING)
658         CANT_HAPPEN("unimplemented WANT"); /* FIXME */
659
660     if (CANT_HAPPEN(valtype != want && want != NSC_NOTYPE)) {
661         valtype = want;
662         switch (want) {
663         case NSC_TYPEID:
664         case NSC_LONG: val->val_as.lng = 0; break;
665         case NSC_DOUBLE: val->val_as.dbl = 0.0; break;
666         case NSC_STRING: val->val_as.str.base = NULL; break;
667         default:
668             CANT_HAPPEN("bad WANT argument");
669         }
670     }
671
672     val->val_type = valtype;
673 }