/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* parse_command.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: mcolonna +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/24 13:47:40 by mcolonna #+# #+# */ /* Updated: 2024/04/29 15:48:43 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ #include "include.h" // To call when a parse error occurs. // Always returns 1 (parse error's status). static int parse_error(void) { minishell_error("parse error"); return (1); } // 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 int 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(err_remember, &arguments, 0); if (err_get()) return (parse_error()); r->argc = list_getsize(&arguments); r->argv = (char *const *)list_convert( fatal_error, args->mc, &arguments); list_add(fatal_error, &args->calls, (t_call *)r); args->got_first_call = true; return (0); } // 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; 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, "<>|"); } else if (!args->got_first_call) error = get_call(args, "<>|"); else return (parse_error()); skip_blank(&args->stream); } return (error); } 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; streamstr_init(&args.stream, command); skip_blank(&args.stream); while (!error && stream_read(&args.stream)) { error = get_element(&args); skip_blank(&args.stream); } if (!error) args.r.calls = (t_call *)list_convert_type( fatal_error, args.mc, &args.calls, sizeof(t_call)); if (error) args.r.error = error; return (args.r); }