From d7b4631701cac2ff450fb473fea6c18bdf248826 Mon Sep 17 00:00:00 2001 From: mcolonna Date: Tue, 30 Apr 2024 14:34:15 +0200 Subject: [PATCH] redirections, empty command, parse errors++ --- include/include.h | 6 ++- src/error.c | 9 +++- src/exec_command.c | 4 +- src/main.c | 15 +++++- src/parse_command.c | 114 ++++++++++++++++++++++++++++++++++---------- 5 files changed, 118 insertions(+), 30 deletions(-) diff --git a/include/include.h b/include/include.h index 81ed7fd..678e891 100644 --- a/include/include.h +++ b/include/include.h @@ -6,7 +6,7 @@ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/23 14:15:12 by mcolonna #+# #+# */ -/* Updated: 2024/04/29 15:56:26 by mcolonna ### ########.fr */ +/* Updated: 2024/04/30 15:00:48 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -47,6 +47,7 @@ typedef struct s_call typedef struct s_command { int error; // 0 if parse_command() succeded, error status if not + bool empty; // true if there isn't anything to do const t_call *calls; // all calls to programs (ended by .program == NULL) int input_fd; // fd to use with '<' redirection (0 by default) int output_fd; // fd to use with '>' redirection (1 by default) @@ -71,6 +72,9 @@ void minishell_error(const char *msg); // Call perror() and exit the program. void fatal_error(const char *msg); +// Call strerror() and exit the program. +void fatal_error_msg(const char *msg); + ///// PATH ///// // Get the PATH values. diff --git a/src/error.c b/src/error.c index ac0246b..d67e423 100644 --- a/src/error.c +++ b/src/error.c @@ -6,7 +6,7 @@ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/23 15:51:56 by mcolonna #+# #+# */ -/* Updated: 2024/04/29 15:39:56 by mcolonna ### ########.fr */ +/* Updated: 2024/04/30 15:01:27 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -31,3 +31,10 @@ void fatal_error(const char *msg) mem_freeall(g_mc); exit(errno); } + +void fatal_error_msg(const char *msg) +{ + minishell_error(msg); + mem_freeall(g_mc); + exit(errno); +} diff --git a/src/exec_command.c b/src/exec_command.c index 1440798..6ae9086 100644 --- a/src/exec_command.c +++ b/src/exec_command.c @@ -6,7 +6,7 @@ /* By: jschaft +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/24 13:48:00 by jschaft #+# #+# */ -/* Updated: 2024/04/29 15:51:00 by mcolonna ### ########.fr */ +/* Updated: 2024/04/30 13:58:04 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -56,7 +56,7 @@ static int execute_call(t_memclass mc, t_call call, const int inout[2], // TODO works with only one call (no pipe). int execute_command(t_memclass mc, t_command command, char *const envp[]) { - const int inout[] = {0, 1}; + const int inout[] = {command.input_fd, command.output_fd}; int nb_calls; int r; diff --git a/src/main.c b/src/main.c index 944584b..c004707 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/23 14:33:45 by mcolonna #+# #+# */ -/* Updated: 2024/04/29 15:40:08 by mcolonna ### ########.fr */ +/* Updated: 2024/04/30 16:06:11 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -53,6 +53,16 @@ static void print_hi(void) t_memclass g_mc; +static void close_fds(const t_command *command) +{ + if (command->input_fd != 0) + if (close(command->input_fd) != -1) + minishell_error("errno"); + if (command->output_fd != 1) + if (close(command->output_fd) != -1) + minishell_error("errno"); +} + int main(const int argc, const char *argv[], char *const envp[]) { t_memclass mc; @@ -72,10 +82,11 @@ int main(const int argc, const char *argv[], char *const envp[]) mc = mem_subclass(fatal_error, g_mc); command_str = ask_command(mc); command = parse_command(mc, command_str); - if (command.error) + if (command.error || command.empty) continue ; errorstatus = execute_command(mc, command, envp); mem_freeall(mc); + close_fds(&command); } return (errorstatus); } diff --git a/src/parse_command.c b/src/parse_command.c index 8a9a93d..310cc71 100644 --- a/src/parse_command.c +++ b/src/parse_command.c @@ -6,7 +6,7 @@ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/24 13:47:40 by mcolonna #+# #+# */ -/* Updated: 2024/04/29 16:45:13 by mcolonna ### ########.fr */ +/* Updated: 2024/04/30 16:22:08 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,9 +14,12 @@ // To call when a parse error occurs. // Always returns 1 (parse error's status). -static int parse_error(void) +static int parse_error(const char *msg) { - minishell_error("parse error"); + const t_memclass mc = mem_subclass(fatal_error, g_mc); + + minishell_error(str_join(fatal_error, mc, "parse error: ", msg)); + mem_freeall(mc); return (1); } @@ -67,7 +70,7 @@ static const char *get_string(t_parsing_args *args, const char *stop_charset) stop_charset_2 = str_join(fatal_error, mc, stop_charset, " \n"); else stop_charset_2 = str_addchar(fatal_error, mc, - str_dup(fatal_error, mc, ""), quote); + str_dup(fatal_error, mc, ""), quote); str = str_dup(fatal_error, mc, ""); while (stream_read(&args->stream) && !char_isin(stream_read(&args->stream), stop_charset_2)) @@ -93,7 +96,7 @@ static int get_call(t_parsing_args *args, const char *stop_charset) { str = get_string(args, stop_charset); if (!str) - return (parse_error()); + return (parse_error("EOF unexpected")); list_add(fatal_error, &arguments, (char *)str); skip_blank(&args->stream); @@ -101,7 +104,7 @@ static int get_call(t_parsing_args *args, const char *stop_charset) r = mem_alloc(fatal_error, args->mc, sizeof(t_call)); r->program = (char *)list_get(err_remember, &arguments, 0); if (err_get()) - return (parse_error()); + return (parse_error("program name expected")); r->argc = list_getsize(&arguments); r->argv = (char *const *)list_convert( fatal_error, args->mc, &arguments); @@ -110,49 +113,112 @@ static int get_call(t_parsing_args *args, const char *stop_charset) return (0); } +static int get_inputfile(t_parsing_args *args, const char *stop_charset) +{ + const char *str; + + if (args->r.input_fd != 0) + return (parse_error("several input files")); + if (!stream_read(&args->stream)) + return (parse_error("EOF unexpected")); + str = get_string(args, stop_charset); + if (!str) + return (parse_error("EOF unexpected")); + args->r.input_fd = open(str, O_RDONLY); + if (args->r.input_fd == -1) + return (perror(str), errno); + return (0); +} + +static int get_outputfile(t_parsing_args *args, const char *stop_charset) +{ + const char *str; + + if (args->r.output_fd != 1) + return (parse_error("several output files")); + if (!stream_read(&args->stream)) + return (parse_error("EOF unexpected")); + str = get_string(args, stop_charset); + if (!str) + return (parse_error("EOF unexpected")); + args->r.output_fd = open( + str, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (args->r.output_fd == -1) + return (perror(str), errno); + return (0); +} + +static void get_element2(t_parsing_args *args, int *error, char c) +{ + stream_pop(&args->stream); + skip_blank(&args->stream); + if (c == '|') + { + if (!args->got_first_call) + *error = parse_error("'|', '>' or '<' expected"); + *error = get_call(args, "<>|"); + } + else if (c == '>') + *error = get_outputfile(args, "<>|"); + else if (c == '<') + *error = get_inputfile(args, "<>|"); + else + fatal_error_msg("internal error u.u"); +} + // Read an element (a call to a program, a '< FILE' or a '> FILE') // On success, return 0. On error, return the error status. -// (TODO redirections) static int get_element(t_parsing_args *args) { - char c; - int error; + char c; + int error; error = 0; while (!error && stream_read(&args->stream)) { c = stream_read(&args->stream); - if (c == '|') - { - if (!args->got_first_call) - return (parse_error()); - stream_pop(&args->stream); - skip_blank(&args->stream); - error = get_call(args, "<>|"); - } + if (char_isin(c, "|><")) + get_element2(args, &error, c); else if (!args->got_first_call) error = get_call(args, "<>|"); else - return (parse_error()); + return (parse_error("'|', '>' or '<'' expected")); skip_blank(&args->stream); } return (error); } +t_parsing_args init_parsing_args(const t_memclass mc) +{ + const t_parsing_args r = { + .mc = mc, + .r = { + .error = 0, + .empty = false, + .input_fd = 0, + .output_fd = 1, + }, + .calls = list_createempty(mc), + .got_first_call = false, + }; + + return (r); +} + t_command parse_command(const t_memclass mc, const char *command) { t_parsing_args args; int error; error = 0; - args.mc = mc; - args.r.error = 0; - args.r.input_fd = 0; - args.r.output_fd = 1; - args.calls = list_createempty(mc); - args.got_first_call = false; + args = init_parsing_args(mc); streamstr_init(&args.stream, command); skip_blank(&args.stream); + if (!stream_read(&args.stream)) + { + args.r.empty = true; + return (args.r); + } while (!error && stream_read(&args.stream)) { error = get_element(&args);