feat: exit builtin
This commit is contained in:
parent
17f8b918c8
commit
3b62c56756
3 changed files with 81 additions and 25 deletions
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "../expansion/expansion.h"
|
#include "../expansion/expansion.h"
|
||||||
#include "../utils/hash_map/hash_map.h"
|
#include "../utils/hash_map/hash_map.h"
|
||||||
|
#include "../utils/vars/vars.h"
|
||||||
|
|
||||||
// Refactored: delegates to helpers in execution_helpers.c
|
// Refactored: delegates to helpers in execution_helpers.c
|
||||||
#include "execution_helpers.h"
|
#include "execution_helpers.h"
|
||||||
|
|
@ -18,27 +19,52 @@ int execution(struct ast *ast, struct hash_map *vars)
|
||||||
if (!ast)
|
if (!ast)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
int res;
|
||||||
switch (ast->type)
|
switch (ast->type)
|
||||||
{
|
{
|
||||||
case AST_VOID:
|
case AST_VOID:
|
||||||
case AST_END:
|
case AST_END:
|
||||||
return 0;
|
res = 0;
|
||||||
|
break;
|
||||||
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))
|
if (!expand(command, vars))
|
||||||
fprintf(stderr, "Error: Variable expansion failed\n");
|
fprintf(stderr, "Error: Variable expansion failed\n");
|
||||||
|
|
||||||
return exec_ast_command(command, vars);
|
res = exec_ast_command(command, vars);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case AST_IF:
|
case AST_IF:
|
||||||
return exec_ast_if(ast_get_if(ast), vars);
|
res = exec_ast_if(ast_get_if(ast), vars);
|
||||||
|
break;
|
||||||
case AST_LIST:
|
case AST_LIST:
|
||||||
return exec_ast_list(ast_get_list(ast), vars);
|
res = exec_ast_list(ast_get_list(ast), vars);
|
||||||
|
break;
|
||||||
case AST_AND_OR:
|
case AST_AND_OR:
|
||||||
return exec_ast_and_or(ast_get_and_or(ast), vars);
|
res = exec_ast_and_or(ast_get_and_or(ast), vars);
|
||||||
|
break;
|
||||||
case AST_LOOP:
|
case AST_LOOP:
|
||||||
return exec_ast_loop(ast_get_loop(ast), vars);
|
res = exec_ast_loop(ast_get_loop(ast), vars);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return 127;
|
res = 127;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == EXEC_SIGNAL_EXIT)
|
||||||
|
{
|
||||||
|
char *exit_val_str = get_var(vars, "EXIT_VALUE");
|
||||||
|
if (exit_val_str == NULL)
|
||||||
|
{
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"Internal error: could not retrieve return value from exit\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return atoi(exit_val_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include "../utils/vars/vars.h"
|
#include "../utils/vars/vars.h"
|
||||||
#include "execution.h"
|
#include "execution.h"
|
||||||
|
|
||||||
|
// === Static functions
|
||||||
|
|
||||||
static int open_redir_file(const struct ast_redir *redir, int *flags, int *mode)
|
static int open_redir_file(const struct ast_redir *redir, int *flags, int *mode)
|
||||||
{
|
{
|
||||||
*mode = 0644;
|
*mode = 0644;
|
||||||
|
|
@ -121,6 +123,30 @@ static char **list_to_argv(struct list *command_list)
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief parses string and returns the represented (unsigned) number
|
||||||
|
* @return the number contained by the string or -1 if number is invalid
|
||||||
|
*/
|
||||||
|
static int atou(char *str)
|
||||||
|
{
|
||||||
|
if (str == NULL || *str == '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
while (str[i] != '\0')
|
||||||
|
{
|
||||||
|
if (str[i] < '0' || str[i] > '9')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
result *= 10;
|
||||||
|
result += str[i] - '0';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int try_builtin(char **argv, struct hash_map *vars);
|
static int try_builtin(char **argv, struct hash_map *vars);
|
||||||
|
|
||||||
static int builtin_break(char **argv);
|
static int builtin_break(char **argv);
|
||||||
|
|
@ -144,6 +170,8 @@ static int exec_assignment(struct list *assignment_list, struct hash_map *vars)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Functions
|
||||||
|
|
||||||
int exec_ast_command(struct ast_command *command, struct hash_map *vars)
|
int exec_ast_command(struct ast_command *command, struct hash_map *vars)
|
||||||
{
|
{
|
||||||
exec_assignment(command->assignments, vars);
|
exec_assignment(command->assignments, vars);
|
||||||
|
|
@ -205,20 +233,17 @@ int exec_ast_if(struct ast_if *if_node, struct hash_map *vars)
|
||||||
if (if_node == NULL)
|
if (if_node == NULL)
|
||||||
return 2;
|
return 2;
|
||||||
int cond = execution(if_node->condition, vars);
|
int cond = execution(if_node->condition, vars);
|
||||||
if (cond == EXEC_SIGNAL_BREAK || cond == EXEC_SIGNAL_CONTINUE)
|
if (cond == EXEC_SIGNAL_BREAK || cond == EXEC_SIGNAL_CONTINUE
|
||||||
|
|| cond == EXEC_SIGNAL_EXIT)
|
||||||
return cond;
|
return cond;
|
||||||
if (cond == 0)
|
if (cond == 0)
|
||||||
{
|
{
|
||||||
int r = execution(if_node->then_clause, vars);
|
int r = execution(if_node->then_clause, vars);
|
||||||
if (r == EXEC_SIGNAL_BREAK || r == EXEC_SIGNAL_CONTINUE)
|
|
||||||
return r;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int r = execution(if_node->else_clause, vars);
|
int r = execution(if_node->else_clause, vars);
|
||||||
if (r == EXEC_SIGNAL_BREAK || r == EXEC_SIGNAL_CONTINUE)
|
|
||||||
return r;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +259,8 @@ int exec_ast_list(struct ast_list *list_node, struct hash_map *vars)
|
||||||
{
|
{
|
||||||
int child_ret = execution(child, vars);
|
int child_ret = execution(child, vars);
|
||||||
if (child_ret == EXEC_SIGNAL_BREAK
|
if (child_ret == EXEC_SIGNAL_BREAK
|
||||||
|| child_ret == EXEC_SIGNAL_CONTINUE)
|
|| child_ret == EXEC_SIGNAL_CONTINUE
|
||||||
|
|| child_ret == EXEC_SIGNAL_EXIT)
|
||||||
return child_ret;
|
return child_ret;
|
||||||
ret = child_ret;
|
ret = child_ret;
|
||||||
}
|
}
|
||||||
|
|
@ -246,16 +272,14 @@ int exec_ast_list(struct ast_list *list_node, struct hash_map *vars)
|
||||||
int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars)
|
int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars)
|
||||||
{
|
{
|
||||||
int left_ret = execution(ao_node->left, vars);
|
int left_ret = execution(ao_node->left, vars);
|
||||||
if (left_ret == EXEC_SIGNAL_BREAK || left_ret == EXEC_SIGNAL_CONTINUE)
|
if (left_ret == EXEC_SIGNAL_BREAK || left_ret == EXEC_SIGNAL_CONTINUE
|
||||||
|
|| left_ret == EXEC_SIGNAL_EXIT)
|
||||||
return left_ret;
|
return left_ret;
|
||||||
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)
|
||||||
{
|
{
|
||||||
int right_ret = execution(ao_node->right, vars);
|
int right_ret = execution(ao_node->right, vars);
|
||||||
if (right_ret == EXEC_SIGNAL_BREAK
|
|
||||||
|| right_ret == EXEC_SIGNAL_CONTINUE)
|
|
||||||
return right_ret;
|
|
||||||
return right_ret;
|
return right_ret;
|
||||||
}
|
}
|
||||||
return left_ret;
|
return left_ret;
|
||||||
|
|
@ -265,9 +289,6 @@ int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars)
|
||||||
if (left_ret != 0)
|
if (left_ret != 0)
|
||||||
{
|
{
|
||||||
int right_ret = execution(ao_node->right, vars);
|
int right_ret = execution(ao_node->right, vars);
|
||||||
if (right_ret == EXEC_SIGNAL_BREAK
|
|
||||||
|| right_ret == EXEC_SIGNAL_CONTINUE)
|
|
||||||
return right_ret;
|
|
||||||
return right_ret;
|
return right_ret;
|
||||||
}
|
}
|
||||||
return left_ret;
|
return left_ret;
|
||||||
|
|
@ -454,13 +475,21 @@ static int builtin_false(char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int builtin_exit(char **argv)
|
static int builtin_exit(char **argv, struct hash_map *vars)
|
||||||
{
|
{
|
||||||
int exit_val = 0;
|
int exit_val = 0;
|
||||||
if (argv[1])
|
if (argv[1])
|
||||||
exit_val = atoi(argv[1]);
|
{
|
||||||
exit(exit_val);
|
exit_val = atou(argv[1]);
|
||||||
return exit_val;
|
if (exit_val == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "exit: Illegal number %s\n", argv[1]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_var_int(vars, "EXIT_VALUE", exit_val);
|
||||||
|
return EXEC_SIGNAL_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int builtin_cd(char **argv, struct hash_map *vars)
|
static int builtin_cd(char **argv, struct hash_map *vars)
|
||||||
|
|
@ -509,7 +538,7 @@ static int try_builtin(char **argv, struct hash_map *vars)
|
||||||
if (strcmp(argv[0], "continue") == 0)
|
if (strcmp(argv[0], "continue") == 0)
|
||||||
return builtin_continue(argv);
|
return builtin_continue(argv);
|
||||||
if (strcmp(argv[0], "exit") == 0)
|
if (strcmp(argv[0], "exit") == 0)
|
||||||
return builtin_exit(argv);
|
return builtin_exit(argv, vars);
|
||||||
if (strcmp(argv[0], "cd") == 0)
|
if (strcmp(argv[0], "cd") == 0)
|
||||||
return builtin_cd(argv, vars);
|
return builtin_cd(argv, vars);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
// Special execution signals used internally to implement loop control
|
// Special execution signals used internally to implement loop control
|
||||||
#define EXEC_SIGNAL_CONTINUE (-2)
|
#define EXEC_SIGNAL_CONTINUE (-2)
|
||||||
#define EXEC_SIGNAL_BREAK (-3)
|
#define EXEC_SIGNAL_BREAK (-3)
|
||||||
|
#define EXEC_SIGNAL_EXIT (-4)
|
||||||
|
|
||||||
int exec_ast_command(struct ast_command *command, struct hash_map *vars);
|
int exec_ast_command(struct ast_command *command, struct hash_map *vars);
|
||||||
int exec_ast_if(struct ast_if *if_node, struct hash_map *vars);
|
int exec_ast_if(struct ast_if *if_node, struct hash_map *vars);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue