#include #include #include #include #include #include #include "projet.h" #include "projetx.m" /* #Sp‚cification: Archivage / RCS RCS a ‚t‚ originalement utilis‚ comme r‚f‚rence pour l'archivage. Son avenir est incertain. Toutes les sp‚cifications concernant RCS doivent ˆtre prise en consid‚ration. RCS revivra peut-ˆtre un jour. */ static PROJET_LOG *rcs_log = NULL; // Collecte ou affiche ou les deux // les op‚rations rcs. static char rcs_test; // Affiche les commandes sans ex‚cuter /* Controle les op‚rations RCS */ void rcs_setmode ( int test) // Affiche les commandes sans ex‚cution ? { rcs_test = (char)test; } /* Enregistre objet pour g‚n‚rer message … l'‚cran. */ void rcs_setlog( PROJET_LOG *log) // Enregistre les commandes dans un log // Peut ˆtre NULL. { rcs_log = log; } /* Ex‚cute un programme via system() en r‚cup‚rant les messages d'erreur. V‚rifie si dans le message d'erreur, il y avait soit les mot "branch number" ou branchpoint. brancherror indiquera si ca a ‚t‚ vue. */ static int near rcs_call ( int *brancherror, const char *std_in, // Red‚finie std_in temporairement const char *cmd, ...) { if (brancherror != NULL) *brancherror = 0; int ret = 0; char buf[3*MAXSIZ_PATH]; va_list list; va_start (list,cmd); vsprintf (buf,cmd,list); va_end (list); char cwd[MAXSIZ_PATH]; path_getcwd(cwd,sizeof(cwd)); if (rcs_log != NULL){ rcs_log->printf ("%s # %s\n",cwd,buf); } if (!rcs_test){ const char *fileerr = "_rcs.err"; int oldstderr = rcs_opendup (fileerr,O_CREAT|O_RDWR|O_TRUNC,2 ,MSGERR_RCSERR); if (oldstderr != -1){ int oldstdin = std_in != NULL ? rcs_opendup (std_in,O_RDONLY,0,MSGERR_RCSINPUT) : 0; if (oldstdin != -1){ ret = rcs_system (buf); rcs_closedup (oldstderr,2); if (std_in != NULL){ rcs_closedup (oldstdin,0); } FILE *fin = fopen_err(fileerr,"r",1); char buf[300]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (strstr(buf,"branch number")!=NULL || strstr(buf,"Branch point")!=NULL || strstr(buf,"branchpoint")!=NULL){ if (brancherror != NULL) *brancherror = 1; } if (rcs_log != NULL){ rcs_log->printf ("%s",buf); } } fclose (fin); file_unlink (fileerr); } } } return ret; } /* Copie un fichier avec affichage dans le log. Retourne -1 si erreur. */ static int near rcs_copy ( const char *src, const char *dst) { int ret = 0; char cwd[MAXSIZ_PATH]; path_getcwd(cwd,sizeof(cwd)); if (rcs_log != NULL){ rcs_log->printf ("%s # copy %s %s\n",cwd,src,dst); } if (!rcs_test){ ret = file_copyp (src,dst); if (ret != -1) ret = 0; } return ret; } /* RCS contruit les noms de fichier archive en ajoute %v. Ce n'est pas suffisant pour les fichiers qui ont un extension de 3 lettres. mangle contiendra un nom corrige avec extension de deux lettres et moins. On fera l'hypothese que tous les extensions utilis‚s sont sont uniques par les deux premier caractŠres. De plus, pour les fichiers sans extensions, RCS ajoute %v sans v‚rifier la longueur. Ca fonctionne pas pour les fichiers de 8 lettres. On ajoutera "_" comme extension pour ces fichiers. */ static void rcs_patchname ( const char *src, char *mangle, // Nom transform‚ pour RCS fonctionne // correctement. char *archive) // Nom de l'archive produit par RCS. // NULL si pas requis. { char base[MAXSIZ_PATH]; char extension[MAXSIZ_EXTENSION]; file_baseext (src,base,extension); int len = strlen(extension); if (len == 3){ extension[2] = '\0'; file_chgext (base,mangle,extension); extension[2] = '%'; }else if (len == 0){ file_chgext (base,mangle,"_"); strcpy (extension,"_%v"); }else{ strcpy (mangle,src); if (len == 1){ strcat (extension,"%v"); }else{ strcat (extension,"%"); } } if (archive != NULL) file_chgext (base,archive,extension); } /* Retourne -1 si erreur quelquoncque irr‚cup‚rable. -2 si l'archivage est refus‚ parce que la branche ancˆtre n'existe pas. */ /* #Sp‚cification: archivage / RCS / no de r‚vision Si on archive une r‚vision … quatre num‚ro et que la r‚vision ancˆtre n'existe pas (r‚vision … deux num‚ro), on en force une avec le mˆme fichier source. C'est en partie pour cette raison que la commande ci est toujours appel‚ avec l'option -f. */ static int near rcs_put0 ( const char *fname, // Fichier const char *username, // Nom du programmeur. REVISION *rev, const char *pathref, // R‚pertoire qui contient la version // archiv‚e. const char *doc) // Documentation expliquant les diff‚rences // avec la version pr‚c‚dante. // Ou NULL { int ret = -1; char fmangle[MAXSIZ_PATH]; char farchive[MAXSIZ_PATH]; rcs_patchname (fname,fmangle,farchive); char path[MAXSIZ_PATH]; path_make (pathref,fmangle,path); if (path_cmp(fname,path)==0 || rcs_copy (fname,path) != -1){ SAVEPATH save; // S‚lectionne le r‚pertoire archive if (path_pushdir (pathref,&save)!=-1){ // Ecrit le commentaire dans un fichier temporaire // la commande ci est appel‚ avec input redirig‚. FILE *fout = fopen_err ("toto","w",0); if (fout != NULL){ fprintf(fout,(doc == NULL ? ".\n" : "%s\n.\n"),doc); fclose (fout); int do_rcs = !file_exist (farchive); char revstr[MAXSIZ_REVISION+1]; rev->format (revstr); int error; // Branch error ? ret = rcs_call (&error,"toto" ,"ci -f -w%s -f%s %s",username,revstr,fmangle); if (ret == -1){ if (error && rev->type()==REVISION_LIVRE){ ret = -2; }else{ error_showdef (MSGERR_CIERROR,fname); } }else{ file_unlink (fname); if (do_rcs){ /* #Sp‚cification: Archivage / RCS / Cr‚ation Par d‚faut, rcs cr‚e un fichier archive avec locking stricte. Ceci est incompatible avec la strat‚gie MKS qui permet … n'importe qui de modifier un source. La commande "rcs -U fichier" est ex‚cut‚e lors de la cr‚ation de l'archive. Elle lib‚ralise l'usage de l'archive. */ rcs_call (NULL,NULL,"rcs -U %s",fmangle); } } file_unlink ("toto"); } path_popdir (&save); } } return ret; } /* Enregistre une nouvelle version d'un fichier. Accepte fichiers binaires. la commande ci a une limitation pour manipuler des path. On copie donc le fichier dans le r‚pertoire d'archivage et on laisse ci travailler localement. On fait l'hypothŠse que le r‚pertoire courant contient le fichier source … archiver. Si le r‚pertoire courant est le mˆme que le r‚pertoire d'archivage, pas de copie. Ca se produit pour le d‚marrage du systŠme d'archivage (void bootrcs.c). Le fichier source sera effac‚ du r‚pertoire si archivage r‚ussit. Retourne -1 si erreur. */ int rcs_put ( const char *fname, // Fichier const char *username, // Nom du programmeur. REVISION *rev, const char *pathref, // R‚pertoire qui contient la version // archiv‚e. const char *doc) // Documentation expliquant les diff‚rences // avec la version pr‚c‚dante. // Ou NULL { int ret = -1; if (file_type(pathref) == 1 || file_mkdiranc(pathref) != -1){ if (ascii_test (fname)==-1){ /* #Sp‚cification: archivage / RCS / fichiers binaires Les fichiers binaires sont accumul‚s dans des sous- r‚pertoires du r‚pertoire d'archivage. Le nom du sous-r‚pertoire est compos‚ … partir de la r‚vision du fichier et de l'extension ".b". On a donc la mˆme flexibilit‚ que rcs, sauf le gain d'espace, puisque chaque r‚vision est stock‚e int‚gralement. */ char pathbin[MAXSIZ_PATH]; char revpath[MAXSIZ_NAME+1]; rev->formatpath (revpath); path_make (pathref,revpath,pathbin); strcat (pathbin,".b"); if (file_type(pathbin) == 1 || file_mkdiranc(pathbin) != -1){ path_make (pathbin,fname,pathbin); ret = rcs_copy (fname,pathbin); } }else{ ret = rcs_put0(fname,username,rev,pathref,doc); if (ret == -2){ REVISION baserev(rev); baserev.cnv (REVISION_INTEGRE); ret = rcs_put0(fname,username,&baserev,pathref ,"Archivage forc‚e de la racine"); if (ret != -1){ ret = rcs_put0(fname,username,rev,pathref,doc); } } } } return ret; } /* Extrait une r‚vision d'un fichier. Supporte fichier binaire. */ int rcs_extract ( const char *fname, // Fichier const REVISION *rev, const char *pathref, // R‚pertoire qui contient la version // archiv‚e. const char *pathomb) // R‚pertoire destination. { int ret = -1; if (file_type(pathomb) == 1 || file_mkdiranc(pathomb) != -1){ /* #Sp‚cification: archivage / RCS / fichiers binaires Lors de l'extraction, nous ne savons pas … l'avance si le fichier … extraire est binaire ou pas. On cherche simplement dans le sous-r‚pertoire correspondant … la r‚vision cherch‚e. Si le fichier y est, c'est qu'il est binaire: on en prend une copie. S'il n'y est pas, on suppose qu'il est ASCII et archiv‚ via RCS. On utilise alors la commande "co" pour extraire la r‚vision command‚e. Cette strat‚gie fait qu'un fichier pourra, pour un mˆme projet etre parfois "binaire" pour certaines r‚visions, parfois ASCII pour d'autre. */ char revpath[MAXSIZ_NAME+1]; rev->formatpath (revpath); char pathbin[MAXSIZ_PATH]; path_make (pathref,revpath,pathbin); strcat (pathbin,".b"); path_make (pathbin,fname,pathbin); if (file_exist(pathbin)){ char path[MAXSIZ_PATH]; path_make (pathomb,fname,path); ret = rcs_copy (pathbin,path); }else{ SAVEPATH save; if (path_pushdir (pathref,&save) != -1){ char fmangle[MAXSIZ_PATH]; rcs_patchname (fname,fmangle,NULL); char revstr[MAXSIZ_REVISION+1]; rev->format (revstr); ret = rcs_call (NULL,NULL,"co -u%s %s",revstr,fmangle); if (ret != -1){ char path[MAXSIZ_PATH]; path_make (pathomb,fname,path); ret = rcs_copy (fmangle,path); if (!rcs_test){ #ifdef MSDOS file_setmode (fmangle,1); // co extrait write protect ! #endif file_unlink (fmangle); } } path_popdir (&save); } } } return ret; }