xref: /aosp_15_r20/external/libopenapv/app/oapv_app_args.h (revision abb65b4b03b69e1d508d4d9a44dcf199df16e7c3)
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  * All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  *
15  * - Neither the name of the copyright owner, nor the names of its contributors
16  *   may be used to endorse or promote products derived from this software
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef _OAPV_APP_ARGS_H_
33 #define _OAPV_APP_ARGS_H_
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include "oapv.h"
39 
40 #define ARGS_VAL_TYPE_MANDATORY      (1 << 0) /* mandatory or not */
41 #define ARGS_VAL_TYPE_NONE           (1 << 2) /* no value */
42 #define ARGS_VAL_TYPE_INTEGER        (2 << 2) /* integer type value */
43 #define ARGS_VAL_TYPE_STRING         (3 << 2) /* string type value */
44 #define ARGS_GET_CMD_OPT_VAL_TYPE(x) ((x) & 0x0C)
45 #define ARGS_GET_IS_OPT_TYPE_PPT(x)  (((x) >> 1) & 0x01)
46 
47 #define ARGS_END_KEY                 (0)
48 #define ARGS_NO_KEY                  (127)
49 #define ARGS_KEY_LONG_CONFIG         "config"
50 #define ARGS_MAX_NUM_CONF_FILES      (16)
51 
52 #define ARGS_MAX_KEY_LONG            (32)
53 
54 typedef struct args_opt {
55     char  key;                         /* option keyword. ex) -f */
56     char  key_long[ARGS_MAX_KEY_LONG]; /* option long keyword, ex) --file */
57     int   val_type;                    /* value type */
58     int   flag;                        /* flag to setting or not */
59     void *val;                         /* actual value */
60     char  desc[512];                   /* description of option */
61 } args_opt_t;
62 
63 typedef struct args_parser args_parser_t;
64 struct args_parser {
65     void (*release)(args_parser_t *args);
66     int (*parse)(args_parser_t *args, int argc, const char *argv[], char **errstr);
67     int (*get_help)(args_parser_t *args, int idx, char *help);
68     int (*get_str)(args_parser_t *args, char *keyl, char *str, int *flag);
69     int (*get_int)(args_parser_t *args, char *keyl, int *val, int *flag);
70     int (*set_str)(args_parser_t *args, char *keyl, char *str);
71     int (*set_int)(args_parser_t *args, char *keyl, int val);
72     int (*set_flag)(args_parser_t *args, char *keyl, int flag);
73     int (*check_mandatory)(args_parser_t *args, char **err_arg);
74 
75     args_opt_t *opts;
76     int         num_option;
77 };
78 
args_search_long_key(args_opt_t * opts,const char * key)79 static int args_search_long_key(args_opt_t *opts, const char *key)
80 {
81     args_opt_t *o;
82     int         oidx = 0;
83 
84     o = opts;
85     while(o->key != ARGS_END_KEY) {
86         if(!strcmp(key, o->key_long)) {
87             return oidx;
88         }
89         oidx++;
90         o++;
91     }
92     return -1;
93 }
94 
args_search_short_arg(args_opt_t * ops,const char key)95 static int args_search_short_arg(args_opt_t *ops, const char key)
96 {
97     args_opt_t *o;
98     int         oidx = 0;
99 
100     o = ops;
101 
102     while(o->key != ARGS_END_KEY) {
103         if(o->key != ARGS_NO_KEY && o->key == key) {
104             return oidx;
105         }
106         oidx++;
107         o++;
108     }
109     return -1;
110 }
111 
args_read_value(args_opt_t * ops,const char * argv)112 static int args_read_value(args_opt_t *ops, const char *argv)
113 {
114     if(argv == NULL || ops->val == NULL) {
115         return -1;
116     }
117     if(argv[0] == '-' && (argv[1] < '0' || argv[1] > '9'))
118         return -1;
119 
120     switch(ARGS_GET_CMD_OPT_VAL_TYPE(ops->val_type)) {
121     case ARGS_VAL_TYPE_INTEGER:
122         *((int *)ops->val) = atoi(argv);
123         break;
124 
125     case ARGS_VAL_TYPE_STRING:
126         strcpy((char *)ops->val, argv);
127         break;
128 
129     default:
130         return -1;
131     }
132     return 0;
133 }
134 
args_get_arg(args_opt_t * ops,int idx,char * result)135 static int args_get_arg(args_opt_t *ops, int idx, char *result)
136 {
137     char        vtype[32];
138     char        value[512];
139     args_opt_t *o = ops + idx;
140 
141     switch(ARGS_GET_CMD_OPT_VAL_TYPE(o->val_type)) {
142     case ARGS_VAL_TYPE_INTEGER:
143         strncpy(vtype, "INTEGER", sizeof(vtype) - 1);
144         sprintf(value, "%d", *((int *)o->val));
145         break;
146 
147     case ARGS_VAL_TYPE_STRING:
148         strncpy(vtype, "STRING", sizeof(vtype) - 1);
149         sprintf(value, "%s", (char *)o->val);
150         break;
151 
152     case ARGS_VAL_TYPE_NONE:
153     default:
154         strncpy(vtype, "FLAG", sizeof(vtype) - 1);
155         sprintf(value, "%d", *((int *)o->val));
156         break;
157     }
158 
159     if(o->flag) {
160         strcat(value, " (SET)");
161     }
162     else {
163         strcat(value, " (DEFAULT)");
164     }
165 
166     sprintf(result, "  -%c(--%s) = %s\n    : %s", o->key, o->key_long,
167             value, o->desc);
168 
169     return 0;
170 }
171 
args_parse_int_x_int(char * str,int * num0,int * num1)172 static int args_parse_int_x_int(char *str, int *num0, int *num1)
173 {
174     char  str0_t[64];
175     int   i, cnt0 = 0, cnt1;
176     char *str0, *str1 = NULL;
177 
178     str0 = str;
179     cnt1 = (int)strlen(str);
180 
181     /* find 'x' */
182     for(i = 0; i < (int)strlen(str); i++) {
183         if(str[i] == 'x' || str[i] == 'X') {
184             str1 = str + i + 1;
185             cnt0 = i;
186             cnt1 = cnt1 - cnt0 - 1;
187             break;
188         }
189     }
190 
191     /* check malformed data */
192     if(str1 == NULL || cnt0 == 0 || cnt1 == 0)
193         return -1;
194 
195     for(i = 0; i < cnt0; i++) {
196         if(str0[i] < 0x30 || str0[i] > 0x39)
197             return -1; /* not a number */
198     }
199     for(i = 0; i < cnt1; i++) {
200         if(str1[i] < 0x30 || str1[i] > 0x39)
201             return -1; /* not a number */
202     }
203 
204     strncpy(str0_t, str0, cnt0);
205     str0_t[cnt0] = '\0';
206 
207     *num0 = atoi(str0_t);
208     *num1 = atoi(str1);
209 
210     return 0;
211 }
212 
args_parse_cfg(FILE * fp,args_opt_t * ops,int is_type_ppt)213 static int args_parse_cfg(FILE *fp, args_opt_t *ops, int is_type_ppt)
214 {
215     char *parser;
216     char  line[256] = "", tag[50] = "", val[256] = "";
217     int   oidx;
218 
219     while(fgets(line, sizeof(line), fp)) {
220         parser = strchr(line, '#');
221         if(parser != NULL)
222             *parser = '\0';
223 
224         parser = strtok(line, "= \t");
225         if(parser == NULL)
226             continue;
227         strncpy(tag, parser, sizeof(tag) - 1);
228 
229         parser = strtok(NULL, "=\n");
230         if(parser == NULL)
231             continue;
232         strncpy(val, parser, sizeof(val) - 1);
233 
234         oidx = args_search_long_key(ops, tag);
235         if(oidx < 0)
236             continue;
237 
238         if(ops[oidx].val == NULL) {
239             return -1;
240         }
241 
242         if(ARGS_GET_IS_OPT_TYPE_PPT(ops[oidx].val_type) == is_type_ppt) {
243             if(ARGS_GET_CMD_OPT_VAL_TYPE(ops[oidx].val_type) != ARGS_VAL_TYPE_NONE) {
244                 if(args_read_value(ops + oidx, val))
245                     continue;
246             }
247             else {
248                 *((int *)ops[oidx].val) = 1;
249             }
250             ops[oidx].flag = 1;
251         }
252     }
253     return 0;
254 }
255 
args_parse_cmd(int argc,const char * argv[],args_opt_t * ops,int * idx,char ** errstr)256 static int args_parse_cmd(int argc, const char *argv[], args_opt_t *ops,
257                           int *idx, char **errstr)
258 {
259     int aidx; /* arg index */
260     int oidx; /* option index */
261 
262     aidx = *idx + 1;
263 
264     if(aidx >= argc || argv[aidx] == NULL)
265         goto NO_MORE;
266     if(argv[aidx][0] != '-')
267         goto ERR;
268 
269     if(argv[aidx][1] == '-') {
270         /* long option */
271         oidx = args_search_long_key(ops, argv[aidx] + 2);
272         if(oidx < 0) {
273             *errstr = (char *)argv[aidx];
274             goto ERR;
275         }
276     }
277     else if(strlen(argv[aidx]) == 2) {
278         /* short option */
279         oidx = args_search_short_arg(ops, argv[aidx][1]);
280         if(oidx < 0) {
281             *errstr = (char *)argv[aidx];
282             goto ERR;
283         }
284     }
285     else {
286         goto ERR;
287     }
288 
289     if(ARGS_GET_CMD_OPT_VAL_TYPE(ops[oidx].val_type) !=
290        ARGS_VAL_TYPE_NONE) {
291         if(aidx + 1 >= argc) {
292             *errstr = (char *)argv[aidx];
293             goto ERR;
294         }
295         if(args_read_value(ops + oidx, argv[aidx + 1])) {
296             *errstr = (char *)argv[aidx];
297             goto ERR;
298         }
299         *idx = *idx + 1;
300     }
301     else {
302         *((int *)ops[oidx].val) = 1;
303     }
304     ops[oidx].flag = 1;
305     *idx = *idx + 1;
306 
307     return ops[oidx].key;
308 
309 NO_MORE:
310     return 0;
311 
312 ERR:
313     return -1;
314 }
315 
args_set_variable_by_key_long(args_opt_t * opts,char * key_long,void * var)316 static int args_set_variable_by_key_long(args_opt_t *opts, char *key_long, void *var)
317 {
318     int   idx;
319     char  buf[ARGS_MAX_KEY_LONG];
320     char *ko = key_long;
321     char *kt = buf;
322 
323     /* if long key has "_", convert to "-". */
324     while(*ko != '\0') {
325         if(*ko == '_')
326             *kt = '-';
327         else
328             *kt = *ko;
329 
330         ko++;
331         kt++;
332     }
333     *kt = '\0';
334 
335     idx = args_search_long_key(opts, buf);
336     if(idx < 0)
337         return -1;
338     opts[idx].val = var;
339     return 0;
340 }
341 
args_set_variable_by_key(args_opt_t * opts,char * key,void * var)342 static int args_set_variable_by_key(args_opt_t *opts, char *key, void *var)
343 {
344     int idx;
345     idx = args_search_short_arg(opts, key[0]);
346     if(idx < 0)
347         return -1;
348     opts[idx].val = var;
349     return 0;
350 }
351 
352 #define ARGS_SET_PARAM_VAR_KEY_LONG(opts, param, key_long) \
353     args_set_variable_by_key_long(opts, #key_long, (void *)&((param)->key_long))
354 
355 #define ARGS_SET_PARAM_VAR_KEY(opts, param, key) \
356     args_set_variable_by_key(opts, #key, (void *)&((param)->key))
357 
args_get(args_parser_t * args,char * keyl,void ** val,int * flag)358 static int args_get(args_parser_t *args, char *keyl, void **val, int *flag)
359 {
360     int idx;
361 
362     idx = args_search_long_key(args->opts, keyl);
363     if(idx >= 0) {
364         if(val)
365             *val = args->opts[idx].val;
366         if(flag)
367             *flag = args->opts[idx].flag;
368         return 0;
369     }
370     else {
371         if(val)
372             *val = NULL; /* no value */
373         if(flag)
374             *flag = 0; /* no set */
375         return -1;
376     }
377 }
378 
args_set_str(args_parser_t * args,char * keyl,char * str)379 static int args_set_str(args_parser_t *args, char *keyl, char *str)
380 {
381     int idx;
382 
383     idx = args_search_long_key(args->opts, keyl);
384     if(idx >= 0) {
385         sprintf((char *)(args->opts[idx].val), "%s", str);
386         args->opts[idx].flag = 1;
387         return 0;
388     }
389     else {
390         return -1;
391     }
392 }
393 
args_set_int(args_parser_t * args,char * keyl,int val)394 static int args_set_int(args_parser_t *args, char *keyl, int val)
395 {
396     int idx;
397 
398     idx = args_search_long_key(args->opts, keyl);
399     if(idx >= 0) {
400         *((int *)(args->opts[idx].val)) = val;
401         args->opts[idx].flag = 1;
402         return 0;
403     }
404     else {
405         return -1;
406     }
407 }
408 
args_set_flag(args_parser_t * args,char * keyl,int flag)409 static int args_set_flag(args_parser_t *args, char *keyl, int flag)
410 {
411     int idx;
412 
413     idx = args_search_long_key(args->opts, keyl);
414     if(idx >= 0) {
415         args->opts[idx].flag = flag;
416         return 0;
417     }
418     return -1;
419 }
420 
args_get_str(args_parser_t * args,char * keyl,char * str,int * flag)421 static int args_get_str(args_parser_t *args, char *keyl, char *str, int *flag)
422 {
423     char *p = NULL;
424     if(args_get(args, keyl, (void **)&p, flag))
425         return -1;
426     if(p) {
427         if(str)
428             strcpy(str, p);
429     }
430     return 0;
431 }
432 
args_get_int(args_parser_t * args,char * keyl,int * val,int * flag)433 static int args_get_int(args_parser_t *args, char *keyl, int *val, int *flag)
434 {
435     int *p = NULL;
436     if(args_get(args, keyl, (void **)&p, flag))
437         return -1;
438     if(p) {
439         *val = *p;
440     }
441     return 0;
442 }
443 
args_parse(args_parser_t * args,int argc,const char * argv[],char ** errstr)444 static int args_parse(args_parser_t *args, int argc, const char *argv[],
445                       char **errstr)
446 {
447     int         i, ret = 0, idx = 0;
448     const char *fname_cfg = NULL;
449     FILE       *fp;
450 
451     int         num_configs = 0;
452     int         pos_conf_files[ARGS_MAX_NUM_CONF_FILES];
453     memset(&pos_conf_files, -1, sizeof(int) * ARGS_MAX_NUM_CONF_FILES);
454 
455     /* config file parsing */
456     for(i = 1; i < argc; i++) {
457         if(!strcmp(argv[i], "--" ARGS_KEY_LONG_CONFIG)) {
458             if(i + 1 < argc) {
459                 num_configs++;
460                 pos_conf_files[num_configs - 1] = i + 1;
461             }
462         }
463     }
464     for(int i = 0; i < num_configs; i++) {
465         fname_cfg = argv[pos_conf_files[i]];
466         if(fname_cfg) {
467             fp = fopen(fname_cfg, "r");
468             if(fp == NULL)
469                 return -1; /* config file error */
470 
471             if(args_parse_cfg(fp, args->opts, 1)) {
472                 fclose(fp);
473                 return -1; /* config file error */
474             }
475             fclose(fp);
476         }
477     }
478     /* command line parsing */
479     while(1) {
480         ret = args_parse_cmd(argc, argv, args->opts, &idx, errstr);
481         if(ret <= 0)
482             break;
483     }
484     return ret;
485 }
486 
args_get_help(args_parser_t * args,int idx,char * help)487 static int args_get_help(args_parser_t *args, int idx, char *help)
488 {
489     int         optional;
490     char        vtype[32];
491     args_opt_t *o = args->opts + idx;
492     char        default_value[256] = { 0 };
493 
494     switch(ARGS_GET_CMD_OPT_VAL_TYPE(o->val_type)) {
495     case ARGS_VAL_TYPE_INTEGER:
496         strncpy(vtype, "INTEGER", sizeof(vtype) - 1);
497         if(o->val != NULL)
498             sprintf(default_value, " [%d]", *(int *)(o->val));
499         break;
500     case ARGS_VAL_TYPE_STRING:
501         strncpy(vtype, "STRING", sizeof(vtype) - 1);
502         if(o->val != NULL)
503             sprintf(default_value, " [%s]", strlen((char *)(o->val)) == 0 ? "None" : (char *)(o->val));
504         break;
505     case ARGS_VAL_TYPE_NONE:
506     default:
507         strncpy(vtype, "FLAG", sizeof(vtype) - 1);
508         if(o->val != NULL)
509             sprintf(default_value, " [%s]", *(int *)(o->val) ? "On" : "Off");
510         break;
511     }
512     optional = !(o->val_type & ARGS_VAL_TYPE_MANDATORY);
513 
514     if(o->key != ARGS_NO_KEY) {
515         sprintf(help, "  -%c, --%s [%s]%s%s\n    : %s", o->key, o->key_long,
516                 vtype, (optional) ? " (optional)" : "", (optional) ? default_value : "", o->desc);
517     }
518     else {
519         sprintf(help, "  --%s [%s]%s%s\n    : %s", o->key_long,
520                 vtype, (optional) ? " (optional)" : "", (optional) ? default_value : "", o->desc);
521     }
522 
523     return 0;
524 }
525 
args_check_mandatory(args_parser_t * args,char ** err_arg)526 static int args_check_mandatory(args_parser_t *args, char **err_arg)
527 {
528     args_opt_t *o = args->opts;
529 
530     while(o->key != 0) {
531         if(o->val_type & ARGS_VAL_TYPE_MANDATORY) {
532             if(o->flag == 0) {
533                 /* not filled all mandatory argument */
534                 *err_arg = o->key_long;
535                 return -1;
536             }
537         }
538         o++;
539     }
540     return 0;
541 }
542 
args_release(args_parser_t * args)543 static void args_release(args_parser_t *args)
544 {
545     if(args != NULL) {
546         if(args->opts != NULL)
547             free(args->opts);
548         free(args);
549     }
550 }
551 
args_create(const args_opt_t * opt_table,int num_opt)552 static args_parser_t *args_create(const args_opt_t *opt_table, int num_opt)
553 {
554     args_parser_t *args = NULL;
555     args_opt_t    *opts = NULL;
556 
557     args = (args_parser_t *)malloc(sizeof(args_parser_t));
558     if(args == NULL)
559         goto ERR;
560     memset(args, 0, sizeof(args_parser_t));
561 
562     opts = (args_opt_t *)malloc(num_opt * sizeof(args_opt_t));
563     if(opts == NULL)
564         goto ERR;
565     memcpy(opts, opt_table, num_opt * sizeof(args_opt_t));
566     args->opts = opts;
567 
568     args->release = args_release;
569     args->parse = args_parse;
570     args->get_help = args_get_help;
571     args->get_str = args_get_str;
572     args->get_int = args_get_int;
573     args->set_str = args_set_str;
574     args->set_int = args_set_int;
575     args->set_flag = args_set_flag;
576     args->check_mandatory = args_check_mandatory;
577 
578     /* find actual number of options */
579     args->num_option = 0;
580     while(opt_table[args->num_option].key != ARGS_END_KEY)
581         args->num_option++;
582 
583     return args;
584 
585 ERR:
586     free(opts);
587     free(args);
588     return NULL;
589 }
590 
591 #endif /*_OAPV_APP_ARGS_H_ */
592