rpm 5.2.1

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

- File List
- Globals

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

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio.h>
    00009 #include <rpmiotypes.h>
    00010 #include <rpmlog.h>
    00011 #include <rpmurl.h>
    00012 #include <argv.h>
    00013 #include <mire.h>
    00014
    00015 #define _RPMEVR_INTERNAL
    00016 #define _RPMTAG_INTERNAL        /* XXX rpmTags->aTags */
    00017 #include <rpmbuild.h>
    00018 #include "debug.h"
    00019
    00020 /*@access FD_t @*/      /* compared with NULL */
    00021 /*@access headerTagIndices @*/  /* rpmTags->aTags */
    00022
    00025 /*@observer@*/ /*@unchecked@*/
    00026 static rpmTag copyTagsDuringParse[] = {
    00027     RPMTAG_EPOCH,
    00028     RPMTAG_VERSION,
    00029     RPMTAG_RELEASE,
    00030     RPMTAG_DISTEPOCH,
    00031     RPMTAG_LICENSE,
    00032     RPMTAG_GROUP,               /* XXX permissive. */
    00033     RPMTAG_SUMMARY,             /* XXX permissive. */
    00034     RPMTAG_DESCRIPTION,         /* XXX permissive. */
    00035     RPMTAG_PACKAGER,
    00036     RPMTAG_DISTRIBUTION,
    00037     RPMTAG_DISTURL,
    00038     RPMTAG_VENDOR,
    00039     RPMTAG_ICON,
    00040     RPMTAG_GIF,
    00041     RPMTAG_XPM,
    00042     RPMTAG_URL,
    00043     RPMTAG_CHANGELOGTIME,
    00044     RPMTAG_CHANGELOGNAME,
    00045     RPMTAG_CHANGELOGTEXT,
    00046     RPMTAG_PREFIXES,
    00047     RPMTAG_DISTTAG,
    00048     RPMTAG_CVSID,
    00049     RPMTAG_VARIANTS,
    00050     RPMTAG_XMAJOR,
    00051     RPMTAG_XMINOR,
    00052     RPMTAG_REPOTAG,
    00053     RPMTAG_KEYWORDS,
    00054     0
    00055 };
    00056
    00059 /*@observer@*/ /*@unchecked@*/
    00060 static rpmTag requiredTags[] = {
    00061     RPMTAG_NAME,
    00062     RPMTAG_VERSION,
    00063     RPMTAG_RELEASE,
    00064     RPMTAG_SUMMARY,
    00065     RPMTAG_GROUP,
    00066     RPMTAG_LICENSE,
    00067     0
    00068 };
    00069
    00072 static void addOrAppendListEntry(Header h, rpmTag tag, char * line)
    00073         /*@modifies h @*/
    00074 {
    00075     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00076     int xx;
    00077     int argc;
    00078     const char **argv;
    00079
    00080     xx = poptParseArgvString(line, &argc, &argv);
    00081     if (argc) {
    00082         he->tag = tag;
    00083         he->t = RPM_STRING_ARRAY_TYPE;
    00084         he->p.argv = argv;
    00085         he->c = argc;
    00086         he->append = 1;
    00087         xx = headerPut(h, he, 0);
    00088         he->append = 0;
    00089     }
    00090     argv = _free(argv);
    00091 }
    00092
    00093 /* Parse a simple part line that only take -n <pkg> or <pkg> */
    00094 /* <pkg> is returned in name as a pointer into malloc'd storage. */
    00095
    00098 static int parseSimplePart(Spec spec, /*@out@*/char ** Np,
    00099                 /*@out@*/rpmParseState *flag)
    00100         /*@globals internalState@*/
    00101         /*@modifies *Np, *flag, internalState, spec->line @*/
    00102 {
    00103     char * s, * se;
    00104     int rc = 0;         /* assume failure */
    00105
    00106     if (Np)
    00107         *Np = NULL;
    00108
    00109     se = strchr(spec->line, '#');
    00110     if (se) {
    00111         *se = '\0';
    00112         while (--se >= spec->line && strchr(" \t\n\r", *se) != NULL)
    00113             *se = '\0';
    00114     }
    00115
    00116     s = xstrdup(spec->line);
    00117     /* Throw away the first token (the %xxxx) */
    00118     (void)strtok(s, " \t\n");
    00119
    00120     if (!(se = strtok(NULL, " \t\n")))
    00121         goto exit;
    00122
    00123     if (!strcmp(se, "-n")) {
    00124         if (!(se = strtok(NULL, " \t\n"))) {
    00125             rc = 1;
    00126             goto exit;
    00127         }
    00128         *flag = PART_NAME;
    00129     } else
    00130         *flag = PART_SUBNAME;
    00131
    00132     if (Np)
    00133         *Np = xstrdup(se);
    00134
    00135     rc = (strtok(NULL, " \t\n") ? 1 : 0);
    00136
    00137 exit:
    00138     s = _free(s);
    00139     return rc;
    00140 }
    00141
    00144 static inline int parseYesNo(const char * s)
    00145         /*@*/
    00146 {
    00147     return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
    00148         !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off"))
    00149             ? 0 : 1);
    00150 }
    00151
    00152 typedef struct tokenBits_s {
    00153 /*@observer@*/ /*@null@*/
    00154     const char * name;
    00155     rpmsenseFlags bits;
    00156 } * tokenBits;
    00157
    00160 /*@observer@*/ /*@unchecked@*/
    00161 static struct tokenBits_s installScriptBits[] = {
    00162     { "interp",         RPMSENSE_INTERP },
    00163     { "preun",          RPMSENSE_SCRIPT_PREUN },
    00164     { "pre",            RPMSENSE_SCRIPT_PRE },
    00165     { "postun",         RPMSENSE_SCRIPT_POSTUN },
    00166     { "post",           RPMSENSE_SCRIPT_POST },
    00167     { "rpmlib",         RPMSENSE_RPMLIB },
    00168     { "verify",         RPMSENSE_SCRIPT_VERIFY },
    00169     { "hint",           RPMSENSE_MISSINGOK },
    00170     { NULL, 0 }
    00171 };
    00172
    00175 /*@observer@*/ /*@unchecked@*/
    00176 static struct tokenBits_s buildScriptBits[] = {
    00177     { "prep",           RPMSENSE_SCRIPT_PREP },
    00178     { "build",          RPMSENSE_SCRIPT_BUILD },
    00179     { "install",        RPMSENSE_SCRIPT_INSTALL },
    00180     { "clean",          RPMSENSE_SCRIPT_CLEAN },
    00181     { "hint",           RPMSENSE_MISSINGOK },
    00182     { NULL, 0 }
    00183 };
    00184
    00187 static int parseBits(const char * s, const tokenBits tokbits,
    00188                 /*@out@*/ rpmsenseFlags * bp)
    00189         /*@modifies *bp @*/
    00190 {
    00191     tokenBits tb;
    00192     const char * se;
    00193     rpmsenseFlags bits = RPMSENSE_ANY;
    00194     int c = 0;
    00195
    00196     if (s) {
    00197         while (*s != '\0') {
    00198             while ((c = *s) && xisspace(c)) s++;
    00199             se = s;
    00200             while ((c = *se) && xisalpha(c)) se++;
    00201             if (s == se)
    00202                 break;
    00203             for (tb = tokbits; tb->name; tb++) {
    00204                 if (tb->name != NULL &&
    00205                     strlen(tb->name) == (size_t)(se-s) && !strncmp(tb->name, s, (se-s)))
    00206                     /*@innerbreak@*/ break;
    00207             }
    00208             if (tb->name == NULL)
    00209                 break;
    00210             bits |= tb->bits;
    00211             while ((c = *se) && xisspace(c)) se++;
    00212             if (c != ',')
    00213                 break;
    00214             s = ++se;
    00215         }
    00216     }
    00217     if (c == 0 && bp) *bp = bits;
    00218     return (c ? RPMRC_FAIL : RPMRC_OK);
    00219 }
    00220
    00223 /*@null@*/
    00224 static inline char * findLastChar(char * s)
    00225         /*@modifies *s @*/
    00226 {
    00227     char *se = s + strlen(s);
    00228
    00229     /* Right trim white space. */
    00230     while (--se > s && strchr(" \t\n\r", *se) != NULL)
    00231         *se = '\0';
    00232     /* Truncate comments. */
    00233     if ((se = strchr(s, '#')) != NULL) {
    00234         *se = '\0';
    00235         while (--se > s && strchr(" \t\n\r", *se) != NULL)
    00236             *se = '\0';
    00237     }
    00238 /*@-temptrans -retalias @*/
    00239     return se;
    00240 /*@=temptrans =retalias @*/
    00241 }
    00242
    00245 static int isMemberInEntry(Header h, const char *name, rpmTag tag)
    00246         /*@globals internalState @*/
    00247         /*@modifies internalState @*/
    00248 {
    00249     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00250     int rc = -1;
    00251     int xx;
    00252
    00253     he->tag = tag;
    00254     xx = headerGet(h, he, 0);
    00255     if (!xx)
    00256         return rc;
    00257     rc = 0;
    00258     while (he->c) {
    00259         he->c--;
    00260         if (xstrcasecmp(he->p.argv[he->c], name))
    00261             continue;
    00262         rc = 1;
    00263         break;
    00264     }
    00265     he->p.ptr = _free(he->p.ptr);
    00266     return rc;
    00267 }
    00268
    00271 static int checkForValidArchitectures(Spec spec)
    00272         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00273         /*@modifies rpmGlobalMacroContext, internalState @*/
    00274 {
    00275     const char *arch = rpmExpand("%{_target_cpu}", NULL);
    00276     const char *os = rpmExpand("%{_target_os}", NULL);
    00277     int rc = RPMRC_FAIL;        /* assume failure. */
    00278
    00279     if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUDEARCH) == 1) {
    00280         rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
    00281         goto exit;
    00282     }
    00283     if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUSIVEARCH) == 0) {
    00284         rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
    00285         goto exit;
    00286     }
    00287     if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUDEOS) == 1) {
    00288         rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
    00289         goto exit;
    00290     }
    00291     if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUSIVEOS) == 0) {
    00292         rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
    00293         goto exit;
    00294     }
    00295     rc = 0;
    00296 exit:
    00297     arch = _free(arch);
    00298     os = _free(os);
    00299     return rc;
    00300 }
    00301
    00308 static rpmRC checkForRequired(Header h, const char * NVR)
    00309         /*@*/
    00310 {
    00311     rpmTag * p;
    00312     rpmRC rc = RPMRC_OK;
    00313
    00314     for (p = requiredTags; *p != 0; p++) {
    00315         if (!headerIsEntry(h, *p)) {
    00316             rpmlog(RPMLOG_ERR,
    00317                         _("%s field must be present in package: %s\n"),
    00318                         tagName(*p), NVR);
    00319             rc = RPMRC_FAIL;
    00320         }
    00321     }
    00322
    00323     return rc;
    00324 }
    00325
    00332 static rpmRC checkForDuplicates(Header h, const char * NVR)
    00333         /*@globals internalState @*/
    00334         /*@modifies h, internalState @*/
    00335 {
    00336     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00337     HeaderIterator hi;
    00338     rpmTag lastTag = 0;
    00339     rpmRC rc = RPMRC_OK;
    00340
    00341     for (hi = headerInit(h);
    00342         headerNext(hi, he, 0);
    00343         he->p.ptr = _free(he->p.ptr))
    00344     {
    00345         if (he->tag != lastTag) {
    00346             lastTag = he->tag;
    00347             continue;
    00348         }
    00349         rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
    00350                      tagName(he->tag), NVR);
    00351         rc = RPMRC_FAIL;
    00352     }
    00353     hi = headerFini(hi);
    00354
    00355     return rc;
    00356 }
    00357
    00360 /*@observer@*/ /*@unchecked@*/
    00361 static struct optionalTag {
    00362     rpmTag      ot_tag;
    00363 /*@observer@*/ /*@null@*/
    00364     const char * ot_mac;
    00365 } optionalTags[] = {
    00366     { RPMTAG_VENDOR,            "%{vendor}" },
    00367     { RPMTAG_PACKAGER,          "%{packager}" },
    00368     { RPMTAG_DISTEPOCH,         "%{distepoch}" },
    00369     { RPMTAG_DISTRIBUTION,      "%{distribution}" },
    00370     { RPMTAG_DISTTAG,           "%{disttag}" },
    00371     { RPMTAG_DISTURL,           "%{disturl}" },
    00372     { 0xffffffff,               "%{class}" },
    00373     { -1, NULL }
    00374 };
    00375
    00378 static void fillOutMainPackage(Header h)
    00379         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00380         /*@modifies h, rpmGlobalMacroContext, internalState @*/
    00381 {
    00382     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00383     struct optionalTag *ot;
    00384     int xx;
    00385
    00386     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
    00387         const char * val;
    00388         rpmTag tag;
    00389
    00390         tag = ot->ot_tag;
    00391
    00392         /* Generate arbitrary tag (if necessary). */
    00393         if (tag == 0xffffffff) {
    00394             val = tagCanonicalize(ot->ot_mac + (sizeof("%{")-1));
    00395             tag = tagGenerate(val);
    00396             val = _free(val);
    00397         }
    00398
    00399         if (headerIsEntry(h, tag))
    00400             continue;
    00401         val = rpmExpand(ot->ot_mac, NULL);
    00402         if (val && *val != '%') {
    00403                 he->tag = tag;
    00404                 he->t = RPM_STRING_TYPE;
    00405                 he->p.str = val;
    00406                 he->c = 1;
    00407                 xx = headerPut(h, he, 0);
    00408         }
    00409         val = _free(val);
    00410     }
    00411 }
    00412
    00415 static int doIcon(Spec spec, Header h)
    00416         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00417         /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState  @*/
    00418 {
    00419     static size_t iconsize = 0;
    00420     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00421     const char *fn, *Lurlfn = NULL;
    00422     struct Source *sp;
    00423     size_t nb;
    00424     rpmuint8_t * icon;
    00425     FD_t fd = NULL;
    00426     int rc = RPMRC_FAIL;        /* assume error */
    00427     int urltype;
    00428     int xx;
    00429
    00430     if (iconsize == 0) {
    00431         iconsize = rpmExpandNumeric("%{?_build_iconsize}");
    00432         if (iconsize < 2048)
    00433             iconsize = 2048;
    00434     }
    00435     icon = alloca(iconsize+1);
    00436
    00437     for (sp = spec->sources; sp != NULL; sp = sp->next) {
    00438         if (sp->flags & RPMFILE_ICON)
    00439             break;
    00440     }
    00441     if (sp == NULL) {
    00442         rpmlog(RPMLOG_ERR, _("No icon file in sources\n"));
    00443         goto exit;
    00444     }
    00445
    00446 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
    00447     /* support splitted source directories, i.e., source files which
    00448        are alternatively placed into the .spec directory and picked
    00449        up from there, too. */
    00450     Lurlfn = rpmGenPath(NULL, "%{_specdir}/", sp->source);
    00451     if (access(Lurlfn, F_OK) == -1) {
    00452         Lurlfn = _free(Lurlfn);
    00453         Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
    00454     }
    00455 #else
    00456     Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
    00457 #endif
    00458
    00459     fn = NULL;
    00460     urltype = urlPath(Lurlfn, &fn);
    00461     switch (urltype) {
    00462     case URL_IS_HTTPS:
    00463     case URL_IS_HTTP:
    00464     case URL_IS_FTP:
    00465     case URL_IS_PATH:
    00466     case URL_IS_UNKNOWN:
    00467         break;
    00468     case URL_IS_DASH:
    00469     case URL_IS_HKP:
    00470         rpmlog(RPMLOG_ERR, _("Invalid icon URL: %s\n"), Lurlfn);
    00471         goto exit;
    00472         /*@notreached@*/ break;
    00473     }
    00474
    00475     fd = Fopen(fn, "r%{?_rpmgio}");
    00476     if (fd == NULL || Ferror(fd)) {
    00477         rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
    00478                 fn, Fstrerror(fd));
    00479         rc = RPMRC_FAIL;
    00480         goto exit;
    00481     }
    00482
    00483     *icon = '\0';
    00484     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
    00485     if (Ferror(fd) || nb == 0) {
    00486         rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
    00487                 fn, Fstrerror(fd));
    00488         goto exit;
    00489     }
    00490     if (nb >= iconsize) {
    00491         rpmlog(RPMLOG_ERR, _("Icon %s is too big (max. %d bytes)\n"),
    00492                 fn, (int)iconsize);
    00493         goto exit;
    00494     }
    00495
    00496     if (icon[0] == 'G' && icon[1] == 'I' && icon[2] == 'F')
    00497         he->tag = RPMTAG_GIF;
    00498     else
    00499     if (icon[0] == '/' && icon[1] == '*' && icon[2] == ' '
    00500      && icon[3] == 'X' && icon[4] == 'P' && icon[5] == 'M')
    00501         he->tag = RPMTAG_XPM;
    00502     else
    00503         he->tag = tagValue("Icon");
    00504     he->t = RPM_BIN_TYPE;
    00505     he->p.ui8p = icon;
    00506     he->c = (rpmTagCount)nb;
    00507     xx = headerPut(h, he, 0);
    00508     rc = 0;
    00509
    00510 exit:
    00511     if (fd) {
    00512         (void) Fclose(fd);
    00513         fd = NULL;
    00514     }
    00515     Lurlfn = _free(Lurlfn);
    00516     return rc;
    00517 }
    00518
    00519 spectag stashSt(Spec spec, Header h, rpmTag tag, const char * lang)
    00520 {
    00521     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00522     spectag t = NULL;
    00523     int xx;
    00524
    00525     if (spec->st) {
    00526         spectags st = spec->st;
    00527         if (st->st_ntags == st->st_nalloc) {
    00528             st->st_nalloc += 10;
    00529             st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
    00530         }
    00531         t = st->st_t + st->st_ntags++;
    00532         t->t_tag = tag;
    00533         t->t_startx = spec->lineNum - 1;
    00534         t->t_nlines = 1;
    00535         t->t_lang = xstrdup(lang);
    00536         t->t_msgid = NULL;
    00537         if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
    00538             he->tag = RPMTAG_NAME;
    00539             xx = headerGet(h, he, 0);
    00540             if (xx) {
    00541                 char buf[1024];
    00542                 sprintf(buf, "%s(%s)", he->p.str, tagName(tag));
    00543                 t->t_msgid = xstrdup(buf);
    00544             }
    00545             he->p.ptr = _free(he->p.ptr);
    00546         }
    00547     }
    00548     /*@-usereleased -compdef@*/
    00549     return t;
    00550     /*@=usereleased =compdef@*/
    00551 }
    00552
    00553 #define SINGLE_TOKEN_ONLY \
    00554 if (multiToken) { \
    00555     rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
    00556              spec->lineNum, spec->line); \
    00557     return RPMRC_FAIL; \
    00558 }
    00559
    00560 /*@-redecl@*/
    00561 extern int noLang;
    00562 /*@=redecl@*/
    00563
    00564 static rpmRC tagValidate(Spec spec, rpmTag tag, const char * value)
    00565         /*@*/
    00566 {
    00567     const char * tagN = tagName(tag);
    00568     const char * pattern = rpmExpand("%{?pattern_", tagN, "}", NULL);
    00569     rpmRC ec = RPMRC_OK;
    00570
    00571     if (pattern && *pattern) {
    00572         miRE mire;
    00573         int xx;
    00574
    00575         mire = mireNew(RPMMIRE_REGEX, tag);
    00576         xx = mireSetCOptions(mire, RPMMIRE_REGEX, 0, 0, NULL);
    00577         if (!xx)
    00578             xx = mireRegcomp(mire, pattern);
    00579         if (!xx)
    00580             xx = mireRegexec(mire, value, strlen(value));
    00581         if (!xx)
    00582             ec = RPMRC_OK;
    00583         else {
    00584             rpmlog(RPMLOG_ERR, _("line %d: invalid tag value(\"%s\") %s: %s\n"),
    00585                     spec->lineNum, pattern, tagN, spec->line);
    00586             ec = RPMRC_FAIL;
    00587         }
    00588
    00589         mire = mireFree(mire);
    00590     }
    00591
    00592     pattern = _free(pattern);
    00593
    00594     return ec;
    00595 }
    00596
    00599 static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
    00600                 const char *macro, const char *lang)
    00601         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00602         /*@modifies spec->macros, spec->st,
    00603                 spec->sources, spec->numSources, spec->noSource,
    00604                 spec->sourceHeader, spec->BANames, spec->BACount,
    00605                 spec->line,
    00606                 pkg->header, pkg->autoProv, pkg->autoReq, pkg->noarch,
    00607                 rpmGlobalMacroContext, fileSystem, internalState @*/
    00608 {
    00609     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00610     char * field = spec->line;
    00611     char * end;
    00612     int multiToken = 0;
    00613     rpmsenseFlags tagflags;
    00614     int len;
    00615     rpmuint32_t num;
    00616     int rc;
    00617     int xx;
    00618 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
    00619     char * expand_field = NULL;
    00620 #endif
    00621
    00622     if (field == NULL) return RPMRC_FAIL;       /* XXX can't happen */
    00623     /* Find the start of the "field" and strip trailing space */
    00624     while ((*field) && (*field != ':'))
    00625         field++;
    00626     if (*field != ':') {
    00627         rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
    00628                  spec->lineNum, spec->line);
    00629         return RPMRC_FAIL;
    00630     }
    00631     field++;
    00632     SKIPSPACE(field);
    00633     if (!*field) {
    00634         /* Empty field */
    00635         rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
    00636                  spec->lineNum, spec->line);
    00637         return RPMRC_FAIL;
    00638     }
    00639 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
    00640     expand_field = rpmExpand(field, NULL);
    00641 #else
    00642     end = findLastChar(field);
    00643 #endif
    00644
    00645     /* Validate tag data content. */
    00646     if (tagValidate(spec, tag, field) != RPMRC_OK)
    00647         return RPMRC_FAIL;
    00648
    00649     /* See if this is multi-token */
    00650 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
    00651     end = expand_field;
    00652 #else
    00653     end = field;
    00654 #endif
    00655     SKIPNONSPACE(end);
    00656     if (*end != '\0')
    00657         multiToken = 1;
    00658 #if defined(RPM_VENDOR_MANDRIVA) /* build-expand-field-for-single-token */
    00659     _free(expand_field);
    00660 #endif
    00661
    00662     switch (tag) {
    00663     case RPMTAG_NAME:
    00664     case RPMTAG_VERSION:
    00665     case RPMTAG_RELEASE:
    00666     case RPMTAG_DISTEPOCH:
    00667     case RPMTAG_URL:
    00668     case RPMTAG_DISTTAG:
    00669     case RPMTAG_REPOTAG:
    00670     case RPMTAG_CVSID:
    00671         SINGLE_TOKEN_ONLY;
    00672         /* These macros are for backward compatibility */
    00673         if (tag == RPMTAG_VERSION) {
    00674             if (strchr(field, '-') != NULL) {
    00675                 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
    00676                     spec->lineNum, "version", spec->line);
    00677                 return RPMRC_FAIL;
    00678             }
    00679             addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
    00680         } else if (tag == RPMTAG_RELEASE) {
    00681             if (strchr(field, '-') != NULL) {
    00682                 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
    00683                     spec->lineNum, "release", spec->line);
    00684                 return RPMRC_FAIL;
    00685             }
    00686             addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
    00687         }
    00688         he->tag = tag;
    00689         he->t = RPM_STRING_TYPE;
    00690         he->p.str = field;
    00691         he->c = 1;
    00692         xx = headerPut(pkg->header, he, 0);
    00693         break;
    00694     case RPMTAG_GROUP:
    00695     case RPMTAG_SUMMARY:
    00696 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
    00697     case RPMTAG_CLASS:
    00698 #endif
    00699         (void) stashSt(spec, pkg->header, tag, lang);
    00700         /*@fallthrough@*/
    00701     case RPMTAG_DISTRIBUTION:
    00702     case RPMTAG_VENDOR:
    00703     case RPMTAG_LICENSE:
    00704     case RPMTAG_PACKAGER:
    00705         if (!*lang) {
    00706             he->tag = tag;
    00707             he->t = RPM_STRING_TYPE;
    00708             he->p.str = field;
    00709             he->c = 1;
    00710             xx = headerPut(pkg->header, he, 0);
    00711         } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) {
    00712             (void) headerAddI18NString(pkg->header, tag, field, lang);
    00713         }
    00714         break;
    00715     /* XXX silently ignore BuildRoot: */
    00716     case RPMTAG_BUILDROOT:
    00717         SINGLE_TOKEN_ONLY;
    00718         macro = NULL;
    00719 #ifdef  DYING
    00720         buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
    00721         (void) urlPath(buildRootURL, &buildRoot);
    00722         if (*buildRoot == '\0') buildRoot = "/";
    00723         if (!strcmp(buildRoot, "/")) {
    00724             rpmlog(RPMLOG_ERR,
    00725                      _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
    00726             buildRootURL = _free(buildRootURL);
    00727             return RPMRC_FAIL;
    00728         }
    00729         buildRootURL = _free(buildRootURL);
    00730 #endif
    00731         break;
    00732     case RPMTAG_KEYWORDS:
    00733     case RPMTAG_VARIANTS:
    00734     case RPMTAG_PREFIXES:
    00735         addOrAppendListEntry(pkg->header, tag, field);
    00736         he->tag = tag;
    00737         xx = headerGet(pkg->header, he, 0);
    00738         if (tag == RPMTAG_PREFIXES)
    00739         while (he->c--) {
    00740             if (he->p.argv[he->c][0] != '/') {
    00741                 rpmlog(RPMLOG_ERR,
    00742                          _("line %d: Prefixes must begin with \"/\": %s\n"),
    00743                          spec->lineNum, spec->line);
    00744                 he->p.ptr = _free(he->p.ptr);
    00745                 return RPMRC_FAIL;
    00746             }
    00747             len = (int)strlen(he->p.argv[he->c]);
    00748             if (he->p.argv[he->c][len - 1] == '/' && len > 1) {
    00749                 rpmlog(RPMLOG_ERR,
    00750                          _("line %d: Prefixes must not end with \"/\": %s\n"),
    00751                          spec->lineNum, spec->line);
    00752                 he->p.ptr = _free(he->p.ptr);
    00753                 return RPMRC_FAIL;
    00754             }
    00755         }
    00756         he->p.ptr = _free(he->p.ptr);
    00757         break;
    00758     case RPMTAG_DOCDIR:
    00759         SINGLE_TOKEN_ONLY;
    00760         if (field[0] != '/') {
    00761             rpmlog(RPMLOG_ERR,
    00762                      _("line %d: Docdir must begin with '/': %s\n"),
    00763                      spec->lineNum, spec->line);
    00764             return RPMRC_FAIL;
    00765         }
    00766         macro = NULL;
    00767         delMacro(NULL, "_docdir");
    00768         addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
    00769         break;
    00770     case RPMTAG_XMAJOR:
    00771     case RPMTAG_XMINOR:
    00772     case RPMTAG_EPOCH:
    00773         SINGLE_TOKEN_ONLY;
    00774         if (parseNum(field, &num)) {
    00775             rpmlog(RPMLOG_ERR,
    00776                      _("line %d: %s takes an integer value: %s\n"),
    00777                      spec->lineNum, tagName(tag), spec->line);
    00778             return RPMRC_FAIL;
    00779         }
    00780         he->tag = tag;
    00781         he->t = RPM_UINT32_TYPE;
    00782         he->p.ui32p = &num;
    00783         he->c = 1;
    00784         xx = headerPut(pkg->header, he, 0);
    00785         break;
    00786     case RPMTAG_AUTOREQPROV:
    00787         pkg->autoReq = parseYesNo(field);
    00788         pkg->autoProv = pkg->autoReq;
    00789         break;
    00790     case RPMTAG_AUTOREQ:
    00791         pkg->autoReq = parseYesNo(field);
    00792         break;
    00793     case RPMTAG_AUTOPROV:
    00794         pkg->autoProv = parseYesNo(field);
    00795         break;
    00796     case RPMTAG_SOURCE:
    00797     case RPMTAG_PATCH:
    00798         SINGLE_TOKEN_ONLY;
    00799         macro = NULL;
    00800         if ((rc = addSource(spec, pkg, field, tag)))
    00801             return rc;
    00802         break;
    00803     case RPMTAG_ICON:
    00804         SINGLE_TOKEN_ONLY;
    00805         macro = NULL;
    00806         if ((rc = addSource(spec, pkg, field, tag)))
    00807             return rc;
    00808         /* XXX the fetch/load of icon needs to be elsewhere. */
    00809         if ((rc = doIcon(spec, pkg->header)))
    00810             return rc;
    00811         break;
    00812     case RPMTAG_NOSOURCE:
    00813     case RPMTAG_NOPATCH:
    00814         spec->noSource = 1;
    00815         if ((rc = parseNoSource(spec, field, tag)))
    00816             return rc;
    00817         break;
    00818     case RPMTAG_BUILDPREREQ:
    00819     case RPMTAG_BUILDREQUIRES:
    00820         if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
    00821             rpmlog(RPMLOG_ERR,
    00822                      _("line %d: Bad %s: qualifiers: %s\n"),
    00823                      spec->lineNum, tagName(tag), spec->line);
    00824             return rc;
    00825         }
    00826         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00827             return rc;
    00828         break;
    00829     case RPMTAG_PREREQ:
    00830     case RPMTAG_REQUIREFLAGS:
    00831         if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
    00832             rpmlog(RPMLOG_ERR,
    00833                      _("line %d: Bad %s: qualifiers: %s\n"),
    00834                      spec->lineNum, tagName(tag), spec->line);
    00835             return rc;
    00836         }
    00837         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00838             return rc;
    00839         break;
    00840     /* Aliases for BuildRequires(hint): */
    00841     case RPMTAG_BUILDSUGGESTS:
    00842     case RPMTAG_BUILDENHANCES:
    00843         tagflags = RPMSENSE_MISSINGOK;
    00844         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00845             return rc;
    00846         break;
    00847     /* Aliases for Requires(hint): */
    00848     case RPMTAG_SUGGESTSFLAGS:
    00849     case RPMTAG_ENHANCESFLAGS:
    00850         tag = RPMTAG_REQUIREFLAGS;
    00851         tagflags = RPMSENSE_MISSINGOK;
    00852         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00853             return rc;
    00854         break;
    00855     case RPMTAG_BUILDOBSOLETES:
    00856     case RPMTAG_BUILDPROVIDES:
    00857     case RPMTAG_BUILDCONFLICTS:
    00858     case RPMTAG_CONFLICTFLAGS:
    00859     case RPMTAG_OBSOLETEFLAGS:
    00860     case RPMTAG_PROVIDEFLAGS:
    00861         tagflags = RPMSENSE_ANY;
    00862         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00863             return rc;
    00864         break;
    00865     case RPMTAG_BUILDPLATFORMS:         /* XXX needs pattern parsing */
    00866     case RPMTAG_EXCLUDEARCH:
    00867     case RPMTAG_EXCLUSIVEARCH:
    00868     case RPMTAG_EXCLUDEOS:
    00869     case RPMTAG_EXCLUSIVEOS:
    00870         addOrAppendListEntry(spec->sourceHeader, tag, field);
    00871         break;
    00872
    00873     case RPMTAG_BUILDARCHS:
    00874     {   const char ** BANames = NULL;
    00875         int BACount = 0;
    00876         if ((rc = poptParseArgvString(field, &BACount, &BANames))) {
    00877             rpmlog(RPMLOG_ERR,
    00878                      _("line %d: Bad BuildArchitecture format: %s\n"),
    00879                      spec->lineNum, spec->line);
    00880             return RPMRC_FAIL;
    00881         }
    00882         if (spec->toplevel) {
    00883             if (BACount > 0 && BANames != NULL) {
    00884                 spec->BACount = BACount;
    00885                 spec->BANames = BANames;
    00886                 BANames = NULL;         /* XXX don't free. */
    00887             }
    00888         } else {
    00889             if (BACount != 1 || strcmp(BANames[0], "noarch")) {
    00890                 rpmlog(RPMLOG_ERR,
    00891                      _("line %d: Only \"noarch\" sub-packages are supported: %s\n"),
    00892                      spec->lineNum, spec->line);
    00893                 BANames = _free(BANames);
    00894                 return RPMRC_FAIL;
    00895             }
    00896             pkg->noarch = 1;
    00897         }
    00898         BANames = _free(BANames);
    00899     }   break;
    00900
    00901     default:
    00902         macro = NULL;
    00903         he->tag = tag;
    00904         he->t = RPM_STRING_ARRAY_TYPE;
    00905         he->p.argv= (const char **) &field;     /* XXX NOCAST */
    00906         he->c = 1;
    00907         he->append = 1;
    00908         xx = headerPut(pkg->header, he, 0);
    00909         he->append = 0;
    00910         break;
    00911     }
    00912
    00913 /*@-usereleased@*/
    00914     if (macro)
    00915         addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
    00916 /*@=usereleased@*/
    00917
    00918     return RPMRC_OK;
    00919 }
    00920
    00921 /* This table has to be in a peculiar order.  If one tag is the */
    00922 /* same as another, plus a few letters, it must come first.     */
    00923
    00926 typedef struct PreambleRec_s {
    00927     rpmTag tag;
    00928     int multiLang;
    00929     int obsolete;
    00930 /*@observer@*/ /*@null@*/
    00931     const char * token;
    00932 } * PreambleRec;
    00933
    00934 /*@unchecked@*/
    00935 static struct PreambleRec_s preambleList[] = {
    00936     {RPMTAG_NAME,               0, 0, "name"},
    00937     {RPMTAG_VERSION,            0, 0, "version"},
    00938     {RPMTAG_RELEASE,            0, 0, "release"},
    00939     {RPMTAG_DISTEPOCH,          0, 0, "distepoch"},
    00940     {RPMTAG_EPOCH,              0, 0, "epoch"},
    00941     {RPMTAG_EPOCH,              0, 1, "serial"},
    00942     {RPMTAG_SUMMARY,            1, 0, "summary"},
    00943     {RPMTAG_LICENSE,            0, 0, "copyright"},
    00944     {RPMTAG_LICENSE,            0, 0, "license"},
    00945     {RPMTAG_DISTRIBUTION,       0, 0, "distribution"},
    00946     {RPMTAG_DISTURL,            0, 0, "disturl"},
    00947     {RPMTAG_VENDOR,             0, 0, "vendor"},
    00948     {RPMTAG_GROUP,              1, 0, "group"},
    00949     {RPMTAG_PACKAGER,           0, 0, "packager"},
    00950     {RPMTAG_URL,                0, 0, "url"},
    00951     {RPMTAG_SOURCE,             0, 0, "source"},
    00952     {RPMTAG_PATCH,              0, 0, "patch"},
    00953     {RPMTAG_NOSOURCE,           0, 0, "nosource"},
    00954     {RPMTAG_NOPATCH,            0, 0, "nopatch"},
    00955     {RPMTAG_EXCLUDEARCH,        0, 0, "excludearch"},
    00956     {RPMTAG_EXCLUSIVEARCH,      0, 0, "exclusivearch"},
    00957     {RPMTAG_EXCLUDEOS,          0, 0, "excludeos"},
    00958     {RPMTAG_EXCLUSIVEOS,        0, 0, "exclusiveos"},
    00959     {RPMTAG_ICON,               0, 0, "icon"},
    00960     {RPMTAG_PROVIDEFLAGS,       0, 0, "provides"},
    00961     {RPMTAG_REQUIREFLAGS,       1, 0, "requires"},
    00962     {RPMTAG_PREREQ,             1, 0, "prereq"},
    00963     {RPMTAG_CONFLICTFLAGS,      0, 0, "conflicts"},
    00964     {RPMTAG_OBSOLETEFLAGS,      0, 0, "obsoletes"},
    00965     {RPMTAG_PREFIXES,           0, 0, "prefixes"},
    00966     {RPMTAG_PREFIXES,           0, 0, "prefix"},
    00967     {RPMTAG_BUILDROOT,          0, 0, "buildroot"},
    00968     {RPMTAG_BUILDARCHS,         0, 0, "buildarchitectures"},
    00969     {RPMTAG_BUILDARCHS,         0, 0, "buildarch"},
    00970     {RPMTAG_BUILDCONFLICTS,     0, 0, "buildconflicts"},
    00971     {RPMTAG_BUILDOBSOLETES,     0, 0, "buildobsoletes"},
    00972     {RPMTAG_BUILDPREREQ,        1, 0, "buildprereq"},
    00973     {RPMTAG_BUILDPROVIDES,      0, 0, "buildprovides"},
    00974     {RPMTAG_BUILDREQUIRES,      1, 0, "buildrequires"},
    00975     {RPMTAG_AUTOREQPROV,        0, 0, "autoreqprov"},
    00976     {RPMTAG_AUTOREQ,            0, 0, "autoreq"},
    00977     {RPMTAG_AUTOPROV,           0, 0, "autoprov"},
    00978     {RPMTAG_DOCDIR,             0, 0, "docdir"},
    00979     {RPMTAG_DISTTAG,            0, 0, "disttag"},
    00980     {RPMTAG_CVSID,              0, 0, "cvsid"},
    00981     {RPMTAG_SVNID,              0, 0, "svnid"},
    00982     {RPMTAG_SUGGESTSFLAGS,      0, 0, "suggests"},
    00983     {RPMTAG_ENHANCESFLAGS,      0, 0, "enhances"},
    00984     {RPMTAG_BUILDSUGGESTS,      0, 0, "buildsuggests"},
    00985     {RPMTAG_BUILDENHANCES,      0, 0, "buildenhances"},
    00986     {RPMTAG_VARIANTS,           0, 0, "variants"},
    00987     {RPMTAG_VARIANTS,           0, 0, "variant"},
    00988     {RPMTAG_XMAJOR,             0, 0, "xmajor"},
    00989     {RPMTAG_XMINOR,             0, 0, "xminor"},
    00990     {RPMTAG_REPOTAG,            0, 0, "repotag"},
    00991     {RPMTAG_KEYWORDS,           0, 0, "keywords"},
    00992     {RPMTAG_KEYWORDS,           0, 0, "keyword"},
    00993     {RPMTAG_BUILDPLATFORMS,     0, 0, "buildplatforms"},
    00994 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
    00995     {RPMTAG_CLASS,              0, 0, "class"},
    00996 #endif
    00997     /*@-nullassign@*/   /* LCL: can't add null annotation */
    00998     {0, 0, 0, 0}
    00999     /*@=nullassign@*/
    01000 };
    01001
    01004 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp,
    01005                 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
    01006         /*@modifies *tagp, *macro, *lang @*/
    01007 {
    01008     PreambleRec p;
    01009     char *s;
    01010     size_t len = 0;
    01011
    01012     /* Search for defined tags. */
    01013     for (p = preambleList; p->token != NULL; p++) {
    01014         len = strlen(p->token);
    01015         if (!(p->token && !xstrncasecmp(spec->line, p->token, len)))
    01016             continue;
    01017         if (p->obsolete) {
    01018             rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"),
    01019                         p->token);
    01020             p = NULL;
    01021         }
    01022         break;
    01023     }
    01024     if (p == NULL)
    01025         return 1;
    01026
    01027     /* Search for arbitrary tags. */
    01028     if (tagp && p->token == NULL) {
    01029         ARGV_t aTags = NULL;
    01030         int rc = 1;     /* assume failure */
    01031
    01032 /*@-noeffect@*/
    01033         (void) tagName(0); /* XXX force arbitrary tags to be initialized. */
    01034 /*@=noeffect@*/
    01035         aTags = rpmTags->aTags;
    01036         if (aTags != NULL && aTags[0] != NULL) {
    01037             ARGV_t av;
    01038             s = tagCanonicalize(spec->line);
    01039 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */
    01040             av = argvSearchLinear(aTags, s, argvFnmatchCasefold);
    01041 #else
    01042             av = argvSearch(aTags, s, argvStrcasecmp);
    01043 #endif
    01044             if (av != NULL) {
    01045                 *tagp = tagGenerate(s);
    01046                 rc = 0;
    01047             }
    01048             s = _free(s);
    01049         }
    01050         return rc;
    01051     }
    01052
    01053     s = spec->line + len;
    01054     SKIPSPACE(s);
    01055
    01056     switch (p->multiLang) {
    01057     default:
    01058     case 0:
    01059         /* Unless this is a source or a patch, a ':' better be next */
    01060         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
    01061             if (*s != ':') return 1;
    01062         }
    01063         *lang = '\0';
    01064         break;
    01065     case 1:     /* Parse optional ( <token> ). */
    01066         if (*s == ':') {
    01067             strcpy(lang, RPMBUILD_DEFAULT_LANG);
    01068             break;
    01069         }
    01070         if (*s != '(') return 1;
    01071         s++;
    01072         SKIPSPACE(s);
    01073         while (!xisspace(*s) && *s != ')')
    01074             *lang++ = *s++;
    01075         *lang = '\0';
    01076         SKIPSPACE(s);
    01077         if (*s != ')') return 1;
    01078         s++;
    01079         SKIPSPACE(s);
    01080         if (*s != ':') return 1;
    01081         break;
    01082     }
    01083
    01084     if (tagp)
    01085         *tagp = p->tag;
    01086     if (macro)
    01087         /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
    01088         *macro = p->token;
    01089         /*@=onlytrans =observertrans =dependenttrans@*/
    01090     return 0;
    01091 }
    01092
    01093 /* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */
    01094 int parsePreamble(Spec spec, int initialPackage)
    01095 {
    01096     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    01097     rpmParseState nextPart;
    01098     int xx;
    01099     char *linep;
    01100     Package pkg;
    01101     char NVR[BUFSIZ];
    01102     char lang[BUFSIZ];
    01103     rpmRC rc;
    01104
    01105     strcpy(NVR, "(main package)");
    01106
    01107     pkg = newPackage(spec);
    01108     if (spec->packages == NULL) {
    01109         spec->packages = pkg;
    01110 assert(initialPackage);
    01111     } else if (! initialPackage) {
    01112         char *name = NULL;
    01113         rpmParseState flag;
    01114         Package lastpkg;
    01115
    01116         /* There is one option to %package: <pkg> or -n <pkg> */
    01117         flag = PART_NONE;
    01118         if (parseSimplePart(spec, &name, &flag)) {
    01119             rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
    01120                         spec->line);
    01121             return RPMRC_FAIL;
    01122         }
    01123
    01124         lastpkg = NULL;
    01125         if (lookupPackage(spec, name, flag, &lastpkg) == RPMRC_OK) {
    01126             pkg->next = lastpkg->next;
    01127         } else {
    01128             /* Add package to end of list */
    01129             for (lastpkg = spec->packages; lastpkg->next != NULL; lastpkg = lastpkg->next)
    01130             {};
    01131         }
    01132 assert(lastpkg != NULL);
    01133         lastpkg->next = pkg;
    01134
    01135         /* Construct the package */
    01136         if (flag == PART_SUBNAME) {
    01137             he->tag = RPMTAG_NAME;
    01138             xx = headerGet(spec->packages->header, he, 0);
    01139             sprintf(NVR, "%s-%s", he->p.str, name);
    01140             he->p.ptr = _free(he->p.ptr);
    01141         } else
    01142             strcpy(NVR, name);
    01143         name = _free(name);
    01144         he->tag = RPMTAG_NAME;
    01145         he->t = RPM_STRING_TYPE;
    01146         he->p.str = NVR;
    01147         he->c = 1;
    01148         xx = headerPut(pkg->header, he, 0);
    01149     }
    01150
    01151     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    01152         nextPart = PART_NONE;
    01153     } else {
    01154         if (rc)
    01155             return rc;
    01156         while ((nextPart = isPart(spec)) == PART_NONE) {
    01157             const char * macro = NULL;
    01158             rpmTag tag;
    01159
    01160             /* Skip blank lines */
    01161             linep = spec->line;
    01162             SKIPSPACE(linep);
    01163             if (*linep != '\0') {
    01164                 if (findPreambleTag(spec, &tag, &macro, lang)) {
    01165                     rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
    01166                                 spec->lineNum, spec->line);
    01167                     return RPMRC_FAIL;
    01168                 }
    01169                 if (handlePreambleTag(spec, pkg, tag, macro, lang))
    01170                     return RPMRC_FAIL;
    01171                 if (spec->BANames && !spec->recursing && spec->toplevel)
    01172                     return PART_BUILDARCHITECTURES;
    01173             }
    01174             if ((rc =
    01175                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    01176                 nextPart = PART_NONE;
    01177                 break;
    01178             }
    01179             if (rc)
    01180                 return rc;
    01181         }
    01182     }
    01183
    01184     /* Do some final processing on the header */
    01185
    01186     /*
    01187      * Expand buildroot one more time to get %{version} and the like
    01188      * from the main package.
    01189      */
    01190     if (initialPackage) {
    01191         const char *s = rpmExpand("%{?buildroot}", NULL);
    01192         if (s && *s)
    01193             (void) addMacro(NULL, "buildroot", NULL, s, -1);
    01194         s = _free(s);
    01195     }
    01196
    01197     /* XXX Skip valid arch check if not building binary package */
    01198     if (!spec->anyarch && checkForValidArchitectures(spec))
    01199         return RPMRC_FAIL;
    01200
    01201     if (pkg == spec->packages)
    01202         fillOutMainPackage(pkg->header);
    01203
    01204     if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK)
    01205         return RPMRC_FAIL;
    01206
    01207     if (pkg != spec->packages)
    01208         headerCopyTags(spec->packages->header, pkg->header,
    01209                         (rpmuint32_t *)copyTagsDuringParse);
    01210
    01211 #ifdef RPM_VENDOR_PLD /* rpm-epoch0 */
    01212     /* Add Epoch: 0 to package header if it was not set by spec */
    01213     he->tag = RPMTAG_NAME;
    01214     if (headerGet(spec->packages->header, he, 0) == 0) {
    01215         rpmuint32_t num = 0;
    01216
    01217         he->tag = RPMTAG_EPOCH;
    01218         he->t = RPM_UINT32_TYPE;
    01219         he->p.ui32p = &num;
    01220         he->c = 1;
    01221         xx = headerPut(pkg->header, he, 0);
    01222
    01223         /* also declare %{epoch} to be same */
    01224         addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC);
    01225     }
    01226 #endif /* RPM_VENDOR_PLD rpm-epoch0 */
    01227
    01228     if (checkForRequired(pkg->header, NVR) != RPMRC_OK)
    01229         return RPMRC_FAIL;
    01230
    01231     return nextPart;
    01232 }