Bläddra i källkod

Merge branch 'master' into myls

Loquicom 6 år sedan
förälder
incheckning
c36fbbe3dc
28 ändrade filer med 2601 tillägg och 105 borttagningar
  1. 3 1
      .gitignore
  2. 401 0
      command.c
  3. 167 0
      command.h
  4. 12 0
      constante.h
  5. 18 1
      error.c
  6. 9 1
      error.h
  7. 104 0
      execute.c
  8. 25 0
      execute.h
  9. 66 0
      expreg.c
  10. 50 0
      expreg.h
  11. 150 0
      ipc.c
  12. 74 0
      ipc.h
  13. 25 4
      makefile
  14. 313 52
      mysh.c
  15. 17 6
      mysh.h
  16. 63 16
      parser.c
  17. 1 1
      parser.h
  18. 140 0
      sem.c
  19. 71 0
      sem.h
  20. 126 0
      shm.c
  21. 63 0
      shm.h
  22. 7 3
      str.c
  23. 322 0
      subdiv.c
  24. 85 0
      subdiv.h
  25. 164 0
      variable.c
  26. 54 0
      variable.h
  27. 69 18
      wildcard.c
  28. 2 2
      wildcard.h

+ 3 - 1
.gitignore

@@ -53,4 +53,6 @@ dkms.conf
 /.directory
 /nbproject
 /mysh
-/mysh.log
+/mysh.log
+*.log
+/bug.txt

+ 401 - 0
command.c

@@ -0,0 +1,401 @@
+/* 
+ * File:   command.c
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "error.h"
+#include "str.h"
+#include "parser.h"
+#include "execute.h"
+#include "ipc.h"
+#include "variable.h"
+#include "command.h"
+#include "mysh.h"
+
+/* --- Extern --- */
+extern Error error;
+extern pid_t last;
+extern int status_cmd;
+extern int result_cmd;
+extern char base_path[];
+extern pid_list pidlist;
+char* cmdlist[] = {
+    "cd",
+    "exit",
+    "status",
+    "setenv",
+    "unsetenv",
+    "set",
+    "unset",
+    "myls",
+    "myps",
+    "myjobs",
+    NULL
+};
+boolean exitsh = false;
+
+/* --- Fonctions publiques --- */
+void ini_pid_list(pid_list* pl) {
+    pl->first = NULL;
+    pl->last = NULL;
+}
+
+pid_node* add_pid(pid_list* pl, pid_t pid, int job, char* cmd) {
+    int length;
+    //Creation noeud
+    pid_node* pn = malloc(sizeof (pid_node));
+    pn->pid = pid;
+    pn->job = job;
+    //Copie nom commande
+    length = strlen(cmd) + 1;
+    pn->cmd = malloc(sizeof(char) * length);
+    memset(pn->cmd, 0, length);
+    strncpy(pn->cmd, cmd, length - 1);
+    //Setup chainement
+    pn->next = NULL;
+    if (pl->first == NULL) {
+        pn->prev = NULL;
+        pl->first = pn;
+        pl->last = pn;
+    } else {
+        pn->prev = pl->last;
+        pl->last->next = pn;
+        pl->last = pn;
+    }
+    return pn;
+}
+
+pid_node* search_pid(pid_list* pl, pid_t pid) {
+    pid_node* pn = pl->first;
+    while (pn != NULL) {
+        if (pn->pid == pid) {
+            return pn;
+        }
+        pn = pn->next;
+    }
+    return NULL;
+}
+
+void remove_pid(pid_list* pl, pid_node* pn) {
+    free(pn->cmd);
+    //Si 1er et seul
+    if (pn->prev == NULL && pn->next == NULL) {
+        pl->first = NULL;
+        pl->last = NULL;
+    }
+    //Si 1er et non seul
+    else if (pn->prev == NULL && pn->next != NULL) {
+        pn->next->prev = NULL;
+        pl->first = pn->next;
+    }
+    //Si dernier
+    else if (pn->next == NULL) {
+        pn->prev->next = NULL;
+        pl->last = pn->prev;
+    }
+    //Sinon si il est au milieu
+    else {
+        pn->prev->next = pn->next;
+        pn->next->prev = pn->prev;
+    }
+    //Free
+    free(pn);
+}
+
+void clean_pid(pid_list* pl) {
+    pid_node* tmp, * pn = pl->first;
+    while (pn != NULL) {
+        tmp = pn->next;
+        free(pn->cmd);
+        free(pn);
+        pn = tmp;
+    }
+    pl->first = NULL;
+    pl->last = NULL;
+}
+
+boolean is_internal_cmd(const char* cmd) {
+    //Parcours tableau pour trouver correspondance
+    for (int i = 0; cmdlist[i] != NULL; i++) {
+        if (strncmp(cmd, cmdlist[i], strlen(cmd)) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+int launch_internal_command(Command* cmd) {
+    int result, length = strlen(cmd->name) + 1;
+    //cd
+    if (strncmp(cmd->name, cmdlist[0], length) == 0) {
+        result = cd(cmd->argc, cmd->argv);
+        return result;
+    }
+    //exit
+    else if (strncmp(cmd->name, cmdlist[1], length) == 0) {
+        result = exit_sh(cmd->argc, cmd->argv);
+        return result;
+    }        
+    //status
+    else if (strncmp(cmd->name, cmdlist[2], length) == 0) {
+        result = status(cmd->argc, cmd->argv);
+        return result;
+    }        
+    //setenv
+    else if (strncmp(cmd->name, cmdlist[3], length) == 0) {
+        result = set_env(cmd->argc, cmd->argv);
+        return result;
+    }        
+    //unsetenv
+    else if (strncmp(cmd->name, cmdlist[4], length) == 0) {
+        result = unset_env(cmd->argc, cmd->argv);
+        return result;
+    }
+    //set
+    else if (strncmp(cmd->name, cmdlist[5], length) == 0) {
+        result = set_local(cmd->argc, cmd->argv);
+        return result;
+    }        
+    //unset
+    else if (strncmp(cmd->name, cmdlist[6], length) == 0) {
+        result = unset_local(cmd->argc, cmd->argv);
+        return result;
+    }
+    //myls
+    else if (strncmp(cmd->name, cmdlist[7], length) == 0) {
+        result = myls(cmd->argc, cmd->argv);
+        return result;
+    }        
+    //myps
+    else if (strncmp(cmd->name, cmdlist[8], length) == 0) {
+        result = myps(cmd->argc, cmd->argv);
+        return result;
+    }   
+    //myjobs
+    else if (strncmp(cmd->name, cmdlist[9], length) == 0) {
+        result = myjobs(cmd->argc, cmd->argv);
+        return result;
+    }   
+    //Aucune commande
+    else {
+        return SHELL_FAIL;
+    }
+}
+
+/* --- Commandes --- */
+int cd(int argc, char** argv) {
+    //Si trop d'arguments
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    } else {
+        //Si aucun argument on va à la racine
+        if (argc == 1) {
+            if (chdir("/") == ERR) {
+                addperror("Erreur chdir()");
+                return EXIT_FAILURE;
+            }
+        }            
+        //Sinon on va dans le dossier indiqué par l'utilisateur
+        else {
+            if (chdir(argv[1]) == ERR) {
+                error.print("path does not exist\n");
+                return EXIT_FAILURE;
+            }
+        }
+    }
+    return EXIT_SUCCESS;
+    //show_current_dir("current working directory is: ", "\n");
+}
+
+int exit_sh(int argc, char** argv) {
+    exitsh = true;
+    return EXIT_SUCCESS;
+}
+
+int status(int argc, char** argv) {
+    if (!(last != -1 && status_cmd != -1)) {
+        error.print("Aucune commande executée\n");
+        return EXIT_FAILURE;
+    }
+    //En fonction du status
+    if (result_cmd == SHELL_FAIL) {
+        printf("%d terminé anormalement\n", last);
+    } else {
+        printf("%d terminé avec comme code de retour %d\n", last, status_cmd);
+    }
+    return EXIT_SUCCESS;
+}
+
+int set_env(int argc, char** argv) {
+    char* str, * key, * val;
+    int length, pos = 0;
+    //Verif les arguments
+    if (argc < 2) {
+        show_shm_data();
+        return EXIT_SUCCESS;
+    }
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    }
+    str = argv[1];
+    length = strlen(str);
+    //Verif que chaine est correcte
+    for (int i = 0; i < length; i++) {
+        if (str[i] == '=') {
+            break;
+        }
+        pos++;
+    }
+    if (pos >= length - 1) {
+        error.print("Argument invalide : clef=valeur attendu, %s donnée\n", str);
+        return EXIT_FAILURE;
+    }
+    //Decoupe la chaine
+    key = malloc(sizeof (char) * (pos + 1));
+    memset(key, 0, pos + 1);
+    strncpy(key, str, pos);
+    val = str + pos + 1;
+    //Ajoute la chaine en shm
+    if (!add_shm_data(str)) {
+        error.print("Erreur interne impossible d'ajouter la variable\n");
+        free(key);
+        return EXIT_FAILURE;
+    }
+    //Ajoute sur le système
+    if (setenv(key, val, true) == ERR) {
+        addperror("Impossible d'ajouter la variable d'environnement");
+        error.print("Erreur interne impossible d'ajouter la variable\n");
+        free(key);
+        return EXIT_FAILURE;
+    }
+    free(key);
+    return EXIT_SUCCESS;
+}
+
+int unset_env(int argc, char** argv) {
+    //Verif les arguments
+    if (argc < 2) {
+        error.print("too few arguments : 1 required, 0 given\n");
+        return EXIT_FAILURE;
+    }
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    }
+    //Supprime de la shm
+    if (!remove_shm_data(argv[1])) {
+        error.print("Erreur interne impossible de supprimer la variable\n");
+        return EXIT_FAILURE;
+    }
+    //Supprime du systeme
+    if (unsetenv(argv[1]) == ERR) {
+        addperror("Impossible de supprimer la variable d'environnement");
+        error.print("Erreur interne impossible de supprimer la variable\n");
+        return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
+
+int set_local(int argc, char** argv){
+    char* str;
+    int length, pos = 0;
+    //Verif les arguments
+    if (argc < 2) {
+        show_local_data();
+        return EXIT_SUCCESS;
+    }
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    }
+    str = argv[1];
+    length = strlen(str);
+    //Verif que chaine est correcte
+    for (int i = 0; i < length; i++) {
+        if (str[i] == '=') {
+            break;
+        }
+        pos++;
+    }
+    if (pos >= length - 1) {
+        error.print("Argument invalide : clef=valeur attendu, %s donnée\n", str);
+        return EXIT_FAILURE;
+    }
+    //Ajoute la chaine en shm
+    if (!add_local_data(str)) {
+        error.print("Erreur interne impossible d'ajouter la variable\n");
+        return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
+
+int unset_local(int argc, char** argv){
+    //Verif les arguments
+    if (argc < 2) {
+        error.print("too few arguments : 1 required, 0 given\n");
+        return EXIT_FAILURE;
+    }
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    }
+    //Supprime de la shm
+    if (!remove_local_data(argv[1])) {
+        error.print("Erreur interne impossible de supprimer la variable\n");
+        return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
+
+int myls(int argc, char** argv){
+    //Preparation nom cmd
+    int length = strlen(base_path);
+    char* path = malloc(sizeof(char) * (length + 4 + 1));
+    memset(path, 0, length + 4 + 1);
+    strncpy(path, base_path, length);
+    path[length] = '/';
+    path[length + 1] = 'm';
+    path[length + 2] = 'y';
+    path[length + 3] = 'l';
+    path[length + 4] = 's';
+    //Execution
+    //return exec_file(path, argv);
+    return 0;
+}
+
+int myps(int argc, char** argv){
+    //Preparation nom cmd
+    int length = strlen(base_path);
+    char* path = malloc(sizeof(char) * (length + 4 + 1));
+    memset(path, 0, length + 4 + 1);
+    strncpy(path, base_path, length);
+    path[length] = '/';
+    path[length + 1] = 'm';
+    path[length + 2] = 'y';
+    path[length + 3] = 'p';
+    path[length + 4] = 's';
+    //Execution
+    //return exec_file(path, argv);
+    return 0;
+}
+
+int myjobs(int argc, char** argv){
+    pid_node* pn = pidlist.first;
+    if(pn == NULL){
+        printf("Aucun job\n");
+        return EXIT_SUCCESS;
+    }
+    while(pn != NULL){
+        printf("[%d] %d En cours %s\n", pn->job, pn->pid, pn->cmd);
+        pn = pn->next;
+    }
+    return EXIT_SUCCESS;
+}

+ 167 - 0
command.h

@@ -0,0 +1,167 @@
+/* 
+ * File:   command.h
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/* --- Include --- */
+#include <sys/types.h>
+#include "constante.h"
+
+/* --- Structure --- */
+typedef struct pid_node pid_node;
+struct pid_node{
+    pid_t pid;
+    int job;
+    char* cmd;
+    pid_node* prev;
+    pid_node* next;
+};
+typedef struct{
+    pid_node* first;
+    pid_node* last;
+}pid_list;
+
+/* --- Extern --- */
+extern char* cmdlist[];
+extern boolean exitsh;
+
+/* --- Fonctions --- */
+/**
+ * Initialise la liste de PID
+ * @param pid_list* La liste de PID
+ */
+void ini_pid_list(pid_list*);
+
+/**
+ * Ajoute un PID dans la liste
+ * @param pid_list* La liste de PID
+ * @param pid_t Le pid
+ * @param int Le numero de job
+ * @param char* Le nom de la commande
+ * @return Le noeud crée
+ */
+pid_node* add_pid(pid_list*, pid_t, int, char*);
+
+/**
+ * Cherche un PID dans la liste
+ * @param pid_list* La liste de PID
+ * @param pid_t le PID
+ * @return Le noeud du pid
+ */
+pid_node* search_pid(pid_list*, pid_t);
+
+/**
+ * Supprime un PID de la liste
+ * @param pid_list* La liste de PID
+ * @param pid_node* Le noeud à supprimer
+ */
+void remove_pid(pid_list*, pid_node*);
+
+/**
+ * Vide la liste de PID
+ * @param pid_list* La liste de PID
+ */
+void clean_pid(pid_list*);
+
+/**
+ * Indique si un commande est une commande interne
+ * @param char* La commande
+ * @return Truu : oui / False : non
+ */
+boolean is_internal_cmd(const char*);
+
+/**
+ * Lance une commande intene
+ * @param Commande* La structure de la commande
+ * @return Le statut
+ */
+int launch_internal_command(Command*);
+
+/* --- Commandes --- */
+/**
+ * Change le dossier de travail actuel
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int cd(int, char**);
+
+/**
+ * Quitte le shell
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int exit_sh(int, char**);
+
+/**
+ * Statut de la dernière éxecution
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int status(int, char**);
+
+/**
+ * AJoute une variable d'environnement
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int set_env(int, char**);
+
+/**
+ * Supprime une variable d'environnement
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int unset_env(int, char**);
+
+/**
+ * Ajoute une variable locale
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int set_local(int, char**);
+
+/**
+ * Supprime une variable locale
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int unset_local(int, char**);
+
+/**
+ * Execute le programme myls
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int myls(int, char**);
+
+/**
+ * Execute le programma myps
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int myps(int, char**);
+
+/**
+ * Affiche tous les jobs
+ * @param int argc
+ * @param char** argv
+ * @return Statut
+ */
+int myjobs(int, char**);
+
+#endif /* COMMAND_H */
+

+ 12 - 0
constante.h

@@ -10,6 +10,7 @@
 
 /* --- General --- */
 #define BUFFER_SIZE 512
+#define MEM_SIZE 8192
 #define SHELL_ERR -1
 #define SHELL_FAIL 0
 #define SHELL_OK 1
@@ -19,6 +20,10 @@
 #define STDOUT 1
 #define STDERR 2
 
+/* --- Tube --- */
+#define TUBE_LECTURE 0
+#define TUBE_ECRITURE 1
+
 /* --- Separateur commande --- */
 #define SHELL_END 0 //Aucune autre commande après
 #define SHELL_NONE 1 //Aucun lien entre les 2 commandes
@@ -35,6 +40,13 @@
 #define SHELLR_ALL 5 // >>&
 #define SHELLRE_ALL 6 // >&
 
+/* --- IPC --- */
+#define IPCKEYPATH "/bin/ls"
+#define SEMCODE 8426
+#define SHMCODEMEM 8520 //Code shm zone des variables
+#define SHMCODEGEST 8521 //Code shm du gestionnaire de la zone des variables
+#define SHMCODEGLOB 8522 //Code shm des varaibles globales entre tous les processus mysh
+
 /* --- Boolean --- */
 #define boolean int
 #define true 1

+ 18 - 1
error.c

@@ -40,7 +40,7 @@ void end(){
     fprintf(stderr, "----- Fin log processus %d (temps en seconde : %ld) -----\n", getpid(), temps);
     //On remet la sortie standard des erreurs
     fd = redirect_fd(STDERR_FILENO, error.errfd);
-    if(error.errfd == ERR){
+    if(fd == ERR){
         adderror("Impossible de rediriger la sortie d'erreur standard");
         return;
     }
@@ -130,6 +130,23 @@ int redirect_fd(int fd1, int fd2){
     return tmpfd;
 }
 
+int redirect_fd2(int fd1, int fd2){
+    int tmpfd;
+    //On duplique le 1er fd
+    tmpfd = dup(fd1);
+    if(tmpfd == ERR){
+        addperror("Erreur pendant la duplication");
+        return ERR;
+    }
+    //On fait en sorte que fd1 soit lié au fichier de fd2
+    if(dup2(fd2, fd1) == ERR){
+        addperror("Erreur pendant le changement de fd");
+        return ERR;
+    }
+    //On retourne le nouveau fd de fd1
+    return tmpfd;
+}
+
 void error_init(){
     //Creation nom fichier puis initialisation
     char filename[19];

+ 9 - 1
error.h

@@ -60,11 +60,19 @@ extern Error error;
 /**
  * Change un fd par la valeur d'un autre fd
  * @param int fd accueil
- * @param int fd source
+ * @param int fd source fermé par la fonction
  * @return int Le nouveau fd du fichier qui avait le fd d'accueil
  */
 int redirect_fd(int, int);
 
+/**
+ * Change un fd par la valeur d'un autre fd
+ * @param int fd accueil
+ * @param int fd source
+ * @return int Le nouveau fd du fichier qui avait le fd d'accueil
+ */
+int redirect_fd2(int, int);
+
 /**
  * Initialise la gestion d'erreur
  * Le log sera nommé err-timestamp.log

+ 104 - 0
execute.c

@@ -0,0 +1,104 @@
+/* 
+ * File:   execute.c
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <wait.h>
+#include <string.h>
+#include "error.h"
+#include "execute.h"
+
+/* --- Extern --- */
+extern Error error;
+pid_t active = -1;
+pid_t last = -1;
+
+/* --- Fonctions publiques --- */
+boolean is_executable_file(const char * cmd) {
+    int result;
+    result = access(cmd, X_OK);
+    if(result == ERR){
+        return false;
+    }
+    return true;
+}
+
+int exec_shell(char* name, char** argv){
+    pid_t pid;  
+    int result;
+    //Fork pour l'exec
+    pid = fork();
+    if(pid == ERR){
+        addperror("Erreur lors du fork pour la commande execvp");
+        return EXIT_FAILURE;
+    }
+    //Fils
+    else if(pid == 0){
+        //Reset sortie erreur
+        result = redirect_fd(STDERR, error.errfd);
+        if(result == ERR){
+            adderror("Impossible de redefinir la sortie d'erreur standard");
+            exit(EXIT_FAILURE);
+        }
+        //Execute commande
+        execvp(name, argv);
+        //Si on arrive ici alors erreur
+        char* errmsg = "Erreur dans le fichier execute.c, fonction exec_shell : Impossible d'executer la commande\n";
+        if(write(result, errmsg, sizeof(char) * strlen(errmsg)) == ERR){
+            addperror("Impossible d'écrire dans le fichier de log");
+        }
+        fprintf(stderr, "Commande introuvable\n");
+        exit(EXIT_FAILURE);
+    }
+    //Pere
+    active = pid;
+    wait(&result);
+    last = pid;
+    active = -1;
+    //Retourne retour fils
+    if(WIFEXITED(result)){
+        return WEXITSTATUS(result);
+    }
+    return EXIT_FAILURE;
+}
+
+int exec_file(char* name, char** argv){
+    pid_t pid;  
+    int result;
+    //Fork pour l'exec
+    pid = fork();
+    if(pid == ERR){
+        addperror("Erreur lors du fork pour la commande execvp");
+        return EXIT_FAILURE;
+    }
+    //Fils
+    else if(pid == 0){
+        //Reset sortie erreur
+        result = redirect_fd(STDERR, error.errfd);
+        if(result == ERR){
+            adderror("Impossible de redefinir la sortie d'erreur standard");
+            exit(EXIT_FAILURE);
+        }
+        //Execute commande
+        execv(name, argv);
+        //Si on arrive ici alors erreur
+        addperror("Impossible d'executer la commande");
+        exit(EXIT_FAILURE);
+    }
+    //Pere
+    active = pid;
+    wait(&result);
+    last = pid;
+    active = -1;
+    //Retourne retour fils
+    if(WIFEXITED(result)){
+        return WEXITSTATUS(result);
+    }
+    return EXIT_FAILURE;
+}

+ 25 - 0
execute.h

@@ -0,0 +1,25 @@
+/* 
+ * File:   execute.h
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#ifndef EXECUTE_H
+#define EXECUTE_H
+
+/* --- Include --- */
+#include <sys/types.h>
+#include "constante.h"
+
+/* --- Extern --- */
+extern pid_t active;
+extern pid_t last;
+
+/* --- Fonctions publiques --- */
+boolean is_executable_file(const char *);
+int exec_shell(char*, char**);
+int exec_file(char*, char**);
+
+#endif /* EXECUTE_H */
+

+ 66 - 0
expreg.c

@@ -0,0 +1,66 @@
+/* 
+ * File:   expreg.c
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "expreg.h"
+
+/* --- Fonctions publiques --- */
+boolean ini_expreg(expreg* er, char* str, char* regex) {
+    //Setup regex
+    if (regcomp(&er->regex, regex, REG_EXTENDED) != 0) {
+        return false;
+    }
+    //Copie la chaine
+    int length = strlen(str);
+    er->str = malloc(sizeof (char) * (length + 1));
+    memset(er->str, 0, length + 1);
+    strncpy(er->str, str, length);
+    //Setup structure
+    er->pos = 0;
+    er->nmatch = er->regex.re_nsub;
+    er->pmatch = malloc(sizeof (regmatch_t) * er->nmatch);
+    return true;
+}
+
+char* get_match_expreg(expreg* er, int* deb, int* fin) {
+    if (regexec(&er->regex, er->str + er->pos, er->nmatch, er->pmatch, 0) != 0) {
+        if(deb != NULL){
+            *deb = -1;
+        }
+        if(fin != NULL){
+            *fin = -1;
+        }
+        return NULL;
+    }
+    //Recup info regex
+    int start = er->pmatch[0].rm_so;
+    int end = er->pmatch[0].rm_eo;
+    int length = end - start;
+    //Indique les positions
+    if(deb != NULL){
+        *deb = er->pos + start;
+    }
+    if(fin != NULL){
+        *fin = er->pos + end;
+    }
+    //Recup la chaine
+    char* str;
+    str = malloc(sizeof(char) * (length + 1));
+    memset(str, 0, length + 1);
+    strncpy(str, &er->str[er->pos + start], length);
+    //On avance dans la chaine
+    er->pos += end;
+    return str;
+}
+
+void clean_expreg(expreg* er) {
+    regfree(&er->regex);
+    free(er->str);
+    free(er->pmatch);
+}

+ 50 - 0
expreg.h

@@ -0,0 +1,50 @@
+/* 
+ * File:   expreg.h
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#ifndef EXPREG_H
+#define EXPREG_H
+
+/* --- Include --- */
+#include <regex.h>
+#include "constante.h"
+
+/* --- Structure --- */
+typedef struct{
+    char* str; //La chaine à vérifier
+    int pos; //Position actuel dans la chaine à verifier
+    regex_t regex;
+    size_t nmatch;
+    regmatch_t* pmatch;
+}expreg;
+
+/* --- Fonctions --- */
+/**
+ * Initialise la structure de gestion du regex
+ * @param expreg* La structure de l'expression reguliere
+ * @param char* La chaine à analyser
+ * @param char* Le regex
+ * @return Reussite
+ */
+boolean ini_expreg(expreg*, char*, char*);
+
+/**
+ * Recupere la prochaine correspondance dans la chaine
+ * @param expreg* La structure de l'expression reguliere
+ * @param int* La position de debut de la correspondance
+ * @param int* La postion de fin de la correspondance
+ * @return La correspondance ou NULL si il n'y en à plus
+ */
+char* get_match_expreg(expreg*, int*, int*);
+
+/**
+ * Vide la structure de l'expression reguliere
+ * @param expreg* La structure de l'expression reguliere
+ */
+void clean_expreg(expreg*);
+
+#endif /* EXPREG_H */
+

+ 150 - 0
ipc.c

@@ -0,0 +1,150 @@
+/* 
+ * File:   ipc.c
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "ipc.h"
+#include "variable.h"
+
+/* --- Extern --- */
+ipc_mysh ipc;
+extern int errno;
+
+/* --- Fonctions publiques --- */
+boolean setup_ipc(char** envp){
+    //boolean setup = true;
+    //SHM pour variable environnement
+    if(!create_shm(&ipc.memoire, SHMCODEMEM, MEM_SIZE)){
+        return false;
+    }
+    //SHM pour gestionnaire variable env
+    if(!create_shm(&ipc.gestionnaire, SHMCODEGEST, sizeof(subdiv))){
+        return false;
+    }
+    //SHM pour variable globale
+    if(!create_shm(&ipc.global, SHMCODEGLOB, sizeof(int))){
+        return false;
+    }
+    //Si creation alors on remplie les segments
+    if(errno != EEXIST){
+        subdiv* sd = (subdiv*) ipc.gestionnaire.adr;
+        char* mem = (char*) ipc.memoire.adr;
+        int* nb = (int*) ipc.global.adr;
+        ini_subdiv(sd);
+        int i = 0;
+	while(envp[i] != NULL){
+            add_fdata_subdiv(sd, mem, envp[i]);
+            i++;
+	}
+        *nb = 0;
+    }
+    //Semaphore
+    int ini[] = {1, 1, 1};
+    if(!create_sem(&ipc.sem, SEMCODE, 3, ini)){
+        return false;
+    }
+    return true;
+}
+
+boolean end_ipc(){
+    //Detache les shm
+    if(!unset_shm(&ipc.memoire)){
+        return false;
+    }
+    if(!unset_shm(&ipc.gestionnaire)){
+        return false;
+    }
+    if(!unset_shm(&ipc.global)){
+        return false;
+    }
+    //Tente de supprimer shm
+    if(delete_shm(&ipc.global)){
+        //Si on est le dernier processus en vie on supprime tous
+        if(!delete_shm(&ipc.memoire)){
+            return false;
+        }
+        if(!delete_shm(&ipc.gestionnaire)){
+            return false;
+        }
+        if(!delete_sem(&ipc.sem)){
+            return false;
+        }
+    }
+    return true;
+}
+
+char* parse_shm_var(char* str){
+    //Recup variable globale
+    subdiv* sd = (subdiv*) ipc.gestionnaire.adr;
+    char* mem = (char*) ipc.memoire.adr;
+    int* buf = (int*) ipc.global.adr;
+    int nb = *buf;
+    char* res;
+    //Regarde si l'ecrivain veut ecrire
+    P(&ipc.sem, SEMECRIRE);
+    V(&ipc.sem, SEMECRIRE);
+    //Modification variable globale
+    P(&ipc.sem, SEMMUTEX);
+    nb++;
+    if(nb == 1){
+        P(&ipc.sem, SEMWAIT);
+    }
+    V(&ipc.sem, SEMMUTEX);
+    //Lecture
+    res = parse_var(str, sd, mem);
+    //Modification variable globale
+    P(&ipc.sem, SEMMUTEX);
+    nb--;
+    if(nb == 0){
+        V(&ipc.sem, SEMWAIT);
+    }
+    V(&ipc.sem, SEMMUTEX);
+    return res;
+}
+
+boolean add_shm_data(char* data){
+    //Recup variable globale
+    subdiv* sd = (subdiv*) ipc.gestionnaire.adr;
+    char* mem = (char*) ipc.memoire.adr;
+    boolean res;
+    //Indique que l'on veut ecrire
+    P(&ipc.sem, SEMECRIRE);
+    //Attend que les lecteurs finissent
+    P(&ipc.sem, SEMWAIT);
+    //Ecriture
+    res = add_fdata_subdiv(sd, mem, data);
+    //Libere les semaphores
+    V(&ipc.sem, SEMWAIT);
+    V(&ipc.sem, SEMECRIRE);
+    return res;
+}
+
+boolean remove_shm_data(char* key){
+    //Recup variable globale
+    subdiv* sd = (subdiv*) ipc.gestionnaire.adr;
+    char* mem = (char*) ipc.memoire.adr;
+    boolean res;
+    //Indique que l'on veut ecrire
+    P(&ipc.sem, SEMECRIRE);
+    //Attend que les lecteurs finissent
+    P(&ipc.sem, SEMWAIT);
+    //Ecriture
+    res = remove_data_subdiv(sd, mem, key);
+    //Libere les semaphores
+    V(&ipc.sem, SEMWAIT);
+    V(&ipc.sem, SEMECRIRE);
+    return res;
+}
+
+void show_shm_data(){
+    //Recup variable globale
+    subdiv* sd = (subdiv*) ipc.gestionnaire.adr;
+    char* mem = (char*) ipc.memoire.adr;
+    //Affiche
+    show_data_subdiv(sd, mem);
+}

+ 74 - 0
ipc.h

@@ -0,0 +1,74 @@
+/* 
+ * File:   ipc.h
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#ifndef IPC_H
+#define IPC_H
+
+/* --- Include --- */
+#include "constante.h"
+#include "sem.h"
+#include "shm.h"
+#include "subdiv.h"
+
+/* --- Constantes --- */
+#define SEMMUTEX 0 //Mutex d'accès aux variables globales
+#define SEMECRIRE 1 //Sem pour indiquer qu'un processus veut ecrire
+#define SEMWAIT 2 //Sem pour faire attendre l'ecrivain
+
+/* --- Structure --- */
+typedef struct{
+    shared_mem memoire;
+    shared_mem gestionnaire;
+    shared_mem global;
+    semaphore sem;
+}ipc_mysh;
+
+/* --- Extern --- */
+extern ipc_mysh ipc;
+
+/* --- Fonctions --- */
+/**
+ * Création/Récupération SHM et SEM
+ * @param char** Envp pour la création
+ * @return Réussite
+ */
+boolean setup_ipc(char**);
+
+/**
+ * Destruction des SHM et SEM
+ * @return Reussite
+ */
+boolean end_ipc();
+
+/**
+ * Remplace les variables d'une chaine par leurs valeurs
+ * @param char* La chaine à analyser
+ * @return La chaine avec les variables remplacées par leur valeurs
+ */
+char* parse_shm_var(char*);
+
+/**
+ * Ajoute une données dans le segment de mémoire
+ * @param char* Les données à ajouter
+ * @return Reussite
+ */
+boolean add_shm_data(char*);
+
+/**
+ * Supprime une donnée dans le segment de mémoire
+ * @param char* La clef
+ * @return Reussite
+ */
+boolean remove_shm_data(char*);
+
+/**
+ * Affiche les variables dans la mémoire
+ */
+void show_shm_data();
+
+#endif /* IPC_H */
+

+ 25 - 4
makefile

@@ -3,7 +3,7 @@
 #
 
 EXEC = mysh myls
-OBJETS = error.o str.o parser.o wildcard.o
+OBJETS = error.o str.o parser.o wildcard.o command.o execute.o sem.o shm.o subdiv.o ipc.o expreg.o variable.o
 NOM_PROJET = mini-shell
 
 #
@@ -26,6 +26,7 @@ OBJETS_O = $(OBJETS) $(EXEC_O)
 CC = gcc
 CCFLAGS_STD = -Wall -O3 -Werror -ansi -pedantic -std=c11
 CCFLAGS_DEBUG = -D _DEBUG_
+CCFLAGS_VALGRIND = -Wall -O0 -ansi -pedantic -std=c11 -g 
 CCFLAGS = $(CCFLAGS_STD)
 CCLIBS =
 
@@ -46,6 +47,9 @@ msg:
 debug: CCFLAGS = $(CCFLAGS_STD) $(CCFLAGS_DEBUG)
 debug: all
 
+valgrind: CCFLAGS = $(CCFLAGS_VALGRIND)
+valgrind: all
+
 #
 # REGLES PAR DEFAUT
 #
@@ -63,6 +67,7 @@ clean:
 	@rm -f *~ *#
 	@rm -f $(EXEC)
 	@rm -f dependances
+	@rm -f *.log
 	@echo "Termine."
 
 depend:
@@ -75,6 +80,11 @@ depend:
 	@cat dependances > makefile
 	@rm dependances
 	@echo "Termine."
+	
+rm-log:
+	@echo "Suppression log..."
+	@rm -f *.log
+	@echo "Termine."
 
 #
 # CREATION ARCHIVE
@@ -88,8 +98,19 @@ archive: clean
 	@echo "Termine."
 
 # DEPENDANCES
-error.o: error.c error.h
+error.o: error.c str.h error.h
 str.o: str.c str.h
-parser.o: parser.c error.h wildcard.h constante.h parser.h str.h
+parser.o: parser.c error.h str.h wildcard.h constante.h ipc.h sem.h shm.h \
+ subdiv.h variable.h parser.h
 wildcard.o: wildcard.c error.h wildcard.h constante.h
-mysh.o: mysh.c error.h parser.h constante.h str.h mysh.h
+command.o: command.c error.h str.h parser.h constante.h execute.h ipc.h \
+ sem.h shm.h subdiv.h variable.h command.h mysh.h
+execute.o: execute.c error.h execute.h constante.h
+sem.o: sem.c error.h sem.h constante.h
+shm.o: shm.c error.h shm.h constante.h
+subdiv.o: subdiv.c subdiv.h constante.h
+ipc.o: ipc.c ipc.h constante.h sem.h shm.h subdiv.h variable.h
+expreg.o: expreg.c expreg.h constante.h
+variable.o: variable.c str.h expreg.h constante.h variable.h subdiv.h
+mysh.o: mysh.c error.h str.h parser.h constante.h command.h execute.h \
+ ipc.h sem.h shm.h subdiv.h mysh.h

+ 313 - 52
mysh.c

@@ -4,27 +4,35 @@
  *
  * Created on 31 octobre 2018, 12:43
  */
+#define _POSIX_C_SOURCE 2
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wait.h>
+#include <signal.h>
 #include "error.h"
 #include "str.h"
 #include "parser.h"
+#include "command.h"
+#include "execute.h"
+#include "ipc.h"
 #include "mysh.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
-
 /* --- Extern --- */
 extern Error error;
+extern boolean exitsh;
+extern pid_t active;
+int status_cmd = -1;
+int result_cmd = -1;
+char base_path[BUFFER_SIZE];
+pid_list pidlist;
 
-/* --- Fonctions privées --- */
-void test_write() {
-    char* a = "azerty\n";
-    int tmp = write(1, a, strlen(a));
-    printf("%d\n", tmp);
-}
+/* --- Globale --- */
+int job = 1;
 
 /* --- Fonctions utilitaires --- */
 void show_current_dir(const char* before, const char* after) {
@@ -42,63 +50,316 @@ void show_current_dir(const char* before, const char* after) {
             printf("%s%s%s", before, buffer, after);
         }
     }
+    fflush(stdout);
+}
+
+int get_line(char* buffer){
+    memset(buffer, 0, BUFFER_SIZE);
+    if(read(STDIN, buffer, BUFFER_SIZE) == ERR){
+        addperror("Impossible de lire dans STDIN");
+        return SHELL_ERR;
+    }
+    return SHELL_OK;
+}
+
+int get_tmp_file(){
+    FILE* f = tmpfile();
+    if(f == NULL){
+        adderror("Impossible de créer un fichier temporaire");
+        return SHELL_ERR;
+    }
+    return fileno(f);
 }
 
 /* --- Main --- */
-int main(int argc, char* argv[]) { 
+int main(int argc, char* argv[], char* envp[]) {
+    //Declaration variables
     CommandTab ct;
-    char str[BUFFER_SIZE];
-    int a;
-    //Initialisation erreur
-    error_finit("mysh.log");
-    //Recup ligne
-    //printf("%s\n", fgets(str, 500, stdin));&
-    memset(str, 0, 500);
-    a = read(STDIN, str, 500);
-    printf("%s\n", str);
-    //Separe les commandes
-    a = parse_line(&ct, str);
-    if(a == SHELL_ERR){
-        addserror("Erreur lors du parse de la ligne");
+    int result;
+    char line[BUFFER_SIZE], before[BUFFER_SIZE];
+    sigset_t sigs_new, sigs_old, sigs_block;
+    //Initialisation structures
+    error_init();
+    ini_pid_list(&pidlist);
+    //Recup chemain de base de l'application
+    if (getcwd(base_path, sizeof (base_path)) == NULL) {
+        addperror("Impossible de récuperer le chemin actuel");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    //Lancement ipc
+    if(!setup_ipc(envp)){
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    //Preparation affichage
+    sprintf(before, "\x1b[32m%s:\x1b[36m", getlogin());
+    //Traitement des signeaux
+    result = sigemptyset(&sigs_new);
+    if(result == ERR){	
+	addperror("Impossible de récuperer un ensemble de signaux vide");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
         error.exit_err();
     }
-    //Parse les commandes
-    a = parse_all_command(&ct);
-    if(a == SHELL_FAIL){
-        addserror("Erreur lors du parse des commandes");
+    //On bloque que sigchld
+    result = sigaddset(&sigs_new, SIGCHLD);
+    if(result == ERR){
+	addperror("Impossible d'ajouter SIGCHLD à l'ensemble de signaux");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
         error.exit_err();
     }
-    //Affiche resultat
-    for (int i = 0; i < ct.length; i++) {
-        Command* c = ct.cmd[i];
-        printf("Commande %d (%s) : \n", i, c->name);
-        for (int j = 0; j < c->argc; j++) {
-            printf("    Argument %d : %s\n", j, c->argv[j]);
+    result = sigprocmask(SIG_BLOCK, &sigs_new, &sigs_old);
+    if(result == -ERR){
+	addperror("Impossible de bloquer les signaux de l'ensemble");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    //Gestion interuption
+    signal(SIGINT, handler);
+    //Boucle infini de lecture
+    while(!exitsh){
+        //On regarde si un fils en fond est mort
+    	if(sigpending(&sigs_block) == ERR){
+                addperror("Impossible de recuperer les signaux en attentes");
+    	} else if(sigismember(&sigs_block, SIGCHLD)){
+                job--;
+    	}
+        //Affichage repertoire
+        show_current_dir(before, ">\x1b[0m ");      
+        //Lecture ligne
+        if(get_line(line) == SHELL_ERR){
+            //error.print("Impossible de lire les commandes\n");
+            continue;
+        }
+        //Parse la ligne et commandes
+        result = parse_line(&ct, line);
+        if(result == SHELL_ERR){
+            error.print("Impossible d'analyser la ligne\n");
+            addserror("Erreur lors du parse de la ligne");
+            continue;
+        }
+        //Si aucune commande on passe
+        if(ct.length == 0){
+            clean_command(&ct);
+            continue;
         }
-        printf("Commande en fond : %d\n\n", ct.bck);
+        //Parse les commandes
+        result = parse_all_command(&ct);
+        if(result == SHELL_FAIL){
+            error.print("Impossible d'analyser la commande\n");
+            addserror("Erreur lors du parse des commandes");
+            continue;
+        }
+        //Execute
+        result_cmd = run(ct, &status_cmd);
+        //Vide le resultat du parse de la ligne de commande
+        clean_command(&ct);
     }
-    //Supprime
-    clean_command(&ct);
-    error.exit();
+    //Nettoyage
+    if(!end_ipc()){
+        adderror("Impossible de terminer correctement les IPC");
+    }
+    clean_pid(&pidlist);
+    error.end();
+    return EXIT_SUCCESS;
 }
 
-/* --- Commandes internes --- */
-void cd(int argc, char** argv) {
-    //Si trop d'arguments
-    if (argc > 2) {
-        error.print("too many arguments : 1 required, %d given\n", argc - 1);
-    } else {
-        //Si aucun argument on va à la racine
-        if (argc == 1) {
-            if (chdir("/") == ERR) {
-                addperror("Erreur chdir()");
+int run(CommandTab ct, int* status){
+    pid_t pid;
+    int result = 0;
+    //Si en fond creation d'un fork pour executer les commandes
+    if(ct.bck){
+        pid = fork();
+        if(pid == ERR){
+            addperror("Erreur lors du fork pour l'execution des commandes");
+            error.print("Erreur systeme, impossible de continuer\n");
+            return SHELL_ERR;
+        }
+        //Fils
+        if(pid == 0){
+            int stat = 0;
+            ct.bck = 0;
+            //Ignore les sigint
+            signal(SIGINT, SIG_IGN);
+            //Lance commande
+            result = run(ct, &stat);
+            //Message de fin + retour
+            if(result == SHELL_FAIL){
+                printf("\n%s (jobs=[%d], pid=%d) terminée avec status=-1\n", ct.line, job, getpid());
+                exit(EXIT_FAILURE);
+            }
+            printf("\n%s (jobs=[%d], pid=%d) terminée avec status=%d\n", ct.line, job, getpid(), stat);
+            exit(EXIT_SUCCESS);
+        }
+        printf("[%d] %d\n", job, pid);
+        //Ajout du fils dans la liste des pid
+        add_pid(&pidlist, pid, job++, ct.line);
+        //Pour le pere c'est fini
+        return SHELL_OK;
+    }
+    //Sinon execution de chaque commande
+    Command* c;
+    int tube[ct.length][2];
+    int tubepos = 0;
+    int infd = -1, outfd = -1, errfd = -1;
+    boolean bpipe = false, skippipe = false, skip = false;
+    //Parcours les commandes
+    for(int i = 0; i < ct.length; i++){
+        c = ct.cmd[i];
+        //Si on skip
+        if(skip){
+            skip = false;
+            continue;
+        }
+        //Si pipe avant
+        if(skippipe){
+            //Si fin chaine pipe
+            if(c->next != SHELL_PIPE){
+                skippipe = false;
+            }
+            //Passe la commande
+            continue;
+        }
+        //Si pipe creation d'un fichier commun
+        skippipe = c->next == SHELL_PIPE ;
+        if(c->next == SHELL_PIPE && c->output == STDOUT){
+            skippipe = false;
+            bpipe = true;
+            //Creation tube
+            if(pipe(tube[tubepos]) == ERR){
+                addperror("Impossible de créer un tube");
+                return SHELL_FAIL;
             }
-        }            //Sinon on va dans le dossier indiqué par l'utilisateur
-        else {
-            if (chdir(argv[1]) == ERR) {
-                error.print("path does not exist\n");
+            //Redirection
+            c->output = tube[tubepos][TUBE_ECRITURE];
+            if(ct.cmd[i + 1]->input == STDIN){
+                ct.cmd[i + 1]->input = tube[tubepos][TUBE_LECTURE];
             }
         }
+        //Effectue les redirections IO
+        if(c->input != STDIN){
+            infd = redirect_fd2(STDIN, c->input);
+            if(infd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->output != STDOUT){
+            outfd = redirect_fd2(STDOUT, c->output);
+            if(outfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->error != STDERR){
+            errfd = redirect_fd2(STDERR, c->error);
+            if(errfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        //Execute la commande
+        if(is_internal_cmd(c->name)){
+            result = launch_internal_command(c);
+        } else if(is_executable_file(c->name)){
+            result = exec_file(c->name, c->argv);
+        } else {
+            result = exec_shell(c->name, c->argv);
+        }
+        //Si on a une variable pour stocker le status de retoure
+        if(status != NULL){
+            *status = result;
+        }
+        //Reset IO
+        if(c->input != STDIN){
+            infd = redirect_fd(STDIN, infd);
+            if(infd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->output != STDOUT){
+            outfd = redirect_fd(STDOUT, outfd);
+            if(outfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->error != STDERR){
+            errfd = redirect_fd(STDERR, errfd);
+            if(errfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        //Fermeture tube
+        if(bpipe){
+            bpipe = false;
+            if(close(outfd) == ERR){
+                addperror("Impossible de fermer tube ecriture");
+                return SHELL_FAIL;
+            }
+            if(close(c->output) == ERR){
+                addperror("Impossible de fermer tube ecriture");
+                return SHELL_FAIL;
+            }
+            c->output = STDOUT;
+        }
+        //Agit en fonction de la jointure avec la prochaine commande
+        if(c->next == SHELL_IF){
+            if(result != EXIT_SUCCESS){
+                skip = true;
+            }
+        } else if(c->next == SHELL_ELSE){
+            if(result == EXIT_SUCCESS){
+                skip = true;
+            }
+        }
+    }
+    if(result != EXIT_SUCCESS){
+        return SHELL_FAIL;
+    }
+    return SHELL_OK;
+}
+
+void handler(int sig){
+    char reponse = ' ';
+    pid_node* pn;
+    //Repositionne le gestionnaire (Ne marche plus apres 1 utilisation)
+    signal(SIGINT, handler);
+    //Si il y a un process actif on le coupe
+    if(active != -1){
+        if(kill(active, SIGINT) == ERR){
+            addperror("Impossible de tuer le processus en cours");
+        }
+        active = -1;
+        return;
+    }
+    //Sinon demande comfirmation pour finir le programme
+    while(reponse != 'o' && reponse != 'O' && reponse != 'n' && reponse != 'N'){
+        //Recup la valeur
+        printf("Voulez vous vraiment quitter ? [O/N] ");
+        if((reponse = getchar()) == EOF){
+            reponse = ' ';
+        }
+        //Vide l'entrée standard
+        while(getchar() != '\n');
+    }
+    //Si oui
+    if(reponse == 'n' || reponse == 'N'){
+        return;
     }
-    //show_current_dir("current working directory is: ", "\n");
+    //Coupe tous les processus en fond
+    pn = pidlist.first;
+    while(pn != NULL){
+        if(kill(pn->pid, SIGINT) == ERR){
+            addperror("Impossible de tuer le processus en fond");
+        }
+        pn = pn->next;
+    }
+    //Termine l'execution
+    if(!end_ipc()){
+        adderror("Impossible de terminer correctement les IPC");
+    }
+    clean_pid(&pidlist);
+    error.exit();
 }

+ 17 - 6
mysh.h

@@ -8,7 +8,13 @@
 #ifndef MYSH_H
 #define MYSH_H
 
-/* --- Fonctions utilitaires --- */
+/* --- Extern --- */
+extern int status_cmd;
+extern int result_cmd;
+extern char base_path[];
+extern pid_list pidlist;
+
+/* --- Fonctions --- */
 /**
  * Affiche le dossier de travail actuel
  * @param char* Chaine à afficher avant le dossier
@@ -16,13 +22,18 @@
  */
 void show_current_dir(const char*, const char*);
 
-/* --- Commandes internes --- */
 /**
- * Change le dossier de travail actuel
- * @param int argc
- * @param char** argv
+ * Execute l'ensemble des commandes d'une ligne
+ * @param CommandTab La ligne de commande parser
+ * @return Result
+ */
+int run(CommandTab, int*);
+
+/**
+ * Gestionnaire de signaux
+ * @param int Le type de singal reçu
  */
-void cd(int, char**);
+void handler(int);
 
 #endif /* MYSH_H */
 

+ 63 - 16
parser.c

@@ -15,6 +15,8 @@
 #include "error.h"
 #include "str.h"
 #include "wildcard.h"
+#include "ipc.h"
+#include "variable.h"
 #include "parser.h"
 
 /* --- Extern --- */
@@ -29,8 +31,13 @@ extern int serrno;
 int nb_commands(char* line){
     //Initialisation variable
     int compteur = 0;
+    boolean vide = true;
     //Parcours chaine pour chercher séparateur et compter le nombre de commande
     while(*line){
+        //Si on croise un caractère
+        if(vide && *line != ' ' && *line != '\0'){
+            vide = false;
+        }
         //Si un ;
         if(*line == ';'){
             compteur++;
@@ -69,7 +76,9 @@ int nb_commands(char* line){
         line++;
     }
     //Ajoute la dernière commande
-    compteur++;
+    if(!vide){
+        compteur++;
+    }
     return compteur;
 }
 
@@ -128,8 +137,6 @@ int get_command(Command* c, char* line){
     c->input = STDIN;
     c->output = STDOUT;
     c->error = STDERR;
-    c->erase[0] = false;
-    c->erase[1] = false;
     //Retour
     return length + separator;
 }
@@ -142,8 +149,17 @@ int get_command(Command* c, char* line){
  * @return int SHELL_OK si réussite, SHELL_ERR sinon
  */
 int set_io(Command* c, char* filename, int redir){
+    printf("Redir : %d\n", redir);
     //Declaration variable
     int file;
+    //Si fichier existe et on supprime
+    if((redir == SHELLRE_OUT || redir == SHELLRE_ERR || redir == SHELLRE_ALL) && access(filename, F_OK) != ERR){
+        if(unlink(filename) == ERR){
+            addperror("Impossible de supprimer le fichier");
+            serrno = SEOPENF;
+            return SHELL_ERR;
+        }
+    }
     //Ouverture du fichier
     file = open(filename, O_CREAT | O_RDWR, S_IRWXU);
     if(file == ERR){
@@ -151,6 +167,14 @@ int set_io(Command* c, char* filename, int redir){
         serrno = SEOPENF;
         return SHELL_ERR;
     }
+    //On se met à la fin du fichier si sortie ou erreur
+    if(redir != SHELLR_IN){
+        if(lseek(file, 0L, SEEK_END) == ERR){
+            addperror("Impossible de se deplacer dans le fichier");
+            serrno = SEOPENF;
+            return SHELL_ERR;
+        }
+    }
     //Analyse dans quel descripteur il doit etre mis
     switch(redir){
         case SHELLR_IN:
@@ -174,9 +198,6 @@ int set_io(Command* c, char* filename, int redir){
                 }
             }
             c->output = file;
-            if(redir == SHELLRE_OUT){
-                c->erase[STDOUT - 1] = true;
-            }
             break;
         case SHELLR_ERR:
         case SHELLRE_ERR:
@@ -188,9 +209,6 @@ int set_io(Command* c, char* filename, int redir){
                 }
             }
             c->error = file;
-            if(redir == SHELLRE_ERR){
-                c->erase[STDERR - 1] = true;
-            }
             break;
         case SHELLR_ALL:
         case SHELLRE_ALL:
@@ -209,10 +227,6 @@ int set_io(Command* c, char* filename, int redir){
             }
             c->output = file;
             c->error = file;
-            if(redir == SHELLRE_ALL){
-                c->erase[STDOUT - 1] = true;
-                c->erase[STDERR - 1] = true;
-            }
             break;
         default :
             serrno = SEREDIRTYPE;
@@ -270,7 +284,7 @@ int set_redirection(Command* c){
                                     return SHELL_ERR;
                                 }
                                 buffer++;
-                                redir = SHELLRE_ALL;
+                                redir = SHELLR_ALL;
                             }
                             //Sinon toujours >>
                             else {
@@ -419,6 +433,16 @@ int split_command(Command* c, char* cmd){
                 cmd++;
                 delim = '"';
             } 
+            //Cote
+            else if(*cmd == '\''){
+                //Verif que ce n'est pas la fin
+                if(!(*(cmd + 1))){
+                    serrno = SEBADCMD;
+                    return SHELL_ERR;
+                }
+                cmd++;
+                delim = '\'';
+            } 
             //Mot sans guillemet autour
             else {
                 length = 0;
@@ -454,6 +478,13 @@ int split_command(Command* c, char* cmd){
                 length = 0;
                 delim = '"';
             } 
+            //Cote
+            else if(*cmd == '\''){
+                cmd++;
+                deb = cmd;
+                length = 0;
+                delim = '\'';
+            }
             //Mot sans guillemet autour
             else {
                 deb = cmd;
@@ -477,7 +508,7 @@ int split_command(Command* c, char* cmd){
     if(chercheFin){
         c->argv[i] = malloc(sizeof(char) * (length + 1));
         memset(c->argv[i], 0, length + 1);
-        strncpy(c->argv[i++], deb, length);  
+        strncpy(c->argv[i++], deb, length); 
     }
     //Set la dernière case du tableau à null
     c->argv[i] = NULL;
@@ -496,6 +527,10 @@ int parse_line(CommandTab* ct, char* line){
         return SHELL_ERR;
     }
     //Initialisation structure
+    tmp = strlen(line);
+    ct->line = malloc(sizeof(char) * (tmp + 1));
+    memset(ct->line, 0, tmp + 1);
+    strncpy(ct->line, line, tmp);
     ct->cmd = malloc(sizeof(Command*) * compteur);
     ct->length = compteur;
     ct->bck = line[strlen(line) - 1] == '&';
@@ -520,7 +555,7 @@ int parse_line(CommandTab* ct, char* line){
 int parse_command(Command* c){
     //Declaration variable
     int length, nbWildcard = 0, res;
-    char* cmd, **wildcardTab;
+    char* cmd, * str, **wildcardTab;
     //Parse les redirections
     length = set_redirection(c);
     if(length == SHELL_ERR || length == 0){
@@ -532,6 +567,17 @@ int parse_command(Command* c){
     strncpy(cmd, c->cmd, length);
     //Split la commande
     split_command(c, cmd);
+    //Remplace variables
+    for(int i = 0; i < c->argc; i++){
+        str = parse_local_var(c->argv[i]);
+        free(c->argv[i]);
+        c->argv[i] = str;
+    }
+    for(int i = 0; i < c->argc; i++){
+        str = parse_shm_var(c->argv[i]);
+        free(c->argv[i]);
+        c->argv[i] = str;
+    }
     //Analyse wildcard
     for(int i = 0; i < c->argc; i++){
         //Regarde si il faut remplacer l'argument par une suite de fichier
@@ -605,4 +651,5 @@ void clean_command(CommandTab* ct){
     }
     //Met à 0 la taille du tableau
     ct->length = 0;
+    free(ct->line);
 }

+ 1 - 1
parser.h

@@ -20,11 +20,11 @@ typedef struct {
     int input; //Descripteur de fichier d'entré
     int output; //Descripteur de fichier de sortie
     int error; //Descripteur de fihier d'erreur
-    boolean erase[2]; //Si on efface le fichier
     int next; //Lien avec la prochaine commande
 } Command;
 
 typedef struct {
+    char* line; //La ligne de commande
     Command** cmd; //Tableau avec toutes les commandes
     int length; //Taille du tableau
     boolean bck; //Si l'ensemble de commande se fait en fond

+ 140 - 0
sem.c

@@ -0,0 +1,140 @@
+#define _XOPEN_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h> /* Constante option */
+#include <errno.h>
+#include "error.h"
+#include "sem.h"
+
+/* --- Extern --- */
+extern int errno;
+
+/* --- Fonctions privées --- */
+/**
+ * Initialise les semaphores
+ * @param semaphore* Le tableau de semaphore
+ * @param int La taille du tableau
+ * @param int* Valeur à initialiser
+ * @return boolean Reussite
+ */
+boolean ini_sem(semaphore* sem, int size, int* iniVal) {
+    /* Initialisation des valeurs */
+    for(int i = 0; i < size; i++){
+        if(semctl(sem->id, i, SETVAL, iniVal[i]) == ERR){
+            addperror("Impossible d'initialiser le tableau de semaphore");
+            return false;
+        }
+    }
+    /* Retour */
+    return true;
+}
+
+/* --- Fonctions publiques --- */
+boolean create_sem(semaphore* sem, int code, int nb, int* iniVal) {
+    int id;
+    /* Création du tableau */
+    key_t key = ftok(IPCKEYPATH, code);
+    if(key == ERR){
+        addperror("Impossible de générer la clef");
+        return false;
+    }
+    id = semget(key, nb, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
+    if (id == ERR) {
+        /* Si le tableau existe deja */
+        if (errno == EEXIST) {
+            adderror("Le tableau de sémaphore existe deja, tentaive de récupération");
+            return get_sem(sem, code);
+        }
+        /* Sinon erreur */
+        addperror("Impossible de créer le tableau de sémaphore");
+        return false;
+    }
+    /* Paramétrage de la structure */
+    sem->id = id;
+    sem->key = key;
+    sem->nb = nb;
+    /* Initialise semaphore */
+    return ini_sem(sem, nb, iniVal);
+}
+
+boolean get_sem(semaphore* sem, int code) {
+    int id;
+    struct semid_ds sem_buf;
+    /* Création du tableau */
+    key_t key = ftok(IPCKEYPATH, code);
+    if(key == ERR){
+        addperror("Impossible de générer la clef");
+        return false;
+    }
+    id = semget(key, 0, S_IRUSR | S_IWUSR);
+    if (id == ERR) {
+        /* Sinon erreur */
+        addperror("Impossible de récupèrer le tableau de sémaphore");
+        return false;
+    }
+    /* Récupération du nombre de semaphore */
+    if (semctl(id, 0, IPC_STAT, &sem_buf) == ERR) {
+        addperror("Impossible de récupèrer les informations du tableau de sémaphore");
+        return false;
+    }
+    /* Paramétrage de la structure */
+    sem->id = id;
+    sem->key = key;
+    sem->nb = sem_buf.sem_nsems;
+    /* Retour */
+    return true;
+}
+
+boolean P(semaphore* sem, int num) {
+    struct sembuf action;
+    /* Le num valide */
+    if (num < 0 || num > (sem->nb - 1)) {
+        adderror("Index tableau semaphore invalide");
+        return false;
+    }
+    /* Parametre sembuf */
+    action.sem_num = num;
+    action.sem_op = -1;
+    /* Puis je */
+    if (semop(sem->id, &action, 1) == ERR) {
+        addperror("Impossible d'effectuer P");
+        return false;
+    }
+    return true;
+}
+
+boolean V(semaphore* sem, int num) {
+    struct sembuf action;
+    /* Le num valide */
+    if (num < 0 || num > (sem->nb - 1)) {
+        adderror("Index tableau semaphore invalide");
+        return false;
+    }
+    /* Parametre sembuf */
+    action.sem_num = num;
+    action.sem_op = 1;
+    /* Vas y */
+    if (semop(sem->id, &action, 1) == ERR) {
+        addperror("Impossible d'effectuer V");
+        return false;
+    }
+    return true;
+}
+
+boolean delete_sem(semaphore* sem) {
+    /* Suppr */
+    if (semctl(sem->id, 0, IPC_RMID) == ERR) {
+        addperror("Impossible de supprimer le tableau de semaphore");
+        return false;
+    }
+    /* Reset struct */
+    sem->id = 0;
+    sem->key = 0;
+    sem->nb = 0;
+    return true;
+}
+
+int get_sem_value(semaphore* sem, int num){
+    return semctl(sem->id, num, GETVAL);
+}

+ 71 - 0
sem.h

@@ -0,0 +1,71 @@
+#ifndef SEM_H
+#define SEM_H
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "constante.h"
+
+/* --- Structures --- */
+
+typedef struct{
+	/* Id retourner par semget */
+	int id;
+	/* Clef d'acces au semaphores */
+	key_t key;
+	/* Nombre de semaphore */
+	int nb;
+}semaphore;
+
+/* --- Fonctions --- */
+
+/**
+ * Creation d'un tableau de semaphores
+ * @param semaphore* Le tableau de semaphore
+ * @param int La clef
+ * @param int Le nombre semaphores
+ * @param int* Valeur à initialiser
+ * @return boolean Reussite
+ */
+boolean create_sem(semaphore*, int, int, int*);
+
+/**
+ * Récuperation d'un tableau de semaphores
+ * @param semaphore* Le tableau de semaphore
+ * @param int La clef
+ * @return boolean Reussite
+ */
+boolean get_sem(semaphore*, int);
+
+/**
+ * Demande l'acces et decremente le semaphore (Puis je)
+ * @param semaphore* Le tableau de semaphore
+ * @param int Le numero de la semaphore
+ * @return boolean Reussite
+ */
+boolean P(semaphore*, int);
+
+/**
+ * Augmente le compteur d'une semaphore (Vas y)
+ * @param semaphore* Le tableau de semaphore
+ * @param int Le numero de la semaphore
+ * @return boolean Reussite
+ */
+boolean V(semaphore*, int);
+
+/**
+ * Supprime un tableau de semaphores
+ * @param semaphore* Le tableau de semaphore
+ * @return boolean Reussite
+ */
+boolean delete_sem(semaphore*);
+
+/**
+ * Récupère la valeur d'un semaphore
+ * @param semaphore* Le tableau de semaphore
+ * @param int Le numero du semaphore dans le tableau
+ * @return int La valeur actuel du semaphore
+ */
+int get_sem_value(semaphore*, int);
+
+#endif

+ 126 - 0
shm.c

@@ -0,0 +1,126 @@
+/* 
+ * File:   shm.c
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h> /* Constante option */
+#include <errno.h>
+#include "error.h"
+#include "shm.h"
+
+/* --- Extern --- */
+extern int errno;
+
+/* --- Fonctions prviées --- */
+
+/**
+ * Indique si il reste des processus utilsant le segment
+ * @param shared_mem* La mémoire partagée
+ * @return Peut ont supprimer ou non
+ */
+boolean can_delete_shm(shared_mem* shm){
+    struct shmid_ds buf;
+    /* Recup les infos de la mémoire */
+    if (shmctl(shm->id, IPC_STAT, &buf) == ERR) {
+        addperror("Impossible de récupérer les données du segment");
+        return false;
+    }
+    /* Verifie qu'il n'y a plus d'utilisateur actif */
+    return buf.shm_nattch == 0;
+}
+
+/* --- Fonctions publiques --- */
+boolean create_shm(shared_mem* shm, int code, int size) {
+    int id;
+    void* adr;
+    /* Création de la shm */
+    key_t key = ftok(IPCKEYPATH, code);
+    if (key == ERR) {
+        addperror("Impossible de générer la clef");
+        return false;
+    }
+    id = shmget(key, size, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
+    if (id == ERR) {
+        /* Si erreur existe deja appel get_shm */
+        if (errno == EEXIST) {
+            adderror("Le segment existe deja, tentative de récupération");
+            return get_shm(shm, code, size);
+        } else {
+            addperror("Impossible de créer la mémoire partagée");
+            return false;
+        }
+    }
+    /* On attache */
+    adr = shmat(id, NULL, 0);
+    if (adr == (void*) ERR) {
+        addperror("Impossible d'attacher le segment");
+        return false;
+    }
+    /* Initialisation de la structure */
+    shm->id = id;
+    shm->key = key;
+    shm->size = size;
+    shm->adr = adr;
+    return true;
+}
+
+boolean get_shm(shared_mem* shm, int code, int size) {
+    int id;
+    void* adr;
+    /* Création de la shm */
+    key_t key = ftok(IPCKEYPATH, code);
+    if (key == ERR) {
+        addperror("Impossible de générer la clef");
+        return false;
+    }
+    id = shmget(key, size, S_IRUSR | S_IWUSR);
+    if (id == ERR) {
+        addperror("Impossible de récupérer la mémoire partagée");
+        return false;
+    }
+    /* On attache */
+    adr = shmat(id, NULL, 0);
+    if (adr == (void*) ERR) {
+        addperror("Impossible d'attacher le segment");
+        return false;
+    }
+    /* Initialisation de la structure */
+    shm->id = id;
+    shm->key = key;
+    shm->size = size;
+    shm->adr = adr;
+    return true;
+}
+
+boolean unset_shm(shared_mem* shm){
+	/* On détache la shm */
+	if(shmdt(shm->adr) == ERR){
+		perror("Erreur lors du détachement de la mémoire ");
+		return false;
+	}
+	shm->adr = NULL;
+        shm->size = 0;
+	/* Retour */
+	return true;
+}
+
+boolean delete_shm(shared_mem* shm) {
+    /* Regarde si on peut supprimer */
+    if(!can_delete_shm(shm)){
+        adderror("Des processus utilisent encore le segment");
+        return false;
+    }
+    /* Supprime */
+    if (shmctl(shm->id, IPC_RMID, 0) == ERR) {
+        addperror("Impossible de supprimer le segment");
+        return false;
+    }
+    /* Reset la structure */
+    shm->id = 0;
+    shm->key = 0;
+    return true;
+}

+ 63 - 0
shm.h

@@ -0,0 +1,63 @@
+/* 
+ * File:   shm.h
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#ifndef SHM_H
+#define SHM_H
+
+/* --- Include --- */
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "constante.h"
+
+/* --- Structure --- */
+typedef struct{
+    //Id de shmget
+    int id;
+    //Clef d'accés à la shm
+    key_t key;
+    //Taille de la zone mémoire
+    int size;
+    //Pointeur vers la zone mémoire
+    void* adr;
+}shared_mem;
+
+/* --- Fonctions --- */
+/**
+ * Création d'un segment de mémoire partagée
+ * @param shared_mem* La mémoire partagée
+ * @param int La clef
+ * @param int La taille de la zone
+ * @return boolean Reussite
+ */
+boolean create_shm(shared_mem*, int, int);
+
+/**
+ * Création d'un segment de mémoire partagée
+ * @param shared_mem* La mémoire partagée
+ * @param int La clef
+ * @param int La taille de la zone
+ * @return boolean Reussite
+ */
+boolean get_shm(shared_mem*, int, int);
+
+/**
+ * Retire le segment de mémoire partagée
+ * @param shared_mem* La mémoire partagée
+ * @return boolean Reussite
+ */
+boolean unset_shm(shared_mem*);
+
+/**
+ * Supprime le segment de memoire partagée
+ * @param shared_mem* La mémoire partagée
+ * @return boolean Reussite
+ */
+boolean delete_shm(shared_mem*);
+
+#endif /* SHM_H */
+

+ 7 - 3
str.c

@@ -20,13 +20,15 @@ char* ltrim(char* str, char mask){
     }
     //Si aucun espace au debut
     if(cmpt == 0){
-        res = malloc(sizeof(char) * strlen(str));
+        res = malloc(sizeof(char) * (strlen(str) + 1));
+        memset(res, 0, strlen(str) + 1);
         strcpy(res, str);
         return res;
     }
     //Sinon creation nouvelle chaine
     res = malloc(sizeof(char) * (strlen(str) - cmpt + 1));
-    for(int i = 0, j = cmpt; i < (strlen(str) - cmpt); i++, j++){
+    memset(res, 0, strlen(str) - cmpt + 1);
+    for(int i = 0, j = cmpt; j < (strlen(str)); i++, j++){
         res[i] = str[j];
     }
     //Retour nouvelle chaine
@@ -43,13 +45,15 @@ char* rtrim(char* str, char mask){
     }
     //Si aucun espace au debut
     if(cmpt == strlen(str) - 1){
-        res = malloc(sizeof(char) * strlen(str));
+        res = malloc(sizeof(char) * (strlen(str) + 1));
+        memset(res, 0, strlen(str) + 1);
         strcpy(res, str);
         return res;
     }
     cmpt++;
     //Sinon creation nouvelle chaine
     res = malloc(sizeof(char) * (cmpt + 2));
+    memset(res, 0, cmpt + 2);
     for(int i = 0; i < cmpt; i++){
         res[i] = str[i];
     }

+ 322 - 0
subdiv.c

@@ -0,0 +1,322 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "subdiv.h" 
+
+/* --- Fonctions privées traitement valeurs --- */
+/**
+ * Indique si une chaine est la clef d'un noeud
+ * @param node* Le noeud
+ * @param char* La mémoire
+ * @param char* La clef
+ * @return true - Oui/false - Non
+ */
+boolean is_key(node* n, char* mem, char* key) {
+    int i, length = strlen(key);
+    //Verif que la clef correspond à celle en param
+    for (i = 0; i < length; i++) {
+        if (mem[i + n->start] != key[i]) {
+            return false;
+        }
+    }
+    //Verif que le caractere suivant est bien un =
+    if (mem[i + n->start] != '=') {
+        return false;
+    }
+    return true;
+}
+
+/**
+ * Cherche une clef
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ * @param char* La clef
+ * @return La node correspondante ou NULL si introuvable
+ */
+node* find_key(subdiv* sd, char* mem, char* key) {
+    int length = strlen(key) + 2; //Clef + = + taille min mot
+    node* n = NULL;
+    //Cherche la clef
+    for (int i = 0; i < MEM_SIZE / 2; i++) {
+        if (sd->use[i] && sd->mem[i].type == MEMSET && sd->mem[i].length >= length) {
+            //Regarde si la clef correspond
+            if (is_key(&sd->mem[i], mem, key)) {
+                n = &sd->mem[i];
+                break;
+            }
+        }
+    }
+    return n;
+}
+
+/**
+ * Récupère la valeur d'un noeid
+ * @param node* La noeud
+ * @param char* La mémoire
+ */
+char* parse_val(node* n, char* mem) {
+    int pos = 0;
+    //Cherche la postion du =
+    while (mem[pos + n->start] != '=') {
+        pos++;
+    }
+    pos++;
+    //Creation chaine
+    char* str = mem + n->start + pos;
+    char* val = malloc(sizeof (char) * (n->length - pos + 1));
+    memset(val, 0, n->length - pos + 1);
+    strncpy(val, str, n->length - pos);
+    //Retour
+    return val;
+}
+
+/* --- Fonctions privées nodes --- */
+
+boolean div_node(subdiv* sd, node* n) {
+    node* newn = NULL;
+    int i;
+    //Verif que la node à diviser est bien libre
+    if (n->type != MEMEMPTY) {
+        return false;
+    }
+    //Cherche une node libre
+    for (i = 0; i < MEM_SIZE; i++) {
+        if (sd->use[i] == 0) {
+            newn = &sd->mem[i];
+            break;
+        }
+    }
+    //Plus de place
+    if (newn == NULL) {
+        return false;
+    }
+    //Setup node
+    newn->index = i;
+    newn->start = n->start + (n->length / 2);
+    newn->end = n->end;
+    newn->length = n->length / 2;
+    newn->type = MEMEMPTY;
+    newn->prev = n->index;
+    newn->next = n->next;
+    //Modifie node suivant la nouvelle
+    if (n->next != -1 || n->next == n->index) {
+        sd->mem[n->next].prev = newn->index;
+    }
+    //Modifie node origine
+    n->end = n->start + (n->length / 2);
+    n->length /= 2;
+    n->next = newn->index;
+    //Indique que la node est utilisé
+    sd->use[i] = true;
+    return true;
+}
+
+boolean fusion_node(subdiv* sd, node* n) {
+    //Verif que la node et la node suivante sont vide
+    if (!(n->type == MEMEMPTY && n->next != -1 && sd->mem[n->next].type == MEMEMPTY)) {
+        return false;
+    }
+    node* n2 = &sd->mem[n->next];
+    //Verif qu'elles ont la meme taille
+    if (n->length != n2->length) {
+        return false;
+    }
+    //Met à jour la node
+    n->end = n2->end;
+    n->length *= 2;
+    n->next = n2->next;
+    if (n2->next != -1 || n2->next == n2->index) {
+        sd->mem[n2->next].prev = n->index;
+    }
+    //Indique que l'autre node n'est plus utilisée
+    sd->use[n2->index] = false;
+    return true;
+}
+
+/* --- Fonctions publiques --- */
+
+void ini_subdiv(subdiv* sd) {
+    sd->mem[0] = (node){0, 0, MEM_SIZE, MEM_SIZE, MEMEMPTY, -1, -1};
+    sd->use[0] = true;
+    for (int i = 1; i < MEM_SIZE / 2; i++) {
+        sd->use[i] = false;
+    }
+}
+
+boolean add_data_subdiv(subdiv* sd, char* mem, char* key, char* data) {
+    //Recup taille data
+    int length = strlen(data) + strlen(key) + 1;
+    //Cherche un espace ou mettre la données
+    node* n = &sd->mem[0];
+    while (n != NULL) {
+        if (n->type == MEMEMPTY && n->length >= length) {
+            break;
+        }
+        //Charge le prochain noeud
+        if(n->next == -1 || n->next == n->index){
+            n = NULL;
+        } else {
+            n = &sd->mem[n->next];
+        }
+    }
+    //Si plus de place
+    if (n == NULL) {
+        return false;
+    }
+    //Si on peut diviser par deux la place libre et stocker dedans
+    if ((n->length / 2) >= length) {
+        //On divise la zone en 2
+        if (!div_node(sd, n)) {
+            return false;
+        }
+        return add_data_subdiv(sd, mem, key, data);
+    }
+    //Genere chaine à mettre en mémoire
+    char* str = malloc(sizeof (char) * (length + 1));
+    memset(str, 0, length + 1);
+    snprintf(str, length + 1, "%s=%s", key, data);
+    //On maj la node
+    n->type = MEMSET;
+    n->length = length;
+    //On met dans la mémoire
+    for (int i = 0; i < length; i++) {
+        mem[i + n->start] = str[i];
+    }
+    //Nettoyage
+    free(str);
+    return true;
+}
+
+boolean add_fdata_subdiv(subdiv* sd, char* mem, char* data) {
+    //Recup taille data
+    int length = strlen(data);
+    //Cherche un espace ou mettre la données
+    node* n = &sd->mem[0];
+    while (n != NULL) {
+        if (n->type == MEMEMPTY && n->length >= length) {
+            break;
+        }
+        //Charge le prochain noeud
+        if(n->next == -1 || n->next == n->index){
+            n = NULL;
+        } else {
+            n = &sd->mem[n->next];
+        }
+    }
+    //Si plus de place
+    if (n == NULL) {
+        return false;
+    }
+    //Si on peut diviser par deux la place libre et stocker dedans
+    if ((n->length / 2) >= length) {
+        //On divise la zone en 2
+        if (!div_node(sd, n)) {
+            return false;
+        }
+        return add_fdata_subdiv(sd, mem, data);
+    }
+    //On maj la node
+    n->type = MEMSET;
+    n->length = length;
+    //On met dans la mémoire
+    for (int i = 0; i < length; i++) {
+        mem[i + n->start] = data[i];
+    }
+    return true;
+}
+
+char* get_data_subdiv(subdiv* sd, char* mem, char* key) {
+    node* n = find_key(sd, mem, key);
+    //Si pas trouvé la clef
+    if (n == NULL) {
+        return NULL;
+    }
+    //Recup valeur
+    return parse_val(n, mem);
+}
+
+boolean remove_data_subdiv(subdiv* sd, char* mem, char* key) {
+    node* n = find_key(sd, mem, key);
+    //Si pas trouvé la clef
+    if (n == NULL) {
+        return false;
+    }
+    //Marque la node comme vide
+    n->length = n->end - n->start;
+    n->type = MEMEMPTY;
+    //Tente la fusion des noeuds (Algo imparfait)
+    n = &sd->mem[0];
+    while (n != NULL) {
+        //On fusionne avec celui d'après si celui d'avant à une taille différente
+        if (n == &sd->mem[0]) {
+            if (fusion_node(sd, n)) {
+                n = &sd->mem[0];
+            } else {
+                //Charge le prochain noeud
+                if(n->next == -1 || n->next == n->index){
+                    n = NULL;
+                } else {
+                    n = &sd->mem[n->next];
+                }
+            }
+        } else if (sd->mem[n->prev].length != n->length) {
+            if (fusion_node(sd, n)) {
+                n = &sd->mem[0];
+            } else {
+                //Charge le prochain noeud
+                if(n->next == -1 || n->next == n->index){
+                    n = NULL;
+                } else {
+                    n = &sd->mem[n->next];
+                }
+            }
+        } else {
+            //Charge le prochain noeud
+            if(n->next == -1 || n->next == n->index){
+                n = NULL;
+            } else {
+                n = &sd->mem[n->next];
+            }
+        }
+    }
+    return true;
+}
+
+void show_subdiv(subdiv* sd) {
+    node* n = &sd->mem[0];
+    while (n != NULL) {
+        printf("Deb : %d, Fin : %d, Length : %d, Real length : %d, Use : %d\n", n->start, n->end, n->length, n->end - n->start, (int) n->type);
+        //Charge le prochain noeud
+        if(n->next == -1){
+            n = NULL;
+        } else {
+            n = &sd->mem[n->next];
+        }
+    }
+}
+
+void show_data_subdiv(subdiv* sd, char* mem){
+    boolean vide = true;
+    node* n = &sd->mem[0];
+    while (n != NULL) {
+        if(n->type == MEMSET){
+            vide = false;
+            char* str = malloc(sizeof(char) * (n->length + 1));
+            char* deb = mem + n->start;
+            memset(str, 0, n->length + 1);
+            strncpy(str, deb, n->length);
+            printf("%s\n", str);
+            free(str);
+        }
+        //Charge le prochain noeud
+        if(n->next == -1 || n->next == n->index){
+            n = NULL;
+        } else {
+            n = &sd->mem[n->next];
+        }
+    }
+    //Si vide
+    if(vide){
+        printf("Aucune variable en mémoire\n");
+    }
+}

+ 85 - 0
subdiv.h

@@ -0,0 +1,85 @@
+#ifndef subdiv_h
+#define subdiv_h
+
+/* --- Include --- */
+#include "constante.h"
+
+/* --- Constante --- */
+#define MEMEMPTY 0
+#define MEMSET 1
+
+/* --- Structures --- */
+typedef struct node node;
+struct node{
+	int index; //Index dans le tableau mem de subdiv
+	int start; //Pos debut (incluse)
+	int end; //Pos fin (non incluse)
+	int length; //Taille réellement utilisée
+	unsigned char type;
+	int prev; //Position de noeud d'avant
+	int next; //Position du prochain noeud
+};
+
+typedef struct{
+	node mem[MEM_SIZE / 2];
+	boolean use[MEM_SIZE / 2];
+}subdiv;
+
+/* --- Fonctions --- */
+/**
+ * Initialise la structure de gestion
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ */
+void ini_subdiv(subdiv*);
+
+/**
+ * Ajoute une donnée dans la mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ * @param char* La clef
+ * @param char* La valeur
+ * @return Réussite
+ */
+boolean add_data_subdiv(subdiv*, char*, char*, char*);
+
+/**
+ * Ajoute une donnée déjà formatée sour la forme clef=valeur en mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ * @param char* La donnée
+ * @return Réussite
+ */
+boolean add_fdata_subdiv(subdiv*, char*, char*); //add formated data
+
+/**
+ * Récupère une donnée dans la mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ * @param char* La clef
+ * @return Réussite
+ */
+char* get_data_subdiv(subdiv*, char*, char*);
+
+/**
+ * Supprime une donnée de la mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ * @param char* La clef
+ * @return Réussite
+ */
+boolean remove_data_subdiv(subdiv*, char*, char*);
+
+/**
+ * Affiche la répartition de la mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ */
+void show_subdiv(subdiv*);
+
+/**
+ * Affiche toutes les données de la mémoire
+ * @param subdiv* Le gestionnaire de mémoire par subdivision
+ * @param char* La mémoire
+ */
+void show_data_subdiv(subdiv*, char*);
+
+#endif 

+ 164 - 0
variable.c

@@ -0,0 +1,164 @@
+/* 
+ * File:   variable.c
+ * Author: Arthur Brandao
+ *
+ * Created on 21 décembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "str.h"
+#include "expreg.h"
+#include "variable.h"
+
+/* --- Extern --- */
+subdiv localsd;
+char localmem[MEM_SIZE];
+boolean ini = false;
+
+/* --- Fonctions publiques --- */
+char* parse_var(char* s, subdiv* sd, char* mem) {
+    expreg er;
+    int length, deb, fin, fin2 = 0, compteur = 0, index = 0;
+    boolean first = true;
+    char* str, * newstr;
+    //Cherche le nombre de clefs dans la chaine
+    length = strlen(s);
+    ini_expreg(&er, s, "(\\$[[:alnum:]_]+)");
+    while ((str = get_match_expreg(&er, &deb, &fin)) != NULL) {
+        //1er tour
+        if (first) {
+            //Si il y a du texte avant 
+            if (deb != 0) {
+                compteur++;
+            }
+            compteur++;
+            //Garde en memoire la pos de fin
+            fin2 = fin;
+            first = false;
+        }            
+        //Autre tours
+        else {
+            //Si il y a eu du texte entre les deux correspondances
+            if (deb != fin2) {
+                compteur++;
+            }
+            compteur++;
+            //Garde en memoire la pos de fin
+            fin2 = fin;
+        }
+        free(str);
+    }
+    //Si on n'est pas à la fin
+    if (fin2 != length) {
+        compteur++;
+    }
+    clean_expreg(&er);
+    //Création tableau
+    char** tab = malloc(sizeof(char*) * compteur);
+    //Sécoupe la chaine
+    first = true;
+    ini_expreg(&er, s, "(\\$[[:alnum:]_]+)");
+    while ((str = get_match_expreg(&er, &deb, &fin)) != NULL) {
+        //1er tour
+        if (first) {
+            //Si il y a du texte avant 
+            if (deb != 0) {
+                tab[index] = malloc(sizeof(char) * (deb + 1));
+                memset(tab[index], 0, deb + 1);
+                strncpy(tab[index], s, deb);
+                index++;
+            }
+            tab[index] = malloc(sizeof(char) * (fin - deb + 1));
+            memset(tab[index], 0, fin - deb + 1);
+            strncpy(tab[index], s + deb, fin - deb);
+            index++;
+            //Garde en memoire la pos de fin
+            fin2 = fin;
+            first = false;
+        }            
+        //Autre tours
+        else {
+            //Si il y a eu du texte entre les deux correspondances
+            if (deb != fin2) {
+                tab[index] = malloc(sizeof(char) * (deb - fin2 + 1));
+                memset(tab[index], 0, deb - fin2 + 1);
+                strncpy(tab[index], s + fin2, deb - fin2);
+                index++;
+            }
+            tab[index] = malloc(sizeof(char) * (fin - deb + 1));
+            memset(tab[index], 0, fin - deb + 1);
+            strncpy(tab[index], s + deb, fin - deb);
+            index++;
+            //Garde en memoire la pos de fin
+            fin2 = fin;
+        }
+        free(str);
+    }
+    //Si on n'est pas à la fin
+    if (fin2 != length) {
+        tab[index] = malloc(sizeof(char) * (length - fin2 + 1));
+        memset(tab[index], 0, length - fin2 + 1);
+        strncpy(tab[index], s + fin2, length - fin2);
+        index++;
+    }
+    clean_expreg(&er);
+    //Remplace les clef par leurs valeurs
+    for(int i = 0; i < compteur; i++){
+        if(tab[i][0] == '$'){
+            char* val = get_data_subdiv(sd, mem, tab[i] + 1);
+            if(val != NULL){
+                free(tab[i]);
+                tab[i] = val;
+            }
+        }
+    }
+    //Reconstruit la chaine
+    length = 0;
+    for(int i = 0; i < compteur; i++){
+        length += strlen(tab[i]);
+    }
+    newstr = malloc(sizeof(char) * (length + 1));
+    memset(newstr, 0, length + 1);
+    index = 0;
+    for(int i = 0; i < compteur; i++){
+        length = strlen(tab[i]);
+        for(int j = 0; j < length; j++){
+            newstr[index] = tab[i][j];
+            index++;
+        }
+        free(tab[i]);
+    }
+    free(tab);
+    return newstr;
+}
+
+char* parse_local_var(char* str){
+    if(!ini){
+        int length = strlen(str) + 1;
+        char* newstr = malloc(sizeof(char) * length);
+        memset(newstr, 0, length);
+        strncpy(newstr, str, length - 1);
+        return newstr;
+    }
+    return parse_var(str, &localsd, localmem);
+}
+
+boolean add_local_data(char* data){
+    if(!ini){
+        ini_subdiv(&localsd);
+        ini = true;
+    }
+    return add_fdata_subdiv(&localsd, localmem, data);
+}
+
+boolean remove_local_data(char* key){
+    if(!ini){
+        return false;
+    }
+    return remove_data_subdiv(&localsd, localmem, key);
+}
+
+void show_local_data(){
+    show_data_subdiv(&localsd, localmem);
+}

+ 54 - 0
variable.h

@@ -0,0 +1,54 @@
+/* 
+ * File:   variable.h
+ * Author: Arthur Brandao
+ *
+ * Gestion des variables locales
+ * 
+ * Created on 21 décembre 2018
+ */
+
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+/* --- Include --- */
+#include "constante.h"
+#include "subdiv.h"
+
+/* --- Fonctions --- */
+/**
+ * Remplace les variables par leur valeur dans une chaine
+ * @param char* La chaine à traiter
+ * @param subdiv* Le gestionnaire de memoir epar subdivision ou sont stocker les valeur
+ * @param char* La mémoire ou sont les valeurs
+ * @return La chaine avec les valeurs replacées
+ */
+char* parse_var(char*, subdiv*, char*);
+
+/**
+ * Remplace les variables d'une chaine par leurs valeurs
+ * @param char* La chaine à analyser
+ * @return La chaine avec les variables remplacées par leur valeurs
+ */
+char* parse_local_var(char*);
+
+/**
+ * Ajoute une données dans la mémoire locale
+ * @param char* Les données à ajouter
+ * @return Reussite
+ */
+boolean add_local_data(char*);
+
+/**
+ * Supprime une donnée dans la mémoire locale
+ * @param char* La clef
+ * @return Reussite
+ */
+boolean remove_local_data(char*);
+
+/**
+ * Affiche les variables dans la mémoire
+ */
+void show_local_data();
+
+#endif /* VARIABLE_H */
+

+ 69 - 18
wildcard.c

@@ -18,12 +18,45 @@
 #include "error.h"
 #include "wildcard.h"
 
-int wildcard_result(const char* seq) {
+/* --- Fonctions privées --- */
+
+/**
+ * Determine la position de separation entre le chemin et la wildcard
+ * @param char* La chaine
+ * @return int Position dans la chaine
+ */
+int wilcard_begin(const char* seq) {
+    int pos = 0, compteur = 1;
+    while (*seq) {
+        if (*seq == '/') {
+            pos = compteur;
+        }
+        seq++;
+        compteur++;
+    }
+    return pos;
+}
+
+/* --- Fonctions publiques --- */
+int wildcard_result(char* seq) {
     //Declaration variable
     struct dirent **namelist;
-    int nbFile, nbRes = 0;
+    int nbFile, nbRes = 0, wcpos;
+    char* wc, *path;
+    //Trouve la wildcard
+    wcpos = wilcard_begin(seq);
+    if (!wcpos) {
+        path = malloc(sizeof (char) * 2);
+        strcpy(path, ".");
+        wc = seq;
+    } else {
+        path = malloc(sizeof (char) * wcpos);
+        memset(path, 0, wcpos);
+        strncpy(path, seq, wcpos - 1); //Pour ne pas prendre le / final
+        wc = seq + wcpos;
+    }
     //Recup la liste des fichiers dans le dossier courant
-    nbFile = scandir(".", &namelist, 0, alphasort);
+    nbFile = scandir(path, &namelist, 0, alphasort);
     if (nbFile < 0) {
         addperror("Erreur scandir()");
         return ERR;
@@ -33,9 +66,9 @@ int wildcard_result(const char* seq) {
         //Si c'est bien un fichier (et non un dossier)
         if (namelist[nbFile]->d_type == DT_REG) {
             //Test par rapport au wildcard
-            if (fnmatch(seq, namelist[nbFile]->d_name, 0) == 0) {
+            if (fnmatch(wc, namelist[nbFile]->d_name, 0) == 0) {
                 //Regarde si le resultat est bien different de la wildcard
-                if (strcmp(seq, namelist[nbFile]->d_name) != 0) {
+                if (strcmp(wc, namelist[nbFile]->d_name) != 0) {
                     nbRes++;
                 }
             }
@@ -47,16 +80,29 @@ int wildcard_result(const char* seq) {
     return nbRes;
 }
 
-int wildcard(const char* seq, int size, char** result) {
+int wildcard(char* seq, int size, char** result) {
     //Declaration variable
     struct dirent **namelist;
-    int nbFile, nbRes = 0;
+    int nbFile, nbRes = 0, wcpos;
+    char* wc, *path;
     //Verification parametre
     if (size < 1) {
-        return ERR;
+        return -1;
+    }
+    //Trouve la wildcard
+    wcpos = wilcard_begin(seq);
+    if (!wcpos) {
+        path = malloc(sizeof (char) * 2);
+        strcpy(path, ".");
+        wc = seq;
+    } else {
+        path = malloc(sizeof (char) * wcpos);
+        memset(path, 0, wcpos);
+        strncpy(path, seq, wcpos - 1);
+        wc = seq + wcpos;
     }
     //Recup la liste des fichiers dans le dossier courant
-    nbFile = scandir(".", &namelist, 0, alphasort);
+    nbFile = scandir(path, &namelist, 0, alphasort);
     if (nbFile < 0) {
         addperror("Erreur scandir()");
         return ERR;
@@ -67,9 +113,17 @@ int wildcard(const char* seq, int size, char** result) {
         //Si c'est bien un fichier (et non un dossier)
         if (namelist[nbFile]->d_type == DT_REG) {
             //Test par rapport au wildcard
-            if (fnmatch(seq, namelist[nbFile]->d_name, 0) == 0) {
-                result[i] = malloc(strlen(namelist[nbFile]->d_name) * sizeof (char));
-                strcpy(result[i++], namelist[nbFile]->d_name);
+            if (fnmatch(wc, namelist[nbFile]->d_name, 0) == 0) {
+                //Si il y a un chemin
+                if (wcpos) {
+                    result[i] = malloc(sizeof (char) * (strlen(path) + strlen(namelist[nbFile]->d_name) + 2));
+                    memset(result[i], 0, strlen(path) + strlen(namelist[nbFile]->d_name) + 2);
+                    sprintf(result[i++], "%s/%s", path, namelist[nbFile]->d_name);
+                } else {
+                    result[i] = malloc(sizeof (char) * (strlen(namelist[nbFile]->d_name) + 1));
+                    memset(result[i], 0, strlen(namelist[nbFile]->d_name) + 1);
+                    sprintf(result[i++], "%s", namelist[nbFile]->d_name);
+                }
                 nbRes++;
             }
         }
@@ -118,8 +172,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (array[i] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(array[i]) * sizeof (char));
             strcpy(newarray[i], array[i]);
@@ -131,8 +184,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (insert[j] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(insert[j]) * sizeof (char));
             strcpy(newarray[i], insert[j]);
@@ -144,8 +196,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (array[j] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(array[j]) * sizeof (char));
             strcpy(newarray[i], array[j]);

+ 2 - 2
wildcard.h

@@ -19,7 +19,7 @@
  * @return int Le nombre de fichiers correspondant (0 si aucun ou si le nom du
  * fichier est identique à la sequence)
  */
-int wildcard_result(const char*);
+int wildcard_result(char*);
 
 /**
  * Recupere les fichiers correspondant à une sequence
@@ -29,7 +29,7 @@ int wildcard_result(const char*);
  * @return int Le nombre d'élement mis dans le tableau (ne depasse jamais la
  * capacité indiqué en paramètre)
  */
-int wildcard(const char*, int, char**);
+int wildcard(char*, int, char**);
 
 /**
  * Insert un tableau à la place d'une valeur d'un autre tableau