mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-27 11:14:42 -05:00
Implement quotes in cmd line parser
This commit is contained in:
parent
02ce7005e6
commit
09f05356e0
3 changed files with 93 additions and 7 deletions
|
@ -6,7 +6,7 @@
|
||||||
static const unsigned int ARGV_COUNT_MAX = 100;
|
static const unsigned int ARGV_COUNT_MAX = 100;
|
||||||
static const unsigned int ARG_SIZE_MAX = 4096;
|
static const unsigned int ARG_SIZE_MAX = 4096;
|
||||||
|
|
||||||
static const char *const cmdline = "foo bar\\ car";
|
static const char *const cmdline = "foo bar\\ baz \"car cdr\"";
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
@ -26,9 +26,10 @@ int main()
|
||||||
));
|
));
|
||||||
|
|
||||||
assert(strcmp(error_msg, "") == 0);
|
assert(strcmp(error_msg, "") == 0);
|
||||||
assert(argc == 2);
|
assert(argc == 3);
|
||||||
assert(strcmp(argv[0], "foo") == 0);
|
assert(strcmp(argv[0], "foo") == 0);
|
||||||
assert(strcmp(argv[1], "bar car") == 0);
|
assert(strcmp(argv[1], "bar baz") == 0);
|
||||||
|
assert(strcmp(argv[2], "car cdr") == 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ enum State {
|
||||||
WHITESPACE,
|
WHITESPACE,
|
||||||
TOKEN,
|
TOKEN,
|
||||||
BACKSLASHED,
|
BACKSLASHED,
|
||||||
|
QUOTED,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool kernaux_cmdline_parse(
|
bool kernaux_cmdline_parse(
|
||||||
|
@ -75,6 +76,15 @@ bool kernaux_cmdline_parse(
|
||||||
state = BACKSLASHED;
|
state = BACKSLASHED;
|
||||||
argv[(*argc)++] = buffer;
|
argv[(*argc)++] = buffer;
|
||||||
}
|
}
|
||||||
|
else if (cur == '"') {
|
||||||
|
if (*argc >= argv_count_max) {
|
||||||
|
kernaux_strncpy(error_msg, "too many args", 13);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = QUOTED;
|
||||||
|
argv[(*argc)++] = buffer;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (*argc >= argv_count_max) {
|
if (*argc >= argv_count_max) {
|
||||||
kernaux_strncpy(error_msg, "too many args", 13);
|
kernaux_strncpy(error_msg, "too many args", 13);
|
||||||
|
@ -108,6 +118,15 @@ bool kernaux_cmdline_parse(
|
||||||
state = BACKSLASHED;
|
state = BACKSLASHED;
|
||||||
argv[(*argc)++] = buffer;
|
argv[(*argc)++] = buffer;
|
||||||
}
|
}
|
||||||
|
else if (cur == '"') {
|
||||||
|
if (*argc >= argv_count_max) {
|
||||||
|
kernaux_strncpy(error_msg, "too many args", 13);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = QUOTED;
|
||||||
|
argv[(*argc)++] = buffer;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (*argc >= argv_count_max) {
|
if (*argc >= argv_count_max) {
|
||||||
kernaux_strncpy(error_msg, "too many args", 13);
|
kernaux_strncpy(error_msg, "too many args", 13);
|
||||||
|
@ -150,6 +169,10 @@ bool kernaux_cmdline_parse(
|
||||||
else if (cur == '\\') {
|
else if (cur == '\\') {
|
||||||
state = BACKSLASHED;
|
state = BACKSLASHED;
|
||||||
}
|
}
|
||||||
|
else if (cur == '"') {
|
||||||
|
kernaux_strncpy(error_msg, "unescaped quotation mark", 24);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (buffer_size >= arg_size_max) {
|
if (buffer_size >= arg_size_max) {
|
||||||
kernaux_strncpy(error_msg, "arg too long", 12);
|
kernaux_strncpy(error_msg, "arg too long", 12);
|
||||||
|
@ -177,6 +200,32 @@ bool kernaux_cmdline_parse(
|
||||||
++buffer_size;
|
++buffer_size;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QUOTED:
|
||||||
|
if (cur == '\0') {
|
||||||
|
kernaux_strncpy(error_msg, "EOL inside quote", 16);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
else if (cur == '"') {
|
||||||
|
if (buffer_size >= arg_size_max) {
|
||||||
|
kernaux_strncpy(error_msg, "arg too long", 12);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = WHITESPACE;
|
||||||
|
*(buffer++) = '\0';
|
||||||
|
buffer_size = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (buffer_size >= arg_size_max) {
|
||||||
|
kernaux_strncpy(error_msg, "arg too long", 12);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(buffer++) = cur;
|
||||||
|
++buffer_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == FINAL) {
|
if (state == FINAL) {
|
||||||
|
|
|
@ -25,10 +25,21 @@ static void test(
|
||||||
|
|
||||||
static const char *const argv0[] = {};
|
static const char *const argv0[] = {};
|
||||||
|
|
||||||
|
static const char *const argv_empty[] = {""};
|
||||||
|
static const char *const argv_empty_X2[] = {"", ""};
|
||||||
|
static const char *const argv_empty_X3[] = {"", "", ""};
|
||||||
|
|
||||||
static const char *const argv_foo[] = {"foo"};
|
static const char *const argv_foo[] = {"foo"};
|
||||||
static const char *const argv_foo_bar[] = {"foo", "bar"};
|
static const char *const argv_foo_bar[] = {"foo", "bar"};
|
||||||
static const char *const argv_foo_bar_car[] = {"foo", "bar", "car"};
|
static const char *const argv_foo_bar_car[] = {"foo", "bar", "car"};
|
||||||
|
|
||||||
|
static const char *const argv_spaceX3_X3[] = {" ", " ", " "};
|
||||||
|
static const char *const argv_backslashX3_X3[] = {"\\\\\\", "\\\\\\", "\\\\\\"};
|
||||||
|
static const char *const argv_quotmarkX3_X3[] = {"\"\"\"", "\"\"\"", "\"\"\""};
|
||||||
|
|
||||||
|
static const char *const argv_foospacebar_car[] = {"foo bar", "car"};
|
||||||
|
static const char *const argv_foo_barspacecar[] = {"foo", "bar car"};
|
||||||
|
|
||||||
static const char *const argv_space[] = {" "};
|
static const char *const argv_space[] = {" "};
|
||||||
static const char *const argv_backslash[] = {"\\"};
|
static const char *const argv_backslash[] = {"\\"};
|
||||||
static const char *const argv_quotmark[] = {"\""};
|
static const char *const argv_quotmark[] = {"\""};
|
||||||
|
@ -63,10 +74,6 @@ static const char *const argv_foo_spacebarspace[] = {"foo", " bar "};
|
||||||
static const char *const argv_foo_backslashbarbackslash[] = {"foo", "\\bar\\"};
|
static const char *const argv_foo_backslashbarbackslash[] = {"foo", "\\bar\\"};
|
||||||
static const char *const argv_foo_quotmarkbarquotmark[] = {"foo", "\"bar\""};
|
static const char *const argv_foo_quotmarkbarquotmark[] = {"foo", "\"bar\""};
|
||||||
|
|
||||||
static const char *const argv_spaceX3_X3[] = {" ", " ", " "};
|
|
||||||
static const char *const argv_backslashX3_X3[] = {"\\\\\\", "\\\\\\", "\\\\\\"};
|
|
||||||
static const char *const argv_quotmarkX3_X3[] = {"\"\"\"", "\"\"\"", "\"\"\""};
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
test("", 0, 0, true, "", 0, argv0);
|
test("", 0, 0, true, "", 0, argv0);
|
||||||
|
@ -82,6 +89,20 @@ int main()
|
||||||
test(" foo bar ", 0, 0, true, "", 2, argv_foo_bar);
|
test(" foo bar ", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
test("foo bar car", 0, 0, true, "", 3, argv_foo_bar_car);
|
test("foo bar car", 0, 0, true, "", 3, argv_foo_bar_car);
|
||||||
|
|
||||||
|
test("\"\"", 0, 0, true, "", 1, argv_empty);
|
||||||
|
test("\"\" \"\"", 0, 0, true, "", 2, argv_empty_X2);
|
||||||
|
test("\"\" \"\" \"\"", 0, 0, true, "", 3, argv_empty_X3);
|
||||||
|
test("\"foo\"", 0, 0, true, "", 1, argv_foo);
|
||||||
|
test("\"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test(" \"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test("\"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test(" \"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test("\"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test("\"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test(" \"foo\" \"bar\"", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test(" \"foo\" \"bar\" ", 0, 0, true, "", 2, argv_foo_bar);
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 0, 0, true, "", 3, argv_foo_bar_car);
|
||||||
|
|
||||||
test("foo bar car", 3, 0, true, "", 3, argv_foo_bar_car);
|
test("foo bar car", 3, 0, true, "", 3, argv_foo_bar_car);
|
||||||
test("foo bar car", 0, 4, true, "", 3, argv_foo_bar_car);
|
test("foo bar car", 0, 4, true, "", 3, argv_foo_bar_car);
|
||||||
test("foo bar car", 3, 4, true, "", 3, argv_foo_bar_car);
|
test("foo bar car", 3, 4, true, "", 3, argv_foo_bar_car);
|
||||||
|
@ -90,6 +111,14 @@ int main()
|
||||||
test("foo bar car", 0, 3, false, "arg too long", 0, argv0);
|
test("foo bar car", 0, 3, false, "arg too long", 0, argv0);
|
||||||
test("foo bar car", 2, 3, false, "arg too long", 0, argv0);
|
test("foo bar car", 2, 3, false, "arg too long", 0, argv0);
|
||||||
|
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 3, 0, true, "", 3, argv_foo_bar_car);
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 0, 4, true, "", 3, argv_foo_bar_car);
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 3, 4, true, "", 3, argv_foo_bar_car);
|
||||||
|
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 2, 0, false, "too many args", 0, argv0);
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 0, 3, false, "arg too long", 0, argv0);
|
||||||
|
test("\"foo\" \"bar\" \"car\"", 2, 3, false, "arg too long", 0, argv0);
|
||||||
|
|
||||||
test("\\ ", 0, 0, true, "", 1, argv_space);
|
test("\\ ", 0, 0, true, "", 1, argv_space);
|
||||||
test("\\\\", 0, 0, true, "", 1, argv_backslash);
|
test("\\\\", 0, 0, true, "", 1, argv_backslash);
|
||||||
test("\\\"", 0, 0, true, "", 1, argv_quotmark);
|
test("\\\"", 0, 0, true, "", 1, argv_quotmark);
|
||||||
|
@ -124,6 +153,13 @@ int main()
|
||||||
test("foo \\\\bar\\\\", 0, 0, true, "", 2, argv_foo_backslashbarbackslash);
|
test("foo \\\\bar\\\\", 0, 0, true, "", 2, argv_foo_backslashbarbackslash);
|
||||||
test("foo \\\"bar\\\"", 0, 0, true, "", 2, argv_foo_quotmarkbarquotmark);
|
test("foo \\\"bar\\\"", 0, 0, true, "", 2, argv_foo_quotmarkbarquotmark);
|
||||||
|
|
||||||
|
test("foo\\ bar car", 0, 0, true, "", 2, argv_foospacebar_car);
|
||||||
|
test("\"foo bar\" car", 0, 0, true, "", 2, argv_foospacebar_car);
|
||||||
|
test("\"foo bar\" \"car\"", 0, 0, true, "", 2, argv_foospacebar_car);
|
||||||
|
test("foo bar\\ car", 0, 0, true, "", 2, argv_foo_barspacecar);
|
||||||
|
test("foo \"bar car\"", 0, 0, true, "", 2, argv_foo_barspacecar);
|
||||||
|
test("\"foo\" \"bar car\"", 0, 0, true, "", 2, argv_foo_barspacecar);
|
||||||
|
|
||||||
test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 3, 0, true, "", 3, argv_spaceX3_X3);
|
test("\\ \\ \\ \\ \\ \\ \\ \\ \\ ", 3, 0, true, "", 3, argv_spaceX3_X3);
|
||||||
test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 3, 0, true, "", 3, argv_backslashX3_X3);
|
test("\\\\\\\\\\\\ \\\\\\\\\\\\ \\\\\\\\\\\\", 3, 0, true, "", 3, argv_backslashX3_X3);
|
||||||
test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 3, 0, true, "", 3, argv_quotmarkX3_X3);
|
test("\\\"\\\"\\\" \\\"\\\"\\\" \\\"\\\"\\\"", 3, 0, true, "", 3, argv_quotmarkX3_X3);
|
||||||
|
|
Loading…
Reference in a new issue