1 #include "xmlrpc_config.h" /* prereq for mallocvar.h -- defines __inline__ */
10 #include "casprintf.h"
13 #include "cmdline_parser.h"
30 struct cmdlineParserCtl {
31 struct optionDesc * optionDescArray;
32 unsigned int numOptions;
33 const char ** argumentArray;
34 unsigned int numArguments;
39 static struct optionx *
40 createLongOptsArray(struct optionDesc * const optionDescArray,
41 unsigned int const numOptions) {
43 struct optionx * longopts;
45 MALLOCARRAY(longopts, numOptions+1);
46 if (longopts != NULL) {
49 for (i = 0; i < numOptions; ++i) {
50 longopts[i].name = optionDescArray[i].name;
51 /* If the option takes a value, we say it is optional even
52 though it never is. That's because if we say it is
53 mandatory, getopt_long_only() pretends it doesn't even
54 recognize the option if the user doesn't give a value.
55 We prefer to generate a meaningful error message when
56 the user omits a required option value.
59 optionDescArray[i].type == OPTTYPE_FLAG ?
60 no_argument : optional_argument;
61 longopts[i].flag = NULL;
64 longopts[numOptions].name = 0;
65 longopts[numOptions].has_arg = 0;
66 longopts[numOptions].flag = 0;
67 longopts[numOptions].val = 0;
75 parseOptionValue(const char * const optarg,
76 struct optionDesc * const optionP,
77 const char ** const errorP) {
79 switch (optionP->type) {
83 casprintf(errorP, "Option requires a value");
84 else if (strlen(optarg) == 0)
85 casprintf(errorP, "Numeric option value is null string");
88 long const longvalue = strtol(optarg, &tailptr, 10);
90 casprintf(errorP, "Non-numeric value "
91 "for numeric option value: '%s'", optarg);
92 else if (errno == ERANGE || longvalue > INT_MAX)
93 casprintf(errorP, "Numeric value out of range: %s", optarg);
95 if (optionP->type == OPTTYPE_UINT) {
97 casprintf(errorP, "Unsigned numeric value is "
98 "negative: %ld", longvalue);
101 optionP->value.u = (unsigned int) longvalue;
105 optionP->value.u = (int) longvalue;
113 casprintf(errorP, "Option requires a value");
116 optionP->value.s = strdup(optarg);
128 processOption(struct optionDesc * const optionP,
129 const char * const optarg,
130 const char ** const errorP) {
134 parseOptionValue(optarg, optionP, &error);
136 casprintf(errorP, "Error in '%s' option: %s", optionP->name, error);
138 optionP->present = true;
144 extractArguments(struct cmdlineParserCtl * const cpP,
145 unsigned int const argc,
146 const char ** const argv) {
148 cpP->numArguments = argc - getopt_argstart();
149 MALLOCARRAY(cpP->argumentArray, cpP->numArguments);
151 if (cpP->argumentArray == NULL) {
152 fprintf(stderr, "Unable to allocate memory for argument array\n");
157 for (i = 0; i < cpP->numArguments; ++i) {
158 cpP->argumentArray[i] = strdup(argv[getopt_argstart() + i]);
159 if (cpP->argumentArray[i] == NULL) {
160 fprintf(stderr, "Unable to allocate memory for Argument %u\n",
171 cmd_processOptions(cmdlineParser const cpP,
173 const char ** const argv,
174 const char ** const errorP) {
176 struct optionx * longopts;
178 longopts = createLongOptsArray(cpP->optionDescArray, cpP->numOptions);
180 if (longopts == NULL)
181 casprintf(errorP, "Unable to get memory for longopts array");
188 /* Set up initial assumption: No options present */
190 for (i = 0; i < cpP->numOptions; ++i)
191 cpP->optionDescArray[i].present = false;
193 endOfOptions = false; /* initial value */
195 while (!endOfOptions && !*errorP) {
196 int const opterr0 = 0;
197 /* Don't let getopt_long_only() print an error message */
198 unsigned int longoptsIndex;
199 const char * unrecognizedOption;
202 getopt_long_onlyx(argc, (char**) argv, "", longopts,
203 &longoptsIndex, opterr0,
204 &endOfOptions, &optarg, &unrecognizedOption);
206 if (unrecognizedOption)
207 casprintf(errorP, "Unrecognized option: '%s'",
211 processOption(&cpP->optionDescArray[longoptsIndex], optarg,
216 extractArguments(cpP, argc, argv);
225 cmd_createOptionParser(void) {
227 struct cmdlineParserCtl * cpP;
232 struct optionDesc * optionDescArray;
235 MALLOCARRAY(optionDescArray, MAXOPTS);
236 if (optionDescArray == NULL) {
240 cpP->optionDescArray = optionDescArray;
248 cmd_destroyOptionParser(cmdlineParser const cpP) {
252 for (i = 0; i < cpP->numOptions; ++i) {
253 struct optionDesc const option = cpP->optionDescArray[i];
254 if (option.type == OPTTYPE_STRING && option.present)
255 strfree(option.value.s);
256 strfree(option.name);
259 for (i = 0; i < cpP->numArguments; ++i)
260 strfree(cpP->argumentArray[i]);
262 free(cpP->optionDescArray);
269 cmd_defineOption(cmdlineParser const cpP,
270 const char * const name,
271 enum optiontype const type) {
273 if (cpP->numOptions < MAXOPTS) {
274 cpP->optionDescArray[cpP->numOptions].name = strdup(name);
275 cpP->optionDescArray[cpP->numOptions].type = type;
283 static struct optionDesc *
284 findOptionDesc(struct cmdlineParserCtl * const cpP,
285 const char * const name) {
287 struct optionDesc * retval;
292 for (i = 0; i < cpP->numOptions && !retval; ++i)
293 if (strcmp(cpP->optionDescArray[i].name, name) == 0)
294 retval = &cpP->optionDescArray[i];
302 cmd_optionIsPresent(cmdlineParser const cpP,
303 const char * const name) {
305 struct optionDesc * const optionDescP = findOptionDesc(cpP, name);
310 fprintf(stderr, "cmdlineParser called incorrectly. "
311 "optionIsPresent() called for undefined option '%s'\n",
315 present = optionDescP->present;
323 cmd_getOptionValueUint(cmdlineParser const cpP,
324 const char * const name) {
326 struct optionDesc * const optionDescP = findOptionDesc(cpP, name);
331 fprintf(stderr, "cmdlineParser called incorrectly. "
332 "cmd_getOptionValueUint() called for undefined option '%s'\n",
336 if (optionDescP->type != OPTTYPE_UINT) {
337 fprintf(stderr, "cmdlineParser called incorrectly. "
338 "cmd_getOptionValueUint() called for non-unsigned integer "
339 "option '%s'\n", optionDescP->name);
342 if (optionDescP->present)
343 retval = optionDescP->value.u;
354 cmd_getOptionValueInt(cmdlineParser const cpP,
355 const char * const name) {
357 struct optionDesc * const optionDescP = findOptionDesc(cpP, name);
362 fprintf(stderr, "cmdlineParser called incorrectly. "
363 "cmd_getOptionValueInt() called for undefined option '%s'\n",
367 if (optionDescP->type != OPTTYPE_INT) {
368 fprintf(stderr, "cmdlineParser called incorrectly. "
369 "cmd_getOptionValueInt() called for non-integer "
370 "option '%s'\n", optionDescP->name);
373 if (optionDescP->present)
374 retval = optionDescP->value.i;
386 cmd_getOptionValueString(cmdlineParser const cpP,
387 const char * const name) {
389 struct optionDesc * const optionDescP = findOptionDesc(cpP, name);
394 fprintf(stderr, "cmdlineParser called incorrectly. "
395 "cmd_getOptionValueString() called for "
396 "undefined option '%s'\n",
400 if (optionDescP->type != OPTTYPE_STRING) {
401 fprintf(stderr, "cmdlineParser called incorrectly. "
402 "getOptionValueString() called for non-string "
403 "option '%s'\n", optionDescP->name);
406 if (optionDescP->present) {
407 retval = strdup(optionDescP->value.s);
408 if (retval == NULL) {
410 "out of memory in cmd_getOptionValueString()\n");
423 cmd_argumentCount(cmdlineParser const cpP) {
425 return cpP->numArguments;
432 cmd_getArgument(cmdlineParser const cpP,
433 unsigned int const argNumber) {
437 if (argNumber >= cpP->numArguments)
440 retval = strdup(cpP->argumentArray[argNumber]);
442 if (retval == NULL) {
444 "out of memory in cmd_getArgument()\n");