back to scratko.xyz
summaryrefslogtreecommitdiff
path: root/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell.c')
-rw-r--r--shell.c553
1 files changed, 152 insertions, 401 deletions
diff --git a/shell.c b/shell.c
index 131de99..71be7fd 100644
--- a/shell.c
+++ b/shell.c
@@ -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,