back to scratko.xyz
summaryrefslogtreecommitdiff
path: root/shell.c
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-05-25 21:36:07 +0300
committerscratko <m@scratko.xyz>2024-05-25 22:05:47 +0300
commitfb322edd72bebddee1a9828baec2f8bc83666ddf (patch)
treefab49e1e88ab1b3b20a45aba354b85b5fdafeff4 /shell.c
parentc1e5cffb43977f5a2f8d9623e40c01dab6d80c46 (diff)
downloadshell-fb322edd72bebddee1a9828baec2f8bc83666ddf.tar.gz
shell-fb322edd72bebddee1a9828baec2f8bc83666ddf.tar.bz2
shell-fb322edd72bebddee1a9828baec2f8bc83666ddf.zip
Shell-II releaseshell-II
Implementation of launching external programs via fork(). Running cd as a change to the current process directory (chdir). Ability to change to user's home directory (cd without arguments).
Diffstat (limited to 'shell.c')
-rw-r--r--shell.c86
1 files changed, 83 insertions, 3 deletions
diff --git a/shell.c b/shell.c
index f635c12..a1b5b29 100644
--- a/shell.c
+++ b/shell.c
@@ -2,6 +2,9 @@
#include "dynamic_array.h"
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
enum modes { word_separation, whole_word };
enum {
@@ -57,7 +60,8 @@ static int is_double_quotes_pair(struct param_type params)
static int check_separation(int ch, struct param_type params)
{
- return (ch == whitespace || ch == tab) && params.is_word && !params.escape_sequences;
+ return (ch == whitespace || ch == tab) && params.is_word &&
+ !params.escape_sequences;
}
static int ignore_spaces(int ch, struct param_type params)
@@ -87,6 +91,7 @@ static void add_word(struct queue *word_chain,
params->is_word = 0;
}
+#if 0
static void print_word(char *word)
{
putchar('[');
@@ -101,6 +106,77 @@ static void print_line(const struct queue *word_chain)
{
queue_processing(word_chain, print_word);
}
+#endif
+
+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;
+}
+
+static int check_cd(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 clean_up_memory(struct queue *word_chain, char **cmdline)
+{
+ queue_clear(word_chain);
+ free(cmdline);
+}
+
+static void run_external_program(struct queue *word_chain)
+{
+ int pid, result;
+ char **cmdline = create_cmdline(word_chain,
+ queue_get_word_count(word_chain));
+ if(check_cd(cmdline[0])) {
+ change_directory(cmdline);
+ clean_up_memory(word_chain, cmdline);
+ }
+ else {
+ pid = fork();
+ if(pid == -1) {
+ perror("fork error");
+ exit(1);
+ }
+ /* child process */
+ if(pid == 0) {
+ execvp(cmdline[0], cmdline);
+ perror(cmdline[0]);
+ exit(1);
+ }
+ /* parent process */
+ wait(&result);
+ clean_up_memory(word_chain, cmdline);
+ }
+}
static void new_line_processing(struct param_type *params,
enum modes *current_mode,
@@ -119,14 +195,18 @@ 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);
+#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)
{
- return (ch == whitespace || ch == tab) && !params.is_word && params.empty_word_flag;
+ return (ch == whitespace || ch == tab) && !params.is_word &&
+ params.empty_word_flag;
}
static void word_separation_processing(int ch, struct param_type *params,
@@ -198,6 +278,7 @@ static void whole_word_processing(int ch, struct param_type *params,
if(escape_double_quotes_or_backslash(ch, *params)) {
dynarr_push_back(tmp_word, ch);
params->escape_sequences = 0;
+ params->is_word = 1;
return;
}
if(start_escape_sequence(ch, *params)) {
@@ -235,7 +316,6 @@ int main()
&tmp_word);
}
putchar(new_line);
- queue_clear(&word_chain);
dynarr_clear(&tmp_word);
return 0;
}