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