1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
/*
Copyright (C) 2018- The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include "list.h"
#include "jx_getopt.h"
#include "stringtools.h"
#include "xxmalloc.h"
static struct list *jx_argv_stack = NULL;
static struct list *jx_argv = NULL;
struct jx *jx_optarg = NULL;
void jx_getopt_push(struct jx *j) {
assert(j);
if (!jx_argv) {
jx_argv = list_create();
}
if (!jx_argv_stack) {
jx_argv_stack = list_create();
}
list_push_head(jx_argv, jx_copy(j));
list_push_head(jx_argv_stack, NULL);
}
static const struct option *option_from_name(const struct option *opt, const char *name, int *indexptr) {
assert(opt);
assert(name);
for (int i = 0; opt[i].name; ++i) {
if (!strcmp(name, opt[i].name)) {
if (indexptr) {
*indexptr = i;
}
return &opt[i];
}
}
return NULL;
}
static char *optarg_from_jx(struct jx *j) {
assert(j);
switch (j->type) {
case JX_BOOLEAN:
return j->u.boolean_value ? xxstrdup("true") : xxstrdup("false");
case JX_INTEGER:
return string_format("%" PRIi64, j->u.integer_value);
case JX_DOUBLE:
return string_format("%g", j->u.double_value);
case JX_STRING:
return xxstrdup(j->u.string_value);
default:
return NULL;
}
}
static bool wrong_arg_type(const struct option *opt, struct jx *j) {
assert(opt);
assert(j);
switch (opt->has_arg) {
case no_argument:
if (!jx_istype(j, JX_NULL)) return true;
break;
case required_argument:
if (jx_istype(j, JX_NULL)) return true;
break;
default:
break;
}
return false;
}
static int write_opt_val(const struct option *opt) {
assert(opt);
if (opt->flag) {
*opt->flag = opt->val;
}
return opt->val;
}
int jx_getopt(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex) {
static char *val = NULL;
struct jx *jx_val = NULL;
free(val);
val = NULL;
jx_delete(jx_val);
jx_val = NULL;
if (!jx_argv) {
jx_argv = list_create();
}
struct jx *head = list_peek_head(jx_argv);
if (head) {
assert(jx_argv_stack);
void *i = list_pop_head(jx_argv_stack);
const char *key = jx_iterate_keys(head, &i);
if (key) {
list_push_head(jx_argv_stack, i);
const struct option *opt = option_from_name(longopts, key, longindex);
if (!opt) return 0;
jx_val = jx_copy(jx_get_value(&i));
assert(jx_val);
if (wrong_arg_type(opt, jx_val)) return 0;
val = optarg_from_jx(jx_val);
optarg = val;
jx_optarg = jx_val;
return write_opt_val(opt);
} else {
jx_delete(list_pop_head(jx_argv));
return jx_getopt(argc, argv, optstring, longopts, longindex);
}
} else {
return getopt_long(argc, argv, optstring, longopts, longindex);
}
}
|