From 859c929333b0c17f1b6027b17cc30bdf4763e6e2 Mon Sep 17 00:00:00 2001 From: scratko Date: Sun, 26 May 2024 17:09:25 +0300 Subject: Shell-III release Added the ability to run programs in the background. Added tokens for future releases. --- Makefile | 4 +-- shell.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 0fc988b..8d28bdd 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ OBJMODULES = $(SRCMODULES:.c=.o) CC = gcc CFLAGS = -Wall -g -c -all: shell-II +all: shell-III %.o: %.с %.h $(CC) $(CFLAGS) $< -o $@ -shell-II: $(OBJMODULES) +shell-III: $(OBJMODULES) $(CC) $(LIBS) $^ -o $@ -include deps.mk diff --git a/shell.c b/shell.c index a1b5b29..c03b62b 100644 --- a/shell.c +++ b/shell.c @@ -15,12 +15,21 @@ enum { double_quotes = '"' }; +/* two-letter tokens */ +enum { + append = '>' + 1, + and = '&' + 1, + or = '|' + 1 +}; + struct param_type { int is_word; int escape_sequences; unsigned int double_quotes_counter; char stored_symbol; int empty_word_flag; + int tokens; + int wrong_command; }; static void show_invitation() @@ -40,10 +49,12 @@ static void init_params(struct param_type *params, enum modes *current_mode) params->double_quotes_counter = 0; params->stored_symbol = ' '; params->empty_word_flag = 0; + params->tokens = 0; + params->wrong_command = 0; *current_mode = word_separation; } -static void prepare_new_line(struct param_type *params, +static void reset_params(struct param_type *params, enum modes *current_mode, struct queue *word_chain, struct dynamic_array *tmp_word) @@ -64,6 +75,50 @@ static int check_separation(int ch, struct param_type params) !params.escape_sequences; } +static int single_tokens(int ch) +{ + return ch == '<' || ch == ';' || ch == '(' || ch == ')'; +} + +static void clean_input_buffer() +{ + int ch; + while((ch = getchar() != new_line)) + {} +} + +static void double_tokens_and_fg(int ch, struct param_type *params) +{ + int next_ch; + next_ch = getchar(); + ungetc(next_ch, stdin); + if(ch == '>' && next_ch == '>') + params->tokens = append; + else if(ch == '|' && next_ch == '|') + params->tokens = or; + else if(ch == '&' && next_ch == '&') + params->tokens = and; + else if(ch == '&') { + while((ch = getchar()) != new_line) { + if(ch != whitespace && ch != tab) { + fprintf(stderr, "incorrect command\n"); + params->wrong_command = 1; + return; + } + } + params->tokens = '&'; + } +} + +static int check_tokens(int ch, struct param_type *params) +{ + if(single_tokens(ch)) + params->tokens = ch; + else + double_tokens_and_fg(ch, params); + return params->tokens; +} + static int ignore_spaces(int ch, struct param_type params) { return (ch == whitespace || ch == tab) && !params.escape_sequences; @@ -87,7 +142,7 @@ static void add_word(struct queue *word_chain, char *word = malloc(tmp_word->last_element_index+1); dynarr_copy_array(tmp_word, word); queue_push(word_chain, word); - tmp_word->last_element_index = -1; + dynarr_drop_word(tmp_word); params->is_word = 0; } @@ -151,9 +206,22 @@ static void clean_up_memory(struct queue *word_chain, char **cmdline) free(cmdline); } -static void run_external_program(struct queue *word_chain) +static void clean_up_zombie_process() +{ + int pid; + do { + pid = wait4(-1, NULL, WNOHANG, NULL); + } while(pid > 0); +} + +static void run_external_program(struct queue *word_chain, + struct param_type *params) { - int pid, result; + int pid, wait_pid, result; + if(word_chain->first == NULL) { + fprintf(stderr, "empty command\n"); + return; + } char **cmdline = create_cmdline(word_chain, queue_get_word_count(word_chain)); if(check_cd(cmdline[0])) { @@ -173,12 +241,20 @@ static void run_external_program(struct queue *word_chain) exit(1); } /* parent process */ - wait(&result); + clean_up_memory(word_chain, cmdline); + + /* waiting for forground process */ + if(params->tokens != '&') { + do { + wait_pid = wait(&result); + } while(wait_pid != pid); + } else + clean_up_zombie_process(); } } -static void new_line_processing(struct param_type *params, +static void command_processing(struct param_type *params, enum modes *current_mode, struct queue *word_chain, struct dynamic_array *tmp_word) @@ -186,7 +262,7 @@ static void new_line_processing(struct param_type *params, /* and odd number of double quotes */ if(!is_double_quotes_pair(*params)) { print_error(); - prepare_new_line(params, current_mode, word_chain, tmp_word); + reset_params(params, current_mode, word_chain, tmp_word); show_invitation(); return; } @@ -195,12 +271,13 @@ 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); + run_external_program(word_chain, params); + if(params->tokens == '&' || params->tokens == 0) + show_invitation(); + reset_params(params, current_mode, word_chain, tmp_word); #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) @@ -232,6 +309,16 @@ static void word_separation_processing(int ch, struct param_type *params, params->escape_sequences = 1; return; } + if(check_tokens(ch, params)) { + command_processing(params, current_mode, word_chain, tmp_word); + return; + } + if(params->wrong_command) { + clean_input_buffer(); + reset_params(params, current_mode, word_chain, tmp_word); + show_invitation(); + return; + } if(check_separation(ch, *params)) { add_word(word_chain, tmp_word, params); params->is_word = 0; @@ -305,8 +392,9 @@ int main() init_params(¶ms, ¤t_mode); show_invitation(); while((ch = getchar()) != EOF) { + clean_up_zombie_process(); if(ch == new_line) - new_line_processing(¶ms, ¤t_mode, &word_chain, + command_processing(¶ms, ¤t_mode, &word_chain, &tmp_word); else if(current_mode == word_separation) word_separation_processing(ch, ¶ms, ¤t_mode, &word_chain, -- cgit v1.2.3