/***************************************************************************** Gestionnaire de terminal Unix: dir.c (c) Pierre ADRIAANS 1994 *****************************************************************************/ #include "dir.h" #include "keyboard.h" char *getcwd(char *,size_t); /***************************************************************************** Dir() ------------------------------------------------------------------------------ Input: - specification de fichiers type "*.h" - pointeur de LLB DirList_t par adresse Process: constitution d'une LLB triee avec le contenu correspondant a la specification. Les ss-rep sont places en tete avec un '/' devant le nom. Output: le nombre de fichiers correspondant a la specification. La fonction travaille avec deux listes: une pour les ss-rep et une pour les fichiers. Elle effectue un merge des deux listes dans celle dont l'adresse est passee. Elle ne libere pas la liste actuelle !!! Ne pas oublier un appel a FreeAllTheList() avant. *****************************************************************************/ int Dir(char *Spec,DirList_t **List) { char *Path = (char *)NULL, /* Chemin d'acces */ *Mask = (char *)NULL, /* Masque de selection */ *Buf = (char *)NULL, /* Buffer temporaire */ Dummy[65]; /* Ss-rep courant */ DIR *pDir = (DIR *)NULL; /* Pointeur de ss-rep */ struct dirent *d = (struct dirent *)NULL; /* Entree de ss-rep */ struct stat s; /* Structure pour analyse */ int rc = 0; /* Nbre de fichiers */ DirList_t *Prec, /* Pointeur de parcours */ *Cour, /* Pointeur de parcours */ *Rep = (DirList_t *)NULL, /* Liste des ss-rep */ *Files = (DirList_t *)NULL, /* Liste des fichiers */ *Enreg; /* Une entree */ /* Analyse de la specification */ Path = (char *)malloc(strlen(Spec) +1); if(Path == (char *)NULL) raise(SIGME); Mask = (char *)malloc(strlen(Spec) +1); if(Mask == (char *)NULL) raise(SIGME); Analyse(Spec,Path,Mask); getcwd(Dummy,64); /* Ouverture du fichier repertoire */ pDir = opendir(Path); if(pDir == (DIR *)NULL) { free(Path); free(Mask); return(0); /* Aucun fichiers dans le ss-rep */ } /* Boucle de lecture */ while((d = readdir(pDir)) != (struct dirent *)NULL) { if(d->d_ino != 0) { if(strcmp(d->d_name,".") == 0) continue; if((strcmp(d->d_name,"..") == 0) && (strcmp(Dummy,PATH_SEPARATOR_STR) == 0)) continue; if(IsInMask(Mask,d->d_name)) { /* Un fichier de plus */ rc++; /* Allouer le buffer de caracteres pour constituer la specification complete du fichier */ Buf = (char *)malloc((strlen(Path) + strlen(d->d_name) + 3)); if(Buf == (char *)NULL) raise(SIGME); /* Construire cette specification */ strcpy(Buf,Path); if(Buf[strlen(Buf) - 1] != PATH_SEPARATOR_CHAR) strcat(Buf,PATH_SEPARATOR_STR); strcat(Buf,d->d_name); /* Demander l'analyse du fichier */ #ifdef BSD_SYMBOLIC_LINKS if(lstat(Buf,&s) == 0) #else if(stat(Buf,&s) == 0) #endif { /* Allouer un element de la liste */ Enreg = (DirList_t *)malloc(sizeof(DirList_t)); if(Enreg == (DirList_t *)NULL) raise(SIGME); /* Initialiser le champ Info systeme */ memcpy(&(Enreg->Info.s),&s,sizeof(struct stat)); /* Non marque pour le moment */ Enreg->Info.Tagged = 0; /* Allouer la chaine pour le nom */ Enreg->Info.Name = (char *)malloc((strlen(d->d_name) + 3)); if(Enreg->Info.Name == (char *)NULL) raise(SIGME); /* Tester le type de fichier */ if(IS_DIR(Enreg->Info.s.st_mode)) { /* Ss-rep: ajouter un '/' au debut en l'enfiler dans la liste des ss-rep */ if(strcmp(d->d_name,"..") != 0) { strcpy(Enreg->Info.Name,PATH_SEPARATOR_STR); strcat(Enreg->Info.Name,d->d_name); } else strcpy(Enreg->Info.Name,d->d_name); AddInList(&Rep,Enreg); } else { /* Fichier: ajouter dans la liste des fichiers */ strcpy(Enreg->Info.Name,d->d_name); AddInList(&Files,Enreg); } } /* Liberer le buffer de specification complete */ free(Buf); Buf = (char *)NULL; } } } /* Termine */ closedir(pDir); /* Liberer les chaines */ free(Path); free(Mask); /* Faire le merge des deux listes dans celle passee par adresse */ /* D'abord les ss-rep s'il y en a */ if(Rep != (DirList_t *)NULL) { *List = Rep; Cour = Rep; Prec = (DirList_t *)NULL; while(Cour != (DirList_t *)NULL) { Prec = Cour; Cour = Cour->Suivant; } /* Append des fichiers s'il y en a */ if(Files != (DirList_t *)NULL) { Prec->Suivant = Files; Files->Prec = Prec; } } else /* S'il n'y a pas de ss-rep, juste les fichiers (NULL si aucun) */ *List = Files; return(rc); } /***************************************************************************** FreeAllTheList() ------------------------------------------------------------------------------ Input: un pointeur de tete de LLB DirList_t Process: liberation de toute la liste *****************************************************************************/ void FreeAllTheList(DirList_t **List) { DirList_t *Prec,*Cour; Cour = *List; Prec = (DirList_t *)NULL; while(Cour != (DirList_t *)NULL) { Prec = Cour; Cour = Cour->Suivant; free(Prec->Info.Name); free(Prec); } *List = (DirList_t *)NULL; } /***************************************************************************** AddInList() ------------------------------------------------------------------------------ Input: - Un pointeur de tete de LLB DirList_t - Un element a ajouter Process: ajout de l'element a sa place dans la LLB ****************************************************************************/ void AddInList(DirList_t **List,DirList_t *Enreg) { DirList_t *Prec,*Cour; if(*List == (DirList_t *)NULL) { *List = Enreg; (*List)->Prec = (DirList_t *)NULL; (*List)->Suivant = (DirList_t *)NULL; } else { Cour = *List; Prec = (DirList_t *)NULL; while((Cour != (DirList_t *)NULL) && (strcmp(Cour->Info.Name,Enreg->Info.Name) < 0)) { Prec = Cour; Cour = Cour->Suivant; } if(Cour == (DirList_t *)NULL) { Prec->Suivant = Enreg; Enreg->Suivant = (DirList_t *)NULL; Enreg->Prec = Prec; } else { if(Prec == (DirList_t *)NULL) { Enreg->Suivant = *List; (*List)->Prec = Enreg; Enreg->Prec = (DirList_t *)NULL; *List = Enreg; } else { Prec->Suivant = Enreg; Enreg->Prec = Prec; Cour->Prec = Enreg; Enreg->Suivant = Cour; } } } } /***************************************************************************** GetName() ------------------------------------------------------------------------------ Input: Str: type "stdio.h" Process: Nom <- "stdio" ou chaine vide si pas de nom *****************************************************************************/ void GetName(char *Str,char *Nom) { int i,j = 0; i = strlen(Str); strcpy(Nom,""); while(j < i && Str[j] != '.') { Nom[j] = Str[j]; j++; } if(j > 0) Nom[j] = 0; } /***************************************************************************** GetExt() ------------------------------------------------------------------------------ Input: Str: type "stdio.h" Process: Ext <- "h" ou chaine vide si pas d'extension Attention: si Str == "test.a.b", Ext <- "b" et pas Ext <- "a.b" !!! *****************************************************************************/ void GetExt(char *Str,char *Ext) { int i,j; char Temp[30]; for(i = (strlen(Str) - 1),j = 0; (i >= 0) && (Str[i] != '.'); i--,j++) Temp[j] = Str[i]; Temp[j] = 0; if(i == -1) { strcpy(Ext,""); return; } /* Pas de point */ for(i = (strlen(Temp) - 1),j = 0; i >= 0; i--,j++) Ext[j] = Temp[i]; Ext[j] = 0; } /***************************************************************************** TestPart() ------------------------------------------------------------------------------ Input: Masque: un masque sur une composante d'un nom de fichier type: * ou db* ou db?a Str: la composante a tester Output: 1 si ca correspond, 0 sinon *****************************************************************************/ int TestPart(char *Masque,char *Str) { int i = 0,MLen,SLen,Borne; int Ok = 1; if(strcmp(Masque,"*") == 0) return(1); if((strcmp(Str,"") == 0) && (strcmp(Masque,"*") != 0)) return(0); MLen = strlen(Masque); SLen = strlen(Str); /* Si le masque est plus long que le nom: si le caractere directement apres la fin du nom dans le masque n'est pas '*' ca ne marche pas */ if(MLen > SLen) if(Masque[SLen] != '*') return(0); /* Parcourir le nom */ while(i < SLen) { switch(Masque[i]) { case '*': i = SLen; break; /* OK */ case '?': i++; break; default: if(Str[i] == 0) { Ok = 0; i = SLen; break; } if(Masque[i] == Str[i]) i++; else { Ok = 0; i = SLen; } } } return(Ok); } /***************************************************************************** IsInMask() ------------------------------------------------------------------------------ Input: Masque: un masque sur un nom de fichier type *.* ou *.c ou db?a.??1 ou db*.* NomFichier: le nom a tester Process: analyseur syntaxique Output: 1 si ca correspond, 0 sinon *****************************************************************************/ int IsInMask(char *Masque,char *NomFichier) { char *MNom = (char *)NULL, *MExt = (char *)NULL, *NNom = (char *)NULL, *NExt = (char *)NULL; int i; int NomOK,ExtOK; if((strcmp(Masque,"*.*") == 0) || (strcmp(Masque,"*") == 0)) return 1; /* Traitement du cas particulier des fichiers '.' et '..' */ if( ((strcmp(NomFichier,".") == 0) || (strcmp(NomFichier,"..") == 0)) ) if( ( (strcmp(Masque,"*.*") == 0) || (strcmp(Masque,"*") == 0) || (strcmp(Masque,"*.") == 0)) ) return 1; else return 0; i = strlen(Masque) + 1; MNom = (char *)malloc(i); if(MNom == (char *)NULL) raise(SIGME); MExt = (char *)malloc(i); if(MExt == (char *)NULL) raise(SIGME); i = strlen(NomFichier) + 1; NNom = (char *)malloc(i); if(NNom == (char *)NULL) raise(SIGME); NExt = (char *)malloc(i); if(NExt == (char *)NULL) raise(SIGME); GetName(Masque,MNom); GetExt(Masque,MExt); GetName(NomFichier,NNom); GetExt(NomFichier,NExt); if(strlen(MNom) == 0) if(strlen(NNom) == 0) NomOK = 1; else return 0; else NomOK = TestPart(MNom,NNom); if(strlen(MExt) == 0) if(strlen(NExt) == 0) ExtOK = 1; else return 0; else ExtOK = TestPart(MExt,NExt); free(MNom); free(MExt); free(NNom); free(NExt); return(NomOK && ExtOK); } /***************************************************************************** GetMask() ------------------------------------------------------------------------------ Input: Spec de type "/usr/include/stdio.h" Process: Path <- "/usr/include" ou chaine vide si pas de chemin Mask <- "stdio.h" Il faut verifier que Spec comporte bien un nom de fichier ou un masque comme element terminal: envoyer "/usr/include" fera le split en "/usr" et "include". *****************************************************************************/ void GetMask(char *Spec,char *Path,char *Mask) { char *Buffer; int LS,i,j,Lim; Buffer = (char*)malloc(strlen(Spec) + 1); if(Buffer == (char*)NULL) raise(SIGME); strcpy(Path,""); strcpy(Mask,""); LS = (strlen(Spec) - 1); i = 0; while((LS >= 0) && (Spec[LS] != PATH_SEPARATOR_CHAR)) { Buffer[i] = Spec[LS]; /* Empiler les lettres du masque */ i++; /* dans Buffer */ LS--; } i--; Lim = i; for(j=0;j <= Lim;j++,i--) Mask[j] = Buffer[i]; /* Depiler les lettres du */ Mask[Lim+1] = 0; /* du masque dans Mask */ if(LS == 0) strcpy(Path,PATH_SEPARATOR_STR); if(LS > 0) { strncpy(Path,Spec,LS); Path[LS] = 0; } free(Buffer); } /***************************************************************************** Analyse() ------------------------------------------------------------------------------ Input: Spec: specification de fichier de type: "stdio.h" "/usr/include" "/usr/include/stdio.h" "/usr/include/*.h" "*.*" ou toute autre variante Path: chaine reservee destinee a recevoir la partie ss-rep Mask: chaine reservee destinee a recevoir la partie masque de fichier Process: analyseur semantique Output: si Spec = "stdio.h": Path <- "." Mask <- "stdio.h" Spec = "/usr/include/*.h" Path <- "/usr/include" Mask <- "*.h" Spec = "/usr/include" Path <- "/usr/include" Mask <- "*.*" *****************************************************************************/ void Analyse(char *Spec,char *Path,char *Mask) { DIR *pDir; struct stat s; if((stat(Spec,&s) == -1) || ((pDir = opendir(Spec)) == NULL) || (closedir(pDir) != 0)) { GetMask(Spec,Path,Mask); /* Soit il y a un masque, soit c'est un */ /* fichier isole: faire le split */ } else { strcpy(Path,Spec); /* C'est le nom d'un sous-repertoire: */ strcpy(Mask,"*.*"); /* prendre *.* dans ce ss-rep */ } /* Si l'analyse ne montre pas de chemin: c'est le ss-rep courant */ if(strcmp(Path,"") == 0) strcpy(Path,"."); }