commit 3780d162acf6e42670502a6c668c1ddb6618944f
parent a6b28e5120f9399946a964dfeed3236409a6aced
Author: night0721 <[email protected]>
Date: Fri, 9 Feb 2024 01:18:14 +0000
pipes
Diffstat:
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);
};
}