Permit file objects in python header constructor
[platform/upstream/rpm.git] / build / parseSpec.c
index 76140a7..3c5349d 100644 (file)
@@ -5,73 +5,59 @@
 
 #include "system.h"
 
-/*@unchecked@*/
-static int _debug = 0;
-
-#include <rpmio_internal.h>
-#include <rpmbuild.h>
-#include "rpmds.h"
-#include "rpmts.h"
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmlib.h>                /* RPM_MACHTABLE & related */
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmds.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmfileutil.h>
 #include "debug.h"
 
-/*@access FD_t @*/     /* compared with NULL */
+#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
 
-/**
- */
-/*@unchecked@*/
-static struct PartRec {
+#define LEN_AND_STR(_tag) (sizeof(_tag)-1), (_tag)
+
+static const struct PartRec {
     int part;
-    int len;
-/*@observer@*/ /*@null@*/
+    size_t len;
     const char * token;
-} partList[] = {
-    { PART_PREAMBLE,      0, "%package"},
-    { PART_PREP,          0, "%prep"},
-    { PART_BUILD,         0, "%build"},
-    { PART_INSTALL,       0, "%install"},
-    { PART_CHECK,         0, "%check"},
-    { PART_CLEAN,         0, "%clean"},
-    { PART_PREUN,         0, "%preun"},
-    { PART_POSTUN,        0, "%postun"},
-    { PART_PRE,           0, "%pre"},
-    { PART_POST,          0, "%post"},
-    { PART_FILES,         0, "%files"},
-    { PART_CHANGELOG,     0, "%changelog"},
-    { PART_DESCRIPTION,   0, "%description"},
-    { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
-    { PART_TRIGGERUN,     0, "%triggerun"},
-    { PART_TRIGGERIN,     0, "%triggerin"},
-    { PART_TRIGGERIN,     0, "%trigger"},
-    { PART_VERIFYSCRIPT,  0, "%verifyscript"},
+} const partList[] = {
+    { PART_PREAMBLE,      LEN_AND_STR("%package")},
+    { PART_PREP,          LEN_AND_STR("%prep")},
+    { PART_BUILD,         LEN_AND_STR("%build")},
+    { PART_INSTALL,       LEN_AND_STR("%install")},
+    { PART_CHECK,         LEN_AND_STR("%check")},
+    { PART_CLEAN,         LEN_AND_STR("%clean")},
+    { PART_PREUN,         LEN_AND_STR("%preun")},
+    { PART_POSTUN,        LEN_AND_STR("%postun")},
+    { PART_PRETRANS,      LEN_AND_STR("%pretrans")},
+    { PART_POSTTRANS,     LEN_AND_STR("%posttrans")},
+    { PART_PRE,           LEN_AND_STR("%pre")},
+    { PART_POST,          LEN_AND_STR("%post")},
+    { PART_FILES,         LEN_AND_STR("%files")},
+    { PART_CHANGELOG,     LEN_AND_STR("%changelog")},
+    { PART_DESCRIPTION,   LEN_AND_STR("%description")},
+    { PART_TRIGGERPOSTUN, LEN_AND_STR("%triggerpostun")},
+    { PART_TRIGGERPREIN,  LEN_AND_STR("%triggerprein")},
+    { PART_TRIGGERUN,     LEN_AND_STR("%triggerun")},
+    { PART_TRIGGERIN,     LEN_AND_STR("%triggerin")},
+    { PART_TRIGGERIN,     LEN_AND_STR("%trigger")},
+    { PART_VERIFYSCRIPT,  LEN_AND_STR("%verifyscript")},
     {0, 0, 0}
 };
 
-/**
- */
-static inline void initParts(struct PartRec *p)
-       /*@modifies p->len @*/
-{
-    for (; p->token != NULL; p++)
-       p->len = strlen(p->token);
-}
-
 rpmParseState isPart(const char *line)
 {
-    struct PartRec *p;
+    const struct PartRec *p;
 
-/*@-boundsread@*/
-    if (partList[0].len == 0)
-       initParts(partList);
-/*@=boundsread@*/
-    
     for (p = partList; p->token != NULL; p++) {
        char c;
-       if (xstrncasecmp(line, p->token, p->len))
+       if (rstrncasecmp(line, p->token, p->len))
            continue;
-/*@-boundsread@*/
        c = *(line + p->len);
-/*@=boundsread@*/
-       if (c == '\0' || xisspace(c))
+       if (c == '\0' || risspace(c))
            break;
     }
 
@@ -81,42 +67,36 @@ rpmParseState isPart(const char *line)
 /**
  */
 static int matchTok(const char *token, const char *line)
-       /*@*/
 {
     const char *b, *be = line;
     size_t toklen = strlen(token);
     int rc = 0;
 
-/*@-boundsread@*/
     while ( *(b = be) != '\0' ) {
        SKIPSPACE(b);
        be = b;
        SKIPNONSPACE(be);
        if (be == b)
            break;
-       if (toklen != (be-b) || xstrncasecmp(token, b, (be-b)))
+       if (toklen != (be-b) || rstrncasecmp(token, b, (be-b)))
            continue;
        rc = 1;
        break;
     }
-/*@=boundsread@*/
 
     return rc;
 }
 
-/*@-boundswrite@*/
 void handleComments(char *s)
 {
     SKIPSPACE(s);
     if (*s == '#')
        *s = '\0';
 }
-/*@=boundswrite@*/
 
 /**
  */
-static void forceIncludeFile(Spec spec, const char * fileName)
-       /*@modifies spec->fileStack @*/
+static void forceIncludeFile(rpmSpec spec, const char * fileName)
 {
     OFI_t * ofi;
 
@@ -126,51 +106,90 @@ static void forceIncludeFile(Spec spec, const char * fileName)
     spec->fileStack = ofi;
 }
 
-/**
- */
-/*@-boundswrite@*/
-static int copyNextLine(Spec spec, OFI_t *ofi, int strip)
-       /*@globals rpmGlobalMacroContext, h_errno,
-               fileSystem @*/
-       /*@modifies spec->nextline, spec->nextpeekc, spec->lbuf, spec->line,
-               ofi->readPtr,
-               rpmGlobalMacroContext, fileSystem @*/
+static int restoreFirstChar(rpmSpec spec)
 {
-    char *last;
-    char ch;
-
     /* Restore 1st char in (possible) next line */
     if (spec->nextline != NULL && spec->nextpeekc != '\0') {
        *spec->nextline = spec->nextpeekc;
        spec->nextpeekc = '\0';
+       return 1;
     }
+    return 0;
+}
+
+/* Return zero on success, 1 if we need to read more and -1 on errors. */
+static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
+{
+    char ch;
+
     /* Expand next line from file into line buffer */
     if (!(spec->nextline && *spec->nextline)) {
-       char *from, *to;
-       to = last = spec->lbuf;
+       int pc = 0, bc = 0, nc = 0;
+       char *from, *to, *p;
+       to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
        from = ofi->readPtr;
        ch = ' ';
-       while (*from && ch != '\n')
+       while (from && *from && ch != '\n')
            ch = *to++ = *from++;
+       spec->lbufPtr = to;
        *to++ = '\0';
        ofi->readPtr = from;
 
+       /* Check if we need another line before expanding the buffer. */
+       for (p = spec->lbuf; *p; p++) {
+           switch (*p) {
+               case '\\':
+                   switch (*(p+1)) {
+                       case '\n': p++, nc = 1; break;
+                       case '\0': break;
+                       default: p++; break;
+                   }
+                   break;
+               case '\n': nc = 0; break;
+               case '%':
+                   switch (*(p+1)) {
+                       case '{': p++, bc++; break;
+                       case '(': p++, pc++; break;
+                       case '%': p++; break;
+                   }
+                   break;
+               case '{': if (bc > 0) bc++; break;
+               case '}': if (bc > 0) bc--; break;
+               case '(': if (pc > 0) pc++; break;
+               case ')': if (pc > 0) pc--; break;
+           }
+       }
+       
+       /* If it doesn't, ask for one more line. */
+       if (pc || bc || nc ) {
+           spec->nextline = "";
+           return 1;
+       }
+       spec->lbufPtr = spec->lbuf;
+
        /* Don't expand macros (eg. %define) in false branch of %if clause */
        if (spec->readStack->reading &&
            expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
-               rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
+               rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
                        spec->lineNum, spec->lbuf);
-               return RPMERR_BADSPEC;
+               return -1;
        }
        spec->nextline = spec->lbuf;
     }
+    return 0;
+}
+
+static void copyNextLineFinish(rpmSpec spec, int strip)
+{
+    char *last;
+    char ch;
 
     /* Find next line in expanded line buffer */
     spec->line = last = spec->nextline;
     ch = ' ';
     while (*spec->nextline && ch != '\n') {
        ch = *spec->nextline++;
-       if (!xisspace(ch))
+       if (!risspace(ch))
            last = spec->nextline;
     }
 
@@ -185,49 +204,31 @@ static int copyNextLine(Spec spec, OFI_t *ofi, int strip)
     
     if (strip & STRIP_TRAILINGSPACE)
        *last = '\0';
-
-    return 0;
 }
-/*@=boundswrite@*/
 
-/*@-boundswrite@*/
-int readLine(Spec spec, int strip)
+static int readLineFromOFI(rpmSpec spec, OFI_t *ofi)
 {
-#ifdef DYING
-    const char *arch;
-    const char *os;
-#endif
-    char  *s;
-    int match;
-    struct ReadLevelEntry *rl;
-    OFI_t *ofi = spec->fileStack;
-    int rc;
-
 retry:
     /* Make sure the current file is open */
-    /*@-branchstate@*/
     if (ofi->fd == NULL) {
        ofi->fd = Fopen(ofi->fileName, "r.fpio");
        if (ofi->fd == NULL || Ferror(ofi->fd)) {
            /* XXX Fstrerror */
-           rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
+           rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
                     ofi->fileName, Fstrerror(ofi->fd));
-           return RPMERR_BADSPEC;
+           return PART_ERROR;
        }
        spec->lineNum = ofi->lineNum = 0;
     }
-    /*@=branchstate@*/
 
     /* Make sure we have something in the read buffer */
     if (!(ofi->readPtr && *(ofi->readPtr))) {
-       /*@-type@*/ /* FIX: cast? */
-       FILE * f = fdGetFp(ofi->fd);
-       /*@=type@*/
+       FILE * f = fdGetFILE(ofi->fd);
        if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
            /* EOF */
            if (spec->readStack->next) {
-               rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
-               return RPMERR_UNMATCHEDIF;
+               rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
+               return PART_ERROR;
            }
 
            /* remove this file from the stack */
@@ -257,86 +258,101 @@ retry:
            sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
        }
     }
-    
-#ifdef DYING
-    arch = NULL;
-    rpmGetArchInfo(&arch, NULL);
-    os = NULL;
-    rpmGetOsInfo(&os, NULL);
-#endif
+    return 0;
+}
+
+int readLine(rpmSpec spec, int strip)
+{
+    char  *s;
+    int match;
+    struct ReadLevelEntry *rl;
+    OFI_t *ofi = spec->fileStack;
+    int rc;
+
+    if (!restoreFirstChar(spec)) {
+    retry:
+       if ((rc = readLineFromOFI(spec, ofi)) != 0)
+           return rc;
+
+       /* Copy next file line into the spec line buffer */
+       rc = copyNextLineFromOFI(spec, ofi);
+       if (rc > 0) {
+           goto retry;
+       } else if (rc < 0) {
+           return PART_ERROR;
+       }
+    }
 
-    /* Copy next file line into the spec line buffer */
-    if ((rc = copyNextLine(spec, ofi, strip)) != 0)
-       return rc;
+    copyNextLineFinish(spec, strip);
 
     s = spec->line;
     SKIPSPACE(s);
 
     match = -1;
-    if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
+    if (!spec->readStack->reading && rstreqn("%if", s, sizeof("%if")-1)) {
        match = 0;
-    } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
-       const char *arch = rpmExpand("%{_target_cpu}", NULL);
+    } else if (rstreqn("%ifarch", s, sizeof("%ifarch")-1)) {
+       char *arch = rpmExpand("%{_target_cpu}", NULL);
        s += 7;
        match = matchTok(arch, s);
        arch = _free(arch);
-    } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
-       const char *arch = rpmExpand("%{_target_cpu}", NULL);
+    } else if (rstreqn("%ifnarch", s, sizeof("%ifnarch")-1)) {
+       char *arch = rpmExpand("%{_target_cpu}", NULL);
        s += 8;
        match = !matchTok(arch, s);
        arch = _free(arch);
-    } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
-       const char *os = rpmExpand("%{_target_os}", NULL);
+    } else if (rstreqn("%ifos", s, sizeof("%ifos")-1)) {
+       char *os = rpmExpand("%{_target_os}", NULL);
        s += 5;
        match = matchTok(os, s);
        os = _free(os);
-    } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
-       const char *os = rpmExpand("%{_target_os}", NULL);
+    } else if (rstreqn("%ifnos", s, sizeof("%ifnos")-1)) {
+       char *os = rpmExpand("%{_target_os}", NULL);
        s += 6;
        match = !matchTok(os, s);
        os = _free(os);
-    } else if (! strncmp("%if", s, sizeof("%if")-1)) {
+    } else if (rstreqn("%if", s, sizeof("%if")-1)) {
        s += 3;
         match = parseExpressionBoolean(spec, s);
        if (match < 0) {
-           rpmError(RPMERR_UNMATCHEDIF,
+           rpmlog(RPMLOG_ERR,
                        _("%s:%d: parseExpressionBoolean returns %d\n"),
                        ofi->fileName, ofi->lineNum, match);
-           return RPMERR_BADSPEC;
+           return PART_ERROR;
        }
-    } else if (! strncmp("%else", s, sizeof("%else")-1)) {
+    } else if (rstreqn("%else", s, sizeof("%else")-1)) {
        s += 5;
        if (! spec->readStack->next) {
            /* Got an else with no %if ! */
-           rpmError(RPMERR_UNMATCHEDIF,
+           rpmlog(RPMLOG_ERR,
                        _("%s:%d: Got a %%else with no %%if\n"),
                        ofi->fileName, ofi->lineNum);
-           return RPMERR_UNMATCHEDIF;
+           return PART_ERROR;
        }
        spec->readStack->reading =
            spec->readStack->next->reading && ! spec->readStack->reading;
        spec->line[0] = '\0';
-    } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
+    } else if (rstreqn("%endif", s, sizeof("%endif")-1)) {
        s += 6;
        if (! spec->readStack->next) {
            /* Got an end with no %if ! */
-           rpmError(RPMERR_UNMATCHEDIF,
+           rpmlog(RPMLOG_ERR,
                        _("%s:%d: Got a %%endif with no %%if\n"),
                        ofi->fileName, ofi->lineNum);
-           return RPMERR_UNMATCHEDIF;
+           return PART_ERROR;
        }
        rl = spec->readStack;
        spec->readStack = spec->readStack->next;
        free(rl);
        spec->line[0] = '\0';
-    } else if (! strncmp("%include", s, sizeof("%include")-1)) {
+    } else if (rstreqn("%include", s, sizeof("%include")-1)) {
        char *fileName, *endFileName, *p;
 
        s += 8;
        fileName = s;
-       if (! xisspace(*fileName)) {
-           rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
-           return RPMERR_BADSPEC;
+       if (! risspace(*fileName)) {
+           rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
+           return PART_ERROR;
        }
        SKIPSPACE(fileName);
        endFileName = fileName;
@@ -344,8 +360,8 @@ retry:
        p = endFileName;
        SKIPSPACE(p);
        if (*p != '\0') {
-           rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
-           return RPMERR_BADSPEC;
+           rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
+           return PART_ERROR;
        }
        *endFileName = '\0';
 
@@ -367,13 +383,11 @@ retry:
        spec->line[0] = '\0';
     }
 
-    /*@-compmempass@*/ /* FIX: spec->readStack->next should be dependent */
+    /* FIX: spec->readStack->next should be dependent */
     return 0;
-    /*@=compmempass@*/
 }
-/*@=boundswrite@*/
 
-void closeSpec(Spec spec)
+void closeSpec(rpmSpec spec)
 {
     OFI_t *ofi;
 
@@ -386,60 +400,36 @@ void closeSpec(Spec spec)
     }
 }
 
-/*@-redecl@*/
-/*@unchecked@*/
 extern int noLang;             /* XXX FIXME: pass as arg */
-/*@=redecl@*/
 
-/*@todo Skip parse recursion if os is not compatible. @*/
-/*@-boundswrite@*/
-int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
-               const char *buildRootURL, int recursing, const char *passPhrase,
-               char *cookie, int anyarch, int force)
+int parseSpec(rpmts ts, const char *specFile, const char *rootDir,
+               const char *buildRoot, int recursing, const char *passPhrase,
+               const char *cookie, int anyarch, int force)
 {
     rpmParseState parsePart = PART_PREAMBLE;
     int initialPackage = 1;
-#ifdef DYING
-    const char *saveArch;
-#endif
     Package pkg;
-    Spec spec;
+    rpmSpec spec;
     
     /* Set up a new Spec structure with no packages. */
     spec = newSpec();
 
-    /*
-     * Note: rpmGetPath should guarantee a "canonical" path. That means
-     * that the following pathologies should be weeded out:
-     *          //bin//sh
-     *          //usr//bin/
-     *          /.././../usr/../bin//./sh (XXX FIXME: dots not handled yet)
-     */
     spec->specFile = rpmGetPath(specFile, NULL);
     spec->fileStack = newOpenFileInfo();
     spec->fileStack->fileName = xstrdup(spec->specFile);
-    if (buildRootURL) {
-       const char * buildRoot;
-       (void) urlPath(buildRootURL, &buildRoot);
-       /*@-branchstate@*/
-       if (*buildRoot == '\0') buildRoot = "/";
-       /*@=branchstate@*/
-       if (!strcmp(buildRoot, "/")) {
-            rpmError(RPMERR_BADSPEC,
-                     _("BuildRoot can not be \"/\": %s\n"), buildRootURL);
-            return RPMERR_BADSPEC;
-        }
-       spec->gotBuildRootURL = 1;
-       spec->buildRootURL = xstrdup(buildRootURL);
-       addMacro(spec->macros, "buildroot", NULL, buildRoot, RMIL_SPEC);
+    /* If buildRoot not specified, use default %{buildroot} */
+    if (buildRoot) {
+       spec->buildRoot = xstrdup(buildRoot);
+    } else {
+       spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL);
     }
     addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
     spec->recursing = recursing;
     spec->anyarch = anyarch;
     spec->force = force;
 
-    if (rootURL)
-       spec->rootURL = xstrdup(rootURL);
+    if (rootDir)
+       spec->rootDir = xstrdup(rootDir);
     if (passPhrase)
        spec->passPhrase = xstrdup(passPhrase);
     if (cookie)
@@ -451,53 +441,63 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
     /* in the spec's line buffer.  Except for parsePreamble(),   */
     /* which handles the initial entry into a spec file.         */
     
-    /*@-infloops@*/    /* LCL: parsePart is modified @*/
-    while (parsePart < PART_LAST && parsePart != PART_NONE) {
+    while (parsePart != PART_NONE) {
+       int goterror = 0;
        switch (parsePart) {
+       /* XXX Trap unexpected RPMRC_FAIL returns for now */
+       case RPMRC_FAIL:
+           rpmlog(RPMLOG_ERR, "FIXME: got RPMRC_FAIL from spec parse\n");
+           abort();
+       case PART_ERROR: /* fallthrough */
+       default:
+           goterror = 1;
+           break;
        case PART_PREAMBLE:
            parsePart = parsePreamble(spec, initialPackage);
            initialPackage = 0;
-           /*@switchbreak@*/ break;
+           break;
        case PART_PREP:
            parsePart = parsePrep(spec);
-           /*@switchbreak@*/ break;
+           break;
        case PART_BUILD:
        case PART_INSTALL:
        case PART_CHECK:
        case PART_CLEAN:
            parsePart = parseBuildInstallClean(spec, parsePart);
-           /*@switchbreak@*/ break;
+           break;
        case PART_CHANGELOG:
            parsePart = parseChangelog(spec);
-           /*@switchbreak@*/ break;
+           break;
        case PART_DESCRIPTION:
            parsePart = parseDescription(spec);
-           /*@switchbreak@*/ break;
+           break;
 
        case PART_PRE:
        case PART_POST:
        case PART_PREUN:
        case PART_POSTUN:
+       case PART_PRETRANS:
+       case PART_POSTTRANS:
        case PART_VERIFYSCRIPT:
+       case PART_TRIGGERPREIN:
        case PART_TRIGGERIN:
        case PART_TRIGGERUN:
        case PART_TRIGGERPOSTUN:
            parsePart = parseScript(spec, parsePart);
-           /*@switchbreak@*/ break;
+           break;
 
        case PART_FILES:
            parsePart = parseFiles(spec);
-           /*@switchbreak@*/ break;
+           break;
 
        case PART_NONE:         /* XXX avoid gcc whining */
        case PART_LAST:
        case PART_BUILDARCHITECTURES:
-           /*@switchbreak@*/ break;
+           break;
        }
 
-       if (parsePart >= PART_LAST) {
-           spec = freeSpec(spec);
-           return parsePart;
+       if (goterror || parsePart >= PART_LAST) {
+           goto errxit;
        }
 
        if (parsePart == PART_BUILDARCHITECTURES) {
@@ -506,7 +506,6 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
 
            closeSpec(spec);
 
-           /* LCL: sizeof(spec->BASpecs[0]) -nullderef whine here */
            spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
            index = 0;
            if (spec->BANames != NULL)
@@ -514,42 +513,25 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
 
                /* Skip if not arch is not compatible. */
                if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
-                   /*@innercontinue@*/ continue;
-#ifdef DYING
-               rpmGetMachine(&saveArch, NULL);
-               saveArch = xstrdup(saveArch);
-               rpmSetMachine(spec->BANames[x], NULL);
-#else
+                   continue;
                addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
-#endif
                spec->BASpecs[index] = NULL;
-               if (parseSpec(ts, specFile, spec->rootURL, buildRootURL, 1,
+               if (parseSpec(ts, specFile, spec->rootDir, buildRoot, 1,
                                  passPhrase, cookie, anyarch, force)
                 || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
                {
                        spec->BACount = index;
-/*@-nullstate@*/
-                       spec = freeSpec(spec);
-                       return RPMERR_BADSPEC;
-/*@=nullstate@*/
+                       goto errxit;
                }
-#ifdef DYING
-               rpmSetMachine(saveArch, NULL);
-               saveArch = _free(saveArch);
-#else
                delMacro(NULL, "_target_cpu");
-#endif
                index++;
            }
 
            spec->BACount = index;
            if (! index) {
-               rpmError(RPMERR_BADSPEC,
+               rpmlog(RPMLOG_ERR,
                        _("No compatible architectures found for build\n"));
-/*@-nullstate@*/
-               spec = freeSpec(spec);
-               return RPMERR_BADSPEC;
-/*@=nullstate@*/
+               goto errxit;
            }
 
            /*
@@ -561,82 +543,60 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
             * further problem that the macro context, particularly
             * %{_target_cpu}, disagrees with the info in the header.
             */
-           /*@-branchstate@*/
            if (spec->BACount >= 1) {
-               Spec nspec = spec->BASpecs[0];
+               rpmSpec nspec = spec->BASpecs[0];
                spec->BASpecs = _free(spec->BASpecs);
                spec = freeSpec(spec);
                spec = nspec;
            }
-           /*@=branchstate@*/
 
            (void) rpmtsSetSpec(ts, spec);
            return 0;
        }
     }
-    /*@=infloops@*/    /* LCL: parsePart is modified @*/
+
+    if (spec->clean == NULL) {
+       char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL);
+       spec->clean = newStringBuf();
+       appendLineStringBuf(spec->clean, body);
+       free(body);
+    }
 
     /* Check for description in each package and add arch and os */
   {
-#ifdef DYING
-    const char *arch = NULL;
-    const char *os = NULL;
-    char *myos = NULL;
-
-    rpmGetArchInfo(&arch, NULL);
-    rpmGetOsInfo(&os, NULL);
-    /*
-     * XXX Capitalizing the 'L' is needed to insure that old
-     * XXX os-from-uname (e.g. "Linux") is compatible with the new
-     * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
-     * XXX A copy of this string is embedded in headers.
-     */
-    if (!strcmp(os, "linux")) {
-       myos = xstrdup(os);
-       *myos = 'L';
-       os = myos;
-    }
-#else
-    const char *platform = rpmExpand("%{_target_platform}", NULL);
-    const char *arch = rpmExpand("%{_target_cpu}", NULL);
-    const char *os = rpmExpand("%{_target_os}", NULL);
-#endif
+    char *platform = rpmExpand("%{_target_platform}", NULL);
+    char *arch = rpmExpand("%{_target_cpu}", NULL);
+    char *os = rpmExpand("%{_target_os}", NULL);
 
     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
        if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
-           const char * name;
-           (void) headerNVR(pkg->header, &name, NULL, NULL);
-           rpmError(RPMERR_BADSPEC, _("Package has no %%description: %s\n"),
-                       name);
-           spec = freeSpec(spec);
-           return RPMERR_BADSPEC;
+           rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
+                  headerGetString(pkg->header, RPMTAG_NAME));
+           goto errxit;
        }
 
-       (void) headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
-       (void) headerAddEntry(pkg->header, RPMTAG_ARCH,
-               RPM_STRING_TYPE, arch, 1);
-       if (!headerIsEntry(pkg->header, RPMTAG_RHNPLATFORM))
-           (void) headerAddEntry(pkg->header, RPMTAG_RHNPLATFORM,
-               RPM_STRING_TYPE, arch, 1);
-       (void) headerAddEntry(pkg->header, RPMTAG_PLATFORM,
-               RPM_STRING_TYPE, platform, 1);
+       headerPutString(pkg->header, RPMTAG_OS, os);
+       /* noarch subpackages already have arch set here, leave it alone */
+       if (!headerIsEntry(pkg->header, RPMTAG_ARCH)) {
+           headerPutString(pkg->header, RPMTAG_ARCH, arch);
+       }
+       headerPutString(pkg->header, RPMTAG_PLATFORM, platform);
 
        pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
 
     }
 
-#ifdef DYING
-    myos = _free(myos);
-#else
     platform = _free(platform);
     arch = _free(arch);
     os = _free(os);
-#endif
   }
 
     closeSpec(spec);
     (void) rpmtsSetSpec(ts, spec);
 
     return 0;
+
+errxit:
+    spec = freeSpec(spec);
+    return PART_ERROR;
 }
-/*@=boundswrite@*/