From 39ca927c0646b2b5e5c992efb7312f2c1cb2767d Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Wed, 21 Jan 2026 20:00:48 +0100 Subject: [PATCH 1/6] fix(IOB): EOF does not overwrite last char anymore --- src/io_backend/io_backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io_backend/io_backend.c b/src/io_backend/io_backend.c index 41236e9..401daed 100644 --- a/src/io_backend/io_backend.c +++ b/src/io_backend/io_backend.c @@ -99,7 +99,7 @@ ssize_t stream_read(char **stream) *stream = context.args; size_t len = strlen(context.args); context.args[len] = EOF; - return len; + return len + 1; } else { From 687f38523b7671fbd338892a5b49559cd7ba9841 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 12:08:51 +0100 Subject: [PATCH 2/6] fix(main_loop): no double echo --- src/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.c b/src/main.c index a6b18a7..b86a9a7 100644 --- a/src/main.c +++ b/src/main.c @@ -81,9 +81,6 @@ int main(int argc, char **argv) ast_print_dot(command_ast); } - // Call the executor with the AST - return_code = execution(command_ast); - // Main parse-execute loop while (command_ast != NULL && command_ast->type != AST_END) { From 609c1667af13343b03a83038bde67405457e10fd Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 12:59:04 +0100 Subject: [PATCH 3/6] fix(lexer): POKEDALLARS --- src/lexer/lexer.c | 2 +- src/lexer/lexer_utils.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 89b5f71..f16088b 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -19,7 +19,7 @@ static bool is_special_char(char c) if (c == EOF) return true; - char special_chars[] = "\n'\"`;#|&\\$(){}<>*"; + char special_chars[] = "\n'\"`;#|&\\(){}<>*"; return strchr(special_chars, c) != NULL; } diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index f954676..0a0a23d 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -45,9 +45,6 @@ static void set_token_spechar(struct token *tok, char *begin, ssize_t size) case '\\': tok->type = TOKEN_BACKSLASH; break; - case '$': - tok->type = TOKEN_DOLLAR; - break; case '(': tok->type = TOKEN_LEFT_PAREN; break; From 4fc43e4678656088b66bafeb9d62a80eb29c2168 Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 22 Jan 2026 12:09:18 +0000 Subject: [PATCH 4/6] feat(dev): expansion --- src/Makefile.am | 2 +- src/execution/execution.c | 22 +++++++++++++--------- src/execution/execution.h | 3 ++- src/expansion/expansion.c | 13 ++++++------- src/expansion/expansion.h | 4 ++-- src/main.c | 4 +++- src/utils/vars/vars.c | 15 +++++++++------ src/utils/vars/vars.h | 5 ----- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index bd5d691..56c48b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,8 +18,8 @@ bin_PROGRAMS = 42sh parser/libparser.a \ lexer/liblexer.a \ io_backend/libio_backend.a \ - expansion/libexpansion.a \ execution/libexecution.a \ + expansion/libexpansion.a \ utils/libutils.a # ================ TESTS ================ diff --git a/src/execution/execution.c b/src/execution/execution.c index ec0fe21..a98ff2f 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -9,7 +9,9 @@ #include #include +#include "../expansion/expansion.h" #include "../utils/ast/ast.h" +#include "../utils/hash_map/hash_map.h" // --- Helpers --- @@ -205,7 +207,7 @@ static int exec_command(struct ast_command *command) * @param ast The AST to execute * @return int The exit status of the last executed command. */ -int execution(struct ast *ast) +int execution(struct ast *ast, struct hash_map *vars) { if (!ast) { @@ -219,18 +221,20 @@ int execution(struct ast *ast) } case AST_CMD: { struct ast_command *command = ast_get_command(ast); + if (!expand(command, vars)) + fprintf(stderr, "Error: Variable expansion failed\n"); return exec_command(command); } case AST_IF: { struct ast_if *if_node = ast_get_if(ast); - int cond = execution(if_node->condition); + int cond = execution(if_node->condition, vars); if (cond == 0) // True { - return execution(if_node->then_clause); + return execution(if_node->then_clause, vars); } else // False { - return execution(if_node->else_clause); + return execution(if_node->else_clause, vars); } } case AST_LIST: { @@ -240,25 +244,25 @@ int execution(struct ast *ast) while (cur) { struct ast *child = (struct ast *)cur->data; - ret = execution(child); + ret = execution(child, vars); cur = cur->next; } return ret; } case AST_AND_OR: { struct ast_and_or *ao_node = ast_get_and_or(ast); - int left_ret = execution(ao_node->left); + int left_ret = execution(ao_node->left, vars); if (ao_node->type == AST_AND_OR_TYPE_AND) { if (left_ret == 0) - return execution(ao_node->right); + return execution(ao_node->right, vars); return left_ret; } else // OR { if (left_ret != 0) - return execution(ao_node->right); + return execution(ao_node->right, vars); return left_ret; } } @@ -335,7 +339,7 @@ int execution(struct ast *ast) close(new_fd); } - int ret = execution(redir->child); + int ret = execution(redir->child, vars); if (saved_fd != -1) { diff --git a/src/execution/execution.h b/src/execution/execution.h index aacacc3..872f0ad 100644 --- a/src/execution/execution.h +++ b/src/execution/execution.h @@ -3,6 +3,7 @@ #include "../utils/ast/ast.h" #include "../utils/lists/lists.h" +#include "../utils/hash_map/hash_map.h" /** * @brief Execute the AST @@ -10,6 +11,6 @@ * @param ast Pointer to the AST structure * @return int Execution status code of the last command */ -int execution(struct ast *ast); +int execution(struct ast *ast, struct hash_map *vars); #endif /* ! EXECUTION_H */ diff --git a/src/expansion/expansion.c b/src/expansion/expansion.c index 407e2f7..ab6241e 100644 --- a/src/expansion/expansion.c +++ b/src/expansion/expansion.c @@ -115,11 +115,10 @@ static bool expand_var(char **str, size_t pos, const struct hash_map *vars) return false; } -struct ast_command *expand(struct ast_command *command, - const struct hash_map *vars) +bool expand(struct ast_command *command, const struct hash_map *vars) { if (command == NULL) - return NULL; + return false; char *str; size_t len; @@ -150,7 +149,7 @@ struct ast_command *expand(struct ast_command *command, // variable expansion bool r = expand_var(&str, i, vars); if (r == false || str == NULL) - return NULL; + return false; i--; // -1 because loop will increment i } @@ -160,7 +159,7 @@ struct ast_command *expand(struct ast_command *command, { // error: quote not closed fprintf(stderr, "Error: quote not closed in string: %s\n", str); - return NULL; + return false; } if (len != strlen(str)) @@ -169,12 +168,12 @@ struct ast_command *expand(struct ast_command *command, if (new_str == NULL) { // error: realloc fail - return NULL; + return false; } l->data = new_str; } l = l->next; } - return command; + return true; } diff --git a/src/expansion/expansion.h b/src/expansion/expansion.h index 7211ae3..64b016f 100644 --- a/src/expansion/expansion.h +++ b/src/expansion/expansion.h @@ -1,6 +1,7 @@ #ifndef EXPANSION_H #define EXPANSION_H +#include #include #include "../utils/hash_map/hash_map.h" @@ -20,7 +21,6 @@ size_t parse_var_name(char *str, char **res); * @param vars The hash map containing variables. * @return A new AST command with variables expanded, or NULL on error. */ -struct ast_command *expand(struct ast_command *command, - const struct hash_map *vars); +bool expand(struct ast_command *command, const struct hash_map *vars); #endif /* ! EXPANSION_H */ diff --git a/src/main.c b/src/main.c index b86a9a7..10644ac 100644 --- a/src/main.c +++ b/src/main.c @@ -85,7 +85,9 @@ int main(int argc, char **argv) while (command_ast != NULL && command_ast->type != AST_END) { // Execute AST - return_code = execution(command_ast); + return_code = execution(command_ast, vars); + + // set $? variable ast_free(&command_ast); diff --git a/src/utils/vars/vars.c b/src/utils/vars/vars.c index 8d762da..290566d 100644 --- a/src/utils/vars/vars.c +++ b/src/utils/vars/vars.c @@ -12,12 +12,7 @@ #define VARS_INITIAL_SIZE 16 -struct hash_map *vars_init(void) -{ - return hash_map_init(VARS_INITIAL_SIZE); -} - -void vars_default(struct hash_map *vars) +static void vars_default(struct hash_map *vars) { set_var_copy(vars, "?", "0"); pid_t pid = getpid(); @@ -26,6 +21,14 @@ void vars_default(struct hash_map *vars) set_var_copy(vars, "$", pid_str); } +struct hash_map *vars_init(void) +{ + struct hash_map *vars = hash_map_init(VARS_INITIAL_SIZE); + if (vars != NULL) + vars_default(vars); + return vars; +} + short short_random(void) { static bool seeded = false; diff --git a/src/utils/vars/vars.h b/src/utils/vars/vars.h index 85fb5ee..9e5fa4c 100644 --- a/src/utils/vars/vars.h +++ b/src/utils/vars/vars.h @@ -10,11 +10,6 @@ */ struct hash_map *vars_init(void); -/** - * Set default variables. - */ -void vars_default(struct hash_map *vars); - /** * Generate a random short integer (16 bits positive [0-32767]). */ From fbc36f35b2c5193261abce512a13e8f8cdad9549 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 14:05:49 +0100 Subject: [PATCH 5/6] fix(IOB): EOF in stdin works --- src/io_backend/io_backend.c | 6 +++++- src/parser/parsing_utils.c | 11 ++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/io_backend/io_backend.c b/src/io_backend/io_backend.c index 401daed..1ce256e 100644 --- a/src/io_backend/io_backend.c +++ b/src/io_backend/io_backend.c @@ -85,7 +85,11 @@ ssize_t stream_read(char **stream) if (nread == -1) { state = IOB_STATE_FINISHED; - return 0; + // MAGNIFICO + // malloc(1); + *stream_buf = EOF; + *stream = stream_buf; + return 1; } else if (nread < 0) state = IOB_STATE_ERROR; diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index 8511930..3be4f05 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -14,7 +14,6 @@ // === Static functions /* Returns true if c is a command terminator, false otherwise - */ static bool isterminator(struct token *token) { if (token == NULL) @@ -31,6 +30,8 @@ static bool isterminator(struct token *token) } } + */ + /* @brief: returns true if token is an end of list indicator. * @warning: not used */ @@ -77,8 +78,8 @@ struct ast *parse_list(struct lexer_context *ctx) while (token->type == TOKEN_SEMICOLON) { token = POP_TOKEN(); - if (!isterminator(token)) // Follow(list) - { + // if (!isterminator(token)) // Follow(list) + // { current_node = parse_and_or(ctx); if (current_node == NULL) { @@ -87,8 +88,8 @@ struct ast *parse_list(struct lexer_context *ctx) return NULL; } result_list = list_append(result_list, current_node); - token = PEEK_TOKEN(); - } + // } + token = PEEK_TOKEN(); } // result_list = list_append(result_list, current_node); From 6dd19a75addd85632f6fb1735624a2af05b2585e Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Thu, 22 Jan 2026 13:10:23 +0000 Subject: [PATCH 6/6] feat(execution): set $? var --- src/execution/execution.c | 1 + src/main.c | 10 +++++++--- src/utils/string_utils/string_utils.c | 9 +++++++++ src/utils/string_utils/string_utils.h | 9 +++++++++ src/utils/vars/vars.c | 12 ++++++++++-- src/utils/vars/vars.h | 6 ++++++ 6 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/execution/execution.c b/src/execution/execution.c index a98ff2f..d1d0e97 100644 --- a/src/execution/execution.c +++ b/src/execution/execution.c @@ -216,6 +216,7 @@ int execution(struct ast *ast, struct hash_map *vars) switch (ast->type) { + case AST_VOID: case AST_END: { return 0; } diff --git a/src/main.c b/src/main.c index 10644ac..a03cfa9 100644 --- a/src/main.c +++ b/src/main.c @@ -84,10 +84,14 @@ int main(int argc, char **argv) // Main parse-execute loop while (command_ast != NULL && command_ast->type != AST_END) { - // Execute AST - return_code = execution(command_ast, vars); + if (command_ast->type != AST_VOID) + { + // Execute AST + return_code = execution(command_ast, vars); - // set $? variable + // set $? variable + set_var_int(vars, "?", return_code); + } ast_free(&command_ast); diff --git a/src/utils/string_utils/string_utils.c b/src/utils/string_utils/string_utils.c index e5b7040..15ad87e 100644 --- a/src/utils/string_utils/string_utils.c +++ b/src/utils/string_utils/string_utils.c @@ -1,6 +1,7 @@ #include "string_utils.h" #include +#include #include #include @@ -42,3 +43,11 @@ char *insert_into(char *dest, const char *src, size_t pos, size_t len) return realloc(dest, new_len + 1); return dest; } + +void int_to_str(int value, char *buffer) +{ + if (buffer == NULL) + return; + + snprintf(buffer, 11, "%d", value); +} diff --git a/src/utils/string_utils/string_utils.h b/src/utils/string_utils/string_utils.h index 7f0e622..36f23ac 100644 --- a/src/utils/string_utils/string_utils.h +++ b/src/utils/string_utils/string_utils.h @@ -18,4 +18,13 @@ char *trim_blank_left(char *str); */ char *insert_into(char *dest, const char *src, size_t pos, size_t len); +/** + * Converts an integer to its string representation. + * @param value The integer value to convert. + * @param buffer A character array where the resulting string will be stored. + * The buffer must be at least 11 bytes long to accommodate the largest + * 32-bit integer and the null terminator. + */ +void int_to_str(int value, char *buffer); + #endif /* STRING_UTILS_H */ diff --git a/src/utils/vars/vars.c b/src/utils/vars/vars.c index 290566d..a69d349 100644 --- a/src/utils/vars/vars.c +++ b/src/utils/vars/vars.c @@ -9,6 +9,7 @@ #include #include "../hash_map/hash_map.h" +#include "../string_utils/string_utils.h" #define VARS_INITIAL_SIZE 16 @@ -16,8 +17,8 @@ static void vars_default(struct hash_map *vars) { set_var_copy(vars, "?", "0"); pid_t pid = getpid(); - char pid_str[20]; - snprintf(pid_str, sizeof(pid_str), "%d", pid); + char pid_str[11]; + int_to_str(pid, pid_str); set_var_copy(vars, "$", pid_str); } @@ -71,3 +72,10 @@ bool set_var_copy(struct hash_map *vars, const char *key, const char *value) free(value_copy); return res; } + +bool set_var_int(struct hash_map *vars, const char *key, int value) +{ + char value_str[11]; + int_to_str(value, value_str); + return set_var_copy(vars, key, value_str); +} diff --git a/src/utils/vars/vars.h b/src/utils/vars/vars.h index 9e5fa4c..19ffae1 100644 --- a/src/utils/vars/vars.h +++ b/src/utils/vars/vars.h @@ -40,4 +40,10 @@ bool set_var(struct hash_map *vars, const char *key, const char *value, */ bool set_var_copy(struct hash_map *vars, const char *key, const char *value); +/** + * Set the value of a variable to an integer. Behavior is similar to + * set_var_copy. + */ +bool set_var_int(struct hash_map *vars, const char *key, int value); + #endif /* ! VARS_H */