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

Generated on Sat Oct 1 16:22:42 2011 for rpm by  doxygen 1.4.4