spz-lab4/src/cli.c

268 lines
5.5 KiB
C
Raw Normal View History

2025-04-23 22:51:00 +03:00
#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},
2025-04-26 22:33:28 +03:00
{"stat", 1, (enum CliArgType[]) {STR}, fs_stat},
{"ls", 0, NULL, fs_ls},
{"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln},
2025-04-26 10:21:23 +03:00
{"rm", 1, (enum CliArgType[]) {STR}, fs_rm},
2025-04-26 22:12:26 +03:00
{"truncate", 2, (enum CliArgType[]) {STR, INT}, fs_truncate},
{"open", 1, (enum CliArgType[]) {STR}, fs_open},
2025-04-26 19:46:34 +03:00
{"seek", 2, (enum CliArgType[]) {INT, INT}, fs_seek},
{"read", 2, (enum CliArgType[]) {INT, INT}, fs_read},
{"write", 2, (enum CliArgType[]) {INT, STR}, fs_write},
{"close", 1, (enum CliArgType[]) {INT}, fs_close},
2025-04-23 22:51:00 +03:00
// custom commands
{"use", 1, (enum CliArgType[]) {STR}, fs_use},
{"la", 0, NULL, fs_la},
2025-04-23 22:51:00 +03:00
{"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 ( ;; ) {
2025-04-24 21:40:16 +03:00
fputs(fs_get_cwd(), stdout);
if (fs_get_cwd()[0]) {
fputs(" $ ", stdout);
} else {
fputs("$ ", stdout);
}
2025-04-23 22:51:00 +03:00
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;
}
}