From 68411d3e3491f721ffefae770a6916e5712afccf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gendre?= <seb@k-7.ch>
Date: Mon, 18 May 2020 23:36:41 +0200
Subject: [PATCH] Start to implement the pipeline mechanism with a chained list
 of cmd_t

---
 src/command.c | 95 +++++++++++++++++++++++++++++++++++++++++++++------
 src/command.h | 33 ++++++++++++++----
 src/shell.c   |  9 ++---
 3 files changed, 115 insertions(+), 22 deletions(-)

diff --git a/src/command.c b/src/command.c
index ee4984a..bd5bf4e 100644
--- a/src/command.c
+++ b/src/command.c
@@ -3,10 +3,22 @@
 
 #include "command.h"
 
-int command_from_str(char *str, cmd_t *cmd) {
+cmd_t *command_from_str(char *str) {
 
-  // Stor next command argument, used in the do…while loop
+  char *str_copy = malloc((strlen(str)+1)*sizeof(char));
+  // Generate the command
+  cmd_t *cmd = malloc(sizeof(cmd_t));
+  // Store next command argument, used in the do…while loop
   char* next_arg;
+
+  // Work with a copy of the given str
+  strcpy(str_copy, str);
+  
+  // If malloc didn't work
+  if (cmd == NULL) {
+    perror("Malloc error for new command");
+    return (cmd_t *)NULL;
+  }
   
   // Initialize a simple command (empty, simple, foreground)
   cmd->type = JOB;
@@ -19,10 +31,10 @@ int command_from_str(char *str, cmd_t *cmd) {
 
     if (cmd->argc == 0) {
       // Extract the commmand name
-      next_arg = strtok(str, DELIMITERS);
+      next_arg = strtok(str_copy, ARGS_DELIMITERS);
     } else {
       // Get the next argument
-      next_arg = strtok(NULL, DELIMITERS);
+      next_arg = strtok(NULL, ARGS_DELIMITERS);
     }
     
     // Extend the cmd->argv array with a new char pointer
@@ -47,22 +59,83 @@ int command_from_str(char *str, cmd_t *cmd) {
   } else {
     cmd->type = JOB;
   }
-  
-  return 0;
+
+  return cmd;
+}
+
+
+/* Parse a string to get a pipeline of commands */
+cmd_t *command_pipeline_from_str(char *str){
+  char **commands = NULL;
+  char *next_command = NULL;
+  int commands_count = 0;
+  cmd_t *previous_command = NULL;
+  cmd_t *first_command = NULL;
+
+  // Cut str into a list of commands string
+  do {
+    if (commands_count == 0) {
+      // Extract the first command
+      next_command = strtok(str, COMMAND_PIPE_DELIMITER);
+    } else {
+      // Get the next command
+      next_command = strtok(NULL, COMMAND_PIPE_DELIMITER);
+    }
+
+    // Extend the command list to add a new command
+    commands = realloc(commands, (commands_count+1)*sizeof(char *));
+    if( commands == NULL) {
+      // In case the reallocation didn't work
+      die_errno("parse_command::realloc");
+    }
+
+    // Store the next command
+    commands[commands_count] = next_command;
+
+    if (next_command != NULL) {
+      // A now command has been added
+      commands_count += 1;
+    }
+    } while (next_command != NULL);
+
+  // For each command string, create a command struct
+  for (int i = 0; i < commands_count; ++i) {
+    if (previous_command == NULL) {
+      first_command = command_from_str(commands[i]);
+    } else {
+      previous_command->next = command_from_str(commands[i]);
+    }
+  }
+
+  return first_command;
 }
 
+
 // Dispose the commande
 void command_dispose(cmd_t *cmd) {
   // Free all the command arguments str inside argv
-  for (int i = 0; i < cmd->argc; ++i) {
-    free(cmd->argv[i]);
-  }
-  // Then, finally, free argv
+  /* for (int i = 0; i < cmd->argc; ++i) { */
+  /*   free(cmd->argv[i]); */
+  /* } */
+  // Free argv
   free(cmd->argv);
+  // Then, finally, free the command
+  free(cmd);
+}
+
+
+/* Fee a pipeline of command from the given command  */
+void command_free_pipeline(cmd_t *cmd) {
+  if (cmd->next != NULL) {
+    command_free_pipeline(cmd->next);
+  } else {
+    command_dispose(cmd);
+  }
 }
 
+
 // Execute the commande
-int command_exec(cmd_t *cmd) {
+int command_pipeline_exec(cmd_t *cmd) {
   switch (cmd->type) {
   case BUILTIN: {
     return builtin_exec_builtin_command(cmd->argc, cmd->argv);
diff --git a/src/command.h b/src/command.h
index c10254e..e8c7dac 100644
--- a/src/command.h
+++ b/src/command.h
@@ -13,7 +13,8 @@
 #include "jobs.h"
 
 // Chars used to separate atoms of a command
-#define  DELIMITERS " \t" 
+#define ARGS_DELIMITERS " \t"
+#define COMMAND_PIPE_DELIMITER "|"
 
 // Command types
 enum command_type {BUILTIN, JOB, PIZZA};
@@ -21,22 +22,33 @@ enum command_type {BUILTIN, JOB, PIZZA};
 // A full user command
 typedef struct cmd cmd_t;
 struct cmd {
-  enum command_type type; // Command type
+  enum command_type type;  // Command type
   char** argv;             // The command arguments
   int argc;                // Number of command arguments
   bool foreground;         // Should the command be run in foreground or background (might not be relevant for your TP depending on TP version)
+  cmd_t *next;             // Pointer to the next command, in case of pipe
 };
 
-/* Parse a user input to get a command
+/* Parse a string to get one command
 *  
 *  Parameters
-*  - user_input: A string containing the full command. IT WILL BE MODIFIED BY THE FUNCTION.
+*  - str: A string containing the full command. IT WILL BE MODIFIED BY THE FUNCTION.
 *  - cmd: Command updated from user input string (i.e. command input). MUST BE DISPOSED SEE FUNCTION dispose_command
 * 
 *  Return: 
-*  -1 in case of error otherwise 0.
+*   A pointer to the new command, NULL in case of error
 */
-int command_from_str(char *str, cmd_t *cmd);
+cmd_t *command_from_str(char *str);
+
+/* Parse a string to get a pipeline of commands
+*  
+*  Parameters
+*  - user_input: A string containing the full command. IT WILL BE MODIFIED BY THE FUNCTION.
+* 
+*  Return: 
+*  The pointer to the first command, NULL in case of error
+*/
+cmd_t *command_pipeline_from_str(char *str);
 
 
 /* Dispose of the command, which free some allocated memory
@@ -47,6 +59,13 @@ int command_from_str(char *str, cmd_t *cmd);
 */
 void command_dispose(cmd_t *cmd);
 
+/* Fee a pipeline of command from the given command 
+ * 
+ *  Parameters:
+ *  - cmd: The command start command of the pipeline to free
+*/
+void command_free_pipeline(cmd_t *cmd);
+
 /* Execute a given command as job or as builtin
  * 
  * Parameters:
@@ -55,7 +74,7 @@ void command_dispose(cmd_t *cmd);
  * Return:
  * - The command return code, 0 is success
  */
-int command_exec(cmd_t *cmd);
+int command_pipeline_exec(cmd_t *cmd);
 
 
 #endif /* COMMAND_H */
diff --git a/src/shell.c b/src/shell.c
index 738ab4a..79d4bc8 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -10,15 +10,16 @@
 
 int main(int argc, char *argv[])
 {
-  char * user_input;
-  cmd_t command;
+  char *user_input;
+  cmd_t *command_p;
   
   user_input = calloc(LIMIT_USER_INPUT_MAX_LENGTH, sizeof(char));
   
   while(1){
     interface_ask_user_input(user_input);
-    command_from_str(user_input, &command);
-    command_exec(&command);
+    command_p = command_pipeline_from_str(user_input);
+    command_pipeline_exec(command_p);
+    command_free_pipeline(command_p);
   }
   return 0;
 }
-- 
GitLab