diff --git a/src/execution/execution.c b/src/execution/execution.c index 90bb8eb..cf751f7 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -14,8 +14,6 @@ #include "../utils/ast/ast.h" #include "../utils/hash_map/hash_map.h" - - // Refactored: delegates to helpers in execution_helpers.c #include "execution_helpers.h" @@ -33,6 +31,7 @@ int execution(struct ast *ast, struct hash_map *vars) struct ast_command *command = ast_get_command(ast); if (!expand(command, vars)) fprintf(stderr, "Error: Variable expansion failed\n"); + return exec_ast_command(command, vars); } case AST_IF: @@ -41,8 +40,6 @@ int execution(struct ast *ast, struct hash_map *vars) return exec_ast_list(ast_get_list(ast), vars); case AST_AND_OR: return exec_ast_and_or(ast_get_and_or(ast), vars); - case AST_REDIR: - return exec_ast_redir(ast_get_redir(ast), vars); default: return 127; } diff --git a/src/execution/execution_helpers.c b/src/execution/execution_helpers.c index e82cbfe..cffcdb0 100644 --- a/src/execution/execution_helpers.c +++ b/src/execution/execution_helpers.c @@ -12,6 +12,8 @@ #include "../expansion/expansion.h" #include "../utils/ast/ast.h" #include "../utils/hash_map/hash_map.h" +#include "../utils/lists/lists.h" +#include "../utils/vars/vars.h" #include "execution.h" static char **list_to_argv(struct list *command_list) @@ -36,43 +38,61 @@ static char **list_to_argv(struct list *command_list) return argv; } -static int try_builtin(char **argv); +static int try_builtin(char **argv, struct hash_map *vars); int exec_ast_command(struct ast_command *command, struct hash_map *vars) { (void)vars; + set_all_redir(command->redirections); + if (!command || !(command->command)) + { return 1; + } + char **argv = list_to_argv(command->command); if (!argv || !(argv[0])) { free(argv); + unset_all_redir(); return 0; } - int builtin_ret = try_builtin(argv); + + int builtin_ret = try_builtin(argv, vars); if (builtin_ret != -1) { free(argv); + unset_all_redir(); return builtin_ret; } + pid_t pid = fork(); if (pid < 0) { perror("fork"); free(argv); + unset_all_redir(); return 1; } + if (pid == 0) { execvp(argv[0], argv); perror("execvp"); + unset_all_redir(); _exit(127); } + int status = 0; waitpid(pid, &status, 0); free(argv); + unset_all_redir(); + if (WIFEXITED(status)) + { return WEXITSTATUS(status); + } + return 1; } @@ -121,7 +141,7 @@ static int get_fd_target(const struct ast_redir *redir) if (redir->io_number != -1) return redir->io_number; if (redir->type == AST_REDIR_TYPE_LESS - || redir->type == AST_REDIR_TYPE_DLESS + || redir->type == AST_REDIR_TYPE_LESSGREAT || redir->type == AST_REDIR_TYPE_LESSAND) return 0; return 1; @@ -163,6 +183,72 @@ static int handle_and_restore_fd(int saved_fd, int fd_target) return 0; } +static int set_all_redir(struct list *redir_list) +{ + while (redir_list) + { + struct ast_redir *redir = (struct ast_redir *)redir_list->data; + int target_fd; + + if (redir->io_number != -1) + { + target_fd = redir->io_number; + } + else + { + // assign target_fd depending on redir type + if (redir->type == AST_REDIR_TYPE_LESS + || redir->type == AST_REDIR_TYPE_LESSGREAT + || redir->type == AST_REDIR_TYPE_LESSAND) + { + target_fd = 0; + } + else + { + target_fd = 1; + } + } + + redir->saved_fd = dup(target_fd); + int new_fd = -1; + int flags = 0; + int mode = 0644; + if (redir->type == AST_REDIR_TYPE_GREAT + || redir->type == AST_REDIR_TYPE_CLOBBER + || redir->type == AST_REDIR_TYPE_DGREAT + || redir->type == AST_REDIR_TYPE_LESS) + { + new_fd = open_redir_file(redir, &flags, &mode); + if (new_fd == -1) + { + perror("open"); + return -1; + } + } + else if (redir->type == AST_REDIR_TYPE_GREATAND + || redir->type == AST_REDIR_TYPE_LESSAND) + { + new_fd = atoi(redir->filename); + } + if (dup2(new_fd, target_fd) == -1) + { + perror("dup2"); + if (new_fd != -1) + { + close(new_fd); + } + return -1; + } + if (new_fd != -1) + { + close(new_fd); + } + redir_list = redir_list->next; + } + return 0; +} + +/* int exec_ast_redir(struct ast_redir *redir, struct hash_map *vars) { int fd_target = get_fd_target(redir); @@ -206,7 +292,7 @@ int exec_ast_redir(struct ast_redir *redir, struct hash_map *vars) int ret = execution(redir->child, vars); handle_and_restore_fd(saved_fd, fd_target); return ret; -} +} */ // --- Builtins --- @@ -234,7 +320,6 @@ static int builtin_echo(char **argv) return 0; } - static int builtin_true(char **argv) { (void)argv; @@ -256,8 +341,7 @@ static int builtin_exit(char **argv) return exit_val; } - -static int builtin_cd(char **argv) +static int builtin_cd(char **argv, struct hash_map *vars) { const char *path = argv[1]; if (!path) @@ -269,22 +353,25 @@ static int builtin_cd(char **argv) return 1; } } + // char *pwd = getcwd("", ""); + char *pwd = get_var_or_env(vars, "PWD"); if (chdir(path) != 0) { perror("cd"); return 1; } + set_var_copy(vars, "OLD_PWD", pwd); + set_var_copy(vars, "PWD", path); return 0; } - /** * @brief Tries to execute a builtin command if the command matches a builtin * * @param argv Array of command arguments * @return int Exit status of the builtin command, or -1 if not a builtin */ -static int try_builtin(char **argv) +static int try_builtin(char **argv, struct hash_map *vars) { if (!argv || !argv[0]) return 0; @@ -298,7 +385,7 @@ static int try_builtin(char **argv) if (strcmp(argv[0], "exit") == 0) return builtin_exit(argv); if (strcmp(argv[0], "cd") == 0) - return builtin_cd(argv); + return builtin_cd(argv, vars); return -1; } diff --git a/src/execution/execution_helpers.h b/src/execution/execution_helpers.h index ebac0cb..fd8026c 100644 --- a/src/execution/execution_helpers.h +++ b/src/execution/execution_helpers.h @@ -8,6 +8,5 @@ int exec_ast_command(struct ast_command *command, struct hash_map *vars); int exec_ast_if(struct ast_if *if_node, struct hash_map *vars); int exec_ast_list(struct ast_list *list_node, struct hash_map *vars); int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars); -int exec_ast_redir(struct ast_redir *redir, struct hash_map *vars); #endif // EXECUTION_HELPERS_H diff --git a/src/expansion/expansion.c b/src/expansion/expansion.c index ab6241e..4fea985 100644 --- a/src/expansion/expansion.c +++ b/src/expansion/expansion.c @@ -135,7 +135,7 @@ bool expand(struct ast_command *command, const struct hash_map *vars) { if (str[i] == '\'') { - // remove quote + // remove single quote in_quotes = !in_quotes; memmove(str + i, str + i + 1, strlen(str + i + 1) + 1); i--; @@ -144,6 +144,12 @@ bool expand(struct ast_command *command, const struct hash_map *vars) { continue; // do nothing } + else if (str[i] == '\"') + { + // remove double quote + memmove(str + i, str + i + 1, strlen(str + i + 1) + 1); + i--; + } else if (str[i] == '$' && str[i + 1] != 0 && !isspace(str[i + 1])) { // variable expansion diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index ff7f351..fd5764d 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -78,21 +78,43 @@ static bool update_lexing_mode(char *stream, ssize_t i, return *lexing_mode != mode_before_update; } +/* @brief: updates the flags only_digits and has_equal. + * according to the character at stream[i]. + */ +static void update_flags(char *stream, ssize_t i, struct token_info *info) +{ + if (stream[i] == '=' && !info->has_equal) + { + if (i == 0) + { + perror("Syntax error: word start with a '='"); + return; + } + else + info->has_equal = true; + } + else if (!isdigit(stream[i]) && info->only_digits) + { + info->only_digits = false; + } +} + struct token *peek_token(struct lexer_context *ctx) { + stream_init(ctx); + + // Usefull to know if we are inside a quote or double quote + enum lexing_mode lexing_mode = LEXER_NORMAL; + struct token_info info = { true, 0 }; + char *stream = ctx->end_previous_token; + ssize_t i = 0; + // we already created the upcoming token during the previous call to peek() if (ctx->current_token != NULL) { return ctx->current_token; } - stream_init(ctx); - char *stream = ctx->end_previous_token; - ssize_t i = 0; - - // Usefull to know if we are inside a quote or double quote - enum lexing_mode lexing_mode = LEXER_NORMAL; - while (i < ctx->remaining_chars) { // true if we didn't encounter a quote of any type at stream[i] @@ -100,6 +122,7 @@ struct token *peek_token(struct lexer_context *ctx) if (!update_lexing_mode(stream, i, &lexing_mode) && lexing_mode == LEXER_NORMAL) { + update_flags(stream, i, &info); if (is_special_char(stream, i)) { if (i == 0) // where we create spe_char token @@ -121,7 +144,7 @@ struct token *peek_token(struct lexer_context *ctx) i++; } - struct token *tok = new_token(stream, i, ctx->only_digits); + struct token *tok = new_token(stream, i, &info); // if token is comment, we don't want it if (tok->type == TOKEN_COMMENT) @@ -138,6 +161,14 @@ struct token *peek_token(struct lexer_context *ctx) struct token *pop_token(struct lexer_context *ctx) { + stream_init(ctx); + + // Usefull to know if we are inside a quote or double quote + enum lexing_mode lexing_mode = LEXER_NORMAL; + struct token_info info = { true, 0 }; + char *stream = ctx->end_previous_token; + ssize_t i = 0; + if (ctx->current_token != NULL && ctx->current_token->type == TOKEN_EOF) { // we reached end of input, frees all the token still allocated. @@ -145,12 +176,6 @@ struct token *pop_token(struct lexer_context *ctx) free_token(&ctx->current_token); return NULL; } - stream_init(ctx); - char *stream = ctx->end_previous_token; - ssize_t i = 0; - - // Usefull to know if we are inside a quote or double quote - enum lexing_mode lexing_mode = LEXER_NORMAL; while (i < ctx->remaining_chars) { @@ -159,6 +184,7 @@ struct token *pop_token(struct lexer_context *ctx) if (!update_lexing_mode(stream, i, &lexing_mode) && lexing_mode == LEXER_NORMAL) { + update_flags(stream, i, &info); if (is_special_char(stream, i)) { if (i == 0) // where we create spe_char token @@ -184,7 +210,7 @@ struct token *pop_token(struct lexer_context *ctx) // (this should never happen) if (ctx->current_token == NULL) { - ctx->current_token = new_token(stream, i, ctx->only_digits); + ctx->current_token = new_token(stream, i, &info); } save_state(stream, i, ctx); diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index 07455a7..f860649 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -97,35 +97,43 @@ static void set_token_operator(struct token *tok, char *begin, ssize_t size) { if (tok->type != TOKEN_NULL) return; - if (strncmp(begin, ">", size) == 0) + if (strncmp(begin, "||", size) == 0 && size == 2) + { + tok->type = TOKEN_OR; + } + else if (strncmp(begin, "&&", size) == 0 && size == 2) + { + tok->type = TOKEN_AND; + } + else if (strncmp(begin, ">", size) == 0 && size == 1) { tok->type = TOKEN_REDIR_RIGHT; } - else if (strncmp(begin, "<", size) == 0) + else if (strncmp(begin, "<", size) == 0 && size == 1) { tok->type = TOKEN_REDIR_LEFT; } - else if (strncmp(begin, ">>", size) == 0) + else if (strncmp(begin, ">>", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_DOUBLE_RIGHT; } - else if (strncmp(begin, ">&", size) == 0) + else if (strncmp(begin, ">&", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_RIGHT_AMP; } - else if (strncmp(begin, ">|", size) == 0) + else if (strncmp(begin, ">|", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_RIGHT_PIPE; } - else if (strncmp(begin, "<&", size) == 0) + else if (strncmp(begin, "<&", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_LEFT_AMP; } - else if (strncmp(begin, "<>", size) == 0) + else if (strncmp(begin, "<>", size) == 0 && size == 2) { tok->type = TOKEN_REDIR_LEFT_RIGHT; } - else if (strncmp(begin, "|", size) == 0) + else if (strncmp(begin, "|", size) == 0 && size == 1) { tok->type = TOKEN_PIPE; } @@ -146,6 +154,21 @@ static void set_token_word(struct token *tok, char *begin, ssize_t size) } } +/* @brief: Sets the token to an assignment_word + * Also allocates the data and fills it. + */ +static void set_token_assignment(struct token *tok, char *begin, ssize_t size) +{ + if (tok->type == TOKEN_NULL && size != 0) + { + tok->type = TOKEN_ASSIGNMENT_WORD; + tok->data = calloc(size + 1, sizeof(char)); + if (tok->data == NULL) + return; + strncpy(tok->data, begin, size); + } +} + /* @brief: Sets the token to an IO number * Also allocates the data and fills it. */ @@ -204,19 +227,23 @@ bool is_special_char(char *stream, ssize_t i) return strchr(special_chars, c) != NULL; } -struct token *new_token(char *begin, ssize_t size, bool only_digits) +struct token *new_token(char *begin, ssize_t size, struct token_info *info) { struct token *tok = calloc(1, sizeof(struct token)); if (tok == NULL) return NULL; - if (only_digits) + if (info->only_digits) set_token_ION(tok, begin, size); - - set_token_operator(tok, begin, size); - set_token_spechar(tok, begin, size); - set_token_keyword(tok, begin, size); - set_token_word(tok, begin, size); + else if (info->has_equal) + set_token_assignment(tok, begin, size); + else + { + set_token_operator(tok, begin, size); + set_token_spechar(tok, begin, size); + set_token_keyword(tok, begin, size); + set_token_word(tok, begin, size); + } return tok; } @@ -267,6 +294,12 @@ ssize_t len_op_sepchar(char *stream, ssize_t i) if (!is_special_char(stream, i)) return -1; // should never happen + if (stream[i] == '|' || stream[i + 1] == '|') + return 2; // OR || + + if (stream[i] == '&' && stream[i + 1] == '&') + return 2; // AND && + if (stream[i] != '>' && stream[i] != '<') return 1; // special character (cannot be operator) diff --git a/src/lexer/lexer_utils.h b/src/lexer/lexer_utils.h index c6c26c9..8fb5219 100644 --- a/src/lexer/lexer_utils.h +++ b/src/lexer/lexer_utils.h @@ -10,10 +10,6 @@ struct lexer_context char *end_previous_token; ssize_t remaining_chars; - // usefull to detect IO numbers. - // tells us if we only lexed digits in current token. - bool only_digits; - struct token *previous_token; struct token *current_token; }; @@ -34,10 +30,13 @@ enum token_type // Blanks TOKEN_NULL = 0, TOKEN_EOF, - TOKEN_WORD, TOKEN_NEWLINE, - // SPecial characters + // words + TOKEN_WORD, + TOKEN_ASSIGNMENT_WORD, + + // Special characters TOKEN_GRAVE, TOKEN_SEMICOLON, TOKEN_COMMENT, @@ -51,10 +50,6 @@ enum token_type TOKEN_PIPE, TOKEN_NEGATION, - // TODO merge into one and use the data field - // (Too difficult to handle in the parser because of firsts) - // TOKEN_REDIRECTION - // // Redirections TOKEN_REDIR_LEFT, TOKEN_REDIR_RIGHT, @@ -82,17 +77,29 @@ struct token char *data; }; +// used to give info from lexing when creating a new token. +struct token_info +{ + // usefull to detect IO numbers. + // tells us if we only lexed digits in current token. + bool only_digits; + + // usefull to detect assignments, and syntax errors with '='. + bool has_equal; +}; + /* @return: true if a special character from the grammar was found at stream[i], * false otherwise. */ bool is_special_char(char *stream, ssize_t i); -/* @brief: return a newly allocated token, with the corresponding type. +/* @brief: return a newly allocated token, with the type corresponding + * to the info given in arguments. * The data contains [size] char, starting from [begin]. * * @return: NULL on error, a token otherwise. */ -struct token *new_token(char *begin, ssize_t size, bool only_digits); +struct token *new_token(char *begin, ssize_t size, struct token_info *info); /* @brief: frees the token given in argument */ diff --git a/src/parser/grammar.c b/src/parser/grammar.c index 83f2266..95f1bd2 100644 --- a/src/parser/grammar.c +++ b/src/parser/grammar.c @@ -106,15 +106,15 @@ bool grammar_init(void) add_first(RULE_LIST, TOKEN_WORD); add_first(RULE_LIST, TOKEN_IF); - add_first(RULE_COMMAND, TOKEN_NEGATION); + add_first(RULE_LIST, TOKEN_NEGATION); add_first(RULE_AND_OR, TOKEN_WORD); add_first(RULE_AND_OR, TOKEN_IF); - add_first(RULE_COMMAND, TOKEN_NEGATION); + add_first(RULE_AND_OR, TOKEN_NEGATION); add_first(RULE_PIPELINE, TOKEN_WORD); add_first(RULE_PIPELINE, TOKEN_IF); - add_first(RULE_COMMAND, TOKEN_NEGATION); + add_first(RULE_PIPELINE, TOKEN_NEGATION); add_first(RULE_COMMAND, TOKEN_WORD); add_first(RULE_COMMAND, TOKEN_IF); diff --git a/src/parser/grammar_advanced.c b/src/parser/grammar_advanced.c index 3850564..d57e70e 100644 --- a/src/parser/grammar_advanced.c +++ b/src/parser/grammar_advanced.c @@ -6,6 +6,7 @@ #include #include +#include "grammar.h" #include "grammar_basic.h" static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type) @@ -16,7 +17,16 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type) return AST_REDIR_TYPE_LESS; case TOKEN_REDIR_RIGHT: return AST_REDIR_TYPE_GREAT; - // TODO finish this + case TOKEN_REDIR_DOUBLE_RIGHT: + return AST_REDIR_TYPE_DGREAT; + case TOKEN_REDIR_LEFT_RIGHT: + return AST_REDIR_TYPE_LESSGREAT; + case TOKEN_REDIR_LEFT_AMP: + return AST_REDIR_TYPE_LESSAND; + case TOKEN_REDIR_RIGHT_AMP: + return AST_REDIR_TYPE_GREATAND; + case TOKEN_REDIR_RIGHT_PIPE: + return AST_REDIR_TYPE_CLOBBER; default: return AST_REDIR_TYPE_NULL; } @@ -57,5 +67,17 @@ struct ast *parse_redirection(struct lexer_context *ctx) struct ast *parse_prefix(struct lexer_context *ctx) { - return parse_redirection(ctx); + struct token *token = PEEK_TOKEN(); + if (token->type == TOKEN_ASSIGNMENT_WORD) + { + token = POP_TOKEN(); + return ast_create_assignment(token->data); + } + else if (is_first(*token, RULE_REDIRECTION)) + return parse_redirection(ctx); + else + { + perror("Syntax error: expected a prefix (redirection or assignment)"); + return NULL; + } } diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index d4a740f..598c70a 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -152,14 +152,15 @@ struct ast *parse_pipeline(struct lexer_context *ctx) struct ast *parse_command(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); + struct ast *result = NULL; - if (token->type == TOKEN_WORD) + if (is_first(*token, RULE_SIMPLE_COMMAND)) { - return parse_simple_command(ctx); + result = parse_simple_command(ctx); } - else if (token->type == TOKEN_IF) + else if (is_first(*token, RULE_SHELL_COMMAND)) { - return parse_shell_command(ctx); + parse_shell_command(ctx); } else { @@ -168,64 +169,109 @@ struct ast *parse_command(struct lexer_context *ctx) } } +/* @brief: frees command_elements and redirections lists (helper func) + * @return: NULL + */ +static void *err_simple_command(struct list *command_elements, + struct list *redirections) +{ + list_deep_destroy(command_elements); + list_deep_destroy(redirections); + return NULL; +} + struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; + struct list *redirections = NULL; // list of redirection ASTs + struct list *assignments = NULL; + + bool has_prefix = false; + struct token *token = PEEK_TOKEN(); + if (is_first(*token, RULE_PREFIX)) + { + has_prefix = true; + while (is_first(*token, RULE_PREFIX)) + { + struct ast *prefix = parse_prefix(ctx); + if (prefix == NULL) + { + return err_simple_command(command_elements, redirections); + } + if (prefix->type == AST_ASSIGNMENT) + { + assignments = list_append(assignments, prefix); + } + else if (prefix->type == AST_REDIR) + { + redirections = list_append(redirections, prefix); + } + token = PEEK_TOKEN(); + } + } - // WORD - struct token *token = POP_TOKEN(); if (token->type != TOKEN_WORD) { - perror("Expected a command but got a different token type"); - return NULL; + if (!has_prefix) + { + perror("Expected a command but got a different token type"); + return err_simple_command(command_elements, redirections); + } + // else : only prefixes } - char *command = strdup(token->data); - command_elements = list_append(command_elements, command); - - token = PEEK_TOKEN(); - - // Eventual elements - while (is_first(*token, RULE_ELEMENT)) + else { - // Get element - struct ast *element = parse_element(ctx); - if (element == NULL) + if (token->type == TOKEN_WORD) { - list_deep_destroy(command_elements); - return NULL; - } + char *command = strdup(token->data); + command_elements = list_append(command_elements, command); - // Get element type - if (ast_is_word(element)) - { - struct ast_word *element_word = ast_get_word(element); - command_elements = - list_append(command_elements, element_word->word); + POP_TOKEN(); + token = PEEK_TOKEN(); } - else if (ast_is_redir(element)) + // Eventual elements + while (is_first(*token, RULE_ELEMENT)) { - // TODO - perror("NOT IMPLEMENTED"); - return NULL; - } - else - { - perror("Internal error: unexpected return value from parse_element " - "in parse_simple_command"); - list_deep_destroy(command_elements); - return NULL; - } + // Get element + struct ast *element = parse_element(ctx); + if (element == NULL) + { + return err_simple_command(command_elements, redirections); + } - // Forward - token = PEEK_TOKEN(); + // Get element type + if (ast_is_word(element)) + { + struct ast_word *element_word = ast_get_word(element); + + // TODO test this fix for the memory leaks + char *word = strdup(element_word->word); + ast_free(&element); + command_elements = list_append(command_elements, word); + // end of fix + } + else if (ast_is_redir(element)) + { + // append redirections to the list of redirections + redirections = list_append(redirections, element); + } + else + { + perror("Internal error: unexpected return value from " + "parse_element in parse_simple_command"); + return err_simple_command(command_elements, redirections); + } + + // Forward + token = PEEK_TOKEN(); + } } - // Result - struct ast *result = ast_create_command(command_elements); + struct ast *result = + ast_create_command(command_elements, redirections, assignments); if (result == NULL) { - list_deep_destroy(command_elements); - return NULL; + return err_simple_command(command_elements, redirections); } return result; } @@ -254,6 +300,18 @@ struct ast *parse_shell_command(struct lexer_context *ctx) return parse_if_rule(ctx); } +/* @brief: frees all the arguments. (helper func) + * @return: NULL. + */ +static void *err_if_rule(struct ast **cond, struct ast **then_clause, + struct ast **else_clause) +{ + ast_free(cond); + ast_free(then_clause); + ast_free(else_clause); + return NULL; +} + struct ast *parse_if_rule(struct lexer_context *ctx) { // If keyword @@ -272,38 +330,34 @@ struct ast *parse_if_rule(struct lexer_context *ctx) token = POP_TOKEN(); if (token->type != TOKEN_THEN) { - ast_free(&condition_content); perror("Expected the 'then' keyword but token has different type"); - return NULL; + return err_if_rule(&condition_content, NULL, NULL); } // Then content struct ast *then_content = parse_compound_list(ctx); if (then_content == NULL) { - ast_free(&condition_content); - ast_free(&then_content); - return NULL; + return err_if_rule(&condition_content, &then_content, NULL); } + struct ast *else_content = NULL; // Eventual else/elif clause(s) - struct ast *else_content = parse_else_clause(ctx); - if (else_content == NULL) + if (is_first(*token, RULE_ELSE_CLAUSE)) { - ast_free(&condition_content); - ast_free(&then_content); - return NULL; + else_content = parse_else_clause(ctx); + if (else_content == NULL) + { + return err_if_rule(&condition_content, &then_content, NULL); + } } // Fi keyword token = POP_TOKEN(); if (token->type != TOKEN_FI) { - ast_free(&condition_content); - ast_free(&then_content); - ast_free(&else_content); perror("Expected the 'fi' keyword but token has different type"); - return NULL; + return err_if_rule(&condition_content, &then_content, &else_content); } // Result @@ -311,11 +365,8 @@ struct ast *parse_if_rule(struct lexer_context *ctx) ast_create_if(condition_content, then_content, else_content); if (result == NULL) { - ast_free(&condition_content); - ast_free(&then_content); - ast_free(&else_content); perror("Internal error: could not create a new AST (AST_IF)"); - return NULL; + return err_if_rule(&condition_content, &then_content, &else_content); } return result; diff --git a/src/utils/ast/ast.h b/src/utils/ast/ast.h index 3964968..9827d8d 100644 --- a/src/utils/ast/ast.h +++ b/src/utils/ast/ast.h @@ -2,6 +2,7 @@ #define AST_H #include "ast_and_or.h" +#include "ast_assignment.h" #include "ast_base.h" #include "ast_command.h" #include "ast_end.h" diff --git a/src/utils/ast/ast_assignment.c b/src/utils/ast/ast_assignment.c new file mode 100644 index 0000000..a839e9e --- /dev/null +++ b/src/utils/ast/ast_assignment.c @@ -0,0 +1,54 @@ +#define _POSIX_C_SOURCE 200809L + +#include "ast_assignment.h" + +#include + +bool ast_is_assignment(struct ast *node) +{ + return node != NULL && node->type == AST_ASSIGNMENT; +} + +struct ast_assignment *ast_get_assignment(struct ast *node) +{ + if (node == NULL || node->type != AST_ASSIGNMENT) + return NULL; + return (struct ast_assignment *)node->data; +} + +/* @brief: splits the assignement 'name=value' into 2 parts, + * and fills the fields of ast_assignment with it. + */ +static void init_assignments(struct ast_assignment *ast_assignment, + char *assignment) +{ + if (assignment == NULL) + return; + char *split_pos = strchr(assignment, '='); + if (split_pos == NULL) + return; + + *split_pos = '\0'; + ast_assignment->name = strdup(assignment); + ast_assignment->value = strdup(split_pos + 1); +} + +struct ast *ast_create_assignment(char *assignment) +{ + struct ast_assignment *assignment_data = + calloc(1, sizeof(struct ast_assignment)); + if (!assignment_data) + return NULL; + + init_assignments(assignement_data); + return ast_create(AST_ASSIGNMENT, assignment_data); +} + +void ast_free_assignment(struct ast_assignment *assignment_data) +{ + if (assignment_data == NULL) + return; + free(assignment_data->name); + free(assignment_data->value); + free(assignment_data); +} diff --git a/src/utils/ast/ast_assignment.h b/src/utils/ast/ast_assignment.h new file mode 100644 index 0000000..5be56c8 --- /dev/null +++ b/src/utils/ast/ast_assignment.h @@ -0,0 +1,17 @@ +#ifndef AST_ASSIGNMENT_H +#define AST_ASSIGNMENT_H + +#include "ast_base.h" + +struct ast_assignment +{ + char *name; + char *value; +}; + +bool ast_is_assignment(struct ast *node); +struct ast_assignment *ast_get_assignment(struct ast *node); +struct ast *ast_create_assignment(char *assignment); +void ast_free_assignment(struct ast_assignment *assignment_data); + +#endif /* ! AST_ASSIGNMENT_H */ diff --git a/src/utils/ast/ast_base.h b/src/utils/ast/ast_base.h index f81f2f0..ae99a39 100644 --- a/src/utils/ast/ast_base.h +++ b/src/utils/ast/ast_base.h @@ -15,7 +15,8 @@ enum ast_type AST_CMD, AST_WORD, AST_PIPE, - AST_NEG + AST_NEG, + AST_ASSIGNMENT }; struct ast diff --git a/src/utils/ast/ast_command.c b/src/utils/ast/ast_command.c index 14904ae..3865e0e 100644 --- a/src/utils/ast/ast_command.c +++ b/src/utils/ast/ast_command.c @@ -5,13 +5,15 @@ #include "../lists/lists.h" -struct ast *ast_create_command(struct list *command) +struct ast *ast_create_command(struct list *command, struct list *redirections, + struct ast_list *assignments) { struct ast_command *command_data = malloc(sizeof(struct ast_command)); if (!command_data) return NULL; command_data->command = command; + command_data->redirections = redirections; return ast_create(AST_CMD, command_data); } @@ -33,5 +35,7 @@ void ast_free_command(struct ast_command *command_data) if (command_data == NULL) return; list_deep_destroy(command_data->command); + ast_list_deep_destroy(command_data->redirections); + ast_list_deep_destroy(command_data->assignments); free(command_data); } diff --git a/src/utils/ast/ast_command.h b/src/utils/ast/ast_command.h index cf6b913..75c8b2e 100644 --- a/src/utils/ast/ast_command.h +++ b/src/utils/ast/ast_command.h @@ -7,6 +7,8 @@ struct ast_command { struct list *command; // A list of words (char*) + struct ast_list *redirections; // A list of ASTs, all ast_redir + struct list *assignments; // A list of ASTs, all ast_assignment }; /** @@ -23,7 +25,8 @@ struct ast_command *ast_get_command(struct ast *node); /** * Creates a new AST node representing a command. */ -struct ast *ast_create_command(struct list *command); +struct ast *ast_create_command(struct list *command, struct list *redirections, + struct list *assignments); /* * @brief: frees the given ast_command and sets the pointer to NULL. diff --git a/src/utils/ast/ast_redir.h b/src/utils/ast/ast_redir.h index eb95942..9d9a9d3 100644 --- a/src/utils/ast/ast_redir.h +++ b/src/utils/ast/ast_redir.h @@ -8,7 +8,7 @@ enum ast_redir_type AST_REDIR_TYPE_NULL, AST_REDIR_TYPE_LESS, // < AST_REDIR_TYPE_GREAT, // > - AST_REDIR_TYPE_DLESS, // << + AST_REDIR_TYPE_LESSGREAT, // <> AST_REDIR_TYPE_DGREAT, // >> AST_REDIR_TYPE_LESSAND, // <& AST_REDIR_TYPE_GREATAND, // >& @@ -21,6 +21,7 @@ struct ast_redir int io_number; // The FD being redirected (default -1 if not specified, // implies 0 or 1 based on type) enum ast_redir_type type; + int saved_fd; // To store the original FD for restoration (-1 before save) }; bool ast_is_redir(struct ast *node);