Merge branch 'dev' of gitlab.cri.epita.fr:guillem.george/42sh into dev

This commit is contained in:
Jean Herail 2026-01-22 16:49:12 +01:00
commit f2e44d93f4
14 changed files with 89 additions and 46 deletions

View file

@ -18,8 +18,8 @@ bin_PROGRAMS = 42sh
parser/libparser.a \ parser/libparser.a \
lexer/liblexer.a \ lexer/liblexer.a \
io_backend/libio_backend.a \ io_backend/libio_backend.a \
expansion/libexpansion.a \
execution/libexecution.a \ execution/libexecution.a \
expansion/libexpansion.a \
utils/libutils.a utils/libutils.a
# ================ TESTS ================ # ================ TESTS ================

View file

@ -9,7 +9,9 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include "../expansion/expansion.h"
#include "../utils/ast/ast.h" #include "../utils/ast/ast.h"
#include "../utils/hash_map/hash_map.h"
// --- Helpers --- // --- Helpers ---
@ -205,7 +207,7 @@ static int exec_command(struct ast_command *command)
* @param ast The AST to execute * @param ast The AST to execute
* @return int The exit status of the last executed command. * @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) if (!ast)
{ {
@ -214,23 +216,26 @@ int execution(struct ast *ast)
switch (ast->type) switch (ast->type)
{ {
case AST_VOID:
case AST_END: { case AST_END: {
return 0; return 0;
} }
case AST_CMD: { case AST_CMD: {
struct ast_command *command = ast_get_command(ast); struct ast_command *command = ast_get_command(ast);
if (!expand(command, vars))
fprintf(stderr, "Error: Variable expansion failed\n");
return exec_command(command); return exec_command(command);
} }
case AST_IF: { case AST_IF: {
struct ast_if *if_node = ast_get_if(ast); 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 if (cond == 0) // True
{ {
return execution(if_node->then_clause); return execution(if_node->then_clause, vars);
} }
else // False else // False
{ {
return execution(if_node->else_clause); return execution(if_node->else_clause, vars);
} }
} }
case AST_LIST: { case AST_LIST: {
@ -240,25 +245,25 @@ int execution(struct ast *ast)
while (cur) while (cur)
{ {
struct ast *child = (struct ast *)cur->data; struct ast *child = (struct ast *)cur->data;
ret = execution(child); ret = execution(child, vars);
cur = cur->next; cur = cur->next;
} }
return ret; return ret;
} }
case AST_AND_OR: { case AST_AND_OR: {
struct ast_and_or *ao_node = ast_get_and_or(ast); 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 (ao_node->type == AST_AND_OR_TYPE_AND)
{ {
if (left_ret == 0) if (left_ret == 0)
return execution(ao_node->right); return execution(ao_node->right, vars);
return left_ret; return left_ret;
} }
else // OR else // OR
{ {
if (left_ret != 0) if (left_ret != 0)
return execution(ao_node->right); return execution(ao_node->right, vars);
return left_ret; return left_ret;
} }
} }
@ -335,7 +340,7 @@ int execution(struct ast *ast)
close(new_fd); close(new_fd);
} }
int ret = execution(redir->child); int ret = execution(redir->child, vars);
if (saved_fd != -1) if (saved_fd != -1)
{ {

View file

@ -3,6 +3,7 @@
#include "../utils/ast/ast.h" #include "../utils/ast/ast.h"
#include "../utils/lists/lists.h" #include "../utils/lists/lists.h"
#include "../utils/hash_map/hash_map.h"
/** /**
* @brief Execute the AST * @brief Execute the AST
@ -10,6 +11,6 @@
* @param ast Pointer to the AST structure * @param ast Pointer to the AST structure
* @return int Execution status code of the last command * @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 */ #endif /* ! EXECUTION_H */

View file

@ -115,11 +115,10 @@ static bool expand_var(char **str, size_t pos, const struct hash_map *vars)
return false; return false;
} }
struct ast_command *expand(struct ast_command *command, bool expand(struct ast_command *command, const struct hash_map *vars)
const struct hash_map *vars)
{ {
if (command == NULL) if (command == NULL)
return NULL; return false;
char *str; char *str;
size_t len; size_t len;
@ -150,7 +149,7 @@ struct ast_command *expand(struct ast_command *command,
// variable expansion // variable expansion
bool r = expand_var(&str, i, vars); bool r = expand_var(&str, i, vars);
if (r == false || str == NULL) if (r == false || str == NULL)
return NULL; return false;
i--; // -1 because loop will increment i i--; // -1 because loop will increment i
} }
@ -160,7 +159,7 @@ struct ast_command *expand(struct ast_command *command,
{ {
// error: quote not closed // error: quote not closed
fprintf(stderr, "Error: quote not closed in string: %s\n", str); fprintf(stderr, "Error: quote not closed in string: %s\n", str);
return NULL; return false;
} }
if (len != strlen(str)) if (len != strlen(str))
@ -169,12 +168,12 @@ struct ast_command *expand(struct ast_command *command,
if (new_str == NULL) if (new_str == NULL)
{ {
// error: realloc fail // error: realloc fail
return NULL; return false;
} }
l->data = new_str; l->data = new_str;
} }
l = l->next; l = l->next;
} }
return command; return true;
} }

View file

@ -1,6 +1,7 @@
#ifndef EXPANSION_H #ifndef EXPANSION_H
#define EXPANSION_H #define EXPANSION_H
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include "../utils/hash_map/hash_map.h" #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. * @param vars The hash map containing variables.
* @return A new AST command with variables expanded, or NULL on error. * @return A new AST command with variables expanded, or NULL on error.
*/ */
struct ast_command *expand(struct ast_command *command, bool expand(struct ast_command *command, const struct hash_map *vars);
const struct hash_map *vars);
#endif /* ! EXPANSION_H */ #endif /* ! EXPANSION_H */

View file

@ -85,7 +85,11 @@ ssize_t stream_read(char **stream)
if (nread == -1) if (nread == -1)
{ {
state = IOB_STATE_FINISHED; state = IOB_STATE_FINISHED;
return 0; // MAGNIFICO
// malloc(1);
*stream_buf = EOF;
*stream = stream_buf;
return 1;
} }
else if (nread < 0) else if (nread < 0)
state = IOB_STATE_ERROR; state = IOB_STATE_ERROR;
@ -99,7 +103,7 @@ ssize_t stream_read(char **stream)
*stream = context.args; *stream = context.args;
size_t len = strlen(context.args); size_t len = strlen(context.args);
context.args[len] = EOF; context.args[len] = EOF;
return len; return len + 1;
} }
else else
{ {

View file

@ -19,7 +19,7 @@ static bool is_special_char(char c)
if (c == EOF) if (c == EOF)
return true; return true;
char special_chars[] = "\n'\"`;#|&\\$(){}<>*"; char special_chars[] = "\n'\"`;#|&\\(){}<>*";
return strchr(special_chars, c) != NULL; return strchr(special_chars, c) != NULL;
} }

View file

@ -45,9 +45,6 @@ static void set_token_spechar(struct token *tok, char *begin, ssize_t size)
case '\\': case '\\':
tok->type = TOKEN_BACKSLASH; tok->type = TOKEN_BACKSLASH;
break; break;
case '$':
tok->type = TOKEN_DOLLAR;
break;
case '(': case '(':
tok->type = TOKEN_LEFT_PAREN; tok->type = TOKEN_LEFT_PAREN;
break; break;

View file

@ -83,9 +83,15 @@ int main(int argc, char **argv)
// Main parse-execute loop // Main parse-execute loop
while (command_ast != NULL && command_ast->type != AST_END) while (command_ast != NULL && command_ast->type != AST_END)
{
if (command_ast->type != AST_VOID)
{ {
// Execute AST // Execute AST
return_code = execution(command_ast); return_code = execution(command_ast, vars);
// set $? variable
set_var_int(vars, "?", return_code);
}
ast_free(&command_ast); ast_free(&command_ast);

View file

@ -14,7 +14,6 @@
// === Static functions // === Static functions
/* Returns true if c is a command terminator, false otherwise /* Returns true if c is a command terminator, false otherwise
*/
static bool isterminator(struct token *token) static bool isterminator(struct token *token)
{ {
if (token == NULL) if (token == NULL)
@ -31,6 +30,8 @@ static bool isterminator(struct token *token)
} }
} }
*/
/* @brief: returns true if token is an end of list indicator. /* @brief: returns true if token is an end of list indicator.
* @warning: not used * @warning: not used
*/ */
@ -77,8 +78,8 @@ struct ast *parse_list(struct lexer_context *ctx)
while (token->type == TOKEN_SEMICOLON) while (token->type == TOKEN_SEMICOLON)
{ {
token = POP_TOKEN(); token = POP_TOKEN();
if (!isterminator(token)) // Follow(list) // if (!isterminator(token)) // Follow(list)
{ // {
current_node = parse_and_or(ctx); current_node = parse_and_or(ctx);
if (current_node == NULL) if (current_node == NULL)
{ {
@ -87,9 +88,9 @@ struct ast *parse_list(struct lexer_context *ctx)
return NULL; return NULL;
} }
result_list = list_append(result_list, current_node); result_list = list_append(result_list, current_node);
// }
token = PEEK_TOKEN(); token = PEEK_TOKEN();
} }
}
// result_list = list_append(result_list, current_node); // result_list = list_append(result_list, current_node);
return ast_create_list(result_list); return ast_create_list(result_list);

View file

@ -1,6 +1,7 @@
#include "string_utils.h" #include "string_utils.h"
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -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 realloc(dest, new_len + 1);
return dest; return dest;
} }
void int_to_str(int value, char *buffer)
{
if (buffer == NULL)
return;
snprintf(buffer, 11, "%d", value);
}

View file

@ -18,4 +18,13 @@ char *trim_blank_left(char *str);
*/ */
char *insert_into(char *dest, const char *src, size_t pos, size_t len); 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 */ #endif /* STRING_UTILS_H */

View file

@ -9,23 +9,27 @@
#include <unistd.h> #include <unistd.h>
#include "../hash_map/hash_map.h" #include "../hash_map/hash_map.h"
#include "../string_utils/string_utils.h"
#define VARS_INITIAL_SIZE 16 #define VARS_INITIAL_SIZE 16
struct hash_map *vars_init(void) static void vars_default(struct hash_map *vars)
{
return hash_map_init(VARS_INITIAL_SIZE);
}
void vars_default(struct hash_map *vars)
{ {
set_var_copy(vars, "?", "0"); set_var_copy(vars, "?", "0");
pid_t pid = getpid(); pid_t pid = getpid();
char pid_str[20]; char pid_str[11];
snprintf(pid_str, sizeof(pid_str), "%d", pid); int_to_str(pid, pid_str);
set_var_copy(vars, "$", pid_str); 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) short short_random(void)
{ {
static bool seeded = false; static bool seeded = false;
@ -68,3 +72,10 @@ bool set_var_copy(struct hash_map *vars, const char *key, const char *value)
free(value_copy); free(value_copy);
return res; 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);
}

View file

@ -10,11 +10,6 @@
*/ */
struct hash_map *vars_init(void); 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]). * Generate a random short integer (16 bits positive [0-32767]).
*/ */
@ -45,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); 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 */ #endif /* ! VARS_H */