Для учебы мне нужно сделать оболочку на С
Я хочу разобрать команду оболочки
Моя функция parse_sequence
выводит command_t *, который представляет собой структуру, содержащую:
char *program_name;
int fd_input;
bool override;
int fd_output;
bool heredoc_mode;
char **args;
command_t *next; // kind of linked_list
То, что я называю последовательностью, - это команда с перенаправлениями и каналами
Последовательности сокращены на &&
, ||
и ;
ls > file | sort
- это одна последовательность, где ls && echo OK
состоит из двух последовательностей
Я колеблюсь между двумя способами достижения парсинга
считать это псевдокодом
первый путь : рекурсия
command_t *parse_sequence(char *sequence)
{
command_t *ret = malloc(sizeof(command_t));
char **tokens = split(sequence);
int i = 0;
while (tokens[i]) {
if (!strcmp(commands[i], "<")) {
// set input file (open commands[i + 1])
}
if (!strcmp(commands[i], ">")) {
// set output file (open commands[i + 1])
}
if (!strcmp(commands[i], "|")) {
// recursion: ret->next = parse_sequence(tokens[i + 1]);
}
else {
if (i == 0)
// set program name
else
// append args
}
}
return (ret);
}
пример : ls > file | sort --rev
i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *recursion and setup pipe*
// in the recursive call commands[0] is "sort"
(recursion) i == 0: set program name
(recursion) i == 1: append argument "--rev"
(recursion) i == 2: exit function because commands[i] == NULL
второй способ : разделить каждую команду с конвейером в качестве разделителя
command_t *parse_sequence(char *sequence)
{
command_t *ret = malloc(sizeof(command_t));
command_t current_command = ret;
char **tokens = split_tokens(sequence, (char **){"|", NULL});
int i = 0;
while (commands[i]) {
if (!strcmp(commands[i], "<")) {
// set input file (open commands[++i])
}
if (!strcmp(commands[i], ">")) {
// set output file (open commands[++i])
}
if (!strcmp(commands[i], "|") // tokens are kept when splitting
// setup pipe
// current_command = current_command->next
// i++
else {
if (i > 0 && commands[i - 1] pipe or redirection)
// set program name
else
// append args
}
}
return (ret);
}
пример : ls > file | sort --rev
i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *setup pipe* and current_command = current_command->next
i == 4: set program name
i == 5: append argument "--rev"
i == 6: exit function because commands[i] == NULL
Какой из двух способов лучше?
С какими проблемами я столкнусь?
Я знаю, что мои примеры неверны в tcsh, но это не важно для моего вопроса
У меня мало времени, поэтому я хочу самый быстрый способ реализации
Спасибо!