17 error (EXIT_FAILURE, 0, "%s", "memory exhausted");
19 /* The `noreturn' cannot be given to error, since it may return if
20 its first argument is 0. To help compilers understand the
21 xalloc_die does not return, call abort. Also, the abort is a
22 safety feature if exit_failure is 0 (which shouldn't happen). */
26 /* Allocate N bytes of memory dynamically, with error checking. */
36 /* Change the size of an allocated block of memory P to N bytes,
37 with error checking. */
39 xrealloc (void *p, size_t n)
47 /* Clone an object P of size S, with error checking. There's no need
48 for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
49 need for an arithmetic overflow check. */
51 xmemdup (void const *p, size_t s)
53 return memcpy (xmalloc (s), p, s);
58 xstrdup (char const *string)
60 return xmemdup (string, strlen (string) + 1);
63 /* TBD: use separate function to parse dates differently */
65 make_number (char *text)
67 value_t *tmp = malloc(sizeof(*tmp));
71 tmp->as_num = strtoll(text,NULL,10);
78 make_string (char *text, type_t t)
80 value_t *tmp = malloc(sizeof(*tmp));
84 tmp->as_str = xstrdup(text);
91 make_tree (type_t t, value_t *left, value_t *right)
93 value_t *tmp = malloc(sizeof(*tmp));
97 tmp->as_tree.left = left;
98 tmp->as_tree.right = right;
105 make_comp (comp_t c, value_t *left, value_t *right)
107 value_t *tmp = make_tree(T_COMP,left,right);
116 #if defined(UNIT_TEST)
117 struct { char *name; char *value; } hacked_obj_fields[] = {
118 { "a", "2" }, { "b", "7" }, { "c", "11" },
123 unit_oget_func (void * notused, char *text)
127 for (i = 0; hacked_obj_fields[i].name; ++i) {
128 if (!strcmp(hacked_obj_fields[i].name,text)) {
129 return hacked_obj_fields[i].value;
135 getter_t unit_oget = { unit_oget_func };
138 unit_sget_func (void * notused, char *text)
142 getter_t unit_sget = { unit_sget_func };
146 string_value (value_t *v, getter_t *oget, getter_t *sget)
152 return oget ? CALL_GETTER(oget,v->as_str) : "";
154 return sget ? CALL_GETTER(sget,v->as_str) : "";
161 is_ok_number (char *a_str)
169 for (p = a_str; *p; ++p) {
179 compare (value_t *left, comp_t op, value_t *right,
180 getter_t *oget, getter_t *sget)
184 int lval = 0; // solely to placate gcc
188 lstr = string_value(left,oget,sget);
189 rstr = string_value(right,oget,sget);
191 if (left->type == T_NUMBER) {
195 if (is_ok_number(lstr)) {
196 lval = strtoll(lstr,NULL,0);
203 lval = eval(left,oget,sget);
209 if (right->type == T_NUMBER) {
210 rval = right->as_num;
213 if (is_ok_number(rstr)) {
214 rval = strtoll(rstr,NULL,0);
221 rval = eval(right,oget,sget);
228 if (!lstr || !rstr) {
231 lval = strcmp(lstr,rstr);
236 case C_LESSTHAN: return (lval < rval);
237 case C_LESSOREQ: return (lval <= rval);
238 case C_EQUAL: return (lval == rval);
239 case C_DIFFERENT: return (lval != rval);
240 case C_GREATEROREQ: return (lval >= rval);
241 case C_GREATERTHAN: return (lval > rval);
248 _print_value (value_t *v, int level)
251 printf("%*sNULL\n",level,"");
257 printf("%*sNUMBER %lld\n",level,"",v->as_num);
260 printf("%*sSTRING %s\n",level,"",v->as_str);
263 #if defined(UNIT_TEST)
264 printf("%*sOBJECT FIELD %s (%s)\n",level,"",v->as_str,
265 unit_oget_func(NULL,v->as_str));
267 printf("%*sOBJECT FIELD %s\n",level,"",v->as_str);
271 #if defined(UNIT_TEST)
272 printf("%*sSERVER FIELD %s (%s)\n",level,"",v->as_str,
273 unit_sget_func(NULL,v->as_str));
275 printf("%*sSERVER FIELD %s\n",level,"",v->as_str);
279 printf("%*sCOMPARISON\n",level,"");
280 _print_value(v->as_tree.left,level+2);
281 _print_value(v->as_tree.right,level+2);
284 printf("%*sNOT\n",level,"");
285 _print_value(v->as_tree.left,level+2);
288 printf("%*sAND\n",level,"");
289 _print_value(v->as_tree.left,level+2);
290 _print_value(v->as_tree.right,level+2);
293 printf("%*sOR\n",level,"");
294 _print_value(v->as_tree.left,level+2);
295 _print_value(v->as_tree.right,level+2);
298 printf("%*sUNKNOWN %d\n",level,"",v->type);
303 print_value (value_t *v)
309 free_value (value_t *v)
326 free_value(v->as_tree.right);
329 free_value(v->as_tree.left);
337 eval (value_t *v, getter_t *oget, getter_t *sget)
343 return v->as_num != 0;
349 return compare(v->as_tree.left,(comp_t)v->as_tree.op,
350 v->as_tree.right, oget, sget);
352 res = eval(v->as_tree.left,oget,sget);
353 return (res >= 0) ? !res : res;
355 res = eval(v->as_tree.left,oget,sget);
357 res = eval(v->as_tree.right,oget,sget);
361 res = eval(v->as_tree.left,oget,sget);
365 return eval(v->as_tree.right,oget,sget);
371 #define YY_INPUT(buf,result,max) { \
372 result = (arg_off < arg_len) ? (*buf = arg_buf[arg_off++], 1) \
373 : (arg_off == arg_len) ? (*buf = '\n', ++arg_off, 1) : 0; \
376 #define YYSTYPE value_t *
379 Stmt = - BoolExpr EOL { *cur_expr = $$; }
382 BoolExpr = l:CompExpr ( - ( AND - r:CompExpr ) { $$ = make_tree(T_AND,l,r); }
383 | - ( OR - r:CompExpr ) { $$ = make_tree(T_OR,l,r); } )* -
386 ( ( LESS - r:Unary { $$ = make_comp(C_LESSTHAN,l,r); } )
387 | ( LESS EQUAL - r:Unary { $$ = make_comp(C_LESSOREQ,l,r); } )
388 | ( EQUAL EQUAL - r:Unary { $$ = make_comp(C_EQUAL,l,r); } )
389 | ( NOT EQUAL - r:Unary { $$ = make_comp(C_DIFFERENT,l,r); } )
390 | ( GREATER EQUAL - r:Unary { $$ = make_comp(C_GREATEROREQ,l,r); } )
391 | ( GREATER - r:Unary { $$ = make_comp(C_GREATERTHAN,l,r); } ) )? -
394 | NOT - e:Atom - { $$ = make_tree(T_NOT,e,NULL); }
395 | NOT - e:Unary - { $$ = make_tree(T_NOT,e,NULL); }
397 Atom = ( Literal | Field | ParenExpr ) -
399 Literal = NUMBER | STRING | TIME
401 Field = DOLLAR i:ID { $$ = make_string((char *)$$,T_OFIELD); }
402 | WAFFLE i:ID { $$ = make_string((char *)$$,T_SFIELD); }
404 ParenExpr = OPEN v:BoolExpr CLOSE - { $$ = v; }
406 NUMBER = < [0-9]+ > { $$= make_number(yytext); }
407 STRING = '"' < [^"]* > '"' { $$ = make_string(yytext,T_STRING); }
408 TIME = '~' < [^~]* > '~' { $$ = make_number(yytext); }
409 ID = < [a-z_]+ > { $$ = (YYSTYPE)yytext; }
422 EOL = '\n' | '\r\n' | '\r' | ';'
429 value_t *expr = NULL;
432 arg_len = strlen(text);
442 #if defined(UNIT_TEST)
444 main (int argc, char **argv)
449 for (i = 1; i < argc; ++i) {
450 expr = parse(argv[i]);
453 printf("= %d\n",eval(expr,&unit_oget,&unit_sget));
456 printf("could not parse '%s'\n",argv[i]);