diff --git a/README.md b/README.md index aa3f1ea..0cb51ba 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,17 @@ _ | _ ``` + +## To-Do + +1. Pipes +2. Exclude things inside quote marks from string splitting and substitutions +3. Interrupts ^C and ^Z, bg, fg + - & and &&, ; +4. Wildcard substitutions *, ? etc +5. tab completion, handling escape sequences like ^[[D +6. Functions and variables +7. PS1 + + + diff --git a/main.c b/main.c index a2e75fa..25a30e9 100644 --- a/main.c +++ b/main.c @@ -9,6 +9,9 @@ int get_alias(Alias *alias, State *state, char *name); int add_alias(State* state, char *name, char *substitution); int del_alias(State *state, char *name); int repl(State* state, FILE *input); +int run_command(State *state, int argc, char *argv[]); +int get_array_element(ArrayElement **ret, GrowingArray* array, char* key); +int del_array_element(GrowingArray* array, char* key); GrowingArray get_growing_array(size_t num_elements, size_t size_elem) { GrowingArray arr; @@ -199,14 +202,83 @@ void shutdown(State *state) { exit(0); } +int check_pipes(State* state, int num_args, char* args[]) { + + int left = 0; + int num_commands = 0; + int space = 10; + // an array of string-arrays which end in NULL + char** *pipes = calloc(space, sizeof(char***)); + + for (int i = 0; i < num_args; i++) { + if (!strcmp(args[i], "|") || i == num_args - 1) { + int command_length = i - left + 1 + num_commands; + char **command = calloc(command_length, sizeof(char**)); + // copy the command into the array + for (int k = 0; k < command_length - 1; k++) { + command[k] = args[left + k]; + } + command[command_length - 1] = 0; + + // grow the array if needed + if (num_commands == space - 2) { + pipes = calloc((space *= 2), sizeof(char***)); + } + + pipes[num_commands] = command; + num_commands++; + + left = i + 1; + } + } + + if (num_commands == 1) { + return ER_NOT_EXISTS; + } + + int pipein[2]; + int pipeout[2]; + memset(pipein, 0, sizeof(int) * 2); + memset(pipeout, 0, sizeof(int) * 2); + + pipe(pipein); + pipe(pipeout); + // 0 is read, 1 is write + + pid_t child; + + int in; + int out; + + in = 0; + out = pipeout[1]; + + for (int i = 0; i < num_commands; i++) { + execute(in, out, pipes[i], &child); + if (i != num_commands - 1) { + if (in == pipein[0]) { + in = pipeout[0]; + out = pipein[1]; + } else { + in = pipein[0]; + out = pipeout[1]; + } + } else { + out = 1; + in = out - 1; + } + } + + return ER_SUCCESS; +} + int check_builtins(State *state, int num_args, char *args[]) { char *builtins[NUM_BUILTINS] = { "cd", "alias", "unalias" }; - - if (!strcmp(args[0], "cd")) { + if (!strcmp(args[0], "cd")) { if (num_args == 1) { chdir(getenv("HOME")); return ER_SUCCESS; @@ -343,15 +415,12 @@ int check_aliases(State *state, char **substitution, char *name) { return ER_FAILURE; } - -int run_command(State *state, int argc, char *argv[]) { - pid_t child; - +int expand_command(State *state, int argc, char* argv[]) { if (argc == 0) { return ER_FAILURE; } - char *substitution; + char *substitution; if (!check_aliases(state, &substitution, argv[0])) { strip_char(argv[0], ' '); argv[0] = reallocarray(argv[0], strlen(substitution) + 1, sizeof(char)); @@ -362,25 +431,29 @@ int run_command(State *state, int argc, char *argv[]) { join_string(&joined, argc, argv, " "); split_string(&new_argv, &len, joined, ' '); - //run_command(state, len, new_argv); - execute(stdin, stdout, new_argv, &child); - waitpid(child, NULL, 0); - return ER_SUCCESS; + run_command(state, len, new_argv); for (int i = 0 ; i < len; i ++) { free(new_argv[i]); } free(new_argv); + return ER_SUCCESS; + } else { + run_command(state, argc, argv); } + return ER_SUCCESS; +} +int run_command(State *state, int argc, char *argv[]) { + pid_t child; if (check_builtins(state, argc, argv) == ER_NOT_EXISTS) { - execute(stdin, stdout, argv, &child); + execute(0,1, argv, &child); waitpid(child, NULL, 0); } - return ER_SUCCESS; } +/* read eval print loop until EOF */ int repl(State* state, FILE *input) { while (true) { char *line; @@ -398,7 +471,11 @@ int repl(State* state, FILE *input) { split_string(&sep_string, &num_words, line, ' '); - run_command(state, num_words, sep_string); + int err = check_pipes(state, num_words, sep_string); + if (err == ER_NOT_EXISTS) { + expand_command(state, num_words, sep_string); + } + for (int i = 0; i < num_words; i++) { free(sep_string[i]); diff --git a/run.c b/run.c index c27e7f4..233aa78 100644 --- a/run.c +++ b/run.c @@ -5,9 +5,7 @@ * * Returns true on success or 1 on failure. */ -int execute(FILE *in, FILE *out, char *args[], pid_t* child_ID) { - int in_FD = fileno(in); - int out_FD = fileno(out); +int execute(int in_FD, int out_FD, char *args[], pid_t* child_ID) { int err = fork(); diff --git a/run.h b/run.h index 0adca76..5e82151 100644 --- a/run.h +++ b/run.h @@ -8,7 +8,7 @@ #ifndef RUNH #define RUNH -int execute(FILE *in, FILE *out, char *args[], pid_t* child_ID); +int execute(int in_FD, int out_FD, char *args[], pid_t* child_ID); int change_dir(char *dir);