libkernaux/src/cmdline.c

195 lines
4.9 KiB
C
Raw Normal View History

2020-12-01 19:55:16 +00:00
#include "config.h"
#include <kernaux/cmdline.h>
2020-12-01 20:22:38 +00:00
2020-12-04 02:41:45 +00:00
enum State {
INITIAL,
FINAL,
WHITESPACE,
TOKEN,
BACKSLASHED,
2020-12-04 02:41:45 +00:00
};
2020-12-01 20:22:38 +00:00
kernaux_bool kernaux_cmdline_parse(
const char *const cmdline,
char *error_msg,
unsigned int *const argc,
char **argv,
char *buffer,
const unsigned int argv_count_max,
const unsigned int arg_size_max
) {
if (
cmdline == KERNAUX_NULL ||
error_msg == KERNAUX_NULL ||
argc == KERNAUX_NULL ||
argv == KERNAUX_NULL ||
argv_count_max == 0 ||
arg_size_max == 0
) {
return KERNAUX_FALSE;
}
kernaux_memset(error_msg, '\0', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
*argc = 0;
for (unsigned int index = 0; index < argv_count_max; ++index) {
argv[index] = KERNAUX_NULL;
}
kernaux_memset(buffer, '\0', argv_count_max * arg_size_max);
if (cmdline[0] == '\0') {
return KERNAUX_TRUE;
}
2020-12-04 02:41:45 +00:00
enum State state = INITIAL;
2020-12-05 21:47:19 +00:00
unsigned int buffer_size = 0;
2020-12-04 02:41:45 +00:00
for (unsigned int index = 0; ; ++index) {
const char cur = cmdline[index];
switch (state) {
case FINAL:
break; // Case break; loop break after switch.
2020-12-04 02:41:45 +00:00
case INITIAL:
if (cur == '\0') {
state = FINAL;
}
else if (cur == ' ') {
state = WHITESPACE;
}
else if (cur == '\\') {
if (*argc >= argv_count_max) {
kernaux_strncpy(error_msg, "too many args", 13);
goto fail;
}
state = BACKSLASHED;
argv[(*argc)++] = buffer;
}
2020-12-04 02:41:45 +00:00
else {
2020-12-05 21:47:19 +00:00
if (*argc >= argv_count_max) {
kernaux_strncpy(error_msg, "too many args", 13);
goto fail;
}
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
2020-12-04 02:41:45 +00:00
state = TOKEN;
2020-12-05 21:47:19 +00:00
argv[(*argc)++] = buffer;
*(buffer++) = cur;
++buffer_size;
2020-12-04 02:41:45 +00:00
}
break;
2020-12-04 02:41:45 +00:00
case WHITESPACE:
if (cur == '\0') {
state = FINAL;
}
else if (cur == ' ') {
}
else if (cur == '\\') {
if (*argc >= argv_count_max) {
kernaux_strncpy(error_msg, "too many args", 13);
goto fail;
}
state = BACKSLASHED;
argv[(*argc)++] = buffer;
}
2020-12-04 02:41:45 +00:00
else {
2020-12-05 21:47:19 +00:00
if (*argc >= argv_count_max) {
kernaux_strncpy(error_msg, "too many args", 13);
goto fail;
}
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
2020-12-04 02:41:45 +00:00
state = TOKEN;
2020-12-05 21:47:19 +00:00
argv[(*argc)++] = buffer;
*(buffer++) = cur;
++buffer_size;
2020-12-04 02:41:45 +00:00
}
break;
2020-12-04 02:41:45 +00:00
case TOKEN:
if (cur == '\0') {
2020-12-05 21:47:19 +00:00
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
2020-12-04 02:41:45 +00:00
state = FINAL;
2020-12-05 21:47:19 +00:00
*(buffer++) = '\0';
buffer_size = 0;
2020-12-04 02:41:45 +00:00
}
else if (cur == ' ') {
2020-12-05 21:47:19 +00:00
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
2020-12-04 02:41:45 +00:00
state = WHITESPACE;
2020-12-05 21:47:19 +00:00
*(buffer++) = '\0';
buffer_size = 0;
2020-12-04 02:41:45 +00:00
}
else if (cur == '\\') {
state = BACKSLASHED;
}
else {
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
*(buffer++) = cur;
++buffer_size;
}
break;
case BACKSLASHED:
if (cur == '\0') {
kernaux_strncpy(error_msg, "EOL after backslash", 19);
goto fail;
}
2020-12-04 02:41:45 +00:00
else {
2020-12-05 21:47:19 +00:00
if (buffer_size >= arg_size_max) {
kernaux_strncpy(error_msg, "arg too long", 12);
goto fail;
}
2020-12-04 02:41:45 +00:00
state = TOKEN;
2020-12-05 21:47:19 +00:00
*(buffer++) = cur;
++buffer_size;
2020-12-01 21:54:18 +00:00
}
2020-12-05 21:47:19 +00:00
break;
}
2020-12-04 02:41:45 +00:00
if (state == FINAL) {
break;
}
}
2020-12-01 20:22:38 +00:00
return KERNAUX_TRUE;
2020-12-01 21:54:18 +00:00
fail:
*argc = 0;
for (unsigned int index = 0; index < argv_count_max; ++index) {
argv[index] = KERNAUX_NULL;
}
kernaux_memset(buffer, '\0', argv_count_max * arg_size_max);
return KERNAUX_FALSE;
2020-12-01 20:22:38 +00:00
}