rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

build/parseSpec.c
Go to the documentation of this file.

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