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