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

Generated on Wed Mar 13 15:34:46 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002