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

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2