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

Generated at Mon May 21 08:53:38 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001