diff options
author | scratko <m@scratko.xyz> | 2024-06-14 15:15:41 +0300 |
---|---|---|
committer | scratko <m@scratko.xyz> | 2024-06-23 23:11:18 +0300 |
commit | ff38bddd4253b5adf08a84df34bfae32c8ae988d (patch) | |
tree | 69e39bf16cb93af3b9a592cf0fa3c489b13db499 | |
parent | 1ee0911f2def54f1b63d18b0924ac65c2db92f11 (diff) | |
download | shell-ff38bddd4253b5adf08a84df34bfae32c8ae988d.tar.gz shell-ff38bddd4253b5adf08a84df34bfae32c8ae988d.tar.bz2 shell-ff38bddd4253b5adf08a84df34bfae32c8ae988d.zip |
Shell-V releaseshell-V
Added pipeline.
Formatting shell.c (created lexical_analysys.c).
Error codes.
Some functions of queue.c are created by preprocessor.
-rw-r--r-- | lexical_analysis.c | 50 | ||||
-rw-r--r-- | lexical_analysis.h | 56 | ||||
-rw-r--r-- | queue.c | 58 | ||||
-rw-r--r-- | queue.h | 3 | ||||
-rw-r--r-- | shell.c | 553 | ||||
-rw-r--r-- | shell.h | 61 |
6 files changed, 253 insertions, 528 deletions
diff --git a/lexical_analysis.c b/lexical_analysis.c index f931118..4349a69 100644 --- a/lexical_analysis.c +++ b/lexical_analysis.c @@ -1,5 +1,6 @@ #include "lexical_analysis.h" -MAKE_QUEUE_PUSH(c_queue, cmdline, char**) + +#include <stdio.h> int is_double_quotes_pair(struct param_type params) { @@ -48,18 +49,14 @@ int is_empty_word(int ch, struct param_type params) int command_execution_condition(struct param_type *params) { return - (!filename_waiting(params) && !params->pipeline) || + (params->tokens != '<' && params->tokens != '>' && + params->tokens != append && !params->pipeline) || (params->pipeline && params->tokens == '&'); } -int is_special_token(int ch) +int is_first_special_token_character(int ch) { - return ch == and || ch == or || ch == '&' || ch == ';' || ch == '|'; -} - -int is_redirect_token(int ch, int next_ch) -{ - return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); + return ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == ';'; } int excessive_words(int ch, struct param_type *params) @@ -72,8 +69,10 @@ int excessive_words(int ch, struct param_type *params) while((next_ch = getchar()) != new_line) { if(next_ch == ' ') continue; - if(!is_special_token(next_ch) && next_ch != '<' && next_ch != '>') + if(!is_first_special_token_character(next_ch)) { + params->wrong_command = err_extra_chars_after_filename; return 1; + } else break; } @@ -88,7 +87,7 @@ void add_word_or_filename(struct w_queue *word_chain, { /* filenames */ if(filename_waiting(params) && !params->wrong_command) - add_filename(tmp_word, params); + add_filename(tmp_word, params); /* execute command */ else if(params->is_word) add_word(word_chain, tmp_word, params); @@ -108,6 +107,17 @@ int is_double_token(struct param_type *params) params->tokens == append; } +int is_special_token(int ch, int next_ch) +{ + return (ch == '&' && next_ch == '&') || (ch == '|' && ch == '|') || + ch == '&' || ch == ';' || ch == '|'; +} + +int is_redirect_token(int ch, int next_ch) +{ + return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); +} + /* * redirection token verification */ @@ -130,14 +140,16 @@ int stream_redirect_tokens(struct w_queue *word_chain, if(is_double_token(params)) getchar(); return 1; - } else { - fprintf(stderr, "syntax error\n"); - params->wrong_command = 1; - } + } else + params->wrong_command = err_redirect_stream_again; } return 0; } +/* + * the first element of the pipeline outputs to a file or + * redirects to a file in the middle of the pipeline + */ int wrong_streams_redirection(struct param_type *params) { return @@ -156,8 +168,7 @@ int pipeline_token_processing(struct w_queue *word_chain, char **cmdline = NULL; if(is_stream_redirection_set(params) && wrong_streams_redirection(params)) { - /* TODO: add error codes */ - params->wrong_command = 1; + params->wrong_command = err_redirect_stream_in_pipeline; return 0; } params->tokens = '|'; @@ -182,7 +193,7 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines, next_ch = getchar(); ungetc(next_ch, stdin); - if(is_special_token(ch)) { + if(is_special_token(ch, next_ch)) { add_word_or_filename(word_chain, tmp_word, params); if(params->wrong_command) @@ -199,8 +210,7 @@ int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines, else if(ch == '&') { while((ch = getchar()) != new_line) { if(ch != whitespace && ch != tab) { - fprintf(stderr, "incorrect command\n"); - params->wrong_command = 1; + params->wrong_command = err_bg_process; return 0; } } diff --git a/lexical_analysis.h b/lexical_analysis.h index e0f791a..3266ad7 100644 --- a/lexical_analysis.h +++ b/lexical_analysis.h @@ -1,54 +1,7 @@ #ifndef LEXICAL_ANALYSIS_H_SENTRY #define LEXICAL_ANALYSIS_H_SENTRY -#include "queue.h" -#include "dynamic_array.h" - -#include <stdio.h> -#include <stdlib.h> - -enum { - new_line = 10, - whitespace = ' ', - tab = 9, - backslash = '\\', - double_quotes = '"' -}; - -/* two-letter tokens */ -enum { - append = '>' + 1, - and = '&' + 1, - or = '|' + 1 -}; - -/* storing file names to redirect standard input/output streams */ -struct io_type { - char *input_stream; - char *output_stream; - char *output_stream_to_append; -}; - -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; - struct io_type streams; - int last_execution_status; - int pipeline; -}; - - -int filename_waiting(struct param_type *params); -void add_filename(struct dynamic_array *tmp_word, struct param_type *params); -void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, - struct param_type *params); -int is_stream_redirection_set(const struct param_type *params); -char** create_cmdline(const struct w_queue *word_chain, int word_counter); +#include "shell.h" int is_double_quotes_pair(struct param_type params); int escape_double_quotes_or_backslash(int ch, struct param_type params); @@ -60,19 +13,23 @@ int start_escape_sequence(int ch, struct param_type params); int is_empty_word(int ch, struct param_type params); int command_execution_condition(struct param_type *params); -int is_special_token(int ch); +int is_special_token(int ch, int next_ch); int is_redirect_token(int ch, int next_ch); int excessive_words(int ch, struct param_type *params); + void add_word_or_filename(struct w_queue *word_chain, struct dynamic_array *tmp_word, struct param_type *params); + int validate_redirections(int ch, int next_ch, struct param_type *params); int is_double_token(struct param_type *params); int stream_redirect_tokens(struct w_queue *word_chain, struct dynamic_array *tmp_word, int ch, struct param_type *params); + int double_quotes_again(int ch, struct param_type params); + int pipeline_token_processing(struct w_queue *word_chain, struct c_queue *cmdlines, struct dynamic_array *tmp_word, @@ -81,4 +38,5 @@ int pipeline_token_processing(struct w_queue *word_chain, int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines, struct dynamic_array *tmp_word, int ch, struct param_type *params); + #endif @@ -1,27 +1,6 @@ #include "queue.h" #include <stdlib.h> -#if 0 -void w_queue_init(struct w_queue *q) -{ - q->first = NULL; - q->last = NULL; -} - -void w_queue_push(struct w_queue *q, char *word) -{ - struct word_item *tmp = malloc(sizeof(struct word_item)); - tmp->word = word; - tmp->next = NULL; - if(!q->first) { - q->first = tmp; - q->last = q->first; - } else { - q->last->next = tmp; - q->last = q->last->next; - } -} -#endif void w_queue_clear(struct w_queue *q) { struct word_item *tmp; @@ -58,22 +37,6 @@ void c_queue_init(struct c_queue *q) q->last_extracted_item = NULL; } -#if 0 -void c_queue_push(struct c_queue *q, char **cmdline) -{ - struct cmdline_item *tmp = malloc(sizeof(struct cmdline_item)); - tmp->cmdline = cmdline; - tmp->next = NULL; - if(!q->first) { - q->first = tmp; - q->last = q->first; - } else { - q->last->next = tmp; - q->last = q->last->next; - } -} -#endif - int c_queue_is_empty(struct c_queue *q) { return q->last_extracted_item->next == NULL; @@ -111,27 +74,6 @@ void c_queue_clear(struct c_queue *q) q->last = NULL; q->last_extracted_item = NULL; } -#if 0 -void p_queue_init(struct p_queue *q) -{ - q->first = NULL; - q->last = NULL; -} - -void p_queue_push(struct p_queue *q, int pid) -{ - struct pid_item *tmp = malloc(sizeof(struct pid_item)); - tmp->pid = pid; - tmp->next = NULL; - if(!q->first) { - q->first = tmp; - q->last = q->first; - } else { - q->last->next = tmp; - q->last = q->last->next; - } -} -#endif int p_queue_find_pid(struct p_queue *q, int pid) { @@ -59,7 +59,10 @@ int w_queue_get_word_count(const struct w_queue *q); void w_queue_copy_words_to_args(const struct w_queue *q, char **cmdline); void c_queue_init(struct c_queue *q); + +/* used in shell.c and lexical_analysis.c */ void c_queue_push(struct c_queue *q, char **cmdline); + char** c_queue_pop(struct c_queue *q); void c_queue_clear(struct c_queue *q); int c_queue_is_empty(struct c_queue *q); @@ -1,3 +1,4 @@ +#include "shell.h" #include "queue.h" #include "dynamic_array.h" #include "lexical_analysis.h" @@ -14,56 +15,16 @@ MAKE_QUEUE_INIT(w_queue) MAKE_QUEUE_INIT(p_queue) MAKE_QUEUE_PUSH(w_queue, word, char*) +MAKE_QUEUE_PUSH(c_queue, cmdline, char**) MAKE_QUEUE_PUSH(p_queue, pid, int) enum modes { word_separation, whole_word }; -#if 0 -enum { - new_line = 10, - whitespace = ' ', - tab = 9, - backslash = '\\', - double_quotes = '"' -}; - -/* two-letter tokens */ -enum { - append = '>' + 1, - and = '&' + 1, - or = '|' + 1 -}; - -/* storing file names to redirect standard input/output streams */ -struct io_type { - char *input_stream; - char *output_stream; - char *output_stream_to_append; -}; - -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; - struct io_type streams; - int last_execution_status; - int pipeline; -}; -#endif static void show_invitation() { printf("> "); } -static void print_error() -{ - fprintf(stderr, "Error: unmatched quotes\n"); -} - /* remove background zombie processes */ static void handler(int signal) { @@ -121,59 +82,6 @@ static void reset_params(struct param_type *params, clear_filename(params); init_params(params, current_mode); } -#if 0 -static int is_double_quotes_pair(struct param_type params) -{ - return !(params.double_quotes_counter % 2); -} -static int check_separation(int ch, struct param_type params) -{ - return (ch == whitespace || ch == tab) && params.is_word && - !params.escape_sequences; -} -#endif -int filename_waiting(struct param_type *params) -{ - if(params->tokens == '<' || params->tokens == '>' || - params->tokens == append) { - if(!params->is_word) - params->wrong_command = 1; - return 1; - } else - return 0; -} - -void add_filename(struct dynamic_array *tmp_word, struct param_type *params) -{ - dynarr_push_back(tmp_word, '\0'); - switch(params->tokens) { - case '<': - params->streams.input_stream = malloc(tmp_word->last_element_index+1); - dynarr_copy_array(tmp_word, params->streams.input_stream); - break; - case '>': - params->streams.output_stream = malloc(tmp_word->last_element_index+1); - dynarr_copy_array(tmp_word, params->streams.output_stream); - break; - case append: - params->streams.output_stream_to_append = - malloc(tmp_word->last_element_index+1); - dynarr_copy_array(tmp_word, params->streams.output_stream_to_append); - } - dynarr_drop_word(tmp_word); - params->is_word = 0; -} - -void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, - struct param_type *params) -{ - dynarr_push_back(tmp_word, 0); - char *word = malloc(tmp_word->last_element_index+1); - dynarr_copy_array(tmp_word, word); - w_queue_push(word_chain, word); - dynarr_drop_word(tmp_word); - params->is_word = 0; -} static void add_letter(int ch, struct dynamic_array *tmp_word, struct param_type *params) @@ -183,161 +91,37 @@ static void add_letter(int ch, struct dynamic_array *tmp_word, params->escape_sequences = 0; } -#if 0 -static int is_double_token(struct param_type *params) -{ - return params->tokens == and || params->tokens == or || - params->tokens == append; -} -static int is_redirect_token(int ch, int next_ch) -{ - return ch == '<' || ch == '>' || (ch == '>' && next_ch == '>'); -} -static int validate_redirections(int ch, int next_ch, struct param_type *params) -{ - return (ch == '<' && params->streams.input_stream == NULL) || - ((ch == '>' || (ch == '>' && next_ch == '>')) && - params->streams.output_stream == NULL && - params->streams.output_stream_to_append == NULL); -} -static void add_word_or_filename(struct w_queue *word_chain, - struct dynamic_array *tmp_word, - struct param_type *params) -{ - /* filenames */ - if(filename_waiting(params) && !params->wrong_command) - add_filename(tmp_word, params); - /* execute command */ - else if(params->is_word) - add_word(word_chain, tmp_word, params); -} - -static int stream_redirect_tokens(struct w_queue *word_chain, - struct dynamic_array *tmp_word, int ch, - struct param_type *params) -{ - int next_ch; - next_ch = getchar(); - ungetc(next_ch, stdin); - - if(is_redirect_token(ch, next_ch)) { - add_word_or_filename(word_chain, tmp_word, params); - - if(params->wrong_command) - return 0; - - if(validate_redirections(ch, next_ch, params)) { - params->tokens = (ch == '>' && next_ch == '>') ? append : ch; - if(is_double_token(params)) - getchar(); - return 1; - } else { - fprintf(stderr, "syntax error\n"); - params->wrong_command = 1; - } - } - return 0; -} -#endif - static void clean_input_buffer() { int ch; while((ch = getchar()) != new_line) {} } -#if 0 -static int is_special_token(int ch) -{ - return ch == and || ch == or || ch == '&' || ch == ';' || ch == '|'; -} -static int wrong_streams_redirection(struct param_type *params) -{ - return - (!params->pipeline && (params->tokens == '>' || - params->tokens == append)) || - (params->pipeline && (params->tokens == '>' || - params->tokens == append || - params->tokens == '<')); -} -#endif -char** create_cmdline(const struct w_queue *word_chain, int word_counter) +static void print_error_msg(const char *error_msg) { - char **cmdline = malloc((word_counter + 1) * sizeof(char*)); - w_queue_copy_words_to_args(word_chain, cmdline); - return cmdline; + if(error_msg) + fprintf(stderr, "%s\n", error_msg); } -int is_stream_redirection_set(const struct param_type *params) -{ - return params->streams.input_stream || params->streams.output_stream || - params->streams.output_stream_to_append; -} -#if 0 -static int pipeline_token_processing(struct w_queue *word_chain, - struct c_queue *cmdlines, - struct dynamic_array *tmp_word, - struct param_type *params) +static const char* error_code_to_token(int error_code) { - char **cmdline = NULL; - if(is_stream_redirection_set(params) && - wrong_streams_redirection(params)) { - /* TODO: add error codes */ - params->wrong_command = 1; - return 0; + switch(error_code) { + case err_filename_expected: return "expected file name"; + case err_redirect_stream_again: return "stream redirected again"; + case err_redirect_stream_in_pipeline: return "bad stream redirect in pipe"; + case err_bg_process: return "extra characters after &"; + case err_empty_command: return "empty command"; + case err_extra_chars_after_filename: return "extra chars after filename"; + case err_odd_double_quotes: return "odd number of double quotes"; } - params->tokens = '|'; - params->pipeline = 1; - cmdline = - create_cmdline(word_chain, w_queue_get_word_count(word_chain)); - - c_queue_push(cmdlines, cmdline); - w_queue_clear(word_chain); - dynarr_drop_word(tmp_word); - return 1; + return NULL; } -static int special_tokens(struct w_queue *word_chain, - struct c_queue *cmdlines, - struct dynamic_array *tmp_word, int ch, - struct param_type *params) +void error_identification(const struct param_type *params) { - int next_ch; - next_ch = getchar(); - ungetc(next_ch, stdin); - - if(is_special_token(ch)) { - add_word_or_filename(word_chain, tmp_word, params); - - if(params->wrong_command) - return 0; - - if(ch == '|' && next_ch == '|') - params->tokens = or; - else if(ch == '|') { - if(!pipeline_token_processing(word_chain, cmdlines, tmp_word, - params)) - return 0; - } 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 0; - } - } - params->tokens = '&'; - } - if(is_double_token(params)) - getchar(); - return 1; - } - return 0; + print_error_msg(error_code_to_token(params->wrong_command)); } -#endif static int special_token_handling(struct w_queue *word_chain, struct c_queue *cmdlines, @@ -348,113 +132,6 @@ static int special_token_handling(struct w_queue *word_chain, stream_redirect_tokens(word_chain, tmp_word, ch, params) ? 1 : special_tokens(word_chain, cmdlines, tmp_word, ch, params); } -#if 0 -static int ignore_spaces(int ch, struct param_type params) -{ - return (ch == whitespace || ch == tab) && !params.escape_sequences; -} - -static int change_mode(int ch, struct param_type params) -{ - return ch == '"' && !params.escape_sequences; -} - -static int start_escape_sequence(int ch, struct param_type params) -{ - return ch == backslash && !params.escape_sequences; -} - -/* name of file for opening stream already exists */ - -static int excessive_words(int ch, const struct param_type *params) -{ - int next_ch; - - if(filename_waiting(params)) { - if(ch == new_line) - return 0; - while((next_ch = getchar()) != new_line) { - if(next_ch == ' ') - continue; - if(!is_special_token(next_ch) && next_ch != '<' && next_ch != '>') - return 1; - else - break; - } - ungetc(next_ch, stdin); - } - return 0; -} -#endif - -static int is_cd_command(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 open_files(const struct param_type *params, int *input_fd, - int *output_fd) -{ - if(params->streams.input_stream) - *input_fd = open(params->streams.input_stream, O_RDONLY); - if(params->streams.output_stream) - *output_fd = open(params->streams.output_stream, O_WRONLY | O_CREAT | - O_TRUNC, 0666); - if(params->streams.output_stream_to_append) - *output_fd = open(params->streams.output_stream_to_append, O_WRONLY | - O_APPEND, 0666); -} - -static void change_streams(int input_fd, int output_fd, int is_pipeline, - int is_begin_pipeline) -{ - if((!is_pipeline && input_fd) || - (is_pipeline && is_begin_pipeline && input_fd)) { - dup2(input_fd, 0); - close(input_fd); - } - if((!is_pipeline && output_fd) || - (is_pipeline && !is_begin_pipeline && output_fd)) { - dup2(output_fd, 1); - close(output_fd); - } -} - -static void set_signal_disposition(struct param_type *params) -{ - if(params->tokens == '&') - /* zombie process termination on signal */ - signal(SIGCHLD, handler); - else - /* the parent process will wait for the process to complete; - default signal disposition - */ - signal(SIGCHLD, SIG_DFL); -} static void wait_for_process_to_complete(struct p_queue *pid_store) { @@ -499,6 +176,39 @@ static void postprocessing(struct w_queue *word_chain, struct c_queue *cmdlines, p_queue_clear(pid_store); } +static void set_signal_disposition(struct param_type *params) +{ + if(params->tokens == '&') + /* zombie process termination on signal */ + signal(SIGCHLD, handler); + else + /* the parent process will wait for the process to complete; + default signal disposition + */ + signal(SIGCHLD, SIG_DFL); +} + +static void change_streams(int input_fd, int output_fd, int is_pipeline, + int is_begin_pipeline) +{ + if((!is_pipeline && input_fd) || + (is_pipeline && is_begin_pipeline && input_fd)) { + dup2(input_fd, 0); + close(input_fd); + } + if((!is_pipeline && output_fd) || + (is_pipeline && !is_begin_pipeline && output_fd)) { + dup2(output_fd, 1); + close(output_fd); + } +} + +int is_stream_redirection_set(const struct param_type *params) +{ + return params->streams.input_stream || params->streams.output_stream || + params->streams.output_stream_to_append; +} + static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, struct param_type *params, int input_fd, int output_fd) @@ -540,6 +250,7 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, if(!c_queue_is_empty(cmdlines)) { dup2(save_read_fd, 0); close(save_read_fd); + close(fd[0]); dup2(fd[1], 1); close(fd[1]); } else { @@ -565,6 +276,48 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, output_fd); } +static void open_files(const struct param_type *params, int *input_fd, + int *output_fd) +{ + if(params->streams.input_stream) + *input_fd = open(params->streams.input_stream, O_RDONLY); + if(params->streams.output_stream) + *output_fd = open(params->streams.output_stream, O_WRONLY | O_CREAT | + O_TRUNC, 0666); + if(params->streams.output_stream_to_append) + *output_fd = open(params->streams.output_stream_to_append, O_WRONLY | + O_APPEND, 0666); +} + +static int is_cd_command(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 run_external_program(struct w_queue *word_chain, struct c_queue *cmdlines, struct param_type *params) @@ -613,6 +366,56 @@ static void run_external_program(struct w_queue *word_chain, } } +int filename_waiting(struct param_type *params) +{ + if(params->tokens == '<' || params->tokens == '>' || + params->tokens == append) { + if(!params->is_word) + params->wrong_command = err_filename_expected; + return 1; + } else + return 0; +} + +void add_filename(struct dynamic_array *tmp_word, struct param_type *params) +{ + dynarr_push_back(tmp_word, '\0'); + switch(params->tokens) { + case '<': + params->streams.input_stream = malloc(tmp_word->last_element_index+1); + dynarr_copy_array(tmp_word, params->streams.input_stream); + break; + case '>': + params->streams.output_stream = malloc(tmp_word->last_element_index+1); + dynarr_copy_array(tmp_word, params->streams.output_stream); + break; + case append: + params->streams.output_stream_to_append = + malloc(tmp_word->last_element_index+1); + dynarr_copy_array(tmp_word, params->streams.output_stream_to_append); + } + dynarr_drop_word(tmp_word); + params->is_word = 0; +} + +void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, + struct param_type *params) +{ + dynarr_push_back(tmp_word, 0); + char *word = malloc(tmp_word->last_element_index+1); + dynarr_copy_array(tmp_word, word); + w_queue_push(word_chain, word); + dynarr_drop_word(tmp_word); + params->is_word = 0; +} + +char** create_cmdline(const struct w_queue *word_chain, int word_counter) +{ + char **cmdline = malloc((word_counter + 1) * sizeof(char*)); + w_queue_copy_words_to_args(word_chain, cmdline); + return cmdline; +} + static void command_processing(struct param_type *params, enum modes *current_mode, struct w_queue *word_chain, @@ -621,11 +424,10 @@ static void command_processing(struct param_type *params, { char **cmdline = NULL; - /* and odd number of double quotes */ + /* odd number of double quotes */ if(!is_double_quotes_pair(*params)) { - print_error(); - reset_params(params, current_mode, word_chain, cmdlines, tmp_word); - show_invitation(); + params->wrong_command = err_odd_double_quotes; + goto clean; return; } if(filename_waiting(params)) { @@ -635,7 +437,7 @@ static void command_processing(struct param_type *params, if(params->tokens == '>' || params->tokens == append) add_filename(tmp_word, params); else if(params->tokens == '<') { - fprintf(stderr, "read in the last pipline element\n"); + params->wrong_command = err_redirect_stream_in_pipeline; goto clean; } } else @@ -643,39 +445,15 @@ static void command_processing(struct param_type *params, } else if(params->empty_word_flag || params->is_word) add_word(word_chain, tmp_word, params); -#if 0 - if(params->empty_word_flag || params->is_word) { - if(filename_waiting(params)) { - if(excessive_words(ch, params)) { - fprintf(stderr, "too many args\n"); - goto clean; - } - if(params->pipeline) { - if(params->tokens == '>' || params->tokens == append) - add_filename(tmp_word, params); - else if(params->tokens == '<') { - fprintf(stderr, "read in the last pipline element\n"); - goto clean; - } - } else - add_filename(tmp_word, params); - } else - add_word(word_chain, tmp_word, params); - - } else if(filename_waiting(params)) { - fprintf(stderr, "filename expected\n"); - goto clean; - } -#endif - if((params->tokens == and || params->tokens == or) && params->last_execution_status == 1) { + /* ??? */ fprintf(stderr, "cannot be performed\n"); return; } if(word_chain->first == NULL) { - fprintf(stderr, "empty command\n"); + params->wrong_command = err_empty_command; goto clean; } @@ -684,26 +462,12 @@ static void command_processing(struct param_type *params, run_external_program(word_chain, cmdlines, params); clean: + error_identification(params); if(params->tokens == '&' || params->tokens == 0 || ch == new_line) show_invitation(); reset_params(params, current_mode, word_chain, cmdlines, tmp_word); } -#if 0 -static int is_empty_word(int ch, struct param_type params) -{ - return (ch == whitespace || ch == tab) && !params.is_word && - params.empty_word_flag; -} - -static int command_execution_condition(struct param_type *params) -{ - return - (!filename_waiting(params) && !params->pipeline) || - (params->pipeline && params->tokens == '&'); -} -#endif - static void word_separation_processing(int ch, struct param_type *params, enum modes *current_mode, struct w_queue *word_chain, @@ -735,6 +499,7 @@ static void word_separation_processing(int ch, struct param_type *params, return; } if(params->wrong_command) { + error_identification(params); clean_input_buffer(); reset_params(params, current_mode, word_chain, cmdlines, tmp_word); show_invitation(); @@ -742,9 +507,9 @@ static void word_separation_processing(int ch, struct param_type *params, } if(check_separation(ch, *params)) { if(excessive_words(ch, params)) { + error_identification(params); clean_input_buffer(); reset_params(params, current_mode, word_chain, cmdlines, tmp_word); - fprintf(stderr, "too many args\n"); show_invitation(); return; } @@ -760,20 +525,6 @@ static void word_separation_processing(int ch, struct param_type *params, add_letter(ch, tmp_word, params); } -#if 0 -static int escape_double_quotes_or_backslash(int ch, struct param_type params) -{ - return params.escape_sequences && - (ch == double_quotes || ch == backslash); -} - -static int double_quotes_again(int ch, struct param_type params) -{ - return ch == double_quotes && !params.is_word && - params.stored_symbol == '"'; -} -#endif - static void whole_word_processing(int ch, struct param_type *params, enum modes *current_mode, struct w_queue *word_chain, @@ -0,0 +1,61 @@ +#ifndef SHELL_H_SENTRY +#define SHELL_H_SENTRY + +#include "dynamic_array.h" +#include "queue.h" + +enum { + new_line = 10, + whitespace = ' ', + tab = 9, + esc = 27, + backslash = '\\', + double_quotes = '"' +}; + +/* two-letter tokens */ +enum { + append = '>' + 1, + and = '&' + 1, + or = '|' + 1 +}; + +/* error codes */ +enum { + err_filename_expected = 1, + err_redirect_stream_again = 2, + err_redirect_stream_in_pipeline = 3, + err_bg_process = 4, + err_empty_command = 5, + err_extra_chars_after_filename = 6, + err_odd_double_quotes = 7 +}; + +/* storing file names to redirect standard input/output streams */ +struct io_type { + char *input_stream; + char *output_stream; + char *output_stream_to_append; +}; + +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; + struct io_type streams; + int last_execution_status; + int pipeline; +}; + +int filename_waiting(struct param_type *params); +void add_filename(struct dynamic_array *tmp_word, struct param_type *params); +void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, + struct param_type *params); +int is_stream_redirection_set(const struct param_type *params); +char** create_cmdline(const struct w_queue *word_chain, int word_counter); + +#endif |