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