90s

Minimalist, customizable shell written in C99 with syntax highlighting
git clone https://codeberg.org/night0721/90s
Log | Files | Refs | README | LICENSE

commit 3780d162acf6e42670502a6c668c1ddb6618944f
parent a6b28e5120f9399946a964dfeed3236409a6aced
Author: night0721 <[email protected]>
Date:   Fri,  9 Feb 2024 01:18:14 +0000

pipes

Diffstat:
MREADME.md | 6++----
Mcommands.c | 50++++++++++++++++++++++++++++++++++++++++++++++++--
Mcommands.h | 1+
Mhistory.c | 7++-----
Mhistory.h | 2+-
Mrush.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
6 files changed, 123 insertions(+), 18 deletions(-)

diff --git a/README.md b/README.md @@ -26,11 +26,10 @@ $ ./rush - Showing current time and directory with custom color - Syntax highlighting on valid commands using ANSI colors - History navigation using up and down keys with history command -- Built in commands -- Export environment variable -- Source commands from a file +- Support for environment variables - Editing using left and right arrow keys - !! to repeat last command +- Pipes # Built in commands - cd @@ -41,7 +40,6 @@ $ ./rush - source # Todo Features -- splits commands based on pipes and whitespaces - stdin, stdout, stderr redirect - background jobs - tab completion diff --git a/commands.c b/commands.c @@ -159,8 +159,6 @@ int execute(char **args) { return 1; } - save_command_history(args); // save command to history file - // prioritize builtin commands for (int i = 0; i < num_builtins(); i++) { if (strcmp(args[0], builtin_cmds[i]) == 0) { @@ -199,3 +197,51 @@ int execute(char **args) { return 1; } + +// execute_pipe with as many pipes as needed +int execute_pipe(char ***args) { + int pipefd[2]; + int status; + pid_t pid; + int i = 0; + int in = 0; + + int num_pipes = 0; + while (args[num_pipes] != NULL) { + num_pipes++; + } + + for (i = 0; i < num_pipes; i++) { + pipe(pipefd); + if ((pid = fork()) == 0) { + dup2(in, 0); // change input according to the old one + if (i < num_pipes - 1) { + dup2(pipefd[1], 1); // change output according to the new one + } + close(pipefd[0]); + execvp(args[i][0], args[i]); + exit(EXIT_FAILURE); + } else if (pid < 0) { + perror("fork failed"); + } + close(pipefd[1]); + in = pipefd[0]; + } + + if ((pid = fork()) == 0) { + dup2(in, 0); + execvp(args[i][0], args[i]); + exit(EXIT_FAILURE); + } else if (pid < 0) { + perror("fork failed"); + } + + close(pipefd[0]); + close(pipefd[1]); + + for (i = 0; i <= num_pipes; i++) { + wait(&status); + } + + return 1; +} diff --git a/commands.h b/commands.h @@ -4,5 +4,6 @@ int num_builtins(); bool is_builtin(char *command); int execute(char **args); +int execute_pipe(char ***args); #endif diff --git a/history.c b/history.c @@ -47,7 +47,7 @@ void check_history_file() { } } -void save_command_history(char **args) { +void save_command_history(char *args) { history_file = fopen(histfile_path, "a+"); if (history_file == NULL) { fprintf(stderr, "rush: Error opening history file\n"); @@ -55,10 +55,7 @@ void save_command_history(char **args) { } char cmd[RL_BUFSIZE]; cmd[0] = '\0'; - for (int i = 0; args[i] != NULL; ++i) { - strcat(cmd, args[i]); - strcat(cmd, " "); - } + strcat(cmd, args); int cmd_len = strlen(cmd); cmd[cmd_len] = '\n'; // put new line feed to split commands // ptr to first obj, size of each obj, number of obj, file ptr diff --git a/history.h b/history.h @@ -1,7 +1,7 @@ #ifndef HISTORY_H_ #define HISTORY_H_ -void save_command_history(char **args); +void save_command_history(char *args); void check_history_file(); char *read_command(int direction); char **get_all_history(bool check); diff --git a/rush.c b/rush.c @@ -7,6 +7,7 @@ #include <time.h> #include <stdbool.h> #include <signal.h> +#include <ctype.h> #include "color.h" #include "constants.h" @@ -386,8 +387,11 @@ char **argsplit(char *line) { char **modifyargs(char **args) { int num_arg = 0; + while (args[num_arg] != NULL) { + num_arg++; + } // makes ls and diff have color without user typing it - if (strncmp(args[0], "ls", 2) == 0 || strncmp(args[0], "diff", 4) == 0) { + if (strncmp(args[0], "ls", 2) == 0 || strncmp(args[0], "diff", 4) == 0 || strncmp(args[0], "grep", 4) == 0) { args[num_arg] = "--color=auto"; num_arg++; args[num_arg] = NULL; @@ -396,6 +400,49 @@ char **modifyargs(char **args) { return args; } +char *trimws(char *str) { + char *end; + while (isspace((unsigned char) *str)) + str++; + if(*str == 0) + return str; + end = str + strlen(str) - 1; + while (end > str && isspace((unsigned char) *end)) + end--; + *(end+1) = 0; + return str; +} + +char ***pipe_argsplit(char *line) { + char ***cmdv = malloc(sizeof(char **) * 128); // 127 commands, 1 for NULL + if (cmdv == NULL) { + fprintf(stderr, "rush: Error allocating memory\n"); + exit(EXIT_FAILURE); + } + char **cmds = malloc(sizeof(char *) * 128); // 127 arguments, 1 for NULL + if (cmds == NULL) { + fprintf(stderr, "rush: Error allocating memory\n"); + exit(EXIT_FAILURE); + } + int num_arg = 0; + char *pipe = strtok(line, "|"); + while (pipe != NULL) { + pipe = trimws(pipe); + cmds[num_arg] = strdup(pipe); + pipe = strtok(NULL, "|"); + num_arg++; + } + cmds[num_arg] = NULL; + + for (int i = 0; i < num_arg; i++) { + char **splitted = argsplit(cmds[i]); + cmdv[i] = modifyargs(splitted); + } + cmdv[num_arg] = NULL; + free(cmds); + return cmdv; +} + // continously prompt for command and execute it void command_loop(char **paths) { char *line; @@ -425,12 +472,28 @@ void command_loop(char **paths) { line = readline(paths); - args = argsplit(line); - args = modifyargs(args); - status = execute(args); - + save_command_history(line); + bool has_pipe = false; + for (int i = 0; line[i] != '\0'; i++) { + if (line[i] == '|') { + has_pipe = true; + break; + } + } + if (has_pipe) { + char ***pipe_args = pipe_argsplit(line); + status = execute_pipe(pipe_args); + while (*pipe_args != NULL) { + free(*pipe_args); + pipe_args++; + } + } else { + args = argsplit(line); + args = modifyargs(args); + status = execute(args); + free(args); + } free(line); - free(args); free(cwd); }; }