Permit file objects in python header constructor
[platform/upstream/rpm.git] / build / parseSpec.c
index 690166b..3c5349d 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "system.h"
 
-#include <rpm/rpmtag.h>
+#include <rpm/rpmtypes.h>
 #include <rpm/rpmlib.h>                /* RPM_MACHTABLE & related */
 #include <rpm/rpmbuild.h>
 #include <rpm/rpmds.h>
 #include <rpm/rpmfileutil.h>
 #include "debug.h"
 
-#define SKIPSPACE(s) { while (*(s) && xisspace(*(s))) (s)++; }
-#define SKIPNONSPACE(s) { while (*(s) && !xisspace(*(s))) (s)++; }
+#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
 
-/* XXX FIXME: strlen for these is calculated at runtime, preventing const */
-static struct PartRec {
+#define LEN_AND_STR(_tag) (sizeof(_tag)-1), (_tag)
+
+static const struct PartRec {
     int part;
     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_PRETRANS,      0, "%pretrans"},
-    { PART_POSTTRANS,     0, "%posttrans"},
-    { 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_TRIGGERPREIN,  0, "%triggerprein"},
-    { 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)
-{
-    for (; p->token != NULL; p++)
-       p->len = strlen(p->token);
-}
-
 rpmParseState isPart(const char *line)
 {
-    struct PartRec *p;
+    const struct PartRec *p;
 
-    if (partList[0].len == 0)
-       initParts(partList);
-    
     for (p = partList; p->token != NULL; p++) {
        char c;
-       if (xstrncasecmp(line, p->token, p->len))
+       if (rstrncasecmp(line, p->token, p->len))
            continue;
        c = *(line + p->len);
-       if (c == '\0' || xisspace(c))
+       if (c == '\0' || risspace(c))
            break;
     }
 
@@ -88,7 +78,7 @@ static int matchTok(const char *token, const char *line)
        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;
@@ -127,6 +117,7 @@ static int restoreFirstChar(rpmSpec spec)
     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;
@@ -138,7 +129,7 @@ static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
        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';
@@ -169,11 +160,10 @@ static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
            }
        }
        
-       /* If it doesn't, ask for one more line. We need a better
-        * error code for this. */
+       /* If it doesn't, ask for one more line. */
        if (pc || bc || nc ) {
            spec->nextline = "";
-           return RPMRC_FAIL;
+           return 1;
        }
        spec->lbufPtr = spec->lbuf;
 
@@ -182,7 +172,7 @@ static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
            expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
                rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
                        spec->lineNum, spec->lbuf);
-               return RPMRC_FAIL;
+               return -1;
        }
        spec->nextline = spec->lbuf;
     }
@@ -199,7 +189,7 @@ static void copyNextLineFinish(rpmSpec spec, int strip)
     ch = ' ';
     while (*spec->nextline && ch != '\n') {
        ch = *spec->nextline++;
-       if (!xisspace(ch))
+       if (!risspace(ch))
            last = spec->nextline;
     }
 
@@ -226,7 +216,7 @@ retry:
            /* XXX Fstrerror */
            rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
                     ofi->fileName, Fstrerror(ofi->fd));
-           return RPMRC_FAIL;
+           return PART_ERROR;
        }
        spec->lineNum = ofi->lineNum = 0;
     }
@@ -238,13 +228,13 @@ retry:
            /* EOF */
            if (spec->readStack->next) {
                rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
-               return RPMRC_FAIL;
+               return PART_ERROR;
            }
 
            /* remove this file from the stack */
            spec->fileStack = ofi->next;
            (void) Fclose(ofi->fd);
-           ofi->fileName = _constfree(ofi->fileName);
+           ofi->fileName = _free(ofi->fileName);
            ofi = _free(ofi);
 
            /* only on last file do we signal EOF to caller */
@@ -281,16 +271,16 @@ int readLine(rpmSpec spec, int strip)
 
     if (!restoreFirstChar(spec)) {
     retry:
-      if ((rc = readLineFromOFI(spec, ofi)) != 0)
-        return rc;
+       if ((rc = readLineFromOFI(spec, ofi)) != 0)
+           return rc;
 
-      /* Copy next file line into the spec line buffer */
-
-      if ((rc = copyNextLineFromOFI(spec, ofi)) != 0) {
-       if (rc == RPMRC_FAIL)
+       /* Copy next file line into the spec line buffer */
+       rc = copyNextLineFromOFI(spec, ofi);
+       if (rc > 0) {
            goto retry;
-       return rc;
-      }
+       } else if (rc < 0) {
+           return PART_ERROR;
+       }
     }
 
     copyNextLineFinish(spec, strip);
@@ -299,70 +289,70 @@ int readLine(rpmSpec spec, int strip)
     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)) {
+    } 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)) {
+    } 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)) {
+    } 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)) {
+    } 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) {
            rpmlog(RPMLOG_ERR,
                        _("%s:%d: parseExpressionBoolean returns %d\n"),
                        ofi->fileName, ofi->lineNum, match);
-           return RPMRC_FAIL;
+           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 ! */
            rpmlog(RPMLOG_ERR,
                        _("%s:%d: Got a %%else with no %%if\n"),
                        ofi->fileName, ofi->lineNum);
-           return RPMRC_FAIL;
+           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 ! */
            rpmlog(RPMLOG_ERR,
                        _("%s:%d: Got a %%endif with no %%if\n"),
                        ofi->fileName, ofi->lineNum);
-           return RPMRC_FAIL;
+           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)) {
+       if (! risspace(*fileName)) {
            rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
-           return RPMRC_FAIL;
+           return PART_ERROR;
        }
        SKIPSPACE(fileName);
        endFileName = fileName;
@@ -371,7 +361,7 @@ int readLine(rpmSpec spec, int strip)
        SKIPSPACE(p);
        if (*p != '\0') {
            rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
-           return RPMRC_FAIL;
+           return PART_ERROR;
        }
        *endFileName = '\0';
 
@@ -405,15 +395,15 @@ void closeSpec(rpmSpec spec)
        ofi = spec->fileStack;
        spec->fileStack = spec->fileStack->next;
        if (ofi->fd) (void) Fclose(ofi->fd);
-       ofi->fileName = _constfree(ofi->fileName);
+       ofi->fileName = _free(ofi->fileName);
        ofi = _free(ofi);
     }
 }
 
 extern int noLang;             /* XXX FIXME: pass as arg */
 
-int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
-               const char *buildRootURL, int recursing, const char *passPhrase,
+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;
@@ -424,36 +414,22 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
     /* 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);
-       if (*buildRoot == '\0') buildRoot = "/";
-       if (!strcmp(buildRoot, "/")) {
-            rpmlog(RPMLOG_ERR,
-                     _("BuildRoot can not be \"/\": %s\n"), buildRootURL);
-            return RPMRC_FAIL;
-        }
-       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)
@@ -465,10 +441,14 @@ 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.         */
     
-       /* LCL: parsePart is modified @*/
-    while (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;
@@ -517,8 +497,7 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
        }
 
        if (goterror || parsePart >= PART_LAST) {
-           spec = freeSpec(spec);
-           return parsePart;
+           goto errxit;
        }
 
        if (parsePart == PART_BUILDARCHITECTURES) {
@@ -527,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)
@@ -538,13 +516,12 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
                    continue;
                addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
                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;
-                       spec = freeSpec(spec);
-                       return RPMRC_FAIL;
+                       goto errxit;
                }
                delMacro(NULL, "_target_cpu");
                index++;
@@ -554,8 +531,7 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
            if (! index) {
                rpmlog(RPMLOG_ERR,
                        _("No compatible architectures found for build\n"));
-               spec = freeSpec(spec);
-               return RPMRC_FAIL;
+               goto errxit;
            }
 
            /*
@@ -578,7 +554,13 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
            return 0;
        }
     }
-       /* 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 */
   {
@@ -588,19 +570,17 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
 
     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);
            rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
-                       name);
-           spec = freeSpec(spec);
-           return RPMRC_FAIL;
+                  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);
-       (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);
 
@@ -615,4 +595,8 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
     (void) rpmtsSetSpec(ts, spec);
 
     return 0;
+
+errxit:
+    spec = freeSpec(spec);
+    return PART_ERROR;
 }