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

Generated at Thu Apr 19 15:29:41 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001