libamxp  1.4.0
Patterns C Implementation
amxp_expression_main.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <sys/resource.h>
60 
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <regex.h>
66 
67 #include <amxc/amxc.h>
68 #include <amxc/amxc_macros.h>
69 
70 #include "amxp_expr_priv.h"
71 #include "amxp_expr.tab.h"
72 
73 #define REGEXP_STORE_SIZE 40
74 typedef struct _amxp_expr_vfunc {
75  amxc_htable_it_t hit;
78 
79 typedef struct _amxp_expr_bfunc {
80  amxc_htable_it_t hit;
83 
84 typedef struct _amxp_regexp {
85  amxc_htable_it_t hit;
86  amxc_llist_it_t lit;
87  regex_t regexp;
89 
90 static amxc_htable_t value_funcs;
91 static amxc_htable_t bool_funcs;
92 static amxc_htable_t regexp_store;
93 static amxc_llist_t regexp_store_list;
94 
95 static void amxp_regexp_clean(amxc_llist_it_t* it) {
96  amxp_regexp_t* amxp_regexp = (amxp_regexp_t*) amxc_container_of(it, amxp_regexp_t, lit);
97  amxc_htable_it_clean(&amxp_regexp->hit, NULL);
98  regfree(&amxp_regexp->regexp);
99  free(amxp_regexp);
100 }
101 
102 static amxp_regexp_t* amxp_regexp_get(const char* regexp_str) {
103  amxp_regexp_t* regexp = NULL;
104  amxc_htable_it_t* it = amxc_htable_get(&regexp_store, regexp_str);
105  if(it != NULL) {
106  regexp = amxc_container_of(it, amxp_regexp_t, hit);
107  amxc_llist_append(&regexp_store_list, &regexp->lit);
108  }
109 
110  return regexp;
111 }
112 
113 CONSTRUCTOR static void amxp_regexp_store_init(void) {
114  amxc_llist_init(&regexp_store_list);
115  amxc_htable_init(&regexp_store, REGEXP_STORE_SIZE);
116 }
117 
118 DESTRUCTOR static void amxp_regexp_store_cleanup(void) {
119  amxc_llist_clean(&regexp_store_list, amxp_regexp_clean);
120  amxc_htable_clean(&regexp_store, NULL);
121 }
122 
123 static void amxp_expr_vfunc_hit_free(UNUSED const char* key,
124  amxc_htable_it_t* it) {
125  amxp_expr_vfunc_t* vfn = amxc_htable_it_get_data(it, amxp_expr_vfunc_t, hit);
126  free(vfn);
127 }
128 
129 static void amxp_expr_bfunc_hit_free(UNUSED const char* key,
130  amxc_htable_it_t* it) {
131  amxp_expr_bfunc_t* bfn = amxc_htable_it_get_data(it, amxp_expr_bfunc_t, hit);
132  free(bfn);
133 }
134 
136  void* buf,
137  size_t max_size) {
138  ssize_t result = 0;
139  result = amxc_rbuffer_read(&expr->rbuffer, (char*) buf, max_size);
140  errno = 0;
141 
142  return result;
143 }
144 
146  amxc_var_t* lvalue,
147  amxc_var_t* rvalue) {
148  bool retval = false;
149  amxp_regexp_t* regexp = NULL;
150  char* regexp_str = NULL;
151  char* value_str = NULL;
152 
153  regexp_str = amxc_var_dyncast(cstring_t, rvalue);
154  value_str = amxc_var_dyncast(cstring_t, lvalue);
155 
156  regexp = amxp_regexp_get(regexp_str);
157  if(regexp == NULL) {
158  regexp = (amxp_regexp_t*) calloc(1, sizeof(amxp_regexp_t));
159  when_null_status(regexp, exit, expr->status = amxp_expr_status_invalid_regexp);
160  if(regcomp(&regexp->regexp, regexp_str, REG_EXTENDED) != 0) {
162  free(regexp);
163  goto exit;
164  }
165  amxc_htable_insert(&regexp_store, regexp_str, &regexp->hit);
166  amxc_llist_append(&regexp_store_list, &regexp->lit);
167 
168  if(amxc_htable_size(&regexp_store) > REGEXP_STORE_SIZE) {
169  amxc_llist_it_t* it = amxc_llist_take_first(&regexp_store_list);
170  amxp_regexp_clean(it);
171  }
172  }
173 
174  if(regexec(&regexp->regexp, value_str, 0, NULL, 0) == 0) {
175  retval = true;
176  }
177 
178 exit:
179  free(regexp_str);
180  free(value_str);
181 
182  return retval;
183 }
184 
185 static bool amxp_expr_string_check(const char* lstr,
186  size_t llength,
187  const char* rstr,
188  size_t rlength,
189  amxp_expr_comp_t comperator) {
190  size_t offset = 0;
191  bool retval = false;
192 
193  when_true(rlength > llength, exit);
194 
195  if(comperator == amxp_expr_comp_starts_with) {
196  offset = 0;
197  } else {
198  offset = llength - rlength;
199  }
200  retval = strncmp(lstr + offset, rstr, rlength) == 0;
201 
202 exit:
203  return retval;
204 }
205 
206 static bool amxp_expr_string_head_tail_check(amxc_var_t* lvalue,
207  amxc_var_t* rvalue,
208  amxp_expr_comp_t comperator) {
209  bool retval = false;
210  char* lstr = amxc_var_dyncast(cstring_t, lvalue);
211  char* rstr = NULL;
212  size_t llength = strlen(lstr);
213 
214  if(amxc_var_type_of(rvalue) == AMXC_VAR_ID_LIST) {
215  amxc_var_for_each(var, rvalue) {
216  size_t rlength = 0;
217  rstr = amxc_var_dyncast(cstring_t, var);
218  rlength = strlen(rstr);
219  retval = amxp_expr_string_check(lstr, llength, rstr, rlength, comperator);
220  free(rstr);
221  if(retval) {
222  break;
223  }
224  }
225  } else {
226  size_t rlength = 0;
227  rstr = amxc_var_dyncast(cstring_t, rvalue);
228  rlength = strlen(rstr);
229  retval = amxp_expr_string_check(lstr, llength, rstr, rlength, comperator);
230  free(rstr);
231  }
232  free(lstr);
233  return retval;
234 }
235 
236 static bool amxp_expr_in_list(amxc_var_t* lvalue,
237  amxc_var_t* rvalue) {
238  const amxc_llist_t* list = amxc_var_constcast(amxc_llist_t, rvalue);
239  int result = 0;
240  bool retval = false;
241 
242  amxc_llist_for_each(it, list) {
243  amxc_var_t* item = amxc_var_from_llist_it(it);
244  int amxc_rv = amxc_var_compare(lvalue, item, &result);
245  if((amxc_rv == 0) && (result == 0)) {
246  retval = true;
247  break;
248  }
249  }
250 
251  return retval;
252 }
253 
254 static bool amxp_expr_in_string(amxc_var_t* lvalue,
255  amxc_var_t* rvalue) {
256  const char* string = amxc_var_constcast(cstring_t, rvalue);
257  int rlength = strlen(string);
258  char* lstr = amxc_var_dyncast(cstring_t, lvalue);
259  int llength = strlen(lstr);
260  bool retval = false;
261 
262  if(llength <= rlength) {
263  for(int i = 0; i <= rlength - llength; i++) {
264  if(strncmp(lstr, string + i, llength) == 0) {
265  retval = true;
266  break;
267  }
268  }
269  }
270 
271  free(lstr);
272  return retval;
273 }
274 
275 static bool amxp_expr_equals_ignorecase(amxc_var_t* lvalue,
276  amxc_var_t* rvalue) {
277  bool retval = false;
278  char* lvalue_str = NULL;
279  char* rvalue_str = NULL;
280 
281  lvalue_str = amxc_var_dyncast(cstring_t, lvalue);
282  rvalue_str = amxc_var_dyncast(cstring_t, rvalue);
283 
284  retval = 0 == strcasecmp(lvalue_str, rvalue_str);
285 
286  free(lvalue_str);
287  free(rvalue_str);
288 
289  return retval;
290 }
291 
292 static bool amxp_expr_is_simple_type(amxc_var_t* value) {
293  int type = amxc_var_type_of(value);
294  return !(type == AMXC_VAR_ID_HTABLE || type == AMXC_VAR_ID_LIST);
295 }
296 
297 static bool amxp_expr_are_simple_types(amxc_var_t* lvalue,
298  amxc_var_t* rvalue) {
299  return (amxp_expr_is_simple_type(lvalue) &&
300  amxp_expr_is_simple_type(rvalue));
301 }
302 
303 static bool amxp_expr_in(amxp_expr_t* expr,
304  amxc_var_t* lvalue,
305  amxc_var_t* rvalue) {
306  int rtype = amxc_var_type_of(rvalue);
307  bool retval = false;
308 
309  if(!amxp_expr_is_simple_type(lvalue)) {
311  goto exit;
312  }
313 
314  switch(rtype) {
315  case AMXC_VAR_ID_LIST:
316  retval = amxp_expr_in_list(lvalue, rvalue);
317  break;
318  case AMXC_VAR_ID_CSTRING:
319  retval = amxp_expr_in_string(lvalue, rvalue);
320  break;
321  case AMXC_VAR_ID_SSV_STRING:
322  case AMXC_VAR_ID_CSV_STRING:
323  amxc_var_cast(rvalue, AMXC_VAR_ID_LIST);
324  retval = amxp_expr_in_list(lvalue, rvalue);
325  break;
326  case AMXC_VAR_ID_BOOL:
327  if(!expr->verify) {
329  }
330  break;
331  default:
333  break;
334  }
335 
336 exit:
337  return retval;
338 }
339 
340 static bool amxp_expr_comperator(int result, amxp_expr_comp_t type) {
341  bool retval = false;
342  switch(type) {
344  retval = (result == 0);
345  break;
347  retval = (result != 0);
348  break;
350  retval = (result < 0);
351  break;
353  retval = (result > 0);
354  break;
356  retval = (result <= 0);
357  break;
359  retval = (result >= 0);
360  break;
361  default:
362  break;
363  }
364  return retval;
365 }
366 
368  amxc_var_t* args,
369  amxc_var_t* ret) {
371  amxc_var_t* data = NULL;
372  amxc_llist_for_each(it, (&args->data.vl)) {
373  data = amxc_var_from_llist_it(it);
374  if(!amxc_var_is_null(data)) {
375  break;
376  }
377  data = NULL;
378  }
379 
380  when_null(data, exit);
381  amxc_var_copy(ret, data);
382 
383  status = amxp_expr_status_ok;
384 
385 exit:
386  return status;
387 }
388 
390  amxc_var_t* args) {
391  bool retval = false;
392  amxc_llist_it_t* it = amxc_llist_get_first(&args->data.vl);
393  amxc_var_t* data = amxc_var_from_llist_it(it);
394 
395  if(amxc_var_is_null(data)) {
396  retval = true;
397  }
398 
399  if((amxc_var_type_of(data) == AMXC_VAR_ID_LIST) &&
400  amxc_llist_is_empty(&data->data.vl)) {
401  retval = true;
402  }
403 
404  if((amxc_var_type_of(data) == AMXC_VAR_ID_HTABLE) &&
405  amxc_htable_is_empty(&data->data.vm)) {
406  retval = true;
407  }
408 
409  return retval;
410 }
411 
412 static bool _bool_contains(amxp_expr_t* expr,
413  amxc_var_t* args) {
414  bool retval = false;
415  amxc_var_t* data = (amxc_var_t*) expr->priv;
416  const char* path = NULL;
417  amxc_var_t field_value;
419 
420  amxc_var_init(&field_value);
421  when_null(data, exit);
422  when_null(expr->get_field, exit);
423 
424  amxc_var_for_each(field_var, args) {
425  if(amxc_var_type_of(field_var) != AMXC_VAR_ID_CSTRING) {
426  // ignore invalid field paths - field paths must be strings
427  continue;
428  }
429  path = amxc_var_constcast(cstring_t, field_var);
430  status = expr->get_field(expr, &field_value, path, expr->priv);
431  retval = (status == amxp_expr_status_ok);
432  if(retval) {
433  // found one, we can stop
434  break;
435  }
436  }
437 
438 exit:
439  amxc_var_clean(&field_value);
440  return retval;
441 }
442 
443 static bool amxp_expr_is_safe_value(const char* string) {
444  if(string == NULL) {
445  return false;
446  }
447  for(const char* c = string; *c != '\0'; c++) {
448  bool is_whitelisted =
449  *c == ' '
450  || *c == '!'
451  || (*c >= '#' && *c <= '&')
452  || (*c >= '(' && *c <= '[')
453  || (*c >= ']' && *c <= '_')
454  || (*c >= 'a' && *c <= '~');
455  if(!is_whitelisted) {
456  return false;
457  }
458  }
459  return true;
460 }
461 
463  int yyparse_rv = 0;
464  int length = 0;
465  when_null(expr, exit);
466  when_null(expr->expression, exit);
467 
468  expr->status = amxp_expr_status_ok;
469  length = strlen(expr->expression);
470  if(length == 0) {
471  goto exit;
472  }
473  amxc_rbuffer_write(&expr->rbuffer,
474  expr->expression,
475  length);
476  if(expr->expression[length - 1] != ';') {
477  amxc_rbuffer_write(&expr->rbuffer, ";", 2);
478  }
479 
481  expr->status = amxp_expr_status_ok;
482 
483  amxp_expr_create_lex(expr);
484  yyparse_rv = yyparse(expr->scanner);
485  amxp_expr_destroy_lex(expr);
486 
487  if(yyparse_rv != 0) {
488  amxp_expr_node_t* node = NULL;
490  node = amxp_expr_node_pop(&expr->nodes);
491  while(node != NULL) {
492  amxp_expr_node_delete(&node);
493  node = amxp_expr_node_pop(&expr->nodes);
494  }
495  }
496 
497  amxc_rbuffer_clean(&expr->rbuffer);
498 
499 exit:
500  return expr->status;
501 }
502 
503 
504 void amxp_expr_msg(amxp_expr_t* expr, const char* format, ...) {
505  va_list args;
506  va_start(args, format);
507  amxc_string_vsetf(&expr->msg, format, args);
508  va_end(args);
509 }
510 
511 int amxp_expr_printf(const char* format, ...) {
512  va_list args;
513  va_start(args, format);
514  vfprintf(stderr, format, args);
515  va_end(args);
516  return 0;
517 }
518 
520  amxc_var_t* lvalue,
521  amxc_var_t* rvalue,
522  amxp_expr_comp_t comperator) {
523  int result = 0;
524  bool retval = false;
525 
526  if((comperator != amxp_expr_comp_in) &&
527  (comperator != amxp_expr_comp_starts_with) &&
528  (comperator != amxp_expr_comp_ends_with) &&
529  (comperator != amxp_expr_comp_contains)) {
530  if(!amxp_expr_are_simple_types(lvalue, rvalue)) {
532  goto exit;
533  }
534  }
535 
536  switch(comperator) {
538  retval = amxp_expr_match_regexp(expr, lvalue, rvalue);
539  break;
542  retval = amxp_expr_string_head_tail_check(lvalue, rvalue, comperator);
543  break;
544  case amxp_expr_comp_in:
545  retval = amxp_expr_in(expr, lvalue, rvalue);
546  break;
548  retval = amxp_expr_in(expr, rvalue, lvalue);
549  break;
551  retval = amxp_expr_equals_ignorecase(rvalue, lvalue);
552  break;
553  default:
554  amxc_var_compare(lvalue, rvalue, &result);
555  retval = amxp_expr_comperator(result, comperator);
556  break;
557  }
558 
559  if(expr->verify) {
560  retval = true;
561  }
562 
563 exit:
564  return retval;
565 }
566 
568  const char* func,
569  amxc_var_t* args,
570  amxc_var_t* ret) {
571  amxc_htable_it_t* it = amxc_htable_get(&value_funcs, func);
572  amxp_expr_vfunc_t* fn = amxc_htable_it_get_data(it, amxp_expr_vfunc_t, hit);
573 
575  when_null(it, exit);
576  if(expr->verify) {
577  expr->status = amxp_expr_status_ok;
578  } else {
579  expr->status = fn->fn(expr, args, ret);
580  }
581 
582 exit:
583  return expr->status;
584 }
585 
587  const char* func,
588  amxc_var_t* args) {
589  int retval = false;
590  amxc_htable_it_t* it = amxc_htable_get(&bool_funcs, func);
591  amxp_expr_bfunc_t* fn = amxc_htable_it_get_data(it, amxp_expr_bfunc_t, hit);
592 
594  when_null(it, exit);
595  expr->status = amxp_expr_status_ok;
596  if(expr->verify) {
597  retval = true;
598  } else {
599  retval = fn->fn(expr, args);
600  }
601 
602 exit:
603  return retval;
604 }
605 
607  amxc_var_t* value,
608  const char* path) {
610  amxp_expr_get_field_t fn = expr->get_field;
611 
612  amxc_var_clean(value);
613  if(expr->verify) {
614  amxc_var_set(bool, value, true);
615  retval = amxp_expr_status_ok;
616  goto exit;
617  }
618 
619  if(fn != NULL) {
620  retval = fn(expr, value, path, expr->priv);
621  }
622 
623  if(amxc_var_is_null(value)) {
625  amxp_expr_msg(expr, "Field not found - %s -", path);
626  }
627  expr->status = retval;
628 
629 exit:
630  return retval;
631 }
632 
633 amxp_expr_status_t amxp_expr_new(amxp_expr_t** expr, const char* expression) {
635  when_null(expr, exit);
636  when_null(expression, exit);
637 
638  *expr = (amxp_expr_t*) calloc(1, sizeof(amxp_expr_t));
639  when_null((*expr), exit);
640 
641  retval = amxp_expr_init(*expr, expression);
642 
643 exit:
644  if((retval != 0) && (expr != NULL) && (*expr != NULL)) {
645  amxp_expr_clean(*expr);
646  free(*expr);
647  *expr = NULL;
648  }
649  return retval;
650 }
651 
653  when_null(expr, exit);
654  when_null(*expr, exit);
655 
656  amxp_expr_clean(*expr);
657  free(*expr);
658  *expr = NULL;
659 
660 exit:
661  return;
662 }
663 
665  const char* expr_fmt,
666  va_list args) {
668  when_null(expr, exit);
669  when_null(expr_fmt, exit);
670 
671  *expr = (amxp_expr_t*) calloc(1, sizeof(amxp_expr_t));
672  when_null((*expr), exit);
673 
674  retval = amxp_expr_vbuildf(*expr, expr_fmt, args);
675 
676 exit:
677  if((retval != 0) && (expr != NULL) && (*expr != NULL)) {
678  amxp_expr_clean(*expr);
679  free(*expr);
680  *expr = NULL;
681  }
682  return retval;
683 }
684 
686  const char* expr_fmt,
687  ...) {
688  va_list args;
690  va_start(args, expr_fmt);
691  retval = amxp_expr_vbuildf_new(expr, expr_fmt, args);
692  va_end(args);
693  return retval;
694 }
695 
697  const char* expression) {
699  when_null(expr, exit);
700 
701  expr->expression = NULL;
702  expr->status = amxp_expr_status_ok;
703  expr->verify = false;
704  expr->get_field = NULL;
705  amxc_rbuffer_init(&expr->rbuffer, 0);
706  amxc_string_init(&expr->msg, 0);
707  amxc_lstack_init(&expr->nodes);
708 
709  when_null(expression, exit);
710  expr->expression = strdup(expression);
711  when_null(expr->expression, exit);
712 
713  retval = amxp_expr_parse(expr);
714  if(retval == 0) {
715  expr->verify = true;
717  expr->verify = false;
718  retval = expr->status;
719  }
720 
721 exit:
722  if((retval != amxp_expr_status_ok) && (expr != NULL)) {
723  amxp_expr_node_t* node = amxp_expr_get_node(expr);
724  free(expr->expression);
725  expr->expression = NULL;
726  amxc_lqueue_clean(&expr->nodes, NULL);
727  amxp_expr_node_delete(&node);
728  }
729  return retval;
730 }
731 
733  const char* expr_fmt,
734  va_list args) {
736  int status = -1;
737  amxc_string_t expression;
738 
739  amxc_string_init(&expression, 0);
740 
741  when_null(expr, exit);
742  when_null(expr_fmt, exit);
743 
744  memset(expr, 0, sizeof(amxp_expr_t));
745 
746  status = amxc_string_vappendf_checked(&expression, amxp_expr_is_safe_value, expr_fmt, args);
747  when_failed_status(status, exit, expr->status = amxp_expr_status_syntax_error);
748  retval = amxp_expr_init(expr, amxc_string_get(&expression, 0));
749 
750 exit:
751  amxc_string_clean(&expression);
752  return retval;
753 }
754 
756  const char* expr_fmt,
757  ...) {
758  va_list args;
760  va_start(args, expr_fmt);
761  retval = amxp_expr_vbuildf(expr, expr_fmt, args);
762  va_end(args);
763  return retval;
764 }
765 
767  amxp_expr_node_t* node = NULL;
768  when_null(expr, exit);
769 
770  free(expr->expression);
771  expr->expression = NULL;
772 
773  node = amxp_expr_get_node(expr);
774  amxp_expr_node_delete(&node);
775  amxc_lstack_clean(&expr->nodes, NULL);
776  amxc_rbuffer_clean(&expr->rbuffer);
777  amxc_string_clean(&expr->msg);
778 
779 exit:
780  return;
781 }
782 
784  amxp_expr_node_dump(expr, amxp_expr_get_node(expr), 0, 0);
785 }
786 
789  void* priv,
790  amxp_expr_status_t* status) {
791  bool rv = true;
792  amxp_expr_node_t* node = NULL;
793 
794  when_null_status(expr, exit, rv = false);
795 
796  expr->get_field = fn;
797  expr->priv = priv;
798 
799  node = amxp_expr_get_node(expr);
800  if(node == NULL) {
801  if(expr->status != amxp_expr_status_ok) {
802  rv = false;
803  }
804  } else {
805  rv = amxp_expr_node_eval(expr, node);
806  }
807 
808  if((status != NULL) && (expr != NULL)) {
809  *status = expr->status;
810  }
811 
812 exit:
813  return rv;
814 }
815 
817  return amxp_expr_evaluate(expr, NULL, NULL, status);
818 }
819 
820 int amxp_expr_add_value_fn(const char* fn_name,
822  int retval = -1;
823  amxp_expr_vfunc_t* vfn = NULL;
824 
825  if(amxc_htable_capacity(&value_funcs) == 0) {
826  amxc_htable_init(&value_funcs, 5);
827  }
828  when_true(amxc_htable_contains(&value_funcs, fn_name), exit);
829  vfn = (amxp_expr_vfunc_t*) calloc(1, sizeof(amxp_expr_vfunc_t));
830  when_null(vfn, exit);
831  vfn->fn = fn;
832  retval = amxc_htable_insert(&value_funcs, fn_name, &vfn->hit);
833 
834 exit:
835  return retval;
836 }
837 
838 int amxp_expr_add_bool_fn(const char* fn_name,
840  int retval = -1;
841  amxp_expr_bfunc_t* bfn = NULL;
842 
843  if(amxc_htable_capacity(&bool_funcs) == 0) {
844  amxc_htable_init(&bool_funcs, 5);
845  }
846 
847  when_true(amxc_htable_contains(&bool_funcs, fn_name), exit);
848  bfn = (amxp_expr_bfunc_t*) calloc(1, sizeof(amxp_expr_bfunc_t));
849  when_null(bfn, exit);
850  bfn->fn = fn;
851  retval = amxc_htable_insert(&bool_funcs, fn_name, &bfn->hit);
852 
853 exit:
854  return retval;
855 }
856 
857 const char* amxp_expr_get_string(amxp_expr_t* expr) {
858  return expr ? expr->expression : NULL;
859 }
860 
861 CONSTRUCTOR_LVL(101) static void amxp_expr_functions_init(void) {
862  amxp_expr_add_value_fn("first_existing", _value_first_of);
865 }
866 
867 DESTRUCTOR_LVL(101) static void amxp_expr_functions_cleanup(void) {
868  amxc_htable_clean(&value_funcs, amxp_expr_vfunc_hit_free);
869  amxc_htable_clean(&bool_funcs, amxp_expr_bfunc_hit_free);
870 }
PRIVATE void amxp_expr_create_lex(amxp_expr_t *expr)
PRIVATE amxp_expr_node_t * amxp_expr_get_node(amxp_expr_t *expr)
enum _amxp_expr_comp amxp_expr_comp_t
PRIVATE void amxp_expr_node_delete(amxp_expr_node_t **node)
PRIVATE void amxp_expr_node_dump(amxp_expr_t *expr, amxp_expr_node_t *node, uint32_t level, uint32_t parent_id)
PRIVATE void amxp_expr_destroy_lex(amxp_expr_t *expr)
PRIVATE amxp_expr_node_t * amxp_expr_node_pop(amxc_lstack_t *stack)
PRIVATE bool amxp_expr_node_eval(amxp_expr_t *expr, amxp_expr_node_t *node)
@ amxp_expr_comp_bigger_equal
@ amxp_expr_comp_ends_with
@ amxp_expr_comp_in
@ amxp_expr_comp_starts_with
@ amxp_expr_comp_lesser
@ amxp_expr_comp_matches
@ amxp_expr_comp_equal
@ amxp_expr_comp_bigger
@ amxp_expr_comp_equals_ignorecase
@ amxp_expr_comp_not_equal
@ amxp_expr_comp_contains
@ amxp_expr_comp_lesser_equal
static bool amxp_expr_in_string(amxc_var_t *lvalue, amxc_var_t *rvalue)
struct _amxp_expr_vfunc amxp_expr_vfunc_t
static bool amxp_expr_equals_ignorecase(amxc_var_t *lvalue, amxc_var_t *rvalue)
static bool amxp_expr_string_head_tail_check(amxc_var_t *lvalue, amxc_var_t *rvalue, amxp_expr_comp_t comperator)
static bool amxp_expr_in_list(amxc_var_t *lvalue, amxc_var_t *rvalue)
void amxp_expr_msg(amxp_expr_t *expr, const char *format,...)
amxp_expr_status_t amxp_expr_buildf_new(amxp_expr_t **expr, const char *expr_fmt,...)
static void amxp_expr_bfunc_hit_free(UNUSED const char *key, amxc_htable_it_t *it)
struct _amxp_regexp amxp_regexp_t
DESTRUCTOR_LVL(101)
static bool _bool_contains(amxp_expr_t *expr, amxc_var_t *args)
int amxp_expr_printf(const char *format,...)
static bool amxp_expr_in(amxp_expr_t *expr, amxc_var_t *lvalue, amxc_var_t *rvalue)
static void amxp_expr_vfunc_hit_free(UNUSED const char *key, amxc_htable_it_t *it)
bool amxp_expr_compare(amxp_expr_t *expr, amxc_var_t *lvalue, amxc_var_t *rvalue, amxp_expr_comp_t comperator)
static bool amxp_expr_is_simple_type(amxc_var_t *value)
static bool amxp_expr_is_safe_value(const char *string)
static amxc_htable_t value_funcs
static amxp_expr_status_t _value_first_of(UNUSED amxp_expr_t *expr, amxc_var_t *args, amxc_var_t *ret)
static void amxp_regexp_clean(amxc_llist_it_t *it)
static amxp_expr_status_t amxp_expr_parse(amxp_expr_t *expr)
static amxc_htable_t bool_funcs
static ssize_t amxp_expr_string_reader(amxp_expr_t *expr, void *buf, size_t max_size)
amxp_expr_status_t amxp_expr_call_value_func(amxp_expr_t *expr, const char *func, amxc_var_t *args, amxc_var_t *ret)
static bool amxp_expr_are_simple_types(amxc_var_t *lvalue, amxc_var_t *rvalue)
static bool _bool_is_empty(UNUSED amxp_expr_t *expr, amxc_var_t *args)
static amxc_htable_t regexp_store
struct _amxp_expr_bfunc amxp_expr_bfunc_t
static amxp_regexp_t * amxp_regexp_get(const char *regexp_str)
static DESTRUCTOR void amxp_regexp_store_cleanup(void)
amxp_expr_status_t amxp_expr_get_field(amxp_expr_t *expr, amxc_var_t *value, const char *path)
amxp_expr_status_t amxp_expr_buildf(amxp_expr_t *expr, const char *expr_fmt,...)
static CONSTRUCTOR void amxp_regexp_store_init(void)
static bool amxp_expr_match_regexp(amxp_expr_t *expr, amxc_var_t *lvalue, amxc_var_t *rvalue)
CONSTRUCTOR_LVL(101)
static bool amxp_expr_comperator(int result, amxp_expr_comp_t type)
static bool amxp_expr_string_check(const char *lstr, size_t llength, const char *rstr, size_t rlength, amxp_expr_comp_t comperator)
bool amxp_expr_call_bool_func(amxp_expr_t *expr, const char *func, amxc_var_t *args)
#define REGEXP_STORE_SIZE
static amxc_llist_t regexp_store_list
#define UNUSED
Definition: main.c:68
const char * amxp_expr_get_string(amxp_expr_t *expr)
Returns the string representation of the given expression.
amxp_expr_status_t amxp_expr_new(amxp_expr_t **expr, const char *expression)
Allocates and initializes an expression.
bool amxp_expr_eval(amxp_expr_t *expr, amxp_expr_status_t *status)
Evaluates an expression.
amxp_expr_status_t amxp_expr_vbuildf(amxp_expr_t *expr, const char *expr_fmt, va_list args)
va_list version of amxp_expr_buildf
void amxp_expr_clean(amxp_expr_t *expr)
Clean-up the expression structure.
amxp_expr_status_t amxp_expr_vbuildf_new(amxp_expr_t **expr, const char *expr_fmt, va_list args)
va_list version of amxp_expr_buildf_new
amxp_expr_status_t(* amxp_expr_get_field_t)(amxp_expr_t *expr, amxc_var_t *value, const char *path, void *priv)
Field fetcher function signature.
bool(* amxp_expr_bool_func_t)(amxp_expr_t *expr, amxc_var_t *args)
Callback function that evaluates to true or false.
int amxp_expr_add_value_fn(const char *fn_name, amxp_expr_value_func_t fn)
Adds a value calculation function.
amxp_expr_status_t(* amxp_expr_value_func_t)(amxp_expr_t *expr, amxc_var_t *args, amxc_var_t *ret)
Callback function that can "calculate" a value.
amxp_expr_status_t amxp_expr_init(amxp_expr_t *expr, const char *expression)
Initializes an expression structure.
bool amxp_expr_evaluate(amxp_expr_t *expr, amxp_expr_get_field_t fn, void *priv, amxp_expr_status_t *status)
Evaluates an expression.
int amxp_expr_add_bool_fn(const char *fn_name, amxp_expr_bool_func_t fn)
Adds a boolean evaluation function.
void amxp_expr_dump_tree(amxp_expr_t *expr)
Dumps the binary tree in dot formatted text file to stdout.
enum _expr_status amxp_expr_status_t
Expression status/error codes.
void amxp_expr_delete(amxp_expr_t **expr)
Deletes a previously allocated expression structure.
@ amxp_expr_status_syntax_error
@ amxp_expr_status_invalid_value
@ amxp_expr_status_field_not_found
@ amxp_expr_status_unknown_error
@ amxp_expr_status_ok
@ amxp_expr_status_function_not_found
@ amxp_expr_status_invalid_regexp
amxp_expr_bool_func_t fn
amxc_htable_it_t hit
amxp_expr_value_func_t fn
amxc_htable_it_t hit
char * expression
amxc_rbuffer_t rbuffer
amxp_expr_get_field_t get_field
amxp_expr_reader_t reader
amxc_string_t msg
amxc_lstack_t nodes
amxp_expr_status_t status
amxc_llist_it_t lit
amxc_htable_it_t hit
static amxc_string_t path