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
00014
00017
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
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
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
00074
00075
00078
00079 static int parseSimplePart(char *line, char **name,
00080 rpmParseState *flag)
00081
00082
00083 {
00084 char *tok;
00085 char linebuf[BUFSIZ];
00086 static char buf[BUFSIZ];
00087
00088 strcpy(linebuf, line);
00089
00090
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
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
00124 const char * name;
00125 rpmsenseFlags bits;
00126 } * tokenBits;
00127
00130
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
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
00158 static int parseBits(const char * s, const tokenBits tokbits,
00159 rpmsenseFlags * bp)
00160
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 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
00192
00195 static inline char * findLastChar(char * s)
00196
00197 {
00198 char *se = s + strlen(s);
00199
00200
00201 while (--se > s && strchr(" \t\n\r", *se) != NULL)
00202 *se = '\0';
00203
00204
00205 return se;
00206
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
00223 while (count--) {
00224 if (!xstrcasecmp(names[count], name))
00225 break;
00226 }
00227 names = hfd(names, type);
00228
00229 return (count >= 0 ? 1 : 0);
00230 }
00231
00234 static int checkForValidArchitectures(Spec spec)
00235
00236
00237 {
00238 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00239 const char *os = rpmExpand("%{_target_os}", NULL);
00240 int rc = RPMERR_BADSPEC;
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
00273 {
00274 int res = 0;
00275 rpmTag * p;
00276
00277
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
00287
00288 return res;
00289 }
00290
00297 static int checkForDuplicates(Header h, const char * NVR)
00298
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
00322 static struct optionalTag {
00323 rpmTag ot_tag;
00324
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
00338
00339 {
00340 struct optionalTag *ot;
00341
00342 for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
00343 if (!headerIsEntry(h, ot->ot_tag)) {
00344
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
00350 }
00351 }
00352 }
00353
00356
00357 static int doIcon(Spec spec, Header h)
00358
00359
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;
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 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
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
00473 return t;
00474
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
00485 extern int noLang;
00486
00487
00490
00491 static int handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
00492 const char *macro, const char *lang)
00493
00494
00495
00496
00497
00498
00499
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;
00515
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
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
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
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
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
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
00587 if (*buildRoot == '\0') buildRoot = "/";
00588
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
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
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
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:
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
00757
00758
00759
00760
00763 typedef struct PreambleRec_s {
00764 rpmTag tag;
00765 int multiLang;
00766 int obsolete;
00767
00768 const char * token;
00769 } * PreambleRec;
00770
00771
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
00831 {0, 0, 0, 0}
00832
00833 };
00834
00837
00838 static int findPreambleTag(Spec spec, rpmTag * tag,
00839 const char ** macro, char * lang)
00840
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
00867 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
00868 if (*s != ':') return 1;
00869 }
00870 *lang = '\0';
00871 break;
00872 case 1:
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
00894 *macro = p->token;
00895
00896 return 0;
00897 }
00898
00899
00900
00901
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
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
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
00951 linep = spec->line;
00952 SKIPSPACE(linep);
00953 if (*linep != '\0') {
00954 if (findPreambleTag(spec, &tag, ¯o, 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
00975
00976
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