From 07ae95a5af0105666fdb77bbc6651bc8e5f05411 Mon Sep 17 00:00:00 2001
From: Brandon Rodriguez <brodriguez8774@gmail.com>
Date: Thu, 2 Nov 2017 17:13:47 -0400
Subject: [PATCH] Add handling for redirection (< and > symbols)

---
 Main.c | 119 ++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 84 insertions(+), 35 deletions(-)

diff --git a/Main.c b/Main.c
index f382d96..a5fa59a 100644
--- a/Main.c
+++ b/Main.c
@@ -20,18 +20,24 @@
  *      ls -l | grep a | grep b | grep c | grep v
  *  appears to work with no issues or memory leaks.
  *
- * Adding a single & (seperated by spaces) at the end of a command enables backgrounding.
+ *  Adding a single & (seperated by spaces) at the end of a command enables backgrounding.
  *  The parent will create a child that runs off to do provided command.
  *  Parent will meanwhile forget about child and prompt for further input.
+ *
+ *  Redirecting with < or > will temporarily change input/output accordingly.
  */
 
 
 /**
  * Known Issues:
- *  Does not handle < or > symbols.
-
- *  Backgrounding slightly messes up user interface display.
+ *  Backgrounding may mess up user interface display.
  *  Should correct after inputing another command.
+ *
+ *  Combining backgrounding and redirection may cause a memory leak.
+ *  The combination may also result in unexpected handling.
+ *  To be perfectly blunt, I don't understand piping/duping nearly
+ *  enough to troubleshoot this behavior.
+ *  As it is, the standard piping/duping is still confusing.
  */
 
 
@@ -56,6 +62,7 @@
 
 // Import headers.
 #include <ctype.h>
+#include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -77,6 +84,10 @@ typedef struct{
     char*** argv;
 } makeargv_struct;
 int run_program;                // Holds if program should continue to run.
+int in_redir_bool;              // Holds if input redirection is denoted.
+char* in_redir_char;            // Input redirection variable.
+int out_redir_bool;             // Holds if output redirection is denoted.
+char* out_redir_char;           // Output redirection variable.
 char* user_input;               // Holds user input value.
 makeargv_struct* line_argv;     // Pointer to makeargv struct.
 makeargv_struct* command_argv;  // Pointer to/array of makeargv structs.
@@ -97,7 +108,7 @@ void set_umask();           // Sets umask value.
 void interupt_handler();    // Handler for ctrl+c signal.
 int check_for_backgrounding(); // Check for backgrounding (&) at end of input.
 void run_backgrounding();   // Runs child processes in background.
-void free_memory();         // Frees memory of vars.
+void check_for_redirection();   // Check for redirection (< or >) within input.
 void free_line_argv();      // Frees memory of line_argv.
 void free_command_argv();   // Frees memory of line_argv.
 
@@ -162,8 +173,9 @@ int main(int argc, char* argv[]) {
         user_input = get_user_input_with_prompt("");
         free(current_directory);
 
-        // Check for backgrounding.
+        // Check for backgrounding/redirection.
         backgrounding_bool = check_for_backgrounding();
+        check_for_redirection();
 
         // Run based on backgrounding bool.
         if (backgrounding_bool == 1) {
@@ -234,9 +246,11 @@ void main_loop() {
         } else {
             execute_command();
         }
-        //free_memory();
         free_command_argv();
         free_line_argv();
+    } else {
+        free(in_redir_char);
+        free(out_redir_char);
     }
 }
 
@@ -286,13 +300,30 @@ void parse_command() {
  * Start initial child pipe, then hand off to recursive function.
  */
 void execute_command() {
-    pid_t pid;
     int status;
+    int fd;
+    pid_t pid;
 
     // Check that there are any provided args.
     if (line_argv->argc > 0) {
+
         switch(pid = fork()) {
-            case 0:     // Child.
+            case 0:     // Child
+
+                // Check for input redirect.
+                if (in_redir_bool == 1) {
+                    fd = open(in_redir_char, O_RDONLY);
+                    free(in_redir_char);
+                    dup2(fd, STDIN_FILENO);
+                }
+
+                // Check for output redirect.
+                if (out_redir_bool == 1) {
+                    fd = open(out_redir_char, O_CREAT | O_APPEND | O_WRONLY, 0777);
+                    free(out_redir_char);
+                    dup2(fd, STDOUT_FILENO);
+                }
+
                 recursive_execute(line_argv->argc, command_argv, (line_argv->argc - 1));
                 break;
 
@@ -302,6 +333,17 @@ void execute_command() {
 
             default:    // Parent.
                 waitpid(pid, &status, 0);   // Wait for child process to end.
+
+                // Check for input redirect.
+                if (in_redir_bool == 1) {
+                    free(in_redir_char);
+                }
+
+                // Check for output redirect.
+                if (out_redir_bool == 1) {
+                    free(out_redir_char);
+                }
+
                 break;
         }
     }
@@ -356,7 +398,6 @@ void recursive_execute(int argc, makeargv_struct* args, int current_arg) {
 
         if (execvp(**temp_pointer->argv, *temp_pointer->argv) == -1) {
             err_msg("Invalid exec arg(s).");
-            //free_memory();
             free_command_argv();
             free_line_argv();
             exit(-1);
@@ -482,7 +523,6 @@ void interupt_handler() {
 int check_for_backgrounding() {
     int index = 0;
     int backgrounding_bool = 0;
-    char* token;
     char* temp_string;
 
     // Go to last index of string.
@@ -506,7 +546,7 @@ int check_for_backgrounding() {
 
     // If background char was found, seperate out token.
     if (backgrounding_bool == 1) {
-        token = strtok_r(user_input, "&", &temp_string);
+        strtok_r(user_input, "&", &temp_string);
     }
 
     return backgrounding_bool;
@@ -543,31 +583,40 @@ void run_backgrounding() {
 
 
 /**
- * Frees memory of main program variables.
+ * Checks for redirection (< or >) chars within input.
  */
-void free_memory() {
-    int index;
-    makeargv_struct* temp_pointer;
-    makeargv_struct* orig_pointer = command_argv;
-
-    index = 0;
-    // Free all of command_argv values.
-    while (line_argv->argc > 0) {
-        temp_pointer = command_argv;
-        ++temp_pointer;
-        free(*(*command_argv->argv));
-        free(*(command_argv->argv));
-        free(command_argv->argv);
-        command_argv = temp_pointer;
-        line_argv->argc--;
+void check_for_redirection() {
+    char* token;
+    char* temp_string;
+    char* redir_string;
+
+    // Check for input redirection.
+    temp_string = copy_string(user_input);
+    token = strtok_r(temp_string, "<", &redir_string);
+    if (strcmp(user_input, token) != 0) {
+        free(user_input);
+        user_input = copy_string(token);
+        in_redir_bool = 1;
+        in_redir_char = copy_string(redir_string);
+    } else {
+        in_redir_bool = 0;
+        //in_redir_char = calloc(1, sizeof(char));
+    }
+    free(temp_string);
+
+    // Check for output redirection.
+    temp_string = copy_string(user_input);
+    token = strtok_r(temp_string, ">", &redir_string);
+    if (strcmp(user_input, token) != 0) {
+        free(user_input);
+        user_input = copy_string(token);
+        out_redir_bool = 1;
+        out_redir_char = copy_string(redir_string);
+    } else {
+        out_redir_bool = 0;
+        //out_redir_char = calloc(1, sizeof(char));
     }
-    free(orig_pointer);
-
-    // Free line_argv values.
-    free(*(*(line_argv->argv + index)));
-    free(*(line_argv->argv));
-    free(line_argv->argv);
-    free(line_argv);
+    free(temp_string);
 }
 
 
-- 
GitLab