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

Generated on Sun Oct 26 13:01:57 2003 for rpm by doxygen1.2.18