diff --git a/.gitignore b/.gitignore index 2eea60a..c5d6576 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +./minishell + # Prerequisites *.d diff --git a/Makefile b/Makefile index 30a561d..52864a7 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SRCS = src/ # include directory INCLUDES = include/ libtf/ libft/ # .c files in src/ without the extension -CODE = main ask_command error path +CODE = main ask_command error path parse_command # directories to 'make' LIBRARIES = libtf libft # .a files to include diff --git a/include/include.h b/include/include.h index f4e37a8..ce10b5f 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/24 13:19:28 by mcolonna ### ########.fr */ +/* Updated: 2024/04/25 16:53:06 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,7 +45,7 @@ typedef struct s_call // Represents a command given by the user. typedef struct s_command { - bool error; // true means an error occured in interpret_command(). + bool error; // true if an error occured in interpret_command(). const t_call *calls; // all calls to programs. int input_fd; // fd to use with '<' redirection (0 by default) int output_fd; // fd to use with '>' redirection (1 by default) @@ -53,7 +53,7 @@ typedef struct s_command // Return the t_command representing the command given by the user. // If error, return a t_command wth the value .error = true. -t_command parse_command(const char *command); +t_command parse_command(const t_memclass mc, const char *command); ///// EXECUTE COMMAND ///// @@ -66,6 +66,9 @@ int execute_command(t_command command); // If msg == "errno", use strerror(errno) void minishell_error(const char *msg); +// Call to write the error and exit the program. +void fatal_error(const char *msg); + ///// PATH ///// // Get the PATH values. diff --git a/libtf/Makefile b/libtf/Makefile index 977f51b..889a1eb 100644 --- a/libtf/Makefile +++ b/libtf/Makefile @@ -5,13 +5,13 @@ INCLUDES = ./ include/ CODE = \ mem mem_utils str1 str2 str3 str_stream str_char1 \ str_char2 str_stream_more str_streamstr print \ - list1 list2 error data read_line read_line_utils + list1 list2 list3 error data read_line read_line_utils PRINTF_CODE = \ conversions1 conversions2 do_conversion ft_itoa tf_printf \ ft_strjoin stream1 stream2 utils1 utils2 PRINTF_SRCS = tf_printf/src/ PRINTF_INCLUDES = ./ tf_printf/include/ -WHAT = LIBTF v9 +WHAT = LIBTF v11 USED = malloc() free() write() # It works and I probably won't change it for the rest of my life diff --git a/libtf/libtf.h b/libtf/libtf.h index 953cae3..1b94f83 100644 --- a/libtf/libtf.h +++ b/libtf/libtf.h @@ -6,7 +6,7 @@ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/18 11:07:59 by mcolonna #+# #+# */ -/* Updated: 2024/03/11 12:12:03 by mcolonna ### ########.fr */ +/* Updated: 2024/04/25 16:06:24 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -381,6 +381,22 @@ void list_rotate(t_list *list); */ void list_revrotate(t_list *list); +/** + * Convert the t_list to a void** ended by NULL. + */ +void **list_convert( + t_err *err, t_memclass mc, const t_list *list); + +/** + * Let '' be the type of the value of all elements of the list: + * convert the t_list to a * list ended by a filled with nul bytes. + * For example: + * If 'list' is {3, 4, 7, 2, 1} wth each element being an int, this function + * will return (int*){3, 4, 7, 2, 1, 0}. + */ +void *list_convert_type(t_err *err, + t_memclass mc, const t_list *list, int size); + ///// DATA ///// /** diff --git a/libtf/src/list3.c b/libtf/src/list3.c new file mode 100644 index 0000000..474b0f0 --- /dev/null +++ b/libtf/src/list3.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* list3.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mcolonna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/25 12:05:28 by mcolonna #+# #+# */ +/* Updated: 2024/04/25 16:19:00 by mcolonna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "libtf.h" + +void **list_convert(t_err *err, t_memclass mc, const t_list *list) +{ + const int size = list_getsize(list); + int i; + void **r; + + r = mem_alloc(err, mc, (size + 1) * sizeof(void *)); + i = -1; + while (++i < size) + r[i] = list_get(err, list, i); + r[i] = NULL; + return (r); +} + +static void fill_with_0(char *dest, int size) +{ + int i; + + i = -1; + while (++i < size) + dest[i] = '\0'; +} + +void *list_convert_type(t_err *err, + t_memclass mc, const t_list *list, int size) +{ + const t_memclass mc_in = mem_subclass(err, mc); + char **const list2 = (char **)list_convert(err, mc_in, list); + const int listsize = list_getsize(list); + char *r; + int i; + + r = mem_alloc(err, mc, (listsize + 1) * size); + i = -1; + while (++i < listsize) + data_cpy(r + i * size, list2[i], size); + fill_with_0(r + i * size, size); + return (r); +} diff --git a/minishell b/minishell deleted file mode 100755 index e178c73..0000000 Binary files a/minishell and /dev/null differ diff --git a/src/error.c b/src/error.c index af34a71..4316050 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/24 13:20:31 by mcolonna ### ########.fr */ +/* Updated: 2024/04/25 13:41:57 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,3 +20,11 @@ void minishell_error(const char *msg) print_str(err_remember, 2, msg); err_get(); } + +// TODO adapt for msg == errno +void fatal_error(const char *msg) +{ + print_str(err_remember, 2, "Fatal error: "); + print_line(err_remember, 2, msg); + exit(1); +} diff --git a/src/main.c b/src/main.c index a3506fa..7101c0c 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/24 13:24:10 by mcolonna ### ########.fr */ +/* Updated: 2024/04/25 16:54:13 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ @@ -62,12 +62,10 @@ int main(const int argc, const char *argv[], const char *envp[]) { mc = mem_newclass(minishell_error); command_str = ask_command(mc); - print_str(minishell_error, 1, "command: "); - print_line(minishell_error, 1, command_str); - /* - command = parse_command(command_str); + command = parse_command(mc, command_str); if (command.error) continue ; + /* errorstatus = execute_command(command); mem_freeall(mc); */ diff --git a/src/parse_command.c b/src/parse_command.c new file mode 100644 index 0000000..0610053 --- /dev/null +++ b/src/parse_command.c @@ -0,0 +1,132 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parse_command.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: mcolonna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/04/24 13:47:40 by mcolonna #+# #+# */ +/* Updated: 2024/04/25 16:51:22 by mcolonna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "include.h" + +// To call when a parse error occurs (TODO) +static void parse_error(const char *msg) +{ + (void)msg; + fatal_error("parse error"); +} + +// Global variables for all the parsing functions +typedef struct s_parsing_args +{ + t_memclass mc; + t_command r; + t_stream stream; + t_list calls; + bool got_first_call; // got at least the first program call? +} t_parsing_args; + +// Skip blank characters +static void skip_blank(t_stream *stream) +{ + stream_skip(stream, " \r\n\t"); +} + +// Read the string, stop if the char is in stop_charset +// TODO quotes +static const char *get_string(t_parsing_args *args, const char *stop_charset) +{ + const t_memclass mc = mem_subclass(fatal_error, args->mc); + const char *stop_charset_2 + = str_join(fatal_error, mc, stop_charset, " \n"); + char *str; + char str2[2]; + char *str3; + + str = str_dup(fatal_error, mc, ""); + str2[1] = '\0'; + while (stream_read(&args->stream) + && !char_isin(stream_read(&args->stream), stop_charset_2)) + { + str2[0] = stream_pop(&args->stream); + str3 = str; + str = str_join(fatal_error, mc, str, str2); + mem_free(str3); + } + str = str_dup(fatal_error, args->mc, str); + mem_freeall(mc); + return (str); +} + +// Get a program call (program names & its arguments) until stop_charset. +static void get_call(t_parsing_args *args, const char *stop_charset) +{ + t_call *r; + t_list arguments; + + arguments = list_createempty(args->mc); + while (stream_read(&args->stream) + && !char_isin(stream_read(&args->stream), stop_charset)) + { + list_add(fatal_error, &arguments, + (char *)get_string(args, stop_charset)); + skip_blank(&args->stream); + } + r = mem_alloc(fatal_error, args->mc, sizeof(t_call)); + r->program = (char *)list_get(parse_error, &arguments, 0); + r->argc = list_getsize(&arguments); + r->argv = (const char *const *)list_convert( + fatal_error, args->mc, &arguments); + list_add(fatal_error, &args->calls, (t_call *)r); + args->got_first_call = true; +} + +// Read an element (a call to a program, a '< FILE' or a '> FILE') +// (TODO redirections) +static void get_element(t_parsing_args *args) +{ + char c; + + while (stream_read(&args->stream)) + { + c = stream_read(&args->stream); + if (c == '|') + { + if (!args->got_first_call) + parse_error(NULL); + stream_pop(&args->stream); + skip_blank(&args->stream); + get_call(args, "<>|"); + } + else if (!args->got_first_call) + get_call(args, "<>|"); + else + parse_error(NULL); + skip_blank(&args->stream); + } +} + +t_command parse_command(const t_memclass mc, const char *command) +{ + t_parsing_args args; + + args.mc = mc; + args.r.error = false; + args.r.input_fd = 0; + args.r.output_fd = 1; + args.calls = list_createempty(mc); + args.got_first_call = false; + streamstr_init(&args.stream, command); + skip_blank(&args.stream); + while (stream_read(&args.stream)) + { + get_element(&args); + skip_blank(&args.stream); + } + args.r.calls = (t_call *)list_convert_type( + fatal_error, args.mc, &args.calls, sizeof(t_call)); + return (args.r); +}