X-Git-Url: http://git.efficios.com/?p=argpar.git;a=blobdiff_plain;f=argpar%2Fargpar.c;h=45658a5b3e914e538cb47848281a1ffcdc1b178d;hp=a37efd000c9edf2edbbf65c5c02f2069e47ee151;hb=4d6198b505eaeb2e60a14331ccb52f90ea397bb4;hpb=37bb2b1fe8e07b4c2cb9c31d4f2c4ffdb56e3e10 diff --git a/argpar/argpar.c b/argpar/argpar.c index a37efd0..45658a5 100644 --- a/argpar/argpar.c +++ b/argpar/argpar.c @@ -33,8 +33,8 @@ /* * An argpar iterator. * - * Such a structure contains the state of an iterator between - * calls to argpar_iter_parse_next(). + * Such a structure contains the state of an iterator between calls to + * argpar_iter_next(). */ struct argpar_iter { /* @@ -47,7 +47,7 @@ struct argpar_iter { /* * Index of the argument to process in the next - * argpar_iter_parse_next() call. + * argpar_iter_next() call. */ unsigned int i; @@ -58,9 +58,15 @@ struct argpar_iter { * Current character of the current short option group: if it's * not `NULL`, the parser is in within a short option group, * therefore it must resume there in the next - * argpar_iter_parse_next() call. + * argpar_iter_next() call. */ const char *short_opt_ch; + + /* Temporary character buffer which only grows */ + struct { + size_t size; + char *data; + } tmp_buf; }; /* Base parsing item */ @@ -247,79 +253,6 @@ end: return; } -static -bool push_item(struct argpar_item_array * const array, - const struct argpar_item * const item) -{ - bool success; - - ARGPAR_ASSERT(array); - ARGPAR_ASSERT(item); - - if (array->n_items == array->n_alloc) { - const unsigned int new_n_alloc = array->n_alloc * 2; - const struct argpar_item ** const new_items = - ARGPAR_REALLOC(array->items, const struct argpar_item *, - new_n_alloc); - if (!new_items) { - success = false; - goto end; - } - - array->n_alloc = new_n_alloc; - array->items = new_items; - } - - array->items[array->n_items] = item; - array->n_items++; - success = true; - -end: - return success; -} - -static -void destroy_item_array(struct argpar_item_array * const array) -{ - if (array) { - unsigned int i; - - for (i = 0; i < array->n_items; i++) { - argpar_item_destroy(array->items[i]); - } - - free(array->items); - free(array); - } -} - -static -struct argpar_item_array *create_item_array(void) -{ - struct argpar_item_array *ret; - const int initial_size = 10; - - ret = ARGPAR_ZALLOC(struct argpar_item_array); - if (!ret) { - goto end; - } - - ret->items = ARGPAR_CALLOC(const struct argpar_item *, initial_size); - if (!ret->items) { - goto error; - } - - ret->n_alloc = initial_size; - goto end; - -error: - destroy_item_array(ret); - ret = NULL; - -end: - return ret; -} - static struct argpar_item_opt *create_opt_item( const struct argpar_opt_descr * const descr, @@ -398,8 +331,10 @@ end: enum parse_orig_arg_opt_ret { PARSE_ORIG_ARG_OPT_RET_OK, - PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -2, - PARSE_ORIG_ARG_OPT_RET_ERROR = -1, + PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -1, + PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG = -2, + PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG = -4, + PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5, }; static @@ -415,10 +350,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, const struct argpar_opt_descr *descr; struct argpar_item_opt *opt_item; - if (strlen(short_opts) == 0) { - try_append_string_printf(error, "Invalid argument"); - goto error; - } + ARGPAR_ASSERT(strlen(short_opts) != 0); if (!iter->short_opt_ch) { iter->short_opt_ch = short_opts; @@ -427,9 +359,9 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, /* Find corresponding option descriptor */ descr = find_descr(descrs, *iter->short_opt_ch, NULL); if (!descr) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; try_append_string_printf(error, "Unknown option `-%c`", *iter->short_opt_ch); + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; goto error; } @@ -453,6 +385,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, "Missing required argument for option `-%c`", *iter->short_opt_ch); used_next_orig_arg = false; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG; goto error; } } @@ -460,6 +393,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, /* Create and append option argument */ opt_item = create_opt_item(descr, opt_arg); if (!opt_item) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; goto error; } @@ -480,9 +414,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, goto end; error: - if (ret == PARSE_ORIG_ARG_OPT_RET_OK) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - } + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); end: return ret; @@ -495,7 +427,6 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, struct argpar_iter * const iter, char ** const error, struct argpar_item ** const item) { - const size_t max_len = 127; enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK; const struct argpar_opt_descr *descr; struct argpar_item_opt *opt_item; @@ -507,16 +438,10 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Position of first `=`, if any */ const char *eq_pos; - /* Buffer holding option name when `long_opt_arg` contains `=` */ - char buf[max_len + 1]; - /* Option name */ const char *long_opt_name = long_opt_arg; - if (strlen(long_opt_arg) == 0) { - try_append_string_printf(error, "Invalid argument"); - goto error; - } + ARGPAR_ASSERT(strlen(long_opt_arg) != 0); /* Find the first `=` in original argument */ eq_pos = strchr(long_opt_arg, '='); @@ -524,15 +449,19 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, const size_t long_opt_name_size = eq_pos - long_opt_arg; /* Isolate the option name */ - if (long_opt_name_size > max_len) { - try_append_string_printf(error, - "Invalid argument `--%s`", long_opt_arg); - goto error; + while (long_opt_name_size > iter->tmp_buf.size - 1) { + iter->tmp_buf.size *= 2; + iter->tmp_buf.data = ARGPAR_REALLOC(iter->tmp_buf.data, + char, iter->tmp_buf.size); + if (!iter->tmp_buf.data) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + goto error; + } } - memcpy(buf, long_opt_arg, long_opt_name_size); - buf[long_opt_name_size] = '\0'; - long_opt_name = buf; + memcpy(iter->tmp_buf.data, long_opt_arg, long_opt_name_size); + iter->tmp_buf.data[long_opt_name_size] = '\0'; + long_opt_name = iter->tmp_buf.data; } /* Find corresponding option descriptor */ @@ -555,6 +484,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, try_append_string_printf(error, "Missing required argument for option `--%s`", long_opt_name); + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG; goto error; } @@ -568,6 +498,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, */ try_append_string_printf(error, "Unexpected argument for option `--%s`", long_opt_name); + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG; goto error; } @@ -587,9 +518,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, goto end; error: - if (ret == PARSE_ORIG_ARG_OPT_RET_OK) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - } + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); end: return ret; @@ -652,7 +581,7 @@ struct argpar_iter *argpar_iter_create(const unsigned int argc, const char * const * const argv, const struct argpar_opt_descr * const descrs) { - struct argpar_iter * const iter = ARGPAR_ZALLOC(struct argpar_iter); + struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter); if (!iter) { goto end; @@ -661,6 +590,13 @@ struct argpar_iter *argpar_iter_create(const unsigned int argc, iter->argc = argc; iter->argv = argv; iter->descrs = descrs; + iter->tmp_buf.size = 128; + iter->tmp_buf.data = ARGPAR_CALLOC(char, iter->tmp_buf.size); + if (!iter->tmp_buf.data) { + argpar_iter_destroy(iter); + iter = NULL; + goto end; + } end: return iter; @@ -669,15 +605,18 @@ end: ARGPAR_HIDDEN void argpar_iter_destroy(struct argpar_iter * const iter) { - free(iter); + if (iter) { + free(iter->tmp_buf.data); + free(iter); + } } ARGPAR_HIDDEN -enum argpar_iter_parse_next_status argpar_iter_parse_next( +enum argpar_iter_next_status argpar_iter_next( struct argpar_iter * const iter, const struct argpar_item ** const item, char ** const error) { - enum argpar_iter_parse_next_status status; + enum argpar_iter_next_status status; enum parse_orig_arg_opt_ret parse_orig_arg_opt_ret; const char *orig_arg; const char *next_orig_arg; @@ -689,7 +628,7 @@ enum argpar_iter_parse_next_status argpar_iter_parse_next( } if (iter->i == iter->argc) { - status = ARGPAR_ITER_PARSE_NEXT_STATUS_END; + status = ARGPAR_ITER_NEXT_STATUS_END; goto end; } @@ -697,21 +636,22 @@ enum argpar_iter_parse_next_status argpar_iter_parse_next( next_orig_arg = iter->i < (iter->argc - 1) ? iter->argv[iter->i + 1] : NULL; - if (orig_arg[0] != '-') { + if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 || + orig_arg[0] != '-') { /* Non-option argument */ - struct argpar_item_non_opt * const non_opt_item = + const struct argpar_item_non_opt * const non_opt_item = create_non_opt_item(orig_arg, iter->i, iter->non_opt_index); if (!non_opt_item) { - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR; + status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; goto end; } iter->non_opt_index++; iter->i++; *item = &non_opt_item->base; - status = ARGPAR_ITER_PARSE_NEXT_STATUS_OK; + status = ARGPAR_ITER_NEXT_STATUS_OK; goto end; } @@ -721,17 +661,31 @@ enum argpar_iter_parse_next_status argpar_iter_parse_next( (struct argpar_item **) item); switch (parse_orig_arg_opt_ret) { case PARSE_ORIG_ARG_OPT_RET_OK: - status = ARGPAR_ITER_PARSE_NEXT_STATUS_OK; + status = ARGPAR_ITER_NEXT_STATUS_OK; break; case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: + case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: try_prepend_while_parsing_arg_to_error(error, iter->i, orig_arg); - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT; + + switch (parse_orig_arg_opt_ret) { + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG; + break; + default: + abort(); + } + break; - case PARSE_ORIG_ARG_OPT_RET_ERROR: - try_prepend_while_parsing_arg_to_error(error, iter->i, - orig_arg); - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; break; default: abort(); @@ -742,88 +696,8 @@ end: } ARGPAR_HIDDEN -unsigned int argpar_iter_get_ingested_orig_args( +unsigned int argpar_iter_ingested_orig_args( const struct argpar_iter * const iter) { return iter->i; } - -ARGPAR_HIDDEN -struct argpar_parse_ret argpar_parse(const unsigned int argc, - const char * const * const argv, - const struct argpar_opt_descr * const descrs, - const bool fail_on_unknown_opt) -{ - struct argpar_parse_ret parse_ret = { 0 }; - const struct argpar_item *item = NULL; - struct argpar_iter *iter = NULL; - - parse_ret.items = create_item_array(); - if (!parse_ret.items) { - parse_ret.error = strdup("Failed to create items array."); - ARGPAR_ASSERT(parse_ret.error); - goto error; - } - - iter = argpar_iter_create(argc, argv, descrs); - if (!iter) { - parse_ret.error = strdup("Failed to create argpar iter."); - ARGPAR_ASSERT(parse_ret.error); - goto error; - } - - while (true) { - const enum argpar_iter_parse_next_status status = - argpar_iter_parse_next(iter, &item, &parse_ret.error); - - if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR) { - goto error; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_END) { - break; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) { - if (fail_on_unknown_opt) { - parse_ret.ingested_orig_args = - argpar_iter_get_ingested_orig_args(iter); - goto error; - } - - free(parse_ret.error); - parse_ret.error = NULL; - break; - } - - ARGPAR_ASSERT(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK); - - if (!push_item(parse_ret.items, item)) { - goto error; - } - - item = NULL; - } - - ARGPAR_ASSERT(!parse_ret.error); - parse_ret.ingested_orig_args = argpar_iter_get_ingested_orig_args(iter); - goto end; - -error: - ARGPAR_ASSERT(parse_ret.error); - - /* That's how we indicate that an error occurred */ - destroy_item_array(parse_ret.items); - parse_ret.items = NULL; - -end: - argpar_iter_destroy(iter); - argpar_item_destroy(item); - return parse_ret; -} - -ARGPAR_HIDDEN -void argpar_parse_ret_fini(struct argpar_parse_ret * const ret) -{ - ARGPAR_ASSERT(ret); - destroy_item_array(ret->items); - ret->items = NULL; - free(ret->error); - ret->error = NULL; -}