251 lines
4.9 KiB
C
251 lines
4.9 KiB
C
|
#include "macro.h"
|
||
|
#include "config.h"
|
||
|
|
||
|
#include "cli.h"
|
||
|
#include "print.h"
|
||
|
|
||
|
#include "fs.h"
|
||
|
#include "ctrl.h"
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
|
||
|
static const struct CliCommandEntry cmd[] = {
|
||
|
// mandatory commands
|
||
|
{"mkfs", 1, (enum CliArgType[]) {INT}, fs_mkfs},
|
||
|
{"create", 1, (enum CliArgType[]) {STR}, fs_create},
|
||
|
|
||
|
// custom commands
|
||
|
{"use", 1, (enum CliArgType[]) {STR}, fs_use},
|
||
|
{"prohibit-write", 0, NULL, fs_prohibit_write},
|
||
|
{"allow-write", 0, NULL, fs_allow_write},
|
||
|
{"exit", 0, NULL, ctrl_exit}
|
||
|
};
|
||
|
|
||
|
|
||
|
static void destroy_tokenized_line(char **tokenized_line)
|
||
|
{
|
||
|
for (int j = 0; j < CLI_MAX_ACCEPTED_ARGS; j++)
|
||
|
if (tokenized_line[j])
|
||
|
free(tokenized_line[j]);
|
||
|
|
||
|
free(tokenized_line);
|
||
|
}
|
||
|
|
||
|
static int tokenized_line_len(char **t)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < CLI_MAX_ACCEPTED_ARGS; i++)
|
||
|
if (!t[i])
|
||
|
break;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
static char **tokenize_line(char *line, ssize_t result)
|
||
|
{
|
||
|
if (result > CLI_MAX_LINE_LENGTH) {
|
||
|
pr_err("command too long (%d > %d)\n", result+1, CLI_MAX_LINE_LENGTH);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
char **tokenized_line = malloc(sizeof(char *) * CLI_MAX_ACCEPTED_ARGS);
|
||
|
memset(tokenized_line, 0, sizeof(char *) * CLI_MAX_ACCEPTED_ARGS);
|
||
|
|
||
|
unsigned int i, t, l;
|
||
|
for (
|
||
|
i = 0, t = 0, l = 0;
|
||
|
i < CLI_MAX_LINE_LENGTH,
|
||
|
t <= CLI_MAX_ACCEPTED_ARGS,
|
||
|
l < CLI_MAX_TOKEN_LENGTH;
|
||
|
i++
|
||
|
) {
|
||
|
if (line[i] == '\n') {
|
||
|
if (l) {
|
||
|
if (t == CLI_MAX_ACCEPTED_ARGS) {
|
||
|
t++;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
tokenized_line[t] = malloc(sizeof(char) * (l+1));
|
||
|
memcpy(tokenized_line[t], &(line[i-l]), l);
|
||
|
tokenized_line[t][l] = '\0';
|
||
|
|
||
|
t++;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
} else if (line[i] == ' ') {
|
||
|
if (l) {
|
||
|
if (t == CLI_MAX_ACCEPTED_ARGS) {
|
||
|
t++;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
tokenized_line[t] = malloc(sizeof(char) * (l+1));
|
||
|
memcpy(tokenized_line[t], &(line[i-l]), l);
|
||
|
tokenized_line[t][l] = '\0';
|
||
|
|
||
|
l = 0;
|
||
|
t++;
|
||
|
}
|
||
|
} else {
|
||
|
l++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
i >= CLI_MAX_LINE_LENGTH ||
|
||
|
t > CLI_MAX_ACCEPTED_ARGS ||
|
||
|
l >= CLI_MAX_TOKEN_LENGTH ||
|
||
|
t == 0
|
||
|
) goto cli_process_error;
|
||
|
|
||
|
return tokenized_line;
|
||
|
|
||
|
|
||
|
cli_process_error:
|
||
|
// print error
|
||
|
if (i >= CLI_MAX_LINE_LENGTH)
|
||
|
pr_err("command too long (> %d)\n", CLI_MAX_LINE_LENGTH);
|
||
|
|
||
|
if (t > CLI_MAX_ACCEPTED_ARGS)
|
||
|
pr_err("too many arguments (> %d)\n", CLI_MAX_ACCEPTED_ARGS);
|
||
|
|
||
|
if (l >= CLI_MAX_TOKEN_LENGTH)
|
||
|
pr_err("argument %d too long (> %d)\n", t, CLI_MAX_TOKEN_LENGTH);
|
||
|
|
||
|
// clean up
|
||
|
destroy_tokenized_line(tokenized_line);
|
||
|
|
||
|
// return
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
void *format_args(char **tokenized_line, unsigned int arg_count, enum CliArgType *arg_types)
|
||
|
{
|
||
|
char *new_struct;
|
||
|
|
||
|
{
|
||
|
// prepare struct space
|
||
|
unsigned int struct_size = 0;
|
||
|
|
||
|
for (unsigned int i = 0; i < arg_count; i++)
|
||
|
switch (arg_types[i]) {
|
||
|
case INT:
|
||
|
struct_size += sizeof(int);
|
||
|
break;
|
||
|
case STR:
|
||
|
struct_size += sizeof(char *);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
new_struct = malloc(struct_size);
|
||
|
memset(new_struct, 0, struct_size);
|
||
|
}
|
||
|
|
||
|
unsigned int struct_offset = 0;
|
||
|
|
||
|
for (unsigned int i = 0; i < arg_count; i++)
|
||
|
{
|
||
|
if (arg_types[i] == INT) {
|
||
|
if (!tokenized_line[i+1]) {
|
||
|
pr_err("missing argument %d of type 'integer'\n", i+1);
|
||
|
goto abandon_struct;
|
||
|
}
|
||
|
|
||
|
int value;
|
||
|
int result = sscanf(tokenized_line[i+1], "%d", &value);
|
||
|
|
||
|
if (result != 1) {
|
||
|
pr_err("argument %d must be of type 'integer'\n", i+1);
|
||
|
goto abandon_struct;
|
||
|
}
|
||
|
|
||
|
*((int*) &(new_struct[struct_offset])) = value;
|
||
|
struct_offset += sizeof(int);
|
||
|
}
|
||
|
else if (arg_types[i] == STR) {
|
||
|
if (!tokenized_line[i+1]) {
|
||
|
pr_err("missing argument %d of type 'string'\n", i+1);
|
||
|
goto abandon_struct;
|
||
|
}
|
||
|
|
||
|
*((char**) &(new_struct[struct_offset])) = tokenized_line[i+1];
|
||
|
struct_offset += sizeof(char *);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new_struct;
|
||
|
|
||
|
abandon_struct:
|
||
|
free(new_struct);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
unsigned int cli_poll_process_next(void)
|
||
|
{
|
||
|
for ( ;; ) {
|
||
|
fputs("$ ", stdout);
|
||
|
|
||
|
size_t buf_size = 0;
|
||
|
char *line = NULL;
|
||
|
|
||
|
ssize_t result = getline(&line, &buf_size, stdin);
|
||
|
if (result == -1)
|
||
|
return 0x1;
|
||
|
|
||
|
char **tokenized_line = tokenize_line(line, result);
|
||
|
free(line);
|
||
|
|
||
|
if (tokenized_line == NULL)
|
||
|
continue;
|
||
|
|
||
|
unsigned int i;
|
||
|
for (i = 0; (i < LEN(cmd)) && strcmp(tokenized_line[0], cmd[i].cmd); i++);
|
||
|
if (i == LEN(cmd)) {
|
||
|
pr_err("command '%s' not found\n", tokenized_line[0]);
|
||
|
destroy_tokenized_line(tokenized_line);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
int tll = tokenized_line_len(tokenized_line);
|
||
|
|
||
|
if ((cmd[i].arg_count + 1) != tll) {
|
||
|
pr_err("wrong amount of arguments for '%s' (%d required, %d got)\n", tokenized_line[0], cmd[i].arg_count, tll-1);
|
||
|
destroy_tokenized_line(tokenized_line);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int (*executor)(void *) = cmd[i].process;
|
||
|
void *data;
|
||
|
|
||
|
if (cmd[i].arg_count) {
|
||
|
data = format_args(tokenized_line, cmd[i].arg_count, cmd[i].args);
|
||
|
|
||
|
if (data == NULL) {
|
||
|
destroy_tokenized_line(tokenized_line);
|
||
|
continue;
|
||
|
}
|
||
|
} else {
|
||
|
data = NULL;
|
||
|
}
|
||
|
|
||
|
int execution_result_code = executor(data);
|
||
|
|
||
|
if (data)
|
||
|
free(data);
|
||
|
|
||
|
destroy_tokenized_line(tokenized_line);
|
||
|
|
||
|
if (0x1 == execution_result_code)
|
||
|
return 0x1;
|
||
|
}
|
||
|
}
|