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