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, &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     static size_t iconsize = 0;
00362     const char *fn, *Lurlfn = NULL;
00363     struct Source *sp;
00364     size_t nb;
00365     char *icon;
00366     FD_t fd = NULL;
00367     int rc = RPMERR_BADSPEC;    /* assume error */
00368     int urltype;
00369     int xx;
00370 
00371     if (iconsize == 0) {
00372         iconsize = rpmExpandNumeric("%{?_build_iconsize}");
00373         if (iconsize < 2048)
00374             iconsize = 2048;
00375     }
00376     icon = alloca(iconsize+1);
00377 
00378     for (sp = spec->sources; sp != NULL; sp = sp->next) {
00379         if (sp->flags & RPMFILE_ICON)
00380             break;
00381     }
00382     if (sp == NULL) {
00383         rpmError(RPMERR_BADSPEC, _("No icon file in sources\n"));
00384         goto exit;
00385     }
00386 
00387     Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
00388 
00389     fn = NULL;
00390     urltype = urlPath(Lurlfn, &fn);
00391     switch (urltype) {  
00392     case URL_IS_HTTPS: 
00393     case URL_IS_HTTP:
00394     case URL_IS_FTP:
00395     case URL_IS_PATH:
00396     case URL_IS_UNKNOWN:
00397         break;
00398     case URL_IS_DASH:
00399     case URL_IS_HKP:
00400         rpmError(RPMERR_BADSPEC, _("Invalid icon URL: %s\n"), Lurlfn);
00401         goto exit;
00402         /*@notreached@*/ break;
00403     }
00404 
00405     fd = Fopen(fn, "r");
00406     if (fd == NULL || Ferror(fd)) {
00407         rpmError(RPMERR_BADSPEC, _("Unable to open icon %s: %s\n"),
00408                 fn, Fstrerror(fd));
00409         rc = RPMERR_BADSPEC;
00410         goto exit;
00411     }
00412 
00413     *icon = '\0';
00414     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
00415     if (Ferror(fd) || nb == 0) {
00416         rpmError(RPMERR_BADSPEC, _("Unable to read icon %s: %s\n"),
00417                 fn, Fstrerror(fd));
00418         goto exit;
00419     }
00420     if (nb >= iconsize) {
00421         rpmError(RPMERR_BADSPEC, _("Icon %s is too big (max. %d bytes)\n"),
00422                 fn, iconsize);
00423         goto exit;
00424     }
00425 
00426     if (!strncmp(icon, "GIF", sizeof("GIF")-1))
00427         xx = headerAddEntry(h, RPMTAG_GIF, RPM_BIN_TYPE, icon, nb);
00428     else if (!strncmp(icon, "/* XPM", sizeof("/* XPM")-1))
00429         xx = headerAddEntry(h, RPMTAG_XPM, RPM_BIN_TYPE, icon, nb);
00430     else {
00431         rpmError(RPMERR_BADSPEC, _("Unknown icon type: %s\n"), fn);
00432         goto exit;
00433     }
00434     rc = 0;
00435     
00436 exit:
00437     if (fd) {
00438         (void) Fclose(fd);
00439         fd = NULL;
00440     }
00441     Lurlfn = _free(Lurlfn);
00442     return rc;
00443 }
00444 /*@=boundswrite@*/
00445 
00446 spectag stashSt(Spec spec, Header h, int tag, const char * lang)
00447 {
00448     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00449     spectag t = NULL;
00450 
00451     if (spec->st) {
00452         spectags st = spec->st;
00453         if (st->st_ntags == st->st_nalloc) {
00454             st->st_nalloc += 10;
00455             st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
00456         }
00457         t = st->st_t + st->st_ntags++;
00458         t->t_tag = tag;
00459         t->t_startx = spec->lineNum - 1;
00460         t->t_nlines = 1;
00461         t->t_lang = xstrdup(lang);
00462         t->t_msgid = NULL;
00463         if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
00464             char *n;
00465             if (hge(h, RPMTAG_NAME, NULL, &n, NULL)) {
00466                 char buf[1024];
00467                 sprintf(buf, "%s(%s)", n, tagName(tag));
00468                 t->t_msgid = xstrdup(buf);
00469             }
00470         }
00471     }
00472     /*@-usereleased -compdef@*/
00473     return t;
00474     /*@=usereleased =compdef@*/
00475 }
00476 
00477 #define SINGLE_TOKEN_ONLY \
00478 if (multiToken) { \
00479     rpmError(RPMERR_BADSPEC, _("line %d: Tag takes single token only: %s\n"), \
00480              spec->lineNum, spec->line); \
00481     return RPMERR_BADSPEC; \
00482 }
00483 
00484 /*@-redecl@*/
00485 extern int noLang;
00486 /*@=redecl@*/
00487 
00490 /*@-boundswrite@*/
00491 static int handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
00492                 const char *macro, const char *lang)
00493         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00494         /*@modifies spec->macros, spec->st,
00495                 spec->sources, spec->numSources, spec->noSource,
00496                 spec->sourceHeader, spec->BANames, spec->BACount,
00497                 spec->line,
00498                 pkg->header, pkg->autoProv, pkg->autoReq, pkg->icon,
00499                 rpmGlobalMacroContext, fileSystem, internalState @*/
00500 {
00501     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00502     HFD_t hfd = headerFreeData;
00503     char * field = spec->line;
00504     char * end;
00505     char ** array;
00506     int multiToken = 0;
00507     rpmsenseFlags tagflags;
00508     rpmTagType type;
00509     int len;
00510     int num;
00511     int rc;
00512     int xx;
00513     
00514     if (field == NULL) return RPMERR_BADSPEC;   /* XXX can't happen */
00515     /* Find the start of the "field" and strip trailing space */
00516     while ((*field) && (*field != ':'))
00517         field++;
00518     if (*field != ':') {
00519         rpmError(RPMERR_BADSPEC, _("line %d: Malformed tag: %s\n"),
00520                  spec->lineNum, spec->line);
00521         return RPMERR_BADSPEC;
00522     }
00523     field++;
00524     SKIPSPACE(field);
00525     if (!*field) {
00526         /* Empty field */
00527         rpmError(RPMERR_BADSPEC, _("line %d: Empty tag: %s\n"),
00528                  spec->lineNum, spec->line);
00529         return RPMERR_BADSPEC;
00530     }
00531     end = findLastChar(field);
00532 
00533     /* See if this is multi-token */
00534     end = field;
00535     SKIPNONSPACE(end);
00536     if (*end != '\0')
00537         multiToken = 1;
00538 
00539     switch (tag) {
00540     case RPMTAG_NAME:
00541     case RPMTAG_VERSION:
00542     case RPMTAG_RELEASE:
00543     case RPMTAG_URL:
00544     case RPMTAG_DISTTAG:
00545     case RPMTAG_REPOTAG:
00546     case RPMTAG_CVSID:
00547         SINGLE_TOKEN_ONLY;
00548         /* These macros are for backward compatibility */
00549         if (tag == RPMTAG_VERSION) {
00550             if (strchr(field, '-') != NULL) {
00551                 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
00552                     spec->lineNum, "version", spec->line);
00553                 return RPMERR_BADSPEC;
00554             }
00555             addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
00556         } else if (tag == RPMTAG_RELEASE) {
00557             if (strchr(field, '-') != NULL) {
00558                 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
00559                     spec->lineNum, "release", spec->line);
00560                 return RPMERR_BADSPEC;
00561             }
00562             addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
00563         }
00564         (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
00565         break;
00566     case RPMTAG_GROUP:
00567     case RPMTAG_SUMMARY:
00568         (void) stashSt(spec, pkg->header, tag, lang);
00569         /*@fallthrough@*/
00570     case RPMTAG_DISTRIBUTION:
00571     case RPMTAG_VENDOR:
00572     case RPMTAG_LICENSE:
00573     case RPMTAG_PACKAGER:
00574         if (!*lang)
00575             (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
00576         else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG)))
00577             (void) headerAddI18NString(pkg->header, tag, field, lang);
00578         break;
00579     /* XXX silently ignore BuildRoot: */
00580     case RPMTAG_BUILDROOT:
00581         SINGLE_TOKEN_ONLY;
00582         macro = NULL;
00583 #ifdef  DYING
00584         buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
00585         (void) urlPath(buildRootURL, &buildRoot);
00586         /*@-branchstate@*/
00587         if (*buildRoot == '\0') buildRoot = "/";
00588         /*@=branchstate@*/
00589         if (!strcmp(buildRoot, "/")) {
00590             rpmError(RPMERR_BADSPEC,
00591                      _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
00592             buildRootURL = _free(buildRootURL);
00593             return RPMERR_BADSPEC;
00594         }
00595         buildRootURL = _free(buildRootURL);
00596 #endif
00597         break;
00598     case RPMTAG_KEYWORDS:
00599     case RPMTAG_VARIANTS:
00600     case RPMTAG_PREFIXES:
00601         addOrAppendListEntry(pkg->header, tag, field);
00602         xx = hge(pkg->header, tag, &type, &array, &num);
00603         if (tag == RPMTAG_PREFIXES)
00604         while (num--) {
00605             if (array[num][0] != '/') {
00606                 rpmError(RPMERR_BADSPEC,
00607                          _("line %d: Prefixes must begin with \"/\": %s\n"),
00608                          spec->lineNum, spec->line);
00609                 array = hfd(array, type);
00610                 return RPMERR_BADSPEC;
00611             }
00612             len = strlen(array[num]);
00613             if (array[num][len - 1] == '/' && len > 1) {
00614                 rpmError(RPMERR_BADSPEC,
00615                          _("line %d: Prefixes must not end with \"/\": %s\n"),
00616                          spec->lineNum, spec->line);
00617                 array = hfd(array, type);
00618                 return RPMERR_BADSPEC;
00619             }
00620         }
00621         array = hfd(array, type);
00622         break;
00623     case RPMTAG_DOCDIR:
00624         SINGLE_TOKEN_ONLY;
00625         if (field[0] != '/') {
00626             rpmError(RPMERR_BADSPEC,
00627                      _("line %d: Docdir must begin with '/': %s\n"),
00628                      spec->lineNum, spec->line);
00629             return RPMERR_BADSPEC;
00630         }
00631         macro = NULL;
00632         delMacro(NULL, "_docdir");
00633         addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
00634         break;
00635     case RPMTAG_XMAJOR:
00636     case RPMTAG_XMINOR:
00637     case RPMTAG_EPOCH:
00638         SINGLE_TOKEN_ONLY;
00639         if (parseNum(field, &num)) {
00640             rpmError(RPMERR_BADSPEC,
00641                      _("line %d: %s takes an integer value: %s\n"),
00642                      spec->lineNum, tagName(tag), spec->line);
00643             return RPMERR_BADSPEC;
00644         }
00645         xx = headerAddEntry(pkg->header, tag, RPM_INT32_TYPE, &num, 1);
00646         break;
00647     case RPMTAG_AUTOREQPROV:
00648         pkg->autoReq = parseYesNo(field);
00649         pkg->autoProv = pkg->autoReq;
00650         break;
00651     case RPMTAG_AUTOREQ:
00652         pkg->autoReq = parseYesNo(field);
00653         break;
00654     case RPMTAG_AUTOPROV:
00655         pkg->autoProv = parseYesNo(field);
00656         break;
00657     case RPMTAG_SOURCE:
00658     case RPMTAG_PATCH:
00659         SINGLE_TOKEN_ONLY;
00660         macro = NULL;
00661         if ((rc = addSource(spec, pkg, field, tag)))
00662             return rc;
00663         break;
00664     case RPMTAG_ICON:
00665         SINGLE_TOKEN_ONLY;
00666         macro = NULL;
00667         if ((rc = addSource(spec, pkg, field, tag)))
00668             return rc;
00669         /* XXX the fetch/load of icon needs to be elsewhere. */
00670         if ((rc = doIcon(spec, pkg->header)))
00671             return rc;
00672         break;
00673     case RPMTAG_NOSOURCE:
00674     case RPMTAG_NOPATCH:
00675         spec->noSource = 1;
00676         if ((rc = parseNoSource(spec, field, tag)))
00677             return rc;
00678         break;
00679     case RPMTAG_BUILDPREREQ:
00680     case RPMTAG_BUILDREQUIRES:
00681         if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
00682             rpmError(RPMERR_BADSPEC,
00683                      _("line %d: Bad %s: qualifiers: %s\n"),
00684                      spec->lineNum, tagName(tag), spec->line);
00685             return rc;
00686         }
00687         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
00688             return rc;
00689         break;
00690     case RPMTAG_PREREQ:
00691     case RPMTAG_REQUIREFLAGS:
00692         if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
00693             rpmError(RPMERR_BADSPEC,
00694                      _("line %d: Bad %s: qualifiers: %s\n"),
00695                      spec->lineNum, tagName(tag), spec->line);
00696             return rc;
00697         }
00698         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
00699             return rc;
00700         break;
00701     /* Aliases for BuildRequires(hint): */
00702     case RPMTAG_BUILDSUGGESTS:
00703     case RPMTAG_BUILDENHANCES:
00704         tagflags = RPMSENSE_MISSINGOK;
00705         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
00706             return rc;
00707         break;
00708     /* Aliases for Requires(hint): */
00709     case RPMTAG_SUGGESTSFLAGS:
00710     case RPMTAG_ENHANCESFLAGS:
00711         tag = RPMTAG_REQUIREFLAGS;
00712         tagflags = RPMSENSE_MISSINGOK;
00713         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
00714             return rc;
00715         break;
00716     case RPMTAG_BUILDOBSOLETES:
00717     case RPMTAG_BUILDPROVIDES:
00718     case RPMTAG_BUILDCONFLICTS:
00719     case RPMTAG_CONFLICTFLAGS:
00720     case RPMTAG_OBSOLETEFLAGS:
00721     case RPMTAG_PROVIDEFLAGS:
00722         tagflags = RPMSENSE_ANY;
00723         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
00724             return rc;
00725         break;
00726     case RPMTAG_BUILDPLATFORMS:         /* XXX needs pattern parsing */
00727     case RPMTAG_EXCLUDEARCH:
00728     case RPMTAG_EXCLUSIVEARCH:
00729     case RPMTAG_EXCLUDEOS:
00730     case RPMTAG_EXCLUSIVEOS:
00731         addOrAppendListEntry(spec->sourceHeader, tag, field);
00732         break;
00733     case RPMTAG_BUILDARCHS:
00734         if ((rc = poptParseArgvString(field,
00735                                       &(spec->BACount),
00736                                       &(spec->BANames)))) {
00737             rpmError(RPMERR_BADSPEC,
00738                      _("line %d: Bad BuildArchitecture format: %s\n"),
00739                      spec->lineNum, spec->line);
00740             return RPMERR_BADSPEC;
00741         }
00742         if (!spec->BACount)
00743             spec->BANames = _free(spec->BANames);
00744         break;
00745 
00746     default:
00747         rpmError(RPMERR_INTERNAL, _("Internal error: Bogus tag %d\n"), tag);
00748         return RPMERR_INTERNAL;
00749     }
00750 
00751     if (macro)
00752         addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
00753     
00754     return 0;
00755 }
00756 /*@=boundswrite@*/
00757 
00758 /* This table has to be in a peculiar order.  If one tag is the */
00759 /* same as another, plus a few letters, it must come first.     */
00760 
00763 typedef struct PreambleRec_s {
00764     rpmTag tag;
00765     int multiLang;
00766     int obsolete;
00767 /*@observer@*/ /*@null@*/
00768     const char * token;
00769 } * PreambleRec;
00770 
00771 /*@unchecked@*/
00772 static struct PreambleRec_s preambleList[] = {
00773     {RPMTAG_NAME,               0, 0, "name"},
00774     {RPMTAG_VERSION,            0, 0, "version"},
00775     {RPMTAG_RELEASE,            0, 0, "release"},
00776     {RPMTAG_EPOCH,              0, 0, "epoch"},
00777     {RPMTAG_EPOCH,              0, 1, "serial"},
00778     {RPMTAG_SUMMARY,            1, 0, "summary"},
00779     {RPMTAG_LICENSE,            0, 0, "copyright"},
00780     {RPMTAG_LICENSE,            0, 0, "license"},
00781     {RPMTAG_DISTRIBUTION,       0, 0, "distribution"},
00782     {RPMTAG_DISTURL,            0, 0, "disturl"},
00783     {RPMTAG_VENDOR,             0, 0, "vendor"},
00784     {RPMTAG_GROUP,              1, 0, "group"},
00785     {RPMTAG_PACKAGER,           0, 0, "packager"},
00786     {RPMTAG_URL,                0, 0, "url"},
00787     {RPMTAG_SOURCE,             0, 0, "source"},
00788     {RPMTAG_PATCH,              0, 0, "patch"},
00789     {RPMTAG_NOSOURCE,           0, 0, "nosource"},
00790     {RPMTAG_NOPATCH,            0, 0, "nopatch"},
00791     {RPMTAG_EXCLUDEARCH,        0, 0, "excludearch"},
00792     {RPMTAG_EXCLUSIVEARCH,      0, 0, "exclusivearch"},
00793     {RPMTAG_EXCLUDEOS,          0, 0, "excludeos"},
00794     {RPMTAG_EXCLUSIVEOS,        0, 0, "exclusiveos"},
00795     {RPMTAG_ICON,               0, 0, "icon"},
00796     {RPMTAG_PROVIDEFLAGS,       0, 0, "provides"},
00797     {RPMTAG_REQUIREFLAGS,       1, 0, "requires"},
00798     {RPMTAG_PREREQ,             1, 0, "prereq"},
00799     {RPMTAG_CONFLICTFLAGS,      0, 0, "conflicts"},
00800     {RPMTAG_OBSOLETEFLAGS,      0, 0, "obsoletes"},
00801     {RPMTAG_PREFIXES,           0, 0, "prefixes"},
00802     {RPMTAG_PREFIXES,           0, 0, "prefix"},
00803     {RPMTAG_BUILDROOT,          0, 0, "buildroot"},
00804     {RPMTAG_BUILDARCHS,         0, 0, "buildarchitectures"},
00805     {RPMTAG_BUILDARCHS,         0, 0, "buildarch"},
00806     {RPMTAG_BUILDCONFLICTS,     0, 0, "buildconflicts"},
00807     {RPMTAG_BUILDOBSOLETES,     0, 0, "buildobsoletes"},
00808     {RPMTAG_BUILDPREREQ,        1, 0, "buildprereq"},
00809     {RPMTAG_BUILDPROVIDES,      0, 0, "buildprovides"},
00810     {RPMTAG_BUILDREQUIRES,      1, 0, "buildrequires"},
00811     {RPMTAG_AUTOREQPROV,        0, 0, "autoreqprov"},
00812     {RPMTAG_AUTOREQ,            0, 0, "autoreq"},
00813     {RPMTAG_AUTOPROV,           0, 0, "autoprov"},
00814     {RPMTAG_DOCDIR,             0, 0, "docdir"},
00815     {RPMTAG_DISTTAG,            0, 0, "disttag"},
00816     {RPMTAG_CVSID,              0, 0, "cvsid"},
00817     {RPMTAG_SVNID,              0, 0, "svnid"},
00818     {RPMTAG_SUGGESTSFLAGS,      0, 0, "suggests"},
00819     {RPMTAG_ENHANCESFLAGS,      0, 0, "enhances"},
00820     {RPMTAG_BUILDSUGGESTS,      0, 0, "buildsuggests"},
00821     {RPMTAG_BUILDENHANCES,      0, 0, "buildenhances"},
00822     {RPMTAG_VARIANTS,           0, 0, "variants"},
00823     {RPMTAG_VARIANTS,           0, 0, "variant"},
00824     {RPMTAG_XMAJOR,             0, 0, "xmajor"},
00825     {RPMTAG_XMINOR,             0, 0, "xminor"},
00826     {RPMTAG_REPOTAG,            0, 0, "repotag"},
00827     {RPMTAG_KEYWORDS,           0, 0, "keywords"},
00828     {RPMTAG_KEYWORDS,           0, 0, "keyword"},
00829     {RPMTAG_BUILDPLATFORMS,     0, 0, "buildplatforms"},
00830     /*@-nullassign@*/   /* LCL: can't add null annotation */
00831     {0, 0, 0, 0}
00832     /*@=nullassign@*/
00833 };
00834 
00837 /*@-boundswrite@*/
00838 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tag,
00839                 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
00840         /*@modifies *tag, *macro, *lang @*/
00841 {
00842     PreambleRec p;
00843     char *s;
00844     size_t len = 0;
00845 
00846     for (p = preambleList; p->token != NULL; p++) {
00847         len = strlen(p->token);
00848         if (!(p->token && !xstrncasecmp(spec->line, p->token, len)))
00849             continue;
00850         if (p->obsolete) {
00851             rpmError(RPMERR_BADSPEC, _("Legacy syntax is unsupported: %s\n"),
00852                         p->token);
00853             p = NULL;
00854         }
00855         break;
00856     }
00857     if (p == NULL || p->token == NULL)
00858         return 1;
00859 
00860     s = spec->line + len;
00861     SKIPSPACE(s);
00862 
00863     switch (p->multiLang) {
00864     default:
00865     case 0:
00866         /* Unless this is a source or a patch, a ':' better be next */
00867         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
00868             if (*s != ':') return 1;
00869         }
00870         *lang = '\0';
00871         break;
00872     case 1:     /* Parse optional ( <token> ). */
00873         if (*s == ':') {
00874             strcpy(lang, RPMBUILD_DEFAULT_LANG);
00875             break;
00876         }
00877         if (*s != '(') return 1;
00878         s++;
00879         SKIPSPACE(s);
00880         while (!xisspace(*s) && *s != ')')
00881             *lang++ = *s++;
00882         *lang = '\0';
00883         SKIPSPACE(s);
00884         if (*s != ')') return 1;
00885         s++;
00886         SKIPSPACE(s);
00887         if (*s != ':') return 1;
00888         break;
00889     }
00890 
00891     *tag = p->tag;
00892     if (macro)
00893         /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
00894         *macro = p->token;
00895         /*@=onlytrans =observertrans =dependenttrans@*/
00896     return 0;
00897 }
00898 /*@=boundswrite@*/
00899 
00900 /*@-boundswrite@*/
00901 /* XXX should return rpmParseState, but RPMERR_BADSPEC forces int return. */
00902 int parsePreamble(Spec spec, int initialPackage)
00903 {
00904     rpmParseState nextPart;
00905     int rc, xx;
00906     char *name, *linep;
00907     Package pkg;
00908     char NVR[BUFSIZ];
00909     char lang[BUFSIZ];
00910 
00911     strcpy(NVR, "(main package)");
00912 
00913     pkg = newPackage(spec);
00914         
00915     if (! initialPackage) {
00916         rpmParseState flag;
00917         /* There is one option to %package: <pkg> or -n <pkg> */
00918         flag = PART_NONE;
00919         if (parseSimplePart(spec->line, &name, &flag)) {
00920             rpmError(RPMERR_BADSPEC, _("Bad package specification: %s\n"),
00921                         spec->line);
00922             return RPMERR_BADSPEC;
00923         }
00924         
00925         if (!lookupPackage(spec, name, flag, NULL)) {
00926             rpmError(RPMERR_BADSPEC, _("Package already exists: %s\n"),
00927                         spec->line);
00928             return RPMERR_BADSPEC;
00929         }
00930         
00931         /* Construct the package */
00932         if (flag == PART_SUBNAME) {
00933             const char * mainName;
00934             xx = headerNVR(spec->packages->header, &mainName, NULL, NULL);
00935             sprintf(NVR, "%s-%s", mainName, name);
00936         } else
00937             strcpy(NVR, name);
00938         xx = headerAddEntry(pkg->header, RPMTAG_NAME, RPM_STRING_TYPE, NVR, 1);
00939     }
00940 
00941     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
00942         nextPart = PART_NONE;
00943     } else {
00944         if (rc)
00945             return rc;
00946         while (! (nextPart = isPart(spec->line))) {
00947             const char * macro;
00948             rpmTag tag;
00949 
00950             /* Skip blank lines */
00951             linep = spec->line;
00952             SKIPSPACE(linep);
00953             if (*linep != '\0') {
00954                 if (findPreambleTag(spec, &tag, &macro, lang)) {
00955                     rpmError(RPMERR_BADSPEC, _("line %d: Unknown tag: %s\n"),
00956                                 spec->lineNum, spec->line);
00957                     return RPMERR_BADSPEC;
00958                 }
00959                 if (handlePreambleTag(spec, pkg, tag, macro, lang))
00960                     return RPMERR_BADSPEC;
00961                 if (spec->BANames && !spec->recursing)
00962                     return PART_BUILDARCHITECTURES;
00963             }
00964             if ((rc =
00965                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
00966                 nextPart = PART_NONE;
00967                 break;
00968             }
00969             if (rc)
00970                 return rc;
00971         }
00972     }
00973 
00974     /* Do some final processing on the header */
00975     
00976     /* XXX Skip valid arch check if not building binary package */
00977     if (!spec->anyarch && checkForValidArchitectures(spec))
00978         return RPMERR_BADSPEC;
00979 
00980     if (pkg == spec->packages)
00981         fillOutMainPackage(pkg->header);
00982 
00983     if (checkForDuplicates(pkg->header, NVR))
00984         return RPMERR_BADSPEC;
00985 
00986     if (pkg != spec->packages)
00987         headerCopyTags(spec->packages->header, pkg->header,
00988                         (int_32 *)copyTagsDuringParse);
00989 
00990     if (headerGetEntry(pkg->header, RPMTAG_EPOCH, NULL, NULL, NULL) == 0) {
00991         int num = 0;
00992         headerAddEntry(pkg->header, RPMTAG_EPOCH, RPM_INT32_TYPE, &num, 1);
00993         addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC);
00994     }
00995     
00996     if (checkForRequired(pkg->header, NVR))
00997         return RPMERR_BADSPEC;
00998 
00999     return nextPart;
01000 }
01001 /*@=boundswrite@*/

Generated on Wed Dec 28 07:45:57 2016 for rpm by  doxygen 1.4.4