From 9afec232f5a4fdac1110ed5582d63dc6a2fd8a2f Mon Sep 17 00:00:00 2001 From: Christer Ekholm Date: Thu, 18 Jan 2024 12:07:38 +0800 Subject: [PATCH 1/5] Adden new API and unit test. --- include/cargs.h | 23 ++++++++++++++++++++++ src/cargs.c | 43 ++++++++++++++++++++++------------------ test/option_test.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/include/cargs.h b/include/cargs.h index f390f12..5bc2472 100644 --- a/include/cargs.h +++ b/include/cargs.h @@ -69,6 +69,11 @@ typedef struct cag_option_context char *value; } cag_option_context; +/** + * Prototype for printer used in cag_option_printer. For example fprint have same prototype + */ +typedef int (*cag_printer)(void *ctx, const char *fmt, ...); + /** * This is just a small macro which calculates the size of an array. */ @@ -84,8 +89,26 @@ typedef struct cag_option_context * @param option_count The option count which will be printed. * @param destination The destination where the output will be printed. */ +#ifndef CAG_NO_FILE CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, FILE *destination); +#endif + +/** + * @brief Prints all options using user callback. + * + * This function prints all options using user callback. This can be used to + * generate the output for a "--help" option. + * Using user callback is useful in tiny system without FILE support + * + * @param options The options which will be printed. + * @param option_count The option count which will be printed. + * @param destination The destination where the output will be printed. + * @param printer The printer callback function. For example fprint. + * @param printer_ctx The parameter for printer callback. For example fprint could use parameter stderr. + */ +CAG_PUBLIC void cag_option_printer(const cag_option *options, size_t option_count, + cag_printer printer, void *printer_ctx); /** * @brief Prepare argument options context for parsing. diff --git a/src/cargs.c b/src/cargs.c index ca6cecd..f94d2d4 100644 --- a/src/cargs.c +++ b/src/cargs.c @@ -8,25 +8,25 @@ #define CAG_OPTION_PRINT_MIN_INDENTION 20 static void cag_option_print_value(const cag_option *option, - size_t *accessor_length, FILE *destination) + size_t *accessor_length, cag_printer printer, void *printer_ctx) { if (option->value_name != NULL) { - *accessor_length += fprintf(destination, "=%s", option->value_name); + *accessor_length += printer(printer_ctx, "=%s", option->value_name); } } static void cag_option_print_letters(const cag_option *option, bool *first, - size_t *accessor_length, FILE *destination) + size_t *accessor_length, cag_printer printer, void *printer_ctx) { const char *access_letter; access_letter = option->access_letters; if (access_letter != NULL) { while (*access_letter) { if (*first) { - *accessor_length += fprintf(destination, "-%c", *access_letter); + *accessor_length += printer(printer_ctx, "-%c", *access_letter); *first = false; } else { - *accessor_length += fprintf(destination, ", -%c", *access_letter); + *accessor_length += printer(printer_ctx, ", -%c", *access_letter); } ++access_letter; } @@ -34,13 +34,13 @@ static void cag_option_print_letters(const cag_option *option, bool *first, } static void cag_option_print_name(const cag_option *option, bool *first, - size_t *accessor_length, FILE *destination) + size_t *accessor_length, cag_printer printer, void *printer_ctx) { if (option->access_name != NULL) { if (*first) { - *accessor_length += fprintf(destination, "--%s", option->access_name); + *accessor_length += printer(printer_ctx, "--%s", option->access_name); } else { - *accessor_length += fprintf(destination, ", --%s", option->access_name); + *accessor_length += printer(printer_ctx, ", --%s", option->access_name); } } } @@ -77,8 +77,16 @@ static size_t cag_option_get_print_indention(const cag_option *options, return result; } -void cag_option_print(const cag_option *options, size_t option_count, - FILE *destination) +#ifndef CAG_NO_FILE +void cag_option_print(const cag_option* options, size_t option_count, + FILE* destination) +{ + cag_option_printer(options, option_count, fprintf, destination); +} +#endif + +CAG_PUBLIC void cag_option_printer(const cag_option *options, + size_t option_count, cag_printer printer, void *printer_ctx) { size_t option_index, indention, i, accessor_length; const cag_option *option; @@ -91,20 +99,17 @@ void cag_option_print(const cag_option *options, size_t option_count, accessor_length = 0; first = true; - fputs(" ", destination); + printer(printer_ctx, " "); - cag_option_print_letters(option, &first, &accessor_length, destination); - cag_option_print_name(option, &first, &accessor_length, destination); - cag_option_print_value(option, &accessor_length, destination); + cag_option_print_letters(option, &first, &accessor_length, printer, printer_ctx); + cag_option_print_name(option, &first, &accessor_length, printer, printer_ctx); + cag_option_print_value(option, &accessor_length, printer, printer_ctx); for (i = accessor_length; i < indention; ++i) { - fputs(" ", destination); + printer(printer_ctx, " "); } - fputs(" ", destination); - fputs(option->description, destination); - - fprintf(destination, "\n"); + printer(printer_ctx, " %s\n", option->description); } } diff --git a/test/option_test.c b/test/option_test.c index fbcb9a3..591d2c8 100755 --- a/test/option_test.c +++ b/test/option_test.c @@ -625,6 +625,7 @@ int option_simple(void) int option_print(void) { +#ifndef CAG_NO_FILE char buf[255]; const char *expected; FILE *test_file; @@ -656,6 +657,53 @@ int option_print(void) fclose(test_file); return EXIT_SUCCESS; +err_test: +err_read: +err_seek: + fclose(test_file); +err_open: + return EXIT_FAILURE; + +#else // #ifndef CAG_NO_FILE + return EXIT_SUCCESS; +#endif +} + +int option_printer(void) +{ + char buf[255]; + const char *expected; + void *test_file; + + expected = " -s Simple flag\n" + " -a Another simple flag\n" + " -m, -M, -o, -O Multiple access letters\n" + " --long Long parameter name\n" + " -k, --key=VALUE Parameter value\n"; + + test_file = tmpfile(); + if (test_file == NULL) { + goto err_open; + } + + cag_option_printer(options, CAG_ARRAY_SIZE(options), (cag_printer)fprintf, + test_file); + + if (fseek(test_file, 0, SEEK_SET) != 0) { + goto err_seek; + } + + if (fread(buf, sizeof(buf), 1, test_file) != 1 && feof(test_file) == 0) { + goto err_read; + } + + if (memcmp(buf, expected, strlen(expected)) != 0) { + goto err_test; + } + + fclose(test_file); + return EXIT_SUCCESS; + err_test: err_read: err_seek: @@ -663,3 +711,4 @@ int option_print(void) err_open: return EXIT_FAILURE; } + From 38c845f50a35ef28b9c156c9790ea67df01da3f4 Mon Sep 17 00:00:00 2001 From: Christer Ekholm Date: Thu, 18 Jan 2024 13:35:16 +0800 Subject: [PATCH 2/5] clean merge conflicts dirtiness --- include/cargs.h | 4 ++-- src/cargs.c | 1 - test/option_test.c | 4 +++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/cargs.h b/include/cargs.h index 24bbf61..0a35b88 100644 --- a/include/cargs.h +++ b/include/cargs.h @@ -251,8 +251,8 @@ CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, * @param printer_ctx The parameter for printer callback. For example fprint * could use parameter stderr. */ - CAG_PUBLIC void cag_option_printer(const cag_option *options, - size_t option_count, cag_printer printer, void *printer_ctx); +CAG_PUBLIC void cag_option_printer(const cag_option *options, + size_t option_count, cag_printer printer, void *printer_ctx); CAG_DEPRECATED( "cag_option_prepare has been deprecated. Use cag_option_init instead.") diff --git a/src/cargs.c b/src/cargs.c index 3e1ef9a..68553da 100644 --- a/src/cargs.c +++ b/src/cargs.c @@ -77,7 +77,6 @@ static size_t cag_option_get_print_indention(const cag_option *options, return result; } - void cag_option_init(cag_option_context *context, const cag_option *options, size_t option_count, int argc, char **argv) { diff --git a/test/option_test.c b/test/option_test.c index ab9c884..b96643a 100755 --- a/test/option_test.c +++ b/test/option_test.c @@ -912,12 +912,14 @@ int option_error_print_short(void) goto err_test; } + destroy_args(); fclose(test_file); return EXIT_SUCCESS; err_test: err_read: err_seek: + destroy_args(); err_setup: fclose(test_file); err_open: @@ -973,4 +975,4 @@ int option_error_print_long(void) fclose(test_file); err_open: return EXIT_FAILURE; -} \ No newline at end of file +} From 6ce854843ad39a60912131c6db5c12b55e2bcc9f Mon Sep 17 00:00:00 2001 From: Christer Ekholm Date: Thu, 18 Jan 2024 13:45:35 +0800 Subject: [PATCH 3/5] Solve code coverity problem --- test/option_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/option_test.c b/test/option_test.c index b96643a..30794a7 100755 --- a/test/option_test.c +++ b/test/option_test.c @@ -898,7 +898,11 @@ int option_error_print_short(void) context.error_index = 1; context.error_letter = 'u'; +#ifdef CAG_NO_FILE cag_option_printer_error(&context, (cag_printer)fprintf, test_file); +#else + cag_option_print_error(&context, test_file); +#endif if (fseek(test_file, 0, SEEK_SET) != 0) { goto err_seek; From f6f1535dc0fa81c25a2d9351d6077a49bbfac02d Mon Sep 17 00:00:00 2001 From: Christer Ekholm Date: Thu, 18 Jan 2024 13:54:59 +0800 Subject: [PATCH 4/5] Fix freebsd buid? --- test/option_test.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/option_test.c b/test/option_test.c index 30794a7..9c8f53f 100755 --- a/test/option_test.c +++ b/test/option_test.c @@ -831,11 +831,17 @@ int option_print(void) #endif } +#ifdef CAG_NO_FILE +typedef void FILE_CTX; +#else +typedef FILE FILE_CTX; +#endif + int option_printer(void) { char buf[255]; const char *expected; - void *test_file; + FILE_CTX *test_file; expected = " -s Simple flag\n" " -a Another simple flag\n" @@ -879,7 +885,7 @@ int option_error_print_short(void) int status; char buf[255]; const char *expected; - void *test_file; + FILE_CTX *test_file; expected = "Unknown option 'u' in '-abu'.\n"; @@ -935,7 +941,7 @@ int option_error_print_long(void) int status; char buf[255]; const char *expected; - void *test_file; + FILE_CTX *test_file; expected = "Unknown option '--unknown'.\n"; From 953c9b00a416c523110857866cec9ffd54f22fbd Mon Sep 17 00:00:00 2001 From: Christer Ekholm Date: Thu, 18 Jan 2024 14:15:07 +0800 Subject: [PATCH 5/5] Fix comments --- include/cargs.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/cargs.h b/include/cargs.h index 0a35b88..6356d02 100644 --- a/include/cargs.h +++ b/include/cargs.h @@ -89,7 +89,7 @@ typedef struct cag_option_context } cag_option_context; /** - * Prototype for printer used in cag_option_printer. For example fprint have same prototype + * Prototype for printer used in cag_option_printer. For example fprintf have same prototype */ typedef int (*cag_printer)(void *ctx, const char *fmt, ...); @@ -211,12 +211,12 @@ CAG_PUBLIC void cag_option_print_error(const cag_option_context *context, * callback. * * This function prints information about the error associated with the invalid - * option to the specified destination (such as a file stream). It helps in - * displaying the error of the current context. + * option using user callback. Callback prototype is same with fprintf. It helps + * in displaying the error of the current context. * * @param context Pointer to the context from which the option was fetched. - * @param printer The printer callback function. For example fprint. - * @param printer_ctx The parameter for printer callback. For example fprint + * @param printer The printer callback function. For example fprintf. + * @param printer_ctx The parameter for printer callback. For example fprintf * could use parameter stderr. */ CAG_PUBLIC void cag_option_printer_error(const cag_option_context *context, @@ -247,8 +247,8 @@ CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, * @param options The options which will be printed. * @param option_count The option count which will be printed. * @param destination The destination where the output will be printed. - * @param printer The printer callback function. For example fprint. - * @param printer_ctx The parameter for printer callback. For example fprint + * @param printer The printer callback function. For example fprintf. + * @param printer_ctx The parameter for printer callback. For example fprintf * could use parameter stderr. */ CAG_PUBLIC void cag_option_printer(const cag_option *options,