Merge branch 'dev' of gitlab.cri.epita.fr:guillem.george/42sh into dev
This commit is contained in:
commit
f2e44d93f4
14 changed files with 89 additions and 46 deletions
|
|
@ -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 ================
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
@ -214,23 +216,26 @@ int execution(struct ast *ast)
|
|||
|
||||
switch (ast->type)
|
||||
{
|
||||
case AST_VOID:
|
||||
case AST_END: {
|
||||
return 0;
|
||||
}
|
||||
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 +245,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 +340,7 @@ int execution(struct ast *ast)
|
|||
close(new_fd);
|
||||
}
|
||||
|
||||
int ret = execution(redir->child);
|
||||
int ret = execution(redir->child, vars);
|
||||
|
||||
if (saved_fd != -1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef EXPANSION_H
|
||||
#define EXPANSION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.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.
|
||||
* @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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -99,7 +103,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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
10
src/main.c
10
src/main.c
|
|
@ -84,8 +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);
|
||||
if (command_ast->type != AST_VOID)
|
||||
{
|
||||
// Execute AST
|
||||
return_code = execution(command_ast, vars);
|
||||
|
||||
// set $? variable
|
||||
set_var_int(vars, "?", return_code);
|
||||
}
|
||||
|
||||
ast_free(&command_ast);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "string_utils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.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 dest;
|
||||
}
|
||||
|
||||
void int_to_str(int value, char *buffer)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
|
||||
snprintf(buffer, 11, "%d", value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -9,23 +9,27 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "../hash_map/hash_map.h"
|
||||
#include "../string_utils/string_utils.h"
|
||||
|
||||
#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();
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -68,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]).
|
||||
*/
|
||||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue