From 36fa53131af669d7f0da1c166586ea28898f8048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kha=C3=AFs=20COLIN?= Date: Tue, 25 Feb 2025 12:53:12 +0100 Subject: [PATCH] command list parse: handle single pipeline --- src/parser/command_list/command_list.c | 109 ++++++++++++++++++++----- src/parser/command_list/command_list.h | 6 +- tests/parse_command_lists.c | 23 +++++- 3 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/parser/command_list/command_list.c b/src/parser/command_list/command_list.c index 5e2a4e6..133d552 100644 --- a/src/parser/command_list/command_list.c +++ b/src/parser/command_list/command_list.c @@ -6,7 +6,7 @@ /* By: khais +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/24 17:49:46 by khais #+# #+# */ -/* Updated: 2025/02/24 18:58:48 by khais ### ########.fr */ +/* Updated: 2025/02/25 13:29:39 by khais ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,40 +14,109 @@ #include "libft.h" #include +/* +** Match a string to an operator +** +** If the string does not match any operator, return OP_INVALID +*/ +static t_operator match_op(char *op) +{ + if (ft_strcmp("&&", op) == 0) + return (OP_AND); + return (OP_INVALID); +} + +/* +** Count the number of pipelines in the given wordstream +** +** Pipelines are separated by operators || and &&. +** +** Does not do error checking about repeated operators, or operators in the +** wrong place. +*/ +static int command_list_count_pipelines(t_wordlist *words) +{ + t_wordlist *current_word; + int count; + + current_word = words; + if (current_word == NULL) + return (0); + count = 1; + while (current_word != NULL) + { + if (match_op(current_word->word->word) != OP_INVALID) + count++; + current_word = current_word->next; + } + return (count); +} + +/* +** Allocate memory for a new command_list, given the input word stream. +** +** Handles malloc error. +*/ +static t_command_list *allocate_command_list(t_wordlist *words) +{ + t_command_list *output; + + if (words == NULL) + return (NULL); + output = ft_calloc(1, sizeof(t_command_list)); + if (output == NULL) + return (NULL); + output->num_pipelines = command_list_count_pipelines(words); + output->pipelines + = ft_calloc(output->num_pipelines, sizeof(t_pipeline *)); + if (output->pipelines == NULL) + return (free(output), NULL); + return (output); +} + +/* +** Create a new command list from the given wordlist. +*/ t_command_list *command_list_from_wordlist(t_wordlist *words) { t_command_list *output; t_wordlist *current_wordlist; t_worddesc *current_word; - output = NULL; - if (words != NULL) + output = allocate_command_list(words); + if (output == NULL) + return (NULL); + current_wordlist = NULL; + current_word = wordlist_pop(&words); + while (current_word != NULL && match_op(current_word->word) == OP_INVALID) { - output = ft_calloc(1, sizeof(t_command_list)); - if (output == NULL) - return (NULL); - current_wordlist = NULL; + current_wordlist = wordlist_push(current_wordlist, current_word); current_word = wordlist_pop(&words); - while (ft_strcmp("&&", current_word->word) != 0) - { - current_wordlist = wordlist_push(current_wordlist, current_word); - current_word = wordlist_pop(&words); - } - worddesc_destroy(current_word); - output->operator = OP_AND; - wordlist_debug(current_wordlist); - output->pipeline_left = pipeline_from_wordlist(current_wordlist); - wordlist_debug(words); - output->pipeline_right = pipeline_from_wordlist(words); } + if (current_word != NULL) + output->operator = match_op(current_word->word); + worddesc_destroy(current_word); + output->pipelines[0] = pipeline_from_wordlist(current_wordlist); + if (words != NULL) + output->pipelines[1] = pipeline_from_wordlist(words); return (output); } +/* +** destroy the given command list and all associated memory +*/ void command_list_destroy(t_command_list *cmd) { + int i; + if (cmd == NULL) return ; - pipeline_destroy(cmd->pipeline_left); - pipeline_destroy(cmd->pipeline_right); + i = 0; + while (i < cmd->num_pipelines) + { + pipeline_destroy(cmd->pipelines[i]); + i++; + } + free(cmd->pipelines); free(cmd); } diff --git a/src/parser/command_list/command_list.h b/src/parser/command_list/command_list.h index 4ac3876..b6081d8 100644 --- a/src/parser/command_list/command_list.h +++ b/src/parser/command_list/command_list.h @@ -6,7 +6,7 @@ /* By: khais +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/24 17:45:01 by khais #+# #+# */ -/* Updated: 2025/02/24 18:09:24 by khais ### ########.fr */ +/* Updated: 2025/02/25 12:43:52 by khais ### ########.fr */ /* */ /* ************************************************************************** */ @@ -67,8 +67,8 @@ typedef enum e_operator */ typedef struct s_command_list { - t_pipeline *pipeline_left; - t_pipeline *pipeline_right; + t_pipeline **pipelines; + int num_pipelines; t_operator operator; } t_command_list; diff --git a/tests/parse_command_lists.c b/tests/parse_command_lists.c index 012e688..1f14f4e 100644 --- a/tests/parse_command_lists.c +++ b/tests/parse_command_lists.c @@ -6,7 +6,7 @@ /* By: khais +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/24 17:40:48 by khais #+# #+# */ -/* Updated: 2025/02/25 12:34:07 by khais ### ########.fr */ +/* Updated: 2025/02/25 13:26:14 by khais ### ########.fr */ /* */ /* ************************************************************************** */ @@ -51,8 +51,11 @@ static void assert_simple_commandequal(t_simple_cmd *expected, t_simple_cmd *got assert(got_word == NULL); } -static void assert_pipelineequal(char *expected, t_pipeline *got) +static void assert_pipelineequal(char *expected, t_command_list *cmd, int idx) { + ft_printf("Expected command list %p to have at least %d pipelines, and got %d\n", cmd, idx + 1, cmd->num_pipelines); + assert(cmd->num_pipelines >= idx + 1); + t_pipeline *got = cmd->pipelines[idx]; ft_dprintf(STDERR_FILENO, "Expected pipeline %p to equal [%s]\n", got, expected); t_pipeline *expected_pipeline = parse_pipeline(expected); assert(expected_pipeline == got || expected_pipeline != NULL); @@ -74,19 +77,31 @@ static void test_parse_command_list_empty(void) command_list_destroy(cmd); } +static void test_parse_command_list_single_pipeline(void) +{ + t_command_list *cmd = parse_command_list("echo this | cat -e"); + assert(cmd != NULL); + assert(cmd->operator == OP_INVALID); + assert_pipelineequal("echo this | cat -e", cmd, 0); + assert(cmd->num_pipelines == 1); + command_list_destroy(cmd); +} + static void test_parse_command_list_simple_and(void) { t_command_list *cmd = parse_command_list("echo this | cat -e && echo works | wc -c"); assert(cmd != NULL); assert(cmd->operator == OP_AND); - assert_pipelineequal("echo this | cat -e", cmd->pipeline_left); - assert_pipelineequal("echo works | wc -c", cmd->pipeline_right); + assert_pipelineequal("echo this | cat -e", cmd, 0); + assert_pipelineequal("echo works | wc -c", cmd, 1); + assert(cmd->num_pipelines == 2); command_list_destroy(cmd); } int main(void) { test_parse_command_list_empty(); + test_parse_command_list_single_pipeline(); test_parse_command_list_simple_and(); return (0); }