Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

build/parsePreamble.c

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

Generated on Thu Apr 29 08:02:16 2004 for rpm by doxygen 1.3.6