feat(main_loop): subshell start
This commit is contained in:
parent
a7065a1d9f
commit
c7822a2534
4 changed files with 153 additions and 62 deletions
72
src/main.c
72
src/main.c
|
|
@ -7,70 +7,9 @@
|
|||
#include "lexer/lexer.h"
|
||||
#include "parser/parser.h"
|
||||
#include "utils/args/args.h"
|
||||
#include "utils/main_loop/main_loop.h"
|
||||
#include "utils/vars/vars.h"
|
||||
|
||||
// === Error codes
|
||||
|
||||
#define SUCCESS 0
|
||||
#define ERR_INPUT_PROCESSING 2
|
||||
#define ERR_MALLOC 3
|
||||
#define ERR_GENERIC 4
|
||||
|
||||
// === Functions
|
||||
|
||||
/* @brief: frees the hash map.
|
||||
* @return: always ERR_INPUT_PROCESSING.
|
||||
*/
|
||||
static int err_input(struct hash_map **vars, struct lexer_context *ctx)
|
||||
{
|
||||
hash_map_free(vars);
|
||||
destroy_lexer_context(ctx);
|
||||
return ERR_INPUT_PROCESSING;
|
||||
}
|
||||
|
||||
static int main_loop(struct lexer_context *ctx, struct hash_map *vars)
|
||||
{
|
||||
int return_code = SUCCESS;
|
||||
// init parser
|
||||
if (!parser_init())
|
||||
{
|
||||
perror("parser initialization failed.");
|
||||
}
|
||||
|
||||
// Retrieve and build first AST
|
||||
struct ast *command_ast = get_ast(ctx);
|
||||
|
||||
// Main parse-execute loop
|
||||
while (command_ast != NULL && command_ast->type != AST_END)
|
||||
{
|
||||
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);
|
||||
|
||||
// Retrieve and build next AST
|
||||
command_ast = get_ast(ctx);
|
||||
}
|
||||
|
||||
if (command_ast == NULL)
|
||||
return err_input(&vars, ctx);
|
||||
|
||||
// === free
|
||||
|
||||
ast_free(&command_ast);
|
||||
parser_close();
|
||||
hash_map_free(&vars);
|
||||
destroy_lexer_context(ctx);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct hash_map *vars = vars_init();
|
||||
|
|
@ -117,7 +56,16 @@ int main(int argc, char **argv)
|
|||
// init lexer context
|
||||
struct lexer_context *ctx = calloc(1, sizeof(struct lexer_context));
|
||||
|
||||
// init parser
|
||||
if (!parser_init())
|
||||
{
|
||||
perror("parser initialization failed.");
|
||||
return err_input(&vars, ctx);
|
||||
}
|
||||
|
||||
return_code = main_loop(ctx, vars);
|
||||
|
||||
parser_close();
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ libutils_a_SOURCES = \
|
|||
ast/ast_loop.c \
|
||||
args/args.c \
|
||||
vars/vars.c \
|
||||
main_loop/main_loop.c \
|
||||
ast/ast_assignment.c \
|
||||
ast/ast_subshell.c \
|
||||
ast/ast_function.c
|
||||
|
|
|
|||
111
src/utils/main_loop/main_loop.c
Normal file
111
src/utils/main_loop/main_loop.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "main_loop.h"
|
||||
|
||||
// === Includes
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "../../execution/execution.h"
|
||||
#include "../../io_backend/io_backend.h"
|
||||
#include "../../lexer/lexer.h"
|
||||
#include "../../parser/parser.h"
|
||||
#include "../args/args.h"
|
||||
#include "../vars/vars.h"
|
||||
|
||||
// === Functions
|
||||
|
||||
int err_input(struct hash_map **vars, struct lexer_context *ctx)
|
||||
{
|
||||
hash_map_free(vars);
|
||||
destroy_lexer_context(ctx);
|
||||
return ERR_INPUT_PROCESSING;
|
||||
}
|
||||
|
||||
int main_loop(struct lexer_context *ctx, struct hash_map *vars)
|
||||
{
|
||||
int return_code = SUCCESS;
|
||||
|
||||
// Retrieve and build first AST
|
||||
struct ast *command_ast = get_ast(ctx);
|
||||
|
||||
// Main parse-execute loop
|
||||
while (command_ast != NULL && command_ast->type != AST_END)
|
||||
{
|
||||
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);
|
||||
|
||||
// Retrieve and build next AST
|
||||
command_ast = get_ast(ctx);
|
||||
}
|
||||
|
||||
if (command_ast == NULL)
|
||||
return err_input(&vars, ctx);
|
||||
|
||||
// === free
|
||||
|
||||
ast_free(&command_ast);
|
||||
hash_map_free(&vars);
|
||||
destroy_lexer_context(ctx);
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
||||
/* @brief: initializes a lexer context from a command string.
|
||||
* @return: pointer to the lexer context, or NULL on failure.
|
||||
*/
|
||||
static struct lexer_context *lexer_init_from_string(char *command)
|
||||
{
|
||||
// Create a lexer context from the command string
|
||||
struct lexer_context *ctx = calloc(1, sizeof(struct lexer_context));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx->end_previous_token = strdup(command);
|
||||
if (ctx->end_previous_token == NULL)
|
||||
{
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->remaining_chars = strlen(command);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int start_subshell(struct hash_map **parent_vars, char *command)
|
||||
{
|
||||
int fd = fork();
|
||||
if (fd < 0)
|
||||
return ERR_GENERIC;
|
||||
|
||||
else if (fd == 0) // Child process
|
||||
{
|
||||
struct lexer_context *ctx = lexer_init_from_string(command);
|
||||
if (ctx == NULL)
|
||||
return ERR_MALLOC;
|
||||
int return_code = main_loop(ctx, *parent_vars);
|
||||
exit(return_code);
|
||||
}
|
||||
else // Parent process
|
||||
{
|
||||
int status;
|
||||
if (waitpid(fd, &status, 0) == -1)
|
||||
return ERR_GENERIC;
|
||||
if (WIFEXITED(status))
|
||||
return WEXITSTATUS(status);
|
||||
else
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
31
src/utils/main_loop/main_loop.h
Normal file
31
src/utils/main_loop/main_loop.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef MAIN_LOOP_H
|
||||
#define MAIN_LOOP_H
|
||||
|
||||
#include "../../utils/vars/vars.h"
|
||||
#include "../../lexer/lexer.h"
|
||||
|
||||
// === Error codes
|
||||
#define SUCCESS 0
|
||||
#define ERR_INPUT_PROCESSING 2
|
||||
#define ERR_MALLOC 3
|
||||
#define ERR_GENERIC 4
|
||||
|
||||
/* @brief: main loop called from main.
|
||||
* @return: exit code.
|
||||
*/
|
||||
int main_loop(struct lexer_context *ctx, struct hash_map *vars);
|
||||
|
||||
/*
|
||||
* @brief: frees the hash map and lexer context.
|
||||
* @return: ERR_INPUT_PROCESSING.
|
||||
*/
|
||||
int err_input(struct hash_map **vars, struct lexer_context *ctx);
|
||||
|
||||
/*
|
||||
* @brief: starts a subshell and builds the intern lexer context
|
||||
* from the string.
|
||||
* @return: exit code of the subshell.
|
||||
*/
|
||||
int start_subshell(struct hash_map **parent_vars, char *command);
|
||||
|
||||
#endif /* MAIN_LOOP_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue