[ADD] manage variables *
Also: - dev: - add docu - add fixes in TODO - add FIXME
This commit is contained in:
parent
e0b059bea6
commit
38170c7211
5 changed files with 277 additions and 73 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/minishell
|
/minishell
|
||||||
|
/dev/*.srctrl*
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
|
6
dev/TODO
6
dev/TODO
|
@ -6,7 +6,6 @@
|
||||||
- signals
|
- signals
|
||||||
- ^C, ^D, ^\
|
- ^C, ^D, ^\
|
||||||
- variables
|
- variables
|
||||||
- normal variables
|
|
||||||
- environment variables
|
- environment variables
|
||||||
- $?
|
- $?
|
||||||
- builtins:
|
- builtins:
|
||||||
|
@ -17,3 +16,8 @@
|
||||||
- unset (with no options)
|
- unset (with no options)
|
||||||
- env (with no options or arguments)
|
- env (with no options or arguments)
|
||||||
- exit (with no options)
|
- exit (with no options)
|
||||||
|
- fix
|
||||||
|
- `$ |` throws 2 errors
|
||||||
|
- empty variables aren't freed
|
||||||
|
|
||||||
|
(also search TODO and FIXME in the files)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
/* By: jschaft <cecile.schaft@orange.fr> +#+ +:+ +#+ */
|
/* By: jschaft <cecile.schaft@orange.fr> +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2024/04/23 14:15:12 by mcolonna #+# #+# */
|
/* Created: 2024/04/23 14:15:12 by mcolonna #+# #+# */
|
||||||
/* Updated: 2024/05/16 18:18:16 by mcolonna ### ########.fr */
|
/* Updated: 2024/06/05 17:45:33 by mcolonna ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
@ -35,6 +35,12 @@ const char *ask_command(t_memclass mc);
|
||||||
|
|
||||||
///// PARSE_COMMAND /////
|
///// PARSE_COMMAND /////
|
||||||
|
|
||||||
|
typedef struct s_variable
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *value;
|
||||||
|
} t_variable;
|
||||||
|
|
||||||
// Represents a call to a program (the program name and its arguments)
|
// Represents a call to a program (the program name and its arguments)
|
||||||
typedef struct s_call
|
typedef struct s_call
|
||||||
{
|
{
|
||||||
|
@ -62,7 +68,8 @@ typedef struct s_pipes
|
||||||
|
|
||||||
// Return the t_command representing the command given by the user.
|
// Return the t_command representing the command given by the user.
|
||||||
// If error, return a t_command wth the value .error = true.
|
// If error, return a t_command wth the value .error = true.
|
||||||
t_command parse_command(const t_memclass mc, const char *command);
|
t_command parse_command(const t_memclass mc, const char *command,
|
||||||
|
t_list *variables);
|
||||||
|
|
||||||
///// EXECUTE COMMAND /////
|
///// EXECUTE COMMAND /////
|
||||||
|
|
||||||
|
|
20
src/main.c
20
src/main.c
|
@ -6,7 +6,7 @@
|
||||||
/* By: jschaft <cecile.schaft@orange.fr> +#+ +:+ +#+ */
|
/* By: jschaft <cecile.schaft@orange.fr> +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2024/04/23 14:33:45 by mcolonna #+# #+# */
|
/* Created: 2024/04/23 14:33:45 by mcolonna #+# #+# */
|
||||||
/* Updated: 2024/05/17 14:39:43 by mcolonna ### ########.fr */
|
/* Updated: 2024/06/05 17:45:43 by mcolonna ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
@ -15,13 +15,13 @@
|
||||||
t_memclass g_mc;
|
t_memclass g_mc;
|
||||||
|
|
||||||
// Execute a command from a string.
|
// Execute a command from a string.
|
||||||
static int do_command(char *const envp[], const char *str)
|
static int do_command(char *const envp[], t_list *variables, const char *str)
|
||||||
{
|
{
|
||||||
const t_memclass mc = mem_subclass(fatal_error, g_mc);
|
const t_memclass mc = mem_subclass(fatal_error, g_mc);
|
||||||
t_command command;
|
t_command command;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
command = parse_command(mc, str);
|
command = parse_command(mc, str, variables);
|
||||||
if (command.error || command.empty)
|
if (command.error || command.empty)
|
||||||
return (command.error);
|
return (command.error);
|
||||||
r = execute_command(mc, command, envp);
|
r = execute_command(mc, command, envp);
|
||||||
|
@ -29,15 +29,16 @@ static int do_command(char *const envp[], const char *str)
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start(char *const envp[])
|
static void start(char *const envp[], t_list *variables)
|
||||||
{
|
{
|
||||||
do_command(envp, "clear");
|
do_command(envp, variables, "clear");
|
||||||
do_command(envp, "cat ./header");
|
do_command(envp, variables, "cat ./header");
|
||||||
do_command(envp, "echo");
|
do_command(envp, variables, "echo");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, const char *argv[], char *const envp[])
|
int main(const int argc, const char *argv[], char *const envp[])
|
||||||
{
|
{
|
||||||
|
t_list variables;
|
||||||
t_memclass mc;
|
t_memclass mc;
|
||||||
const char *command_str;
|
const char *command_str;
|
||||||
int errorstatus;
|
int errorstatus;
|
||||||
|
@ -46,13 +47,14 @@ int main(const int argc, const char *argv[], char *const envp[])
|
||||||
(void)argv;
|
(void)argv;
|
||||||
g_mc = NULL;
|
g_mc = NULL;
|
||||||
g_mc = mem_newclass(fatal_error);
|
g_mc = mem_newclass(fatal_error);
|
||||||
start(envp);
|
variables = list_createempty(g_mc);
|
||||||
|
start(envp, &variables);
|
||||||
errorstatus = 0;
|
errorstatus = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
mc = mem_subclass(fatal_error, g_mc);
|
mc = mem_subclass(fatal_error, g_mc);
|
||||||
command_str = ask_command(mc);
|
command_str = ask_command(mc);
|
||||||
do_command(envp, command_str);
|
do_command(envp, &variables, command_str);
|
||||||
}
|
}
|
||||||
return (errorstatus);
|
return (errorstatus);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,49 @@
|
||||||
/* By: mcolonna <marvin@42.fr> +#+ +:+ +#+ */
|
/* By: mcolonna <marvin@42.fr> +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2024/04/24 13:47:40 by mcolonna #+# #+# */
|
/* Created: 2024/04/24 13:47:40 by mcolonna #+# #+# */
|
||||||
/* Updated: 2024/05/17 14:41:50 by mcolonna ### ########.fr */
|
/* Updated: 2024/06/06 15:58:38 by mcolonna ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "include.h"
|
#include "include.h"
|
||||||
|
|
||||||
|
#define SYMBOL_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
|
||||||
|
|
||||||
|
// Return a pointer to the variable 'name'.
|
||||||
|
// If the variable doesn't exist, it's created with an empty value.
|
||||||
|
// (An undefined variable is considered of an empty value)
|
||||||
|
static t_variable *variables_find(t_list *variables, const char *name)
|
||||||
|
{
|
||||||
|
t_list_element *el;
|
||||||
|
t_variable *r;
|
||||||
|
|
||||||
|
el = variables->first;
|
||||||
|
while (el)
|
||||||
|
{
|
||||||
|
r = (t_variable *)el->value;
|
||||||
|
if (str_eq(r->name, name))
|
||||||
|
return (r);
|
||||||
|
el = el->next;
|
||||||
|
}
|
||||||
|
r = mem_alloc(fatal_error, variables->mc, sizeof(t_variable));
|
||||||
|
r->name = name;
|
||||||
|
r->value = "";
|
||||||
|
list_add(fatal_error, variables, r);
|
||||||
|
return (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a variable to a new value.
|
||||||
|
void variables_set(t_list *variables, const t_variable var)
|
||||||
|
{
|
||||||
|
variables_find(variables, var.name)->value = var.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of a variable from its name.
|
||||||
|
const char *variables_get(t_list *variables, const char *name)
|
||||||
|
{
|
||||||
|
return (variables_find(variables, name)->value);
|
||||||
|
}
|
||||||
|
|
||||||
// Ask the user for data and set readfd to the fd which will receive this
|
// Ask the user for data and set readfd to the fd which will receive this
|
||||||
// data.
|
// data.
|
||||||
// Returns 'errno' on error.
|
// Returns 'errno' on error.
|
||||||
|
@ -58,12 +95,13 @@ static int parse_error(const char *msg)
|
||||||
// Global variables for all the parsing functions
|
// Global variables for all the parsing functions
|
||||||
typedef struct s_parsing_args
|
typedef struct s_parsing_args
|
||||||
{
|
{
|
||||||
t_memclass mc;
|
t_memclass mc; // mc freed given to parse_command
|
||||||
t_command r;
|
t_command r; // t_command that parse_command will return
|
||||||
t_stream stream;
|
t_stream stream; // stream reading the command string
|
||||||
t_list calls;
|
t_list calls; // list of calls
|
||||||
bool got_first_call; // got at least the first program call?
|
bool got_first_call; // already got at least the first program call?
|
||||||
const char *heredoc;
|
const char *heredoc; // EOF line for heredoc. NULL if no heredoc
|
||||||
|
t_list *variables; // list of current variables
|
||||||
} t_parsing_args;
|
} t_parsing_args;
|
||||||
|
|
||||||
// Skip blank characters
|
// Skip blank characters
|
||||||
|
@ -87,37 +125,139 @@ static char *str_addchar(t_err err, t_memclass mc, const char *str, char c)
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the string, stop if the char is in stop_charset
|
// Read until a character is in the charset or is '\0'
|
||||||
// TODO variables if using "
|
// and append the string to dest..
|
||||||
static const char *get_string(t_parsing_args *args, const char *stop_charset)
|
static void read_until(t_parsing_args *args, const char **dest,
|
||||||
|
const char *stop_charset)
|
||||||
{
|
{
|
||||||
char quote;
|
|
||||||
const t_memclass mc = mem_subclass(fatal_error, args->mc);
|
|
||||||
const char *stop_charset_2;
|
|
||||||
char *str;
|
|
||||||
|
|
||||||
quote = '\0';
|
|
||||||
if (char_isin(stream_read(&args->stream), "\"'"))
|
|
||||||
quote = stream_pop(&args->stream);
|
|
||||||
if (!quote)
|
|
||||||
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 = str_dup(fatal_error, mc, "");
|
|
||||||
while (stream_read(&args->stream)
|
while (stream_read(&args->stream)
|
||||||
&& !char_isin(stream_read(&args->stream), stop_charset_2))
|
&& !char_isin(stream_read(&args->stream), stop_charset)
|
||||||
str = str_addchar(fatal_error, mc, str, stream_pop(&args->stream));
|
)
|
||||||
if (quote)
|
*dest = str_addchar(fatal_error, args->mc, *dest,
|
||||||
if (!stream_pop(&args->stream))
|
stream_pop(&args->stream));
|
||||||
return (NULL);
|
}
|
||||||
str = str_dup(fatal_error, args->mc, str);
|
|
||||||
mem_freeall(mc);
|
// Read until a character isn't in the charset or is '\0'
|
||||||
|
// and append the string to dest.
|
||||||
|
void read_only(t_parsing_args *args, const char **dest, const char *charset)
|
||||||
|
{
|
||||||
|
while (char_isin(stream_read(&args->stream), charset))
|
||||||
|
*dest = str_addchar(fatal_error, args->mc, *dest,
|
||||||
|
stream_pop(&args->stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the value of the variable and append it to dest.
|
||||||
|
// The stream must point to the first char of the variable name.
|
||||||
|
// FIXME Manage error (no variable name)
|
||||||
|
static void read_variable_value(t_parsing_args *args, const char **dest)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *value;
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
|
name = str_dup(fatal_error, args->mc, "");
|
||||||
|
read_only(args, &name, SYMBOL_CHARS);
|
||||||
|
value = variables_get(args->variables, name);
|
||||||
|
mem_free((char *)name);
|
||||||
|
tmp = *dest;
|
||||||
|
*dest = str_join(fatal_error, args->mc, *dest, value);
|
||||||
|
mem_free((char *)tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string without quotes.
|
||||||
|
// Append it to dest.
|
||||||
|
static void read_string_noquote(t_parsing_args *args, const char **dest,
|
||||||
|
const char *stop_charset)
|
||||||
|
{
|
||||||
|
const char *real_stop_charset
|
||||||
|
= str_join(fatal_error, args->mc, stop_charset, "$");
|
||||||
|
|
||||||
|
while (stream_read(&args->stream)
|
||||||
|
&& !char_isin(stream_read(&args->stream), stop_charset))
|
||||||
|
{
|
||||||
|
read_until(args, dest, real_stop_charset);
|
||||||
|
if (stream_read(&args->stream) == '$')
|
||||||
|
{
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
read_variable_value(args, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string with ' quotes.
|
||||||
|
// Append it to dest.
|
||||||
|
// Return false if it is not a ' quoted string.
|
||||||
|
// If parse error, return true and change args.r.error accordingly.
|
||||||
|
static bool read_string_quote(t_parsing_args *args, const char **dest)
|
||||||
|
{
|
||||||
|
if (stream_read(&args->stream) != '\'')
|
||||||
|
return (false);
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
read_until(args, dest, "'");
|
||||||
|
if (!stream_read(&args->stream))
|
||||||
|
{
|
||||||
|
args->r.error = parse_error("EOF unexpected");
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string with " quotes.
|
||||||
|
// Append it to dest.
|
||||||
|
// Return false if it is not a " quoted string.
|
||||||
|
// If parse error, return true and change args.r.error accordingly.
|
||||||
|
static bool read_string_doublequote(t_parsing_args *args, const char **dest)
|
||||||
|
{
|
||||||
|
if (stream_read(&args->stream) != '"')
|
||||||
|
return (false);
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
while (stream_read(&args->stream) != '"')
|
||||||
|
{
|
||||||
|
read_until(args, dest, "\"$");
|
||||||
|
if (stream_read(&args->stream) == '$')
|
||||||
|
{
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
read_variable_value(args, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stream_read(&args->stream))
|
||||||
|
{
|
||||||
|
args->r.error = parse_error("EOF unexpected");
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
stream_pop(&args->stream);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the string, stop if the char is in stop_charset.
|
||||||
|
// Possible syntaxes:
|
||||||
|
// - /[^(stop_charset)]+/
|
||||||
|
// - /'.*'/
|
||||||
|
// - /".*"/
|
||||||
|
static const char *read_string(t_parsing_args *args, const char *stop_charset)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
char *const real_stop_charset
|
||||||
|
= str_join(fatal_error, args->mc, stop_charset, " \r\n\t");
|
||||||
|
|
||||||
|
str = str_dup(fatal_error, args->mc, "");
|
||||||
|
while (!args->r.error
|
||||||
|
&& stream_read(&args->stream)
|
||||||
|
&& !char_isin(stream_read(&args->stream), real_stop_charset))
|
||||||
|
{
|
||||||
|
if (!read_string_quote(args, &str)
|
||||||
|
&& !read_string_doublequote(args, &str))
|
||||||
|
read_string_noquote(args, &str, real_stop_charset);
|
||||||
|
}
|
||||||
|
mem_free(real_stop_charset);
|
||||||
return (str);
|
return (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a program call (program names & its arguments) until stop_charset.
|
// Get a program call (program names & its arguments) until stop_charset.
|
||||||
static int get_call(t_parsing_args *args, const char *stop_charset)
|
// Change args accordingly.
|
||||||
|
// On success, return 0. On error, return the error status.
|
||||||
|
static int read_call(t_parsing_args *args, const char *stop_charset)
|
||||||
{
|
{
|
||||||
t_call *r;
|
t_call *r;
|
||||||
t_list arguments;
|
t_list arguments;
|
||||||
|
@ -127,7 +267,7 @@ static int get_call(t_parsing_args *args, const char *stop_charset)
|
||||||
while (stream_read(&args->stream)
|
while (stream_read(&args->stream)
|
||||||
&& !char_isin(stream_read(&args->stream), stop_charset))
|
&& !char_isin(stream_read(&args->stream), stop_charset))
|
||||||
{
|
{
|
||||||
str = get_string(args, stop_charset);
|
str = read_string(args, stop_charset);
|
||||||
if (!str)
|
if (!str)
|
||||||
return (parse_error("EOF unexpected"));
|
return (parse_error("EOF unexpected"));
|
||||||
list_add(fatal_error, &arguments,
|
list_add(fatal_error, &arguments,
|
||||||
|
@ -146,7 +286,10 @@ static int get_call(t_parsing_args *args, const char *stop_charset)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_inputfile(t_parsing_args *args, const char *stop_charset)
|
// Read a '<' or '<<' redirection from the file.
|
||||||
|
// Change args accordingly.
|
||||||
|
// On success, return 0. On error, return the error status.
|
||||||
|
static int read_inputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
bool heredoc;
|
bool heredoc;
|
||||||
|
@ -159,7 +302,7 @@ static int get_inputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
if (heredoc)
|
if (heredoc)
|
||||||
stream_pop(&args->stream);
|
stream_pop(&args->stream);
|
||||||
skip_blank(&args->stream);
|
skip_blank(&args->stream);
|
||||||
str = get_string(args, stop_charset);
|
str = read_string(args, stop_charset);
|
||||||
if (!str)
|
if (!str)
|
||||||
return (parse_error("EOF unexpected"));
|
return (parse_error("EOF unexpected"));
|
||||||
if (heredoc)
|
if (heredoc)
|
||||||
|
@ -173,7 +316,10 @@ static int get_inputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_outputfile(t_parsing_args *args, const char *stop_charset)
|
// Read a '>' or '>>' redirection from the file.
|
||||||
|
// Change args accordingly.
|
||||||
|
// On success, return 0. On error, return the error status.
|
||||||
|
static int read_outputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
{
|
{
|
||||||
const char *str;
|
const char *str;
|
||||||
int flag;
|
int flag;
|
||||||
|
@ -189,7 +335,7 @@ static int get_outputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
flag = O_APPEND;
|
flag = O_APPEND;
|
||||||
}
|
}
|
||||||
skip_blank(&args->stream);
|
skip_blank(&args->stream);
|
||||||
str = get_string(args, stop_charset);
|
str = read_string(args, stop_charset);
|
||||||
if (!str)
|
if (!str)
|
||||||
return (parse_error("EOF unexpected"));
|
return (parse_error("EOF unexpected"));
|
||||||
args->r.output_fd = open(
|
args->r.output_fd = open(
|
||||||
|
@ -199,7 +345,8 @@ static int get_outputfile(t_parsing_args *args, const char *stop_charset)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_element2(t_parsing_args *args, int *error, char c)
|
// (extension of read_element)
|
||||||
|
static void read_element2(t_parsing_args *args, int *error, char c)
|
||||||
{
|
{
|
||||||
stream_pop(&args->stream);
|
stream_pop(&args->stream);
|
||||||
skip_blank(&args->stream);
|
skip_blank(&args->stream);
|
||||||
|
@ -207,19 +354,20 @@ static void get_element2(t_parsing_args *args, int *error, char c)
|
||||||
{
|
{
|
||||||
if (!args->got_first_call)
|
if (!args->got_first_call)
|
||||||
*error = parse_error("'|', '>' or '<' expected");
|
*error = parse_error("'|', '>' or '<' expected");
|
||||||
*error = get_call(args, "<>|");
|
*error = read_call(args, "<>|");
|
||||||
}
|
}
|
||||||
else if (c == '>')
|
else if (c == '>')
|
||||||
*error = get_outputfile(args, "<>|");
|
*error = read_outputfile(args, "<>|");
|
||||||
else if (c == '<')
|
else if (c == '<')
|
||||||
*error = get_inputfile(args, "<>|");
|
*error = read_inputfile(args, "<>|");
|
||||||
else
|
else
|
||||||
fatal_error_msg("internal error u.u");
|
fatal_error_msg("internal error u.u");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read an element (a call to a program, a '< FILE' or a '> FILE')
|
// Read an element from the stream (a call to a program or a redirection)
|
||||||
|
// Change args accordingly.
|
||||||
// On success, return 0. On error, return the error status.
|
// On success, return 0. On error, return the error status.
|
||||||
static int get_element(t_parsing_args *args)
|
static int read_element(t_parsing_args *args)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
int error;
|
int error;
|
||||||
|
@ -229,9 +377,9 @@ static int get_element(t_parsing_args *args)
|
||||||
{
|
{
|
||||||
c = stream_read(&args->stream);
|
c = stream_read(&args->stream);
|
||||||
if (char_isin(c, "|><"))
|
if (char_isin(c, "|><"))
|
||||||
get_element2(args, &error, c);
|
read_element2(args, &error, c);
|
||||||
else if (!args->got_first_call)
|
else if (!args->got_first_call)
|
||||||
error = get_call(args, "<>|");
|
error = read_call(args, "<>|");
|
||||||
else
|
else
|
||||||
return (parse_error("'|', '>' or '<'' expected"));
|
return (parse_error("'|', '>' or '<'' expected"));
|
||||||
skip_blank(&args->stream);
|
skip_blank(&args->stream);
|
||||||
|
@ -239,31 +387,82 @@ static int get_element(t_parsing_args *args)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
t_parsing_args init_parsing_args(const t_memclass mc)
|
// Check if the command is a variable definition.
|
||||||
|
// If possible, change 'variables' accordingly and return true.
|
||||||
|
// If not, return false.
|
||||||
|
// FIXME read_string not possible.
|
||||||
|
static bool parse_variable_set_command(
|
||||||
|
t_parsing_args *args, const char *command, t_list *variables)
|
||||||
|
{
|
||||||
|
t_variable var;
|
||||||
|
|
||||||
|
streamstr_init(&args->stream, command);
|
||||||
|
skip_blank(&args->stream);
|
||||||
|
var.name = str_dup(fatal_error, args->mc, "");
|
||||||
|
read_only(args, &var.name, SYMBOL_CHARS);
|
||||||
|
if (str_len(var.name) == 0 || stream_pop(&args->stream) != '=')
|
||||||
|
return (false);
|
||||||
|
var.value = read_string(args, "<>|/");
|
||||||
|
skip_blank(&args->stream);
|
||||||
|
if (stream_read(&args->stream))
|
||||||
|
return (false);
|
||||||
|
variables_set(variables, var);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the command from the stream, and define args and args->r accordingly.
|
||||||
|
static void read_command(t_parsing_args *args)
|
||||||
|
{
|
||||||
|
while (!args->r.error && stream_read(&args->stream))
|
||||||
|
{
|
||||||
|
args->r.error = read_element(args);
|
||||||
|
skip_blank(&args->stream);
|
||||||
|
}
|
||||||
|
if (!args->r.error)
|
||||||
|
args->r.calls = (t_call *)list_convert_type(
|
||||||
|
fatal_error, args->mc, &args->calls, sizeof(t_call));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a t_parsing_args shared between all the parse_command subfunctions.
|
||||||
|
// Define every fields but .stream
|
||||||
|
static t_parsing_args init_parsing_args(const t_memclass mc,
|
||||||
|
t_list *variables)
|
||||||
{
|
{
|
||||||
const t_parsing_args r = {
|
const t_parsing_args r = {
|
||||||
.mc = mc,
|
|
||||||
.r = {
|
.r = {
|
||||||
.error = 0,
|
.error = 0,
|
||||||
.empty = false,
|
.empty = false,
|
||||||
.input_fd = 0,
|
.input_fd = 0,
|
||||||
.output_fd = 1,
|
.output_fd = 1,
|
||||||
},
|
},
|
||||||
|
.mc = mc,
|
||||||
.calls = list_createempty(mc),
|
.calls = list_createempty(mc),
|
||||||
.got_first_call = false,
|
.got_first_call = false,
|
||||||
.heredoc = NULL,
|
.heredoc = NULL,
|
||||||
|
.variables = variables,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (r);
|
return (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
t_command parse_command(const t_memclass mc, const char *command)
|
// - If the command string contains call(s), return the t_command to execute.
|
||||||
|
// - If necessary, input the user for the heredoc.
|
||||||
|
// - If the command string is a variable definition, define it and return
|
||||||
|
// an "empty" t_command.
|
||||||
|
// - If the command string is empty (or blank), return an "empty" t_command.
|
||||||
|
// - If there is any error, return a t_command with .error != 0.
|
||||||
|
// FIXME error with heredoc and parse error
|
||||||
|
t_command parse_command(const t_memclass mc, const char *command,
|
||||||
|
t_list *variables)
|
||||||
{
|
{
|
||||||
t_parsing_args args;
|
t_parsing_args args;
|
||||||
int error;
|
|
||||||
|
|
||||||
error = 0;
|
args = init_parsing_args(mc, variables);
|
||||||
args = init_parsing_args(mc);
|
if (parse_variable_set_command(&args, command, variables))
|
||||||
|
{
|
||||||
|
args.r.empty = true;
|
||||||
|
return (args.r);
|
||||||
|
}
|
||||||
streamstr_init(&args.stream, command);
|
streamstr_init(&args.stream, command);
|
||||||
skip_blank(&args.stream);
|
skip_blank(&args.stream);
|
||||||
if (!stream_read(&args.stream))
|
if (!stream_read(&args.stream))
|
||||||
|
@ -271,16 +470,7 @@ t_command parse_command(const t_memclass mc, const char *command)
|
||||||
args.r.empty = true;
|
args.r.empty = true;
|
||||||
return (args.r);
|
return (args.r);
|
||||||
}
|
}
|
||||||
while (!error && stream_read(&args.stream))
|
read_command(&args);
|
||||||
{
|
|
||||||
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;
|
|
||||||
if (args.heredoc)
|
if (args.heredoc)
|
||||||
heredoc(mc, &args.r.input_fd, args.heredoc);
|
heredoc(mc, &args.r.input_fd, args.heredoc);
|
||||||
return (args.r);
|
return (args.r);
|
||||||
|
|
Loading…
Add table
Reference in a new issue