libamxo  4.3.4
Object Definition Language (ODL) parsing
amxo_parser_include.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 #ifndef _GNU_SOURCE
55 #define _GNU_SOURCE
56 #endif
57 
58 #include "amxo_parser_priv.h"
59 #include "amxo_parser_hooks_priv.h"
60 #include "amxo_parser.tab.h"
61 
62 static void amxo_parser_push(amxo_parser_t* parent,
63  amxo_parser_t* child) {
64  child->resolvers = parent->resolvers;
65  child->hooks = parent->hooks;
66  child->include_stack = parent->include_stack;
67  child->entry_points = parent->entry_points;
68  child->post_includes = parent->post_includes;
69  child->parent = parent;
70  child->sync_contexts = parent->sync_contexts;
71  amxc_var_copy(&child->config, &parent->config);
72 }
73 
74 static void amxo_parser_pop(amxo_parser_t* parent,
75  amxo_parser_t* child) {
76  parent->resolvers = child->resolvers;
77  parent->entry_points = child->entry_points;
78  parent->post_includes = child->post_includes;
79  parent->sync_contexts = child->sync_contexts;
80  amxc_llist_move(&parent->event_list, &child->event_list);
81  amxc_llist_move(&parent->function_names, &child->function_names);
82  child->include_stack = NULL;
83  child->hooks = NULL;
84  child->resolvers = NULL;
85  child->entry_points = NULL;
86  child->post_includes = NULL;
87  child->parent = NULL;
88  child->sync_contexts = NULL;
89  amxc_llist_for_each(it, (&child->global_config)) {
90  amxc_string_t* str_name = amxc_string_from_llist_it(it);
91  const char* name = amxc_string_get(str_name, 0);
92  amxc_var_t* option = amxc_var_get_path(&child->config,
93  name,
94  AMXC_VAR_FLAG_DEFAULT);
95  if(!amxc_var_is_null(option)) {
96  amxc_var_set_path(&parent->config, name, option, AMXC_VAR_FLAG_UPDATE | AMXC_VAR_FLAG_AUTO_ADD);
97  amxc_llist_append(&parent->global_config, &str_name->it);
98  }
99  }
100 }
101 
102 static amxc_var_t* amxo_parser_can_include(amxo_parser_t* pctx,
103  const char* full_path) {
104  amxc_var_t* incstack = NULL;
105  if(amxc_var_get_key(pctx->include_stack, full_path, AMXC_VAR_FLAG_DEFAULT) != NULL) {
106  goto exit;
107  }
108  if(pctx->include_stack == NULL) {
109  amxc_var_new(&pctx->include_stack);
110  amxc_var_set_type(pctx->include_stack, AMXC_VAR_ID_HTABLE);
111  }
112  incstack = amxc_var_add_key(bool, pctx->include_stack, full_path, true);
113 
114 exit:
115  return incstack;
116 }
117 
118 static bool amxo_parser_exists(const char* incdir,
119  const char* file_path,
120  char** full_path) {
121  bool retval = false;
122  amxc_string_t concat_path;
123  amxc_string_init(&concat_path, 0);
124 
125  if((incdir != NULL) && (*incdir != 0)) {
126  amxc_string_setf(&concat_path, "%s/%s", incdir, file_path);
127  } else {
128  amxc_string_setf(&concat_path, "%s", file_path);
129  }
130  *full_path = realpath(amxc_string_get(&concat_path, 0), NULL);
131  if(*full_path != NULL) {
132  retval = true;
133  }
134  amxc_string_clean(&concat_path);
135 
136  return retval;
137 }
138 
140  const char* file_path,
141  amxc_var_t** incstack,
142  char** full_path) {
143  int retval = -1;
144  amxc_var_t* config = amxo_parser_get_config(pctx, "include-dirs");
145  const amxc_llist_t* incdirs = amxc_var_constcast(amxc_llist_t, config);
146  amxc_string_t res_file_path;
147  struct stat statbuf;
148 
149  amxc_string_init(&res_file_path, 0);
150 
151  if(amxc_string_set_resolved(&res_file_path, file_path, &pctx->config) > 0) {
152  file_path = amxc_string_get(&res_file_path, 0);
153  }
154 
155  if(!amxo_parser_find(pctx, incdirs, file_path, full_path)) {
156  retval = 2;
157  pctx->status = amxd_status_file_not_found;
158  amxo_parser_msg(pctx, "Include file not found \"%s\"", file_path);
159  goto exit;
160  }
161 
162  if(stat(*full_path, &statbuf) != 0) {
163  retval = 2;
164  pctx->status = amxd_status_file_not_found;
165  amxo_parser_msg(pctx, "Include file not found \"%s\"", file_path);
166  goto exit;
167  }
168 
169  *incstack = amxo_parser_can_include(pctx, *full_path);
170  if(*incstack == NULL) {
171  pctx->status = amxd_status_recursion;
172  amxo_parser_msg(pctx, "Recursive include detected \"%s\"", file_path);
173  goto exit;
174  }
175 
176  retval = 0;
177 
178 exit:
179  amxc_string_clean(&res_file_path);
180  return retval;
181 }
182 
184  const char* full_path) {
185  int retval = -1;
186  amxo_parser_t parser;
187 
188  amxo_parser_child_init(&parser);
189  amxo_hooks_start_include(pctx, full_path);
190  amxo_parser_push(pctx, &parser);
191  retval = amxo_parser_parse_file_impl(&parser, full_path, pctx->object);
192  amxo_parser_pop(pctx, &parser);
193  amxo_hooks_end_include(pctx, full_path);
194  amxo_parser_clean(&parser);
195 
196  if(retval != 0) {
197  retval = 3;
198  if(pctx->status == amxd_status_ok) {
199  pctx->status = amxd_status_unknown_error;
200  }
201  amxo_parser_msg(pctx, "Error found in %s", full_path);
202  }
203 
204  return retval;
205 }
206 
208  const char* full_path) {
209  int retval = -1;
210  int count = 0;
211  struct dirent** namelist;
212  amxc_string_t file;
213  int n;
214 
215  amxc_string_init(&file, 0);
216 
217  n = scandir(full_path, &namelist, NULL, alphasort);
218  if(n == -1) {
219  pctx->status = amxd_status_unknown_error;
220  goto exit;
221  }
222 
223  retval = 0;
224  for(int i = 0; i < n; i++) {
225  int len = 0;
226  if(retval != 0) {
227  free(namelist[i]);
228  continue;
229  }
230  if(namelist[i]->d_type == DT_DIR) {
231  free(namelist[i]);
232  continue;
233  }
234  len = strlen(namelist[i]->d_name);
235  if(strncmp(namelist[i]->d_name + len - 4, ".odl", 4) != 0) {
236  free(namelist[i]);
237  continue;
238  }
239  amxc_string_setf(&file, "%s/%s", full_path, namelist[i]->d_name);
240  retval = amxo_parser_include_file(pctx, amxc_string_get(&file, 0));
241  count++;
242  free(namelist[i]);
243  }
244 
245  if(count == 0) {
246  pctx->status = amxd_status_ok;
247  retval = 4;
248  }
249  free(namelist);
250 
251 exit:
252  amxc_string_clean(&file);
253  return retval;
254 }
255 
257  const amxc_llist_t* dirs,
258  const char* file_path,
259  char** full_path) {
260  bool retval = false;
261 
262  if(file_path[0] != '/') {
263  amxc_string_t res_path;
264  amxc_string_init(&res_path, 0);
265  amxc_llist_for_each(it, dirs) {
266  amxc_var_t* var_dir = amxc_var_from_llist_it(it);
267  const char* dir = amxc_var_constcast(cstring_t, var_dir);
268  if(amxc_string_set_resolved(&res_path, dir, &parser->config) > 0) {
269  dir = amxc_string_get(&res_path, 0);
270  }
271 
272  if(amxo_parser_exists(dir, file_path, full_path)) {
273  break;
274  }
275  amxc_string_reset(&res_path);
276  }
277  amxc_string_clean(&res_path);
278  when_null(*full_path, exit);
279  } else {
280  if(!amxo_parser_exists(NULL, file_path, full_path)) {
281  goto exit;
282  }
283  }
284  retval = true;
285 
286 exit:
287  return retval;
288 }
289 
290 int amxo_parser_add_post_include(amxo_parser_t* pctx, const char* file_path) {
291  int retval = -1;
292  char* full_path = NULL;
293  amxc_var_t* incstack = NULL;
294 
295  retval = amxo_parser_check(pctx, file_path, &incstack, &full_path);
296  when_failed(retval, exit);
297 
298  if(pctx->post_includes == NULL) {
299  amxc_var_new(&pctx->post_includes);
300  amxc_var_set_type(pctx->post_includes, AMXC_VAR_ID_LIST);
301  }
302 
303  amxc_var_add(cstring_t, pctx->post_includes, full_path);
304 
305 exit:
306  amxc_var_delete(&incstack);
307  free(full_path);
308  return retval;
309 }
310 
311 int amxo_parser_include(amxo_parser_t* pctx, const char* file_path) {
312  int retval = -1;
313  char* full_path = NULL;
314  amxc_var_t* incstack = NULL;
315  struct stat statbuf;
316 
317  retval = amxo_parser_check(pctx, file_path, &incstack, &full_path);
318  when_failed(retval, exit);
319 
320  stat(full_path, &statbuf);
321 
322  if(S_ISDIR(statbuf.st_mode)) {
323  retval = amxo_parser_include_dir(pctx, full_path);
324  } else {
325  retval = amxo_parser_include_file(pctx, full_path);
326  }
327 
328 exit:
329  amxc_var_delete(&incstack);
330  free(full_path);
331  return retval;
332 }
PRIVATE void amxo_hooks_end_include(amxo_parser_t *parser, const char *file)
PRIVATE void amxo_hooks_start_include(amxo_parser_t *parser, const char *file)
static amxc_var_t * amxo_parser_can_include(amxo_parser_t *pctx, const char *full_path)
static int amxo_parser_include_file(amxo_parser_t *pctx, const char *full_path)
static int amxo_parser_include_dir(amxo_parser_t *pctx, const char *full_path)
bool amxo_parser_find(amxo_parser_t *parser, const amxc_llist_t *dirs, const char *file_path, char **full_path)
static void amxo_parser_push(amxo_parser_t *parent, amxo_parser_t *child)
static void amxo_parser_pop(amxo_parser_t *parent, amxo_parser_t *child)
static int amxo_parser_check(amxo_parser_t *pctx, const char *file_path, amxc_var_t **incstack, char **full_path)
static bool amxo_parser_exists(const char *incdir, const char *file_path, char **full_path)
int amxo_parser_include(amxo_parser_t *pctx, const char *file_path)
int amxo_parser_add_post_include(amxo_parser_t *pctx, const char *file_path)
PRIVATE int amxo_parser_parse_file_impl(amxo_parser_t *parser, const char *file_path, amxd_object_t *object)
PRIVATE void amxo_parser_msg(amxo_parser_t *parser, const char *format,...) __attribute__((format(printf
PRIVATE void amxo_parser_child_init(amxo_parser_t *parser)
config
amxc_var_t * amxo_parser_get_config(amxo_parser_t *parser, const char *path)
Gets a configuration option.
void amxo_parser_clean(amxo_parser_t *parser)
Cleans up the odl parser instance.
The ODL parser structure.
Definition: amxo_types.h:245
amxc_htable_t * resolvers
Definition: amxo_types.h:269
amxc_llist_t * hooks
Definition: amxo_types.h:274
amxc_lstack_t event_list
Definition: amxo_types.h:283
amxc_llist_t function_names
Definition: amxo_types.h:268
amxc_var_t config
Definition: amxo_types.h:250
amxc_var_t * include_stack
Definition: amxo_types.h:277
amxc_llist_t * entry_points
Definition: amxo_types.h:273
amxd_status_t status
Definition: amxo_types.h:258
amxc_llist_t global_config
Definition: amxo_types.h:253
amxc_var_t * post_includes
Definition: amxo_types.h:275
amxd_object_t * object
Definition: amxo_types.h:262
amxo_parser_t * parent
Definition: amxo_types.h:285
amxc_llist_t * sync_contexts
Definition: amxo_types.h:290