#include #include #include #include #include #include #include #include #include "permut.h" #include "nadoc.m" typedef struct { char *nomfct; char *desc; char touch; /* Cette fonction sert encore */ } HISTO_FCT; typedef struct { int nbfct; HISTO_FCT *fcts; } HISTO_TBL; /* Initialise la structure HISTO_TBL pour accumuler des description */ static void near histo_init (HISTO_TBL *tbl) { tbl->nbfct = 0; tbl->fcts = (HISTO_FCT*)calloc_err (1000,sizeof(HISTO_FCT),1); } /* Termine la structure HISTO_TBL */ static void near histo_end (HISTO_TBL *tbl) { int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; for (i=0; inomfct == NULL){ free (fct->nomfct); free (fct->desc); } } free (tbl->fcts); tbl->fcts = NULL; tbl->nbfct = 0; } static void near histo_ajoute ( HISTO_TBL *tbl, const char *nomfct, const char *desc) { int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; for (i=0; inomfct == NULL){ break; } } if (i == nbfct) tbl->nbfct++; assert (tbl->nbfct < 1000); fct->nomfct = strdup_err (nomfct,1); fct->desc = strdup_err (desc,1); fct->touch = 0; } /* Ajoute ou révise une description de fonction */ static void near histo_accum ( HISTO_TBL *tbl, const char *index, const char *desc) { char nomfct[50]; char *pt = str_skipword (str_skip(index)); pt = str_skipword(str_skip(pt)); pt = str_copyword(nomfct,str_skip(pt)); pt = str_skip (pt); if (pt[0] == 'N'){ histo_ajoute (tbl,nomfct,desc); }else if (pt[0] == 'R'){ int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; for (i=0; inomfct,nomfct)==0){ free (fct->desc); fct->desc = strdup_err (desc,1); break; } } if (i == nbfct){ /* Fonction révisée pas encore rencontré dans le fichier C'est une condition qui ne se produit pas en opération normale. Si le fichier d'historique grossit de façon importante, l'usager peut choisir d'éliminer les premières versions des fonctions qui ont subient beaucoup de modification. C'est pourquoi on peut avoir rencontré un révision "R" sans création "N" */ histo_ajoute (tbl,nomfct,desc); } }else if (pt[0] == 'D'){ int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; for (i=0; inomfct,nomfct)==0){ free (fct->nomfct); free (fct->desc); fct->nomfct = NULL; fct->desc = NULL; break; } } } } /* Lit un fichier d'historique et construit la table des fonctions actives Retourne -1 si erreur */ static int near histo_read (const char *fname, HISTO_TBL *tbl) { int ret = -1; FILE *fin = vfopen_err (fname,"r",0); if (fin != NULL){ /* Chaque fonction est précédé d'un commentaire spécial ~ DATE nom_fonction etat(N,R,O) */ char *accum = (char*)malloc_err (10000,1); char *ptacc = accum; char buf[300]; char index[300]; int is_load = 0; accum[0] = '\0'; ret = 0; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (buf[0] == '/' && buf[1] == '*' && buf[2] == '~'){ if (is_load){ histo_accum (tbl,index,accum); is_load = 0; } strcpy (index,buf); ptacc = accum; is_load = 1; }else if (buf[0] != '\n'){ ptacc = stpcpy (ptacc,buf); } } if (is_load){ histo_accum (tbl,index,accum); } free (accum); fclose (fin); } return ret; } /* Ajoute une révision à un fichier d'historique si une fonction a changée ou est nouvelle Retourne -1 si erreur */ static int near histo_revise( HISTO_TBL *tbl, const char *fname, const char *date, const char *index, const char *desc, FILE *fout) { int ret = 0; char nomfct[50]; int len; str_copyword (nomfct,index+3); len = strlen(nomfct)-1; if (nomfct[len] != '!' && nomfct[len] != ':'){ fprintf (stderr,MSG_U(E_IVLDSTRUCT ,"Invalid structure for file %s\n%s\n"),fname,index); ret = -1; }else{ int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; char date0[20]; char date1[20]; char *pt = str_copyword (date0,str_skip(date+3)); str_copyword(date1,str_skip(pt)); nomfct[len] = '\0'; for (i=0; inomfct,nomfct)==0){ fct->touch = 1; if (strcmp (fct->desc,desc) != 0){ fprintf (fout,"/*~%s %s %s R */\n%s\n" ,date0,date1,nomfct,desc); } break; } } if (i == nbfct){ fprintf (fout,"/*~%s %s %s N */\n%s\n" ,date0,date1,nomfct,desc); } } return ret; } /* Lit un fichier .NAP et détermine les fonctions qui ont changés ou nouvelles retourne -1 si erreur */ static int near histo_readnap ( const char *fname, HISTO_TBL *tbl, FILE *fout) /* Fichier qui accumule les révisions */ { int ret = -1; FILE *fin = vfopen_err (fname,"r",1); if (fin != NULL){ /* Chaque fonction est précédé d'un commentaire spécial ~nom_fonction : fichier Un commentaire spécial donne la date de révision d'un source ~date heure: fichier */ char *accum = (char*)malloc_err (10000,1); char *ptacc = accum; char buf[300]; char date[100]; char index[100]; accum[0] = '\0'; ret = 0; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (buf[0] == '/' && buf[1] == '*' && buf[2] == '~'){ if (ptacc > accum){ ret |= histo_revise (tbl,fname,date,index,accum,fout); } if (isdigit(buf[3])){ strcpy (date,buf); }else{ strcpy (index,buf); } ptacc = accum; }else if (buf[0] != '\n' && buf[0] != '\r'){ /* On teste le \n et \r au debut de la ligne pour compatibilité DOS <-> UNIX */ /* Protection de base contre les fichiers bousillés */ if ((int)(ptacc - accum) < 9000){ ptacc = stpcpy (ptacc,buf); } } } if (ptacc > accum){ ret |= histo_revise (tbl,fname,date,index,accum,fout); } free (accum); fclose (fin); } return ret; } /* Détermine les fonction qui n'existe plus */ static void near histo_chkold (HISTO_TBL *tbl, FILE *fout) { int i; HISTO_FCT *fct = tbl->fcts; int nbfct = tbl->nbfct; for (i=0; inomfct != NULL && !fct->touch){ fprintf (fout,"/*~??/??/?? ??.??.??: %s D */\n\n",fct->nomfct); } } } /* Met a jour un fichier .NAH à partir d'un fichier .NAP Retourne -1 si erreur Si le fichier .NAH n'existe pas, il est créé */ int histo_update ( const char *fnah, const char *fnap) { int ret = -1; HISTO_TBL tbl; histo_init (&tbl); if (!file_exist(fnah) || histo_read(fnah,&tbl)!=-1){ FILE *fout = fopen_err (fnah,"a",1); if (histo_readnap (fnap,&tbl,fout) !=-1){ histo_chkold (&tbl,fout); ret = 0; } fclose (fout); } histo_end (&tbl); return ret; } #ifdef TEST int main () { histo_update ("test.nah","test.nap"); return 0; } #endif