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