[ADD] while passed as builtins and break builtins

This commit is contained in:
tekClovis
2025-04-28 14:00:28 +02:00
parent 24f4215cab
commit f47ff9e53f
12 changed files with 312 additions and 326 deletions

View File

@@ -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:

View File

@@ -1,138 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** loop
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#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;
}

View File

@@ -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"},

View File

@@ -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 */

33
src/builtins/break.c Normal file
View File

@@ -0,0 +1,33 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** break
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#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);
}

View File

@@ -1,181 +0,0 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** foreach
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#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;
}

104
src/builtins/get_loop_cmd.c Normal file
View File

@@ -0,0 +1,104 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** get_loop_cmd
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#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;
}

166
src/builtins/loop.c Normal file
View File

@@ -0,0 +1,166 @@
/*
** EPITECH PROJECT, 2025
** 42sh
** File description:
** foreach
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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))