libamxrt  0.4.2
Ambiorix Run Time Library
amxrt_args.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 <stdlib.h>
60 #include <string.h>
61 
62 #include <yajl/yajl_gen.h>
63 #include <amxrt/amxrt.h>
64 #include <amxj/amxj_variant.h>
65 
66 #include "amxrt_priv.h"
67 
68 static void amxrt_cmd_line_free_option(amxc_llist_it_t* it) {
69  amxrt_arg_t* option = amxc_container_of(it, amxrt_arg_t, it);
70  free(option);
71 }
72 
73 static int amxrt_cmd_line_default(amxc_var_t* config,
74  int arg_id,
75  const char* value) {
76  int rv = 0;
77  switch(arg_id) {
78  case 'I':
79  amxc_var_add(cstring_t, GET_ARG(config, AMXRT_COPT_INCDIRS), value);
80  break;
81 
82  case 'L':
83  amxc_var_add(cstring_t, GET_ARG(config, AMXRT_COPT_LIBDIRS), value);
84  break;
85 
86  case 'B':
87  amxc_var_add(cstring_t, GET_ARG(config, AMXRT_COPT_BACKENDS), value);
88  break;
89 
90  case 'u':
91  amxc_var_add(cstring_t, GET_ARG(config, AMXRT_COPT_URIS), value);
92  break;
93 
94  case 'A':
95  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_AUTO_DETECT), false);
96  break;
97 
98  case 'C':
99  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_AUTO_CONNECT), false);
100  break;
101 
102  case 'D':
103  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DAEMON), true);
104  break;
105 
106  case 'E':
107  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_EVENT), true);
108  break;
109 
110  case 'd':
111  if((value == NULL) || (strcmp(value, "config") == 0)) {
112  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CONFIG), true);
113  } else if(strcmp(value, "caps") == 0) {
114  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CAPS), true);
115  }
116  break;
117 
118  case 'p':
119  amxc_var_set(int32_t, GET_ARG(config, AMXRT_COPT_PRIORITY), atoi(value));
120  break;
121 
122  case 'N':
123  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_PID_FILE), false);
124  break;
125 
126  case 'O':
127  amxc_var_add_key(cstring_t, config, AMXRT_COPT_ODL, value);
128  break;
129 
130  case 'l':
131  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_LOG), true);
132  break;
133 
134  case 'R':
135  amxc_var_add(cstring_t, GET_ARG(config, AMXRT_COPT_REQUIRES), value);
136  break;
137 
138  case 'o':
139  amxrt_cmd_line_parse_assignment(value, false);
140  break;
141 
142  case 'F':
143  amxrt_cmd_line_parse_assignment(value, true);
144  break;
145 
146 
147  case 'h': {
149  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CONFIG), false);
150  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CAPS), false);
151  rv = -1;
152  }
153  break;
154 
155  case 'H': {
157  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CONFIG), false);
158  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CAPS), false);
159  rv = -1;
160  }
161  break;
162 
163  default: {
164  amxrt_print_error("Argument not recognized - %d", arg_id);
166  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CONFIG), false);
167  amxc_var_set(bool, GET_ARG(config, AMXRT_COPT_DUMP_CAPS), false);
168  rv = -1;
169  }
170  break;
171 
172  }
173 
174  return rv;
175 }
176 
177 // private - called from constructor
179  amxrt_cmd_line_add_option(0, 'h', "help", no_argument, "Print usage help and exit", NULL);
180  amxrt_cmd_line_add_option(0, 'H', "HELP", no_argument, "Print extended help and exit", NULL);
181  amxrt_cmd_line_add_option(0, 'B', "backend", required_argument, "Loads the shared object as bus backend", "so file");
182  amxrt_cmd_line_add_option(0, 'u', "uri", required_argument, "Adds an uri to the list of uris", "uri");
183  amxrt_cmd_line_add_option(0, 'A', "no-auto-detect", no_argument, "Do not auto detect unix domain sockets and back-ends", NULL);
184  amxrt_cmd_line_add_option(0, 'C', "no-connect", no_argument, "Do not auto connect the provided or detected uris", NULL);
185  amxrt_cmd_line_add_option(0, 'I', "include-dir", required_argument, "Adds include directory for odl parser, multiple allowed", "dir");
186  amxrt_cmd_line_add_option(0, 'L', "import-dir", required_argument, "Adds import directory for odl parser, multiple allowed", "dir");
187  amxrt_cmd_line_add_option(0, 'o', "option", required_argument, "Adds a configuration option", "name=value");
188  amxrt_cmd_line_add_option(0, 'F', "forced-option", required_argument, "Adds a configuration option, which can not be overwritten by odl files", "name=value");
189  amxrt_cmd_line_add_option(0, 'O', "ODL", required_argument, "An ODL in string format, only one ODL string allowed", "odl-string");
190  amxrt_cmd_line_add_option(0, 'D', "daemon", no_argument, "Daemonize the process", NULL);
191  amxrt_cmd_line_add_option(0, 'p', "priority", required_argument, "Sets the process nice level", "nice level");
192  amxrt_cmd_line_add_option(0, 'N', "no-pid-file", no_argument, "Disables the creation of a pid-file in /var/run", NULL);
193  amxrt_cmd_line_add_option(0, 'E', "eventing", no_argument, "Enables eventing during loading of ODL files", NULL);
194  amxrt_cmd_line_add_option(0, 'd', "dump", optional_argument, "Dumps configuration options or capabilities at start-up", "[caps|config]");
195  amxrt_cmd_line_add_option(0, 'l', "log", no_argument, "Write to syslog instead of stdout and stderr", NULL);
196  amxrt_cmd_line_add_option(0, 'R', "requires", required_argument, "Checks if datamodel objects are available or waits until they are available", "root object");
197 }
198 
199 // remove all defined command line options
201  amxrt_t* rt = amxrt_get();
202  amxc_llist_clean(&rt->cmd_line_args, amxrt_cmd_line_free_option);
203 }
204 
205 // add a command line option definition
206 int amxrt_cmd_line_add_option(int id, char short_option, const char* long_option, int has_args, const char* doc, const char* arg_doc) {
207  int rv = -1;
208  amxrt_t* rt = amxrt_get();
209  amxrt_arg_t* option = NULL;
210 
211  option = (amxrt_arg_t*) calloc(1, sizeof(amxrt_arg_t));
212  when_null(option, exit);
213 
214  option->id = id == 0 ? (int) short_option : id;
215  option->short_option = short_option;
216  option->long_option = long_option;
217  option->has_args = has_args;
218  option->doc = doc;
219  option->arg_doc = arg_doc;
220 
221  rv = amxc_llist_append(&rt->cmd_line_args, &option->it);
222 
223 exit:
224  if(rv != 0) {
225  free(option);
226  }
227  return rv;
228 }
229 
230 void amxrt_cmd_line_set_usage_doc(const char* usage) {
231  amxrt_t* rt = amxrt_get();
232  rt->usage_doc = usage == NULL ? "[OPTIONS] <odl files>" : usage;
233 }
234 
235 // parse the command line arguments
236 int amxrt_cmd_line_parse(int argc, char* argv[], amxrt_arg_fn_t fn) {
237  amxrt_t* rt = amxrt_get();
238  amxc_var_t* config = amxrt_get_config();
239  int nr_options = amxc_llist_size(&rt->cmd_line_args);
240  struct option* long_options = (struct option*) calloc(nr_options + 1, sizeof(struct option));
241  amxc_string_t format;
242  int index = 0;
243  int rv = 0;
244  int c;
245 
246  if(long_options == NULL) {
247  // handle error case where calloc failed
248  return -1;
249  }
250 
251  optind = 1;
252  amxc_string_init(&format, 0);
253  amxc_llist_for_each(it, &rt->cmd_line_args) {
254  amxrt_arg_t* option = amxc_container_of(it, amxrt_arg_t, it);
255  long_options[index].name = option->long_option;
256  long_options[index].has_arg = option->has_args;
257  long_options[index].val = option->id;
258  if(option->has_args == no_argument) {
259  amxc_string_appendf(&format, "%c", option->short_option);
260  } else if(option->has_args == optional_argument) {
261  amxc_string_appendf(&format, "%c::", option->short_option);
262  } else {
263  amxc_string_appendf(&format, "%c:", option->short_option);
264  }
265  index++;
266  }
267 
268  index = 0;
269  while(1) {
270  c = getopt_long(argc, argv, amxc_string_get(&format, 0), long_options, &index);
271  if(c == -1) {
272  break;
273  }
274  rv = -2;
275  if(fn != NULL) {
276  // call provided function
277  // if it returns 0 the option is handled
278  // if it returns -1 stop option parsing and exit
279  // if it returns -2 call default argument handler
280  // all others are considered as an error
281  rv = fn(config, c, optarg);
282  }
283  if(rv == -2) {
284  rv = amxrt_cmd_line_default(config, c, optarg);
285  }
286  when_failed_status(rv, exit, rv = -1);
287  }
288 
289 exit:
290  free(long_options);
291  amxc_string_clean(&format);
292  return rv == 0 ? optind : rv;
293 }
294 
295 // parse a command line option where the value has this format "name=value"
296 void amxrt_cmd_line_parse_assignment(const char* option, bool force) {
297  amxrt_t* rt = amxrt_get();
298  amxc_var_t* config = NULL;
299  amxc_string_t str_option;
300  amxc_llist_t options;
301  amxc_string_t* name = NULL;
302  amxc_string_t* value = NULL;
303  amxc_var_t var_option;
304 
305  amxc_var_init(&var_option);
306  amxc_llist_init(&options);
307  amxc_string_init(&str_option, 0);
308 
309  amxc_string_set(&str_option, option);
310  amxc_string_split_to_llist(&str_option, &options, '=');
311  when_true(amxc_llist_is_empty(&options), leave);
312  when_true(amxc_llist_size(&options) != 2, leave);
313 
314  name = amxc_string_from_llist_it(amxc_llist_get_first(&options));
315  value = amxc_string_from_llist_it(amxc_llist_get_last(&options));
316 
317  amxc_string_trim(name, NULL);
318  amxc_string_trim(value, NULL);
319 
320  if(amxc_var_set(jstring_t, &var_option, amxc_string_get(value, 0)) != 0) {
321  amxc_var_set(cstring_t, &var_option, amxc_string_get(value, 0));
322  } else {
323  amxc_var_cast(&var_option, AMXC_VAR_ID_ANY);
324  }
325 
326  config = force ? &rt->forced_options : &rt->parser.config;
327  amxc_var_set_path(config, amxc_string_get(name, 0), &var_option,
328  AMXC_VAR_FLAG_AUTO_ADD | AMXC_VAR_FLAG_COPY);
329 
330 leave:
331  amxc_string_clean(&str_option);
332  amxc_llist_clean(&options, amxc_string_list_it_free);
333  amxc_var_clean(&var_option);
334  return;
335 }
static amxrt_t rt
Definition: amxrt.c:74
#define AMXRT_COPT_BACKENDS
Definition: amxrt.h:75
#define AMXRT_COPT_URIS
Definition: amxrt.h:73
#define AMXRT_COPT_PID_FILE
Definition: amxrt.h:84
#define AMXRT_COPT_ODL
Definition: amxrt.h:81
#define AMXRT_COPT_LIBDIRS
Definition: amxrt.h:79
int(* amxrt_arg_fn_t)(amxc_var_t *config, int arg_id, const char *value)
Definition: amxrt.h:115
#define AMXRT_COPT_DUMP_CONFIG
Definition: amxrt.h:91
#define AMXRT_COPT_PRIORITY
Definition: amxrt.h:83
#define AMXRT_COPT_DUMP_CAPS
Definition: amxrt.h:92
#define AMXRT_COPT_REQUIRES
Definition: amxrt.h:99
#define AMXRT_COPT_EVENT
Definition: amxrt.h:90
#define AMXRT_COPT_AUTO_DETECT
Definition: amxrt.h:76
#define AMXRT_COPT_LOG
Definition: amxrt.h:98
#define AMXRT_COPT_AUTO_CONNECT
Definition: amxrt.h:77
#define AMXRT_COPT_DAEMON
Definition: amxrt.h:82
#define AMXRT_COPT_INCDIRS
Definition: amxrt.h:78
void amxrt_cmd_line_add_default_options(void)
Definition: amxrt_args.c:178
static void amxrt_cmd_line_free_option(amxc_llist_it_t *it)
Definition: amxrt_args.c:68
static int amxrt_cmd_line_default(amxc_var_t *config, int arg_id, const char *value)
Definition: amxrt_args.c:73
PRIVATE amxrt_t * amxrt_get(void)
Definition: amxrt.c:297
PRIVATE void amxrt_print_error(const char *fmt,...)
PRIVATE void amxrt_print_help(void)
#define c(x)
Definition: amxrt_priv.h:97
void amxrt_cmd_line_parse_assignment(const char *option, bool force)
Parses an command line option or an argument with an assignment.
Definition: amxrt_args.c:296
int amxrt_cmd_line_add_option(int id, char short_option, const char *long_option, int has_args, const char *doc, const char *arg_doc)
Adds a command line option definition.
Definition: amxrt_args.c:206
int amxrt_cmd_line_parse(int argc, char *argv[], amxrt_arg_fn_t fn)
Starts parsing the command line options.
Definition: amxrt_args.c:236
void amxrt_cmd_line_set_usage_doc(const char *usage)
Set the overall usage documentation string.
Definition: amxrt_args.c:230
void amxrt_cmd_line_options_reset(void)
Removes all default options.
Definition: amxrt_args.c:200
void amxrt_print_usage(void)
Prints the usage information and all available options to stdout.
amxc_var_t * amxrt_get_config(void)
Gets the htable variant containing the configuration options.
Definition: amxrt.c:301
const char * arg_doc
Definition: amxrt_priv.h:114
const char * long_option
Definition: amxrt_priv.h:110
amxc_llist_it_t it
Definition: amxrt_priv.h:115
const char * doc
Definition: amxrt_priv.h:113
amxc_llist_t cmd_line_args
Definition: amxrt_priv.h:102
amxo_parser_t parser
Definition: amxrt_priv.h:101
amxc_var_t forced_options
Definition: amxrt_priv.h:103
const char * usage_doc
Definition: amxrt_priv.h:105
config
Definition: test.odl:54