From fb322edd72bebddee1a9828baec2f8bc83666ddf Mon Sep 17 00:00:00 2001 From: scratko Date: Sat, 25 May 2024 21:36:07 +0300 Subject: Shell-II release Implementation of launching external programs via fork(). Running cd as a change to the current process directory (chdir). Ability to change to user's home directory (cd without arguments). --- shell.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 3 deletions(-) (limited to 'shell.c') diff --git a/shell.c b/shell.c index f635c12..a1b5b29 100644 --- a/shell.c +++ b/shell.c @@ -2,6 +2,9 @@ #include "dynamic_array.h" #include #include +#include +#include +#include enum modes { word_separation, whole_word }; enum { @@ -57,7 +60,8 @@ static int is_double_quotes_pair(struct param_type params) static int check_separation(int ch, struct param_type params) { - return (ch == whitespace || ch == tab) && params.is_word && !params.escape_sequences; + return (ch == whitespace || ch == tab) && params.is_word && + !params.escape_sequences; } static int ignore_spaces(int ch, struct param_type params) @@ -87,6 +91,7 @@ static void add_word(struct queue *word_chain, params->is_word = 0; } +#if 0 static void print_word(char *word) { putchar('['); @@ -101,6 +106,77 @@ static void print_line(const struct queue *word_chain) { queue_processing(word_chain, print_word); } +#endif + +static char** create_cmdline(const struct queue *word_chain, + int word_counter) +{ + char **cmdline = malloc((word_counter + 1) * sizeof(char*)); + queue_copy_words_to_args(word_chain, cmdline); + return cmdline; +} + +static int check_cd(const char *arg) +{ + return !strcmp(arg, "cd"); +} + +static void change_directory(char **cmdline) +{ + int result; + char *first_arg = cmdline[1]; + char *path = NULL; + /* change to user home directory */ + if(first_arg == NULL) { + path = getenv("HOME"); + if(!path) { + perror("I don't know where's your home..."); + return; + } + } else { + if(cmdline[2]) { + perror("cd: too many arguments"); + return; + } + path = first_arg; + } + result = chdir(path); + if(result == -1) + perror(path); +} + +static void clean_up_memory(struct queue *word_chain, char **cmdline) +{ + queue_clear(word_chain); + free(cmdline); +} + +static void run_external_program(struct queue *word_chain) +{ + int pid, result; + char **cmdline = create_cmdline(word_chain, + queue_get_word_count(word_chain)); + if(check_cd(cmdline[0])) { + change_directory(cmdline); + clean_up_memory(word_chain, cmdline); + } + else { + pid = fork(); + if(pid == -1) { + perror("fork error"); + exit(1); + } + /* child process */ + if(pid == 0) { + execvp(cmdline[0], cmdline); + perror(cmdline[0]); + exit(1); + } + /* parent process */ + wait(&result); + clean_up_memory(word_chain, cmdline); + } +} static void new_line_processing(struct param_type *params, enum modes *current_mode, @@ -119,14 +195,18 @@ static void new_line_processing(struct param_type *params, dynarr_push_back(tmp_word, '\0'); add_word(word_chain, tmp_word, params); } + run_external_program(word_chain); +#if 0 print_line(word_chain); +#endif prepare_new_line(params, current_mode, word_chain, tmp_word); show_invitation(); } static int is_empty_word(int ch, struct param_type params) { - return (ch == whitespace || ch == tab) && !params.is_word && params.empty_word_flag; + return (ch == whitespace || ch == tab) && !params.is_word && + params.empty_word_flag; } static void word_separation_processing(int ch, struct param_type *params, @@ -198,6 +278,7 @@ static void whole_word_processing(int ch, struct param_type *params, if(escape_double_quotes_or_backslash(ch, *params)) { dynarr_push_back(tmp_word, ch); params->escape_sequences = 0; + params->is_word = 1; return; } if(start_escape_sequence(ch, *params)) { @@ -235,7 +316,6 @@ int main() &tmp_word); } putchar(new_line); - queue_clear(&word_chain); dynarr_clear(&tmp_word); return 0; } -- cgit v1.2.3