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

# build/parsePreamble.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio_internal.h>
    00009 #include <rpmbuild.h>
    00010 #include "debug.h"
    00011
    00012 /*@access FD_t @*/      /* compared with NULL */
    00013
    00016 /*@observer@*/ /*@unchecked@*/
    00017 static rpmTag copyTagsDuringParse[] = {
    00018     RPMTAG_EPOCH,
    00019     RPMTAG_VERSION,
    00020     RPMTAG_RELEASE,
    00021     RPMTAG_LICENSE,
    00022     RPMTAG_PACKAGER,
    00023     RPMTAG_DISTRIBUTION,
    00024     RPMTAG_DISTURL,
    00025     RPMTAG_VENDOR,
    00026     RPMTAG_ICON,
    00027     RPMTAG_URL,
    00028     RPMTAG_CHANGELOGTIME,
    00029     RPMTAG_CHANGELOGNAME,
    00030     RPMTAG_CHANGELOGTEXT,
    00031     RPMTAG_PREFIXES,
    00032     RPMTAG_RHNPLATFORM,
    00033     0
    00034 };
    00035
    00038 /*@observer@*/ /*@unchecked@*/
    00039 static rpmTag requiredTags[] = {
    00040     RPMTAG_NAME,
    00041     RPMTAG_VERSION,
    00042     RPMTAG_RELEASE,
    00043     RPMTAG_SUMMARY,
    00044     RPMTAG_GROUP,
    00045     RPMTAG_LICENSE,
    00046     0
    00047 };
    00048
    00051 static void addOrAppendListEntry(Header h, int_32 tag, char * line)
    00052         /*@modifies h @*/
    00053 {
    00054     int xx;
    00055     int argc;
    00056     const char **argv;
    00057
    00058     xx = poptParseArgvString(line, &argc, &argv);
    00059     if (argc)
    00060         xx = headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, argv, argc);
    00061     argv = _free(argv);
    00062 }
    00063
    00064 /* Parse a simple part line that only take -n <pkg> or <pkg> */
    00065 /* <pkg> is return in name as a pointer into a static buffer */
    00066
    00069 /*@-boundswrite@*/
    00070 static int parseSimplePart(char *line, /*@out@*/char **name, /*@out@*/int *flag)
    00071         /*@globals internalState@*/
    00072         /*@modifies *name, *flag, internalState @*/
    00073 {
    00074     char *tok;
    00075     char linebuf[BUFSIZ];
    00076     static char buf[BUFSIZ];
    00077
    00078     strcpy(linebuf, line);
    00079
    00080     /* Throw away the first token (the %xxxx) */
    00081     (void)strtok(linebuf, " \t\n");
    00082
    00083     if (!(tok = strtok(NULL, " \t\n"))) {
    00084         *name = NULL;
    00085         return 0;
    00086     }
    00087
    00088     if (!strcmp(tok, "-n")) {
    00089         if (!(tok = strtok(NULL, " \t\n")))
    00090             return 1;
    00091         *flag = PART_NAME;
    00092     } else {
    00093         *flag = PART_SUBNAME;
    00094     }
    00095     strcpy(buf, tok);
    00096     *name = buf;
    00097
    00098     return (strtok(NULL, " \t\n")) ? 1 : 0;
    00099 }
    00100 /*@=boundswrite@*/
    00101
    00104 static inline int parseYesNo(const char * s)
    00105         /*@*/
    00106 {
    00107     return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
    00108         !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off"))
    00109             ? 0 : 1);
    00110 }
    00111
    00112 typedef struct tokenBits_s {
    00113 /*@observer@*/ /*@null@*/ const char * name;
    00114     rpmsenseFlags bits;
    00115 } * tokenBits;
    00116
    00119 /*@observer@*/ /*@unchecked@*/
    00120 static struct tokenBits_s installScriptBits[] = {
    00121     { "interp",         RPMSENSE_INTERP },
    00122     { "prereq",         RPMSENSE_PREREQ },
    00123     { "preun",          RPMSENSE_SCRIPT_PREUN },
    00124     { "pre",            RPMSENSE_SCRIPT_PRE },
    00125     { "postun",         RPMSENSE_SCRIPT_POSTUN },
    00126     { "post",           RPMSENSE_SCRIPT_POST },
    00127     { "rpmlib",         RPMSENSE_RPMLIB },
    00128     { "verify",         RPMSENSE_SCRIPT_VERIFY },
    00129     { NULL, 0 }
    00130 };
    00131
    00134 /*@observer@*/ /*@unchecked@*/
    00135 static struct tokenBits_s buildScriptBits[] = {
    00136     { "prep",           RPMSENSE_SCRIPT_PREP },
    00137     { "build",          RPMSENSE_SCRIPT_BUILD },
    00138     { "install",        RPMSENSE_SCRIPT_INSTALL },
    00139     { "clean",          RPMSENSE_SCRIPT_CLEAN },
    00140     { NULL, 0 }
    00141 };
    00142
    00145 /*@-boundswrite@*/
    00146 static int parseBits(const char * s, const tokenBits tokbits,
    00147                 /*@out@*/ rpmsenseFlags * bp)
    00148         /*@modifies *bp @*/
    00149 {
    00150     tokenBits tb;
    00151     const char * se;
    00152     rpmsenseFlags bits = RPMSENSE_ANY;
    00153     int c = 0;
    00154
    00155     if (s) {
    00156         while (*s != '\0') {
    00157             while ((c = *s) && xisspace(c)) s++;
    00158             se = s;
    00159             while ((c = *se) && xisalpha(c)) se++;
    00160             if (s == se)
    00161                 break;
    00162             for (tb = tokbits; tb->name; tb++) {
    00163                 if (tb->name != NULL &&
    00164                     strlen(tb->name) == (se-s) && !strncmp(tb->name, s, (se-s)))
    00165                     /*@innerbreak@*/ break;
    00166             }
    00167             if (tb->name == NULL)
    00168                 break;
    00169             bits |= tb->bits;
    00170             while ((c = *se) && xisspace(c)) se++;
    00171             if (c != ',')
    00172                 break;
    00173             s = ++se;
    00174         }
    00175     }
    00176     if (c == 0 && bp) *bp = bits;
    00177     return (c ? RPMERR_BADSPEC : 0);
    00178 }
    00179 /*@=boundswrite@*/
    00180
    00183 static inline char * findLastChar(char * s)
    00184         /*@*/
    00185 {
    00186     char *res = s;
    00187
    00188 /*@-boundsread@*/
    00189     while (*s != '\0') {
    00190         if (! xisspace(*s))
    00191             res = s;
    00192         s++;
    00193     }
    00194 /*@=boundsread@*/
    00195
    00196     /*@-temptrans -retalias@*/
    00197     return res;
    00198     /*@=temptrans =retalias@*/
    00199 }
    00200
    00203 static int isMemberInEntry(Header h, const char *name, rpmTag tag)
    00204         /*@*/
    00205 {
    00206     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00207     HFD_t hfd = headerFreeData;
    00208     const char ** names;
    00209     rpmTagType type;
    00210     int count;
    00211
    00212     if (!hge(h, tag, &type, (void **)&names, &count))
    00213         return -1;
    00214 /*@-boundsread@*/
    00215     while (count--) {
    00216         if (!xstrcasecmp(names[count], name))
    00217             break;
    00218     }
    00219     names = hfd(names, type);
    00220 /*@=boundsread@*/
    00221     return (count >= 0 ? 1 : 0);
    00222 }
    00223
    00226 static int checkForValidArchitectures(Spec spec)
    00227         /*@*/
    00228 {
    00229 #ifndef DYING
    00230     const char *arch = NULL;
    00231     const char *os = NULL;
    00232
    00233     rpmGetArchInfo(&arch, NULL);
    00234     rpmGetOsInfo(&os, NULL);
    00235 #else
    00236     const char *arch = rpmExpand("%{_target_cpu}", NULL);
    00237     const char *os = rpmExpand("%{_target_os}", NULL);
    00238 #endif
    00239
    00240     if (isMemberInEntry(spec->buildRestrictions,
    00241                         arch, RPMTAG_EXCLUDEARCH) == 1) {
    00242         rpmError(RPMERR_BADSPEC, _("Architecture is excluded: %s\n"), arch);
    00243         return RPMERR_BADSPEC;
    00244     }
    00245     if (isMemberInEntry(spec->buildRestrictions,
    00246                         arch, RPMTAG_EXCLUSIVEARCH) == 0) {
    00247         rpmError(RPMERR_BADSPEC, _("Architecture is not included: %s\n"), arch);
    00248         return RPMERR_BADSPEC;
    00249     }
    00250     if (isMemberInEntry(spec->buildRestrictions,
    00251                         os, RPMTAG_EXCLUDEOS) == 1) {
    00252         rpmError(RPMERR_BADSPEC, _("OS is excluded: %s\n"), os);
    00253         return RPMERR_BADSPEC;
    00254     }
    00255     if (isMemberInEntry(spec->buildRestrictions,
    00256                         os, RPMTAG_EXCLUSIVEOS) == 0) {
    00257         rpmError(RPMERR_BADSPEC, _("OS is not included: %s\n"), os);
    00258         return RPMERR_BADSPEC;
    00259     }
    00260
    00261     return 0;
    00262 }
    00263
    00270 static int checkForRequired(Header h, const char * NVR)
    00271         /*@modifies h @*/ /* LCL: parse error here with modifies */
    00272 {
    00273     int res = 0;
    00274     rpmTag * p;
    00275
    00276 /*@-boundsread@*/
    00277     for (p = requiredTags; *p != 0; p++) {
    00278         if (!headerIsEntry(h, *p)) {
    00279             rpmError(RPMERR_BADSPEC,
    00280                         _("%s field must be present in package: %s\n"),
    00281                         tagName(*p), NVR);
    00282             res = 1;
    00283         }
    00284     }
    00285 /*@=boundsread@*/
    00286
    00287     return res;
    00288 }
    00289
    00296 static int checkForDuplicates(Header h, const char * NVR)
    00297         /*@modifies h @*/
    00298 {
    00299     int res = 0;
    00300     int lastTag, tag;
    00301     HeaderIterator hi;
    00302
    00303     for (hi = headerInitIterator(h), lastTag = 0;
    00304         headerNextIterator(hi, &tag, NULL, NULL, NULL);
    00305         lastTag = tag)
    00306     {
    00307         if (tag != lastTag)
    00308             continue;
    00309         rpmError(RPMERR_BADSPEC, _("Duplicate %s entries in package: %s\n"),
    00310                      tagName(tag), NVR);
    00311         res = 1;
    00312     }
    00313     hi = headerFreeIterator(hi);
    00314
    00315     return res;
    00316 }
    00317
    00320 /*@observer@*/ /*@unchecked@*/
    00321 static struct optionalTag {
    00322     rpmTag      ot_tag;
    00323 /*@observer@*/ /*@null@*/ const char * ot_mac;
    00324 } optionalTags[] = {
    00325     { RPMTAG_VENDOR,            "%{vendor}" },
    00326     { RPMTAG_PACKAGER,          "%{packager}" },
    00327     { RPMTAG_DISTRIBUTION,      "%{distribution}" },
    00328     { RPMTAG_DISTURL,           "%{disturl}" },
    00329     { -1, NULL }
    00330 };
    00331
    00334 static void fillOutMainPackage(Header h)
    00335         /*@globals rpmGlobalMacroContext @*/
    00336         /*@modifies h, rpmGlobalMacroContext @*/
    00337 {
    00338     struct optionalTag *ot;
    00339
    00340     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
    00341         if (!headerIsEntry(h, ot->ot_tag)) {
    00342 /*@-boundsread@*/
    00343             const char *val = rpmExpand(ot->ot_mac, NULL);
    00344             if (val && *val != '%')
    00345                 (void) headerAddEntry(h, ot->ot_tag, RPM_STRING_TYPE, (void *)val, 1);
    00346             val = _free(val);
    00347 /*@=boundsread@*/
    00348         }
    00349     }
    00350 }
    00351
    00354 /*@-boundswrite@*/
    00355 static int readIcon(Header h, const char * file)
    00356         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00357         /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState  @*/
    00358 {
    00359     const char *fn = NULL;
    00360     char *icon;
    00361     FD_t fd;
    00362     int rc = 0;
    00363     off_t size;
    00364     size_t nb, iconsize;
    00365
    00366     /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
    00367     fn = rpmGetPath("%{_sourcedir}/", file, NULL);
    00368
    00369     fd = Fopen(fn, "r.ufdio");
    00370     if (fd == NULL || Ferror(fd)) {
    00371         rpmError(RPMERR_BADSPEC, _("Unable to open icon %s: %s\n"),
    00372                 fn, Fstrerror(fd));
    00373         rc = RPMERR_BADSPEC;
    00374         goto exit;
    00375     }
    00376     size = fdSize(fd);
    00377     iconsize = (size >= 0 ? size : (8 * BUFSIZ));
    00378     if (iconsize == 0) {
    00379         (void) Fclose(fd);
    00380         rc = 0;
    00381         goto exit;
    00382     }
    00383
    00384     icon = xmalloc(iconsize + 1);
    00385     *icon = '\0';
    00386
    00387     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
    00388     if (Ferror(fd) || (size >= 0 && nb != size)) {
    00389         rpmError(RPMERR_BADSPEC, _("Unable to read icon %s: %s\n"),
    00390                 fn, Fstrerror(fd));
    00391         rc = RPMERR_BADSPEC;
    00392     }
    00393     (void) Fclose(fd);
    00394     if (rc)
    00395         goto exit;
    00396
    00397     if (! strncmp(icon, "GIF", sizeof("GIF")-1)) {
    00398         (void) headerAddEntry(h, RPMTAG_GIF, RPM_BIN_TYPE, icon, iconsize);
    00399     } else if (! strncmp(icon, "/* XPM", sizeof("/* XPM")-1)) {
    00400         (void) headerAddEntry(h, RPMTAG_XPM, RPM_BIN_TYPE, icon, iconsize);
    00401     } else {
    00402         rpmError(RPMERR_BADSPEC, _("Unknown icon type: %s\n"), file);
    00403         rc = RPMERR_BADSPEC;
    00404         goto exit;
    00405     }
    00406     icon = _free(icon);
    00407
    00408 exit:
    00409     fn = _free(fn);
    00410     return rc;
    00411 }
    00412 /*@=boundswrite@*/
    00413
    00414 spectag stashSt(Spec spec, Header h, int tag, const char * lang)
    00415 {
    00416     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00417     spectag t = NULL;
    00418
    00419     if (spec->st) {
    00420         spectags st = spec->st;
    00421         if (st->st_ntags == st->st_nalloc) {
    00422             st->st_nalloc += 10;
    00423             st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
    00424         }
    00425         t = st->st_t + st->st_ntags++;
    00426         t->t_tag = tag;
    00427         t->t_startx = spec->lineNum - 1;
    00428         t->t_nlines = 1;
    00429         t->t_lang = xstrdup(lang);
    00430         t->t_msgid = NULL;
    00431         if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
    00432             char *n;
    00433             if (hge(h, RPMTAG_NAME, NULL, (void **) &n, NULL)) {
    00434                 char buf[1024];
    00435                 sprintf(buf, "%s(%s)", n, tagName(tag));
    00436                 t->t_msgid = xstrdup(buf);
    00437             }
    00438         }
    00439     }
    00440     /*@-usereleased -compdef@*/
    00441     return t;
    00442     /*@=usereleased =compdef@*/
    00443 }
    00444
    00445 #define SINGLE_TOKEN_ONLY \
    00446 if (multiToken) { \
    00447     rpmError(RPMERR_BADSPEC, _("line %d: Tag takes single token only: %s\n"), \
    00448              spec->lineNum, spec->line); \
    00449     return RPMERR_BADSPEC; \
    00450 }
    00451
    00452 /*@-redecl@*/
    00453 extern int noLang;
    00454 /*@=redecl@*/
    00455
    00458 /*@-boundswrite@*/
    00459 static int handlePreambleTag(Spec spec, Package pkg, int tag, const char *macro,
    00460                              const char *lang)
    00461         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00462         /*@modifies spec->macros, spec->st, spec->buildRootURL,
    00463                 spec->sources, spec->numSources, spec->noSource,
    00464                 spec->buildRestrictions, spec->BANames, spec->BACount,
    00465                 spec->line, spec->gotBuildRootURL,
    00466                 pkg->header, pkg->autoProv, pkg->autoReq, pkg->icon,
    00467                 rpmGlobalMacroContext, fileSystem, internalState @*/
    00468 {
    00469     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00470     HFD_t hfd = headerFreeData;
    00471     char * field = spec->line;
    00472     char * end;
    00473     char ** array;
    00474     int multiToken = 0;
    00475     rpmsenseFlags tagflags;
    00476     rpmTagType type;
    00477     int len;
    00478     int num;
    00479     int rc;
    00480     int xx;
    00481
    00482     if (field == NULL) return RPMERR_BADSPEC;   /* XXX can't happen */
    00483     /* Find the start of the "field" and strip trailing space */
    00484     while ((*field) && (*field != ':'))
    00485         field++;
    00486     if (*field != ':') {
    00487         rpmError(RPMERR_BADSPEC, _("line %d: Malformed tag: %s\n"),
    00488                  spec->lineNum, spec->line);
    00489         return RPMERR_BADSPEC;
    00490     }
    00491     field++;
    00492     SKIPSPACE(field);
    00493     if (!*field) {
    00494         /* Empty field */
    00495         rpmError(RPMERR_BADSPEC, _("line %d: Empty tag: %s\n"),
    00496                  spec->lineNum, spec->line);
    00497         return RPMERR_BADSPEC;
    00498     }
    00499     end = findLastChar(field);
    00500     *(end+1) = '\0';
    00501
    00502     /* See if this is multi-token */
    00503     end = field;
    00504     SKIPNONSPACE(end);
    00505     if (*end != '\0')
    00506         multiToken = 1;
    00507
    00508     switch (tag) {
    00509       case RPMTAG_NAME:
    00510       case RPMTAG_VERSION:
    00511       case RPMTAG_RELEASE:
    00512       case RPMTAG_URL:
    00513       case RPMTAG_RHNPLATFORM:
    00514         SINGLE_TOKEN_ONLY;
    00515         /* These macros are for backward compatibility */
    00516         if (tag == RPMTAG_VERSION) {
    00517             if (strchr(field, '-') != NULL) {
    00518                 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
    00519                     spec->lineNum, "version", spec->line);
    00520                 return RPMERR_BADSPEC;
    00521             }
    00522             addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
    00523         } else if (tag == RPMTAG_RELEASE) {
    00524             if (strchr(field, '-') != NULL) {
    00525                 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
    00526                     spec->lineNum, "release", spec->line);
    00527                 return RPMERR_BADSPEC;
    00528             }
    00529             addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
    00530         }
    00531         (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
    00532         break;
    00533       case RPMTAG_GROUP:
    00534       case RPMTAG_SUMMARY:
    00535         (void) stashSt(spec, pkg->header, tag, lang);
    00536         /*@fallthrough@*/
    00537       case RPMTAG_DISTRIBUTION:
    00538       case RPMTAG_VENDOR:
    00539       case RPMTAG_LICENSE:
    00540       case RPMTAG_PACKAGER:
    00541         if (!*lang)
    00542             (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
    00543         else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG)))
    00544             (void) headerAddI18NString(pkg->header, tag, field, lang);
    00545         break;
    00546       case RPMTAG_BUILDROOT:
    00547         SINGLE_TOKEN_ONLY;
    00548       { const char * buildRoot = NULL;
    00549         const char * buildRootURL = spec->buildRootURL;
    00550
    00551         /*
    00552          * Note: rpmGenPath should guarantee a "canonical" path. That means
    00553          * that the following pathologies should be weeded out:
    00554          *          //bin//sh
    00555          *          //usr//bin/
    00556          *          /.././../usr/../bin//./sh
    00557          */
    00558         if (buildRootURL == NULL) {
    00559             buildRootURL = rpmGenPath(NULL, "%{?buildroot:%{buildroot}}", NULL);
    00560             if (strcmp(buildRootURL, "/")) {
    00561                 spec->buildRootURL = buildRootURL;
    00562                 macro = NULL;
    00563             } else {
    00564                 const char * specURL = field;
    00565
    00566                 buildRootURL = _free(buildRootURL);
    00567                 (void) urlPath(specURL, (const char **)&field);
    00568                 /*@-branchstate@*/
    00569                 if (*field == '\0') field = "/";
    00570                 /*@=branchstate@*/
    00571                 buildRootURL = rpmGenPath(spec->rootURL, field, NULL);
    00572                 spec->buildRootURL = buildRootURL;
    00573                 field = (char *) buildRootURL;
    00574             }
    00575             spec->gotBuildRootURL = 1;
    00576         } else {
    00577             macro = NULL;
    00578         }
    00579         buildRootURL = rpmGenPath(NULL, spec->buildRootURL, NULL);
    00580         (void) urlPath(buildRootURL, &buildRoot);
    00581         /*@-branchstate@*/
    00582         if (*buildRoot == '\0') buildRoot = "/";
    00583         /*@=branchstate@*/
    00584         if (!strcmp(buildRoot, "/")) {
    00585             rpmError(RPMERR_BADSPEC,
    00586                      _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
    00587             buildRootURL = _free(buildRootURL);
    00588             return RPMERR_BADSPEC;
    00589         }
    00590         buildRootURL = _free(buildRootURL);
    00591       } break;
    00592       case RPMTAG_PREFIXES:
    00593         addOrAppendListEntry(pkg->header, tag, field);
    00594         xx = hge(pkg->header, tag, &type, (void **)&array, &num);
    00595         while (num--) {
    00596             len = strlen(array[num]);
    00597             if (array[num][len - 1] == '/' && len > 1) {
    00598                 rpmError(RPMERR_BADSPEC,
    00599                          _("line %d: Prefixes must not end with \"/\": %s\n"),
    00600                          spec->lineNum, spec->line);
    00601                 array = hfd(array, type);
    00602                 return RPMERR_BADSPEC;
    00603             }
    00604         }
    00605         array = hfd(array, type);
    00606         break;
    00607       case RPMTAG_DOCDIR:
    00608         SINGLE_TOKEN_ONLY;
    00609         if (field[0] != '/') {
    00610             rpmError(RPMERR_BADSPEC,
    00611                      _("line %d: Docdir must begin with '/': %s\n"),
    00612                      spec->lineNum, spec->line);
    00613             return RPMERR_BADSPEC;
    00614         }
    00615         macro = NULL;
    00616         delMacro(NULL, "_docdir");
    00617         addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
    00618         break;
    00619       case RPMTAG_EPOCH:
    00620         SINGLE_TOKEN_ONLY;
    00621         if (parseNum(field, &num)) {
    00622             rpmError(RPMERR_BADSPEC,
    00623                      _("line %d: Epoch/Serial field must be a number: %s\n"),
    00624                      spec->lineNum, spec->line);
    00625             return RPMERR_BADSPEC;
    00626         }
    00627         xx = headerAddEntry(pkg->header, tag, RPM_INT32_TYPE, &num, 1);
    00628         break;
    00629       case RPMTAG_AUTOREQPROV:
    00630         pkg->autoReq = parseYesNo(field);
    00631         pkg->autoProv = pkg->autoReq;
    00632         break;
    00633       case RPMTAG_AUTOREQ:
    00634         pkg->autoReq = parseYesNo(field);
    00635         break;
    00636       case RPMTAG_AUTOPROV:
    00637         pkg->autoProv = parseYesNo(field);
    00638         break;
    00639       case RPMTAG_SOURCE:
    00640       case RPMTAG_PATCH:
    00641         SINGLE_TOKEN_ONLY;
    00642         macro = NULL;
    00643         if ((rc = addSource(spec, pkg, field, tag)))
    00644             return rc;
    00645         break;
    00646       case RPMTAG_ICON:
    00647         SINGLE_TOKEN_ONLY;
    00648         if ((rc = addSource(spec, pkg, field, tag)))
    00649             return rc;
    00650         if ((rc = readIcon(pkg->header, field)))
    00651             return RPMERR_BADSPEC;
    00652         break;
    00653       case RPMTAG_NOSOURCE:
    00654       case RPMTAG_NOPATCH:
    00655         spec->noSource = 1;
    00656         if ((rc = parseNoSource(spec, field, tag)))
    00657             return rc;
    00658         break;
    00659       case RPMTAG_BUILDPREREQ:
    00660       case RPMTAG_BUILDREQUIRES:
    00661         if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
    00662             rpmError(RPMERR_BADSPEC,
    00663                      _("line %d: Bad %s: qualifiers: %s\n"),
    00664                      spec->lineNum, tagName(tag), spec->line);
    00665             return rc;
    00666         }
    00667         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00668             return rc;
    00669         break;
    00670       case RPMTAG_REQUIREFLAGS:
    00671       case RPMTAG_PREREQ:
    00672         if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
    00673             rpmError(RPMERR_BADSPEC,
    00674                      _("line %d: Bad %s: qualifiers: %s\n"),
    00675                      spec->lineNum, tagName(tag), spec->line);
    00676             return rc;
    00677         }
    00678         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00679             return rc;
    00680         break;
    00681       case RPMTAG_BUILDCONFLICTS:
    00682       case RPMTAG_CONFLICTFLAGS:
    00683       case RPMTAG_OBSOLETEFLAGS:
    00684       case RPMTAG_PROVIDEFLAGS:
    00685         tagflags = RPMSENSE_ANY;
    00686         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00687             return rc;
    00688         break;
    00689       case RPMTAG_EXCLUDEARCH:
    00690       case RPMTAG_EXCLUSIVEARCH:
    00691       case RPMTAG_EXCLUDEOS:
    00692       case RPMTAG_EXCLUSIVEOS:
    00693         addOrAppendListEntry(spec->buildRestrictions, tag, field);
    00694         break;
    00695       case RPMTAG_BUILDARCHS:
    00696         if ((rc = poptParseArgvString(field,
    00697                                       &(spec->BACount),
    00698                                       &(spec->BANames)))) {
    00699             rpmError(RPMERR_BADSPEC,
    00700                      _("line %d: Bad BuildArchitecture format: %s\n"),
    00701                      spec->lineNum, spec->line);
    00702             return RPMERR_BADSPEC;
    00703         }
    00704         if (!spec->BACount)
    00705             spec->BANames = _free(spec->BANames);
    00706         break;
    00707
    00708       default:
    00709         rpmError(RPMERR_INTERNAL, _("Internal error: Bogus tag %d\n"), tag);
    00710         return RPMERR_INTERNAL;
    00711     }
    00712
    00713     if (macro)
    00714         addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
    00715
    00716     return 0;
    00717 }
    00718 /*@=boundswrite@*/
    00719
    00720 /* This table has to be in a peculiar order.  If one tag is the */
    00721 /* same as another, plus a few letters, it must come first.     */
    00722
    00725 typedef struct PreambleRec_s {
    00726     rpmTag tag;
    00727     int len;
    00728     int multiLang;
    00729 /*@observer@*/ /*@null@*/ const char * token;
    00730 } * PreambleRec;
    00731
    00732 /*@unchecked@*/
    00733 static struct PreambleRec_s preambleList[] = {
    00734     {RPMTAG_NAME,               0, 0, "name"},
    00735     {RPMTAG_VERSION,            0, 0, "version"},
    00736     {RPMTAG_RELEASE,            0, 0, "release"},
    00737     {RPMTAG_EPOCH,              0, 0, "epoch"},
    00738     {RPMTAG_EPOCH,              0, 0, "serial"},
    00739     {RPMTAG_SUMMARY,            0, 1, "summary"},
    00740     {RPMTAG_LICENSE,            0, 0, "copyright"},
    00741     {RPMTAG_LICENSE,            0, 0, "license"},
    00742     {RPMTAG_DISTRIBUTION,       0, 0, "distribution"},
    00743     {RPMTAG_DISTURL,            0, 0, "disturl"},
    00744     {RPMTAG_VENDOR,             0, 0, "vendor"},
    00745     {RPMTAG_GROUP,              0, 1, "group"},
    00746     {RPMTAG_PACKAGER,           0, 0, "packager"},
    00747     {RPMTAG_URL,                0, 0, "url"},
    00748     {RPMTAG_SOURCE,             0, 0, "source"},
    00749     {RPMTAG_PATCH,              0, 0, "patch"},
    00750     {RPMTAG_NOSOURCE,           0, 0, "nosource"},
    00751     {RPMTAG_NOPATCH,            0, 0, "nopatch"},
    00752     {RPMTAG_EXCLUDEARCH,        0, 0, "excludearch"},
    00753     {RPMTAG_EXCLUSIVEARCH,      0, 0, "exclusivearch"},
    00754     {RPMTAG_EXCLUDEOS,          0, 0, "excludeos"},
    00755     {RPMTAG_EXCLUSIVEOS,        0, 0, "exclusiveos"},
    00756     {RPMTAG_ICON,               0, 0, "icon"},
    00757     {RPMTAG_PROVIDEFLAGS,       0, 0, "provides"},
    00758     {RPMTAG_REQUIREFLAGS,       0, 1, "requires"},
    00759     {RPMTAG_PREREQ,             0, 1, "prereq"},
    00760     {RPMTAG_CONFLICTFLAGS,      0, 0, "conflicts"},
    00761     {RPMTAG_OBSOLETEFLAGS,      0, 0, "obsoletes"},
    00762     {RPMTAG_PREFIXES,           0, 0, "prefixes"},
    00763     {RPMTAG_PREFIXES,           0, 0, "prefix"},
    00764     {RPMTAG_BUILDROOT,          0, 0, "buildroot"},
    00765     {RPMTAG_BUILDARCHS,         0, 0, "buildarchitectures"},
    00766     {RPMTAG_BUILDARCHS,         0, 0, "buildarch"},
    00767     {RPMTAG_BUILDCONFLICTS,     0, 0, "buildconflicts"},
    00768     {RPMTAG_BUILDPREREQ,        0, 1, "buildprereq"},
    00769     {RPMTAG_BUILDREQUIRES,      0, 1, "buildrequires"},
    00770     {RPMTAG_AUTOREQPROV,        0, 0, "autoreqprov"},
    00771     {RPMTAG_AUTOREQ,            0, 0, "autoreq"},
    00772     {RPMTAG_AUTOPROV,           0, 0, "autoprov"},
    00773     {RPMTAG_DOCDIR,             0, 0, "docdir"},
    00774     {RPMTAG_RHNPLATFORM,        0, 0, "rhnplatform"},
    00775     /*@-nullassign@*/   /* LCL: can't add null annotation */
    00776     {0, 0, 0, 0}
    00777     /*@=nullassign@*/
    00778 };
    00779
    00782 static inline void initPreambleList(void)
    00783         /*@globals preambleList @*/
    00784         /*@modifies preambleList @*/
    00785 {
    00786     PreambleRec p;
    00787     for (p = preambleList; p->token != NULL; p++)
    00788         if (p->token) p->len = strlen(p->token);
    00789 }
    00790
    00793 /*@-boundswrite@*/
    00794 static int findPreambleTag(Spec spec, /*@out@*/int * tag,
    00795                 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
    00796         /*@modifies *tag, *macro, *lang @*/
    00797 {
    00798     PreambleRec p;
    00799     char *s;
    00800
    00801     if (preambleList[0].len == 0)
    00802         initPreambleList();
    00803
    00804     for (p = preambleList; p->token != NULL; p++) {
    00805         if (p->token && !xstrncasecmp(spec->line, p->token, p->len))
    00806             break;
    00807     }
    00808     if (p->token == NULL)
    00809         return 1;
    00810
    00811     s = spec->line + p->len;
    00812     SKIPSPACE(s);
    00813
    00814     switch (p->multiLang) {
    00815     default:
    00816     case 0:
    00817         /* Unless this is a source or a patch, a ':' better be next */
    00818         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
    00819             if (*s != ':') return 1;
    00820         }
    00821         *lang = '\0';
    00822         break;
    00823     case 1:     /* Parse optional ( <token> ). */
    00824         if (*s == ':') {
    00825             strcpy(lang, RPMBUILD_DEFAULT_LANG);
    00826             break;
    00827         }
    00828         if (*s != '(') return 1;
    00829         s++;
    00830         SKIPSPACE(s);
    00831         while (!xisspace(*s) && *s != ')')
    00832             *lang++ = *s++;
    00833         *lang = '\0';
    00834         SKIPSPACE(s);
    00835         if (*s != ')') return 1;
    00836         s++;
    00837         SKIPSPACE(s);
    00838         if (*s != ':') return 1;
    00839         break;
    00840     }
    00841
    00842     *tag = p->tag;
    00843     if (macro)
    00844         /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
    00845         *macro = p->token;
    00846         /*@=onlytrans =observertrans =dependenttrans@*/
    00847     return 0;
    00848 }
    00849 /*@=boundswrite@*/
    00850
    00851 /*@-boundswrite@*/
    00852 int parsePreamble(Spec spec, int initialPackage)
    00853 {
    00854     int nextPart;
    00855     int tag, rc, xx;
    00856     char *name, *linep;
    00857     int flag;
    00858     Package pkg;
    00859     char NVR[BUFSIZ];
    00860     char lang[BUFSIZ];
    00861
    00862     strcpy(NVR, "(main package)");
    00863
    00864     pkg = newPackage(spec);
    00865
    00866     if (! initialPackage) {
    00867         /* There is one option to %package: <pkg> or -n <pkg> */
    00868         if (parseSimplePart(spec->line, &name, &flag)) {
    00869             rpmError(RPMERR_BADSPEC, _("Bad package specification: %s\n"),
    00870                         spec->line);
    00871             return RPMERR_BADSPEC;
    00872         }
    00873
    00874         if (!lookupPackage(spec, name, flag, NULL)) {
    00875             rpmError(RPMERR_BADSPEC, _("Package already exists: %s\n"),
    00876                         spec->line);
    00877             return RPMERR_BADSPEC;
    00878         }
    00879
    00880         /* Construct the package */
    00881         if (flag == PART_SUBNAME) {
    00882             const char * mainName;
    00883             xx = headerNVR(spec->packages->header, &mainName, NULL, NULL);
    00884             sprintf(NVR, "%s-%s", mainName, name);
    00885         } else
    00886             strcpy(NVR, name);
    00887         xx = headerAddEntry(pkg->header, RPMTAG_NAME, RPM_STRING_TYPE, NVR, 1);
    00888     }
    00889
    00890     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    00891         nextPart = PART_NONE;
    00892     } else {
    00893         if (rc)
    00894             return rc;
    00895         while (! (nextPart = isPart(spec->line))) {
    00896             const char * macro;
    00897             /* Skip blank lines */
    00898             linep = spec->line;
    00899             SKIPSPACE(linep);
    00900             if (*linep != '\0') {
    00901                 if (findPreambleTag(spec, &tag, &macro, lang)) {
    00902                     rpmError(RPMERR_BADSPEC, _("line %d: Unknown tag: %s\n"),
    00903                                 spec->lineNum, spec->line);
    00904                     return RPMERR_BADSPEC;
    00905                 }
    00906                 if (handlePreambleTag(spec, pkg, tag, macro, lang))
    00907                     return RPMERR_BADSPEC;
    00908                 if (spec->BANames && !spec->recursing)
    00909                     return PART_BUILDARCHITECTURES;
    00910             }
    00911             if ((rc =
    00912                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    00913                 nextPart = PART_NONE;
    00914                 break;
    00915             }
    00916             if (rc)
    00917                 return rc;
    00918         }
    00919     }
    00920
    00921     /* Do some final processing on the header */
    00922
    00923     if (!spec->gotBuildRootURL && spec->buildRootURL) {
    00924         rpmError(RPMERR_BADSPEC, _("Spec file can't use BuildRoot\n"));
    00925         return RPMERR_BADSPEC;
    00926     }
    00927
    00928     /* XXX Skip valid arch check if not building binary package */
    00929     if (!spec->anyarch && checkForValidArchitectures(spec))
    00930         return RPMERR_BADSPEC;
    00931
    00932     if (pkg == spec->packages)
    00933         fillOutMainPackage(pkg->header);
    00934
    00935     if (checkForDuplicates(pkg->header, NVR))
    00936         return RPMERR_BADSPEC;
    00937
    00938     if (pkg != spec->packages)
    00939         headerCopyTags(spec->packages->header, pkg->header,
    00940                         (int_32 *)copyTagsDuringParse);
    00941
    00942     if (checkForRequired(pkg->header, NVR))
    00943         return RPMERR_BADSPEC;
    00944
    00945     return nextPart;
    00946 }
    00947 /*@=boundswrite@*/