libamxp  1.4.0
Patterns C Implementation
amxp_expression_var.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 
72 typedef struct _var_collector {
73  amxc_string_t* path;
74  const amxc_var_t* var;
75  amxc_llist_it_t it;
77 
78 static void var_collector_it_free(amxc_llist_it_t* it) {
79  var_collector_t* c = amxc_container_of(it, var_collector_t, it);
80  amxc_string_delete(&c->path);
81  free(c);
82 }
83 
85  const amxc_var_t* var,
86  amxc_llist_t* vars) {
87  var_collector_t* c = (var_collector_t*) calloc(1, sizeof(var_collector_t));
88  when_null(c, exit);
89  amxc_string_new(&c->path, 0);
90  amxc_string_setf(c->path, "%s", path);
91  c->var = var;
92 
93  amxc_llist_append(vars, &c->it);
94 
95 exit:
96  return c;
97 }
98 
99 static void var_path_add(amxc_string_t* path, const char* name, uint32_t index) {
100  const char* sep = amxc_string_is_empty(path) ? "" : ".";
101  if(name != NULL) {
102  amxc_string_appendf(path, "%s'%s'", sep, name);
103  } else {
104  amxc_string_appendf(path, "%s%d", sep, index);
105  }
106 }
107 
108 static void var_update_entry(var_collector_t* c, const char* token) {
109  int index = 0;
110  bool isindex = false;
111  char* endptr = NULL;
112  amxc_var_t* temp = NULL;
113 
114  index = strtol(token, &endptr, 0);
115  if(*endptr == 0) {
116  temp = amxc_var_get_index(c->var, index, AMXC_VAR_FLAG_DEFAULT);
117  }
118  if(temp == NULL) {
119  temp = amxc_var_get_key(c->var, token, AMXC_VAR_FLAG_DEFAULT);
120  } else {
121  isindex = true;
122  }
123 
124  if(temp != NULL) {
125  c->var = temp;
126  var_path_add(c->path, isindex ? NULL : token, index);
127  } else {
128  amxc_llist_it_take(&c->it);
130  }
131 }
132 
133 static void var_add_filtered_entry(amxc_var_t* item,
134  const char* base_path,
135  const char* token,
136  amxp_expr_t* expr,
137  amxc_llist_t* new_entries,
138  const char* name,
139  uint32_t index) {
140  var_collector_t* nc = NULL;
141 
142  if(token[0] == '*') {
143  nc = var_collector_new(base_path, item, new_entries);
144  var_path_add(nc->path, name, index);
145  } else {
146  if(amxp_expr_eval_var(expr, item, NULL)) {
147  nc = var_collector_new(base_path, item, new_entries);
148  var_path_add(nc->path, name, index);
149  }
150  }
151 }
152 
154  amxc_llist_t* new_entries,
155  const char* token) {
156  const amxc_llist_t* items = amxc_var_constcast(amxc_llist_t, current->var);
157  const char* base = amxc_string_get(current->path, 0);
158  uint32_t index = 0;
159  amxp_expr_t expr;
160 
161  if(token[0] == '[') {
162  amxp_expr_init(&expr, token + 1);
163  }
164  amxc_llist_iterate(it, items) {
165  amxc_var_t* item = amxc_var_from_llist_it(it);
166  if(index != 0) {
167  var_add_filtered_entry(item, base, token, &expr, new_entries, NULL, index);
168  }
169  index++;
170  }
171 
172  if(token[0] == '*') {
173  var_path_add(current->path, NULL, 0);
174  current->var = amxc_var_get_index(current->var, 0, AMXC_VAR_FLAG_DEFAULT);
175  } else {
176  amxc_var_t* item = amxc_var_get_index(current->var, 0, AMXC_VAR_FLAG_DEFAULT);
177  if(!amxp_expr_eval_var(&expr, item, NULL)) {
178  amxc_llist_it_take(&current->it);
180  } else {
181  var_path_add(current->path, NULL, 0);
182  current->var = item;
183  }
184  }
185 
186  if(token[0] == '[') {
187  amxp_expr_clean(&expr);
188  }
189 }
190 
192  amxc_llist_t* new_entries,
193  const char* token) {
194  const amxc_htable_t* items = amxc_var_constcast(amxc_htable_t, current->var);
195  const char* first = NULL;
196  const char* base = amxc_string_get(current->path, 0);
197  amxp_expr_t expr;
198 
199  if(token[0] == '[') {
200  amxp_expr_init(&expr, token + 1);
201  }
202 
203  amxc_htable_iterate(it, items) {
204  const char* name = amxc_htable_it_get_key(it);
205  amxc_var_t* item = amxc_var_from_htable_it(it);
206  if(first != NULL) {
207  var_add_filtered_entry(item, base, token, &expr, new_entries, name, 0);
208  } else {
209  first = name;
210  }
211  }
212 
213  if(token[0] == '*') {
214  var_path_add(current->path, first, 0);
215  current->var = amxc_var_get_key(current->var, first, AMXC_VAR_FLAG_DEFAULT);
216  } else {
217  amxc_var_t* item = amxc_var_get_key(current->var, first, AMXC_VAR_FLAG_DEFAULT);
218  if(!amxp_expr_eval_var(&expr, item, NULL)) {
219  amxc_llist_it_take(&current->it);
221  } else {
222  var_path_add(current->path, first, 0);
223  current->var = item;
224  }
225  }
226 
227  if(token[0] == '[') {
228  amxp_expr_clean(&expr);
229  }
230 }
231 
233  amxc_llist_t* new_entries,
234  const char* token) {
235 
236  if((amxc_var_type_of(current->var) != AMXC_VAR_ID_HTABLE) &&
237  ( amxc_var_type_of(current->var) != AMXC_VAR_ID_LIST)) {
238  amxc_llist_it_take(&current->it);
240  goto exit;
241  }
242 
243  if(amxc_var_type_of(current->var) == AMXC_VAR_ID_LIST) {
244  var_update_filtered_list(current, new_entries, token);
245  } else {
246  var_update_filtered_table(current, new_entries, token);
247  }
248 
249 exit:
250  return;
251 }
252 
253 static void var_update_collection(amxc_llist_t* vars, amxc_string_t* part) {
254  size_t len = amxc_string_text_length(part);
255  uint32_t offset = 0;
256  char* token = amxc_string_take_buffer(part);
257  amxc_llist_t new_entries;
258  amxc_llist_init(&new_entries);
259 
260  if((token[0] == '\'') || (token[0] == '"') || (token[0] == '[')) {
261  token[len - 1] = 0;
262  offset = 1;
263  }
264 
265  amxc_llist_for_each(it1, vars) {
266  var_collector_t* c = amxc_container_of(it1, var_collector_t, it);
267 
268  if((token[0] == '*') || (token[0] == '[')) {
269  var_update_filtered(c, &new_entries, token);
270  } else {
271  var_update_entry(c, token + offset);
272  }
273 
274  c = NULL;
275  }
276 
277  amxc_llist_for_each(it2, &new_entries) {
278  amxc_llist_append(vars, it2);
279  }
280 
281  free(token);
282 }
283 
284 static void var_collect(amxc_llist_t* vars, amxc_llist_t* parts) {
285  amxc_llist_for_each(it, parts) {
286  amxc_string_t* part = amxc_container_of(it, amxc_string_t, it);
287  var_update_collection(vars, part);
288  amxc_string_delete(&part);
289  }
290 }
291 
292 static int var_build_parts(amxc_llist_t* parts, const char* path) {
293  int retval = 0;
294  amxc_string_t search_path;
295  amxc_string_init(&search_path, 0);
296 
297  amxc_string_set(&search_path, path);
298  amxc_string_trim(&search_path, NULL);
299 
300  retval = amxc_string_split_to_llist(&search_path, parts, '.');
301  when_failed(retval, exit);
302  if((search_path.buffer != NULL) && (search_path.buffer[0] == '[')) {
303  amxc_string_t* fp = amxc_string_from_llist_it(amxc_llist_get_first(parts));
304  if((fp != NULL) && (fp->buffer != NULL) && (fp->buffer[0] != '[')) {
305  amxc_string_prepend(fp, "[", 1);
306  amxc_string_append(fp, "]", 1);
307  }
308  }
309 
310 exit:
311  amxc_string_clean(&search_path);
312  return retval;
313 }
314 
316  const amxc_var_t* const data,
317  amxp_expr_status_t* status) {
318  bool rv = false;
319  when_null(data, exit);
320  when_true(amxc_var_type_of(data) != AMXC_VAR_ID_HTABLE, exit);
321 
322  rv = amxp_expr_evaluate(expr, amxp_expr_get_field_var, (void*) data, status);
323 
324 exit:
325  return rv;
326 }
327 
329  amxc_var_t* value,
330  const char* path,
331  void* priv) {
333  amxc_var_t* data = (amxc_var_t*) priv;
334  amxc_var_t* field = NULL;
335 
336  if(path && (path[0] == '.')) {
337  field = amxc_var_get_path(data, path + 1, AMXC_VAR_FLAG_DEFAULT);
338  } else {
339  field = amxc_var_get_path(data, path, AMXC_VAR_FLAG_DEFAULT);
340  }
341  if(amxc_var_copy(value, field) == 0) {
342  status = amxp_expr_status_ok;
343  }
344 
345  return status;
346 }
347 
348 int amxp_expr_find_var_paths(const amxc_var_t* const var,
349  amxc_llist_t* paths,
350  const char* path) {
351  int retval = 0;
352  amxc_llist_t parts;
353  amxc_llist_t vars;
354 
355  amxc_llist_init(&parts);
356  amxc_llist_init(&vars);
357 
358  when_null(var, exit);
359  when_null(paths, exit);
360  when_str_empty(path, exit);
361 
362  retval = var_build_parts(&parts, path);
363  when_failed(retval, exit);
364  var_collector_new("", var, &vars);
365  var_collect(&vars, &parts);
366 
367  amxc_llist_for_each(it, &vars) {
368  var_collector_t* c = amxc_container_of(it, var_collector_t, it);
369  amxc_llist_append(paths, &c->path->it);
370  c->path = NULL;
371  }
372 
373 exit:
374  amxc_llist_clean(&parts, amxc_string_list_it_free);
375  amxc_llist_clean(&vars, var_collector_it_free);
376  return retval;
377 }
378 
379 int amxp_expr_find_var_values(const amxc_var_t* const var,
380  amxc_htable_t* values,
381  const char* path) {
382  int retval = 0;
383  amxc_llist_t parts;
384  amxc_llist_t vars;
385 
386  amxc_llist_init(&parts);
387  amxc_llist_init(&vars);
388 
389  when_null(var, exit);
390  when_null(values, exit);
391  when_str_empty(path, exit);
392 
393  retval = var_build_parts(&parts, path);
394  when_failed(retval, exit);
395  var_collector_new("", var, &vars);
396  var_collect(&vars, &parts);
397 
398  amxc_llist_for_each(it, &vars) {
399  var_collector_t* c = amxc_container_of(it, var_collector_t, it);
400  amxc_var_t* value = NULL;
401  amxc_var_new(&value);
402  amxc_var_copy(value, c->var);
403  amxc_htable_insert(values, amxc_string_get(c->path, 0), &value->hit);
404  }
405 
406 exit:
407  amxc_llist_clean(&parts, amxc_string_list_it_free);
408  amxc_llist_clean(&vars, var_collector_it_free);
409  return retval;
410 }
411 
412 amxc_var_t* amxp_expr_find_var(const amxc_var_t* const var,
413  const char* path) {
414  const amxc_var_t* retval = NULL;
415  int rv = 0;
416  var_collector_t* first = NULL;
417  amxc_llist_t parts;
418  amxc_llist_t vars;
419 
420  amxc_llist_init(&parts);
421  amxc_llist_init(&vars);
422 
423  when_null(var, exit);
424  when_str_empty(path, exit);
425 
426  rv = var_build_parts(&parts, path);
427  when_failed(rv, exit);
428 
429  var_collector_new("", var, &vars);
430  var_collect(&vars, &parts);
431 
432  if(amxc_llist_is_empty(&vars)) {
433  goto exit;
434  }
435 
436  first = amxc_container_of(amxc_llist_get_first(&vars), var_collector_t, it);
437  if((first == NULL) || (amxc_llist_it_get_next(&first->it) != NULL)) {
438  goto exit;
439  }
440 
441  retval = first->var;
442 
443 exit:
444  amxc_llist_clean(&parts, amxc_string_list_it_free);
445  amxc_llist_clean(&vars, var_collector_it_free);
446  return (amxc_var_t*) retval;
447 }
static void var_update_filtered_table(var_collector_t *current, amxc_llist_t *new_entries, const char *token)
static int var_build_parts(amxc_llist_t *parts, const char *path)
static void var_collector_it_free(amxc_llist_it_t *it)
static void var_update_filtered(var_collector_t *current, amxc_llist_t *new_entries, const char *token)
static void var_add_filtered_entry(amxc_var_t *item, const char *base_path, const char *token, amxp_expr_t *expr, amxc_llist_t *new_entries, const char *name, uint32_t index)
struct _var_collector var_collector_t
static var_collector_t * var_collector_new(const char *path, const amxc_var_t *var, amxc_llist_t *vars)
static void var_path_add(amxc_string_t *path, const char *name, uint32_t index)
static void var_update_filtered_list(var_collector_t *current, amxc_llist_t *new_entries, const char *token)
amxp_expr_status_t amxp_expr_get_field_var(UNUSED amxp_expr_t *expr, amxc_var_t *value, const char *path, void *priv)
static void var_update_entry(var_collector_t *c, const char *token)
static void var_update_collection(amxc_llist_t *vars, amxc_string_t *part)
static void var_collect(amxc_llist_t *vars, amxc_llist_t *parts)
static struct timeval current
Definition: amxp_timer.c:66
static struct event_base * base
Definition: main.c:70
#define UNUSED
Definition: main.c:68
int amxp_expr_find_var_values(const amxc_var_t *const var, amxc_htable_t *values, const char *path)
Search matching variant paths in a composite variant.
bool amxp_expr_eval_var(amxp_expr_t *expr, const amxc_var_t *const data, amxp_expr_status_t *status)
Evaluates an expression against a composite variant.
void amxp_expr_clean(amxp_expr_t *expr)
Clean-up the expression structure.
int amxp_expr_find_var_paths(const amxc_var_t *const var, amxc_llist_t *paths, const char *path)
Search matching variant paths in a composite variant.
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.
amxc_var_t * amxp_expr_find_var(const amxc_var_t *const var, const char *path)
Search a matching variant and returns a pointer to that variant.
enum _expr_status amxp_expr_status_t
Expression status/error codes.
@ amxp_expr_status_unknown_error
@ amxp_expr_status_ok
amxc_llist_it_t it
const amxc_var_t * var
amxc_string_t * path
static amxc_string_t path