X-Git-Url: http://git.efficios.com/?p=argpar.git;a=blobdiff_plain;f=argpar%2Fargpar.c;h=58cbc2b9d917203be676d58e7259bb8518cf0529;hp=1ee5539ec0b221cd1457237ba434ecb1974ea2f0;hb=dd757a651292048da829dd6fa085c1f107569bcc;hpb=d4539a906f9b4114a3f0a40e33598cf8077767c2 diff --git a/argpar/argpar.c b/argpar/argpar.c index 1ee5539..58cbc2b 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,7 +58,7 @@ 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; }; @@ -140,13 +140,18 @@ char *argpar_asprintf(const char * const fmt, ...) } static __attribute__((format(ARGPAR_PRINTF_FORMAT, 2, 3))) -bool append_string_printf(char ** const str, const char *fmt, ...) +bool try_append_string_printf(char ** const str, const char *fmt, ...) { char *new_str = NULL; - char *addendum; + char *addendum = NULL; bool success; va_list args; + if (!str) { + success = true; + goto end; + } + ARGPAR_ASSERT(str); va_start(args, fmt); addendum = argpar_vasprintf(fmt, args); @@ -393,8 +398,11 @@ 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_INVALID_ARG = -3, + PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG = -4, + PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5, }; static @@ -410,10 +418,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) { - 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; @@ -422,9 +427,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; - append_string_printf(error, "Unknown option `-%c`", + try_append_string_printf(error, "Unknown option `-%c`", *iter->short_opt_ch); + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; goto error; } @@ -444,10 +449,11 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, */ if (!opt_arg || (iter->short_opt_ch[1] && strlen(opt_arg) == 0)) { - append_string_printf(error, + try_append_string_printf(error, "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; } } @@ -455,6 +461,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; } @@ -475,9 +482,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; @@ -508,10 +513,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Option name */ const char *long_opt_name = long_opt_arg; - if (strlen(long_opt_arg) == 0) { - 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, '='); @@ -520,8 +522,9 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Isolate the option name */ if (long_opt_name_size > max_len) { - append_string_printf(error, "Invalid argument `--%s`", - long_opt_arg); + try_append_string_printf(error, + "Invalid argument `--%s`", long_opt_arg); + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; goto error; } @@ -533,7 +536,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Find corresponding option descriptor */ descr = find_descr(descrs, '\0', long_opt_name); if (!descr) { - append_string_printf(error, "Unknown option `--%s`", + try_append_string_printf(error, "Unknown option `--%s`", long_opt_name); ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; goto error; @@ -547,9 +550,10 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, } else { /* `--long-opt arg` style */ if (!next_orig_arg) { - append_string_printf(error, + 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; } @@ -561,8 +565,9 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, * Unexpected `--opt=arg` style for a long option which * doesn't accept an argument. */ - append_string_printf(error, + 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; } @@ -582,9 +587,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; @@ -615,13 +618,17 @@ enum parse_orig_arg_opt_ret parse_orig_arg_opt(const char * const orig_arg, } static -bool prepend_while_parsing_arg_to_error(char ** const error, +bool try_prepend_while_parsing_arg_to_error(char ** const error, const unsigned int i, const char * const arg) { char *new_error; bool success; - ARGPAR_ASSERT(error); + if (!error) { + success = true; + goto end; + } + ARGPAR_ASSERT(*error); new_error = argpar_asprintf("While parsing argument #%u (`%s`): %s", i + 1, arg, *error); @@ -664,20 +671,23 @@ void argpar_iter_destroy(struct argpar_iter * const 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; ARGPAR_ASSERT(iter->i <= iter->argc); - *error = NULL; + + if (error) { + *error = NULL; + } if (iter->i == iter->argc) { - status = ARGPAR_ITER_PARSE_NEXT_STATUS_END; + status = ARGPAR_ITER_NEXT_STATUS_END; goto end; } @@ -685,21 +695,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; } @@ -709,15 +720,35 @@ 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: - prepend_while_parsing_arg_to_error(error, iter->i, orig_arg); - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: + case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG: + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: + try_prepend_while_parsing_arg_to_error(error, iter->i, + orig_arg); + + 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_INVALID_ARG: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_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: - 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(); @@ -728,7 +759,7 @@ 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; @@ -759,27 +790,32 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, } 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) { + const enum argpar_iter_next_status status = + argpar_iter_next(iter, &item, &parse_ret.error); + + switch (status) { + case ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG: + case ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG: + case ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG: + case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY: goto error; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_END) { - break; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) { + case ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT: if (fail_on_unknown_opt) { parse_ret.ingested_orig_args = - argpar_iter_get_ingested_orig_args(iter); + argpar_iter_ingested_orig_args(iter); goto error; } free(parse_ret.error); parse_ret.error = NULL; + goto success; + case ARGPAR_ITER_NEXT_STATUS_END: + goto success; + default: + ARGPAR_ASSERT(status == ARGPAR_ITER_NEXT_STATUS_OK); break; } - ARGPAR_ASSERT(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK); - if (!push_item(parse_ret.items, item)) { goto error; } @@ -787,8 +823,9 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, item = NULL; } +success: ARGPAR_ASSERT(!parse_ret.error); - parse_ret.ingested_orig_args = argpar_iter_get_ingested_orig_args(iter); + parse_ret.ingested_orig_args = argpar_iter_ingested_orig_args(iter); goto end; error: