Improve cmdline file API (#103)

This commit is contained in:
Alex Kotov 2022-06-27 19:30:47 +03:00 committed by GitHub
parent f39383128f
commit dacdfede2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 298 additions and 278 deletions

View File

@ -1,6 +1,7 @@
2022-06-27 Alex Kotov <kotovalexarian@gmail.com> 2022-06-27 Alex Kotov <kotovalexarian@gmail.com>
* include/kernaux/memory_file.h: Added * include/kernaux/memory_file.h: Added
* include/kernaux/cmdline: Added function "kernaux_cmdline_file"
2022-06-25 Alex Kotov <kotovalexarian@gmail.com> 2022-06-25 Alex Kotov <kotovalexarian@gmail.com>

View File

@ -8,7 +8,7 @@
#include <mruby/presym.h> #include <mruby/presym.h>
#include <mruby/string.h> #include <mruby/string.h>
#define ARGV_COUNT_MAX 256 #define ARG_COUNT_MAX 256
#define BUFFER_SIZE 4096 #define BUFFER_SIZE 4096
#ifdef KERNAUX_VERSION_WITH_CMDLINE #ifdef KERNAUX_VERSION_WITH_CMDLINE
@ -34,7 +34,7 @@ mrb_value rb_KernAux_cmdline(mrb_state *const mrb, mrb_value self)
mrb_get_args(mrb, "z", &str); mrb_get_args(mrb, "z", &str);
size_t argc; size_t argc;
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX]; char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
char **const argv = malloc(sizeof(char*) * ARGV_COUNT_MAX); char **const argv = malloc(sizeof(char*) * ARG_COUNT_MAX);
char *const buffer = malloc(BUFFER_SIZE); char *const buffer = malloc(BUFFER_SIZE);
const bool status = kernaux_cmdline( const bool status = kernaux_cmdline(
@ -43,7 +43,7 @@ mrb_value rb_KernAux_cmdline(mrb_state *const mrb, mrb_value self)
&argc, &argc,
argv, argv,
buffer, buffer,
ARGV_COUNT_MAX, ARG_COUNT_MAX,
BUFFER_SIZE BUFFER_SIZE
); );

View File

@ -79,11 +79,11 @@ if KernAux::Version.with_cmdline?
end end
cmdline = escape_str.call test['cmdline'] cmdline = escape_str.call test['cmdline']
argv_count_max = test['argv_count_max'] arg_count_max = test['arg_count_max']
buffer_size = test['buffer_size'] buffer_size = test['buffer_size']
result = test['result']&.map(&escape_str) result = test['result']&.map(&escape_str)
next unless argv_count_max.nil? && buffer_size.nil? && !result.nil? next unless arg_count_max.nil? && buffer_size.nil? && !result.nil?
assert "transforms #{cmdline.inspect} to #{result.inspect}" do assert "transforms #{cmdline.inspect} to #{result.inspect}" do
assert_equal KernAux.cmdline(cmdline), result assert_equal KernAux.cmdline(cmdline), result

View File

@ -2,12 +2,12 @@
#ifdef KERNAUX_VERSION_WITH_CMDLINE #ifdef KERNAUX_VERSION_WITH_CMDLINE
#define ARGV_COUNT_MAX 256 #define ARG_COUNT_MAX 256
#define BUFFER_SIZE 4096 #define BUFFER_SIZE 4096
struct Data { struct Data {
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX]; char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
char *argv[ARGV_COUNT_MAX]; char *argv[ARG_COUNT_MAX];
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
}; };
@ -64,7 +64,7 @@ VALUE rb_KernAux_cmdline(const VALUE self_rb, VALUE cmdline_rb)
&argc, &argc,
data->argv, data->argv,
data->buffer, data->buffer,
ARGV_COUNT_MAX, ARG_COUNT_MAX,
BUFFER_SIZE BUFFER_SIZE
); );

View File

@ -100,11 +100,11 @@ KernAux::Version.with_cmdline? and RSpec.describe KernAux, '.cmdline' do
end end
cmdline = escape_str.call test['cmdline'] cmdline = escape_str.call test['cmdline']
argv_count_max = test['argv_count_max'] arg_count_max = test['arg_count_max']
buffer_size = test['buffer_size'] buffer_size = test['buffer_size']
result = test['result']&.map(&escape_str) result = test['result']&.map(&escape_str)
next unless argv_count_max.nil? && buffer_size.nil? && !result.nil? next unless arg_count_max.nil? && buffer_size.nil? && !result.nil?
it "transforms #{cmdline.inspect} to #{result.inspect}" do it "transforms #{cmdline.inspect} to #{result.inspect}" do
expect(described_class.cmdline(cmdline)).to eq result expect(described_class.cmdline(cmdline)).to eq result

View File

@ -13,7 +13,7 @@ extern "C" {
argc: *mut size_t, argc: *mut size_t,
argv: *mut *mut c_char, argv: *mut *mut c_char,
buffer: *mut c_char, buffer: *mut c_char,
argv_count_max: size_t, arg_count_max: size_t,
buffer_size: size_t, buffer_size: size_t,
) -> bool; ) -> bool;
} }
@ -24,7 +24,7 @@ mod tests {
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
const ARGV_COUNT_MAX: usize = 100; const ARG_COUNT_MAX: usize = 100;
const BUFFER_SIZE: usize = 4096; const BUFFER_SIZE: usize = 4096;
#[test] #[test]
@ -34,8 +34,8 @@ mod tests {
let mut error_msg: [c_char; ERROR_MSG_SIZE_MAX] = let mut error_msg: [c_char; ERROR_MSG_SIZE_MAX] =
[0; ERROR_MSG_SIZE_MAX]; [0; ERROR_MSG_SIZE_MAX];
let mut argc: size_t = 0; let mut argc: size_t = 0;
let mut argv: [*mut c_char; ARGV_COUNT_MAX] = let mut argv: [*mut c_char; ARG_COUNT_MAX] =
[0 as *mut c_char; ARGV_COUNT_MAX]; [0 as *mut c_char; ARG_COUNT_MAX];
let mut buffer: [c_char; BUFFER_SIZE] = [0; BUFFER_SIZE]; let mut buffer: [c_char; BUFFER_SIZE] = [0; BUFFER_SIZE];
unsafe { unsafe {
@ -45,7 +45,7 @@ mod tests {
&mut argc, &mut argc,
argv.as_mut_ptr(), argv.as_mut_ptr(),
buffer.as_mut_ptr(), buffer.as_mut_ptr(),
ARGV_COUNT_MAX, ARG_COUNT_MAX,
BUFFER_SIZE, BUFFER_SIZE,
)); ));
} }

View File

@ -51,46 +51,46 @@
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
argv_count_max: 3 arg_count_max: 3
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
buffer_size: 12 buffer_size: 12
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
argv_count_max: 3 arg_count_max: 3
buffer_size: 12 buffer_size: 12
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
argv_count_max: 2 arg_count_max: 2
error: 'too many args' error: 'too many args'
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
buffer_size: 11 buffer_size: 11
error: 'EOF or buffer overflow' error: 'EOF or buffer overflow'
- cmdline: 'foo bar car' - cmdline: 'foo bar car'
argv_count_max: 2 arg_count_max: 2
buffer_size: 11 buffer_size: 11
error: 'too many args' error: 'too many args'
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 3 arg_count_max: 3
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
buffer_size: 12 buffer_size: 12
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 3 arg_count_max: 3
buffer_size: 12 buffer_size: 12
result: ['foo', 'bar', 'car'] result: ['foo', 'bar', 'car']
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 2 arg_count_max: 2
error: 'too many args' error: 'too many args'
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
buffer_size: 11 buffer_size: 11
error: 'EOF or buffer overflow' error: 'EOF or buffer overflow'
- cmdline: '\"foo\" \"bar\" \"car\"' - cmdline: '\"foo\" \"bar\" \"car\"'
argv_count_max: 2 arg_count_max: 2
buffer_size: 11 buffer_size: 11
error: 'too many args' error: 'too many args'

View File

@ -4,7 +4,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#define ARGV_COUNT_MAX 100 #define ARG_COUNT_MAX 100
#define BUFFER_SIZE 4096 #define BUFFER_SIZE 4096
static const char *const cmdline = "foo bar\\ baz \"car cdr\""; static const char *const cmdline = "foo bar\\ baz \"car cdr\"";
@ -13,7 +13,7 @@ void example_main()
{ {
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX]; char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
size_t argc; size_t argc;
char *argv[ARGV_COUNT_MAX]; char *argv[ARG_COUNT_MAX];
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
assert(kernaux_cmdline( assert(kernaux_cmdline(
@ -22,7 +22,7 @@ void example_main()
&argc, &argc,
argv, argv,
buffer, buffer,
ARGV_COUNT_MAX, ARG_COUNT_MAX,
BUFFER_SIZE BUFFER_SIZE
)); ));

View File

@ -5,22 +5,62 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#define ARG_COUNT_MAX 100
#define BUFFER_SIZE 4096
static const char *const cmdline = "foo bar\\ baz \"car cdr\""; static const char *const cmdline = "foo bar\\ baz \"car cdr\"";
static char buffer[4096]; static void with_args_indices_array();
static void without_args_indices_array();
void example_main() void example_main()
{
with_args_indices_array();
without_args_indices_array();
}
void with_args_indices_array()
{ {
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX]; char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
size_t argc; size_t argc;
size_t argv[ARG_COUNT_MAX];
char buffer[BUFFER_SIZE];
struct KernAux_MemoryFile memory_file = struct KernAux_MemoryFile memory_file =
KernAux_MemoryFile_create(buffer, sizeof(buffer), NULL); KernAux_MemoryFile_create(buffer, BUFFER_SIZE, NULL);
assert(kernaux_cmdline_file( assert(kernaux_cmdline_file(
cmdline, cmdline,
error_msg, error_msg,
&argc, &argc,
&memory_file.file &memory_file.file,
argv,
ARG_COUNT_MAX
));
assert(strcmp(error_msg, "") == 0);
assert(argc == 3);
assert(strcmp(&buffer[argv[0]], "foo") == 0);
assert(strcmp(&buffer[argv[1]], "bar baz") == 0);
assert(strcmp(&buffer[argv[2]], "car cdr") == 0);
}
void without_args_indices_array()
{
char error_msg[KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX];
size_t argc;
char buffer[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,
NULL,
0
)); ));
assert(strcmp(error_msg, "") == 0); assert(strcmp(error_msg, "") == 0);

View File

@ -20,7 +20,7 @@ bool kernaux_cmdline(
size_t *argc, size_t *argc,
char **argv, char **argv,
char *buffer, char *buffer,
size_t argv_count_max, size_t arg_count_max,
size_t buffer_size size_t buffer_size
); );
@ -28,7 +28,9 @@ bool kernaux_cmdline_file(
const char *cmdline, const char *cmdline,
char *error_msg, char *error_msg,
size_t *argc, size_t *argc,
KernAux_File file KernAux_File file,
size_t *arg_idxs,
size_t arg_count_max
); );
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -25,9 +25,10 @@ static bool kernaux_cmdline_common(
char arg_terminator, char arg_terminator,
char **argv, char **argv,
char *buffer, char *buffer,
size_t argv_count_max, KernAux_File file,
size_t buffer_size, size_t *arg_idxs,
KernAux_File file size_t arg_count_max,
size_t buffer_size
); );
/***************************** /*****************************
@ -40,14 +41,14 @@ bool kernaux_cmdline(
size_t *const argc, size_t *const argc,
char **const argv, char **const argv,
char *const buffer, char *const buffer,
const size_t argv_count_max, const size_t arg_count_max,
const size_t buffer_size const size_t buffer_size
) { ) {
KERNAUX_ASSERT(cmdline); KERNAUX_ASSERT(cmdline);
KERNAUX_ASSERT(error_msg); KERNAUX_ASSERT(error_msg);
KERNAUX_ASSERT(argc); KERNAUX_ASSERT(argc);
KERNAUX_ASSERT(argv); KERNAUX_ASSERT(argv);
KERNAUX_ASSERT(argv_count_max > 0); KERNAUX_ASSERT(arg_count_max > 0);
KERNAUX_ASSERT(buffer_size > 0); KERNAUX_ASSERT(buffer_size > 0);
return kernaux_cmdline_common( return kernaux_cmdline_common(
@ -57,9 +58,10 @@ bool kernaux_cmdline(
'\0', // arg_terminator '\0', // arg_terminator
argv, argv,
buffer, buffer,
argv_count_max, NULL,
buffer_size, NULL,
NULL arg_count_max,
buffer_size
); );
} }
@ -67,12 +69,15 @@ bool kernaux_cmdline_file(
const char *const cmdline, const char *const cmdline,
char *const error_msg, char *const error_msg,
size_t *const argc, size_t *const argc,
const KernAux_File file const KernAux_File file,
size_t *arg_idxs,
size_t arg_count_max
) { ) {
KERNAUX_ASSERT(cmdline); KERNAUX_ASSERT(cmdline);
KERNAUX_ASSERT(error_msg); KERNAUX_ASSERT(error_msg);
KERNAUX_ASSERT(argc); KERNAUX_ASSERT(argc);
KERNAUX_ASSERT(file); KERNAUX_ASSERT(file);
KERNAUX_ASSERT(arg_idxs == NULL || arg_count_max > 0);
return kernaux_cmdline_common( return kernaux_cmdline_common(
cmdline, cmdline,
@ -81,9 +86,10 @@ bool kernaux_cmdline_file(
'\0', // arg_terminator '\0', // arg_terminator
NULL, NULL,
NULL, NULL,
0, file,
0, arg_idxs,
file arg_count_max,
0
); );
} }
@ -91,52 +97,67 @@ bool kernaux_cmdline_file(
* Implementation: main internal function * * Implementation: main internal function *
******************************************/ ******************************************/
#define CLEAR do { \
*argc = 0; \
if (argv) memset(argv, 0, sizeof(char*) * arg_count_max); \
if (buffer) memset(buffer, '\0', buffer_size); \
if (arg_idxs) memset(arg_idxs, 0, sizeof(size_t) * arg_count_max); \
} while (0)
#define FAIL(msg) do { \ #define FAIL(msg) do { \
strcpy(error_msg, msg); \ strcpy(error_msg, msg); \
goto fail; \ goto fail; \
} while (0) } while (0)
#define PUT_CHAR(char) do { \ #define PUT_CHAR(char) do { \
if (buffer_size && buffer_pos >= buffer_size) { \ if (buffer_size && buffer_or_file_pos >= buffer_size) { \
FAIL("EOF or buffer overflow"); \ FAIL("EOF or buffer overflow"); \
} \ } \
if (buffer) { \ if (buffer) { \
buffer[buffer_pos++] = char; \ buffer[buffer_or_file_pos] = char; \
} \ } \
if (file) { \ if (file) { \
if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \
FAIL("EOF or buffer overflow"); \ FAIL("EOF or buffer overflow"); \
} \ } \
} \ } \
++buffer_or_file_pos; \
} while (0) } while (0)
#define PUT_ARG do { \ #define PUT_ARG do { \
if (argv_count_max && *argc >= argv_count_max) { \ if (arg_count_max && *argc >= arg_count_max) { \
FAIL("too many args"); \ FAIL("too many args"); \
} \ } \
if (argv && buffer) { \ if (argv && buffer) { \
argv[*argc] = &buffer[buffer_pos]; \ argv[*argc] = &buffer[buffer_or_file_pos]; \
} \ } \
++(*argc); \ if (arg_idxs) { \
arg_idxs[*argc] = buffer_or_file_pos; \
} \
++(*argc); \
} while (0) } while (0)
#define PUT_ARG_AND_CHAR(char) do { \ #define PUT_ARG_AND_CHAR(char) do { \
if (argv_count_max && *argc >= argv_count_max) { \ if (arg_count_max && *argc >= arg_count_max) { \
FAIL("too many args"); \ FAIL("too many args"); \
} \ } \
if (buffer_size && buffer_pos >= buffer_size) { \ if (buffer_size && buffer_or_file_pos >= buffer_size) { \
FAIL("EOF or buffer overflow"); \ FAIL("EOF or buffer overflow"); \
} \ } \
if (argv && buffer) { \ if (argv && buffer) { \
argv[*argc] = &buffer[buffer_pos]; \ argv[*argc] = &buffer[buffer_or_file_pos]; \
buffer[buffer_pos++] = char; \ buffer[buffer_or_file_pos] = char; \
} \ } \
if (file) { \ if (file) { \
if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \ if (KernAux_File_putc(file, char) == KERNAUX_EOF) { \
FAIL("EOF or buffer overflow"); \ FAIL("EOF or buffer overflow"); \
} \ } \
} \ } \
if (arg_idxs) { \
arg_idxs[*argc] = buffer_or_file_pos; \
} \
++(*argc); \ ++(*argc); \
++buffer_or_file_pos; \
} while (0) } while (0)
bool kernaux_cmdline_common( bool kernaux_cmdline_common(
@ -146,23 +167,23 @@ bool kernaux_cmdline_common(
char arg_terminator, char arg_terminator,
char **const argv, char **const argv,
char *const buffer, char *const buffer,
const size_t argv_count_max, const KernAux_File file,
const size_t buffer_size, size_t *const arg_idxs,
const KernAux_File file const size_t arg_count_max,
const size_t buffer_size
) { ) {
KERNAUX_ASSERT(cmdline); KERNAUX_ASSERT(cmdline);
KERNAUX_ASSERT(error_msg); KERNAUX_ASSERT(error_msg);
KERNAUX_ASSERT(argc); KERNAUX_ASSERT(argc);
(void)arg_idxs;
memset(error_msg, '\0', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX); memset(error_msg, '\0', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
*argc = 0; CLEAR;
if (argv) memset(argv, 0, sizeof(char*) * argv_count_max);
if (buffer) memset(buffer, '\0', buffer_size);
if (cmdline[0] == '\0') return true; if (cmdline[0] == '\0') return true;
enum State state = INITIAL; enum State state = INITIAL;
size_t buffer_pos = 0; size_t buffer_or_file_pos = 0;
for (size_t index = 0; ; ++index) { for (size_t index = 0; ; ++index) {
const char cur = cmdline[index]; const char cur = cmdline[index];
@ -259,8 +280,6 @@ bool kernaux_cmdline_common(
return true; return true;
fail: fail:
*argc = 0; CLEAR;
if (argv) memset(argv, 0, sizeof(char*) * argv_count_max);
if (buffer) memset(buffer, '\0', buffer_size);
return false; return false;
} }

View File

@ -65,7 +65,9 @@ TESTS += test_cmdline
test_cmdline_LDADD = $(top_builddir)/libkernaux.la test_cmdline_LDADD = $(top_builddir)/libkernaux.la
test_cmdline_SOURCES = \ test_cmdline_SOURCES = \
main.c \ main.c \
test_cmdline.c test_cmdline.c \
cmdline_test.h \
cmdline_test.c
endif endif
#################### ####################
@ -81,7 +83,9 @@ test_cmdline_gen_SOURCES = \
test_cmdline_gen.c \ test_cmdline_gen.c \
cmdline_gen.py \ cmdline_gen.py \
cmdline_gen.jinja \ cmdline_gen.jinja \
$(top_srcdir)/common/cmdline.yml $(top_srcdir)/common/cmdline.yml \
cmdline_test.h \
cmdline_test.c
endif endif
endif endif

View File

@ -2,29 +2,13 @@
#include "config.h" #include "config.h"
#endif #endif
#include <kernaux/cmdline.h> #include "cmdline_test.h"
#include <kernaux/memory_file.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define ARGV_COUNT_MAX 100
#define BUFFER_SIZE 4096
static void test(
const char *cmdline,
size_t argv_count_max,
size_t buffer_size,
bool expected_result,
const char *expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
);
void test_main() void test_main()
{ {
{% for case in cases %} {% for case in cases %}
@ -39,7 +23,7 @@ void test_main()
test( test(
{{ escape_str(case.cmdline) }}, {{ escape_str(case.cmdline) }},
{{ escape_int(case.argv_count_max or 0) }}, {{ escape_int(case.arg_count_max or 0) }},
{{ escape_int(case.buffer_size or 0) }}, {{ escape_int(case.buffer_size or 0) }},
{% if not case.error %} {% if not case.error %}
true, true,
@ -60,90 +44,3 @@ void test_main()
} }
{% endfor %} {% endfor %}
} }
void test(
const char *const cmdline,
size_t argv_count_max,
size_t buffer_size,
const bool expected_result,
const char *const expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
) {
if (argv_count_max == 0) argv_count_max = ARGV_COUNT_MAX;
if (buffer_size == 0) buffer_size = BUFFER_SIZE;
char *error_msg = malloc(KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
size_t argc = 1234;
char **const argv = malloc(sizeof(char*) * argv_count_max);
char *const buffer = malloc(buffer_size);
assert(error_msg);
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);
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);
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);
}
}
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);
free(argv);
free(buffer);
}

134
tests/cmdline_test.c Normal file
View File

@ -0,0 +1,134 @@
#include "cmdline_test.h"
#include <kernaux/cmdline.h>
#include <kernaux/memory_file.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define ARG_COUNT_MAX 100
#define BUFFER_SIZE 4096
void test(
const char *const cmdline,
size_t arg_count_max,
size_t buffer_size,
const bool expected_result,
const char *const expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
) {
if (arg_count_max == 0) arg_count_max = ARG_COUNT_MAX;
if (buffer_size == 0) buffer_size = BUFFER_SIZE;
char *error_msg = malloc(KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
size_t argc = 1234;
char **const argv = malloc(sizeof(char*) * arg_count_max);
size_t *arg_idxs = malloc(sizeof(size_t) * arg_count_max);
char *const buffer = malloc(buffer_size);
assert(error_msg);
assert(argv);
assert(buffer);
{
memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
memset(argv, 0, sizeof(char*) * arg_count_max);
memset(arg_idxs, 0, sizeof(size_t) * arg_count_max);
memset(buffer, 'x', buffer_size);
assert(
kernaux_cmdline(
cmdline,
error_msg,
&argc,
argv,
buffer,
arg_count_max,
buffer_size
) == !!expected_result
);
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);
}
}
for (size_t index = argc; index < arg_count_max; ++index) {
assert(argv[index] == NULL);
}
}
{
memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
memset(argv, 0, sizeof(char*) * arg_count_max);
memset(arg_idxs, 0, sizeof(size_t) * arg_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,
arg_idxs,
arg_count_max
) == !!expected_result
);
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(&buffer[arg_idxs[index]], expected_argv[index]) == 0);
}
}
}
if (strcmp(expected_error_msg, "too many args") != 0) {
memset(error_msg, 'x', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
memset(argv, 0, sizeof(char*) * arg_count_max);
memset(arg_idxs, 0, sizeof(size_t) * arg_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,
NULL,
0
) == !!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);
free(argv);
free(arg_idxs);
free(buffer);
}

26
tests/cmdline_test.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef KERNAUX_INCLUDED_TESTS_CMDLINE_TEST
#define KERNAUX_INCLUDED_TESTS_CMDLINE_TEST
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
void test(
const char *cmdline,
size_t arg_count_max,
size_t buffer_size,
bool expected_result,
const char *expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -2,29 +2,13 @@
#include "config.h" #include "config.h"
#endif #endif
#include <kernaux/cmdline.h> #include "cmdline_test.h"
#include <kernaux/memory_file.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define ARGV_COUNT_MAX 100
#define BUFFER_SIZE 4096
static void test(
const char *cmdline,
size_t argv_count_max,
size_t buffer_size,
bool expected_result,
const char *expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
);
static const char *const argv_spaceX3_X3[] = {" ", " ", " "}; static const char *const argv_spaceX3_X3[] = {" ", " ", " "};
static const char *const argv_backslashX3_X3[] = {"\\\\\\", "\\\\\\", "\\\\\\"}; static const char *const argv_backslashX3_X3[] = {"\\\\\\", "\\\\\\", "\\\\\\"};
static const char *const argv_quotmarkX3_X3[] = {"\"\"\"", "\"\"\"", "\"\"\""}; static const char *const argv_quotmarkX3_X3[] = {"\"\"\"", "\"\"\"", "\"\"\""};
@ -133,90 +117,3 @@ void test_main()
free(buffer); free(buffer);
} }
} }
void test(
const char *const cmdline,
size_t argv_count_max,
size_t buffer_size,
const bool expected_result,
const char *const expected_error_msg,
size_t expected_argc,
const char *const *const expected_argv
) {
if (argv_count_max == 0) argv_count_max = ARGV_COUNT_MAX;
if (buffer_size == 0) buffer_size = BUFFER_SIZE;
char *error_msg = malloc(KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
size_t argc = 1234;
char **const argv = malloc(sizeof(char*) * argv_count_max);
char *const buffer = malloc(buffer_size);
assert(error_msg);
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);
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);
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);
}
}
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);
free(argv);
free(buffer);
}