Main Page Modules Data Structures File List Data Fields Globals Related Pages

# build/parseSpec.c

Go to the documentation of this file.

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