/* juin09-petitsh.c : petit shell en C - correction * * Edouard.Thiel@lif.univ-mrs.fr - 15/06/2009 * * Compilation : gcc -Wall -o juin09-petitsh juin09-petitsh.c * Usage : ./juin09-petitsh * * This program is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ #define _GNU_SOURCE /* pour avoir strndup */ #include #include #include #include #include #include #define LIGNE_MAX 4096 #define TARGS_MAX 256 int executer_une_com (char **v, char *af) { int p, status; if (v[0] == NULL) return 0; if (strcmp (v[0], "exit") == 0) exit (0); p = fork (); if (p < 0) { perror ("fork"); return 1; } if (p == 0) { /* Processus fils */ execvp (v[0], v); perror ("execvp"); exit (1); } /* Suite du pere */ if (af != NULL && af[0] == '&' && af[1] == 0) return 0; /* En tache de fond */ waitpid (p, &status, 0); /* Attend fin fils p */ return WEXITSTATUS (status); } int car_dans (char c, char *s) /* voir aussi: man strchr */ { int i; for (i = 0; s[i] != 0; i++) if (s[i] == c) return 1; return 0; } int chercher_arg (char *s, int *pos, int *debut, int *fin) { int i; char c; /* On saute les blancs */ for (i = *pos; s[i] != 0; i++) if (! car_dans (s[i], " \t")) break; c = s[i]; if (car_dans (c, ";&")) { /* Se'parateurs */ *debut = i; *fin = *pos = i+1; } else if (car_dans (c, "\"'")) { /* Chai^ne entre "" ou '' */ *debut = i+1; for (i = *debut; s[i] != 0; i++) if (s[i] == c) break; *fin = i; *pos = (s[i] == c) ? i+1 : i; return 1; /* RQ: "" est un argument */ } else { /* Autre argument ou vide */ *debut = i; for (i = *debut; s[i] != 0; i++) if (car_dans (s[i], " \t\n\"';&")) break; *fin = *pos = i; } return *debut == *fin ? 0 : 1; } void decouper_ligne (char *ligne, char **targs) { int i, pos = 0, debut, fin; for (i = 0; i < TARGS_MAX-1; i++) { if (chercher_arg (ligne, &pos, &debut, &fin) == 0) break; targs[i] = strndup (ligne+debut, fin-debut); } targs[i] = NULL; } int executer_commandes (char **targs) { char *v[TARGS_MAX]; int i, j, last = 0; i = 0; while (targs[i] != NULL) { /* Recopie de targs dans v jusqu'a` NULL ou ";" ou "&" */ for (j = 0; targs[i+j] != NULL; j++) { if (strcmp (targs[i+j], ";") == 0 || strcmp (targs[i+j], "&") == 0 ) break; v[j] = targs[i+j]; } v[j] = NULL; last = executer_une_com (v, targs[i+j]); if (targs[i+j] == NULL) break; i += j+1; } return last; } void liberer_targs (char **targs) { int j; for (j = 0; j < TARGS_MAX && targs[j] != NULL; j++) free (targs[j]); } int main (int argc, char *argv[]) { char ligne[LIGNE_MAX], *targs[TARGS_MAX]; int last = 0; while (1) { printf ("%d> ", last); fflush (stdout); if (fgets (ligne, LIGNE_MAX-1, stdin) == NULL) return 0; decouper_ligne (ligne, targs); last = executer_commandes (targs); liberer_targs (targs); } return 0; }