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

Generated at Thu Sep 6 11:32:28 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001