back to scratko.xyz
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-06-12 18:52:28 +0300
committerscratko <m@scratko.xyz>2024-06-12 18:52:28 +0300
commit1ee0911f2def54f1b63d18b0924ac65c2db92f11 (patch)
tree945cf5fc2e0e3fe3095349950ff51e4b561a1f8e
parent8bcfbe6a15f6195c3501b9bde633081da67179d1 (diff)
downloadshell-1ee0911f2def54f1b63d18b0924ac65c2db92f11.tar.gz
shell-1ee0911f2def54f1b63d18b0924ac65c2db92f11.tar.bz2
shell-1ee0911f2def54f1b63d18b0924ac65c2db92f11.zip
version shell-V with commented out code
-rw-r--r--Makefile6
-rw-r--r--lexical_analysis.c214
-rw-r--r--lexical_analysis.h84
-rw-r--r--queue.c141
-rw-r--r--queue.h66
-rw-r--r--shell.c495
6 files changed, 825 insertions, 181 deletions
diff --git a/Makefile b/Makefile
index 3fe276d..8a49831 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,14 @@
-SRCMODULES = dynamic_array.c queue.c shell.c
+SRCMODULES = dynamic_array.c queue.c lexical_analysis.c shell.c
OBJMODULES = $(SRCMODULES:.c=.o)
CC = gcc
CFLAGS = -Wall -g -c
-all: shell-IV
+all: shell-V
%.o: %.с %.h
$(CC) $(CFLAGS) $< -o $@
-shell-IV: $(OBJMODULES)
+shell-V: $(OBJMODULES)
$(CC) $(LIBS) $^ -o $@
-include deps.mk
diff --git a/lexical_analysis.c b/lexical_analysis.c
new file mode 100644
index 0000000..f931118
--- /dev/null
+++ b/lexical_analysis.c
@@ -0,0 +1,214 @@
+#include "lexical_analysis.h"
+MAKE_QUEUE_PUSH(c_queue, cmdline, char**)
+
+int is_double_quotes_pair(struct param_type params)
+{
+ return !(params.double_quotes_counter % 2);
+}
+
+int escape_double_quotes_or_backslash(int ch, struct param_type params)
+{
+ return params.escape_sequences &&
+ (ch == double_quotes || ch == backslash);
+}
+
+int double_quotes_again(int ch, struct param_type params)
+{
+ return ch == double_quotes && !params.is_word &&
+ params.stored_symbol == '"';
+}
+
+int check_separation(int ch, struct param_type params)
+{
+ return (ch == whitespace || ch == tab) && params.is_word &&
+ !params.escape_sequences;
+}
+
+int ignore_spaces(int ch, struct param_type params)
+{
+ return (ch == whitespace || ch == tab) && !params.escape_sequences;
+}
+
+int change_mode(int ch, struct param_type params)
+{
+ return ch == '"' && !params.escape_sequences;
+}
+
+int start_escape_sequence(int ch, struct param_type params)
+{
+ return ch == backslash && !params.escape_sequences;
+}
+
+int is_empty_word(int ch, struct param_type params)
+{
+ return (ch == whitespace || ch == tab) && !params.is_word &&
+ params.empty_word_flag;
+}
+
+int command_execution_condition(struct param_type *params)
+{
+ return
+ (!filename_waiting(params) && !params->pipeline) ||
+ (params->pipeline && params->tokens == '&');
+}
+
+int is_special_token(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 == '>');
+}
+
+int excessive_words(int ch, 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;
+}
+
+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);
+}
+
+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);
+}
+
+int is_double_token(struct param_type *params)
+{
+ return params->tokens == and || params->tokens == or ||
+ params->tokens == append;
+}
+
+/*
+ * redirection token verification
+ */
+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;
+}
+
+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 == '<'));
+}
+
+int pipeline_token_processing(struct w_queue *word_chain,
+ struct c_queue *cmdlines,
+ struct dynamic_array *tmp_word,
+ struct param_type *params)
+{
+ char **cmdline = NULL;
+ if(is_stream_redirection_set(params) &&
+ wrong_streams_redirection(params)) {
+ /* TODO: add error codes */
+ params->wrong_command = 1;
+ return 0;
+ }
+ 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;
+}
+
+/*
+ * verification of special tokens (|, &, &&, ||), except redirection tokens
+ */
+int special_tokens(struct w_queue *word_chain, struct c_queue *cmdlines,
+ struct dynamic_array *tmp_word, int ch,
+ 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;
+}
diff --git a/lexical_analysis.h b/lexical_analysis.h
new file mode 100644
index 0000000..e0f791a
--- /dev/null
+++ b/lexical_analysis.h
@@ -0,0 +1,84 @@
+#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);
+
+int is_double_quotes_pair(struct param_type params);
+int escape_double_quotes_or_backslash(int ch, struct param_type params);
+int double_quotes_again(int ch, struct param_type params);
+int check_separation(int ch, struct param_type params);
+int ignore_spaces(int ch, struct param_type params);
+int change_mode(int ch, struct param_type params);
+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_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,
+ struct param_type *params);
+
+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 eed3cf8..3787236 100644
--- a/queue.c
+++ b/queue.c
@@ -1,13 +1,14 @@
#include "queue.h"
#include <stdlib.h>
-void queue_init(struct queue *q)
+#if 0
+void w_queue_init(struct w_queue *q)
{
q->first = NULL;
q->last = NULL;
}
-void queue_push(struct queue *q, char *word)
+void w_queue_push(struct w_queue *q, char *word)
{
struct word_item *tmp = malloc(sizeof(struct word_item));
tmp->word = word;
@@ -20,32 +21,19 @@ void queue_push(struct queue *q, char *word)
q->last = q->last->next;
}
}
-
-void queue_clear(struct queue *q)
+#endif
+void w_queue_clear(struct w_queue *q)
{
struct word_item *tmp;
while(q->first) {
tmp = q->first;
q->first = q->first->next;
- free(tmp->word);
free(tmp);
}
q->last = NULL;
}
-#if 0
-void queue_processing(const struct queue *q, void (*callback)(char*))
-{
- struct word_item *tmp;
- tmp = q->first;
- while(tmp) {
- callback(tmp->word);
- tmp = tmp->next;
- }
-}
-#endif
-
-int queue_get_word_count(const struct queue *q)
+int w_queue_get_word_count(const struct w_queue *q)
{
struct word_item *tmp;
int counter;
@@ -54,7 +42,7 @@ int queue_get_word_count(const struct queue *q)
return counter;
}
-void queue_copy_words_to_args(const struct queue *q, char **cmdline)
+void w_queue_copy_words_to_args(const struct w_queue *q, char **cmdline)
{
struct word_item *tmp;
int mas_idx;
@@ -62,3 +50,118 @@ void queue_copy_words_to_args(const struct queue *q, char **cmdline)
cmdline[mas_idx] = tmp->word;
cmdline[mas_idx] = NULL;
}
+
+void c_queue_init(struct c_queue *q)
+{
+ q->first = NULL;
+ q->last = NULL;
+ 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;
+}
+
+char** c_queue_pop(struct c_queue *q)
+{
+ if(!q->last_extracted_item) {
+ if(q->first) {
+ q->last_extracted_item = q->first;
+ return q->last_extracted_item->cmdline;
+ }
+ return NULL;
+ } else {
+ if(q->last_extracted_item->next) {
+ q->last_extracted_item = q->last_extracted_item->next;
+ return q->last_extracted_item->cmdline;
+ }
+ return NULL;
+ }
+}
+
+void c_queue_clear(struct c_queue *q)
+{
+ struct cmdline_item *tmp = NULL;
+ while(q->first) {
+ int i;
+ for(i = 0; q->first->cmdline[i]; ++i)
+ free(q->first->cmdline[i]);
+ free(q->first->cmdline);
+ tmp = q->first;
+ q->first = q->first->next;
+ free(tmp);
+ }
+ 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)
+{
+ struct pid_item *tmp = q->first;
+ while(tmp) {
+ if(tmp->pid == pid)
+ return 1;
+ tmp = tmp->next;
+ }
+ return 0;
+}
+
+int p_queue_get_process_quantity(struct p_queue *q)
+{
+ int counter = 0;
+ struct pid_item *tmp = q->first;
+ while(tmp) {
+ ++counter;
+ tmp = tmp->next;
+ }
+ return counter;
+}
+
+void p_queue_clear(struct p_queue *q)
+{
+ struct pid_item *tmp = NULL;
+ while(q->first) {
+ tmp = q->first;
+ q->first = q->first->next;
+ free(tmp);
+ }
+ q->last = NULL;
+}
diff --git a/queue.h b/queue.h
index fedcd0b..325706e 100644
--- a/queue.h
+++ b/queue.h
@@ -1,23 +1,71 @@
#ifndef QUEUE_H_SENTRY
#define QUEUE_H_SENTRY
+#define MAKE_QUEUE_INIT(NAME) \
+ void NAME ## _init(struct NAME *q) \
+{ \
+ q->first = NULL; \
+ q->last = NULL; \
+}
+
+#define MAKE_QUEUE_PUSH(NAME, VALUE, TYPE) \
+ void NAME ## _push(struct NAME *q, TYPE VALUE) \
+{ \
+ struct VALUE ## _item *tmp = malloc(sizeof(struct VALUE ## _item)); \
+ tmp-> VALUE = VALUE; \
+ tmp->next = NULL; \
+ if(!q->first) { \
+ q->first = tmp; \
+ q->last = q->first; \
+ } else { \
+ q->last->next = tmp; \
+ q->last = q->last->next; \
+ } \
+}
+
struct word_item {
char *word;
struct word_item *next;
};
-struct queue {
+struct cmdline_item {
+ char **cmdline;
+ struct cmdline_item *next;
+};
+
+struct pid_item {
+ int pid;
+ struct pid_item *next;
+};
+
+struct w_queue {
struct word_item *first;
struct word_item *last;
};
-void queue_init(struct queue *q);
-void queue_push(struct queue *q, char *word);
-void queue_clear(struct queue *q);
-#if 0
-void queue_processing(const struct queue *q, void (*callback)(char*));
-#endif
-int queue_get_word_count(const struct queue *q);
-void queue_copy_words_to_args(const struct queue *q, char **cmdline);
+struct c_queue {
+ struct cmdline_item *first;
+ struct cmdline_item *last;
+ struct cmdline_item *last_extracted_item;
+};
+
+struct p_queue {
+ struct pid_item *first;
+ struct pid_item *last;
+};
+
+void w_queue_clear(struct w_queue *q);
+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);
+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);
+
+int p_queue_find_pid(struct p_queue *q, int pid);
+void p_queue_clear(struct p_queue *q);
+int p_queue_get_process_quantity(struct p_queue *q);
#endif
diff --git a/shell.c b/shell.c
index d3b96b3..131de99 100644
--- a/shell.c
+++ b/shell.c
@@ -1,5 +1,6 @@
#include "queue.h"
#include "dynamic_array.h"
+#include "lexical_analysis.h"
#include <stdio.h>
#include <stdlib.h>
@@ -10,7 +11,13 @@
#include <signal.h>
#include <errno.h>
+MAKE_QUEUE_INIT(w_queue)
+MAKE_QUEUE_INIT(p_queue)
+MAKE_QUEUE_PUSH(w_queue, word, char*)
+MAKE_QUEUE_PUSH(p_queue, pid, int)
+
enum modes { word_separation, whole_word };
+#if 0
enum {
new_line = 10,
whitespace = ' ',
@@ -43,7 +50,9 @@ struct param_type {
int wrong_command;
struct io_type streams;
int last_execution_status;
+ int pipeline;
};
+#endif
static void show_invitation()
{
@@ -83,6 +92,7 @@ static void init_params(struct param_type *params, enum modes *current_mode)
params->streams.output_stream_to_append = NULL;
/* 0 - success, 1 - error */
params->last_execution_status = 0;
+ params->pipeline = 0;
*current_mode = word_separation;
}
@@ -101,40 +111,39 @@ static void clear_filename(struct param_type *params)
static void reset_params(struct param_type *params,
enum modes *current_mode,
- struct queue *word_chain,
+ struct w_queue *word_chain,
+ struct c_queue *cmdlines,
struct dynamic_array *tmp_word)
{
- queue_clear(word_chain);
+ w_queue_clear(word_chain);
+ c_queue_clear(cmdlines);
dynarr_drop_word(tmp_word);
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;
}
-
-static 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 int filename_waiting(const struct param_type *params)
+#endif
+int filename_waiting(struct param_type *params)
{
- return params->tokens == '<' || params->tokens == '>' ||
- params->tokens == append;
+ if(params->tokens == '<' || params->tokens == '>' ||
+ params->tokens == append) {
+ if(!params->is_word)
+ params->wrong_command = 1;
+ return 1;
+ } else
+ return 0;
}
-static void add_filename(struct dynamic_array *tmp_word,
- struct param_type *params)
+void add_filename(struct dynamic_array *tmp_word, struct param_type *params)
{
dynarr_push_back(tmp_word, '\0');
switch(params->tokens) {
@@ -155,29 +164,35 @@ static void add_filename(struct dynamic_array *tmp_word,
params->is_word = 0;
}
-static void add_word(struct queue *word_chain,
- 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)
{
dynarr_push_back(tmp_word, 0);
char *word = malloc(tmp_word->last_element_index+1);
dynarr_copy_array(tmp_word, word);
- queue_push(word_chain, 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)
+{
+ dynarr_push_back(tmp_word, ch);
+ params->is_word = 1;
+ 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) ||
@@ -185,8 +200,19 @@ static int validate_redirections(int ch, int next_ch, struct param_type *params)
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 queue *word_chain,
+static int stream_redirect_tokens(struct w_queue *word_chain,
struct dynamic_array *tmp_word, int ch,
struct param_type *params)
{
@@ -195,20 +221,10 @@ static int stream_redirect_tokens(struct queue *word_chain,
ungetc(next_ch, stdin);
if(is_redirect_token(ch, next_ch)) {
- /* filenames */
- if(filename_waiting(params))
- if(params->is_word)
- add_filename(tmp_word, params);
- else {
- fprintf(stderr, "syntax error\n");
- params->wrong_command = 1;
- return 0;
- }
- /* execute command */
- else if(params->is_word) {
- add_word(word_chain, tmp_word, params);
- params->is_word = 0;
- }
+ 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;
@@ -222,6 +238,7 @@ static int stream_redirect_tokens(struct queue *word_chain,
}
return 0;
}
+#endif
static void clean_input_buffer()
{
@@ -229,67 +246,109 @@ static void clean_input_buffer()
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)
+{
+ char **cmdline = malloc((word_counter + 1) * sizeof(char*));
+ w_queue_copy_words_to_args(word_chain, cmdline);
+ return cmdline;
+}
-static int special_tokens_allowed(int ch, struct param_type *params)
+int is_stream_redirection_set(const struct param_type *params)
{
- return (!filename_waiting(params) ||
- (filename_waiting(params) && params->is_word));
+ 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)
+{
+ char **cmdline = NULL;
+ if(is_stream_redirection_set(params) &&
+ wrong_streams_redirection(params)) {
+ /* TODO: add error codes */
+ params->wrong_command = 1;
+ return 0;
+ }
+ 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;
}
-static int special_tokens(struct dynamic_array *tmp_word, int ch,
- struct param_type *params)
+static int special_tokens(struct w_queue *word_chain,
+ struct c_queue *cmdlines,
+ struct dynamic_array *tmp_word, int ch,
+ struct param_type *params)
{
int next_ch;
next_ch = getchar();
ungetc(next_ch, stdin);
if(is_special_token(ch)) {
- if(special_tokens_allowed(ch, params)) {
- if(filename_waiting(params) && params->is_word) {
- add_filename(tmp_word, params);
- params->is_word = 0;
- }
- if(ch == '|')
- params->tokens = '|';
- 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 0;
- }
+ 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;
- } else {
- params->wrong_command = 1;
- fprintf(stderr, "filename expected\n");
+ params->tokens = '&';
}
+ if(is_double_token(params))
+ getchar();
+ return 1;
}
return 0;
}
+#endif
-static int special_token_handling(struct queue *word_chain,
- struct dynamic_array *tmp_word, int ch,
- struct param_type *params)
+static int special_token_handling(struct w_queue *word_chain,
+ struct c_queue *cmdlines,
+ struct dynamic_array *tmp_word, int ch,
+ struct param_type *params)
{
return
stream_redirect_tokens(word_chain, tmp_word, ch, params) ?
- 1 : special_tokens(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;
@@ -326,14 +385,7 @@ static int excessive_words(int ch, const struct param_type *params)
}
return 0;
}
-
-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;
-}
+#endif
static int is_cd_command(const char *arg)
{
@@ -364,14 +416,6 @@ static void change_directory(char **cmdline)
perror(path);
}
-static void clean_up_memory(struct queue *word_chain, char **cmdline,
- struct param_type *params)
-{
- queue_clear(word_chain);
- free(cmdline);
- clear_filename(params);
-}
-
static void open_files(const struct param_type *params, int *input_fd,
int *output_fd)
{
@@ -385,18 +429,57 @@ static void open_files(const struct param_type *params, int *input_fd,
O_APPEND, 0666);
}
-static void change_streams(int input_fd, int output_fd)
+static void change_streams(int input_fd, int output_fd, int is_pipeline,
+ int is_begin_pipeline)
{
- if(input_fd) {
+ if((!is_pipeline && input_fd) ||
+ (is_pipeline && is_begin_pipeline && input_fd)) {
dup2(input_fd, 0);
close(input_fd);
}
- if(output_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)
+{
+ int total_process_counter, current_process_counter, wait_pid;
+ total_process_counter = p_queue_get_process_quantity(pid_store);
+ current_process_counter = 0;
+
+ do {
+ wait_pid = wait(NULL);
+ if(p_queue_find_pid(pid_store, wait_pid))
+ ++current_process_counter;
+ } while(total_process_counter != current_process_counter);
+
+ /* return of background process zombie cleanup */
+ signal(SIGCHLD, handler);
+}
+
+static void clean_up_memory(struct w_queue *word_chain,
+ struct c_queue *cmdlines, struct param_type *params)
+{
+ w_queue_clear(word_chain);
+ c_queue_clear(cmdlines);
+ clear_filename(params);
+}
+
static void close_files(int input_fd, int output_fd)
{
if(input_fd)
@@ -405,17 +488,94 @@ static void close_files(int input_fd, int output_fd)
close(output_fd);
}
-static void run_external_program(struct queue *word_chain,
+static void postprocessing(struct w_queue *word_chain, struct c_queue *cmdlines,
+ struct p_queue *pid_store, struct param_type *params,
+ int input_fd, int output_fd)
+{
+ clean_up_memory(word_chain, cmdlines, params);
+ close_files(input_fd, output_fd);
+ if(params->tokens != '&')
+ wait_for_process_to_complete(pid_store);
+ p_queue_clear(pid_store);
+}
+
+static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines,
+ struct param_type *params,
+ int input_fd, int output_fd)
+{
+ struct p_queue pid_store;
+ p_queue_init(&pid_store);
+ char **cmdline = NULL;
+ int fd[2];
+ int save_read_fd, pid;
+
+ pipe(fd);
+ cmdline = c_queue_pop(cmdlines);
+ set_signal_disposition(params);
+ pid = fork();
+
+ if(pid == 0) {
+ close(fd[0]);
+ dup2(fd[1], 1);
+ close(fd[1]);
+ if(is_stream_redirection_set(params))
+ change_streams(input_fd, output_fd, 1, 1);
+ execvp(cmdline[0], cmdline);
+ perror(cmdline[0]);
+ exit(1);
+ }
+
+ close(fd[1]);
+ p_queue_push(&pid_store, pid);
+
+ while(!c_queue_is_empty(cmdlines)) {
+ cmdline = c_queue_pop(cmdlines);
+ /* if not last process in pipeline*/
+ if(!c_queue_is_empty(cmdlines)) {
+ save_read_fd = fd[0];
+ pipe(fd);
+ }
+ pid = fork();
+ if(pid == 0) {
+ if(!c_queue_is_empty(cmdlines)) {
+ dup2(save_read_fd, 0);
+ close(save_read_fd);
+ dup2(fd[1], 1);
+ close(fd[1]);
+ } else {
+ dup2(fd[0], 0);
+ close(fd[0]);
+ }
+ /* for last process in pipeline */
+ if(c_queue_is_empty(cmdlines))
+ if(is_stream_redirection_set(params))
+ change_streams(input_fd, output_fd, 1, 0);
+ execvp(cmdline[0], cmdline);
+ perror(cmdline[0]);
+ exit(1);
+ }
+ if(!c_queue_is_empty(cmdlines)) {
+ close(save_read_fd);
+ close(fd[1]);
+ } else
+ close(fd[0]);
+ p_queue_push(&pid_store, pid);
+ }
+ postprocessing(word_chain, cmdlines, &pid_store, params, input_fd,
+ output_fd);
+}
+
+static void run_external_program(struct w_queue *word_chain,
+ struct c_queue *cmdlines,
struct param_type *params)
{
- int pid, wait_pid, result, input_fd, output_fd;
+ int pid, input_fd, output_fd;
+ struct p_queue pid_store;
+ p_queue_init(&pid_store);
+ char **cmdline = NULL;
input_fd = 0;
output_fd = 0;
- if(word_chain->first == NULL) {
- fprintf(stderr, "empty command\n");
- return;
- }
if(is_stream_redirection_set(params))
open_files(params, &input_fd, &output_fd);
@@ -423,100 +583,131 @@ static void run_external_program(struct queue *word_chain,
perror("can't open file");
return;
}
- char **cmdline = create_cmdline(word_chain,
- queue_get_word_count(word_chain));
- if(is_cd_command(cmdline[0])) {
- change_directory(cmdline);
- clean_up_memory(word_chain, cmdline, params);
+ if(params->pipeline) {
+ make_pipeline(word_chain, cmdlines, params, input_fd, output_fd);
+ return;
}
+ cmdline = c_queue_pop(cmdlines);
+ if(is_cd_command(cmdline[0]))
+ change_directory(cmdline);
else {
+ set_signal_disposition(params);
pid = fork();
if(pid == -1) {
perror("fork error");
exit(1);
}
- 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);
-
/* child process */
if(pid == 0) {
if(is_stream_redirection_set(params))
- change_streams(input_fd, output_fd);
+ change_streams(input_fd, output_fd, 0, 0);
execvp(cmdline[0], cmdline);
params->last_execution_status = 1;
perror(cmdline[0]);
exit(1);
}
-
/* parent process */
- close_files(input_fd, output_fd);
- clean_up_memory(word_chain, cmdline, params);
-
- /* waiting for forground process by pid*/
- if(params->tokens != '&')
- do {
- wait_pid = wait(&result);
- } while(wait_pid != pid);
-
- /* return of background process zombie cleanup */
- signal(SIGCHLD, handler);
+ p_queue_push(&pid_store, pid);
+ postprocessing(word_chain, cmdlines, &pid_store, params, input_fd,
+ output_fd);
}
}
static void command_processing(struct param_type *params,
enum modes *current_mode,
- struct queue *word_chain,
+ struct w_queue *word_chain,
+ struct c_queue *cmdlines,
struct dynamic_array *tmp_word, int ch)
{
+ char **cmdline = NULL;
+
/* and odd number of double quotes */
if(!is_double_quotes_pair(*params)) {
print_error();
- reset_params(params, current_mode, word_chain, tmp_word);
+ reset_params(params, current_mode, word_chain, cmdlines, tmp_word);
show_invitation();
return;
}
+ if(filename_waiting(params)) {
+ if(params->wrong_command)
+ 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 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(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
+ } 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)
+ params->last_execution_status == 1) {
fprintf(stderr, "cannot be performed\n");
- else
- run_external_program(word_chain, params);
+ return;
+ }
+
+ if(word_chain->first == NULL) {
+ fprintf(stderr, "empty command\n");
+ goto clean;
+ }
+
+ cmdline = create_cmdline(word_chain, w_queue_get_word_count(word_chain));
+ c_queue_push(cmdlines, cmdline);
+ run_external_program(word_chain, cmdlines, params);
clean:
if(params->tokens == '&' || params->tokens == 0 || ch == new_line)
show_invitation();
- reset_params(params, current_mode, word_chain, tmp_word);
+ 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 queue *word_chain,
+ struct w_queue *word_chain,
+ struct c_queue *cmdlines,
struct dynamic_array *tmp_word)
{
/* could be a marker for the beginning of a blank word */
@@ -537,21 +728,22 @@ static void word_separation_processing(int ch, struct param_type *params,
params->escape_sequences = 1;
return;
}
- if(special_token_handling(word_chain, tmp_word, ch, params)) {
- if(!filename_waiting(params))
- command_processing(params, current_mode, word_chain, tmp_word, ch);
+ if(special_token_handling(word_chain, cmdlines, tmp_word, ch, params)) {
+ if(command_execution_condition(params))
+ command_processing(params, current_mode, word_chain, cmdlines,
+ tmp_word, ch);
return;
}
if(params->wrong_command) {
clean_input_buffer();
- reset_params(params, current_mode, word_chain, tmp_word);
+ reset_params(params, current_mode, word_chain, cmdlines, tmp_word);
show_invitation();
return;
}
if(check_separation(ch, *params)) {
if(excessive_words(ch, params)) {
clean_input_buffer();
- reset_params(params, current_mode, word_chain, tmp_word);
+ reset_params(params, current_mode, word_chain, cmdlines, tmp_word);
fprintf(stderr, "too many args\n");
show_invitation();
return;
@@ -565,11 +757,10 @@ static void word_separation_processing(int ch, struct param_type *params,
if(ignore_spaces(ch, *params))
return;
- dynarr_push_back(tmp_word, ch);
- params->is_word = 1;
- params->escape_sequences = 0;
+ 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 &&
@@ -581,10 +772,11 @@ 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 queue *word_chain,
+ struct w_queue *word_chain,
struct dynamic_array *tmp_word)
{
if(double_quotes_again(ch, *params)) {
@@ -613,29 +805,32 @@ static void whole_word_processing(int ch, struct param_type *params,
/* backslash recovery */
if(params->escape_sequences)
dynarr_push_back(tmp_word, backslash);
- dynarr_push_back(tmp_word, ch);
- params->is_word = 1;
- params->escape_sequences = 0;
+
+ add_letter(ch, tmp_word, params);
}
int main()
{
int ch;
struct param_type params;
- struct queue word_chain;
+ struct w_queue word_chain;
+ struct c_queue cmdlines;
struct dynamic_array tmp_word;
enum modes current_mode = word_separation;
- queue_init(&word_chain);
+
+ w_queue_init(&word_chain);
+ c_queue_init(&cmdlines);
dynarr_create_array(&tmp_word);
init_params(&params, &current_mode);
show_invitation();
+
while((ch = getchar()) != EOF) {
if(ch == new_line)
command_processing(&params, &current_mode, &word_chain,
- &tmp_word, ch);
+ &cmdlines, &tmp_word, ch);
else if(current_mode == word_separation)
word_separation_processing(ch, &params, &current_mode, &word_chain,
- &tmp_word);
+ &cmdlines, &tmp_word);
else if(current_mode == whole_word)
whole_word_processing(ch, &params, &current_mode, &word_chain,
&tmp_word);