• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

build/parsePreamble.c

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

Generated on Mon Nov 29 2010 05:18:41 for rpm by  doxygen 1.7.2