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