/** * * @File : exo_06.cxx * * @Authors : A. B. Dragut * * @Date : 2012 * * @Synopsis : emulation de la fonction systeme * * **/ #include #include #include #include // atoi() #include // memcpy(), strspn(), strcspn(), strlen() #include // system() #include #include "CExc.h" #include "nsSysteme.h" // Fork(), Signal() using namespace std; using namespace nsSysteme; // Fork(), Signal() namespace{ char **extractionLexemes(const char *const commande, const char *const separateurs) { // cette fonction analyse la chaine 'commande' fournie en entree pour en // separer les lexemes (tokens) selon les caracteres donnes dans 'separateurs' // de plus, elle alloue de la memoire (juste ce qu'il faut), et rend un pointeur // vers cette zone; c'est au code qui l'appelle de liberer ensuite la memoire // lorsqu'il n'y en a plus besoin, utilisant bien entendu 'free()' // la zone memoire ainsi allouee et rendue est organisee en deux region differentes, // une apres l'autre: elle commence avec une suite de char *, chacun pointant vers // le debut d'un lexeme, finissant avec un pointeur null. ensuite se trouve une autre // region, qui contient les lexemes proprement-dits (copies depuis 'commande') // la taille de cette zone memoire est donc donnee par le nombre de lexemes + 1 (pour // les pointeurs, donc *sizeof(char*), et par la longueur de 'commande' plus un, etant // la somme de ces deux nombres. size_t lexemes = 0; size_t longueur; char *memEcrit; char **tabLexemes; size_t i, n; const char *cmd, *p; if (!commande || !separateurs || !*commande || !*separateurs) { return NULL; // donc si les entrees sont vides, etc. } cmd = commande + strspn(commande, separateurs); // ignorer les separateurs du debut longueur = strlen(cmd); // ce sera l'espace requis pour la commande proprement-dite if (longueur < 1) { return NULL; // donc encore une fois si l'entree n'a pas de commande } // Nous allons d'abord apprendre combien d'elements (lexemes -- tokens) il y a p = cmd; while (*p) { lexemes++; p += strcspn(p, separateurs); // on saute le lexeme p += strspn(p, separateurs); // et on saute le ou les separateurs } // On alloue toute la memoire dont on a besoin: les pointeurs et le texte lui-meme memEcrit = (char *)malloc((lexemes + 1) * sizeof (char *) + longueur + 1); // avec le // pointeur null et avec le \0 a la fin tabLexemes = (char **)memEcrit; // et ce sera ce qu'on rend en sortie memEcrit += (lexemes + 1) * sizeof (char *); // maintenant on se met au debut de la zone // qui contiendra les lexemes, un apres l'autre, termines chacun par un \0 for (i = 0; i < lexemes; i++) { // grande boucle pour traiter chaque lexeme // cmd pointera sur le lexeme a lire pour traitement dans cette iteration // memEcrit pointe vers la destination d'ecriture du lexeme tabLexemes[i] = memEcrit; // ceci est le debut du lexeme -- on l'enregistre n = strcspn(cmd, separateurs); // ceci est la longueur de ce lexeme if (n > 0) { // on copie tout le lexeme dans la zone memoire destination memcpy(memEcrit, cmd, n); } memEcrit[n] = '\0'; // et on le termine "a la main" avec le \0 memEcrit += n + 1; // on avance le pointeur pour la zone memoire du lexeme suivant cmd += n; // on avance le pointeur de lecture sautant par dessus ce lexeme cmd += strspn(cmd, separateurs); // et on saute egalement les separateurs } tabLexemes[lexemes] = NULL; // pour marquer la fin du tableau de chaines return tabLexemes; // et on rend le pointeur vers le debut de la zone } void System (const char * const LigneCommande){ if (::pid_t PidFils = Fork ()) //pere Waitpid (PidFils); else //fils { char **NewArgv = extractionLexemes(LigneCommande," "); ::execvp (NewArgv [0], NewArgv); throw CExc("execv ()",NewArgv [0]); } } // System() } // namespace anonyme int main(int argc, char * argv []) { try { if (2!= argc) throw CExc("main()",string ("Usage : ") + argv [0] + " "); System(argv [1]); return 0; } catch (const CExc & Exc) { cerr <