2 * \file build/parsePreamble.c
3 * Parse tags in global section from spec file.
11 #include <rpm/header.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmurl.h>
14 #include <rpm/rpmfileutil.h>
15 #include "rpmio/rpmlua.h"
16 #include "build/rpmbuild_internal.h"
17 #include "build/rpmbuild_misc.h"
20 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
21 #define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
22 #define SKIPWHITE(_x) {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
23 #define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
27 static const rpmTagVal copyTagsDuringParse[] = {
51 static const rpmTagVal requiredTags[] = {
62 static rpmRC addOrAppendListEntry(Header h, rpmTagVal tag, const char * line)
68 if ((xx = poptParseArgvString(line, &argc, &argv))) {
69 rpmlog(RPMLOG_ERR, _("Error parsing tag field: %s\n"), poptStrerror(xx));
73 headerPutStringArray(h, tag, argv, argc);
79 /* Parse a simple part line that only take -n <pkg> or <pkg> */
80 /* <pkg> is returned in name as a pointer into a dynamic buffer */
84 static int parseSimplePart(const char *line, char **name, int *flag)
87 char *linebuf = xstrdup(line);
90 /* Throw away the first token (the %xxxx) */
91 (void)strtok(linebuf, " \t\n");
94 if (!(tok = strtok(NULL, " \t\n"))) {
99 if (rstreq(tok, "-n")) {
100 if (!(tok = strtok(NULL, " \t\n"))) {
106 *flag = PART_SUBNAME;
108 *name = xstrdup(tok);
109 rc = strtok(NULL, " \t\n") ? 1 : 0;
118 static inline int parseYesNo(const char * s)
120 return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
121 !rstrcasecmp(s, "false") || !rstrcasecmp(s, "off"))
125 static struct Source *findSource(rpmSpec spec, uint32_t num, int flag)
129 for (p = spec->sources; p != NULL; p = p->next)
130 if ((num == p->num) && (p->flags & flag)) return p;
135 static int parseNoSource(rpmSpec spec, const char * field, rpmTagVal tag)
142 if (tag == RPMTAG_NOSOURCE) {
143 flag = RPMBUILD_ISSOURCE;
146 flag = RPMBUILD_ISPATCH;
151 for (f = fe; *f != '\0'; f = fe) {
159 if (*fe != '\0') fe++;
161 if (parseUnsignedNum(f, &num)) {
162 rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
167 if (! (p = findSource(spec, num, flag))) {
168 rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %u\n"),
169 spec->lineNum, name, num);
173 p->flags |= RPMBUILD_ISNO;
180 static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag)
184 const char *name = NULL;
192 flag = RPMBUILD_ISSOURCE;
194 fieldp = spec->line + 6;
197 flag = RPMBUILD_ISPATCH;
199 fieldp = spec->line + 5;
202 flag = RPMBUILD_ISICON;
211 if (tag != RPMTAG_ICON) {
212 /* We already know that a ':' exists, and that there */
213 /* are no spaces before it. */
214 /* This also now allows for spaces and tabs between */
215 /* the number and the ':' */
217 char *fieldp_backup = fieldp;
219 while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
225 nump = fieldp_backup;
227 if (nump == NULL || *nump == '\0') {
228 num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX;
230 if (parseUnsignedNum(fieldp_backup, &num)) {
231 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
232 spec->lineNum, name, spec->line);
240 /* Check whether tags of the same number haven't already been defined */
241 for (p = spec->sources; p != NULL; p = p->next) {
242 if ( p->num != num ) continue;
243 if ((tag == RPMTAG_SOURCE && p->flags == RPMBUILD_ISSOURCE) ||
244 (tag == RPMTAG_PATCH && p->flags == RPMBUILD_ISPATCH)) {
245 rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num);
250 /* Create the entry and link it in */
251 p = xmalloc(sizeof(*p));
253 p->fullSource = xstrdup(field);
255 p->source = strrchr(p->fullSource, '/');
257 if ((buf = strrchr(p->source,'='))) p->source = buf;
260 p->source = p->fullSource;
263 if (tag != RPMTAG_ICON) {
264 p->next = spec->sources;
273 if (tag != RPMTAG_ICON) {
274 char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
276 int nofetch = (spec->flags & RPMSPEC_FORCE) ||
277 rpmExpandNumeric("%{_disable_source_fetch}");
279 /* try to download source/patch if it's missing */
280 if (lstat(body, &st) != 0 && errno == ENOENT && !nofetch) {
282 if (urlIsURL(p->fullSource) != URL_IS_UNKNOWN) {
283 url = rstrdup(p->fullSource);
285 url = rpmExpand("%{_default_source_url}", NULL);
286 rstrcat(&url, p->source);
287 if (*url == '%') url = _free(url);
290 rpmlog(RPMLOG_WARNING, _("Downloading %s to %s\n"), url, body);
291 if (urlGetFile(url, body) != 0) {
293 rpmlog(RPMLOG_ERR, _("Couldn't download %s\n"), p->fullSource);
300 rasprintf(&buf, "%s%d",
301 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
302 addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
304 rasprintf(&buf, "%sURL%d",
305 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
306 addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
309 if (!spec->recursing) {
310 rpmlua lua = NULL; /* global state */
311 const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
312 rpmluaPushTable(lua, what);
313 rpmluav var = rpmluavNew();
314 rpmluavSetListMode(var, 1);
315 rpmluavSetValue(var, RPMLUAV_STRING, body);
316 rpmluaSetVar(lua, var);
327 typedef const struct tokenBits_s {
334 static struct tokenBits_s const installScriptBits[] = {
335 { "interp", RPMSENSE_INTERP },
336 { "preun", RPMSENSE_SCRIPT_PREUN },
337 { "pre", RPMSENSE_SCRIPT_PRE },
338 { "postun", RPMSENSE_SCRIPT_POSTUN },
339 { "post", RPMSENSE_SCRIPT_POST },
340 { "rpmlib", RPMSENSE_RPMLIB },
341 { "verify", RPMSENSE_SCRIPT_VERIFY },
342 { "pretrans", RPMSENSE_PRETRANS },
343 { "posttrans", RPMSENSE_POSTTRANS },
344 { "hint", RPMSENSE_MISSINGOK },
345 { "strong", RPMSENSE_STRONG },
351 static int parseBits(const char * s, const tokenBits tokbits,
356 rpmsenseFlags bits = RPMSENSE_ANY;
362 while ((c = *s) && risspace(c)) s++;
364 while ((c = *se) && risalpha(c)) se++;
367 for (tb = tokbits; tb->name; tb++) {
368 if (tb->name != NULL &&
369 strlen(tb->name) == (se-s) && rstreqn(tb->name, s, (se-s)))
372 if (tb->name == NULL) {
377 while ((c = *se) && risspace(c)) se++;
389 static inline char * findLastChar(char * s)
404 static int isMemberInEntry(Header h, const char *name, rpmTagVal tag)
410 if (!headerGet(h, tag, &td, HEADERGET_MINMEM))
413 while ((str = rpmtdNextString(&td))) {
414 if (!rstrcasecmp(str, name)) {
426 static rpmRC checkForValidArchitectures(rpmSpec spec)
428 char *arch = rpmExpand("%{_target_cpu}", NULL);
429 char *os = rpmExpand("%{_target_os}", NULL);
430 rpmRC rc = RPMRC_FAIL; /* assume failure */
432 if (isMemberInEntry(spec->buildRestrictions,
433 arch, RPMTAG_EXCLUDEARCH) == 1) {
434 rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
437 if (isMemberInEntry(spec->buildRestrictions,
438 arch, RPMTAG_EXCLUSIVEARCH) == 0) {
439 rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
442 if (isMemberInEntry(spec->buildRestrictions,
443 os, RPMTAG_EXCLUDEOS) == 1) {
444 rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
447 if (isMemberInEntry(spec->buildRestrictions,
448 os, RPMTAG_EXCLUSIVEOS) == 0) {
449 rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
462 * Check that required tags are present in header.
464 * @param NVR package name-version-release
465 * @return RPMRC_OK if OK
467 static int checkForRequired(Header h, const char * NVR)
472 for (p = requiredTags; *p != 0; p++) {
473 if (!headerIsEntry(h, *p)) {
475 _("%s field must be present in package: %s\n"),
476 rpmTagGetName(*p), NVR);
485 * Check that no duplicate tags are present in header.
487 * @param NVR package name-version-release
488 * @return RPMRC_OK if OK
490 static int checkForDuplicates(Header h, const char * NVR)
493 rpmTagVal tag, lastTag = RPMTAG_NOT_FOUND;
494 HeaderIterator hi = headerInitIterator(h);
496 while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
497 if (tag == lastTag) {
498 rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
499 rpmTagGetName(tag), NVR);
504 headerFreeIterator(hi);
511 static struct optionalTag {
514 } const optionalTags[] = {
515 { RPMTAG_VENDOR, "%{vendor}" },
516 { RPMTAG_PACKAGER, "%{packager}" },
517 { RPMTAG_DISTRIBUTION, "%{distribution}" },
518 { RPMTAG_DISTURL, "%{disturl}" },
519 { RPMTAG_BUGURL, "%{bugurl}" },
525 static void fillOutMainPackage(Header h)
527 const struct optionalTag *ot;
529 for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
530 if (!headerIsEntry(h, ot->ot_tag)) {
531 char *val = rpmExpand(ot->ot_mac, NULL);
532 if (val && *val != '%') {
533 headerPutString(h, ot->ot_tag, val);
542 static rpmRC readIcon(Header h, const char * file)
545 uint8_t *icon = NULL;
547 rpmRC rc = RPMRC_FAIL; /* assume failure */
551 /* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
552 fn = rpmGetPath("%{_sourcedir}/", file, NULL);
554 fd = Fopen(fn, "r.ufdio");
556 rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
561 iconsize = (size >= 0 ? size : (8 * BUFSIZ));
563 rc = RPMRC_OK; /* XXX Eh? */
567 icon = xmalloc(iconsize + 1);
570 nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
571 if (Ferror(fd) || (size >= 0 && nb != size)) {
572 rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
577 if (rstreqn((char*)icon, "GIF", sizeof("GIF")-1)) {
578 headerPutBin(h, RPMTAG_GIF, icon, iconsize);
579 } else if (rstreqn((char*)icon, "/* XPM", sizeof("/* XPM")-1)) {
580 headerPutBin(h, RPMTAG_XPM, icon, iconsize);
582 rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), file);
594 #define SINGLE_TOKEN_ONLY \
596 rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
597 spec->lineNum, spec->line); \
602 * Check for inappropriate characters. All alphanums are considered sane.
604 * @param field string to check
605 * @param fsize size of string to check
606 * @param whitelist string of permitted characters
607 * @return RPMRC_OK if OK
609 rpmRC rpmCharCheck(rpmSpec spec, const char *field, size_t fsize, const char *whitelist)
611 const char *ch, *stop = &field[fsize];
613 for (ch=field; *ch && ch < stop; ch++) {
614 if (risalnum(*ch) || strchr(whitelist, *ch)) continue;
616 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '%c' in: %s\n"),
617 spec->lineNum, *ch, spec->line);
619 rpmlog(RPMLOG_ERR, _("line %d: Illegal char in: %s\n"),
620 spec->lineNum, spec->line);
624 if (strstr(field, "..") != NULL) {
625 rpmlog(RPMLOG_ERR, _("line %d: Illegal sequence \"..\" in: %s\n"),
626 spec->lineNum, spec->line);
633 static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
634 const char *macro, const char *lang)
636 char * field = spec->line;
639 rpmsenseFlags tagflags = RPMSENSE_ANY;
640 rpmRC rc = RPMRC_FAIL;
642 if (field == NULL) /* XXX can't happen */
644 /* Find the start of the "field" and strip trailing space */
645 while ((*field) && (*field != ':'))
648 rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
649 spec->lineNum, spec->line);
656 rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
657 spec->lineNum, spec->line);
660 end = findLastChar(field);
663 /* See if this is multi-token */
672 if (rpmCharCheck(spec, field, strlen(field), ".-_+%{}"))
674 headerPutString(pkg->header, tag, field);
679 if (rpmCharCheck(spec, field, strlen(field), "._+%{}~"))
681 headerPutString(pkg->header, tag, field);
686 /* XXX TODO: validate format somehow */
689 headerPutString(pkg->header, tag, field);
693 case RPMTAG_DISTRIBUTION:
696 case RPMTAG_PACKAGER:
698 headerPutString(pkg->header, tag, field);
699 } else if (!((spec->flags & RPMSPEC_NOLANG) &&
700 !rstreq(lang, RPMBUILD_DEFAULT_LANG)))
701 headerAddI18NString(pkg->header, tag, field, lang);
703 case RPMTAG_BUILDROOT:
704 /* just silently ignore BuildRoot */
707 case RPMTAG_PREFIXES: {
710 if (addOrAppendListEntry(pkg->header, tag, field))
712 headerGet(pkg->header, tag, &td, HEADERGET_MINMEM);
713 while ((str = rpmtdNextString(&td))) {
714 size_t len = strlen(str);
715 if (len > 1 && str[len-1] == '/') {
717 _("line %d: Prefixes must not end with \"/\": %s\n"),
718 spec->lineNum, spec->line);
728 if (field[0] != '/') {
729 rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"),
730 spec->lineNum, spec->line);
734 delMacro(NULL, "_docdir");
735 addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
740 if (parseUnsignedNum(field, &epoch)) {
742 _("line %d: Epoch field must be an unsigned number: %s\n"),
743 spec->lineNum, spec->line);
746 headerPutUint32(pkg->header, tag, &epoch, 1);
749 case RPMTAG_AUTOREQPROV:
750 pkg->autoReq = parseYesNo(field);
751 pkg->autoProv = pkg->autoReq;
754 pkg->autoReq = parseYesNo(field);
756 case RPMTAG_AUTOPROV:
757 pkg->autoProv = parseYesNo(field);
762 if (addSource(spec, pkg, field, tag))
767 if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field))
770 case RPMTAG_NOSOURCE:
773 if (parseNoSource(spec, field, tag))
776 case RPMTAG_ORDERFLAGS:
777 case RPMTAG_REQUIREFLAGS:
778 if (parseBits(lang, installScriptBits, &tagflags)) {
779 rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"),
780 spec->lineNum, rpmTagGetName(tag), spec->line);
785 case RPMTAG_BUILDPREREQ:
786 case RPMTAG_BUILDREQUIRES:
787 case RPMTAG_BUILDCONFLICTS:
788 case RPMTAG_CONFLICTFLAGS:
789 case RPMTAG_OBSOLETEFLAGS:
790 case RPMTAG_PROVIDEFLAGS:
791 if (parseRCPOT(spec, pkg, field, tag, 0, tagflags))
794 case RPMTAG_SUGGESTSFLAGS:
795 case RPMTAG_ENHANCESFLAGS:
796 case RPMTAG_BUILDSUGGESTS:
797 case RPMTAG_BUILDENHANCES:
798 tagflags = RPMSENSE_MISSINGOK;
799 if (macro && (!strcmp(macro, "recommends") || !strcmp(macro, "buildrecommends")))
800 tagflags |= RPMSENSE_STRONG;
801 if (macro && (!strcmp(macro, "supplements") || !strcmp(macro, "buildsupplements")))
802 tagflags |= RPMSENSE_STRONG;
803 if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
806 case RPMTAG_EXCLUDEARCH:
807 case RPMTAG_EXCLUSIVEARCH:
808 case RPMTAG_EXCLUDEOS:
809 case RPMTAG_EXCLUSIVEOS:
810 if (addOrAppendListEntry(spec->buildRestrictions, tag, field))
813 case RPMTAG_BUILDARCHS: {
815 const char **BANames = NULL;
816 if (poptParseArgvString(field, &BACount, &BANames)) {
818 _("line %d: Bad BuildArchitecture format: %s\n"),
819 spec->lineNum, spec->line);
822 if (spec->packages == pkg) {
823 spec->BACount = BACount;
824 spec->BANames = BANames;
826 if (BACount != 1 || !rstreq(BANames[0], "noarch")) {
828 _("line %d: Only noarch subpackages are supported: %s\n"),
829 spec->lineNum, spec->line);
830 BANames = _free(BANames);
833 headerPutString(pkg->header, RPMTAG_ARCH, "noarch");
836 spec->BANames = _free(spec->BANames);
839 case RPMTAG_COLLECTIONS:
840 case RPMTAG_BUILDINFO:
841 if (addOrAppendListEntry(pkg->header, tag, field))
845 rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag);
850 addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
856 /* This table has to be in a peculiar order. If one tag is the */
857 /* same as another, plus a few letters, it must come first. */
861 typedef const struct PreambleRec_s {
869 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
871 static struct PreambleRec_s const preambleList[] = {
872 {RPMTAG_NAME, 0, 0, LEN_AND_STR("name")},
873 {RPMTAG_VERSION, 0, 0, LEN_AND_STR("version")},
874 {RPMTAG_RELEASE, 0, 0, LEN_AND_STR("release")},
875 {RPMTAG_EPOCH, 0, 0, LEN_AND_STR("epoch")},
876 {RPMTAG_SUMMARY, 1, 0, LEN_AND_STR("summary")},
877 {RPMTAG_LICENSE, 0, 0, LEN_AND_STR("license")},
878 {RPMTAG_DISTRIBUTION, 0, 0, LEN_AND_STR("distribution")},
879 {RPMTAG_DISTURL, 0, 0, LEN_AND_STR("disturl")},
880 {RPMTAG_VENDOR, 0, 0, LEN_AND_STR("vendor")},
881 {RPMTAG_GROUP, 1, 0, LEN_AND_STR("group")},
882 {RPMTAG_PACKAGER, 0, 0, LEN_AND_STR("packager")},
883 {RPMTAG_URL, 0, 0, LEN_AND_STR("url")},
884 {RPMTAG_VCS, 0, 0, LEN_AND_STR("vcs")},
885 {RPMTAG_SOURCE, 0, 0, LEN_AND_STR("source")},
886 {RPMTAG_PATCH, 0, 0, LEN_AND_STR("patch")},
887 {RPMTAG_NOSOURCE, 0, 0, LEN_AND_STR("nosource")},
888 {RPMTAG_NOPATCH, 0, 0, LEN_AND_STR("nopatch")},
889 {RPMTAG_EXCLUDEARCH, 0, 0, LEN_AND_STR("excludearch")},
890 {RPMTAG_EXCLUSIVEARCH, 0, 0, LEN_AND_STR("exclusivearch")},
891 {RPMTAG_EXCLUDEOS, 0, 0, LEN_AND_STR("excludeos")},
892 {RPMTAG_EXCLUSIVEOS, 0, 0, LEN_AND_STR("exclusiveos")},
893 {RPMTAG_ICON, 0, 0, LEN_AND_STR("icon")},
894 {RPMTAG_PROVIDEFLAGS, 0, 0, LEN_AND_STR("provides")},
895 {RPMTAG_REQUIREFLAGS, 2, 0, LEN_AND_STR("requires")},
896 {RPMTAG_PREREQ, 2, 1, LEN_AND_STR("prereq")},
897 {RPMTAG_CONFLICTFLAGS, 0, 0, LEN_AND_STR("conflicts")},
898 {RPMTAG_OBSOLETEFLAGS, 0, 0, LEN_AND_STR("obsoletes")},
899 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefixes")},
900 {RPMTAG_PREFIXES, 0, 0, LEN_AND_STR("prefix")},
901 {RPMTAG_BUILDROOT, 0, 0, LEN_AND_STR("buildroot")},
902 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarchitectures")},
903 {RPMTAG_BUILDARCHS, 0, 0, LEN_AND_STR("buildarch")},
904 {RPMTAG_BUILDCONFLICTS, 0, 0, LEN_AND_STR("buildconflicts")},
905 {RPMTAG_BUILDPREREQ, 0, 1, LEN_AND_STR("buildprereq")},
906 {RPMTAG_BUILDREQUIRES, 0, 0, LEN_AND_STR("buildrequires")},
907 {RPMTAG_AUTOREQPROV, 0, 0, LEN_AND_STR("autoreqprov")},
908 {RPMTAG_AUTOREQ, 0, 0, LEN_AND_STR("autoreq")},
909 {RPMTAG_AUTOPROV, 0, 0, LEN_AND_STR("autoprov")},
910 {RPMTAG_DOCDIR, 0, 0, LEN_AND_STR("docdir")},
911 {RPMTAG_DISTTAG, 0, 0, LEN_AND_STR("disttag")},
912 {RPMTAG_BUGURL, 0, 0, LEN_AND_STR("bugurl")},
913 {RPMTAG_COLLECTIONS, 0, 0, LEN_AND_STR("collections")},
914 {RPMTAG_ORDERFLAGS, 2, 0, LEN_AND_STR("orderwithrequires")},
915 {RPMTAG_SUGGESTSFLAGS, 0, 0, LEN_AND_STR("recommends")},
916 {RPMTAG_SUGGESTSFLAGS, 0, 0, LEN_AND_STR("suggests")},
917 {RPMTAG_ENHANCESFLAGS, 0, 0, LEN_AND_STR("supplements")},
918 {RPMTAG_ENHANCESFLAGS, 0, 0, LEN_AND_STR("enhances")},
919 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildrecommends")},
920 {RPMTAG_BUILDSUGGESTS, 0, 0, LEN_AND_STR("buildsuggests")},
921 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildsupplements")},
922 {RPMTAG_BUILDENHANCES, 0, 0, LEN_AND_STR("buildenhances")},
923 {RPMTAG_SECMANIFEST, 0, 0, LEN_AND_STR("manifest")},
924 {RPMTAG_BUILDINFO, 0, 0, LEN_AND_STR("buildinfo")},
930 static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
931 const char ** macro, char * lang)
936 for (p = preambleList; p->token != NULL; p++) {
937 if (!(p->token && !rstrncasecmp(spec->line, p->token, p->len)))
940 rpmlog(RPMLOG_WARNING, _("line %d: %s is deprecated: %s\n"),
941 spec->lineNum, p->token, spec->line);
945 if (p == NULL || p->token == NULL)
948 s = spec->line + p->len;
954 /* Unless this is a source or a patch, a ':' better be next */
955 if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
956 if (*s != ':') return 1;
960 case 1: /* Parse optional ( <token> ). */
963 /* Type 1 is multilang, 2 is qualifiers with no defaults */
964 strcpy(lang, (p->type == 1) ? RPMBUILD_DEFAULT_LANG : "");
967 if (*s != '(') return 1;
970 while (!risspace(*s) && *s != ')')
974 if (*s != ')') return 1;
977 if (*s != ':') return 1;
987 int parsePreamble(rpmSpec spec, int initialPackage)
989 int nextPart = PART_ERROR;
990 int res = PART_ERROR; /* assume failure */
998 pkg = newPackage(spec);
1000 if (! initialPackage) {
1001 /* There is one option to %package: <pkg> or -n <pkg> */
1002 if (parseSimplePart(spec->line, &name, &flag)) {
1003 rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
1008 if (!lookupPackage(spec, name, flag, NULL)) {
1009 rpmlog(RPMLOG_ERR, _("Package already exists: %s\n"), spec->line);
1014 /* Construct the package */
1015 if (flag == PART_SUBNAME) {
1016 rasprintf(&NVR, "%s-%s",
1017 headerGetString(spec->packages->header, RPMTAG_NAME), name);
1019 NVR = xstrdup(name);
1021 headerPutString(pkg->header, RPMTAG_NAME, NVR);
1023 NVR = xstrdup("(main package)");
1026 if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1027 nextPart = PART_NONE;
1028 } else if (rc < 0) {
1031 while (! (nextPart = isPart(spec->line))) {
1035 /* Skip blank lines */
1038 if (*linep != '\0') {
1039 if (findPreambleTag(spec, &tag, ¯o, lang)) {
1040 rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
1041 spec->lineNum, spec->line);
1044 if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
1047 if (spec->BANames && !spec->recursing) {
1048 res = PART_BUILDARCHITECTURES;
1053 readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
1054 nextPart = PART_NONE;
1064 * Expand buildroot one more time to get %{version} and the like
1065 * from the main package, validate sanity. The spec->buildRoot could
1066 * still contain unexpanded macros but it cannot be empty or '/', and it
1067 * can't be messed with by anything spec does beyond this point.
1069 if (initialPackage) {
1070 char *buildRoot = rpmGetPath(spec->buildRoot, NULL);
1071 if (*buildRoot == '\0') {
1072 rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n"));
1075 if (rstreq(buildRoot, "/")) {
1076 rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n"));
1079 free(spec->buildRoot);
1080 spec->buildRoot = buildRoot;
1081 addMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC);
1084 /* XXX Skip valid arch check if not building binary package */
1085 if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) {
1089 /* It is the main package */
1090 if (pkg == spec->packages) {
1091 fillOutMainPackage(pkg->header);
1092 /* Define group tag to something when group is undefined in main package*/
1093 if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) {
1094 headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified");
1098 if (checkForDuplicates(pkg->header, NVR)) {
1102 if (pkg != spec->packages) {
1103 headerCopyTags(spec->packages->header, pkg->header,
1104 (rpmTagVal *)copyTagsDuringParse);
1107 if (checkForRequired(pkg->header, NVR)) {
1111 /* if we get down here nextPart has been set to non-error */