back to scratko.xyz
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-06-14 15:15:41 +0300
committerscratko <m@scratko.xyz>2024-06-23 23:11:18 +0300
commitff38bddd4253b5adf08a84df34bfae32c8ae988d (patch)
tree69e39bf16cb93af3b9a592cf0fa3c489b13db499
parent1ee0911f2def54f1b63d18b0924ac65c2db92f11 (diff)
downloadshell-V.tar.gz
shell-V.tar.bz2
shell-V.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.c50
-rw-r--r--lexical_analysis.h56
-rw-r--r--queue.c58
-rw-r--r--queue.h3
-rw-r--r--shell.c553
-rw-r--r--shell.h61
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
diff --git a/queue.c b/queue.c
index 3787236..9d77d00 100644
--- a/queue.c
+++ b/queue.c
@@ -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)
{
diff --git a/queue.h b/queue.h
index 325706e..c11ffd8 100644
--- a/queue.h
+++ b/queue.h
@@ -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);
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,
diff --git a/shell.h b/shell.h
new file mode 100644
index 0000000..ec87f57
--- /dev/null
+++ b/shell.h
@@ -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