#include #include #include #include #include "projet.h" /* Analyse une r‚vision et extrait les composantes. Retourne -1 si invalide. */ static int near revision_parse ( const char *str, int *version, int *integre, int *prog, int *livre) { int ret = -1; int accum[4]; int nbacc = 0; accum[0] = accum[1] = accum[2] = accum[3] = 0; while (*str != '\0'){ if (isdigit(str[0])){ if (nbacc == 4) break; // Trop de membre accum[nbacc] = atoi(str); nbacc++; str = str_skipdig(str); if (str[0] == '\0'){ ret = 0; break; }else if (str[0] == '.'){ str++; }else{ break; } }else{ break; } } if (ret == 0){ if (nbacc == 3) ret = -1; } *version = accum[0]; *integre = accum[1]; *prog = accum[2]; *livre = accum[3]; return ret; } /* #Sp‚cification: r‚vision / format Une r‚vision est compos‚ de quatre composantes num‚riques, dont deux qui sont optionnelles. version.integre[.prog.livre] version: correspond … la r‚vision principale. Cela correspond directement … une version de produit. integre: R‚vision cr‚‚e lors d'une intŠgration. prog: Sous-r‚vision cr‚‚e lorsqu'un programmeur livre une correction. Si prog == 0, alors la r‚vision correspond … une version principale ou une version issue d'une int‚gration. livre: Les diff‚rentes livraisons d'un programmeur. */ # /* Controle les transformations sur les num‚ros de r‚visions revstr contient une r‚vision en format v.i.p.l */ PUBLIC REVISION::REVISION(const char *revstr) { revision_parse (revstr,&version,&integre,&prog,&livre); } PUBLIC REVISION::REVISION(const REVISION *rev) { version = rev->version; integre = rev->integre; prog = rev->prog; livre = rev->livre; } PUBLIC REVISION::REVISION() { // Assure que isnull() retourne vrai. version = 1000; integre = prog = livre = 0; } /* programme une nouvelle r‚vision. On utilise cette fonction surtout quand le constructeur sans argument est utilis‚. */ PUBLIC int REVISION::set (const char *revstr) { return revision_parse (revstr,&version,&integre,&prog,&livre); } /* V‚rifie si un num‚ro de r‚vision est valide. Une r‚vision possŠde 1,2 ou 4 num‚ros s‚par‚s par des '.'. Retourne -1 si erreur. */ PUBLIC STATIC int REVISION::check (const char *revstr) { int version; int integre; int prog; int livre; return revision_parse (revstr,&version,&integre,&prog,&livre); } /* Retourne le type de r‚vision */ PUBLIC REVISION_TYPE REVISION::type() const { REVISION_TYPE ret = REVISION_LIVRE; if (prog == 0){ if (integre == 0){ ret = REVISION_VERSION; }else{ ret = REVISION_INTEGRE; } } return ret; } /* Retourne le num‚ro de livraison d'une r‚vision. Retourne 0 si cette r‚vision est une REVISION_VERSION ou REVISION_INTEGRE */ PUBLIC int REVISION::getlivre() const { return livre; } /* Calcul le num‚ro de la prochaine r‚vision en fonction du type requis. Retourne -1 si le prog fournis ne correspond pas au programmeur d‚j… enregistrer. On retrouve ce cas ou cette version est d‚j… une livraison. La REVISION n'est pas modifi‚ dans ce cas. */ PUBLIC int REVISION::next (int _prog, REVISION_TYPE _type) { int ret = 0; REVISION_TYPE curtype = type(); int nversion = version; int nintegre = integre; int nprog = prog; int nlivre = livre; if (_type == REVISION_LIVRE){ if (curtype == REVISION_LIVRE){ if (_prog != prog){ ret = -1; } nlivre++; }else{ nprog = _prog; nlivre = 1; #if 0 if (curtype == REVISION_VERSION){ // PremiŠre livraison d'une version majeure nintegre = 1; } #endif } }else if (_type == REVISION_INTEGRE){ nintegre++; nprog = 0; nlivre = 0; #if 0 if (curtype != REVISION_LIVRE){ // Pas d'integration … partir d'une version majeure ret = -1; }else{ nintegre++; nprog = 0; nlivre = 0; } #endif } if (ret != -1){ version = nversion; integre = nintegre; prog = nprog; livre = nlivre; } return ret; } /* Convertit une r‚vision en version ou en int‚gration. Elimine les deux derniers digits */ PUBLIC void REVISION::cnv (REVISION_TYPE type) { prog = 0; livre = 0; if (type == REVISION_VERSION) integre = 0; } /* Formatte un r‚vision en ASCII. */ PUBLIC void REVISION::format (char *revstr) const { REVISION_TYPE curtype = type(); char *ctl; if (curtype == REVISION_VERSION){ ctl = "%d.%d"; // Ca va afficher X.0. rcs version DOS // n'accepte pas les r‚visions a un chiffre. }else if (curtype == REVISION_INTEGRE){ ctl = "%d.%d"; }else{ ctl = "%d.%d.%d.%d"; } sprintf (revstr,ctl,version,integre,prog,livre); } static void near revision_formatdig (char *str,int val) { if (val < 10){ *str++ = '_'; *str++ = val+'0'; *str = '\0'; }else{ sprintf (str,"%d",val); } } /* Formatte un num‚ro de r‚vision pour former un nom de r‚pertoire valide pour DOS (8 caractŠres). L'extension ne peut pas ˆtre utilis‚ (3 caractŠres) parce que r‚serv‚ pour qualifier le type de r‚pertoire. */ PUBLIC void REVISION::formatpath (char *path) const { /* #Sp‚cification: r‚vision / format path Un num‚ro de r‚vision peut servir … composer un nom de r‚pertoire. Une r‚vision contient au maximum 4 num‚ro de deux chiffres chacun. Si un num‚ro n'a qu'un chiffre, un '_' sera ins‚r‚. exemple: 1.0 -> _1_0 1.12 -> _112 10.1.50.2 -> 10_150_2 Cette convention est utilis‚ parce qu'elle fonctionne pour tous les systŠmes d'exploitation que nous connaissons. */ revision_formatdig(path,version); revision_formatdig(path+2,integre); if (prog != 0){ revision_formatdig(path+4,prog); revision_formatdig(path+6,livre); } } /* Traduit une r‚vision en format path, en format avec points. _1_0 -> 1.0 Retourne -1 si le format est invalide. */ int revision_path2rev( const char *src, char *dst) // Si == NULL, fait simplement validation de src { int ret = -1; char tmp[MAXSIZ_REVISION]; if (dst == NULL) dst = tmp; int len = strlen(src); if (len == 4 || len == 8){ int premier = 1; ret = 0; while (*src != '\0'){ if (!premier) *dst++ = '.'; premier = 0; if (*src == '_'){ src++; if (!isdigit(src[0])) ret = -1; *dst++ = *src++; }else{ if (!isdigit(src[0])) ret = -1; *dst++ = *src++; if (!isdigit(src[0])) ret = -1; *dst++ = *src++; } } } *dst = '\0'; return ret; } /* Formatte deux premier num‚ro d'une r‚vision pour faire nom de r‚pertoire. valide pour DOS (8 caractŠres). Cette fonction permet de d‚terminer une portion du path dans le r‚pertoire kit\build. Ce r‚pertoire ne contient que des versions int‚gr‚s. */ PUBLIC void REVISION::formatbld (char *path) const { revision_formatdig(path,version); revision_formatdig(path+2,integre); } /* Compare une r‚vision avec une autre. Retourne < 0 si l'autre est plus r‚cente (plus nouvelle). == 0 si identique. > 0 si l'autre est moins nouvelle. */ PUBLIC int REVISION::cmp (const REVISION *rev) const { int ret = version - rev->version; if (ret == 0){ ret = integre - rev->integre; if (ret == 0){ ret = prog - rev->prog; if (ret == 0){ ret = livre - rev->livre; } } } return ret; } /* Elimine la partie programmeur.livraison. On utilise cette fonction pour retrouver la version int‚gr‚e dont est issue cette r‚vision. */ PUBLIC void REVISION::strip() { prog = livre = 0; } /* Retourne le no du programmeur qui a cr‚‚ cette r‚vision. */ PUBLIC int REVISION::getprog() { return prog; } /* Retourne != 0 si c'est la r‚vision nulle 0.0.0.1 La r‚vision nulle sert … identifier par exemple qu'un fichier n'a pas encore ‚t‚ livr‚. Ce m‚canisme est particuliŠrement utile pour l'‚dition d'une fusion dans l'espace usager (voir ufusion.c et intgdat2.c). */ PUBLIC int REVISION::isnull() { return version == 1000 && integre == 0 && prog == 0 && livre == 0; } #ifdef TEST static void testnext (REVISION *rev, REVISION_TYPE type, int prog) { static char *tb[]={ "VERSION", "INTEGRE", "LIVRE" }; printf ("\tnext %10s prog %2d ",tb[type],prog); if (rev->next(prog,type)!=-1){ char str[MAXSIZ_REVISION+1]; rev->format(str); printf ("%s\n",str); }else{ printf ("Invalide\n"); } } static void test (const char *str) { printf ("----------- test %s -------------\n",str); if (REVISION::check(str)==-1){ printf ("revision :%s: est invalide\n",str); }else{ REVISION rev(str); for (int prog = 1; prog < 3; prog++){ testnext (&rev,REVISION_VERSION,prog); testnext (&rev,REVISION_INTEGRE,prog); testnext (&rev,REVISION_LIVRE,prog); } } } int main (int, char *[]) { test ("1"); test ("1.1"); test ("1.1.1"); test ("1.1.1.1"); test ("2"); test ("2.2"); test ("2.2.2"); test ("2.2.2.2"); } #endif