From 2b90136b3a988807ec40e182fa1f9df8160d05fc Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Wed, 6 May 2020 19:52:07 +0200 Subject: [PATCH] Adding a redirection involving a pty --- Makefile | 3 +- include/key_functions.h | 16 +++- include/redirections.h | 8 +- include/shell.h | 16 ++-- src/execute.c | 2 +- src/key_bindings/basic_typing_functions.c | 16 ++++ src/key_bindings/default_bindings.c | 3 + src/main.c | 1 + src/prompt.c | 4 +- src/redirections/pty_pipe.c | 91 +++++++++++++++++++++++ src/redirections/redirections_functions.c | 2 +- src/shell.c | 55 ++++++-------- 12 files changed, 167 insertions(+), 50 deletions(-) create mode 100644 src/redirections/pty_pipe.c diff --git a/Makefile b/Makefile index 9f3e0f7..f23177c 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,8 @@ SRC = src/shell.c \ src/utility/split_commands.c \ src/utility/get_return.c \ src/key_bindings/basic_typing_functions.c \ - src/key_bindings/default_bindings.c + src/key_bindings/default_bindings.c \ + src/redirections/pty_pipe.c OBJ = $(SRC:%.c=%.o) OBJ += src/main.o diff --git a/include/key_functions.h b/include/key_functions.h index 4edd969..2b9c255 100644 --- a/include/key_functions.h +++ b/include/key_functions.h @@ -5,16 +5,24 @@ ** bindings */ -#include "shell.h" - #pragma once +#include "shell.h" + typedef struct key_function { const char *name; int (*run)(int key, buffer_t *command_buffer, env_t *env); } key_function_t; -extern const key_function_t key_functions[]; +typedef struct binding +{ + int key; + int (*func)(int key, buffer_t *command_buffer, env_t *env); +} binding_t; -int self_insert_command(int key, buffer_t *command_buffer, env_t *env); \ No newline at end of file +extern const key_function_t key_functions[]; +extern const binding_t emacs_bindings[]; + +int self_insert_command(int key, buffer_t *buffer, env_t *env); +int newline_command(int key, buffer_t *buffer, env_t *env); \ No newline at end of file diff --git a/include/redirections.h b/include/redirections.h index 6fd2731..17991a5 100644 --- a/include/redirections.h +++ b/include/redirections.h @@ -15,7 +15,8 @@ typedef enum redirection_type { INPUT = 1 << 0, OUTPUT = 1 << 1, PIPE = 1 << 2, - EX_PIPE = 1 << 3 + EX_PIPE = 1 << 3, + PTY = 1 << 4 } redirection_type; @@ -50,3 +51,8 @@ bool fd_is_used(int fd, redirection *inout); bool handle_redirections(redirection *inout[2], env_t *env, bool builtin); bool handle_parent_inout(redirection *inout[2], env_t *env, bool builtin); + + +struct redirection *new_ncurses_pty(); +int pyt_get_fd(redirection *pty); +void pty_get_output(redirection *pty, env_t *env); \ No newline at end of file diff --git a/include/shell.h b/include/shell.h index bf40ba4..1646cf6 100644 --- a/include/shell.h +++ b/include/shell.h @@ -7,9 +7,13 @@ typedef struct redirection redirection; typedef struct env_s env_t; +typedef struct binding binding_t; #pragma once +#define SHELL_NAME "42sh" + #include +#include typedef struct history_s { @@ -26,20 +30,16 @@ typedef struct buffer char *buffer; int size; int pos; + int startx; } buffer_t; -typedef struct binding -{ - int key; - int (*func)(int key, buffer_t *command_buffer, env_t *env); -} binding_t; - typedef struct env_s { char **env; char **vars; history_t *history; binding_t *bindings; + WINDOW *window; } env_t; void start_shell(env_t *env); @@ -65,6 +65,4 @@ bool envvar_is_valid(const char *str); #define INVALID_ENV_VAR \ "setenv: Variable name must contain alphanumeric characters.\n" -#define ERROR 84 - -extern const binding_t emacs_bindings[]; +#define ERROR 84 \ No newline at end of file diff --git a/src/execute.c b/src/execute.c index 1f8f0f3..a23bfa2 100644 --- a/src/execute.c +++ b/src/execute.c @@ -87,7 +87,7 @@ bool handle_parent_inout(redirection *inout[2], env_t *env, bool builtin) } if (inout[1] && inout[1]->type->run_cmd) { inout[1]->type->run_cmd(inout[1], env); - return (true); + return (!(inout[1]->type->type & PTY)); } return (false); } diff --git a/src/key_bindings/basic_typing_functions.c b/src/key_bindings/basic_typing_functions.c index bf5a0ee..32db0c5 100644 --- a/src/key_bindings/basic_typing_functions.c +++ b/src/key_bindings/basic_typing_functions.c @@ -6,7 +6,9 @@ */ #include "shell.h" +#include "builtin.h" #include "key_functions.h" +#include #include #include #include @@ -29,4 +31,18 @@ int self_insert_command(int key, buffer_t *buffer, env_t *env) strcpy(buffer->buffer + buffer->pos, chars); buffer->pos += charslen; return (0); +} + +int newline_command(int key, buffer_t *buffer, env_t *env) +{ + int ret; + + if (!buffer->buffer) + return (0); + add_to_history(buffer->buffer, env); + move(getcury(env->window) + 1, 0); + ret = eval_raw_cmd(buffer->buffer, env); + buffer->buffer[0] = '\0'; + buffer->pos = 0; + return (ret); } \ No newline at end of file diff --git a/src/key_bindings/default_bindings.c b/src/key_bindings/default_bindings.c index 0a95255..76b4deb 100644 --- a/src/key_bindings/default_bindings.c +++ b/src/key_bindings/default_bindings.c @@ -7,13 +7,16 @@ #include "shell.h" #include "key_functions.h" +#include #include const key_function_t key_functions[] = { {"self-insert-command", &self_insert_command}, + {"newline", &newline_command}, {NULL, NULL} }; const binding_t emacs_bindings[] = { + {'\n', &newline_command}, {0, NULL} }; \ No newline at end of file diff --git a/src/main.c b/src/main.c index 1045fcb..50c441e 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,7 @@ */ #include "shell.h" +#include "key_functions.h" #include #include #include diff --git a/src/prompt.c b/src/prompt.c index f91841a..656547b 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -29,11 +29,13 @@ int prompt_run(char *cmd, redirection *inout[2], env_t *env) char **argv = get_argv(cmd); if (!argv) { - perror("mysh"); + perror(SHELL_NAME); return (-1); } if (!argv[0]) return (0); + if (inout[1] == NULL) + inout[1] = new_ncurses_pty(); if (**argv == '!' && argv[0][1] && argv[0][1] != ' ') return (run_builtin(&builtins[5], argv, inout, env)); for (int i = 0; builtins[i].name; i++) diff --git a/src/redirections/pty_pipe.c b/src/redirections/pty_pipe.c new file mode 100644 index 0000000..b413d02 --- /dev/null +++ b/src/redirections/pty_pipe.c @@ -0,0 +1,91 @@ +/* +** EPITECH PROJECT, 2020 +** ash +** File description: +** pty_pipe +*/ + +#include "redirections.h" +#include +#include +#include +#include +#include +#include +#include +#define _XOPEN_SOURCE 600 +#define __USE_XOPEN_EXTENDED +#include + + +const struct redirection_map pty_type = { + .key = NULL, + .get_fd = &pyt_get_fd, + .run_cmd = &pty_get_output, + .type = OUTPUT | PIPE | EX_PIPE | PTY +}; + +int pty_open(char **slave_name) +{ + int master = open("/dev/ptmx", O_RDWR | O_NOCTTY); + int my_errno; + + *slave_name = NULL; + if (master < 0) + return (-1); + if (grantpt(master) < 0 || unlockpt(master) < 0 + || !(*slave_name = ptsname(master))) { + my_errno = errno; + close(master); + errno = my_errno; + return (-1); + } + return (master); +} + +struct redirection *new_ncurses_pty() +{ + struct redirection *pty = malloc(sizeof(*pty)); + char *slave; + + if (!pty) + return (NULL); + pty->type = &pty_type; + pty->fd = -1; + pty->extra_data = pty_open(&slave); + if (pty->extra_data < 0) { + perror(SHELL_NAME); + return (pty); + } + pty->fd = open(slave, O_RDWR); + if (pty->fd == -1) + perror(SHELL_NAME); + return (pty); +} + +// Function called only the child +int pyt_get_fd(redirection *pty) +{ +#ifdef TIOCSTTY + if (ioctl(pty->fd, TIOCSTTY, 0) == -1) + perror(SHELL_NAME); +#endif + dup2(pty->fd, 2); + return (pty->fd); +} + +// Function only called on the parent +// READ FROM pty->extra_data and put it to the ncurses window; +// Once the read return a EOF, the child program should be stopped. +void pty_get_output(redirection *pty, env_t *env) +{ + char *line = NULL; + size_t size = 0; + FILE *file = fdopen(pty->extra_data, "r"); + int y = getcury(env->window); + + while (getline(&line, &size, file) > 0) + mvaddstr(y++, 0, line); + if (line) + free(line); +} \ No newline at end of file diff --git a/src/redirections/redirections_functions.c b/src/redirections/redirections_functions.c index 2680f1b..fd5b9e5 100644 --- a/src/redirections/redirections_functions.c +++ b/src/redirections/redirections_functions.c @@ -25,7 +25,7 @@ void redirection_ctr(redirection *red, char *cmd, const redirection_map *type) red->fd = -1; if (type->type & EX_PIPE) { if (pipe(fd) != 0) { - perror("mysh"); + perror(SHELL_NAME); red->fd = -1; red->extra_data = -1; return; diff --git a/src/shell.c b/src/shell.c index 225e066..10e3c02 100644 --- a/src/shell.c +++ b/src/shell.c @@ -15,31 +15,6 @@ #include #include -void test() -{ - // char *cmd = NULL; - // size_t read = 0; - // char *p; - // bool should_close = false; - - // while (!should_close) { - // if (cmd) { - // p = strchr(cmd, '\n'); - // if (p) - // *p = '\0'; - // add_to_history(cmd, env); - // if (eval_raw_cmd(cmd, env) < 0) - // should_close = true; - // } - // if (!should_close) { - // prompt_prepare(env); - // should_close = getline(&cmd, &read, stdin) < 0; - // } - // } - // if (cmd) - // free(cmd); -} - int process_key(int key, buffer_t *buffer, env_t *env) { for (int i = 0; env->bindings[i].func; i++) @@ -48,23 +23,39 @@ int process_key(int key, buffer_t *buffer, env_t *env) return (self_insert_command(key, buffer, env)); } -void start_shell(env_t *env) +WINDOW *window_create() { WINDOW *window = initscr(); - int key; - buffer_t buffer = {.size = 0, .buffer = NULL, .pos = 0}; raw(); noecho(); keypad(window, true); + return (window); +} + +void window_destroy(WINDOW *window) +{ + delwin(window); + noraw(); + endwin(); +} + +void start_shell(env_t *env) +{ + buffer_t buffer = {.size = 0, .buffer = NULL, .pos = 0, .startx = 0}; + int key; + int y; + + env->window = window_create(); prompt_prepare(env); do { - printf("%s \n", buffer.buffer); + refresh(); + y = getcury(env->window); + mvaddstr(y, buffer.startx, buffer.buffer); + move(y, buffer.pos + buffer.startx); key = getch(); if (key == ERR) break; } while (process_key(key, &buffer, env) >= 0); - delwin(window); - noraw(); - endwin(); + window_destroy(env->window); } \ No newline at end of file