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

build/parsePreamble.c

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

Generated on Sun Feb 2 23:31:59 2003 for rpm by doxygen1.2.18