build/parseSpec.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>
00009 #include <rpmbuild.h>
00010 #include "rpmds.h"
00011 #include "rpmts.h"
00012 #include "debug.h"
00013 
00014 /*@access FD_t @*/      /* compared with NULL */
00015 
00018 /*@unchecked@*/
00019 static struct PartRec {
00020     int part;
00021     int len;
00022 /*@observer@*/ /*@null@*/
00023     const char * token;
00024 } partList[] = {
00025     { PART_PREAMBLE,      0, "%package"},
00026     { PART_PREP,          0, "%prep"},
00027     { PART_BUILD,         0, "%build"},
00028     { PART_INSTALL,       0, "%install"},
00029     { PART_CHECK,         0, "%check"},
00030     { PART_CLEAN,         0, "%clean"},
00031     { PART_PREUN,         0, "%preun"},
00032     { PART_POSTUN,        0, "%postun"},
00033     { PART_PRETRANS,      0, "%pretrans"},
00034     { PART_POSTTRANS,     0, "%posttrans"},
00035     { PART_PRE,           0, "%pre"},
00036     { PART_POST,          0, "%post"},
00037     { PART_FILES,         0, "%files"},
00038     { PART_CHANGELOG,     0, "%changelog"},
00039     { PART_DESCRIPTION,   0, "%description"},
00040     { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
00041     { PART_TRIGGERPREIN,  0, "%triggerprein"},
00042     { PART_TRIGGERUN,     0, "%triggerun"},
00043     { PART_TRIGGERIN,     0, "%triggerin"},
00044     { PART_TRIGGERIN,     0, "%trigger"},
00045     { PART_VERIFYSCRIPT,  0, "%verifyscript"},
00046     {0, 0, 0}
00047 };
00048 
00051 static inline void initParts(struct PartRec *p)
00052         /*@modifies p->len @*/
00053 {
00054     for (; p->token != NULL; p++)
00055         p->len = strlen(p->token);
00056 }
00057 
00058 rpmParseState isPart(const char *line)
00059 {
00060     struct PartRec *p;
00061 
00062 /*@-boundsread@*/
00063     if (partList[0].len == 0)
00064         initParts(partList);
00065 /*@=boundsread@*/
00066     
00067     for (p = partList; p->token != NULL; p++) {
00068         char c;
00069         if (xstrncasecmp(line, p->token, p->len))
00070             continue;
00071 /*@-boundsread@*/
00072         c = *(line + p->len);
00073 /*@=boundsread@*/
00074         if (c == '\0' || xisspace(c))
00075             break;
00076     }
00077 
00078     return (p->token ? p->part : PART_NONE);
00079 }
00080 
00083 static int matchTok(const char *token, const char *line)
00084         /*@*/
00085 {
00086     const char *b, *be = line;
00087     size_t toklen = strlen(token);
00088     int rc = 0;
00089 
00090 /*@-boundsread@*/
00091     while ( *(b = be) != '\0' ) {
00092         SKIPSPACE(b);
00093         be = b;
00094         SKIPNONSPACE(be);
00095         if (be == b)
00096             break;
00097         if (toklen != (be-b) || xstrncasecmp(token, b, (be-b)))
00098             continue;
00099         rc = 1;
00100         break;
00101     }
00102 /*@=boundsread@*/
00103 
00104     return rc;
00105 }
00106 
00107 /*@-boundswrite@*/
00108 void handleComments(char *s)
00109 {
00110     SKIPSPACE(s);
00111     if (*s == '#')
00112         *s = '\0';
00113 }
00114 /*@=boundswrite@*/
00115 
00118 static void forceIncludeFile(Spec spec, const char * fileName)
00119         /*@modifies spec->fileStack @*/
00120 {
00121     OFI_t * ofi;
00122 
00123     ofi = newOpenFileInfo();
00124     ofi->fileName = xstrdup(fileName);
00125     ofi->next = spec->fileStack;
00126     spec->fileStack = ofi;
00127 }
00128 
00131 /*@-boundswrite@*/
00132 static int copyNextLine(Spec spec, OFI_t *ofi, int strip)
00133         /*@globals rpmGlobalMacroContext, h_errno,
00134                 fileSystem @*/
00135         /*@modifies spec->nextline, spec->nextpeekc, spec->lbuf, spec->line,
00136                 ofi->readPtr,
00137                 rpmGlobalMacroContext, fileSystem @*/
00138 {
00139     char *last;
00140     char ch;
00141 
00142     /* Restore 1st char in (possible) next line */
00143     if (spec->nextline != NULL && spec->nextpeekc != '\0') {
00144         *spec->nextline = spec->nextpeekc;
00145         spec->nextpeekc = '\0';
00146     }
00147     /* Expand next line from file into line buffer */
00148     if (!(spec->nextline && *spec->nextline)) {
00149         int pc = 0, bc = 0, nc = 0;
00150         char *from, *to, *p;
00151         to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
00152         from = ofi->readPtr;
00153         ch = ' ';
00154         while (*from && ch != '\n')
00155             ch = *to++ = *from++;
00156 /*@-mods@*/
00157         spec->lbufPtr = to;
00158 /*@=mods@*/
00159         *to++ = '\0';
00160         ofi->readPtr = from;
00161 
00162         /* Check if we need another line before expanding the buffer. */
00163         for (p = spec->lbuf; *p; p++) {
00164             switch (*p) {
00165                 case '\\':
00166                     switch (*(p+1)) {
00167                         case '\n': p++, nc = 1; /*@innerbreak@*/ break;
00168                         case '\0': /*@innerbreak@*/ break;
00169                         default: p++; /*@innerbreak@*/ break;
00170                     }
00171                     /*@switchbreak@*/ break;
00172                 case '\n': nc = 0; /*@switchbreak@*/ break;
00173                 case '%':
00174                     switch (*(p+1)) {
00175                         case '{': p++, bc++; /*@innerbreak@*/ break;
00176                         case '(': p++, pc++; /*@innerbreak@*/ break;
00177                         case '%': p++; /*@innerbreak@*/ break;
00178                     }
00179                     /*@switchbreak@*/ break;
00180                 case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
00181                 case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
00182                 case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
00183                 case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
00184             }
00185         }
00186         
00187         /* If it doesn't, ask for one more line. We need a better
00188          * error code for this. */
00189         if (pc || bc || nc ) {
00190 /*@-observertrans -readonlytrans@*/
00191             spec->nextline = "";
00192 /*@=observertrans =readonlytrans@*/
00193             return RPMERR_UNMATCHEDIF;
00194         }
00195 /*@-mods@*/
00196         spec->lbufPtr = spec->lbuf;
00197 /*@=mods@*/
00198 
00199         /* Don't expand macros (eg. %define) in false branch of %if clause */
00200         /* Also don't expand macros in %changelog where we set STRIP_NOEXPAND flag */
00201         /* (first line is ommited, so if there is e.g. %date macro, it will be expanded */
00202         if (!(strip & STRIP_NOEXPAND)) {
00203         if (spec->readStack->reading &&
00204             expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
00205                 rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
00206                         spec->lineNum, spec->lbuf);
00207                 return RPMERR_BADSPEC;
00208         }
00209         }       
00210         spec->nextline = spec->lbuf;
00211     }
00212 
00213     /* Find next line in expanded line buffer */
00214     spec->line = last = spec->nextline;
00215     ch = ' ';
00216     while (*spec->nextline && ch != '\n') {
00217         ch = *spec->nextline++;
00218         if (!xisspace(ch))
00219             last = spec->nextline;
00220     }
00221 
00222     /* Save 1st char of next line in order to terminate current line. */
00223     if (*spec->nextline != '\0') {
00224         spec->nextpeekc = *spec->nextline;
00225         *spec->nextline = '\0';
00226     }
00227     
00228     if (strip & STRIP_COMMENTS)
00229         handleComments(spec->line);
00230     
00231     if (strip & STRIP_TRAILINGSPACE)
00232         *last = '\0';
00233 
00234     return 0;
00235 }
00236 /*@=boundswrite@*/
00237 
00238 static const char *getAlternateArch(const char *arch)
00239 {
00240     const char *alternate_arch = NULL;
00241     if (! strncmp("x86_64", arch, sizeof("x86_64")-1))
00242       alternate_arch = "amd64";
00243     else if (! strncmp("amd64", arch, sizeof("amd64")-1))
00244       alternate_arch = "x86_64";
00245     return alternate_arch;
00246 }
00247 
00248 /*@-boundswrite@*/
00249 int readLine(Spec spec, int strip)
00250 {
00251 #ifdef  DYING
00252     const char *arch;
00253     const char *os;
00254 #endif
00255     char  *s;
00256     int match;
00257     struct ReadLevelEntry *rl;
00258     OFI_t *ofi = spec->fileStack;
00259     int rc;
00260 
00261 retry:
00262     /* Make sure the current file is open */
00263     /*@-branchstate@*/
00264     if (ofi->fd == NULL) {
00265         ofi->fd = Fopen(ofi->fileName, "r.fpio");
00266         if (ofi->fd == NULL || Ferror(ofi->fd)) {
00267             /* XXX Fstrerror */
00268             rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
00269                      ofi->fileName, Fstrerror(ofi->fd));
00270             return RPMERR_BADSPEC;
00271         }
00272         spec->lineNum = ofi->lineNum = 0;
00273     }
00274     /*@=branchstate@*/
00275 
00276     /* Make sure we have something in the read buffer */
00277     if (!(ofi->readPtr && *(ofi->readPtr))) {
00278         /*@-type@*/ /* FIX: cast? */
00279         FILE * f = fdGetFp(ofi->fd);
00280         /*@=type@*/
00281         if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
00282             /* EOF */
00283             if (spec->readStack->next) {
00284                 rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
00285                 return RPMERR_UNMATCHEDIF;
00286             }
00287 
00288             /* remove this file from the stack */
00289             spec->fileStack = ofi->next;
00290             (void) Fclose(ofi->fd);
00291             ofi->fileName = _free(ofi->fileName);
00292             ofi = _free(ofi);
00293 
00294             /* only on last file do we signal EOF to caller */
00295             ofi = spec->fileStack;
00296             if (ofi == NULL)
00297                 return 1;
00298 
00299             /* otherwise, go back and try the read again. */
00300             goto retry;
00301         }
00302         ofi->readPtr = ofi->readBuf;
00303         ofi->lineNum++;
00304         spec->lineNum = ofi->lineNum;
00305         if (spec->sl) {
00306             speclines sl = spec->sl;
00307             if (sl->sl_nlines == sl->sl_nalloc) {
00308                 sl->sl_nalloc += 100;
00309                 sl->sl_lines = (char **) xrealloc(sl->sl_lines, 
00310                         sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00311             }
00312             sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00313         }
00314     }
00315     
00316     /* Copy next file line into the spec line buffer */
00317     if ((rc = copyNextLine(spec, ofi, strip)) != 0) {
00318         if (rc == RPMERR_UNMATCHEDIF)
00319             goto retry;
00320         return rc;
00321     }
00322 
00323     s = spec->line;
00324     SKIPSPACE(s);
00325 
00326     match = -1;
00327     if (! (strip & STRIP_NOEXPAND)) {
00328     if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00329         match = 0;
00330     } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00331         const char *arch = rpmExpand("%{_target_cpu}", NULL);
00332         const char *alternate_arch = getAlternateArch(arch);
00333         s += 7;
00334         match = matchTok(arch, s) || (alternate_arch && matchTok(alternate_arch, s));
00335         arch = _free(arch);
00336     } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00337         const char *arch = rpmExpand("%{_target_cpu}", NULL);
00338         const char *alternate_arch = getAlternateArch(arch);
00339         s += 8;
00340         match = !matchTok(arch, s) && (!alternate_arch || !matchTok(alternate_arch, s));
00341         arch = _free(arch);
00342     } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00343         const char *os = rpmExpand("%{_target_os}", NULL);
00344         s += 5;
00345         match = matchTok(os, s);
00346         os = _free(os);
00347     } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00348         const char *os = rpmExpand("%{_target_os}", NULL);
00349         s += 6;
00350         match = !matchTok(os, s);
00351         os = _free(os);
00352     } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00353         s += 3;
00354         match = parseExpressionBoolean(spec, s);
00355         if (match < 0) {
00356             rpmError(RPMERR_UNMATCHEDIF,
00357                         _("%s:%d: parseExpressionBoolean returns %d\n"),
00358                         ofi->fileName, ofi->lineNum, match);
00359             return RPMERR_BADSPEC;
00360         }
00361     } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00362         s += 5;
00363         if (! spec->readStack->next) {
00364             /* Got an else with no %if ! */
00365             rpmError(RPMERR_UNMATCHEDIF,
00366                         _("%s:%d: Got a %%else with no %%if\n"),
00367                         ofi->fileName, ofi->lineNum);
00368             return RPMERR_UNMATCHEDIF;
00369         }
00370         spec->readStack->reading =
00371             spec->readStack->next->reading && ! spec->readStack->reading;
00372         spec->line[0] = '\0';
00373     } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00374         s += 6;
00375         if (! spec->readStack->next) {
00376             /* Got an end with no %if ! */
00377             rpmError(RPMERR_UNMATCHEDIF,
00378                         _("%s:%d: Got a %%endif with no %%if\n"),
00379                         ofi->fileName, ofi->lineNum);
00380             return RPMERR_UNMATCHEDIF;
00381         }
00382         rl = spec->readStack;
00383         spec->readStack = spec->readStack->next;
00384         free(rl);
00385         spec->line[0] = '\0';
00386     } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00387         char *fileName, *endFileName, *p;
00388 
00389         s += 8;
00390         fileName = s;
00391         if (! xisspace(*fileName)) {
00392             rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00393             return RPMERR_BADSPEC;
00394         }
00395         SKIPSPACE(fileName);
00396         endFileName = fileName;
00397         SKIPNONSPACE(endFileName);
00398         p = endFileName;
00399         SKIPSPACE(p);
00400         if (*p != '\0') {
00401             rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00402             return RPMERR_BADSPEC;
00403         }
00404         *endFileName = '\0';
00405 
00406         forceIncludeFile(spec, fileName);
00407 
00408         ofi = spec->fileStack;
00409         goto retry;
00410     }
00411     }
00412 
00413     if (match != -1) {
00414         rl = xmalloc(sizeof(*rl));
00415         rl->reading = spec->readStack->reading && match;
00416         rl->next = spec->readStack;
00417         spec->readStack = rl;
00418         spec->line[0] = '\0';
00419     }
00420 
00421     if (! spec->readStack->reading) {
00422         spec->line[0] = '\0';
00423     }
00424 
00425     /*@-compmempass@*/ /* FIX: spec->readStack->next should be dependent */
00426     return 0;
00427     /*@=compmempass@*/
00428 }
00429 /*@=boundswrite@*/
00430 
00431 void closeSpec(Spec spec)
00432 {
00433     OFI_t *ofi;
00434 
00435     while (spec->fileStack) {
00436         ofi = spec->fileStack;
00437         spec->fileStack = spec->fileStack->next;
00438         if (ofi->fd) (void) Fclose(ofi->fd);
00439         ofi->fileName = _free(ofi->fileName);
00440         ofi = _free(ofi);
00441     }
00442 }
00443 
00444 /*@-redecl@*/
00445 /*@unchecked@*/
00446 extern int noLang;              /* XXX FIXME: pass as arg */
00447 /*@=redecl@*/
00448 
00449 /*@todo Skip parse recursion if os is not compatible. @*/
00450 /*@-boundswrite@*/
00451 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00452                 int recursing, const char *passPhrase,
00453                 char *cookie, int anyarch, int force, int verify)
00454 {
00455     rpmParseState parsePart = PART_PREAMBLE;
00456     int initialPackage = 1;
00457     Package pkg;
00458     Spec spec;
00459     
00460     /* Set up a new Spec structure with no packages. */
00461     spec = newSpec();
00462 
00463     /*
00464      * Note: rpmGetPath should guarantee a "canonical" path. That means
00465      * that the following pathologies should be weeded out:
00466      *          //bin//sh
00467      *          //usr//bin/
00468      *          /.././../usr/../bin//./sh (XXX FIXME: dots not handled yet)
00469      */
00470     spec->specFile = rpmGetPath(specFile, NULL);
00471     spec->fileStack = newOpenFileInfo();
00472     spec->fileStack->fileName = xstrdup(spec->specFile);
00473 
00474     spec->recursing = recursing;
00475     spec->anyarch = anyarch;
00476     spec->force = force;
00477 
00478     if (rootURL)
00479         spec->rootURL = xstrdup(rootURL);
00480     if (passPhrase)
00481         spec->passPhrase = xstrdup(passPhrase);
00482     if (cookie)
00483         spec->cookie = xstrdup(cookie);
00484 
00485     spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00486 
00487     /* XXX %_docdir should be set somewhere else. */
00488     addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00489 
00490     /* All the parse*() functions expect to have a line pre-read */
00491     /* in the spec's line buffer.  Except for parsePreamble(),   */
00492     /* which handles the initial entry into a spec file.         */
00493     
00494     /*@-infloops@*/     /* LCL: parsePart is modified @*/
00495     while (parsePart < PART_LAST && parsePart != PART_NONE) {
00496         switch (parsePart) {
00497         case PART_PREAMBLE:
00498             parsePart = parsePreamble(spec, initialPackage);
00499             initialPackage = 0;
00500             /*@switchbreak@*/ break;
00501         case PART_PREP:
00502             parsePart = parsePrep(spec, verify);
00503             /*@switchbreak@*/ break;
00504         case PART_BUILD:
00505         case PART_INSTALL:
00506         case PART_CHECK:
00507         case PART_CLEAN:
00508             parsePart = parseBuildInstallClean(spec, parsePart);
00509             /*@switchbreak@*/ break;
00510         case PART_CHANGELOG:
00511             parsePart = parseChangelog(spec);
00512             /*@switchbreak@*/ break;
00513         case PART_DESCRIPTION:
00514             parsePart = parseDescription(spec);
00515             /*@switchbreak@*/ break;
00516 
00517         case PART_PRE:
00518         case PART_POST:
00519         case PART_PREUN:
00520         case PART_POSTUN:
00521         case PART_PRETRANS:
00522         case PART_POSTTRANS:
00523         case PART_VERIFYSCRIPT:
00524         case PART_TRIGGERPREIN:
00525         case PART_TRIGGERIN:
00526         case PART_TRIGGERUN:
00527         case PART_TRIGGERPOSTUN:
00528             parsePart = parseScript(spec, parsePart);
00529             /*@switchbreak@*/ break;
00530 
00531         case PART_FILES:
00532             parsePart = parseFiles(spec);
00533             /*@switchbreak@*/ break;
00534 
00535         case PART_NONE:         /* XXX avoid gcc whining */
00536         case PART_LAST:
00537         case PART_BUILDARCHITECTURES:
00538             /*@switchbreak@*/ break;
00539         }
00540 
00541         if (parsePart >= PART_LAST) {
00542             spec = freeSpec(spec);
00543             return parsePart;
00544         }
00545 
00546         if (parsePart == PART_BUILDARCHITECTURES) {
00547             int index;
00548             int x;
00549 
00550             closeSpec(spec);
00551 
00552             /* LCL: sizeof(spec->BASpecs[0]) -nullderef whine here */
00553             spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
00554             index = 0;
00555             if (spec->BANames != NULL)
00556             for (x = 0; x < spec->BACount; x++) {
00557 
00558                 /* XXX DIEDIEDIE: filter irrelevant platforms here. */
00559 
00560                 /* XXX there's more to do than set the macro. */
00561                 addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
00562                 spec->BASpecs[index] = NULL;
00563                 if (parseSpec(ts, specFile, spec->rootURL, 1,
00564                                   passPhrase, cookie, anyarch, force, verify)
00565                  || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
00566                 {
00567                         spec->BACount = index;
00568 /*@-nullstate@*/
00569                         spec = freeSpec(spec);
00570                         return RPMERR_BADSPEC;
00571 /*@=nullstate@*/
00572                 }
00573 
00574                 /* XXX there's more to do than delete the macro. */
00575                 delMacro(NULL, "_target_cpu");
00576                 index++;
00577             }
00578 
00579             spec->BACount = index;
00580             if (! index) {
00581                 rpmError(RPMERR_BADSPEC,
00582                         _("No compatible architectures found for build\n"));
00583 /*@-nullstate@*/
00584                 spec = freeSpec(spec);
00585                 return RPMERR_BADSPEC;
00586 /*@=nullstate@*/
00587             }
00588 
00589             /*
00590              * Return the 1st child's fully parsed Spec structure.
00591              * The restart of the parse when encountering BuildArch
00592              * causes problems for "rpm -q --specfile". This is
00593              * still a hack because there may be more than 1 arch
00594              * specified (unlikely but possible.) There's also the
00595              * further problem that the macro context, particularly
00596              * %{_target_cpu}, disagrees with the info in the header.
00597              */
00598             /*@-branchstate@*/
00599             if (spec->BACount >= 1) {
00600                 Spec nspec = spec->BASpecs[0];
00601                 spec->BASpecs = _free(spec->BASpecs);
00602                 spec = freeSpec(spec);
00603                 spec = nspec;
00604             }
00605             /*@=branchstate@*/
00606 
00607             (void) rpmtsSetSpec(ts, spec);
00608             return 0;
00609         }
00610     }
00611     /*@=infloops@*/     /* LCL: parsePart is modified @*/
00612 
00613     /* Check for description in each package and add arch and os */
00614   {
00615     const char *platform = rpmExpand("%{_target_platform}", NULL);
00616     const char *arch = rpmExpand("%{_target_cpu}", NULL);
00617     const char *os = rpmExpand("%{_target_os}", NULL);
00618 
00619     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00620         if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00621             const char * name;
00622             (void) headerNVR(pkg->header, &name, NULL, NULL);
00623             rpmError(RPMERR_BADSPEC, _("Package has no %%description: %s\n"),
00624                         name);
00625             spec = freeSpec(spec);
00626             return RPMERR_BADSPEC;
00627         }
00628 
00629         (void) headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
00630         (void) headerAddEntry(pkg->header, RPMTAG_ARCH,
00631                 RPM_STRING_TYPE, arch, 1);
00632         (void) headerAddEntry(pkg->header, RPMTAG_PLATFORM,
00633                 RPM_STRING_TYPE, platform, 1);
00634 
00635         pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00636 
00637     }
00638 
00639     platform = _free(platform);
00640     arch = _free(arch);
00641     os = _free(os);
00642   }
00643 
00644     closeSpec(spec);
00645     (void) rpmtsSetSpec(ts, spec);
00646 
00647     return 0;
00648 }
00649 /*@=boundswrite@*/

Generated on Mon Aug 23 10:39:54 2010 for rpm by  doxygen 1.5.1