From 9b5c06e9276fb56ce0327caee160ad58eacd8d86 Mon Sep 17 00:00:00 2001 From: savalet Date: Wed, 26 Mar 2025 19:59:37 +0100 Subject: [PATCH] Add heredoc --- src/ast.c | 3 +- src/ast.h | 11 +++--- src/redirects.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ src/redirects.h | 18 ++++++++++ src/tokeniser.c | 1 + src/visitor.c | 45 +++-------------------- ulib/str/puterror.c | 2 +- ulib/u_str.h | 2 +- 8 files changed, 122 insertions(+), 48 deletions(-) create mode 100644 src/redirects.c create mode 100644 src/redirects.h diff --git a/src/ast.c b/src/ast.c index cafdac1..cfd0a2d 100644 --- a/src/ast.c +++ b/src/ast.c @@ -20,7 +20,8 @@ ast_t *parse_arg(ast_ctx_t *ctx, ast_t *node) ctx->act_tok = get_next_token(ctx); if (ctx->act_tok.type == T_SEMICOLON) return node; - if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND | T_IN_REDIRECT)) { + if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND | + T_IN_REDIRECT | T_HEREDOC)) { if (!ensure_node_cap(node)) return NULL; node->vector.tokens[node->vector.sz] = ctx->act_tok; diff --git a/src/ast.h b/src/ast.h index 86090fc..39730b6 100644 --- a/src/ast.h +++ b/src/ast.h @@ -29,11 +29,12 @@ typedef enum { T_PREV_CMD = 1 << 9, // !! T_VAR = 1 << 10, // $ T_REDIRECT = 1 << 11, // > - T_IN_REDIRECT = 1 << 12, // < - T_APPEND = 1 << 13, // >> - T_EOF = 1 << 14, // \0 - T_ARG = 1 << 15, - T_INVALID = 1 << 16 + T_APPEND = 1 << 12, // >> + T_HEREDOC = 1 << 13, // < + T_IN_REDIRECT = 1 << 14, // < + T_EOF = 1 << 15, // \0 + T_ARG = 1 << 16, + T_INVALID = 1 << 17 } token_type_t; typedef enum { diff --git a/src/redirects.c b/src/redirects.c new file mode 100644 index 0000000..0a44173 --- /dev/null +++ b/src/redirects.c @@ -0,0 +1,88 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include +#include +#include +#include +#include +#include + +#include "exec.h" +#include "u_str.h" + +bool handle_out_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz) +{ + if (!(node->vector.tokens[i].type & (T_REDIRECT | T_APPEND))) + return true; + if (i >= sz || node->vector.tokens[i + 1].type != T_ARG) + return (WRITE_CONST(STDERR_FILENO, + "Missing name for redirect.\n"), false); + ef->skip_i = ef->skip_i ?: i; + ef->skip_sz += 2; + node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0'; + ef->rout_fd = open(node->vector.tokens[i + 1].str, O_CREAT | O_WRONLY | + (node->vector.tokens[i].type == T_APPEND ? O_APPEND : O_TRUNC), 0644); + if (ef->rout_fd < 0) + return (puterror(node->vector.tokens[i + 1].str), false); + ef->out_fd = ef->rout_fd; + return true; +} + +bool handle_in_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz) +{ + if (node->vector.tokens[i].type != T_IN_REDIRECT) + return true; + if (i >= sz || node->vector.tokens[i + 1].type != T_ARG) + return (WRITE_CONST(STDERR_FILENO, + "Missing name for redirect.\n"), false); + ef->skip_i = ef->skip_i ?: i; + ef->skip_sz += 2; + node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0'; + ef->rin_fd = open(node->vector.tokens[i + 1].str, O_RDONLY); + if (ef->rin_fd < 0) + return (puterror(node->vector.tokens[i + 1].str), false); + ef->in_fd = ef->rin_fd; + return true; +} + +int handle_heredoc_loop(ast_t *node, size_t i) +{ + int fds[2]; + buff_t buffer = { .str = NULL }; + + if (pipe(fds) < 0) + return (puterror("pipe"), -1); + node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0'; + WRITE_CONST(STDOUT_FILENO, "? "); + while (getline(&buffer.str, &buffer.sz, stdin) != -1) { + buffer.str[u_strlen(buffer.str) - 1] = '\0'; + if (u_strcmp(buffer.str, node->vector.tokens[i + 1].str) == 0) + break; + write(fds[1], buffer.str, u_strlen(buffer.str)); + write(fds[1], "\n", 1); + WRITE_CONST(STDOUT_FILENO, "? "); + } + free(buffer.str); + close(fds[1]); + return fds[0]; +} + +bool handle_heredoc(ef_t *ef, ast_t *node, size_t i, size_t sz) +{ + if (node->vector.tokens[i].type != T_HEREDOC) + return true; + if (i >= sz || node->vector.tokens[i + 1].type != T_ARG) + return (WRITE_CONST(STDERR_FILENO, + "Missing name for redirect.\n"), false); + ef->skip_i = ef->skip_i ?: i; + ef->skip_sz += 2; + ef->in_fd = handle_heredoc_loop(node, i); + if (ef->in_fd == -1) + return false; + return true; +} diff --git a/src/redirects.h b/src/redirects.h new file mode 100644 index 0000000..9845802 --- /dev/null +++ b/src/redirects.h @@ -0,0 +1,18 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#ifndef REDIRECTS_H + #define REDIRECTS_H + #include + + #include "exec.h" + +bool handle_out_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz); +bool handle_in_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz); +int handle_heredoc_loop(ast_t *node, size_t i); +bool handle_heredoc(ef_t *ef, ast_t *node, size_t i, size_t sz); +#endif /* REDIRECTS_H */ diff --git a/src/tokeniser.c b/src/tokeniser.c index ec38a42..cf55231 100644 --- a/src/tokeniser.c +++ b/src/tokeniser.c @@ -25,6 +25,7 @@ const tokens_list_t TOKENS_LIST[] = { { T_VAR, "$", 1, "T_VAR" }, { T_APPEND, ">>", 2, "T_APPEND" }, { T_REDIRECT, ">", 1, "T_REDIRECT" }, + { T_HEREDOC, "<<", 2, "T_HEREDOC" }, { T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" }, { T_EOF, "\0", 1, "T_EOF" } }; diff --git a/src/visitor.c b/src/visitor.c index 7b9f6f0..0a15492 100644 --- a/src/visitor.c +++ b/src/visitor.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -13,45 +14,9 @@ #include "builtins.h" #include "common.h" #include "exec.h" +#include "redirects.h" #include "u_str.h" -static -bool handle_out_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz) -{ - if (!(node->vector.tokens[i].type & (T_REDIRECT | T_APPEND))) - return true; - if (i >= sz || node->vector.tokens[i + 1].type != T_ARG) - return (WRITE_CONST(STDERR_FILENO, - "Missing name for redirect.\n"), false); - ef->skip_i = ef->skip_i ?: i; - ef->skip_sz += 2; - node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0'; - ef->rout_fd = open(node->vector.tokens[i + 1].str, O_CREAT | O_WRONLY | - (node->vector.tokens[i].type == T_APPEND ? O_APPEND : O_TRUNC), 0644); - if (ef->rout_fd < 0) - return (puterror(node->vector.tokens[i + 1].str), false); - ef->out_fd = ef->rout_fd; - return true; -} - -static -bool handle_in_redirect(ef_t *ef, ast_t *node, size_t i, size_t sz) -{ - if (node->vector.tokens[i].type != T_IN_REDIRECT) - return true; - if (i >= sz || node->vector.tokens[i + 1].type != T_ARG) - return (WRITE_CONST(STDERR_FILENO, - "Missing name for redirect.\n"), false); - ef->skip_i = ef->skip_i ?: i; - ef->skip_sz += 2; - node->vector.tokens[i + 1].str[node->vector.tokens[i + 1].sz] = '\0'; - ef->rin_fd = open(node->vector.tokens[i + 1].str, O_RDONLY); - if (ef->rin_fd < 0) - return (puterror(node->vector.tokens[i + 1].str), false); - ef->in_fd = ef->rin_fd; - return true; -} - /* * ef->in_fd = ef->pin_fd; * ef->out_fd = ef->out_fd; @@ -69,9 +34,9 @@ int visit_cmd(ef_t *ef) ef->rout_fd = 0; ef->rin_fd = 0; for (size_t i = 0; i < ef->act_node->vector.sz; i++) { - if (!handle_in_redirect(ef, ef->act_node, i, ef->act_node->vector.sz)) - return -1; - if (!handle_out_redirect(ef, ef->act_node, i, ef->act_node->vector.sz)) + if (!handle_in_redirect(ef, ef->act_node, i, ef->act_node->vector.sz) + || !handle_out_redirect(ef, ef->act_node, i, ef->act_node->vector.sz) + || !handle_heredoc(ef, ef->act_node, i, ef->act_node->vector.sz)) return -1; } result = execute(ef); diff --git a/ulib/str/puterror.c b/ulib/str/puterror.c index d05c3f7..b862fe5 100644 --- a/ulib/str/puterror.c +++ b/ulib/str/puterror.c @@ -11,7 +11,7 @@ #include "u_str.h" -void puterror(char *prefix) +void puterror(char const *prefix) { char const *error_msg = strerror(errno); size_t len; diff --git a/ulib/u_str.h b/ulib/u_str.h index d79e54b..37ba5c8 100644 --- a/ulib/u_str.h +++ b/ulib/u_str.h @@ -33,6 +33,6 @@ int u_spacelen(char const *str); int u_strcspn(char *str, char c); bool u_str_is_alnum(char *str); bool u_str_is_only_alnum(char *str); -void puterror(char *prefix); +void puterror(char const *prefix); #endif /* STRING_H */