build/spec.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include "buildio.h"
00009 #include "rpmds.h"
00010 #include "rpmfi.h"
00011 #include "rpmts.h"
00012 
00013 #include "debug.h"
00014 
00015 /*@-redecl@*/
00016 extern int specedit;
00017 /*@=redecl@*/
00018 
00019 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00020 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00021 
00022 /*@access Header @*/    /* compared with NULL */
00023 /*@access rpmfi @*/     /* compared with NULL */
00024 
00029 static inline
00030 /*@null@*/ struct TriggerFileEntry * freeTriggerFiles(/*@only@*/ /*@null@*/ struct TriggerFileEntry * p)
00031         /*@modifies p @*/
00032 {
00033     struct TriggerFileEntry *o, *q = p;
00034     
00035     while (q != NULL) {
00036         o = q;
00037         q = q->next;
00038         o->fileName = _free(o->fileName);
00039         o->script = _free(o->script);
00040         o->prog = _free(o->prog);
00041         o = _free(o);
00042     }
00043     return NULL;
00044 }
00045 
00051 static inline
00052 /*@null@*/ struct Source * freeSources(/*@only@*/ /*@null@*/ struct Source * s)
00053         /*@modifies s @*/
00054 {
00055     struct Source *r, *t = s;
00056 
00057     while (t != NULL) {
00058         r = t;
00059         t = t->next;
00060         r->fullSource = _free(r->fullSource);
00061         r = _free(r);
00062     }
00063     return NULL;
00064 }
00065 
00066 /*@-boundswrite@*/
00067 int lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkg)
00068 {
00069     const char *pname;
00070     const char *fullName;
00071     Package p;
00072     
00073     /* "main" package */
00074     if (name == NULL) {
00075         if (pkg)
00076             *pkg = spec->packages;
00077         return 0;
00078     }
00079 
00080     /* Construct package name */
00081   { char *n;
00082     if (flag == PART_SUBNAME) {
00083         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
00084         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
00085         while (*pname != '\0') *n++ = *pname++;
00086         *n++ = '-';
00087     } else {
00088         fullName = n = alloca(strlen(name)+1);
00089     }
00090     /*@-mayaliasunique@*/
00091     strcpy(n, name);
00092     /*@=mayaliasunique@*/
00093   }
00094 
00095     /* Locate package with fullName */
00096     for (p = spec->packages; p != NULL; p = p->next) {
00097         (void) headerNVR(p->header, &pname, NULL, NULL);
00098         if (pname && (! strcmp(fullName, pname))) {
00099             break;
00100         }
00101     }
00102 
00103     if (pkg)
00104         /*@-dependenttrans@*/ *pkg = p; /*@=dependenttrans@*/
00105     return ((p == NULL) ? 1 : 0);
00106 }
00107 /*@=boundswrite@*/
00108 
00109 Package newPackage(Spec spec)
00110 {
00111     Package p;
00112     Package pp;
00113 
00114     p = xcalloc(1, sizeof(*p));
00115 
00116     p->header = headerNew();
00117     p->ds = NULL;
00118     p->icon = NULL;
00119 
00120     p->autoProv = 1;
00121     p->autoReq = 1;
00122     
00123 #if 0    
00124     p->reqProv = NULL;
00125     p->triggers = NULL;
00126     p->triggerScripts = NULL;
00127 #endif
00128 
00129     p->triggerFiles = NULL;
00130     
00131     p->fileFile = NULL;
00132     p->fileList = NULL;
00133 
00134     p->cpioList = NULL;
00135 
00136     p->preInFile = NULL;
00137     p->postInFile = NULL;
00138     p->preUnFile = NULL;
00139     p->postUnFile = NULL;
00140     p->verifyFile = NULL;
00141 
00142     p->specialDoc = NULL;
00143 
00144     if (spec->packages == NULL) {
00145         spec->packages = p;
00146     } else {
00147         /* Always add package to end of list */
00148         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
00149             {};
00150         pp->next = p;
00151     }
00152     p->next = NULL;
00153 
00154     return p;
00155 }
00156 
00157 Package freePackage(Package pkg)
00158 {
00159     if (pkg == NULL) return NULL;
00160     
00161     pkg->preInFile = _free(pkg->preInFile);
00162     pkg->postInFile = _free(pkg->postInFile);
00163     pkg->preUnFile = _free(pkg->preUnFile);
00164     pkg->postUnFile = _free(pkg->postUnFile);
00165     pkg->verifyFile = _free(pkg->verifyFile);
00166 
00167     pkg->header = headerFree(pkg->header);
00168     pkg->ds = rpmdsFree(pkg->ds);
00169     pkg->fileList = freeStringBuf(pkg->fileList);
00170     pkg->fileFile = _free(pkg->fileFile);
00171     if (pkg->cpioList) {
00172         rpmfi fi = pkg->cpioList;
00173         pkg->cpioList = NULL;
00174         fi = rpmfiFree(fi);
00175     }
00176 
00177     pkg->specialDoc = freeStringBuf(pkg->specialDoc);
00178     pkg->icon = freeSources(pkg->icon);
00179     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
00180 
00181     pkg = _free(pkg);
00182     return NULL;
00183 }
00184 
00185 Package freePackages(Package packages)
00186 {
00187     Package p;
00188 
00189     while ((p = packages) != NULL) {
00190         packages = p->next;
00191         p->next = NULL;
00192         p = freePackage(p);
00193     }
00194     return NULL;
00195 }
00196 
00199 static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
00200         /*@*/
00201 {
00202     struct Source *p;
00203 
00204     for (p = spec->sources; p != NULL; p = p->next)
00205         if ((num == p->num) && (p->flags & flag)) return p;
00206 
00207     return NULL;
00208 }
00209 
00210 /*@-boundsread@*/
00211 int parseNoSource(Spec spec, const char * field, int tag)
00212 {
00213     const char *f, *fe;
00214     const char *name;
00215     int num, flag;
00216 
00217     if (tag == RPMTAG_NOSOURCE) {
00218         flag = RPMBUILD_ISSOURCE;
00219         name = "source";
00220     } else {
00221         flag = RPMBUILD_ISPATCH;
00222         name = "patch";
00223     }
00224     
00225     fe = field;
00226     for (f = fe; *f != '\0'; f = fe) {
00227         struct Source *p;
00228 
00229         SKIPWHITE(f);
00230         if (*f == '\0')
00231             break;
00232         fe = f;
00233         SKIPNONWHITE(fe);
00234         if (*fe != '\0') fe++;
00235 
00236         if (parseNum(f, &num)) {
00237             rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s\n"),
00238                      spec->lineNum, f);
00239             return RPMERR_BADSPEC;
00240         }
00241 
00242         if (! (p = findSource(spec, num, flag))) {
00243             rpmError(RPMERR_BADSPEC, _("line %d: Bad no%s number: %d\n"),
00244                      spec->lineNum, name, num);
00245             return RPMERR_BADSPEC;
00246         }
00247 
00248         p->flags |= RPMBUILD_ISNO;
00249 
00250     }
00251 
00252     return 0;
00253 }
00254 /*@=boundsread@*/
00255 
00256 /*@-boundswrite@*/
00257 int addSource(Spec spec, Package pkg, const char *field, int tag)
00258 {
00259     struct Source *p;
00260     int flag = 0;
00261     char *name = NULL;
00262     char *nump;
00263     const char *fieldp = NULL;
00264     char buf[BUFSIZ];
00265     int num = 0;
00266 
00267     buf[0] = '\0';
00268     /*@-branchstate@*/
00269     switch (tag) {
00270       case RPMTAG_SOURCE:
00271         flag = RPMBUILD_ISSOURCE;
00272         name = "source";
00273         fieldp = spec->line + 6;
00274         break;
00275       case RPMTAG_PATCH:
00276         flag = RPMBUILD_ISPATCH;
00277         name = "patch";
00278         fieldp = spec->line + 5;
00279         break;
00280       case RPMTAG_ICON:
00281         flag = RPMBUILD_ISICON;
00282         fieldp = NULL;
00283         break;
00284     }
00285     /*@=branchstate@*/
00286 
00287     /* Get the number */
00288     if (tag != RPMTAG_ICON) {
00289         /* We already know that a ':' exists, and that there */
00290         /* are no spaces before it.                          */
00291         /* This also now allows for spaces and tabs between  */
00292         /* the number and the ':'                            */
00293 
00294         nump = buf;
00295         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
00296             *nump++ = *fieldp++;
00297         }
00298         *nump = '\0';
00299 
00300         nump = buf;
00301         SKIPSPACE(nump);
00302         if (nump == NULL || *nump == '\0') {
00303             num = 0;
00304         } else {
00305             if (parseNum(buf, &num)) {
00306                 rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
00307                          spec->lineNum, name, spec->line);
00308                 return RPMERR_BADSPEC;
00309             }
00310         }
00311     }
00312 
00313     /* Create the entry and link it in */
00314     p = xmalloc(sizeof(*p));
00315     p->num = num;
00316     p->fullSource = xstrdup(field);
00317     p->flags = flag;
00318     p->source = strrchr(p->fullSource, '/');
00319     if (p->source) {
00320         p->source++;
00321     } else {
00322         p->source = p->fullSource;
00323     }
00324 
00325     if (tag != RPMTAG_ICON) {
00326         p->next = spec->sources;
00327         spec->sources = p;
00328     } else {
00329         p->next = pkg->icon;
00330         pkg->icon = p;
00331     }
00332 
00333     spec->numSources++;
00334 
00335     if (tag != RPMTAG_ICON) {
00336         /*@-nullpass@*/         /* LCL: varargs needs null annotate. */
00337         const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
00338         /*@=nullpass@*/
00339 
00340         sprintf(buf, "%s%d",
00341                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
00342         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
00343         sprintf(buf, "%sURL%d",
00344                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
00345         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
00346         body = _free(body);
00347     }
00348     
00349     return 0;
00350 }
00351 /*@=boundswrite@*/
00352 
00355 static inline /*@only@*/ /*@null@*/ speclines newSl(void)
00356         /*@*/
00357 {
00358     speclines sl = NULL;
00359     /*@-branchstate@*/
00360     if (specedit) {
00361         sl = xmalloc(sizeof(*sl));
00362         sl->sl_lines = NULL;
00363         sl->sl_nalloc = 0;
00364         sl->sl_nlines = 0;
00365     }
00366     /*@=branchstate@*/
00367     return sl;
00368 }
00369 
00372 /*@-boundswrite@*/
00373 static inline /*@null@*/ speclines freeSl(/*@only@*/ /*@null@*/ speclines sl)
00374         /*@modifies sl @*/
00375 {
00376     int i;
00377     if (sl == NULL) return NULL;
00378     for (i = 0; i < sl->sl_nlines; i++)
00379         /*@-unqualifiedtrans@*/
00380         sl->sl_lines[i] = _free(sl->sl_lines[i]);
00381         /*@=unqualifiedtrans@*/
00382     sl->sl_lines = _free(sl->sl_lines);
00383     return _free(sl);
00384 }
00385 /*@=boundswrite@*/
00386 
00389 static inline /*@only@*/ /*@null@*/ spectags newSt(void)
00390         /*@*/
00391 {
00392     spectags st = NULL;
00393     /*@-branchstate@*/
00394     if (specedit) {
00395         st = xmalloc(sizeof(*st));
00396         st->st_t = NULL;
00397         st->st_nalloc = 0;
00398         st->st_ntags = 0;
00399     }
00400     /*@=branchstate@*/
00401     return st;
00402 }
00403 
00406 static inline /*@null@*/ spectags freeSt(/*@only@*/ /*@null@*/ spectags st)
00407         /*@modifies st @*/
00408 {
00409     int i;
00410     if (st == NULL) return NULL;
00411     for (i = 0; i < st->st_ntags; i++) {
00412         spectag t = st->st_t + i;
00413         t->t_lang = _free(t->t_lang);
00414         t->t_msgid = _free(t->t_msgid);
00415     }
00416     st->st_t = _free(st->st_t);
00417     return _free(st);
00418 }
00419 
00420 Spec newSpec(void)
00421 {
00422     Spec spec = xcalloc(1, sizeof(*spec));
00423     
00424     spec->specFile = NULL;
00425 
00426     spec->sl = newSl();
00427     spec->st = newSt();
00428 
00429     spec->fileStack = NULL;
00430 /*@-boundswrite@*/
00431     spec->lbuf[0] = '\0';
00432 /*@=boundswrite@*/
00433     spec->line = spec->lbuf;
00434     spec->nextline = NULL;
00435     spec->nextpeekc = '\0';
00436     spec->lineNum = 0;
00437     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
00438     spec->readStack->next = NULL;
00439     spec->readStack->reading = 1;
00440 
00441     spec->rootURL = NULL;
00442     spec->prep = NULL;
00443     spec->build = NULL;
00444     spec->install = NULL;
00445     spec->check = NULL;
00446     spec->clean = NULL;
00447 
00448     spec->sources = NULL;
00449     spec->packages = NULL;
00450     spec->noSource = 0;
00451     spec->numSources = 0;
00452 
00453     spec->sourceRpmName = NULL;
00454     spec->sourcePkgId = NULL;
00455     spec->sourceHeader = NULL;
00456     spec->sourceCpioList = NULL;
00457     
00458     spec->gotBuildRootURL = 0;
00459     spec->buildRootURL = NULL;
00460     spec->buildSubdir = NULL;
00461 
00462     spec->passPhrase = NULL;
00463     spec->timeCheck = 0;
00464     spec->cookie = NULL;
00465 
00466     spec->buildRestrictions = headerNew();
00467     spec->BANames = NULL;
00468     spec->BACount = 0;
00469     spec->recursing = 0;
00470     spec->BASpecs = NULL;
00471 
00472     spec->force = 0;
00473     spec->anyarch = 0;
00474 
00475 /*@i@*/ spec->macros = rpmGlobalMacroContext;
00476     
00477     return spec;
00478 }
00479 
00480 Spec freeSpec(Spec spec)
00481 {
00482     struct ReadLevelEntry *rl;
00483 
00484     if (spec == NULL) return NULL;
00485 
00486     spec->sl = freeSl(spec->sl);
00487     spec->st = freeSt(spec->st);
00488 
00489     spec->prep = freeStringBuf(spec->prep);
00490     spec->build = freeStringBuf(spec->build);
00491     spec->install = freeStringBuf(spec->install);
00492     spec->check = freeStringBuf(spec->check);
00493     spec->clean = freeStringBuf(spec->clean);
00494 
00495     spec->buildRootURL = _free(spec->buildRootURL);
00496     spec->buildSubdir = _free(spec->buildSubdir);
00497     spec->rootURL = _free(spec->rootURL);
00498     spec->specFile = _free(spec->specFile);
00499 
00500 #ifdef  DEAD
00501   { struct OpenFileInfo *ofi;
00502     while (spec->fileStack) {
00503         ofi = spec->fileStack;
00504         spec->fileStack = ofi->next;
00505         ofi->next = NULL;
00506         ofi->fileName = _free(ofi->fileName);
00507         ofi = _free(ofi);
00508     }
00509   }
00510 #else
00511     closeSpec(spec);
00512 #endif
00513 
00514     while (spec->readStack) {
00515         rl = spec->readStack;
00516         /*@-dependenttrans@*/
00517         spec->readStack = rl->next;
00518         /*@=dependenttrans@*/
00519         rl->next = NULL;
00520         rl = _free(rl);
00521     }
00522     
00523     spec->sourceRpmName = _free(spec->sourceRpmName);
00524     spec->sourcePkgId = _free(spec->sourcePkgId);
00525     spec->sourceHeader = headerFree(spec->sourceHeader);
00526 
00527     if (spec->sourceCpioList) {
00528         rpmfi fi = spec->sourceCpioList;
00529         spec->sourceCpioList = NULL;
00530         fi = rpmfiFree(fi);
00531     }
00532     
00533     spec->buildRestrictions = headerFree(spec->buildRestrictions);
00534 
00535     if (!spec->recursing) {
00536 /*@-boundswrite@*/
00537         if (spec->BASpecs != NULL)
00538         while (spec->BACount--) {
00539             /*@-unqualifiedtrans@*/
00540             spec->BASpecs[spec->BACount] =
00541                         freeSpec(spec->BASpecs[spec->BACount]);
00542             /*@=unqualifiedtrans@*/
00543         }
00544 /*@=boundswrite@*/
00545         /*@-compdef@*/
00546         spec->BASpecs = _free(spec->BASpecs);
00547         /*@=compdef@*/
00548     }
00549     spec->BANames = _free(spec->BANames);
00550 
00551     spec->passPhrase = _free(spec->passPhrase);
00552     spec->cookie = _free(spec->cookie);
00553 
00554     spec->sources = freeSources(spec->sources);
00555     spec->packages = freePackages(spec->packages);
00556     
00557     spec = _free(spec);
00558 
00559     return spec;
00560 }
00561 
00562 /*@only@*/
00563 struct OpenFileInfo * newOpenFileInfo(void)
00564 {
00565     struct OpenFileInfo *ofi;
00566 
00567     ofi = xmalloc(sizeof(*ofi));
00568     ofi->fd = NULL;
00569     ofi->fileName = NULL;
00570     ofi->lineNum = 0;
00571 /*@-boundswrite@*/
00572     ofi->readBuf[0] = '\0';
00573 /*@=boundswrite@*/
00574     ofi->readPtr = NULL;
00575     ofi->next = NULL;
00576 
00577     return ofi;
00578 }
00579 
00584 static void
00585 printNewSpecfile(Spec spec)
00586         /*@globals fileSystem @*/
00587         /*@modifies spec->sl->sl_lines[], fileSystem @*/
00588 {
00589     Header h;
00590     speclines sl = spec->sl;
00591     spectags st = spec->st;
00592     const char * msgstr = NULL;
00593     int i, j;
00594 
00595     if (sl == NULL || st == NULL)
00596         return;
00597 
00598     /*@-branchstate@*/
00599     for (i = 0; i < st->st_ntags; i++) {
00600         spectag t = st->st_t + i;
00601         const char * tn = tagName(t->t_tag);
00602         const char * errstr;
00603         char fmt[1024];
00604 
00605         fmt[0] = '\0';
00606         if (t->t_msgid == NULL)
00607             h = spec->packages->header;
00608         else {
00609             Package pkg;
00610             char *fe;
00611 
00612 /*@-bounds@*/
00613             strcpy(fmt, t->t_msgid);
00614             for (fe = fmt; *fe && *fe != '('; fe++)
00615                 {} ;
00616             if (*fe == '(') *fe = '\0';
00617 /*@=bounds@*/
00618             h = NULL;
00619             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00620                 const char *pkgname;
00621                 h = pkg->header;
00622                 (void) headerNVR(h, &pkgname, NULL, NULL);
00623                 if (!strcmp(pkgname, fmt))
00624                     /*@innerbreak@*/ break;
00625             }
00626             if (pkg == NULL || h == NULL)
00627                 h = spec->packages->header;
00628         }
00629 
00630         if (h == NULL)
00631             continue;
00632 
00633         fmt[0] = '\0';
00634 /*@-boundswrite@*/
00635         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
00636 /*@=boundswrite@*/
00637         msgstr = _free(msgstr);
00638 
00639         /* XXX this should use queryHeader(), but prints out tn as well. */
00640         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
00641         if (msgstr == NULL) {
00642             rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr);
00643             return;
00644         }
00645 
00646 /*@-boundswrite@*/
00647         switch(t->t_tag) {
00648         case RPMTAG_SUMMARY:
00649         case RPMTAG_GROUP:
00650             /*@-unqualifiedtrans@*/
00651             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
00652             /*@=unqualifiedtrans@*/
00653             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
00654                 continue;
00655             {   char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
00656                 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
00657                 sl->sl_lines[t->t_startx] = buf;
00658             }
00659             /*@switchbreak@*/ break;
00660         case RPMTAG_DESCRIPTION:
00661             for (j = 1; j < t->t_nlines; j++) {
00662                 if (*sl->sl_lines[t->t_startx + j] == '%')
00663                     /*@innercontinue@*/ continue;
00664                 /*@-unqualifiedtrans@*/
00665                 sl->sl_lines[t->t_startx + j] =
00666                         _free(sl->sl_lines[t->t_startx + j]);
00667                 /*@=unqualifiedtrans@*/
00668             }
00669             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
00670                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
00671                 continue;
00672             }
00673             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
00674             if (t->t_nlines > 2)
00675                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
00676             /*@switchbreak@*/ break;
00677         }
00678 /*@=boundswrite@*/
00679     }
00680     /*@=branchstate@*/
00681     msgstr = _free(msgstr);
00682 
00683 /*@-boundsread@*/
00684     for (i = 0; i < sl->sl_nlines; i++) {
00685         const char * s = sl->sl_lines[i];
00686         if (s == NULL)
00687             continue;
00688         printf("%s", s);
00689         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
00690             printf("\n");
00691     }
00692 /*@=boundsread@*/
00693 }
00694 
00695 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
00696 {
00697     Spec spec = NULL;
00698     Package pkg;
00699     char * buildRoot = NULL;
00700     int recursing = 0;
00701     char * passPhrase = "";
00702     char *cookie = NULL;
00703     int anyarch = 1;
00704     int force = 1;
00705     int res = 1;
00706     int xx;
00707 
00708     if (qva->qva_showPackage == NULL)
00709         goto exit;
00710 
00711 /*@-branchstate@*/
00712     /*@-mods@*/ /* FIX: make spec abstract */
00713     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
00714                 cookie, anyarch, force)
00715       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
00716     {
00717         rpmError(RPMERR_QUERY,
00718                         _("query of specfile %s failed, can't parse\n"), arg);
00719         goto exit;
00720     }
00721     /*@=mods@*/
00722 /*@=branchstate@*/
00723 
00724     res = 0;
00725     if (specedit) {
00726         printNewSpecfile(spec);
00727         goto exit;
00728     }
00729 
00730     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
00731         xx = qva->qva_showPackage(qva, ts, pkg->header);
00732 
00733 exit:
00734     spec = freeSpec(spec);
00735     return res;
00736 }

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2