/* * File: parser.c * Author: Arthur Brandao * * Created on 31 octobre 2018 */ #include #include #include #include #include "parser.h" /* --- Fonctions privées --- */ int nb_commands(char* line){ //Initialisation variable int compteur = 0; //Parcours chaine pour chercher séparateur et compter le nombre de commande while(*line){ //Si un ; if(*line == ';'){ compteur++; } //Si | ou || else if(*line == '|'){ //Verif que ce n'est pas le dernier carac if(*(line + 1) == '\0'){ return SHELL_ERR; } //Si un || on avance de 1 en plus else if(*(line + 1) == '|'){ //Si à la fin de la chaine if(*(line + 2) == '\0'){ return SHELL_ERR; } line++; } compteur++; } //Si un && if(*line == '&'){ //Si celui d'apres est bien un && if(*(line + 1) == '&'){ line++; compteur++; } //Sinon il doit y avoir un vide pour etre le & du bck ou un > avant else if(*(line + 1) != '\0' && *(line - 1) != '>'){ return SHELL_ERR; } } line++; } //Ajoute la dernière commande compteur++; return compteur; } /** * Recup la 1er commande * @param c Structure commande à initialiser * @param line Ligne avec la commande * @return int Le décallage à effectuer dans line */ int get_command(Command* c, char* line){ //Declaration variable char* deb = line, * old; int length = 0, separator = 0, next = SHELL_NONE; //Parcours chaine pour chercher un séparateur while(*line){ //Si un ; if(*line == ';'){ separator = 1; break; } //Si | ou || else if(*line == '|'){ //Si 1 ou 2 | if(*(line + 1) == '|'){ separator = 2; next = SHELL_ELSE; } else { separator = 1; next = SHELL_PIPE; } break; } //Si un && if(*line == '&'){ //Si celui d'apres est bien un && if(*(line + 1) == '&'){ separator = 2; next = SHELL_IF; break; } } length++; line++; } //Verif si c'est la dernière commande if(!*line){ next = SHELL_END; } //Allocation memoire et copie chaine c->cmd = malloc(sizeof(char) * (length + 1)); strncpy(c->cmd, deb, length); c->next = next; c->argc = 0; c->input = STDIN; c->output = STDOUT; c->error = STDERR; //Trim et supprime l'ancienne chaine old = c->cmd; c->cmd = rtrim(c->cmd, ' '); free(old); //Retour return length + separator; } /* --- Fonctions publiques --- */ int parse_line(CommandTab* ct, char* line){ //Declaration variable int compteur, tmp; //Nettoyage ligne line = trim(mtrim(line, '\n')); //Compte le nombre de commande dans la ligne compteur = nb_commands(line); if(compteur == SHELL_ERR){ return SHELL_ERR; } //Initialisation structure ct->cmd = malloc(sizeof(Command*) * compteur); ct->length = compteur; //Recupération de chaque commande for(int i = 0; i < compteur; i++){ ct->cmd[i] = malloc(sizeof(Command)); tmp = get_command(ct->cmd[i], line); line += tmp; //Si pas dernière commande on trim if(i + 1 < compteur){ line = ltrim(line, ' '); } } //Retour return SHELL_OK; } int parse_command(Command* c){ boolean guillemet = false; char* deb, * file, * buffer = c->cmd + 1; int redir = 0, compteur; //Parcours chaine while(*buffer){ //Repere redirection while(*buffer){ //Entrée if(*buffer == '<'){ //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } buffer++; redir = SHELLR_IN; break; } //Sortie else if (*buffer == '>'){ //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } else { buffer++; //Si >> if(*buffer == '>'){ //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } else { buffer++; //Si >>& if(*buffer == '&'){ //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } buffer++; redir = SHELLRE_ALL; } //Sinon toujours >> else { redir = SHELLR_OUT; } } } // Si >& else if(*buffer == '&'){ //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } redir = SHELLRE_ALL; buffer++; } //Sinon > else { redir = SHELLRE_OUT; } } break; } //Sortie erreur else if (*buffer == '2' && *(buffer - 1) == ' ' && *(buffer + 1) && *(buffer + 1) == '>'){ buffer++; //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } else { buffer++; //Si 2>> if(*buffer == '>'){ buffer++; //Si il n'y a rien apres if(!(*(buffer + 1))){ return SHELL_ERR; } redir = SHELLR_ERR; } //Sinon 2> else { redir = SHELLRE_ERR; } } break; } buffer++; } //On passe les espaces while(*buffer == ' '){ buffer++; } //Si on est à la fin de la chaine if(*buffer == '\0'){ return SHELL_ERR; } //Regarde si le nom du fichier est entre "" guillemet = *buffer == '"'; //Sauvegarde debut nom fichier deb = buffer; compteur = 0; //Lecture nom du fichier while(*buffer){ //Incremente compteur++; buffer++; //Test arret if(guillemet && *buffer == '"'){ break; } else if(!guillemet && (*buffer == '<' || *buffer == '>' || (*buffer == ' ' && *(buffer - 1) != '\\'))){ break; } } //Si fin de la commande et guillemet alors erreur if(!(*buffer) && guillemet){ return SHELL_ERR; } //Retire guillement si besoin if(guillemet){ deb++; compteur--; buffer++; } //Allocation file et copie nom fichier file = malloc(sizeof(char) * compteur); strncpy(file, deb, compteur); printf("%s %d %d\n", file, redir, guillemet); free(file); //Passe les espaces while(*buffer == ' '){ buffer++; } } return 1; } int parse_all_command(CommandTab* ct){ int tmp; for(int i = 0; i < ct->length; i++){ tmp = parse_command(ct->cmd[i]); if(tmp != SHELL_OK){ return SHELL_FAIL; } } return SHELL_OK; } void clean_command(CommandTab* ct){ extern int errno; //Vide le tableau for(int i = 0; i < ct->length; i++){ //Si la commande a été parsée on vide les arguments if(ct->cmd[i]->argc > 0){ ct->cmd[i]->name = NULL; for(int j = 0; j < ct->cmd[i]->argc; j++){ free(ct->cmd[i]->argv[j]); } } //Ferme les fichiers ouverts si besoin if(ct->cmd[i]->input != STDIN){ if(close(ct->cmd[i]->input)){ fprintf(stderr, "Erreur lors de la fermeture du fichier d'input de %s : %s", ct->cmd[i]->cmd, strerror(errno)); } } if(ct->cmd[i]->output != STDOUT){ if(close(ct->cmd[i]->output)){ fprintf(stderr, "Erreur lors de la fermeture du fichier d'output de %s : %s", ct->cmd[i]->cmd, strerror(errno)); } } if(ct->cmd[i]->error != STDERR){ if(close(ct->cmd[i]->error)){ fprintf(stderr, "Erreur lors de la fermeture du fichier d'error de %s : %s", ct->cmd[i]->cmd, strerror(errno)); } } //Supprime la ligne de commande free(ct->cmd[i]->cmd); //Supprime la structure free(ct->cmd[i]); } //Met à 0 la taille du tableau ct->length = 0; }