From f39383128fe09f43b4931158072cbd357dbec369 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Mon, 27 Jun 2022 17:46:29 +0300 Subject: [PATCH] Generic (file) cmdline (#102) --- .gitignore | 4 +- ChangeLog | 4 + Makefile.am | 3 +- README.md | 5 +- bindings/mruby/test/cmdline.rb | 2 +- .../ruby/spec/lib/kernaux/cmdline_spec.rb | 2 +- common/cmdline.yml | 4 +- examples/Makefile.am | 18 ++ examples/cmdline.c | 1 + examples/cmdline_file.c | 31 +++ examples/memory_file.c | 16 ++ include/Makefile.am | 3 +- include/kernaux.h.in | 1 + include/kernaux/cmdline.h | 9 + include/kernaux/memory_file.h | 37 +++ src/cmdline.c | 244 ++++++++++-------- src/memory_file.c | 51 ++++ tests/Makefile.am | 24 +- tests/cmdline_gen.jinja | 74 ++++-- tests/test_cmdline.c | 94 ++++--- tests/{test_printf_reg.c => test_printf.c} | 0 21 files changed, 453 insertions(+), 174 deletions(-) create mode 100644 examples/cmdline_file.c create mode 100644 examples/memory_file.c create mode 100644 include/kernaux/memory_file.h create mode 100644 src/memory_file.c rename tests/{test_printf_reg.c => test_printf.c} (100%) diff --git a/.gitignore b/.gitignore index a98493dc..44ef892c 100644 --- a/.gitignore +++ b/.gitignore @@ -108,11 +108,13 @@ /examples/assert /examples/cmdline +/examples/cmdline_file /examples/generic_file /examples/generic_malloc /examples/generic_mutex /examples/macro_container_of /examples/memmap +/examples/memory_file /examples/ntoa /examples/panic /examples/pfa @@ -145,9 +147,9 @@ /tests/test_ntoa_assert /tests/test_pfa /tests/test_pfa_assert +/tests/test_printf /tests/test_printf_fmt_gen /tests/test_printf_fmt_gen.c /tests/test_printf_gen /tests/test_printf_gen.c -/tests/test_printf_reg /tests/test_units_human diff --git a/ChangeLog b/ChangeLog index 9305dd34..90eb8fb9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-06-27 Alex Kotov + + * include/kernaux/memory_file.h: Added + 2022-06-25 Alex Kotov * configure.ac: Removed package "io" diff --git a/Makefile.am b/Makefile.am index 5f42b2be..8575219b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,7 +33,8 @@ libkernaux_la_SOURCES = \ src/libc.h \ src/generic/file.c \ src/generic/malloc.c \ - src/generic/mutex.c + src/generic/mutex.c \ + src/memory_file.c ######## # libc # diff --git a/README.md b/README.md index d331b46d..b209f98b 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ zero). Work-in-progress APIs can change at any time. * Architecture-specific code (*work in progress*) * [Declarations](/include/kernaux/arch/) * [Functions](/include/kernaux/asm/) + * [Memory file](/include/kernaux/memory_file.h) (*non-breaking since* **?.?.?**) + * [Example](/examples/memory_file.c) * Generic types * [File](/include/kernaux/generic/file.h) (*non-breaking since* **?.?.?**) * [Example](/examples/generic_file.c) @@ -57,7 +59,8 @@ zero). Work-in-progress APIs can change at any time. * Algorithms * [Free list memory allocator](/include/kernaux/free_list.h) (*non-breaking since* **?.?.?**) * [Simple command line parser](/include/kernaux/cmdline.h) (*non-breaking since* **0.2.0**) - * [Example](/examples/cmdline.c) + * [Example: buffer](/examples/cmdline.c) + * [Example: file](/examples/cmdline_file.c) * [Page Frame Allocator](/include/kernaux/pfa.h) (*work in progress*) * [Example](/examples/pfa.c) * Data formats diff --git a/bindings/mruby/test/cmdline.rb b/bindings/mruby/test/cmdline.rb index 6d675058..98ff730a 100644 --- a/bindings/mruby/test/cmdline.rb +++ b/bindings/mruby/test/cmdline.rb @@ -65,7 +65,7 @@ if KernAux::Version.with_cmdline? end assert 'when args cause buffer overflow' do - assert_raise KernAux::CmdlineError, 'buffer overflow' do + assert_raise KernAux::CmdlineError, 'EOF or buffer overflow' do KernAux.cmdline 'a' * 4096 end end diff --git a/bindings/ruby/spec/lib/kernaux/cmdline_spec.rb b/bindings/ruby/spec/lib/kernaux/cmdline_spec.rb index dbbe0624..38b984ff 100644 --- a/bindings/ruby/spec/lib/kernaux/cmdline_spec.rb +++ b/bindings/ruby/spec/lib/kernaux/cmdline_spec.rb @@ -87,7 +87,7 @@ KernAux::Version.with_cmdline? and RSpec.describe KernAux, '.cmdline' do specify do expect { cmdline }.to \ - raise_error described_class::CmdlineError, 'buffer overflow' + raise_error described_class::CmdlineError, 'EOF or buffer overflow' end end diff --git a/common/cmdline.yml b/common/cmdline.yml index fda7bb58..c371aacf 100644 --- a/common/cmdline.yml +++ b/common/cmdline.yml @@ -66,7 +66,7 @@ error: 'too many args' - cmdline: 'foo bar car' buffer_size: 11 - error: 'buffer overflow' + error: 'EOF or buffer overflow' - cmdline: 'foo bar car' argv_count_max: 2 buffer_size: 11 @@ -88,7 +88,7 @@ error: 'too many args' - cmdline: '\"foo\" \"bar\" \"car\"' buffer_size: 11 - error: 'buffer overflow' + error: 'EOF or buffer overflow' - cmdline: '\"foo\" \"bar\" \"car\"' argv_count_max: 2 buffer_size: 11 diff --git a/examples/Makefile.am b/examples/Makefile.am index a9ce7706..c011b7a2 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -21,6 +21,16 @@ cmdline_LDADD = $(top_builddir)/libkernaux.la cmdline_SOURCES = main.c cmdline.c endif +################ +# cmdline_file # +################ + +if WITH_CMDLINE +TESTS += cmdline_file +cmdline_file_LDADD = $(top_builddir)/libkernaux.la +cmdline_file_SOURCES = main.c cmdline_file.c +endif + ################ # generic_file # ################ @@ -63,6 +73,14 @@ memmap_LDADD = $(top_builddir)/libkernaux.la memmap_SOURCES = main.c memmap.c endif +############### +# memory_file # +############### + +TESTS += memory_file +memory_file_LDADD = $(top_builddir)/libkernaux.la +memory_file_SOURCES = main.c memory_file.c + ######## # ntoa # ######## diff --git a/examples/cmdline.c b/examples/cmdline.c index 6103aa60..4c968542 100644 --- a/examples/cmdline.c +++ b/examples/cmdline.c @@ -1,6 +1,7 @@ #include #include +#include #include #define ARGV_COUNT_MAX 100 diff --git a/examples/cmdline_file.c b/examples/cmdline_file.c new file mode 100644 index 00000000..b90ecadd --- /dev/null +++ b/examples/cmdline_file.c @@ -0,0 +1,31 @@ +#include +#include + +#include +#include +#include + +static const char *const cmdline = "foo bar\\ baz \"car cdr\""; + +static char buffer[4096]; + +void example_main() +{ + char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX]; + size_t argc; + struct KernAux_MemoryFile memory_file = + KernAux_MemoryFile_create(buffer, sizeof(buffer), NULL); + + assert(kernaux_cmdline_file( + cmdline, + error_msg, + &argc, + &memory_file.file + )); + + assert(strcmp(error_msg, "") == 0); + assert(argc == 3); + assert(strcmp(&buffer[0], "foo") == 0); + assert(strcmp(&buffer[4], "bar baz") == 0); + assert(strcmp(&buffer[12], "car cdr") == 0); +} diff --git a/examples/memory_file.c b/examples/memory_file.c new file mode 100644 index 00000000..7fb542cf --- /dev/null +++ b/examples/memory_file.c @@ -0,0 +1,16 @@ +#include + +#include +#include + +static char buffer[4096]; + +void example_main() +{ + struct KernAux_MemoryFile memory_file = + KernAux_MemoryFile_create(buffer, sizeof(buffer), NULL); + + KernAux_File_puts(&memory_file.file, "Hello, World!"); + + assert(strcmp(buffer, "Hello, World!") == 0); +} diff --git a/include/Makefile.am b/include/Makefile.am index a264a460..6d6d82bf 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -11,7 +11,8 @@ nobase_include_HEADERS = \ kernaux/version.h \ kernaux/generic/file.h \ kernaux/generic/malloc.h \ - kernaux/generic/mutex.h + kernaux/generic/mutex.h \ + kernaux/memory_file.h ######## # ARCH # diff --git a/include/kernaux.h.in b/include/kernaux.h.in index 3ce50c20..6e245acd 100644 --- a/include/kernaux.h.in +++ b/include/kernaux.h.in @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/include/kernaux/cmdline.h b/include/kernaux/cmdline.h index 5b51b88e..266e0aa8 100644 --- a/include/kernaux/cmdline.h +++ b/include/kernaux/cmdline.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include + #include #include @@ -22,6 +24,13 @@ bool kernaux_cmdline( size_t buffer_size ); +bool kernaux_cmdline_file( + const char *cmdline, + char *error_msg, + size_t *argc, + KernAux_File file +); + #ifdef __cplusplus } #endif diff --git a/include/kernaux/memory_file.h b/include/kernaux/memory_file.h new file mode 100644 index 00000000..9ec57471 --- /dev/null +++ b/include/kernaux/memory_file.h @@ -0,0 +1,37 @@ +#ifndef KERNAUX_INCLUDED_MEMORY_FILE +#define KERNAUX_INCLUDED_MEMORY_FILE + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +typedef struct KernAux_MemoryFile { + struct KernAux_File file; + + KernAux_Mutex KERNAUX_PRIVATE_FIELD(mutex); + char *KERNAUX_PRIVATE_FIELD(ptr); + size_t KERNAUX_PRIVATE_FIELD(size); + size_t KERNAUX_PRIVATE_FIELD(pos); +} *KernAux_MemoryFile; + +struct KernAux_MemoryFile +KernAux_MemoryFile_create(void *ptr, size_t size, KernAux_Mutex mutex); + +void KernAux_MemoryFile_init( + KernAux_MemoryFile memory_file, + void *ptr, + size_t size, + KernAux_Mutex mutex +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cmdline.c b/src/cmdline.c index a556bc2c..7ac93311 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -4,6 +4,7 @@ #include #include +#include #include "libc.h" @@ -17,6 +18,22 @@ enum State { QUOTE_BACKSLASH, }; +static bool kernaux_cmdline_common( + const char *cmdline, + char *error_msg, + size_t *argc, + char arg_terminator, + char **argv, + char *buffer, + size_t argv_count_max, + size_t buffer_size, + KernAux_File file +); + +/***************************** + * Implementations: main API * + *****************************/ + bool kernaux_cmdline( const char *const cmdline, char *const error_msg, @@ -33,10 +50,114 @@ bool kernaux_cmdline( KERNAUX_ASSERT(argv_count_max > 0); KERNAUX_ASSERT(buffer_size > 0); + return kernaux_cmdline_common( + cmdline, + error_msg, + argc, + '\0', // arg_terminator + argv, + buffer, + argv_count_max, + buffer_size, + NULL + ); +} + +bool kernaux_cmdline_file( + const char *const cmdline, + char *const error_msg, + size_t *const argc, + const KernAux_File file +) { + KERNAUX_ASSERT(cmdline); + KERNAUX_ASSERT(error_msg); + KERNAUX_ASSERT(argc); + KERNAUX_ASSERT(file); + + return kernaux_cmdline_common( + cmdline, + error_msg, + argc, + '\0', // arg_terminator + NULL, + NULL, + 0, + 0, + file + ); +} + +/****************************************** + * Implementation: main internal function * + ******************************************/ + +#define FAIL(msg) do { \ + strcpy(error_msg, msg); \ + goto fail; \ +} while (0) + +#define PUT_CHAR(char) do { \ + if (buffer_size && buffer_pos >= buffer_size) { \ + FAIL("EOF or buffer overflow"); \ + } \ + if (buffer) { \ + buffer[buffer_pos++] = char; \ + } \ + if (file) { \ + if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ + FAIL("EOF or buffer overflow"); \ + } \ + } \ +} while (0) + +#define PUT_ARG do { \ + if (argv_count_max && *argc >= argv_count_max) { \ + FAIL("too many args"); \ + } \ + if (argv && buffer) { \ + argv[*argc] = &buffer[buffer_pos]; \ + } \ + ++(*argc); \ +} while (0) + +#define PUT_ARG_AND_CHAR(char) do { \ + if (argv_count_max && *argc >= argv_count_max) { \ + FAIL("too many args"); \ + } \ + if (buffer_size && buffer_pos >= buffer_size) { \ + FAIL("EOF or buffer overflow"); \ + } \ + if (argv && buffer) { \ + argv[*argc] = &buffer[buffer_pos]; \ + buffer[buffer_pos++] = char; \ + } \ + if (file) { \ + if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ + FAIL("EOF or buffer overflow"); \ + } \ + } \ + ++(*argc); \ +} while (0) + +bool kernaux_cmdline_common( + const char *const cmdline, + char *const error_msg, + size_t *const argc, + char arg_terminator, + char **const argv, + char *const buffer, + const size_t argv_count_max, + const size_t buffer_size, + const KernAux_File file +) { + KERNAUX_ASSERT(cmdline); + KERNAUX_ASSERT(error_msg); + KERNAUX_ASSERT(argc); + memset(error_msg, '\0', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); *argc = 0; - memset(argv, 0, sizeof(char*) * argv_count_max); - memset(buffer, '\0', buffer_size); + if (argv) memset(argv, 0, sizeof(char*) * argv_count_max); + if (buffer) memset(buffer, '\0', buffer_size); if (cmdline[0] == '\0') return true; @@ -56,35 +177,14 @@ bool kernaux_cmdline( } else if (cur == ' ') { state = WHITESPACE; } else if (cur == '\\') { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - state = BACKSLASH; - argv[(*argc)++] = &buffer[buffer_pos]; + PUT_ARG; } else if (cur == '"') { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - state = QUOTE; - argv[(*argc)++] = &buffer[buffer_pos]; + PUT_ARG; } else { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = TOKEN; - argv[(*argc)++] = &buffer[buffer_pos]; - buffer[buffer_pos++] = cur; + PUT_ARG_AND_CHAR(cur); } break; @@ -94,121 +194,61 @@ bool kernaux_cmdline( } else if (cur == ' ') { // do nothing } else if (cur == '\\') { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - state = BACKSLASH; - argv[(*argc)++] = &buffer[buffer_pos]; + PUT_ARG; } else if (cur == '"') { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - state = QUOTE; - argv[(*argc)++] = &buffer[buffer_pos]; + PUT_ARG; } else { - if (*argc >= argv_count_max) { - strcpy(error_msg, "too many args"); - goto fail; - } - - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = TOKEN; - argv[(*argc)++] = &buffer[buffer_pos]; - buffer[buffer_pos++] = cur; + PUT_ARG_AND_CHAR(cur); } break; case TOKEN: if (cur == '\0') { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = FINAL; - buffer[buffer_pos++] = '\0'; + PUT_CHAR(arg_terminator); } else if (cur == ' ') { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = WHITESPACE; - buffer[buffer_pos++] = '\0'; + PUT_CHAR(arg_terminator); } else if (cur == '\\') { state = BACKSLASH; } else if (cur == '"') { - strcpy(error_msg, "unescaped quotation mark"); - goto fail; + FAIL("unescaped quotation mark"); } else { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - - buffer[buffer_pos++] = cur; + PUT_CHAR(cur); } break; case BACKSLASH: if (cur == '\0') { - strcpy(error_msg, "EOL after backslash"); - goto fail; + FAIL("EOL after backslash"); } else { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = TOKEN; - buffer[buffer_pos++] = cur; + PUT_CHAR(cur); } break; case QUOTE: if (cur == '\0') { - strcpy(error_msg, "EOL inside quote"); - goto fail; + FAIL("EOL inside quote"); } else if (cur == '\\') { state = QUOTE_BACKSLASH; } else if (cur == '"') { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = WHITESPACE; - buffer[buffer_pos++] = '\0'; + PUT_CHAR(arg_terminator); } else { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - - buffer[buffer_pos++] = cur; + PUT_CHAR(cur); } break; case QUOTE_BACKSLASH: if (cur == '\0') { - strcpy(error_msg, "EOL after backslash inside quote"); - goto fail; + FAIL("EOL after backslash inside quote"); } else { - if (buffer_pos >= buffer_size) { - strcpy(error_msg, "buffer overflow"); - goto fail; - } - state = QUOTE; - buffer[buffer_pos++] = cur; + PUT_CHAR(cur); } break; } @@ -220,7 +260,7 @@ bool kernaux_cmdline( fail: *argc = 0; - memset(argv, 0, sizeof(char*) * argv_count_max); - memset(buffer, '\0', buffer_size); + if (argv) memset(argv, 0, sizeof(char*) * argv_count_max); + if (buffer) memset(buffer, '\0', buffer_size); return false; } diff --git a/src/memory_file.c b/src/memory_file.c new file mode 100644 index 00000000..a721dedb --- /dev/null +++ b/src/memory_file.c @@ -0,0 +1,51 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +static int KernAux_MemoryFile_putc(void *file, unsigned char c); + +struct KernAux_MemoryFile KernAux_MemoryFile_create( + void *const ptr, + const size_t size, + const KernAux_Mutex mutex +) { + struct KernAux_MemoryFile memory_file; + KernAux_MemoryFile_init(&memory_file, ptr, size, mutex); + return memory_file; +} + +void KernAux_MemoryFile_init( + const KernAux_MemoryFile memory_file, + void *const ptr, + const size_t size, + const KernAux_Mutex mutex +) { + KERNAUX_ASSERT(memory_file); + KERNAUX_ASSERT(ptr); + KERNAUX_ASSERT(size); + + memory_file->file.putc = KernAux_MemoryFile_putc; + memory_file->file.puts = NULL; + memory_file->file.write = NULL; + memory_file->mutex = mutex; + memory_file->ptr = ptr; + memory_file->size = size; + memory_file->pos = 0; +} + +int KernAux_MemoryFile_putc(void *const file, const unsigned char c) +{ + const KernAux_MemoryFile memory_file = file; + KERNAUX_ASSERT(memory_file); + KERNAUX_ASSERT(memory_file->ptr); + KERNAUX_ASSERT(memory_file->size); + + if (memory_file->pos >= memory_file->size) return KERNAUX_EOF; + memory_file->ptr[memory_file->pos++] = c; + return c; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index d5d476e8..e0a1c822 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -290,6 +290,18 @@ test_pfa_assert_SOURCES = \ endif endif +############### +# test_printf # +############### + +if WITH_PRINTF +TESTS += test_printf +test_printf_LDADD = $(top_builddir)/libkernaux.la +test_printf_SOURCES = \ + main.c \ + test_printf.c +endif + ####################### # test_printf_fmt_gen # ####################### @@ -335,18 +347,6 @@ CLEANFILES += test_printf_gen.c test_printf_gen.c: printf_gen.py printf_gen.jinja $(top_srcdir)/common/printf.yml $(top_srcdir)/common/printf_orig.yml python3 printf_gen.py -################### -# test_printf_reg # -################### - -if WITH_PRINTF -TESTS += test_printf_reg -test_printf_reg_LDADD = $(top_builddir)/libkernaux.la -test_printf_reg_SOURCES = \ - main.c \ - test_printf_reg.c -endif - #################### # test_units_human # #################### diff --git a/tests/cmdline_gen.jinja b/tests/cmdline_gen.jinja index 7852df3c..99be76eb 100644 --- a/tests/cmdline_gen.jinja +++ b/tests/cmdline_gen.jinja @@ -3,6 +3,7 @@ #endif #include +#include #include #include @@ -82,33 +83,64 @@ void test( assert(argv); assert(buffer); - memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); - memset(argv, 'x', sizeof(char*) * argv_count_max); - memset(buffer, 'x', buffer_size); + { + memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); + memset(argv, 'x', sizeof(char*) * argv_count_max); + memset(buffer, 'x', buffer_size); - assert( - kernaux_cmdline( - cmdline, - error_msg, - &argc, - argv, - buffer, - argv_count_max, - buffer_size - ) == !!expected_result - ); + assert( + kernaux_cmdline( + cmdline, + error_msg, + &argc, + argv, + buffer, + argv_count_max, + buffer_size + ) == !!expected_result + ); - assert(strcmp(error_msg, expected_error_msg) == 0); - assert(argc == expected_argc); + assert(strcmp(error_msg, expected_error_msg) == 0); + assert(argc == expected_argc); - if (expected_argv) { - for (size_t index = 0; index < argc; ++index) { - assert(strcmp(argv[index], expected_argv[index]) == 0); + if (expected_argv) { + for (size_t index = 0; index < argc; ++index) { + assert(strcmp(argv[index], expected_argv[index]) == 0); + } + } + + for (size_t index = argc; index < argv_count_max; ++index) { + assert(argv[index] == NULL); } } - for (size_t index = argc; index < argv_count_max; ++index) { - assert(argv[index] == NULL); + if (strcmp(expected_error_msg, "too many args") != 0) { + memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); + memset(argv, 'x', sizeof(char*) * argv_count_max); + memset(buffer, 'x', buffer_size); + + struct KernAux_MemoryFile memory_file = + KernAux_MemoryFile_create(buffer, buffer_size, NULL); + + assert( + kernaux_cmdline_file( + cmdline, + error_msg, + &argc, + &memory_file.file + ) == !!expected_result + ); + + assert(strcmp(error_msg, expected_error_msg) == 0); + assert(argc == expected_argc); + + if (expected_argv) { + const char *arg = buffer; + for (size_t index = 0; index < argc; ++index) { + assert(strcmp(expected_argv[index], arg) == 0); + arg += strlen(arg) + 1; + } + } } free(error_msg); diff --git a/tests/test_cmdline.c b/tests/test_cmdline.c index 618783f7..996d7cf1 100644 --- a/tests/test_cmdline.c +++ b/tests/test_cmdline.c @@ -3,6 +3,7 @@ #endif #include +#include #include #include @@ -51,15 +52,15 @@ void test_main() test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 3, 12, true, "", 3, argv_backslashX3_X3); test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 3, 12, true, "", 3, argv_quotmarkX3_X3); - test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 2, 0, false, "too many args", 0, NULL); - test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 2, 0, false, "too many args", 0, NULL); - test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 2, 0, false, "too many args", 0, NULL); - test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 0, 11, false, "buffer overflow", 0, NULL); - test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 0, 11, false, "buffer overflow", 0, NULL); - test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 0, 11, false, "buffer overflow", 0, NULL); - test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 2, 11, false, "too many args", 0, NULL); - test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 2, 11, false, "too many args", 0, NULL); - test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 2, 11, false, "too many args", 0, NULL); + test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 2, 0, false, "too many args", 0, NULL); + test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 2, 0, false, "too many args", 0, NULL); + test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 2, 0, false, "too many args", 0, NULL); + test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 0, 11, false, "EOF or buffer overflow", 0, NULL); + test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 0, 11, false, "EOF or buffer overflow", 0, NULL); + test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 0, 11, false, "EOF or buffer overflow", 0, NULL); + test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 2, 11, false, "too many args", 0, NULL); + test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 2, 11, false, "too many args", 0, NULL); + test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 2, 11, false, "too many args", 0, NULL); test("\\", 0, 0, false, "EOL after backslash", 0, NULL); test(" \\", 0, 0, false, "EOL after backslash", 0, NULL); @@ -128,7 +129,7 @@ void test_main() memset(buffer, 'a', 4096); buffer[4096] = '\0'; // 4096 of "a" - test(buffer, 256, 4096, false, "buffer overflow", 0, NULL); + test(buffer, 256, 4096, false, "EOF or buffer overflow", 0, NULL); free(buffer); } } @@ -155,33 +156,64 @@ void test( assert(argv); assert(buffer); - memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); - memset(argv, 'x', sizeof(char*) * argv_count_max); - memset(buffer, 'x', buffer_size); + { + memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); + memset(argv, 'x', sizeof(char*) * argv_count_max); + memset(buffer, 'x', buffer_size); - assert( - kernaux_cmdline( - cmdline, - error_msg, - &argc, - argv, - buffer, - argv_count_max, - buffer_size - ) == !!expected_result - ); + assert( + kernaux_cmdline( + cmdline, + error_msg, + &argc, + argv, + buffer, + argv_count_max, + buffer_size + ) == !!expected_result + ); - assert(strcmp(error_msg, expected_error_msg) == 0); - assert(argc == expected_argc); + assert(strcmp(error_msg, expected_error_msg) == 0); + assert(argc == expected_argc); - if (expected_argv) { - for (size_t index = 0; index < argc; ++index) { - assert(strcmp(argv[index], expected_argv[index]) == 0); + if (expected_argv) { + for (size_t index = 0; index < argc; ++index) { + assert(strcmp(argv[index], expected_argv[index]) == 0); + } + } + + for (size_t index = argc; index < argv_count_max; ++index) { + assert(argv[index] == NULL); } } - for (size_t index = argc; index < argv_count_max; ++index) { - assert(argv[index] == NULL); + if (strcmp(expected_error_msg, "too many args") != 0) { + memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); + memset(argv, 'x', sizeof(char*) * argv_count_max); + memset(buffer, 'x', buffer_size); + + struct KernAux_MemoryFile memory_file = + KernAux_MemoryFile_create(buffer, buffer_size, NULL); + + assert( + kernaux_cmdline_file( + cmdline, + error_msg, + &argc, + &memory_file.file + ) == !!expected_result + ); + + assert(strcmp(error_msg, expected_error_msg) == 0); + assert(argc == expected_argc); + + if (expected_argv) { + const char *arg = buffer; + for (size_t index = 0; index < argc; ++index) { + assert(strcmp(expected_argv[index], arg) == 0); + arg += strlen(arg) + 1; + } + } } free(error_msg); diff --git a/tests/test_printf_reg.c b/tests/test_printf.c similarity index 100% rename from tests/test_printf_reg.c rename to tests/test_printf.c