2 * \file build/parsePreamble.c
3 * Parse tags in global section from spec file.
8 #include <rpmio_internal.h>
12 /*@access FD_t @*/ /* compared with NULL */
16 /*@observer@*/ /*@unchecked@*/
17 static rpmTag copyTagsDuringParse[] = {
39 /*@observer@*/ /*@unchecked@*/
40 static rpmTag requiredTags[] = {
52 static void addOrAppendListEntry(Header h, int_32 tag, char * line)
59 xx = poptParseArgvString(line, &argc, &argv);
61 xx = headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, argv, argc);
65 /* Parse a simple part line that only take -n <pkg> or <pkg> */
66 /* <pkg> is return in name as a pointer into a static buffer */
71 static int parseSimplePart(char *line, /*@out@*/char **name, /*@out@*/int *flag)
72 /*@globals internalState@*/
73 /*@modifies *name, *flag, internalState @*/
77 static char buf[BUFSIZ];
79 strcpy(linebuf, line);
81 /* Throw away the first token (the %xxxx) */
82 (void)strtok(linebuf, " \t\n");
84 if (!(tok = strtok(NULL, " \t\n"))) {
89 if (!strcmp(tok, "-n")) {
90 if (!(tok = strtok(NULL, " \t\n")))
99 return (strtok(NULL, " \t\n")) ? 1 : 0;
105 static inline int parseYesNo(const char * s)
108 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
109 !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off"))
113 typedef struct tokenBits_s {
114 /*@observer@*/ /*@null@*/
121 /*@observer@*/ /*@unchecked@*/
122 static struct tokenBits_s installScriptBits[] = {
123 { "interp", RPMSENSE_INTERP },
124 { "prereq", RPMSENSE_PREREQ },
125 { "preun", RPMSENSE_SCRIPT_PREUN },
126 { "pre", RPMSENSE_SCRIPT_PRE },
127 { "postun", RPMSENSE_SCRIPT_POSTUN },
128 { "post", RPMSENSE_SCRIPT_POST },
129 { "rpmlib", RPMSENSE_RPMLIB },
130 { "verify", RPMSENSE_SCRIPT_VERIFY },
136 /*@observer@*/ /*@unchecked@*/
137 static struct tokenBits_s buildScriptBits[] = {
138 { "prep", RPMSENSE_SCRIPT_PREP },
139 { "build", RPMSENSE_SCRIPT_BUILD },
140 { "install", RPMSENSE_SCRIPT_INSTALL },
141 { "clean", RPMSENSE_SCRIPT_CLEAN },
148 static int parseBits(const char * s, const tokenBits tokbits,
149 /*@out@*/ rpmsenseFlags * bp)
154 rpmsenseFlags bits = RPMSENSE_ANY;
159 while ((c = *s) && xisspace(c)) s++;
161 while ((c = *se) && xisalpha(c)) se++;
164 for (tb = tokbits; tb->name; tb++) {
165 if (tb->name != NULL &&
166 strlen(tb->name) == (se-s) && !strncmp(tb->name, s, (se-s)))
167 /*@innerbreak@*/ break;
169 if (tb->name == NULL)
172 while ((c = *se) && xisspace(c)) se++;
178 if (c == 0 && bp) *bp = bits;
179 return (c ? RPMERR_BADSPEC : 0);
185 static inline char * findLastChar(char * s)
198 /*@-temptrans -retalias@*/
200 /*@=temptrans =retalias@*/
205 static int isMemberInEntry(Header h, const char *name, rpmTag tag)
208 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
209 HFD_t hfd = headerFreeData;
214 if (!hge(h, tag, &type, (void **)&names, &count))
218 if (!xstrcasecmp(names[count], name))
221 names = hfd(names, type);
223 return (count >= 0 ? 1 : 0);
228 static int checkForValidArchitectures(Spec spec)
232 const char *arch = NULL;
233 const char *os = NULL;
235 rpmGetArchInfo(&arch, NULL);
236 rpmGetOsInfo(&os, NULL);
238 const char *arch = rpmExpand("%{_target_cpu}", NULL);
239 const char *os = rpmExpand("%{_target_os}", NULL);
242 if (isMemberInEntry(spec->buildRestrictions,
243 arch, RPMTAG_EXCLUDEARCH) == 1) {
244 rpmError(RPMERR_BADSPEC, _("Architecture is excluded: %s\n"), arch);
245 return RPMERR_BADSPEC;
247 if (isMemberInEntry(spec->buildRestrictions,
248 arch, RPMTAG_EXCLUSIVEARCH) == 0) {
249 rpmError(RPMERR_BADSPEC, _("Architecture is not included: %s\n"), arch);
250 return RPMERR_BADSPEC;
252 if (isMemberInEntry(spec->buildRestrictions,
253 os, RPMTAG_EXCLUDEOS) == 1) {
254 rpmError(RPMERR_BADSPEC, _("OS is excluded: %s\n"), os);
255 return RPMERR_BADSPEC;
257 if (isMemberInEntry(spec->buildRestrictions,
258 os, RPMTAG_EXCLUSIVEOS) == 0) {
259 rpmError(RPMERR_BADSPEC, _("OS is not included: %s\n"), os);
260 return RPMERR_BADSPEC;
267 * Check that required tags are present in header.
269 * @param NVR package name-version-release
272 static int checkForRequired(Header h, const char * NVR)
273 /*@modifies h @*/ /* LCL: parse error here with modifies */
279 for (p = requiredTags; *p != 0; p++) {
280 if (!headerIsEntry(h, *p)) {
281 rpmError(RPMERR_BADSPEC,
282 _("%s field must be present in package: %s\n"),
293 * Check that no duplicate tags are present in header.
295 * @param NVR package name-version-release
298 static int checkForDuplicates(Header h, const char * NVR)
305 for (hi = headerInitIterator(h), lastTag = 0;
306 headerNextIterator(hi, &tag, NULL, NULL, NULL);
311 rpmError(RPMERR_BADSPEC, _("Duplicate %s entries in package: %s\n"),
315 hi = headerFreeIterator(hi);
322 /*@observer@*/ /*@unchecked@*/
323 static struct optionalTag {
325 /*@observer@*/ /*@null@*/
328 { RPMTAG_VENDOR, "%{vendor}" },
329 { RPMTAG_PACKAGER, "%{packager}" },
330 { RPMTAG_DISTRIBUTION, "%{distribution}" },
331 { RPMTAG_DISTURL, "%{disturl}" },
337 static void fillOutMainPackage(Header h)
338 /*@globals rpmGlobalMacroContext, h_errno @*/
339 /*@modifies h, rpmGlobalMacroContext @*/
341 struct optionalTag *ot;
343 for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
344 if (!headerIsEntry(h, ot->ot_tag)) {
346 const char *val = rpmExpand(ot->ot_mac, NULL);
347 if (val && *val != '%')
348 (void) headerAddEntry(h, ot->ot_tag, RPM_STRING_TYPE, (void *)val, 1);
358 static int readIcon(Header h, const char * file)
359 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
360 /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState @*/
362 const char *fn = NULL;
369 /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
370 fn = rpmGetPath("%{_sourcedir}/", file, NULL);
372 fd = Fopen(fn, "r.ufdio");
373 if (fd == NULL || Ferror(fd)) {
374 rpmError(RPMERR_BADSPEC, _("Unable to open icon %s: %s\n"),
380 iconsize = (size >= 0 ? size : (8 * BUFSIZ));
387 icon = xmalloc(iconsize + 1);
390 nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
391 if (Ferror(fd) || (size >= 0 && nb != size)) {
392 rpmError(RPMERR_BADSPEC, _("Unable to read icon %s: %s\n"),
400 if (! strncmp(icon, "GIF", sizeof("GIF")-1)) {
401 (void) headerAddEntry(h, RPMTAG_GIF, RPM_BIN_TYPE, icon, iconsize);
402 } else if (! strncmp(icon, "/* XPM", sizeof("/* XPM")-1)) {
403 (void) headerAddEntry(h, RPMTAG_XPM, RPM_BIN_TYPE, icon, iconsize);
405 rpmError(RPMERR_BADSPEC, _("Unknown icon type: %s\n"), file);
417 spectag stashSt(Spec spec, Header h, int tag, const char * lang)
419 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
423 spectags st = spec->st;
424 if (st->st_ntags == st->st_nalloc) {
426 st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
428 t = st->st_t + st->st_ntags++;
430 t->t_startx = spec->lineNum - 1;
432 t->t_lang = xstrdup(lang);
434 if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
436 if (hge(h, RPMTAG_NAME, NULL, (void **) &n, NULL)) {
438 sprintf(buf, "%s(%s)", n, tagName(tag));
439 t->t_msgid = xstrdup(buf);
443 /*@-usereleased -compdef@*/
445 /*@=usereleased =compdef@*/
448 #define SINGLE_TOKEN_ONLY \
450 rpmError(RPMERR_BADSPEC, _("line %d: Tag takes single token only: %s\n"), \
451 spec->lineNum, spec->line); \
452 return RPMERR_BADSPEC; \
462 static int handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
463 const char *macro, const char *lang)
464 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
465 /*@modifies spec->macros, spec->st, spec->buildRootURL,
466 spec->sources, spec->numSources, spec->noSource,
467 spec->buildRestrictions, spec->BANames, spec->BACount,
468 spec->line, spec->gotBuildRootURL,
469 pkg->header, pkg->autoProv, pkg->autoReq, pkg->icon,
470 rpmGlobalMacroContext, fileSystem, internalState @*/
472 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
473 HFD_t hfd = headerFreeData;
474 char * field = spec->line;
478 rpmsenseFlags tagflags;
485 if (field == NULL) return RPMERR_BADSPEC; /* XXX can't happen */
486 /* Find the start of the "field" and strip trailing space */
487 while ((*field) && (*field != ':'))
490 rpmError(RPMERR_BADSPEC, _("line %d: Malformed tag: %s\n"),
491 spec->lineNum, spec->line);
492 return RPMERR_BADSPEC;
498 rpmError(RPMERR_BADSPEC, _("line %d: Empty tag: %s\n"),
499 spec->lineNum, spec->line);
500 return RPMERR_BADSPEC;
502 end = findLastChar(field);
505 /* See if this is multi-token */
516 case RPMTAG_RHNPLATFORM:
519 /* These macros are for backward compatibility */
520 if (tag == RPMTAG_VERSION) {
521 if (strchr(field, '-') != NULL) {
522 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
523 spec->lineNum, "version", spec->line);
524 return RPMERR_BADSPEC;
526 addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
527 } else if (tag == RPMTAG_RELEASE) {
528 if (strchr(field, '-') != NULL) {
529 rpmError(RPMERR_BADSPEC, _("line %d: Illegal char '-' in %s: %s\n"),
530 spec->lineNum, "release", spec->line);
531 return RPMERR_BADSPEC;
533 addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
535 (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
539 (void) stashSt(spec, pkg->header, tag, lang);
541 case RPMTAG_DISTRIBUTION:
544 case RPMTAG_PACKAGER:
546 (void) headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1);
547 else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG)))
548 (void) headerAddI18NString(pkg->header, tag, field, lang);
550 case RPMTAG_BUILDROOT:
552 { const char * buildRoot = NULL;
553 const char * buildRootURL = spec->buildRootURL;
556 * Note: rpmGenPath should guarantee a "canonical" path. That means
557 * that the following pathologies should be weeded out:
560 * /.././../usr/../bin//./sh
562 if (buildRootURL == NULL) {
563 buildRootURL = rpmGenPath(NULL, "%{?buildroot:%{buildroot}}", NULL);
564 if (strcmp(buildRootURL, "/")) {
565 spec->buildRootURL = buildRootURL;
568 const char * specURL = field;
570 buildRootURL = _free(buildRootURL);
571 (void) urlPath(specURL, (const char **)&field);
573 if (*field == '\0') field = "/";
575 buildRootURL = rpmGenPath(spec->rootURL, field, NULL);
576 spec->buildRootURL = buildRootURL;
577 field = (char *) buildRootURL;
579 spec->gotBuildRootURL = 1;
583 buildRootURL = rpmGenPath(NULL, spec->buildRootURL, NULL);
584 (void) urlPath(buildRootURL, &buildRoot);
586 if (*buildRoot == '\0') buildRoot = "/";
588 if (!strcmp(buildRoot, "/")) {
589 rpmError(RPMERR_BADSPEC,
590 _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
591 buildRootURL = _free(buildRootURL);
592 return RPMERR_BADSPEC;
594 buildRootURL = _free(buildRootURL);
596 case RPMTAG_PREFIXES:
597 addOrAppendListEntry(pkg->header, tag, field);
598 xx = hge(pkg->header, tag, &type, (void **)&array, &num);
600 len = strlen(array[num]);
601 if (array[num][len - 1] == '/' && len > 1) {
602 rpmError(RPMERR_BADSPEC,
603 _("line %d: Prefixes must not end with \"/\": %s\n"),
604 spec->lineNum, spec->line);
605 array = hfd(array, type);
606 return RPMERR_BADSPEC;
609 array = hfd(array, type);
613 if (field[0] != '/') {
614 rpmError(RPMERR_BADSPEC,
615 _("line %d: Docdir must begin with '/': %s\n"),
616 spec->lineNum, spec->line);
617 return RPMERR_BADSPEC;
620 delMacro(NULL, "_docdir");
621 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
625 if (parseNum(field, &num)) {
626 rpmError(RPMERR_BADSPEC,
627 _("line %d: Epoch/Serial field must be a number: %s\n"),
628 spec->lineNum, spec->line);
629 return RPMERR_BADSPEC;
631 xx = headerAddEntry(pkg->header, tag, RPM_INT32_TYPE, &num, 1);
633 case RPMTAG_AUTOREQPROV:
634 pkg->autoReq = parseYesNo(field);
635 pkg->autoProv = pkg->autoReq;
638 pkg->autoReq = parseYesNo(field);
640 case RPMTAG_AUTOPROV:
641 pkg->autoProv = parseYesNo(field);
647 if ((rc = addSource(spec, pkg, field, tag)))
652 if ((rc = addSource(spec, pkg, field, tag)))
654 if ((rc = readIcon(pkg->header, field)))
655 return RPMERR_BADSPEC;
657 case RPMTAG_NOSOURCE:
660 if ((rc = parseNoSource(spec, field, tag)))
663 case RPMTAG_BUILDPREREQ:
664 case RPMTAG_BUILDREQUIRES:
665 if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
666 rpmError(RPMERR_BADSPEC,
667 _("line %d: Bad %s: qualifiers: %s\n"),
668 spec->lineNum, tagName(tag), spec->line);
671 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
674 case RPMTAG_REQUIREFLAGS:
676 if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
677 rpmError(RPMERR_BADSPEC,
678 _("line %d: Bad %s: qualifiers: %s\n"),
679 spec->lineNum, tagName(tag), spec->line);
682 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
685 case RPMTAG_BUILDCONFLICTS:
686 case RPMTAG_CONFLICTFLAGS:
687 case RPMTAG_OBSOLETEFLAGS:
688 case RPMTAG_PROVIDEFLAGS:
689 tagflags = RPMSENSE_ANY;
690 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
693 case RPMTAG_EXCLUDEARCH:
694 case RPMTAG_EXCLUSIVEARCH:
695 case RPMTAG_EXCLUDEOS:
696 case RPMTAG_EXCLUSIVEOS:
697 addOrAppendListEntry(spec->buildRestrictions, tag, field);
699 case RPMTAG_BUILDARCHS:
700 if ((rc = poptParseArgvString(field,
702 &(spec->BANames)))) {
703 rpmError(RPMERR_BADSPEC,
704 _("line %d: Bad BuildArchitecture format: %s\n"),
705 spec->lineNum, spec->line);
706 return RPMERR_BADSPEC;
709 spec->BANames = _free(spec->BANames);
713 rpmError(RPMERR_INTERNAL, _("Internal error: Bogus tag %d\n"), tag);
714 return RPMERR_INTERNAL;
718 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
724 /* This table has to be in a peculiar order. If one tag is the */
725 /* same as another, plus a few letters, it must come first. */
729 typedef struct PreambleRec_s {
734 /*@observer@*/ /*@null@*/
739 static struct PreambleRec_s preambleList[] = {
740 {RPMTAG_NAME, 0, 0, 0, "name"},
741 {RPMTAG_VERSION, 0, 0, 0, "version"},
742 {RPMTAG_RELEASE, 0, 0, 0, "release"},
743 {RPMTAG_EPOCH, 0, 0, 0, "epoch"},
744 {RPMTAG_EPOCH, 0, 0, 1, "serial"},
745 {RPMTAG_SUMMARY, 0, 1, 0, "summary"},
746 {RPMTAG_LICENSE, 0, 0, 1, "copyright"},
747 {RPMTAG_LICENSE, 0, 0, 0, "license"},
748 {RPMTAG_DISTRIBUTION, 0, 0, 0, "distribution"},
749 {RPMTAG_DISTURL, 0, 0, 0, "disturl"},
750 {RPMTAG_VENDOR, 0, 0, 0, "vendor"},
751 {RPMTAG_GROUP, 0, 1, 0, "group"},
752 {RPMTAG_PACKAGER, 0, 0, 0, "packager"},
753 {RPMTAG_URL, 0, 0, 0, "url"},
754 {RPMTAG_SOURCE, 0, 0, 0, "source"},
755 {RPMTAG_PATCH, 0, 0, 0, "patch"},
756 {RPMTAG_NOSOURCE, 0, 0, 0, "nosource"},
757 {RPMTAG_NOPATCH, 0, 0, 0, "nopatch"},
758 {RPMTAG_EXCLUDEARCH, 0, 0, 0, "excludearch"},
759 {RPMTAG_EXCLUSIVEARCH, 0, 0, 0, "exclusivearch"},
760 {RPMTAG_EXCLUDEOS, 0, 0, 0, "excludeos"},
761 {RPMTAG_EXCLUSIVEOS, 0, 0, 0, "exclusiveos"},
762 {RPMTAG_ICON, 0, 0, 0, "icon"},
763 {RPMTAG_PROVIDEFLAGS, 0, 0, 0, "provides"},
764 {RPMTAG_REQUIREFLAGS, 0, 1, 0, "requires"},
765 {RPMTAG_PREREQ, 0, 1, 0, "prereq"},
766 {RPMTAG_CONFLICTFLAGS, 0, 0, 0, "conflicts"},
767 {RPMTAG_OBSOLETEFLAGS, 0, 0, 0, "obsoletes"},
768 {RPMTAG_PREFIXES, 0, 0, 0, "prefixes"},
769 {RPMTAG_PREFIXES, 0, 0, 0, "prefix"},
770 {RPMTAG_BUILDROOT, 0, 0, 0, "buildroot"},
771 {RPMTAG_BUILDARCHS, 0, 0, 0, "buildarchitectures"},
772 {RPMTAG_BUILDARCHS, 0, 0, 0, "buildarch"},
773 {RPMTAG_BUILDCONFLICTS, 0, 0, 0, "buildconflicts"},
774 {RPMTAG_BUILDPREREQ, 0, 1, 0, "buildprereq"},
775 {RPMTAG_BUILDREQUIRES, 0, 1, 0, "buildrequires"},
776 {RPMTAG_AUTOREQPROV, 0, 0, 0, "autoreqprov"},
777 {RPMTAG_AUTOREQ, 0, 0, 0, "autoreq"},
778 {RPMTAG_AUTOPROV, 0, 0, 0, "autoprov"},
779 {RPMTAG_DOCDIR, 0, 0, 0, "docdir"},
780 {RPMTAG_RHNPLATFORM, 0, 0, 1, "rhnplatform"},
781 {RPMTAG_DISTTAG, 0, 0, 0, "disttag"},
782 /*@-nullassign@*/ /* LCL: can't add null annotation */
789 static inline void initPreambleList(void)
790 /*@globals preambleList @*/
791 /*@modifies preambleList @*/
794 for (p = preambleList; p->token != NULL; p++)
795 if (p->token) p->len = strlen(p->token);
801 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tag,
802 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
803 /*@modifies *tag, *macro, *lang @*/
808 if (preambleList[0].len == 0)
811 for (p = preambleList; p->token != NULL; p++) {
812 if (!(p->token && !xstrncasecmp(spec->line, p->token, p->len)))
815 rpmError(RPMERR_BADSPEC, _("Legacy syntax is unsupported: %s\n"),
821 if (p == NULL || p->token == NULL)
824 s = spec->line + p->len;
827 switch (p->multiLang) {
830 /* Unless this is a source or a patch, a ':' better be next */
831 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
832 if (*s != ':') return 1;
836 case 1: /* Parse optional ( <token> ). */
838 strcpy(lang, RPMBUILD_DEFAULT_LANG);
841 if (*s != '(') return 1;
844 while (!xisspace(*s) && *s != ')')
848 if (*s != ')') return 1;
851 if (*s != ':') return 1;
857 /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
859 /*@=onlytrans =observertrans =dependenttrans@*/
865 int parsePreamble(Spec spec, int initialPackage)
875 strcpy(NVR, "(main package)");
877 pkg = newPackage(spec);
879 if (! initialPackage) {
880 /* There is one option to %package: <pkg> or -n <pkg> */
881 if (parseSimplePart(spec->line, &name, &flag)) {
882 rpmError(RPMERR_BADSPEC, _("Bad package specification: %s\n"),
884 return RPMERR_BADSPEC;
887 if (!lookupPackage(spec, name, flag, NULL)) {
888 rpmError(RPMERR_BADSPEC, _("Package already exists: %s\n"),
890 return RPMERR_BADSPEC;
893 /* Construct the package */
894 if (flag == PART_SUBNAME) {
895 const char * mainName;
896 xx = headerNVR(spec->packages->header, &mainName, NULL, NULL);
897 sprintf(NVR, "%s-%s", mainName, name);
900 xx = headerAddEntry(pkg->header, RPMTAG_NAME, RPM_STRING_TYPE, NVR, 1);
903 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
904 nextPart = PART_NONE;
908 while (! (nextPart = isPart(spec->line))) {
912 /* Skip blank lines */
915 if (*linep != '\0') {
916 if (findPreambleTag(spec, &tag, ¯o, lang)) {
917 rpmError(RPMERR_BADSPEC, _("line %d: Unknown tag: %s\n"),
918 spec->lineNum, spec->line);
919 return RPMERR_BADSPEC;
921 if (handlePreambleTag(spec, pkg, tag, macro, lang))
922 return RPMERR_BADSPEC;
923 if (spec->BANames && !spec->recursing)
924 return PART_BUILDARCHITECTURES;
927 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
928 nextPart = PART_NONE;
936 /* Do some final processing on the header */
938 if (!spec->gotBuildRootURL && spec->buildRootURL) {
939 rpmError(RPMERR_BADSPEC, _("Spec file can't use BuildRoot\n"));
940 return RPMERR_BADSPEC;
943 /* XXX Skip valid arch check if not building binary package */
944 if (!spec->anyarch && checkForValidArchitectures(spec))
945 return RPMERR_BADSPEC;
947 if (pkg == spec->packages)
948 fillOutMainPackage(pkg->header);
950 if (checkForDuplicates(pkg->header, NVR))
951 return RPMERR_BADSPEC;
953 if (pkg != spec->packages)
954 headerCopyTags(spec->packages->header, pkg->header,
955 (int_32 *)copyTagsDuringParse);
957 if (checkForRequired(pkg->header, NVR))
958 return RPMERR_BADSPEC;