diff --git a/src/ast/ast.c b/src/ast/ast.c index 115e2d6..a6c62ba 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -107,8 +107,6 @@ ast_t *parse_condition(ast_ctx_t *ctx) if (l_node == NULL) return NULL; - if (ctx->act_tok.type & (T_WHILE)) - ctx->ast = parse_loop(ctx); else { switch (ctx->act_tok.type) { case T_PIPE: diff --git a/src/ast/loop.c b/src/ast/loop.c deleted file mode 100644 index b2a5b58..0000000 --- a/src/ast/loop.c +++ /dev/null @@ -1,138 +0,0 @@ -/* -** EPITECH PROJECT, 2025 -** 42sh -** File description: -** loop -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ast.h" -#include "builtins.h" -#include "common.h" -#include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" - -//TODO: need to know how to get the next arg -ast_t *parse_loop(ast_ctx_t *ctx) -{ - ast_t *node = create_node(ctx); - - if (node == NULL) - return NULL; - node->type = N_LOP; - node->tok = ctx->act_tok; - node->loop.cap = 2; - node->loop.buffers = NULL; - node->loop.sz = 0; - node->loop.condition = NULL; - return node; -} - -static -ast_t *buffers_realloc(ast_t *node) -{ - char **new_buffers = u_realloc(node->loop.buffers, sizeof - *node->loop.buffers * node->loop.sz, sizeof - *node->loop.buffers * (node->loop.cap << 1)); - - if (new_buffers == NULL) - return NULL; - node->loop.buffers = new_buffers; - node->loop.cap <<= 1; - return node; -} - -static -ast_t *get_first_cmd(ast_t *node, char prompt[], size_t *bf_len) -{ - printf("%s", prompt); - node->loop.buffers[node->loop.sz] = NULL; - getline(&(node->loop.buffers[node->loop.sz]), bf_len, stdin); - *bf_len = u_strlen(node->loop.buffers[node->loop.sz]); - node->loop.buffers[node->loop.sz][*bf_len - 1] = '\0'; - node->loop.sz += 1; - return node; -} - -static -ast_t *increase_buffers(ast_t *node, size_t *buffer_len) -{ - node->loop.buffers[node->loop.sz] = NULL; - getline(&(node->loop.buffers[node->loop.sz]), buffer_len, stdin); - *buffer_len = u_strlen(node->loop.buffers[node->loop.sz]); - node->loop.buffers[node->loop.sz][*buffer_len - 1] = '\0'; - node->loop.sz++; - return node; -} - -static -ast_t *get_usr_loop_cmd(ast_t *node) -{ - char prompt[] = "while? "; - size_t buffer_len; - - node->loop.buffers = malloc(sizeof(char *) * node->loop.cap); - node = get_first_cmd(node, prompt, &buffer_len); - while (strcmp("end", node->loop.buffers[node->loop.sz - 1])){ - printf("%s", prompt); - if (node->loop.sz >= node->loop.cap) - node = buffers_realloc(node); - if (node == NULL) - return NULL; - increase_buffers(node, &buffer_len); - } - free(node->loop.buffers[node->loop.sz]); - node->loop.sz--; - node->loop.buffers[node->loop.sz] = NULL; - return node; -} - -void exit_child(int sig __attribute__((unused))) -{ - _exit(sig); -} - -//TODO: need to change the while true by a check_condition -static -void launch_loop(ef_t *ef, ast_t *node) -{ - int status; - - signal(SIGINT, exit_child); - signal(EOF, exit_child); - node = get_usr_loop_cmd(node); - if (node == NULL) - exit(84); - while (true) - for (size_t i = 0; i < node->loop.sz; i++) - status = visitor(node->loop.buffers[i], ef->exec_ctx); - free_array(node->loop.buffers); - exit(status); -} - -int visit_loop(ef_t *ef, ast_t *node) -{ - int status; - pid_t pid = fork(); - - if (pid == 0) - launch_loop(ef, node); - else - wait(&status); - if (WIFEXITED(status)) - ef->history->last_exit_code = - ef->history->last_exit_code ?: WEXITSTATUS(status); - return status; -} diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index de25f5d..ee99479 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -28,7 +28,6 @@ const tokens_list_t TOKENS_LIST[] = { { T_REDIRECT, ">", 1, "T_REDIRECT" }, { T_HEREDOC, "<<", 2, "T_HEREDOC" }, { T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" }, - { T_WHILE, "while", 5, "T_WHILE"}, { T_IF, "if", 2, "T_IF"}, { T_THEN, "then", 4, "T_THEN"}, { T_ELSE, "else", 4, "T_ELSE"}, diff --git a/src/builtins.h b/src/builtins.h index a2ee2cd..1d1894f 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -31,8 +31,10 @@ int builtins_display_alias(alias_t *alias); int builtins_repeat(ef_t *ef, char **args); int builtins_yes(ef_t *ef, char **args); int builtins_foreach(ef_t *ef, char **args); +int builtins_while(ef_t *ef, char **args); int builtins_set(ef_t *ef, char **args); int builtins_unset(ef_t *ef, char **args); int builtins_where(ef_t *ef, char **args); int builtins_which(ef_t *ef, char **args); +int builtins_break(ef_t *ef, char **args); #endif /* BUILTIND_H */ diff --git a/src/builtins/break.c b/src/builtins/break.c new file mode 100644 index 0000000..a105c68 --- /dev/null +++ b/src/builtins/break.c @@ -0,0 +1,33 @@ +/* +** EPITECH PROJECT, 2025 +** 42sh +** File description: +** break +*/ +#include +#include +#include + +#include "ast.h" +#include "builtins.h" +#include "common.h" +#include "exec.h" +#include "u_str.h" + +bool checking_error(ef_t *ef, char **args) +{ + if (args[1]) + return (WRITE_CONST(STDERR_FILENO, "break: Too many arguments.\n"), + RETURN_FAILURE); + if (!ef->exec_ctx->local->in_a_loop) + return (WRITE_CONST(STDERR_FILENO, "break: Not in while/foreach.\n"), + RETURN_FAILURE); + return RETURN_SUCCESS; +} + +int builtins_break(ef_t *ef, char **args) +{ + if (ef->exec_ctx->local->in_a_loop) + exit(checking_error(ef, args)); + return checking_error(ef, args); +} diff --git a/src/builtins/foreach.c b/src/builtins/foreach.c deleted file mode 100644 index f24dff3..0000000 --- a/src/builtins/foreach.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -** EPITECH PROJECT, 2025 -** 42sh -** File description: -** foreach -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ast.h" -#include "builtins.h" -#include "common.h" -#include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" -#include "loop.h" -#include "local.h" - -static -bool checking_error(ef_t *ef, char **args) -{ - if (my_array_len(args) < 3) - return (WRITE_CONST(STDERR_FILENO, "foreach: Too few arguments.\n"), - true); - if (check_local_var(args[1], args[0])) - return true; - return false; -} - -static -usr_cmd_t *buffers_realloc(usr_cmd_t *usr) -{ - char **new_buffers = u_realloc(usr->local_var, sizeof - *usr->local_var * usr->sz, sizeof - *usr->local_var * (usr->cap << 1)); - - if (new_buffers == NULL) - return NULL; - usr->local_var = new_buffers; - usr->cap <<= 1; - return usr; -} - -static -usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) -{ - printf("%s", prompt); - usr->local_var[usr->sz] = NULL; - getline(&(usr->local_var[usr->sz]), bf_len, stdin); - *bf_len = u_strlen(usr->local_var[usr->sz]); - usr->local_var[usr->sz][*bf_len - 1] = '\0'; - usr->sz += 1; - return usr; -} - -static -usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) -{ - usr->local_var[usr->sz] = NULL; - getline(&(usr->local_var[usr->sz]), buffer_len, stdin); - *buffer_len = u_strlen(usr->local_var[usr->sz]); - usr->local_var[usr->sz][*buffer_len - 1] = '\0'; - usr->sz++; - return usr; -} - -static -usr_cmd_t *handle_end(usr_cmd_t *us, char prompt[]) -{ - us->sz--; - if (!us->local_var[us->sz] || - strcmp("end", us->local_var[us->sz])){ - printf("%s: end not found.\n", prompt); - free_array(us->local_var); - us->local_var = NULL; - exit(RETURN_FAILURE); - return NULL; - } - free(us->local_var[us->sz]); - us->local_var[us->sz] = NULL; - return us; -} - -static -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd) -{ - char prompt[] = "foreach? "; - size_t buffer_len; - - usr_cmd->local_var = malloc(sizeof(char *) * usr_cmd->cap); - if (usr_cmd->local_var == NULL) - return NULL; - usr_cmd = get_first_cmd(usr_cmd, prompt, &buffer_len); - while (strcmp("end", usr_cmd->local_var[usr_cmd->sz - 1])){ - printf("foreach? "); - if (usr_cmd->sz >= usr_cmd->cap) - usr_cmd = buffers_realloc(usr_cmd); - if (usr_cmd == NULL) - return NULL; - increase_buffers(usr_cmd, &buffer_len); - } - usr_cmd = handle_end(usr_cmd, prompt); - return usr_cmd; -} - -static -int do_a_lap(ef_t *ef, char **args) -{ - int status = 0; - - for (int i = 0; args[i]; i++) - status = visitor(args[i], ef->exec_ctx); - return status; -} - -static -int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) -{ - int status = 0; - char **save_cmds = arraydup(usr_cmds->local_var); - - if (save_cmds == NULL) - exit(84); - for (int i = 2; args[i]; i++){ - if (!set_local(ef->exec_ctx->local, args[1], args[i])) - exit(84); - status = do_a_lap(ef, usr_cmds->local_var); - free_array(usr_cmds->local_var); - usr_cmds->local_var = arraydup(save_cmds); - } - free_array(save_cmds); - return status; -} - -static -void launch_loop(ef_t *ef, char **args) -{ - int status = RETURN_FAILURE; - usr_cmd_t *usr_cmds = malloc(sizeof(usr_cmd_t)); - - if (usr_cmds == NULL) - exit(84); - usr_cmds->cap = 2; - usr_cmds->sz = 0; - signal(SIGINT, exit_child); - signal(EOF, exit_child); - usr_cmds = get_usr_loop_cmd(usr_cmds); - if (usr_cmds == NULL) - exit(84); - status = foreach_loop(ef, args, usr_cmds); - free_array(usr_cmds->local_var); - free(usr_cmds); - exit(status); -} - -int builtins_foreach(ef_t *ef, char **args) -{ - int status = 0; - pid_t pid; - - if (checking_error(ef, args)) - return RETURN_FAILURE; - pid = fork(); - if (pid == 0) - launch_loop(ef, args); - else - wait(&status); - if (WIFEXITED(status)) - ef->history->last_exit_code = - ef->history->last_exit_code ?: WEXITSTATUS(status); - return status; -} diff --git a/src/builtins/get_loop_cmd.c b/src/builtins/get_loop_cmd.c new file mode 100644 index 0000000..83b4f32 --- /dev/null +++ b/src/builtins/get_loop_cmd.c @@ -0,0 +1,104 @@ +/* +** EPITECH PROJECT, 2025 +** 42sh +** File description: +** get_loop_cmd +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ast.h" +#include "builtins.h" +#include "common.h" +#include "exec.h" +#include "redirects.h" +#include "u_str.h" +#include "u_mem.h" +#include "loop.h" +#include "local.h" + +static +usr_cmd_t *buffers_realloc(usr_cmd_t *usr) +{ + char **new_buffers = u_realloc(usr->cmds, sizeof + *usr->cmds * usr->sz, sizeof + *usr->cmds * (usr->cap << 1)); + + if (new_buffers == NULL) + return NULL; + usr->cmds = new_buffers; + usr->cap <<= 1; + return usr; +} + +static +usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) +{ + usr->cmds[usr->sz] = NULL; + getline(&(usr->cmds[usr->sz]), buffer_len, stdin); + *buffer_len = u_strlen(usr->cmds[usr->sz]); + usr->cmds[usr->sz][*buffer_len - 1] = '\0'; + usr->sz++; + return usr; +} + +static +usr_cmd_t *handle_end(usr_cmd_t *us, char prompt[]) +{ + us->sz--; + if (!us->cmds[us->sz] || strcmp("end", us->cmds[us->sz])){ + printf("%s: end not found.\n", prompt); + free_array(us->cmds); + us->cmds = NULL; + exit(RETURN_FAILURE); + return NULL; + } + free(us->cmds[us->sz]); + us->cmds[us->sz] = NULL; + return us; +} + +static +usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) +{ + if (isatty(STDIN_FILENO)) + printf("%s? ", prompt); + usr->cmds[usr->sz] = NULL; + getline(&(usr->cmds[usr->sz]), bf_len, stdin); + *bf_len = u_strlen(usr->cmds[usr->sz]); + usr->cmds[usr->sz][*bf_len - 1] = '\0'; + usr->sz += 1; + return usr; +} + +usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]) +{ + size_t buffer_len; + + if (usr_cmd == NULL) + return NULL; + usr_cmd->cmds = malloc(sizeof(char *) * usr_cmd->cap); + if (usr_cmd->cmds == NULL) + return NULL; + usr_cmd = get_first_cmd(usr_cmd, prompt, &buffer_len); + while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1])){ + if (isatty(STDIN_FILENO)) + printf("%s? ", prompt); + if (usr_cmd->sz >= usr_cmd->cap) + usr_cmd = buffers_realloc(usr_cmd); + if (usr_cmd == NULL) + return NULL; + increase_buffers(usr_cmd, &buffer_len); + } + usr_cmd = handle_end(usr_cmd, prompt); + return usr_cmd; +} diff --git a/src/builtins/loop.c b/src/builtins/loop.c new file mode 100644 index 0000000..41849b5 --- /dev/null +++ b/src/builtins/loop.c @@ -0,0 +1,166 @@ +/* +** EPITECH PROJECT, 2025 +** 42sh +** File description: +** foreach +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ast.h" +#include "builtins.h" +#include "common.h" +#include "exec.h" +#include "redirects.h" +#include "u_str.h" +#include "u_mem.h" +#include "loop.h" +#include "local.h" + +void exit_child(int sig __attribute__((unused))) +{ + _exit(sig); +} + +static +bool checking_for_error(ef_t *ef, char **args) +{ + if (my_array_len(args) < 3) + return (WRITE_CONST(STDERR_FILENO, "foreach: Too few arguments.\n"), + true); + if (check_local_var(args[1], args[0])) + return true; + return false; +} + +static +bool checking_while_error(ef_t *ef, char **args) +{ + if (my_array_len(args) < 2) + return (WRITE_CONST(STDERR_FILENO, "while: Too few arguments.\n"), + true); + if (my_array_len(args) > 2) + return (WRITE_CONST(STDERR_FILENO, "while: Expression Syntax.\n"), + true); + return false; +} + +static +int do_a_lap(ef_t *ef, char **args) +{ + int status = 0; + + for (int i = 0; args[i]; i++) + status = visitor(args[i], ef->exec_ctx); + return status; +} + +static +int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) +{ + int status = 0; + char **save_cmds = arraydup(usr_cmds->cmds); + + if (save_cmds == NULL) + exit(84); + for (int i = 2; args[i]; i++){ + if (!set_local(ef->exec_ctx->local, args[1], args[i])) + exit(84); + status = do_a_lap(ef, usr_cmds->cmds); + free_array(usr_cmds->cmds); + usr_cmds->cmds = arraydup(save_cmds); + } + free_array(save_cmds); + return status; +} + +static +int while_loop(ef_t *ef, usr_cmd_t *usr_cmds) +{ + int status = 0; + char **save_cmds = arraydup(usr_cmds->cmds); + + if (save_cmds == NULL) + exit(84); + while (true){ + status = do_a_lap(ef, usr_cmds->cmds); + free_array(usr_cmds->cmds); + usr_cmds->cmds = arraydup(save_cmds); + } + free_array(save_cmds); + return status; +} + +static +int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char prompt[]) +{ + if (strcmp(prompt, "foreach") == 0) + return foreach_loop(ef, args, usr_cmd); + return while_loop(ef, usr_cmd); +} + +static +void launch_loop(ef_t *ef, char **args, char prompt[]) +{ + int status = RETURN_FAILURE; + usr_cmd_t *usr_cmds = malloc(sizeof(usr_cmd_t)); + + ef->exec_ctx->local->in_a_loop = true; + if (usr_cmds == NULL) + exit(84); + usr_cmds->cap = 2; + usr_cmds->sz = 0; + signal(SIGINT, exit_child); + signal(EOF, exit_child); + usr_cmds = get_usr_loop_cmd(usr_cmds, prompt); + if (usr_cmds == NULL) + exit(84); + status = choose_loop(ef, args, usr_cmds, prompt); + free_array(usr_cmds->cmds); + free(usr_cmds); + exit(status); +} + +int builtins_foreach(ef_t *ef, char **args) +{ + int status = 0; + pid_t pid; + + if (checking_for_error(ef, args)) + return RETURN_FAILURE; + pid = fork(); + if (pid == 0) + launch_loop(ef, args, "foreach"); + else + wait(&status); + if (WIFEXITED(status)) + ef->history->last_exit_code = + ef->history->last_exit_code ?: WEXITSTATUS(status); + return status; +} + +int builtins_while(ef_t *ef, char **args) +{ + int status = 0; + pid_t pid; + + if (checking_while_error(ef, args)) + return RETURN_FAILURE; + pid = fork(); + if (pid == 0) + launch_loop(ef, args, "while"); + else + wait(&status); + if (WIFEXITED(status)) + ef->history->last_exit_code = + ef->history->last_exit_code ?: WEXITSTATUS(status); + return status; +} diff --git a/src/exec.c b/src/exec.c index 0c07df2..b6174e5 100644 --- a/src/exec.c +++ b/src/exec.c @@ -40,10 +40,12 @@ const builtins_funcs_t BUILTINS[] = { { "alias", &builtins_alias}, { "yes", &builtins_yes }, { "foreach", &builtins_foreach }, + { "while", &builtins_while }, { "set", &builtins_set }, { "unset", &builtins_unset }, { "where", &builtins_where }, - { "which", &builtins_which } + { "which", &builtins_which }, + { "break", &builtins_break } }; const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS; diff --git a/src/local.h b/src/local.h index ef8f6b2..d68d237 100644 --- a/src/local.h +++ b/src/local.h @@ -14,6 +14,7 @@ typedef struct { size_t sz; size_t cap; char **local_var; + bool in_a_loop; } local_t; bool set_local(local_t *local, char *var, char *value); diff --git a/src/loop.h b/src/loop.h index 997b3da..b8f8544 100644 --- a/src/loop.h +++ b/src/loop.h @@ -13,6 +13,8 @@ typedef struct { size_t sz; size_t cap; - char **local_var; + char **cmds; } usr_cmd_t; + +usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]); #endif /* LOOP_H */ diff --git a/src/visitor.c b/src/visitor.c index d1887e4..d9f492e 100644 --- a/src/visitor.c +++ b/src/visitor.c @@ -146,8 +146,6 @@ int visit_expression(ef_t *ef, ast_t *node) { int result = RETURN_FAILURE; - if (node->type == N_LOP) - result = visit_loop(ef, node); if (node->tok.type == T_SEMICOLON) result = visit_semi(ef, node); if (node->tok.type & (T_IF | T_AND | T_OR))