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