back to scratko.xyz
summaryrefslogtreecommitdiff
path: root/shell.c
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-05-26 17:09:25 +0300
committerscratko <m@scratko.xyz>2024-05-26 17:09:25 +0300
commit859c929333b0c17f1b6027b17cc30bdf4763e6e2 (patch)
tree3b6dfe7e03644927d078f2c386d48fe5bde47302 /shell.c
parentfb322edd72bebddee1a9828baec2f8bc83666ddf (diff)
downloadshell-III.tar.gz
shell-III.tar.bz2
shell-III.zip
Shell-III releaseshell-III
Added the ability to run programs in the background. Added tokens for future releases.
Diffstat (limited to 'shell.c')
-rw-r--r--shell.c110
1 files changed, 99 insertions, 11 deletions
diff --git a/shell.c b/shell.c
index a1b5b29..c03b62b 100644
--- a/shell.c
+++ b/shell.c
@@ -15,12 +15,21 @@ enum {
double_quotes = '"'
};
+/* two-letter tokens */
+enum {
+ append = '>' + 1,
+ and = '&' + 1,
+ or = '|' + 1
+};
+
struct param_type {
int is_word;
int escape_sequences;
unsigned int double_quotes_counter;
char stored_symbol;
int empty_word_flag;
+ int tokens;
+ int wrong_command;
};
static void show_invitation()
@@ -40,10 +49,12 @@ static void init_params(struct param_type *params, enum modes *current_mode)
params->double_quotes_counter = 0;
params->stored_symbol = ' ';
params->empty_word_flag = 0;
+ params->tokens = 0;
+ params->wrong_command = 0;
*current_mode = word_separation;
}
-static void prepare_new_line(struct param_type *params,
+static void reset_params(struct param_type *params,
enum modes *current_mode,
struct queue *word_chain,
struct dynamic_array *tmp_word)
@@ -64,6 +75,50 @@ static int check_separation(int ch, struct param_type params)
!params.escape_sequences;
}
+static int single_tokens(int ch)
+{
+ return ch == '<' || ch == ';' || ch == '(' || ch == ')';
+}
+
+static void clean_input_buffer()
+{
+ int ch;
+ while((ch = getchar() != new_line))
+ {}
+}
+
+static void double_tokens_and_fg(int ch, struct param_type *params)
+{
+ int next_ch;
+ next_ch = getchar();
+ ungetc(next_ch, stdin);
+ if(ch == '>' && next_ch == '>')
+ params->tokens = append;
+ else if(ch == '|' && next_ch == '|')
+ params->tokens = or;
+ else if(ch == '&' && next_ch == '&')
+ params->tokens = and;
+ else if(ch == '&') {
+ while((ch = getchar()) != new_line) {
+ if(ch != whitespace && ch != tab) {
+ fprintf(stderr, "incorrect command\n");
+ params->wrong_command = 1;
+ return;
+ }
+ }
+ params->tokens = '&';
+ }
+}
+
+static int check_tokens(int ch, struct param_type *params)
+{
+ if(single_tokens(ch))
+ params->tokens = ch;
+ else
+ double_tokens_and_fg(ch, params);
+ return params->tokens;
+}
+
static int ignore_spaces(int ch, struct param_type params)
{
return (ch == whitespace || ch == tab) && !params.escape_sequences;
@@ -87,7 +142,7 @@ static void add_word(struct queue *word_chain,
char *word = malloc(tmp_word->last_element_index+1);
dynarr_copy_array(tmp_word, word);
queue_push(word_chain, word);
- tmp_word->last_element_index = -1;
+ dynarr_drop_word(tmp_word);
params->is_word = 0;
}
@@ -151,9 +206,22 @@ static void clean_up_memory(struct queue *word_chain, char **cmdline)
free(cmdline);
}
-static void run_external_program(struct queue *word_chain)
+static void clean_up_zombie_process()
+{
+ int pid;
+ do {
+ pid = wait4(-1, NULL, WNOHANG, NULL);
+ } while(pid > 0);
+}
+
+static void run_external_program(struct queue *word_chain,
+ struct param_type *params)
{
- int pid, result;
+ int pid, wait_pid, result;
+ if(word_chain->first == NULL) {
+ fprintf(stderr, "empty command\n");
+ return;
+ }
char **cmdline = create_cmdline(word_chain,
queue_get_word_count(word_chain));
if(check_cd(cmdline[0])) {
@@ -173,12 +241,20 @@ static void run_external_program(struct queue *word_chain)
exit(1);
}
/* parent process */
- wait(&result);
+
clean_up_memory(word_chain, cmdline);
+
+ /* waiting for forground process */
+ if(params->tokens != '&') {
+ do {
+ wait_pid = wait(&result);
+ } while(wait_pid != pid);
+ } else
+ clean_up_zombie_process();
}
}
-static void new_line_processing(struct param_type *params,
+static void command_processing(struct param_type *params,
enum modes *current_mode,
struct queue *word_chain,
struct dynamic_array *tmp_word)
@@ -186,7 +262,7 @@ static void new_line_processing(struct param_type *params,
/* and odd number of double quotes */
if(!is_double_quotes_pair(*params)) {
print_error();
- prepare_new_line(params, current_mode, word_chain, tmp_word);
+ reset_params(params, current_mode, word_chain, tmp_word);
show_invitation();
return;
}
@@ -195,12 +271,13 @@ static void new_line_processing(struct param_type *params,
dynarr_push_back(tmp_word, '\0');
add_word(word_chain, tmp_word, params);
}
- run_external_program(word_chain);
+ run_external_program(word_chain, params);
+ if(params->tokens == '&' || params->tokens == 0)
+ show_invitation();
+ reset_params(params, current_mode, word_chain, tmp_word);
#if 0
print_line(word_chain);
#endif
- prepare_new_line(params, current_mode, word_chain, tmp_word);
- show_invitation();
}
static int is_empty_word(int ch, struct param_type params)
@@ -232,6 +309,16 @@ static void word_separation_processing(int ch, struct param_type *params,
params->escape_sequences = 1;
return;
}
+ if(check_tokens(ch, params)) {
+ command_processing(params, current_mode, word_chain, tmp_word);
+ return;
+ }
+ if(params->wrong_command) {
+ clean_input_buffer();
+ reset_params(params, current_mode, word_chain, tmp_word);
+ show_invitation();
+ return;
+ }
if(check_separation(ch, *params)) {
add_word(word_chain, tmp_word, params);
params->is_word = 0;
@@ -305,8 +392,9 @@ int main()
init_params(&params, &current_mode);
show_invitation();
while((ch = getchar()) != EOF) {
+ clean_up_zombie_process();
if(ch == new_line)
- new_line_processing(&params, &current_mode, &word_chain,
+ command_processing(&params, &current_mode, &word_chain,
&tmp_word);
else if(current_mode == word_separation)
word_separation_processing(ch, &params, &current_mode, &word_chain,