Initial revision
authorjbj <devnull@localhost>
Thu, 30 May 2002 15:03:17 +0000 (15:03 +0000)
committerjbj <devnull@localhost>
Thu, 30 May 2002 15:03:17 +0000 (15:03 +0000)
CVS patchset: 5454
CVS date: 2002/05/30 15:03:17

26 files changed:
xmlspec/Makefile [new file with mode: 0644]
xmlspec/XMLAttrs.cpp [new file with mode: 0644]
xmlspec/XMLAttrs.h [new file with mode: 0644]
xmlspec/XMLBase.h [new file with mode: 0644]
xmlspec/XMLChangelog.cpp [new file with mode: 0644]
xmlspec/XMLChangelog.h [new file with mode: 0644]
xmlspec/XMLFiles.cpp [new file with mode: 0644]
xmlspec/XMLFiles.h [new file with mode: 0644]
xmlspec/XMLMacro.cpp [new file with mode: 0644]
xmlspec/XMLMacro.h [new file with mode: 0644]
xmlspec/XMLMirror.cpp [new file with mode: 0644]
xmlspec/XMLMirror.h [new file with mode: 0644]
xmlspec/XMLPackage.cpp [new file with mode: 0644]
xmlspec/XMLPackage.h [new file with mode: 0644]
xmlspec/XMLParser.cpp [new file with mode: 0644]
xmlspec/XMLParser.h [new file with mode: 0644]
xmlspec/XMLRequires.cpp [new file with mode: 0644]
xmlspec/XMLRequires.h [new file with mode: 0644]
xmlspec/XMLScript.cpp [new file with mode: 0644]
xmlspec/XMLScript.h [new file with mode: 0644]
xmlspec/XMLSource.cpp [new file with mode: 0644]
xmlspec/XMLSource.h [new file with mode: 0644]
xmlspec/XMLSpec.cpp [new file with mode: 0644]
xmlspec/XMLSpec.h [new file with mode: 0644]
xmlspec/example.spec.xml [new file with mode: 0644]
xmlspec/xml2spec.cpp [new file with mode: 0644]

diff --git a/xmlspec/Makefile b/xmlspec/Makefile
new file mode 100644 (file)
index 0000000..0367c78
--- /dev/null
@@ -0,0 +1,37 @@
+G++       = g++
+CPPFLAGS  = -O2 -Wall#-D_DEBUG_
+PREFIX    = /usr/local
+DESTDIR   =
+LDFLAGS   =
+
+CPPSRCS = XMLAttrs.cpp XMLChangelog.cpp XMLFiles.cpp XMLMacro.cpp \
+          XMLMirror.cpp XMLParser.cpp XMLPackage.cpp XMLRequires.cpp \
+          XMLScript.cpp XMLSource.cpp XMLSpec.cpp xml2spec.cpp
+CPPOBJS = $(CPPSRCS:.cpp=.o)
+INCS    = -I. -I.. -I../build -I../lib -I../rpmio
+LIBDIR  = #-L../build/.libs
+LIBS    = -lexpat -lrpm -lrpmbuild -lrpmdb -lrpmio -lpopt
+
+all: xml2spec
+
+.SUFFIXES: .cpp .o
+
+.cpp.o:
+       $(G++) $(CPPFLAGS) $(INCS) -c $<
+
+xml2spec: $(CPPOBJS)
+       $(G++) $(CPPFLAGS) $(LDFLAGS) -o xml2spec $(CPPOBJS) $(LIBDIR) $(LIBS)
+
+test: xml2spec
+       @./xml2spec example.spec.xml example.out.spec
+
+clean: clean-xml2spec
+
+clean-xml2spec:
+       @rm -rf xml2spec *.o
+       @rm -rf example.out.spec
+       @rm -rf example.out.xml
+
+install:
+       @mkdir -p $(DESTDIR)$(PREFIX)/bin
+       @cp xml2spec $(DESTDIR)$(PREFIX)/bin
diff --git a/xmlspec/XMLAttrs.cpp b/xmlspec/XMLAttrs.cpp
new file mode 100644 (file)
index 0000000..a20b29a
--- /dev/null
@@ -0,0 +1,109 @@
+// standard C++ includes
+#include <string>
+
+// standard includes
+#include <string.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+XMLAttr::XMLAttr(const char* szName,
+                               const char* szValue)
+       : XMLBase()
+{
+       if (szName)
+               m_sName.assign(szName);
+       if (szValue)
+               m_sValue.assign(szValue);
+}
+
+XMLAttr::XMLAttr(const XMLAttr& rAttr)
+       : XMLBase()
+{
+       m_sName.assign(rAttr.m_sName);
+       m_sValue.assign(rAttr.m_sValue);
+}
+
+XMLAttr::~XMLAttr()
+{
+}
+
+XMLAttr XMLAttr::operator=(XMLAttr attr)
+{
+       m_sName.assign(attr.m_sName);
+       m_sValue.assign(attr.m_sValue);
+}
+
+XMLAttrs::XMLAttrs(const char** szAttrs)
+       : XMLBase()
+{
+       for (int i = 0; szAttrs && szAttrs[i]; i += 2) {
+               XMLAttr attr(szAttrs[i],
+                                       szAttrs[i+1]);
+               m_vAttrs.push_back(attr);
+       }
+}
+
+XMLAttrs::XMLAttrs(const XMLAttrs& rAttrs)
+       : XMLBase()
+{
+       m_vAttrs = rAttrs.m_vAttrs;
+}
+
+XMLAttrs::~XMLAttrs()
+{
+}
+
+bool XMLAttrs::validate(structValidAttrs* paValids,
+                                               XMLBase* pError)
+{
+       // nothing found at present
+       for (unsigned int i = 0; paValids[i].m_nValue != XATTR_END; i++)
+               paValids[i].m_bFound = false;
+
+       // test everything we have
+       for (unsigned int i = 0; i < num(); i++) {
+               bool bInvalid = true;
+               for (unsigned int j = 0; paValids[j].m_nValue != XATTR_END; j++) {
+                       if (strcasecmp(paValids[j].m_szName, get(i).getName()) == 0) {
+                               paValids[i].m_bFound = true;
+                               bInvalid = false;
+                               break;
+                       }
+               }
+               if (bInvalid) {
+                       char szTmp[1024];
+                       sprintf(szTmp, "Unknown attribute '%s'", get(i).getName());
+                       pError->setWarning(szTmp);
+               }
+       }
+
+       // see if we have mandator tags that are not there
+       for (unsigned int i = 0; paValids[i].m_nValue != XATTR_END; i++) {
+               if (paValids[i].m_bMandatory && !paValids[i].m_bFound) {
+                       char szTmp[1024];
+                       sprintf(szTmp, "Mandatory attribute '%s' not found",
+                                                       paValids[i].m_szName);
+                       pError->setError(szTmp);
+                       return false;
+               }
+       }
+
+       // if we got this far, everything is ok
+       return true;
+}
+
+const char* XMLAttrs::get(const char* szName)
+{
+       if (szName)
+       {
+               for (unsigned int i = 0; i < num(); i++) {
+                       if (strcasecmp(szName, get(i).getName()) == 0)
+                               return get(i).getValue();
+               }
+       }
+       return NULL;
+}
diff --git a/xmlspec/XMLAttrs.h b/xmlspec/XMLAttrs.h
new file mode 100644 (file)
index 0000000..4ae4d28
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef _H_XMLATTRS_
+#define _H_XMLATTRS_
+
+// standard C++ includes
+#include <string>
+#include <vector>
+
+// our includes
+#include "XMLBase.h"
+
+using namespace std;
+
+// definition for the end of the attributes
+#define XATTR_END  0xFFFF
+
+struct structValidAttrs
+{
+       unsigned int m_nValue;
+       bool         m_bMandatory;
+       bool         m_bFound;
+       char*        m_szName;
+};
+
+// forward class definitions
+class XMLSpec;
+
+class XMLAttr : public XMLBase
+{
+//
+// contructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName The name of the attribute
+        * @param szValue The attribute value
+        * @return none
+        **/
+       XMLAttr(const char* szName,
+                       const char* szValue);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rAttr Reference to the attribute to copy
+        * @return none
+        **/
+       XMLAttr(const XMLAttr& rAttr);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLAttr();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param attr The attribute to copy
+        * @return the assigned obkect
+        **/
+       XMLAttr operator=(XMLAttr attr);
+
+//
+// get/set functions
+//
+public:
+       /**
+        * Returns the attribute name
+        * .
+        * @param none
+        * @return string containing the attribute name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Returns the attribute value
+        * .
+        * @param none
+        * @return string containing the attribute value
+        **/
+       const char* getValue()
+       {
+               return m_sValue.c_str();
+       }
+
+//
+// member variables
+//
+public:
+       string m_sName;
+       string m_sValue;
+};
+
+class XMLAttrs : public XMLBase
+{
+//
+// constructors/destructor
+//
+public:
+       /**
+        * The default attribute constructor
+        * .
+        * @param szAttrs Pointer to an array of attributes, terminated by NULL
+        * @return none
+        **/
+       XMLAttrs(const char** szAttrs);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rAttrs The attribute object to copy
+        * @return none
+        **/
+        XMLAttrs(const XMLAttrs& rAttrs);
+
+       /**
+        * The default destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLAttrs();
+
+//
+// member functions
+//
+public:
+       /**
+        * Validates an attribute object against the valid attributes. This
+        * checks for mandatory attributes (error) as well as unexpected
+        * attributes. (warnings)
+        * .
+        * @param paValids Pointer to the array of valid attributes
+        * @param pError   The class in which we will set the errors
+        *                 and/or warnings.
+        * @return true on valid attributes, false otherwise
+        **/
+       bool validate(structValidAttrs* paValids,
+                                 XMLBase* pError);
+
+       /**
+        * Returns the value of an attribute as specified by the name
+        * .
+        * @param szName The name of the attribute whose value we are
+        *               to return
+        * @return The value or NULL if the attribute was not found
+        **/
+       const char* get(const char* szName);
+
+//
+// member variables get/set functions
+//
+public:
+       /**
+        * Gets the number of attributes contained in this object
+        * .
+        * @param none
+        * @returns The number of attributes
+        **/
+       unsigned int num()
+       {
+               return m_vAttrs.size();
+       }
+
+       /**
+        * Returns a specific attribute by number
+        * .
+        * @param nNum The number of the attribute to return
+        * @return The attribute or NULL if it doesn't exist
+        **/
+       XMLAttr& get(unsigned int nNum)
+       {
+               return m_vAttrs[nNum];
+       }
+
+//
+// protected data members
+//
+protected:
+       vector<XMLAttr> m_vAttrs;
+};
+
+#endif
diff --git a/xmlspec/XMLBase.h b/xmlspec/XMLBase.h
new file mode 100644 (file)
index 0000000..fae8f93
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef _H_XMLBASE_
+#define _H_XMLBASE_
+
+// standard C++ includes
+#include <string>
+
+// standard include
+#include <stdio.h>
+
+using namespace std;
+
+class XMLBase
+{
+//
+// constructors/destructor methods
+//
+public:
+       /**
+        * Default class constructor
+        * .
+        * param none
+        * @return none
+        **/
+       XMLBase()
+       {
+               m_bHasError = false;
+               m_bHasWarning = false;
+       }
+
+       /**
+        * Default class destructor
+        * .
+        * param none
+        * @return none
+        **/
+       ~XMLBase()
+       {
+       }
+
+//
+// member variable get and set functions
+//
+public:
+       /**
+        * Tests if the object has an error set.
+        * .
+        * @param none
+        * @return true if we have an error, false otherwise
+        **/
+       bool hasError()
+       {
+               return m_bHasError;
+       }
+
+       /**
+        * Sets the error message that can be retrieved from this
+        * object instance
+        * .
+        * @param szError The error string
+        * @return none
+        **/
+       void setError(const char* szError = NULL)
+       {
+               if (szError) {
+                       m_bHasError = true;
+                       m_sError.assign(szError);
+               }
+               else
+                       m_bHasError = false;
+       }
+
+       /**
+        * Returns the currently set error value
+        * .
+        * @param none
+        * @return pointer to the error string
+        **/
+       const char* getError()
+       {
+               m_bHasError = false;
+               return m_sError.c_str();
+       }
+
+       /**
+        * Tests if the object has a warning set.
+        * .
+        * @param none
+        * @return true if we have a warning, false otherwise
+        **/
+       bool hasWarning()
+       {
+               return m_bHasWarning;
+       }
+
+       /**
+        * Sets the warning message that can be retrieved from this
+        * object instance
+        * .
+        * @param szWarning The warning string
+        * @return none
+        **/
+       void setWarning(const char* szWarning = NULL)
+       {
+               if (szWarning) {
+                       m_bHasWarning = true;
+                       m_sWarning.assign(szWarning);
+               }
+               else
+                       m_bHasWarning = false;
+       }
+
+       /**
+        * Returns the currently set warning value
+        * .
+        * @param none
+        * @return pointer to the warning string
+        **/
+       const char* getWarning()
+       {
+               m_bHasWarning = false;
+               return m_sWarning.c_str();
+       }
+
+//
+// protected internal variables
+//
+protected:
+       bool   m_bHasError;
+       string m_sError;
+       bool   m_bHasWarning;
+       string m_sWarning;
+};
+
+#endif
diff --git a/xmlspec/XMLChangelog.cpp b/xmlspec/XMLChangelog.cpp
new file mode 100644 (file)
index 0000000..52aaf9a
--- /dev/null
@@ -0,0 +1,170 @@
+// standard C++ includes
+#include <string>
+
+// our includes
+#include "XMLChangelog.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+bool XMLChangelogEntry::parseCreate(XMLAttrs* pAttrs,
+                                                                       const char* szChange,
+                                                                       XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+
+       XMLChangelogEntry change(szChange);
+       pSpec->getChangelog().lastDate().addEntry(change);
+       return true;
+}
+
+XMLChangelogEntry::XMLChangelogEntry(const char* szChange)
+       : XMLBase()
+{
+       m_sChange.assign(szChange);
+}
+
+XMLChangelogEntry::XMLChangelogEntry(const XMLChangelogEntry& rEntry)
+       : XMLBase()
+{
+       m_sChange.assign(rEntry.m_sChange);
+}
+
+XMLChangelogEntry::~XMLChangelogEntry()
+{
+}
+
+void XMLChangelogEntry::toSpecFile(ostream& rOut)
+{
+       rOut << endl << "- " << getChange();
+}
+
+void XMLChangelogEntry::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t\t\t<change>" << getChange() << "</change>";
+}
+
+// attribute structure for XMLChangelogDate
+structValidAttrs g_paChangelogDateAttrs[] =
+{
+       {0x0000,    true,  false, "date"},
+       {0x0001,    true,  false, "author"},
+       {0x0002,    false, false, "author-email"},
+       {0x0003,    false, false, "version"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLChangelogDate::parseCreate(XMLAttrs* pAttrs,
+                                                                  XMLSpec* pSpec)
+{
+       // validate our attributes
+       if (!pAttrs->validate(g_paChangelogDateAttrs, (XMLBase*)pSpec))
+               return false;
+
+       XMLChangelogDate date(pAttrs->get("date"),
+                                                 pAttrs->get("author"),
+                                                 pAttrs->get("author-email"),
+                                                 pAttrs->get("version"));
+       pSpec->getChangelog().addDate(date);
+       return true;
+}
+
+XMLChangelogDate::XMLChangelogDate(const char* szDate,
+                                                                  const char* szAuthor,
+                                                                  const char* szEmail,
+                                                                  const char* szVersion)
+       : XMLBase()
+{
+       if (szDate)
+               m_sDate.assign(szDate);
+       if (szAuthor)
+               m_sAuthor.assign(szAuthor);
+       if (szEmail)
+               m_sEmail.assign(szEmail);
+       if (szVersion)
+               m_sVersion.assign(szVersion);
+}
+
+XMLChangelogDate::XMLChangelogDate(const XMLChangelogDate& rDate)
+       : XMLBase()
+{
+       m_sDate.assign(rDate.m_sDate);
+       m_sAuthor.assign(rDate.m_sAuthor);
+       m_sEmail.assign(rDate.m_sEmail);
+       m_sVersion.assign(rDate.m_sVersion);
+       m_vEntries = rDate.m_vEntries;
+}
+
+XMLChangelogDate::~XMLChangelogDate()
+{
+}
+
+void XMLChangelogDate::toSpecFile(ostream& rOut)
+{
+       if (numEntries()) {
+               rOut << endl << "* " << getDate() << " " << getAuthor();
+               if (hasEmail())
+                       rOut << " <" << getEmail() << ">";
+               if (hasVersion())
+                       rOut << " " << getVersion();
+               for (unsigned int i = 0; i < numEntries(); i++)
+                       getEntry(i).toSpecFile(rOut);
+               rOut << endl;
+       }
+}
+
+void XMLChangelogDate::toXMLFile(ostream& rOut)
+{
+       if (numEntries()) {
+               rOut << endl << "\t\t<changes date=\"" << getDate() << "\"";
+               rOut << endl << "\t\t         author=\"" << getAuthor() << "\"";
+               if (hasEmail())
+                       rOut << endl << "\t\t         author-email=\"" << getEmail() << "\"";
+               if (hasVersion())
+                       rOut << endl << "\t\t         version=\"" << getVersion() << "\"";
+               rOut << ">";
+               for (unsigned int i = 0; i < numEntries(); i++)
+                       getEntry(i).toXMLFile(rOut);
+               rOut << endl << "\t\t</changes>";
+       }
+}
+
+XMLChangelog::XMLChangelog()
+       : XMLBase()
+{
+}
+
+XMLChangelog::XMLChangelog(const XMLChangelog& rChangelog)
+       : XMLBase()
+{
+       m_vDates = rChangelog.m_vDates;
+}
+
+XMLChangelog::~XMLChangelog()
+{
+}
+
+void XMLChangelog::toSpecFile(ostream& rOut)
+{
+       if (numDates()) {
+               rOut << endl << "%changelog";
+               for (unsigned int i = 0; i < numDates(); i++)
+                       getDate(i).toSpecFile(rOut);
+               rOut << endl;
+       }
+}
+
+void XMLChangelog::toXMLFile(ostream& rOut)
+{
+       if (numDates()) {
+               rOut << endl << "\t<changelog>";
+               for (unsigned int i = 0; i < numDates(); i++)
+                       getDate(i).toXMLFile(rOut);
+               rOut << endl << "\t<changelog>";
+       }
+}
+
+void XMLChangelog::toRPMStruct(Spec spec)
+{
+}
diff --git a/xmlspec/XMLChangelog.h b/xmlspec/XMLChangelog.h
new file mode 100644 (file)
index 0000000..959936d
--- /dev/null
@@ -0,0 +1,420 @@
+#ifndef _H_XMLCHANGELOG_
+#define _H_XMLCHANGELOG_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+
+// rpm includes
+#include <rpmbuild.h>
+
+// forward class definitions
+class XMLSpec;
+class XMLChangelog;
+
+using namespace std;
+
+class XMLChangelogEntry : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Adds a changelog entry
+        * .
+        * @param pAttrs  The XML attributes
+        * @param szEntry The entry to create
+        * @param pSpec   Pointer to our spec
+        * @return true on success, false othersise
+        */
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       const char* szEntry,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default contructor
+        * .
+        * @param szChange The change entry
+        * @return none
+        **/
+        XMLChangelogEntry(const char* szChange);
+
+        /**
+         * Copy constructor
+         * .
+         * @param rEntry Reference to the entry to copy
+         * @return none
+         **/
+         XMLChangelogEntry(const XMLChangelogEntry& rEntry);
+
+        /**
+         * Destructor
+         * .
+         * @param none
+         * @return none
+         **/
+         ~XMLChangelogEntry();
+
+//
+// member functions
+//
+public:
+       /**
+        * Outputs the object into a spec file
+        * .
+        * @param rOut Reference to our output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Outputs the object into an XML spec file
+        * .
+        * @param rOut Reference to our output stream
+        * @return none
+        **/
+        void toXMLFile(ostream& rOut);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Returns the enrty
+        * .
+        * @param none
+        * @return string containing the entry
+        **/
+        const char* getChange()
+        {
+               return m_sChange.c_str();
+        }
+
+//
+// member variables
+//
+public:
+       string m_sChange;
+};
+
+class XMLChangelogDate : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Creates a XMLChangelogDate object
+        * .
+        * @param pAttrs The XML attributes
+        * @param pSpec The spec to add this object to
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default contructor
+        * .
+        * @param szDate The date
+        * @param szAuthor The author
+        * @param szEmail The author's email
+        * @param szVersion The version in which this change was made
+        * @return none
+        **/
+       XMLChangelogDate(const char* szDate,
+                                        const char* szAuthor,
+                                        const char* szEmail,
+                                        const char* szVersion);
+
+       /**
+        * Copy contructor
+        * .
+        * @param rDate Reference to the date object to copy
+        * @return none
+        **/
+       XMLChangelogDate(const XMLChangelogDate& rDate);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLChangelogDate();
+
+//
+// public member functions
+//
+public:
+       /**
+        * Outputs the object into a spec file
+        * .
+        * @param rOut Reference to our output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Outputs the object into an XML spec file
+        * .
+        * @param rOut Reference to our output stream
+        * @return none
+        **/
+        void toXMLFile(ostream& rOut);
+
+//
+// member variables get/set functions
+//
+public:
+       /**
+        * Returns the date for the group of entries
+        * .
+        * @param none
+        * @return string representation of the date
+        **/
+       const char* getDate()
+       {
+               return m_sDate.c_str();
+       }
+
+       /**
+        * Checks for an author
+        * .
+        * @param none
+        * @return true if we have an author, false otherwise
+        **/
+       bool hasAuthor()
+       {
+               return m_sAuthor.length() ? true : false;
+       }
+
+       /**
+        * Returns the author's name
+        * .
+        * @param none
+        * @return string containing the author's name
+        **/
+       const char* getAuthor()
+       {
+               return m_sAuthor.c_str();
+       }
+
+       /**
+        * Checks if we have an email address for the author
+        * .
+        * @param none
+        * @return true if we hava an email, false otherwise
+        **/
+       bool hasEmail()
+       {
+               return m_sEmail.length() ? true : false;
+       }
+
+       /**
+        * Returns the author's email addresse
+        * .
+        * @param none
+        * @return a string containing the author's email address
+        **/
+       const char* getEmail()
+       {
+               return m_sEmail.c_str();
+       }
+
+       /**
+        * Checks if we have a change version
+        * .
+        * @param none
+        * @return true if we have a version, false otherwise
+        **/
+       bool hasVersion()
+       {
+               return m_sVersion.length() ? true : false;
+       }
+
+       /**
+        * Gets the change version
+        * .
+        * @param none
+        * @return string containing the version
+        **/
+       const char* getVersion()
+       {
+               return m_sVersion.c_str();
+       }
+
+       /**
+        * Returns the number of entries for this date
+        * .
+        * @param none
+        * @return the number of entries
+        **/
+       unsigned int numEntries()
+       {
+               return m_vEntries.size();
+       }
+
+       /**
+        * Returns a specific entry
+        * .
+        * @param nNum The number of the entry to return
+        * @return the enrty
+        **/
+       XMLChangelogEntry& getEntry(unsigned int nNum)
+       {
+               return m_vEntries[nNum];
+       }
+
+       /**
+        * Adds an entry for this date
+        * .
+        * @param szEntry The entry to add
+        * @return none
+        **/
+       void addEntry(XMLChangelogEntry& rEntry)
+       {
+               m_vEntries.push_back(rEntry);
+       }
+
+//
+// member variables
+//
+protected:
+       string                    m_sDate;
+       string                    m_sAuthor;
+       string                    m_sEmail;
+       string                    m_sVersion;
+       vector<XMLChangelogEntry> m_vEntries;
+};
+
+class XMLChangelog : public XMLBase
+{
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param none
+        * @return none
+        **/
+       XMLChangelog();
+
+       /**
+        * Copy constructor
+        * .
+        * @param rChangelog The object to copy
+        * @return none
+        **/
+       XMLChangelog(const XMLChangelog& rChangelog);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLChangelog();
+
+//
+// public member functions
+//
+public:
+       /**
+        * Converts the object into a spec file
+        * .
+        * @param rOut Reference to the output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an xML spec
+        * .
+        * @param rOut Reference to the output stream
+        * @return none
+        **/
+        void toXMLFile(ostream& rOut);
+
+        /**
+         * Converts the object into an RPM structure
+         * .
+         * @param spec RPM structure
+         * @return none
+         **/
+         void toRPMStruct(Spec spec);
+//
+// variable get/set functions
+//
+public:
+       /**
+        * Adds a date to the changelog
+        * .
+        * @param rDate The date to add
+        * @return none
+        **/
+       void addDate(XMLChangelogDate& rDate)
+       {
+               m_vDates.push_back(rDate);
+       }
+
+       /**
+        * Returns the number of dates in the changelog
+        * .
+        * @param none
+        * @return the number of dates
+        **/
+       unsigned int numDates()
+       {
+               return m_vDates.size();
+       }
+
+       /**
+        * Gets a specific date
+        * .
+        * @param nNum The entry number
+        * @return The requated date
+        **/
+       XMLChangelogDate& getDate(unsigned int nNum)
+       {
+               return m_vDates[nNum];
+       }
+
+       /**
+        * Gets the last date we have added
+        * .
+        * @param none
+        * @return the last date
+        **/
+       XMLChangelogDate& lastDate()
+       {
+               return m_vDates[numDates()-1];
+       }
+
+//
+// member variables
+//
+protected:
+       vector<XMLChangelogDate> m_vDates;
+};
+
+#endif
diff --git a/xmlspec/XMLFiles.cpp b/xmlspec/XMLFiles.cpp
new file mode 100644 (file)
index 0000000..f4da05a
--- /dev/null
@@ -0,0 +1,179 @@
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLFiles.h"
+#include "XMLPackage.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+// attribute structure for XMLFile
+structValidAttrs g_paFileAttrs[] =
+{
+       {0x0000,    false, false, "attr"},
+       {0x0001,    false, false, "gid"},
+       {0x0002,    false, false, "uid"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLFile::parseCreate(XMLAttrs* pAttrs,
+                                                 const char* szPath,
+                                                 XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pSpec || !pAttrs->validate(g_paFileAttrs, (XMLBase*)pSpec))
+               return false;
+
+       // create and return
+       XMLFile file(pAttrs->get("attr"),
+                                pAttrs->get("uid"),
+                                pAttrs->get("gid"),
+                                szPath);
+       pSpec->lastPackage().getFiles().addFile(file);
+       return true;
+}
+
+XMLFile::XMLFile(const char* szAttr,
+                                const char* szOwner,
+                                const char* szGroup,
+                                const char* szPath)
+       : XMLBase()
+{
+       if (szAttr)
+               m_sAttr.assign(szAttr);
+       if (szOwner)
+               m_sOwner.assign(szOwner);
+       if (szGroup)
+               m_sGroup.assign(szGroup);
+       if (szPath)
+               m_sPath.assign(szPath);
+}
+
+XMLFile::XMLFile(const XMLFile& rFile)
+       : XMLBase()
+{
+       m_sAttr.assign(rFile.m_sAttr);
+       m_sOwner.assign(rFile.m_sOwner);
+       m_sGroup.assign(rFile.m_sGroup);
+       m_sPath.assign(rFile.m_sPath);
+}
+
+XMLFile::~XMLFile()
+{
+}
+
+XMLFile XMLFile::operator=(XMLFile file)
+{
+       m_sAttr.assign(file.m_sAttr);
+       m_sOwner.assign(file.m_sOwner);
+       m_sGroup.assign(file.m_sGroup);
+       m_sPath.assign(file.m_sPath);
+}
+
+void XMLFile::toSpecFile(ostream& rOut)
+{
+       if (hasAttr() || hasOwner() || hasGroup()) {
+               rOut << "%attr(";
+               rOut << (hasAttr() ? getAttr() : "-");
+               rOut << "," << (hasOwner() ? getOwner() : "-");
+               rOut << "," << (hasGroup() ? getGroup() : "-");
+               rOut << ") ";
+       }
+       rOut << getPath() << endl;
+}
+
+void XMLFile::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t\t\t<file";
+       if (hasAttr())
+               rOut << " attr=\"" << getAttr() << "\"";
+       if (hasOwner())
+               rOut << " uid=\"" << getOwner() << "\"";
+       if (hasGroup())
+               rOut << " gid=\"" << getAttr() << "\"";
+       rOut << ">";
+       rOut << getPath() << "</file>";
+}
+
+// attribute structure for XMLFiles
+structValidAttrs g_paFilesAttrs[] =
+{
+       {0x0000,    false, false, "attr"},
+       {0x0001,    false, false, "gid"},
+       {0x0002,    false, false, "uid"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLFiles::parseCreate(XMLAttrs* pAttrs,
+                                                  XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pSpec || !pAttrs->validate(g_paFilesAttrs, (XMLBase*)pSpec))
+               return false;
+
+       pSpec->lastPackage().getFiles().setDefAttr(pAttrs->get("attr"));
+       pSpec->lastPackage().getFiles().setDefOwner(pAttrs->get("uid"));
+       pSpec->lastPackage().getFiles().setDefGroup(pAttrs->get("gid"));
+       return true;
+}
+
+XMLFiles::XMLFiles()
+       : XMLBase()
+{
+}
+
+XMLFiles::XMLFiles(const XMLFiles& rFiles)
+       : XMLBase()
+{
+       m_sAttr.assign(rFiles.m_sAttr);
+       m_sOwner.assign(rFiles.m_sOwner);
+       m_sGroup.assign(rFiles.m_sGroup);
+       m_vFiles = rFiles.m_vFiles;
+}
+
+XMLFiles::~XMLFiles()
+{
+}
+
+XMLFiles XMLFiles::operator=(XMLFiles files)
+{
+       m_sAttr.assign(files.m_sAttr);
+       m_sOwner.assign(files.m_sOwner);
+       m_sGroup.assign(files.m_sGroup);
+       m_vFiles = files.m_vFiles;
+       return *this;
+}
+
+void XMLFiles::toSpecFile(ostream& rOut)
+{
+       if (numFiles()) {
+               if (hasDefAttr() || hasDefOwner() || hasDefGroup()) {
+                       rOut << "%defattr(";
+                       rOut << (hasDefAttr() ? getDefAttr() : "-");
+                       rOut << "," << (hasDefOwner() ? getDefOwner() : "-");
+                       rOut << "," << (hasDefGroup() ? getDefGroup() : "-");
+                       rOut << ")" << endl;
+               }
+               for (unsigned int i = 0; i < numFiles(); i++)
+                       getFile(i).toSpecFile(rOut);
+       }
+}
+
+void XMLFiles::toXMLFile(ostream& rOut)
+{
+       if (numFiles()) {
+               rOut << endl << "\t\t<files";
+               if (hasDefAttr())
+                       rOut << " attr=\"" << getDefAttr() << "\"";
+               if (hasDefOwner())
+                       rOut << " uid=\"" << getDefOwner() << "\"";
+               if (hasDefGroup())
+                       rOut << " gid=\"" << getDefGroup() << "\"";
+               rOut << ">";
+               for (unsigned int i = 0; i < numFiles(); i++)
+                       getFile(i).toXMLFile(rOut);
+               rOut << endl << "\t\t</files>";
+       }
+}
diff --git a/xmlspec/XMLFiles.h b/xmlspec/XMLFiles.h
new file mode 100644 (file)
index 0000000..7cf9444
--- /dev/null
@@ -0,0 +1,426 @@
+#ifndef _H_XMLFILES_
+#define _H_XMLFILES_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+
+// forward class definitions
+class XMLPackage;
+class XMLFiles;
+class XMLSpec;
+
+using namespace std;
+
+// <file ...>
+class XMLFile : public XMLBase
+{
+//
+// object creation static functions
+//
+public:
+       /**
+        * Creates a file object and add it to the correct XMLFiles
+        * container.
+        * .
+        * @param pAttrs The attributes in the XML tag
+        * @param szPath The file path
+        * @param pSpec The spec to which these files belong
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       const char* szPath,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default contructor
+        * .
+        * @param szAttr The file's attribute (NULL if default)
+        * @param szOwner The file's owner (NULL if default)
+        * @param szGroup The file's group (NULL if default)
+        * @param szPath The file path
+        * @return none
+        **/
+       XMLFile(const char* szAttr,
+                       const char* szOwner,
+                       const char* szGroup,
+                       const char* szPath);
+
+       /**
+        * Copy constructire
+        * .
+        * @param rFile Reference to the object to copy
+        * @return none
+        **/
+        XMLFile(const XMLFile& rFile);
+
+       /**
+        * Default destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLFile();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param file The file that we wish to copy
+        * @return a copy of the original
+        **/
+       XMLFile operator=(XMLFile file);
+
+//
+// member functions
+//
+public:
+       /**
+        * Outputs the obkect to an RPM spec file
+        * .
+        * @param rOut Reference to the output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Outputs the object to an XML spec file
+        * .
+        * @param rOut Reference to the output stream
+        * @return none
+        **/
+        void toXMLFile(ostream& rOut);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Returns the file path
+        * .
+        * @param none
+        * @return string containing the path
+        **/
+       const char* getPath()
+       {
+               return m_sPath.c_str();
+       }
+
+       /**
+        * Checks for a file attribute
+        * .
+        * @param none
+        * @return true if we have one, false otherwise
+        **/
+       bool hasAttr()
+       {
+               return m_sAttr.length() ? true : false;
+       }
+
+       /**
+        * Returns the file attribute
+        * .
+        * @param none
+        * @return the sttribute string
+        **/
+       const char* getAttr()
+       {
+               return m_sAttr.c_str();
+       }
+
+       /**
+        * Checks if we have a file owner
+        * .
+        * @param none
+        * @return true if we have an owner, false otherwise
+        **/
+       bool hasOwner()
+       {
+               return m_sOwner.length() ? true : false;
+       }
+
+       /**
+        * Returns the file owner
+        * .
+        * @param no0ne
+        * @return the owner as a string
+        **/
+       const char* getOwner()
+       {
+               return m_sOwner.c_str();
+       }
+
+       /**
+        * Checks for a file group
+        * .
+        * @param none
+        * @return true if we have a group, false otherwise
+        **/
+       bool hasGroup()
+       {
+               return m_sGroup.length() ? true : false;
+       }
+
+       /**
+        * Returns the file group
+        * .
+        * @param none
+        * @return string containing the group
+        **/
+       const char* getGroup()
+       {
+               return m_sGroup.c_str();
+       }
+
+//
+// member variables
+//
+protected:
+       string    m_sPath;
+       string    m_sAttr;
+       string    m_sOwner;
+       string    m_sGroup;
+};
+
+// <files ...>
+class XMLFiles : public XMLBase
+{
+//
+// object creation static functions
+//
+public:
+       /**
+        * Creates an object as parsed from an XML spec
+        * .
+        * @param pAttrs XML atrtributes to use
+        * @param pSpec The spec to which we are adding this object to
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param none
+        * @return none
+        **/
+       XMLFiles();
+
+       /**
+        * Copy constructor
+        * .
+        * @param rFiles Reference to the object to copy
+        * @return none
+        **/
+       XMLFiles(const XMLFiles& rFiles);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLFiles();
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut);
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param files XMLFiles object to copy
+        * @return copied object
+        **/
+       XMLFiles operator=(XMLFiles files);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Adds a file to our file list
+        * .
+        * @param rFile File to add
+        * @return none
+        **/
+       void addFile(XMLFile& rFile)
+       {
+               m_vFiles.push_back(rFile);
+       }
+
+       /**
+        * Returns the number of files in our list
+        * .
+        * @param none
+        * @return none
+        **/
+       unsigned int numFiles()
+       {
+               return m_vFiles.size();
+       }
+
+       /**
+        * Returns a specific file
+        * .
+        * @param nNum Number of the file to return
+        * @return the file object
+        **/
+       XMLFile& getFile(unsigned int nNum)
+       {
+               return m_vFiles[nNum];
+       }
+
+       /**
+        * Checks for a default attribute
+        * .
+        * @param none
+        * @return true if we have a default attribute, false otherwise
+        **/
+       bool hasDefAttr()
+       {
+               return m_sAttr.length() ? true : false;
+       }
+
+       /**
+        * Sets the default attribute
+        * .
+        * @param szAttr The attribute value
+        * @return none
+        **/
+       void setDefAttr(const char* szAttr)
+       {
+               if (szAttr)
+                       m_sAttr.assign(szAttr);
+       }
+
+       /**
+        * Returns the default attribute
+        * .
+        * @param none
+        * @return string contating the attribute
+        **/
+       const char* getDefAttr()
+       {
+               return m_sAttr.c_str();
+       }
+
+       /**
+        * Check if we have a default owner
+        * .
+        * @param none
+        * @return true if we have an owner, false otherwise
+        **/
+       bool hasDefOwner()
+       {
+               return m_sOwner.length() ? true : false;
+       }
+
+       /**
+        * Sets the default owner
+        * .
+        * @param szOwner The owner
+        * @return none
+        **/
+       void setDefOwner(const char* szOwner)
+       {
+               if (szOwner)
+                       m_sOwner.assign(szOwner);
+       }
+
+       /**
+        * Returns the default owner
+        * .
+        * @param none
+        * @return the owner string
+        **/
+       const char* getDefOwner()
+       {
+               return m_sOwner.c_str();
+       }
+
+       /**
+        * Checks if we have a default group
+        * .
+        * @param none
+        * @return true if we have an owner, false otherwise
+        **/
+       bool hasDefGroup()
+       {
+               return m_sGroup.length() ? true : false;
+       }
+
+       /**
+        * Sets the default group
+        * .
+        * @param szGroup The group to set
+        * @return none
+        **/
+       void setDefGroup(const char* szGroup)
+       {
+               if (szGroup)
+                       m_sGroup.assign(szGroup);
+       }
+
+       /**
+        * Gets the default group
+        * .
+        * @param none
+        * @return string representation of the group
+        **/
+       const char* getDefGroup()
+       {
+               return m_sGroup.c_str();
+       }
+
+//
+// member variables
+//
+protected:
+       string          m_sAttr;
+       string          m_sOwner;
+       string          m_sGroup;
+       vector<XMLFile> m_vFiles;
+};
+
+#endif
diff --git a/xmlspec/XMLMacro.cpp b/xmlspec/XMLMacro.cpp
new file mode 100644 (file)
index 0000000..31f0b21
--- /dev/null
@@ -0,0 +1,61 @@
+// our includes
+#include "XMLMacro.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+// attribute structure for XMLMacro
+structValidAttrs g_paMacroAttrs[] =
+{
+       {0x0000,    true,  false, "name"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLMacro::parseCreate(XMLAttrs* pAttrs,
+                                                  const char* szMacro,
+                                                  XMLSpec* pSpec)
+{
+       if (!pSpec || !szMacro || !pAttrs->validate(g_paMacroAttrs, (XMLBase*)pAttrs))
+               return false;
+       XMLMacro macro(pAttrs->get("name"), szMacro);
+       pSpec->addXMacro(macro);
+       return true;
+}
+
+XMLMacro::XMLMacro(const char* szName,
+                                  const char* szMacro)
+       : XMLBase()
+{
+       if (szName)
+               m_sName.assign(szName);
+       if (szMacro)
+               m_sValue.assign(szMacro);
+}
+
+XMLMacro::XMLMacro(const XMLMacro& rMacro)
+       : XMLBase()
+{
+       m_sName.assign(rMacro.m_sName);
+       m_sValue.assign(rMacro.m_sValue);
+}
+
+XMLMacro::~XMLMacro()
+{
+}
+
+XMLMacro XMLMacro::operator=(XMLMacro macro)
+{
+       m_sName.assign(macro.m_sName);
+       m_sValue.assign(macro.m_sValue);
+}
+
+void XMLMacro::toSpecFile(ostream& rOut)
+{
+       rOut << "%define " << getName() << " " << getValue() << endl;
+}
+
+void XMLMacro::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t<macro name=\"" << getName() << "\">";
+       rOut << getValue() << "</macro>";
+}
diff --git a/xmlspec/XMLMacro.h b/xmlspec/XMLMacro.h
new file mode 100644 (file)
index 0000000..c45fbcb
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef _H_XMLMACRO_
+#define _H_XMLMACRO_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+
+// our includes
+#include "XMLAttrs.h"
+
+// forward class definitions
+class XMLSpec;
+
+using namespace std;
+
+//<macro ...>
+class XMLMacro : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Creates an XMLMacro object
+        * .
+        * @param pAttrs XML tag attributes
+        * @param szMacro The macro contents
+        * @param pSpec the spec to add the macro to
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       const char* szMacro,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName The name of the macro
+        * @param szMacro The expanded macro
+        * @return none
+        **/
+       XMLMacro(const char* szName,
+                        const char* szMacro);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rMacro the macro to copy
+        * @return none
+        **/
+       XMLMacro(const XMLMacro& rMacro);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLMacro();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param macro The macro to copy
+        * @return our copied object
+        **/
+       XMLMacro operator=(XMLMacro macro);
+
+//
+// member functions
+//
+public:
+       /**
+        * Outputs the macro into an RPM spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Outputs the macro into an XML spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut);
+
+//
+// member get/set functions
+//
+public:
+       /**
+        * Gets the macro name
+        * .
+        * @param none
+        * @return string containing the macro name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Gets tha macro value
+        * .
+        * @param none
+        * @return string contatining the macro value
+        **/
+       const char* getValue()
+       {
+               return m_sValue.c_str();
+       }
+
+//
+// member variables
+//
+protected:
+       string m_sName;
+       string m_sValue;
+};
+
+#endif
diff --git a/xmlspec/XMLMirror.cpp b/xmlspec/XMLMirror.cpp
new file mode 100644 (file)
index 0000000..a94a4cf
--- /dev/null
@@ -0,0 +1,78 @@
+// our includes
+#include "XMLMirror.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+// attribute structure for XMLMirror
+structValidAttrs g_paMirrorAttrs[] =
+{
+       {0x0000,    true,  false, "path"},
+       {0x0001,    false, false, "description"},
+       {0x0002,    false, false, "country"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLMirror::parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec,
+                                                       bool bPatch)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paMirrorAttrs, (XMLBase*)pSpec))
+               return false;
+
+       XMLMirror mirror(pAttrs->get("path"),
+                                        pAttrs->get("description"),
+                                        pAttrs->get("country"));
+       if (bPatch && pSpec->numPatches())
+               pSpec->lastPatch().addMirror(mirror);
+       else if (!bPatch && pSpec->numSources())
+               pSpec->lastSource().addMirror(mirror);
+       return true;
+}
+
+XMLMirror::XMLMirror(const char* szPath,
+                                        const char* szDescription,
+                                        const char* szCountry) : XMLBase()
+{
+       if (szPath)
+               m_sPath.assign(szPath);
+       if (szDescription)
+               m_sDescription.assign(szDescription);
+       if (szCountry)
+               m_sCountry.assign(szCountry);
+}
+
+XMLMirror::XMLMirror(const XMLMirror& rMirror)
+       : XMLBase()
+{
+       m_sPath.assign(rMirror.m_sPath);
+       m_sDescription.assign(rMirror.m_sDescription);
+       m_sCountry.assign(rMirror.m_sCountry);
+}
+
+XMLMirror::~XMLMirror()
+{
+}
+
+XMLMirror XMLMirror::operator=(XMLMirror mirror)
+{
+       m_sPath.assign(mirror.m_sPath);
+       m_sDescription.assign(mirror.m_sDescription);
+       m_sCountry.assign(mirror.m_sCountry);
+}
+
+void XMLMirror::toSpecFile(ostream& rOut)
+{
+       rOut << endl << "# mirror: " << getPath();
+}
+
+void XMLMirror::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t\t<mirror path=\"" << getPath() << "\"";
+       if (hasDescription())
+               rOut << endl << "\t\t        description=\"" << getDescription() << "\"";
+       if (hasCountry())
+               rOut << endl << "\t\t        country=\"" << getCountry() << "\"";
+       rOut << " />";
+}
diff --git a/xmlspec/XMLMirror.h b/xmlspec/XMLMirror.h
new file mode 100644 (file)
index 0000000..96dcfef
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef _H_XMLMIRROR_
+#define _H_XMLMIRROR_
+
+// standard C++ includes
+#include <string>
+#include <vector>
+#include <iostream>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+
+// forward declaration
+class XMLSpec;
+
+using namespace std;
+
+// <mirror ...>
+class XMLMirror : public XMLBase
+{
+//
+// static object creation functions
+//
+public:
+       /**
+        * static function for creation of an XMLMirror object
+        * .
+        * @param pAttrs Pointer to our attribute structure
+        * @param pSpec Pointer to our spec that is to ultimately
+        *              contain the object
+        * @param bPatch true if we are handling the mirror for a patch
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec,
+                                                       bool bPatch = false);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor for the XMLMirror object
+        * .
+        * @param szPath        Full path for the mirror
+        * @param szDescription Full mirror description
+        * @param szCoutry      Country code for the mirror
+        * @return none
+        **/
+       XMLMirror(const char* szPath,
+                         const char* szDescription,
+                         const char* szCountry);
+
+       /**
+        * Copy contructor
+        * .
+        * @param rMirror Reference to the object to copy
+        * @return none
+        **/
+       XMLMirror(const XMLMirror& rMirror);
+
+       /**
+        * Destructor for an XMLMirror object
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLMirror();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param mirror The mirror to get the values from
+        * @return The modified object
+        **/
+       XMLMirror operator=(XMLMirror mirror);
+
+//
+// public member functions
+//
+public:
+       /**
+        * Converts an XMLMirror object to a RPM spec file
+        * .
+        * @param rOut File stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts an XMLMirror object to an XML spec file
+        * .
+        * @param rOut File stream
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Checks if we have a path
+        * .
+        * @param none
+        * @return true if we have a path, false otherise
+        **/
+       bool hasPath()
+       {
+               return m_sPath.length() ? true : false;
+       }
+
+       /**
+        * Returns the path
+        * .
+        * @param none
+        * @return The path strinbg
+        **/
+       const char* getPath()
+       {
+               return m_sPath.c_str();
+       }
+
+       /**
+        * Checks if we have a description set
+        * .
+        * @param none
+        * @return true is we have a description, false otherwise
+        **/
+       bool hasDescription()
+       {
+               return m_sDescription.length() ? true : false;
+       }
+
+       /**
+        * Returns the description
+        * .
+        * @param none
+        * @return the description string
+        **/
+       const char* getDescription()
+       {
+               return m_sDescription.c_str();
+       }
+
+       /**
+        * Checks if we have a country set
+        * .
+        * @param none
+        * @return true if we have a country, false otherwise
+        **/
+       bool hasCountry()
+       {
+               return m_sCountry.length() ? true : false;
+       }
+
+       /**
+        * Gets the country
+        * .
+        * @param none
+        * @return The country string
+        **/
+       const char* getCountry()
+       {
+               return m_sCountry.c_str();
+       }
+
+//
+// member variables
+//
+protected:
+       string     m_sPath;
+       string     m_sDescription;
+       string     m_sCountry;
+};
+
+#endif
diff --git a/xmlspec/XMLPackage.cpp b/xmlspec/XMLPackage.cpp
new file mode 100644 (file)
index 0000000..39a81c6
--- /dev/null
@@ -0,0 +1,233 @@
+// standard C++ includes
+#include <string>
+
+// our includes
+#include "XMLPackage.h"
+#include "XMLSpec.h"
+
+// attribute structure for XMLPackage
+structValidAttrs g_paPackageAttrs[] =
+{
+       {0x0000,    false, false, "name"},
+       {0x0001,    false, false, "group"},
+       {0x0002,    false, false, "sub"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLPackage::parseCreate(XMLAttrs* pAttrs,
+                                                        XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paPackageAttrs, (XMLBase*)pSpec))
+               return false;
+
+       // setup the name attribute
+       string sName;
+       if (pAttrs->get("name"))
+               sName.assign(pAttrs->get("name"));
+
+       // is this something else but a sub-package
+       bool bSub = true;
+       if (pAttrs->get("sub"))
+               if (strcasecmp(pAttrs->get("sub"), "no") == 0)
+                       bSub = false;
+
+       // if we have a name, cool, now test if the package already exists
+       if (sName.length()) {
+               XMLPackage package(sName.c_str(),
+                                                  pAttrs->get("group"),
+                                                  bSub);
+               pSpec->addPackage(package);
+       }
+
+       // already something existing with %{name} ?
+       else {
+               XMLPackage package(NULL,
+                                                  pAttrs->get("group"),
+                                                  bSub);
+               pSpec->addPackage(package);
+       }
+       return true;
+}
+
+bool XMLPackage::setDescription(const char* szDescription,
+                                                               XMLSpec* pSpec)
+{
+       if (pSpec) {
+               pSpec->lastPackage().setDescription(szDescription);
+               return true;
+       }
+       else
+               return false;
+}
+
+bool XMLPackage::setSummary(const char* szSummary,
+                                                       XMLSpec* pSpec)
+{
+       if (pSpec) {
+               pSpec->lastPackage().setSummary(szSummary);
+               return true;
+       }
+       else
+               return false;
+}
+
+XMLPackage::XMLPackage(const char* szName,
+                                          const char* szGroup,
+                                          bool bSub)
+       : XMLBase()
+{
+       if (szName)
+               m_sName.assign(szName);
+       if (szGroup)
+               m_sGroup.assign(szGroup);
+       m_bSub = bSub;
+}
+
+XMLPackage::XMLPackage(const XMLPackage& rPackage)
+       : XMLBase()
+{
+       m_sName.assign(rPackage.m_sName);
+       m_sGroup.assign(rPackage.m_sGroup);
+       m_sSummary.assign(rPackage.m_sSummary);
+       m_sDescription.assign(rPackage.m_sDescription);
+       m_bSub = rPackage.m_bSub;
+       m_Requires = rPackage.m_Requires;
+       m_BuildRequires = rPackage.m_BuildRequires;
+       m_Provides = rPackage.m_Provides;
+       m_Obsoletes = rPackage.m_Obsoletes;
+       m_Post = rPackage.m_Post;
+       m_PostUn = rPackage.m_PostUn;
+       m_Pre = rPackage.m_Pre;
+       m_PreUn = rPackage.m_PreUn;
+       m_Verify = rPackage.m_Verify;
+       m_Files = rPackage.m_Files;
+}
+
+XMLPackage::~XMLPackage()
+{
+}
+
+void XMLPackage::toSpecFile(ostream& rOut)
+{
+       // top package bit
+       if (hasName()) {
+               rOut << endl << "%package";
+               rOut << (!isSubPackage() ? " -n " : " ") << getName() << endl;
+       }
+       else
+               rOut << endl << endl;
+
+       // add the summary
+       if (hasSummary())
+               rOut << "summary:        " << getSummary() << endl;
+
+       // do we have a group?
+       if (hasGroup())
+               rOut << "group:          " << getGroup() << endl;
+
+       getProvides().toSpecFile(rOut, "provides");
+       getObsoletes().toSpecFile(rOut, "obsoletes");
+       getRequires().toSpecFile(rOut, "requires");
+       getBuildRequires().toSpecFile(rOut, "buildrequires");
+
+       // add the description
+       if (hasDescription()) {
+               rOut << "%description ";
+               if (hasName()) {
+                       rOut << (!isSubPackage() ? "-n " : "");
+                       rOut << getName();
+               }
+               rOut << endl << getDescription() << endl;
+       }
+}
+
+void toSectionSpecFile(ostream& rOut,
+                                          const char* szSection,
+                                          XMLPackage* pPkg)
+{
+       rOut << endl << "%" << szSection;
+       if (pPkg->hasName())
+               rOut << (!pPkg->isSubPackage() ? " -n " : " ") << pPkg->getName();
+       rOut << endl;
+}
+
+void XMLPackage::toScriptsSpecFile(ostream& rOut)
+{
+       if (getPre().numScripts()) {
+               toSectionSpecFile(rOut, "pre", this);
+               getPre().toSpecFile(rOut, "pre");
+       }
+
+       if (getPost().numScripts()) {
+               toSectionSpecFile(rOut, "post", this);
+               getPost().toSpecFile(rOut, "post");
+       }
+
+       if (getPreUn().numScripts()) {
+               toSectionSpecFile(rOut, "preun", this);
+               getPreUn().toSpecFile(rOut, "preun");
+       }
+
+       if (getPostUn().numScripts()) {
+               toSectionSpecFile(rOut, "postun", this);
+               getPostUn().toSpecFile(rOut, "postun");
+       }
+
+       if (getVerify().numScripts()) {
+               toSectionSpecFile(rOut, "verifyscript", this);
+               getVerify().toSpecFile(rOut, "verifyscript");
+       }
+}
+
+void XMLPackage::toFilesSpecFile(ostream& rOut)
+{
+       rOut << endl << "%files";
+       if (hasName())
+               rOut << (!isSubPackage() ? " -n " : " ") << getName();
+       rOut << endl;
+       getFiles().toSpecFile(rOut);
+}
+
+void XMLPackage::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t<package";
+       if (hasName()) {
+               rOut << " name=\"" << getName() << "\"";
+               if (!isSubPackage())
+                       rOut << " sub=\"no\"";
+       }
+       if (hasGroup())
+               rOut << " group=\"" << getGroup() << "\"";
+       rOut << ">";
+       if (hasSummary())
+               rOut << endl << "\t\t<summary>" << getSummary() << "\t\t</summary>";
+       if (hasDescription())
+               rOut << endl << "\t\t<description>" << getDescription() << "\t\t</description>";
+
+       getProvides().toXMLFile(rOut, "provides");
+       getObsoletes().toXMLFile(rOut, "obsoletes");
+       getRequires().toXMLFile(rOut, "requires");
+       getBuildRequires().toXMLFile(rOut, "buildrequires");
+
+       getPre().toXMLFile(rOut, "pre");
+       getPost().toXMLFile(rOut, "post");
+       getPreUn().toXMLFile(rOut, "preun");
+       getPostUn().toXMLFile(rOut, "postun");
+       getVerify().toXMLFile(rOut, "verify");
+
+       getFiles().toXMLFile(rOut);
+
+       rOut << endl << "\t</package>";
+}
+
+void XMLPackage::toRPMStruct(Spec spec)
+{
+       //Package pkg = newPackage(spec);
+       //if (!hasName() && pkg == spec->packages)
+       //      fillOutMainPackage(pkg->header);
+       //else if (pkg != spec->packages)
+       //      headerCopyTags(spec->packages->header,
+       //                                 pkg->header,
+       //                                 (int_32 *)copyTagsDuringParse);
+}
diff --git a/xmlspec/XMLPackage.h b/xmlspec/XMLPackage.h
new file mode 100644 (file)
index 0000000..a2202a4
--- /dev/null
@@ -0,0 +1,397 @@
+#ifndef _H_XMLPACKAGE_
+#define _H_XMLPACKAGE_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+#include "XMLFiles.h"
+#include "XMLRequires.h"
+#include "XMLScript.h"
+
+// rpm includes
+#include <rpmbuild.h>
+
+// forward class declarations
+class XMLSpec;
+
+using namespace std;
+
+class XMLPackage : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Creates an object as parsed from an XML spec
+        * .
+        * @param pAttrs XML atrtributes to use
+        * @param pSpec The spec to which we are adding this object to
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+       /**
+        * Sets the description for the last package
+        * .
+        * @param szDescription the description
+        * @param pSpec The spec containing the package
+        * @return true on success, false otherwise
+        **/
+       static bool setDescription(const char* szDescription,
+                                                          XMLSpec* pSpec);
+
+       /**
+        * Sets the summary for the last added package
+        * .
+        * @param szSummary The summary to set
+        * @param pSpec The spec contraining the package
+        * @return trus on success, false otherwise
+        **/
+       static bool setSummary(const char* szSummary,
+                                                  XMLSpec* pSpec);
+
+//
+// constructors/destructors
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName The package name
+        * @param szGroup The group this package belongs to
+        * @param bSub true if this is a sub-package
+        * @return none
+        **/
+       XMLPackage(const char* szName,
+                          const char* szGroup,
+                          bool bSub);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rPackage The package to copy from
+        * @return none
+        **/
+       XMLPackage(const XMLPackage& rPackage);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLPackage();
+
+//
+// public member functions
+//
+public:
+       /**
+        * Converts the object to a spec file
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the scripts part of the object to a spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toScriptsSpecFile(ostream& rOut);
+
+       /**
+        * Converts the files part of the object to a spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toFilesSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object to an XML spec
+        * .
+        * @param rOut The output stream
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut);
+
+       /**
+        * Converts the object to an RPM structure
+        * .
+        * @param Spec The main Spec object
+        * @param none
+        **/
+       void toRPMStruct(Spec spec);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Checks of we have a package name
+        * .
+        * @param none
+        * @return true if we have a name, false otherwise
+        **/
+       bool hasName()
+       {
+               return m_sName.length() ? true : false;
+       }
+
+       /**
+        * Gets the package name
+        * .
+        * @param none
+        * @return string containing the package name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Checks if we have a group
+        * .
+        * @param none
+        * @return true if we have a group, false otherwise
+        **/
+       bool hasGroup()
+       {
+               return m_sGroup.length() ? true : false;
+       }
+
+       /**
+        * Returns the group
+        * .
+        * @param none
+        * @return string containing the group
+        **/
+       const char* getGroup()
+       {
+               return m_sGroup.c_str();
+       }
+
+       /**
+        * Tests if we are a sub-package
+        * .
+        * @param none
+        * @return true if this is a sub-package
+        **/
+       bool isSubPackage()
+       {
+               return m_bSub;
+       }
+
+       /**
+        * Checks if we have a summary
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasSummary()
+       {
+               return m_sSummary.length() ? true : false;
+       }
+
+       /**
+        * Gets the summary
+        * .
+        * @param none
+        * @return the summary string
+        **/
+       const char* getSummary()
+       {
+               return m_sSummary.c_str();
+       }
+
+       /**
+        * Set the summary
+        * .
+        * @param szSummary the summary
+        * @return none
+        **/
+       void setSummary(const char* szSummary)
+       {
+               if (szSummary)
+                       m_sSummary.assign(szSummary);
+       }
+
+       /**
+        * Checks if we have a description
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasDescription()
+       {
+               return m_sDescription.length() ? true : false;
+       }
+
+       /**
+        * Get the description
+        * .
+        * @param none
+        * @return string containing the description
+        **/
+       const char* getDescription()
+       {
+               return m_sDescription.c_str();
+       }
+
+       /**
+        * Sets the description
+        * .
+        * @param szDescription The description string
+        * @return nonew
+        **/
+       void setDescription(const char* szDescription)
+       {
+               if (szDescription)
+                       m_sDescription.assign(szDescription);
+       }
+
+       /**
+        * Gets the provides
+        * .
+        * @param none
+        * @return reference to the provides
+        **/
+       XMLPackageContainer& getProvides()
+       {
+               return m_Provides;
+       }
+
+       /**
+        * Gets the package requires
+        * .
+        * @param none
+        * @return reference to the requires
+        **/
+       XMLPackageContainer& getRequires()
+       {
+               return m_Requires;
+       }
+
+       /**
+        * Get the buildrequires
+        * .
+        * @param none
+        * @return reference to the buildrequires
+        **/
+       XMLPackageContainer& getBuildRequires()
+       {
+               return m_BuildRequires;
+       }
+
+       /**
+        * Gets the obsoletes
+        * .
+        * @param none
+        * @return reference to the obsoletes
+        **/
+       XMLPackageContainer& getObsoletes()
+       {
+               return m_Obsoletes;
+       }
+
+       /**
+        * Gets the files
+        * .
+        * @param none
+        * @return reference to the files
+        **/
+       XMLFiles& getFiles()
+       {
+               return m_Files;
+       }
+
+       /**
+        * Gets the pre section
+        * .
+        * @param none
+        * @return reference to the pre section
+        **/
+       XMLPackageScripts& getPre()
+       {
+               return m_Pre;
+       }
+
+       /**
+        * Gets the post section
+        * .
+        * @param none
+        * @return reference to the post section
+        **/
+       XMLPackageScripts& getPost()
+       {
+               return m_Post;
+       }
+
+       /**
+        * Gets the preun section
+        * .
+        * @param none
+        * @return reference to the preun section
+        **/
+       XMLPackageScripts& getPreUn()
+       {
+               return m_PreUn;
+       }
+
+       /**
+        * Gets the postun section
+        * .
+        * @param none
+        * @return reference to the postun section
+        **/
+       XMLPackageScripts& getPostUn()
+       {
+               return m_PostUn;
+       }
+
+       /**
+        * Gets the verify section
+        * .
+        * @param none
+        * @return reference to the verify section
+        **/
+       XMLPackageScripts& getVerify()
+       {
+               return m_Verify;
+       }
+
+//
+// member variables
+//
+protected:
+       string              m_sName;
+       string              m_sGroup;
+       string              m_sSummary;
+       string              m_sDescription;
+       bool                m_bSub;
+       XMLPackageContainer m_Requires;
+       XMLPackageContainer m_BuildRequires;
+       XMLPackageContainer m_Provides;
+       XMLPackageContainer m_Obsoletes;
+       XMLPackageScripts   m_Pre;
+       XMLPackageScripts   m_PreUn;
+       XMLPackageScripts   m_Post;
+       XMLPackageScripts   m_PostUn;
+       XMLPackageScripts   m_Verify;
+       XMLFiles            m_Files;
+};
+
+#endif
diff --git a/xmlspec/XMLParser.cpp b/xmlspec/XMLParser.cpp
new file mode 100644 (file)
index 0000000..8045a71
--- /dev/null
@@ -0,0 +1,938 @@
+// standard library includes
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// standard C++ includes
+#include <fstream>
+#include <string>
+
+// 3rd party library includes
+#include <expat.h>
+
+// our includes
+#include "XMLSpec.h"
+
+// this is the maximum tree dept we will require as
+// well as the number of scructures a specific tag can
+// occur in
+#define XML_MAX_TREE_DEPTH 5
+#define XML_MAX_PRE_TAGS   10
+
+using namespace std;
+
+// these define the error values
+enum eXMLErr
+{
+       XMLERR_WARNING = 0x0000,
+       XMLERR_ERROR,
+       XMLERR_FATAL
+};
+
+// this defines the structure that we are using in the callback
+// containing all the parse-specific data we might need.
+struct structCBData
+{
+       XML_Parser*  m_pParser;
+       string       m_sFilename;
+       int          m_nWarnings;
+       int          m_nErrors;
+       int          m_nDepth;
+       unsigned int m_pnTree[XML_MAX_TREE_DEPTH];
+       string       m_sData;
+       XMLSpec*     m_pSpec;
+       XMLAttrs*    m_pAttrs;
+};
+
+// enumeration of all XML tags that are recognised
+enum enumXMLTAGValid
+{
+       XTAG_NO          = 0x0000,
+       XTAG_WRONGSTRUCT,
+       XTAG_SPEC,
+       XTAG_SOURCE,
+       XTAG_PATCH,
+       XTAG_NOSOURCE,
+       XTAG_MIRROR,
+       XTAG_PACKAGE,
+       XTAG_SUMMARY,
+       XTAG_DESC,
+       XTAG_REQS,
+       XTAG_BREQS,
+       XTAG_PROVS,
+       XTAG_OBSOLS,
+       XTAG_FILES,
+       XTAG_FILE,
+       XTAG_MACRO,
+       XTAG_PREP,
+       XTAG_SETUP,
+       XTAG_BUILD,
+       XTAG_INSTALL,
+       XTAG_CLEAN,
+       XTAG_PRE,
+       XTAG_POST,
+       XTAG_PREUN,
+       XTAG_POSTUN,
+       XTAG_VERIFY,
+       XTAG_SCRIPT,
+       XTAG_CHANGELOG,
+       XTAG_CHANGES,
+       XTAG_CHANGE,
+       XTAG_ANY         = 0xFFFF // this always needs to be the last entry
+};
+
+// this is a structure to match tags to their values
+struct structXMLMatch
+{
+       unsigned int m_nVal;
+       int          m_pnDepth[XML_MAX_TREE_DEPTH+1];
+       unsigned int m_pnFollows[XML_MAX_PRE_TAGS+1];
+       char*        m_szName;
+};
+
+// this allows for the matching of all tags
+structXMLMatch g_pMatches[] =
+{
+       {
+               XTAG_SPEC,         { 0, -1, -1},    {
+                                                                                               XTAG_ANY,
+                                                                                               XTAG_NO
+                                                                                       },
+               "spec"
+       },
+       {
+               XTAG_PACKAGE,      { 1,  3, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_REQS,
+                                                                                               XTAG_BREQS,
+                                                                                               XTAG_PROVS,
+                                                                                               XTAG_OBSOLS,
+                                                                                               XTAG_NO
+                                                                                       },
+               "package"
+       },
+       {
+               XTAG_SOURCE,       { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "source"
+       },
+       {
+               XTAG_PATCH,        { 1,  2, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_PREP,
+                                                                                               XTAG_NO
+                                                                                       },
+               "patch"
+       },
+       {
+               XTAG_NOSOURCE,     { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "nosource"
+       },
+       {
+               XTAG_MIRROR,       { 2, -1, -1},    {
+                                                                                               XTAG_SOURCE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "mirror"
+       },
+       {
+               XTAG_SUMMARY,      { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "summary"
+       },
+       {
+               XTAG_DESC,         { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "description"
+       },
+       {
+               XTAG_REQS,         { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "requires"
+       },
+       {
+               XTAG_BREQS,        { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "buildrequires"
+       },
+       {
+               XTAG_PROVS,        { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "provides"
+       },
+       {
+               XTAG_OBSOLS,       { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "obsoletes"
+       },
+       {
+               XTAG_FILES,        { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "files"
+       },
+       {
+               XTAG_FILE,         { 3, -1, -1},    {
+                                                                                               XTAG_FILES,
+                                                                                               XTAG_NO
+                                                                                       },
+               "file"
+       },
+       {
+               XTAG_MACRO,        { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "macro"
+       },
+       {
+               XTAG_PREP,         { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "prep"
+       },
+       {
+               XTAG_SETUP,        { 2, -1, -1},    {
+                                                                                               XTAG_PREP,
+                                                                                               XTAG_NO
+                                                                                       },
+               "setup"
+       },
+       {
+               XTAG_BUILD,        { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "build"
+       },
+       {
+               XTAG_INSTALL,      { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "install"
+       },
+       {
+               XTAG_CLEAN,        { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "clean"
+       },
+       {
+               XTAG_PRE,          { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "pre"
+       },
+       {
+               XTAG_POST,         { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "post"
+       },
+       {
+               XTAG_PREUN,       { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "preun"
+       },
+       {
+               XTAG_POSTUN,       { 2, -1, -1},    {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "postun"
+       },
+       {
+               XTAG_VERIFY,        { 2, -1, -1},   {
+                                                                                               XTAG_PACKAGE,
+                                                                                               XTAG_NO
+                                                                                       },
+               "verify"
+       },
+       {
+               XTAG_SCRIPT,       { 2,  3, -1},    {
+                                                                                               XTAG_PREP,
+                                                                                               XTAG_BUILD,
+                                                                                               XTAG_INSTALL,
+                                                                                               XTAG_CLEAN,
+                                                                                               XTAG_PRE,
+                                                                                               XTAG_POST,
+                                                                                               XTAG_PREUN,
+                                                                                               XTAG_POSTUN,
+                                                                                               XTAG_VERIFY,
+                                                                                               XTAG_NO
+                                                                                       },
+               "script"
+       },
+       {
+               XTAG_CHANGELOG,    { 1, -1, -1},    {
+                                                                                               XTAG_SPEC,
+                                                                                               XTAG_NO
+                                                                                       },
+               "changelog"
+       },
+       {
+               XTAG_CHANGES,      { 2, -1, -1},    {
+                                                                                               XTAG_CHANGELOG,
+                                                                                               XTAG_NO
+                                                                                       },
+               "changes"
+       },
+       {
+               XTAG_CHANGE,       { 3, -1, -1},    {
+                                                                                               XTAG_CHANGES,
+                                                                                               XTAG_NO
+                                                                                       },
+               "change"
+       },
+       // this always needs to be the last entry
+       {
+               XTAG_NO,           {-1, -1, -1},    {
+                                                                                               XTAG_NO
+                                                                                       },
+               "none"
+       }
+};
+
+const char* treeToString(unsigned int* pnTree,
+                                                int nDepth)
+{
+       // internal string storage
+       string sTree;
+
+       // build the tree to the specified depth
+       for (int i = 0; i < nDepth; i++) {
+               int j = 0;
+               while (g_pMatches[j].m_nVal != pnTree[i])
+                       j++;
+               sTree += string("<") + string(g_pMatches[j].m_szName) + string(">");
+       }
+
+       // return the tree string
+       return sTree.c_str();
+}
+
+unsigned int getTagValue(const char* szElement,
+                                                int nDepth,
+                                                unsigned int nPrev)
+{
+       // first convert the tag to a tag value
+       unsigned int nTagVal = XTAG_NO;
+
+       // loop through all matches to see if we have a valid
+       // tag here
+       int i = 0;
+       do {
+               // test if we have a match
+               if (strcasecmp(g_pMatches[i].m_szName, szElement) == 0) {
+                       // look for a match on the tree depth
+                       int j = 0;
+                       nTagVal = XTAG_WRONGSTRUCT;
+                       while (g_pMatches[i].m_pnDepth[j] != -1) {
+                               if (g_pMatches[i].m_pnDepth[j++] == nDepth) {
+                                       j = 0;
+                                       do {
+                                               if (g_pMatches[i].m_pnFollows[j] == nPrev) {
+                                                       nTagVal = g_pMatches[i].m_nVal;
+                                                       break;
+                                               }
+                                       } while (g_pMatches[i].m_pnFollows[++j] != XTAG_NO);
+                                       break;
+                               }
+                       }
+                       // break out
+                       break;
+               }
+       } while (g_pMatches[++i].m_nVal != XTAG_NO);
+
+       // return
+       return nTagVal;
+}
+
+void createError(int nErrType,
+                                structCBData* pData,
+                                const char* szFormat, ...)
+{
+       // one more error/warning
+       nErrType == XMLERR_WARNING ? pData->m_nWarnings++ : pData->m_nErrors++;
+
+       // setup internal variables
+       FILE* fOut = stderr;
+       switch (nErrType) {
+               case XMLERR_WARNING:
+                       fOut = stdout;
+                       fprintf(fOut, "%s(%d): warning: ", pData->m_sFilename.c_str(),
+                                                 XML_GetCurrentLineNumber(*(pData->m_pParser)));
+                       break;
+               case XMLERR_ERROR:
+                       fprintf(fOut, "%s(%d): error:   ", pData->m_sFilename.c_str(),
+                                                 XML_GetCurrentLineNumber(*(pData->m_pParser)));
+                       break;
+               case XMLERR_FATAL:
+                       fprintf(fOut, "%s(%d): fatal:   ", pData->m_sFilename.c_str(),
+                                                 XML_GetCurrentLineNumber(*(pData->m_pParser)));
+                       break;
+               default:
+                       return;
+       }
+
+       // create the argument list and print
+       va_list vaArgList;
+       va_start(vaArgList, szFormat);
+       vfprintf(fOut, szFormat, vaArgList);
+       fprintf(fOut, "\n");
+}
+
+void startDepth0(structCBData* pData)
+{
+       // this indicates a spec start
+       if (pData->m_pnTree[0] == XTAG_SPEC) {
+               // if we have a spec already, we are in trouble
+               if (pData->m_pSpec)
+                       createError(XMLERR_ERROR, pData, "Extra 'spec' tag found.");
+               else if (!(pData->m_pSpec = XMLSpec::parseCreate(pData->m_pAttrs,
+                                                                                                                pData->m_sFilename.c_str())))
+                       createError(XMLERR_ERROR, pData,
+                                               "Failed to parse 'spec' tag (%s).",
+                                               pData->m_pAttrs->getError());
+               else if (pData->m_pAttrs->hasWarning())
+                       createError(XMLERR_WARNING, pData, pData->m_pAttrs->getWarning());
+       }
+}
+
+void startDepth1(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // hanlde tag
+       switch (pData->m_pnTree[1]) {
+               case XTAG_PACKAGE:
+                       if (!XMLPackage::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'package' tag or package already exists (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_SOURCE:
+                       if (!XMLSource::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'source' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_PATCH:
+                       if (!XMLPatch::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'patch' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_NOSOURCE:
+                       if (!XMLNoSource::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'nosource' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_CHANGELOG:
+               case XTAG_PREP:
+               case XTAG_BUILD:
+               case XTAG_INSTALL:
+               case XTAG_CLEAN:
+               default:
+                       break;
+       }
+}
+
+void startDepth2(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // handle tag
+       switch (pData->m_pnTree[2]) {
+               case XTAG_MIRROR:
+                       switch (pData->m_pnTree[1]) {
+                               case XTAG_SOURCE:
+                                       if (!XMLMirror::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'mirror' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_PATCH:
+                                       if (!XMLMirror::parseCreate(pData->m_pAttrs, pData->m_pSpec, true))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'mirror' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                       }
+                       break;
+               case XTAG_FILES:
+                       if (!XMLFiles::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'change' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_CHANGES:
+                       if (!XMLChangelogDate::parseCreate(pData->m_pAttrs, pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'change' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_REQS:
+               case XTAG_BREQS:
+               case XTAG_PROVS:
+               case XTAG_OBSOLS:
+               default:
+                       break;
+       }
+}
+
+void startDepth3(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // handle tag
+       switch (pData->m_pnTree[3]) {
+               case XTAG_PACKAGE:
+                       switch (pData->m_pnTree[2]) {
+                               case XTAG_REQS:
+                                       if (!XMLPackageContainer::addRequire(pData->m_pAttrs,
+                                                                                                                pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'package' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_BREQS:
+                                       if (!XMLPackageContainer::addBuildRequire(pData->m_pAttrs,
+                                                                                                                         pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'package' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_PROVS:
+                                       if (!XMLPackageContainer::addProvide(pData->m_pAttrs,
+                                                                                                                pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'package' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_OBSOLS:
+                                       if (!XMLPackageContainer::addObsolete(pData->m_pAttrs,
+                                                                                                                 pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to parse 'package' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+void startElementCB(void* pCBData,
+                                       const char* szElement,
+                                       const char** szAttr)
+{
+       // get the data structure we are working with and
+       structCBData* pData = (structCBData*)pCBData;
+
+       // validate and get the tag we are working with
+       unsigned int nTag = getTagValue(szElement,
+                                                                       pData->m_nDepth,
+                                                                       pData->m_nDepth ? pData->m_pnTree[pData->m_nDepth-1] : XTAG_ANY);
+
+       if (nTag == XTAG_NO || nTag == XTAG_WRONGSTRUCT)
+               return createError(XMLERR_WARNING, pData, "Unexpected tag '%s' in structure '%s'.",
+                                                 szElement,
+                                                 treeToString(pData->m_pnTree, pData->m_nDepth++));
+       pData->m_pnTree[pData->m_nDepth] = nTag;
+       pData->m_sData.assign("");
+
+       if (pData->m_pAttrs)
+               delete pData->m_pAttrs;
+       pData->m_pAttrs = new XMLAttrs(szAttr);
+
+       switch (pData->m_nDepth++) {
+               case 0:
+                       startDepth0(pData);
+                       break;
+               case 1:
+                       startDepth1(pData);
+                       break;
+               case 2:
+                       startDepth2(pData);
+                       break;
+               case 3:
+                       startDepth3(pData);
+                       break;
+               default:
+                       break;
+       }
+}
+
+void endDepth1(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // handle tag
+       switch (pData->m_pnTree[1]) {
+               case XTAG_MACRO:
+                       if (!XMLMacro::parseCreate(pData->m_pAttrs,
+                                                                          pData->m_sData.c_str(),
+                                                                          pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to add macro entry (%s).",
+                                                       pData->m_pAttrs->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               default:
+                       break;
+       }
+}
+
+void endDepth2(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // do the tag
+       switch (pData->m_pnTree[2]) {
+               case XTAG_SUMMARY:
+                       if (!XMLPackage::setSummary(pData->m_sData.c_str(),
+                                                                               pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to add 'summary'.");
+                       break;
+               case XTAG_DESC:
+                       if (!XMLPackage::setDescription(pData->m_sData.c_str(),
+                                                                                       pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to add 'description'.");
+                       break;
+               case XTAG_SCRIPT:
+                       switch (pData->m_pnTree[1]) {
+                               case XTAG_PREP:
+                                       if (!XMLScripts::addPrepScript(pData->m_pAttrs,
+                                                                                                  pData->m_sData.c_str(),
+                                                                                                  pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to add shell entry.");
+                                       break;
+                               case XTAG_BUILD:
+                                       if (!XMLScripts::addBuildScript(pData->m_pAttrs,
+                                                                                                       pData->m_sData.c_str(),
+                                                                                                       pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to add shell entry.");
+                                       break;
+                               case XTAG_INSTALL:
+                                       if (!XMLScripts::addInstallScript(pData->m_pAttrs,
+                                                                                                         pData->m_sData.c_str(),
+                                                                                                         pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to add shell entry.");
+                                       break;
+                               case XTAG_CLEAN:
+                                       if (!XMLScripts::addCleanScript(pData->m_pAttrs,
+                                                                                                       pData->m_sData.c_str(),
+                                                                                                       pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to add shell entry.");
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+void endDepth3(structCBData* pData)
+{
+       // make sure we have a spec
+       if (!pData->m_pSpec) {
+               createError(XMLERR_ERROR, pData, "Spec has not been defined.");
+               return;
+       }
+
+       // handle tag
+       switch (pData->m_pnTree[3]) {
+               case XTAG_CHANGE:
+                       if (!XMLChangelogEntry::parseCreate(pData->m_pAttrs,
+                                                                                               pData->m_sData.c_str(),
+                                                                                               pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData,
+                                                       "Failed to add changelog entry.");
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_FILE:
+                       if (!XMLFile::parseCreate(pData->m_pAttrs,
+                                                                         pData->m_sData.c_str(),
+                                                                         pData->m_pSpec))
+                               createError(XMLERR_ERROR, pData, "Failed to parse 'file' tag (%s).",
+                                                       pData->m_pSpec->getError());
+                       else if (pData->m_pSpec->hasWarning())
+                               createError(XMLERR_WARNING, pData, pData->m_pSpec->getWarning());
+                       break;
+               case XTAG_SCRIPT:
+                       switch (pData->m_pnTree[2]) {
+                               case XTAG_PRE:
+                                       if (!XMLPackageScripts::addPreScript(pData->m_pAttrs,
+                                                                                                                pData->m_sData.c_str(),
+                                                                                                                pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'script' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_POST:
+                                       if (!XMLPackageScripts::addPostScript(pData->m_pAttrs,
+                                                                                                                 pData->m_sData.c_str(),
+                                                                                                                 pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'script' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_PREUN:
+                                       if (!XMLPackageScripts::addPreUnScript(pData->m_pAttrs,
+                                                                                                                  pData->m_sData.c_str(),
+                                                                                                                  pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'script' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_POSTUN:
+                                       if (!XMLPackageScripts::addPostUnScript(pData->m_pAttrs,
+                                                                                                                       pData->m_sData.c_str(),
+                                                                                                                       pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'script' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               case XTAG_VERIFY:
+                                       if (!XMLPackageScripts::addVerifyScript(pData->m_pAttrs,
+                                                                                                                       pData->m_sData.c_str(),
+                                                                                                                       pData->m_pSpec))
+                                               createError(XMLERR_ERROR, pData,
+                                                                       "Failed to parse 'script' tag (%s).",
+                                                                       pData->m_pSpec->getError());
+                                       else if (pData->m_pSpec->hasWarning())
+                                               createError(XMLERR_WARNING, pData,
+                                                                       pData->m_pSpec->getWarning());
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+void endElementCB(void* pCBData,
+                                const char* szElement)
+{
+       // get the data structure we are working with
+       structCBData* pData = (structCBData*)pCBData;
+       pData->m_nDepth--;
+
+       // validate and get the tag we are working with
+       unsigned int nTag = getTagValue(szElement,
+                                                                       pData->m_nDepth,
+                                                                       pData->m_nDepth ? pData->m_pnTree[pData->m_nDepth-1] : XTAG_ANY);
+       if (nTag == XTAG_NO || nTag == XTAG_WRONGSTRUCT)
+               return;
+
+       // handle the tree depth
+       switch (pData->m_nDepth) {
+               case 0:
+                       break;
+               case 1:
+                       endDepth1(pData);
+                       break;
+               case 2:
+                       endDepth2(pData);
+                       break;
+               case 3:
+                       endDepth3(pData);
+                       break;
+               default:
+                       break;
+       }
+
+       // clean up
+       pData->m_sData.assign("");
+}
+
+void characterCB(void* pCBData,
+                                const char* szStr,
+                                int nLen)
+{
+       // get the data structure we are working with
+       structCBData* pData = (structCBData*)pCBData;
+
+       // append the string to our internal data
+       if (nLen) {
+               char* szTmp = new char[nLen+1];
+               strncpy(szTmp, szStr, nLen);
+               szTmp[nLen] = '\0';
+               pData->m_sData.append(szTmp);
+               delete[] szTmp;
+       }
+}
+
+int parseXMLSpec(const char* szXMLFilename,
+                                XMLSpec*& pSpec)
+{
+       // create and setup our parser for use
+       printf("Creating XML parser instance ... ");
+       XML_Parser parser = XML_ParserCreate(NULL);
+       if (!parser) {
+               printf("Failed.\n\tERROR: Couldn't allocate memory for parser\n\n");
+               return -1;
+       }
+       else
+               printf("Ok.\n");
+       XML_SetElementHandler(parser, startElementCB, endElementCB);
+       XML_SetCharacterDataHandler(parser, characterCB);
+       structCBData stData;
+       stData.m_pParser = &parser;
+       stData.m_sFilename.assign(szXMLFilename);
+       stData.m_nWarnings = 0;
+       stData.m_nErrors = 0;
+       stData.m_nDepth = 0;
+       stData.m_pSpec = NULL;
+       stData.m_pAttrs = NULL;
+       XML_SetUserData(parser, (void*)&stData);
+
+       // open the input and output files here
+       printf("Opening input XML spec ... ");
+       ifstream fIn(szXMLFilename);
+       if (!fIn.is_open()) {
+               printf("Failed.\n\tERROR: Could not open %s\n\n", szXMLFilename);
+               return -2;
+       }
+       else
+               printf("Ok.\n");
+
+       // parse our configuration (loop through file,
+       // doing a break if needed (fatal error))
+       printf("Parsing %s: \n", szXMLFilename);
+       char szBuff[1024+1];
+       unsigned int nLength = 0;
+       while (!fIn.eof()) {
+               fIn.get(szBuff, 1024, '\0');
+               unsigned int nRead = strlen(szBuff);
+               nLength += nRead;
+               if (!XML_Parse(parser, szBuff, nRead, fIn.eof() ? 1 : 0)) {
+                       createError(XMLERR_FATAL, &stData, "XML parsing: %s",
+                                               XML_ErrorString(XML_GetErrorCode(parser)));
+                       break;
+               }
+       }
+
+       // print the end results
+       printf("\t%d bytes parsed, %d errors(s), %d warnings(s)\n",
+                       nLength, stData.m_nErrors, stData.m_nWarnings);
+       printf("Closing input XML spec ... ");
+       fIn.close();
+       printf("Ok.\n");
+
+       // clean up
+       if (stData.m_nErrors) {
+               if (stData.m_pSpec != NULL)
+                       delete stData.m_pSpec;
+               pSpec = NULL;
+       }
+       else
+               pSpec = stData.m_pSpec;
+
+       // return number of errors
+       return stData.m_nErrors;
+}
diff --git a/xmlspec/XMLParser.h b/xmlspec/XMLParser.h
new file mode 100644 (file)
index 0000000..1669537
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _H_XMLPARSER_
+#define _H_XMLPARSER_
+
+// our includes
+#include "XMLSpec.h"
+
+/**
+ * Parses an XML spec into the internal data structures as
+ * defined in the XML* classes.
+ * .
+ * @param szXMLFilename The Spec to read as parser input
+ * @param pSpec         A reference to the spec data structure we
+ *                      are to fill.
+ * @return The number of parsing/other errors (0 == success)
+ **/
+extern int parseXMLSpec(const char* szXMLFilename,
+                                               XMLSpec*& pSpec);
+
+#endif
diff --git a/xmlspec/XMLRequires.cpp b/xmlspec/XMLRequires.cpp
new file mode 100644 (file)
index 0000000..3840c8c
--- /dev/null
@@ -0,0 +1,177 @@
+// our includes
+#include "XMLAttrs.h"
+#include "XMLPackage.h"
+#include "XMLRequires.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+// attribute structure for XMLPackageEntry
+structValidAttrs g_paEntryAttrs[] =
+{
+       {0x0000,    true,  false, "name"},
+       {0x0001,    false, false, "version"},
+       {0x0002,    false, false, "cmp"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLPackageEntry::parseCreate(XMLAttrs* pAttrs,
+                                                                 XMLPackageContainer& rContainer)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paEntryAttrs, (XMLBase*)pAttrs))
+               return false;
+
+       // create and return
+       XMLPackageEntry entry(pAttrs->get("name"),
+                                                 pAttrs->get("version"),
+                                                 pAttrs->get("cmp"));
+       rContainer.addEntry(entry);
+       return true;
+}
+
+XMLPackageEntry::XMLPackageEntry(const char* szName,
+                                                                const char* szVersion,
+                                                                const char* szCmp)
+       : XMLBase()
+{
+       if (szName)
+               m_sName.assign(szName);
+       if (szVersion)
+               m_sVersion.assign(szVersion);
+       m_sCmp.assign("=");
+       if (szCmp) {
+               if (strcasecmp(szCmp, "lt") == 0)
+                       m_sCmp.assign("<");
+               else if (strcasecmp(szCmp, "le") == 0)
+                       m_sCmp.assign("<=");
+               else if (strcasecmp(szCmp, "gt") == 0)
+                       m_sCmp.assign(">");
+               else if (strcasecmp(szCmp, "ge") == 0)
+                       m_sCmp.assign(">=");
+       }
+}
+
+XMLPackageEntry::XMLPackageEntry(const XMLPackageEntry& rEntry)
+       : XMLBase()
+{
+       m_sName.assign(rEntry.m_sName);
+       m_sVersion.assign(rEntry.m_sVersion);
+       m_sCmp.assign(rEntry.m_sCmp);
+}
+
+XMLPackageEntry::~XMLPackageEntry()
+{
+}
+
+XMLPackageEntry XMLPackageEntry::operator=(XMLPackageEntry entry)
+{
+       m_sName.assign(entry.m_sName);
+       m_sVersion.assign(entry.m_sVersion);
+       m_sCmp.assign(entry.m_sCmp);
+       return *this;
+}
+
+void XMLPackageEntry::toSpecFile(ostream& rOut)
+{
+       rOut << getName();
+       if (hasVersion()) {
+               rOut << " " << getCompare() << " " << getVersion();
+       }
+}
+
+void XMLPackageEntry::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t\t\t<package name=\"" << getName() << "\"";
+       if (hasVersion()) {
+               if (m_sCmp.compare("=") == 0)
+                       rOut << " cmp=\"eq\"";
+               else if (m_sCmp.compare("<") == 0)
+                       rOut << " cmp=\"lt\"";
+               else if (m_sCmp.compare("<=") == 0)
+                       rOut << " cmp=\"le\"";
+               else if (m_sCmp.compare(">") == 0)
+                       rOut << " cmp=\"gt\"";
+               else if (m_sCmp.compare(">=") == 0)
+                       rOut << " cmp=\"ge\"";
+               rOut << " version=\"" << getVersion() << "\"";
+       }
+       rOut << " />";
+}
+
+XMLPackageContainer::XMLPackageContainer()
+       : XMLBase()
+{
+}
+
+XMLPackageContainer::XMLPackageContainer(const XMLPackageContainer& rContainer)
+       : XMLBase()
+{
+       m_vPackages = rContainer.m_vPackages;
+}
+
+XMLPackageContainer::~XMLPackageContainer()
+{
+}
+
+XMLPackageContainer XMLPackageContainer::operator=(XMLPackageContainer container)
+{
+       m_vPackages = container.m_vPackages;
+       return *this;
+}
+
+void XMLPackageContainer::toSpecFile(ostream& rOut,
+                                                                        const char* szTag)
+{
+       if (numEntries()) {
+               rOut << szTag << ": ";
+               for (unsigned int i = 0; i < numEntries(); i++) {
+                       rOut << (i ? ", " : "");
+                       getEntry(i).toSpecFile(rOut);
+               }
+               rOut << endl;
+       }
+}
+
+void XMLPackageContainer::toXMLFile(ostream& rOut,
+                                                                       const char* szTag)
+{
+       if (numEntries()) {
+               rOut << endl << "\t\t<" << szTag << ">";
+               for (unsigned int i = 0; i < numEntries(); i++)
+                       getEntry(i).toXMLFile(rOut);
+               rOut << endl << "\t\t</" << szTag << ">";
+       }
+}
+
+bool XMLPackageContainer::addRequire(XMLAttrs* pAttrs,
+                                                                        XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLPackageEntry::parseCreate(pAttrs, pSpec->lastPackage().getRequires());
+}
+
+bool XMLPackageContainer::addBuildRequire(XMLAttrs* pAttrs,
+                                                                                 XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLPackageEntry::parseCreate(pAttrs, pSpec->lastPackage().getBuildRequires());
+}
+
+bool XMLPackageContainer::addProvide(XMLAttrs* pAttrs,
+                                                                        XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLPackageEntry::parseCreate(pAttrs, pSpec->lastPackage().getProvides());
+}
+
+bool XMLPackageContainer::addObsolete(XMLAttrs* pAttrs,
+                                                                         XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLPackageEntry::parseCreate(pAttrs, pSpec->lastPackage().getObsoletes());
+}
diff --git a/xmlspec/XMLRequires.h b/xmlspec/XMLRequires.h
new file mode 100644 (file)
index 0000000..4fc9fd6
--- /dev/null
@@ -0,0 +1,315 @@
+#ifndef _H_XMLREQUIRES_
+#define _H_XMLREQUIRES_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// standard C includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+
+// forward definitions
+class XMLPackage;
+class XMLPackageContainer;
+class XMLSpec;
+
+using namespace std;
+
+//<package ...> (after requires, buildrequires, obsoletes, provides)
+class XMLPackageEntry : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Creates an object as parsed from an XML spec
+        * .
+        * @param pAttrs XML atrtributes to use
+        * @param rContainer The container to which to add the object
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLPackageContainer& rContainer);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName Name of the package
+        * @param szVersion version of the package
+        * @param szCmp the comparator (eq,lt,le,gt,ge)
+        * @return none
+        **/
+       XMLPackageEntry(const char* szName,
+                                       const char* szVersion,
+                                       const char* szCmp);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rEntry reference to the entrry to copy
+        * @return none
+        **/
+       XMLPackageEntry(const XMLPackageEntry& rEntry);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLPackageEntry();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param entry The entry to assigne to
+        * @return thye modified object
+        **/
+       XMLPackageEntry operator=(XMLPackageEntry entry);
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut output stream
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Gets the name
+        * .
+        * @param none
+        * @return string containing the name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Checks if we have a version
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasVersion()
+       {
+               return m_sVersion.length() ? true : false;
+       }
+
+       /**
+        * Gets the version
+        * .
+        * @param none
+        * @return string containing the version
+        **/
+       const char* getVersion()
+       {
+               return m_sVersion.c_str();
+       }
+
+       /**
+        * Gets the comparision string
+        * .
+        * @param none
+        * @return string with the comparator (=, <, <=, >, >=, <>)
+        **/
+        const char* getCompare()
+        {
+               return m_sCmp.c_str();
+        }
+
+//
+// member variables
+//
+protected:
+       string m_sName;
+       string m_sVersion;
+       string m_sCmp;
+};
+
+//<requires,obsoletes,buildrequires,provides ...>
+class XMLPackageContainer : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Adds a require
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpecx pointer to the spec to add to
+        * @return true on success, false otherwise
+        **/
+       static bool addRequire(XMLAttrs* pAttrs,
+                                                  XMLSpec* pSpec);
+
+       /**
+        * Adds a buildrequire
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpecx pointer to the spec to add to
+        * @return true on success, false otherwise
+        **/
+       static bool addBuildRequire(XMLAttrs* pAttrs,
+                                                               XMLSpec* pSpec);
+
+       /**
+        * Adds a provide
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpecx pointer to the spec to add to
+        * @return true on success, false otherwise
+        **/
+       static bool addProvide(XMLAttrs* pAttrs,
+                                                  XMLSpec* pSpec);
+
+       /**
+        * Adds an obsolete
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpecx pointer to the spec to add to
+        * @return true on success, false otherwise
+        **/
+       static bool addObsolete(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param none
+        * @return none
+        **/
+       XMLPackageContainer();
+
+       /**
+        * Copy constructor
+        * .
+        * @param rContainer The container to copy
+        * @return none
+        **/
+        XMLPackageContainer(const XMLPackageContainer& rContainer);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       virtual ~XMLPackageContainer();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param container The container to copy
+        * @return a copy of the object
+        **/
+       XMLPackageContainer operator=(XMLPackageContainer container);
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec
+        * .
+        * @param rOut Output stream
+        * @param szTag the tag for this object (eg. buildrequires)
+        * @return none
+        **/
+       virtual void toSpecFile(ostream& rOut,
+                                                       const char* szTag);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @para szTag the tag for this object (eg. buildrequires)
+        * @return none
+        **/
+       virtual void toXMLFile(ostream& rOut,
+                                                  const char* szTag);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Gets the number of entries
+        * .
+        * @param none
+        * @return the number of entries
+        **/
+       unsigned int numEntries()
+       {
+               return m_vPackages.size();
+       }
+
+       /**
+        * Gets a specific entry
+        * .
+        * @param nNum The number of the entry
+        * @return reference to the entry
+        **/
+       XMLPackageEntry& getEntry(unsigned int nNum)
+       {
+               return m_vPackages[nNum];
+       }
+
+       /**
+        * Adds an entry
+        * .
+        * @param rPackage the entry to add
+        * @return none
+        **/
+       void addEntry(XMLPackageEntry& rPackage)
+       {
+               m_vPackages.push_back(rPackage);
+       }
+
+//
+// member variables
+//
+protected:
+       vector<XMLPackageEntry> m_vPackages;
+};
+
+#endif
diff --git a/xmlspec/XMLScript.cpp b/xmlspec/XMLScript.cpp
new file mode 100644 (file)
index 0000000..7b808ec
--- /dev/null
@@ -0,0 +1,232 @@
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLPackage.h"
+#include "XMLScript.h"
+#include "XMLSpec.h"
+
+// attribute structure for XMLScript
+structValidAttrs g_paScriptAttrs[] =
+{
+       {0x0000,    false, false, "dir"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLScript::parseCreate(XMLAttrs* pAttrs,
+                                                       const char* szScript,
+                                                       XMLScripts& rContainer)
+{
+       if (!pAttrs->validate(g_paScriptAttrs, (XMLBase*)pAttrs))
+               return false;
+       XMLScript script(szScript, pAttrs->get("dir"));
+       rContainer.add(script);
+       return true;
+}
+
+XMLScript::XMLScript(const char* szScript,
+                                        const char* szDir)
+       : XMLBase()
+{
+       if (szScript)
+               m_sValue.assign(szScript);
+       if (szDir)
+               m_sDir.assign(szDir);
+}
+
+XMLScript::XMLScript(const XMLScript& rScript)
+       : XMLBase()
+{
+       m_sValue.assign(rScript.m_sValue);
+       m_sDir.assign(rScript.m_sDir);
+}
+
+XMLScript::~XMLScript()
+{
+}
+
+XMLScript XMLScript::operator=(XMLScript script)
+{
+       m_sValue.assign(script.m_sValue);
+       m_sDir.assign(script.m_sDir);
+}
+
+void XMLScript::toSpecFile(ostream& rOut)
+{
+       if (hasDirectory())
+               rOut << "cd " << getDirectory() << endl;
+       rOut << getValue() << endl;
+}
+
+void XMLScript::toXMLFile(ostream& rOut,
+                                                 const char* szIndent)
+{
+       rOut << endl << szIndent << "\t\t<script";
+       if (hasDirectory())
+               rOut << " dir=\"" << getDirectory() << "\"";
+       rOut << ">" << getValue() << "</script>";
+}
+
+void XMLScript::toRPMStruct(StringBuf* pSB)
+{
+       if (hasDirectory()) {
+               char szBuff[getDirectoryLen()+3+1];
+               sprintf(szBuff, "cd %s", getDirectory());
+               appendStringBuf(*pSB, szBuff);
+       }
+       appendStringBuf(*pSB, getValue());
+}
+
+bool XMLScripts::addPrepScript(XMLAttrs* pAttrs,
+                                                          const char* szScript,
+                                                          XMLSpec* pSpec)
+{
+       // no spec or already set
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->getPrep());
+}
+
+bool XMLScripts::addBuildScript(XMLAttrs* pAttrs,
+                                                               const char* szScript,
+                                                               XMLSpec* pSpec)
+{
+       // no spec or already set
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->getBuild());
+}
+
+bool XMLScripts::addInstallScript(XMLAttrs* pAttrs,
+                                                                 const char* szScript,
+                                                                 XMLSpec* pSpec)
+{
+       // no spec or already set
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->getInstall());
+}
+
+bool XMLScripts::addCleanScript(XMLAttrs* pAttrs,
+                                                               const char* szScript,
+                                                               XMLSpec* pSpec)
+{
+       // no spec or already set
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->getClean());
+}
+
+XMLScripts::XMLScripts()
+       : XMLBase()
+{
+}
+
+XMLScripts::XMLScripts(const XMLScripts& rContainer)
+       : XMLBase()
+{
+       m_vScripts = rContainer.m_vScripts;
+}
+
+XMLScripts::~XMLScripts()
+{
+}
+
+void XMLScripts::toSpecFile(ostream& rOut,
+                                                       const char* szTag)
+{
+       if (numScripts()) {
+               rOut << endl << "%" << szTag << endl;
+               for (unsigned int i = 0; i < numScripts(); i++)
+                       getScript(i).toSpecFile(rOut);
+       }
+}
+
+void XMLScripts::toXMLFile(ostream& rOut,
+                                                  const char* szTag)
+{
+       if (numScripts()) {
+               rOut << endl << "\t<" << szTag << ">";
+               for (unsigned int i = 0; i < numScripts(); i++)
+                       getScript(i).toXMLFile(rOut, "");
+               rOut << endl << "\t</" << szTag << ">";
+       }
+}
+
+bool XMLPackageScripts::addPreScript(XMLAttrs* pAttrs,
+                                                                        const char* szScript,
+                                                                        XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->lastPackage().getPre());
+}
+
+bool XMLPackageScripts::addPostScript(XMLAttrs* pAttrs,
+                                                                         const char* szScript,
+                                                                         XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->lastPackage().getPost());
+}
+
+bool XMLPackageScripts::addPreUnScript(XMLAttrs* pAttrs,
+                                                                          const char* szScript,
+                                                                          XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->lastPackage().getPreUn());
+}
+
+bool XMLPackageScripts::addPostUnScript(XMLAttrs* pAttrs,
+                                                                               const char* szScript,
+                                                                               XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->lastPackage().getPostUn());
+}
+
+bool XMLPackageScripts::addVerifyScript(XMLAttrs* pAttrs,
+                                                                               const char* szScript,
+                                                                               XMLSpec* pSpec)
+{
+       if (!pSpec)
+               return false;
+       return XMLScript::parseCreate(pAttrs, szScript, pSpec->lastPackage().getVerify());
+}
+
+XMLPackageScripts::XMLPackageScripts()
+       : XMLScripts()
+{
+}
+
+XMLPackageScripts::XMLPackageScripts(const XMLPackageScripts& rContainer)
+       : XMLScripts(rContainer)
+{
+}
+
+XMLPackageScripts::~XMLPackageScripts()
+{
+}
+
+void XMLPackageScripts::toSpecFile(ostream& rOut,
+                                                                  const char* szTag)
+{
+       // NOTE: header not done here, but by "package"
+       for (unsigned int i = 0; i < numScripts(); i++)
+               getScript(i).toSpecFile(rOut);
+}
+
+void XMLPackageScripts::toXMLFile(ostream& rOut,
+                                                                 const char* szTag)
+{
+       if (numScripts()) {
+               rOut << endl << "\t\t<" << szTag << ">";
+               for (unsigned int i = 0; i < numScripts(); i++)
+                       getScript(i).toXMLFile(rOut, "\t");
+               rOut << endl << "\t\t</" << szTag << ">";
+       }
+}
diff --git a/xmlspec/XMLScript.h b/xmlspec/XMLScript.h
new file mode 100644 (file)
index 0000000..9b6e332
--- /dev/null
@@ -0,0 +1,408 @@
+#ifndef _H_XMLSCRIPT_
+#define _H_XMLSCRIPT_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+
+// rpm includes
+#include <rpmbuild.h>
+
+// forward definitions
+class XMLPackage;
+class XMLSpec;
+class XMLScripts;
+
+using namespace std;
+
+class XMLScript : public XMLBase
+{
+//
+// factory methods
+//
+public:
+       /**
+        * Creates a script object and adds it to the container
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script value
+        * @param rContainer reference to the script container to add to
+        * @return true on success, false otherwise
+        **/
+        static bool parseCreate(XMLAttrs* pAttrs,
+                                                        const char* szScript,
+                                                        XMLScripts& rContainer);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szScript The script
+        * @param szDir Directory to execute the script in
+        * @return none
+        **/
+        XMLScript(const char* szScript,
+                          const char* szDir);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rScript Script to copy
+        * @return none
+        **/
+        XMLScript(const XMLScript& rScript);
+
+        /**
+         * Destructor
+         * .
+         * @param none
+         * @return none
+         **/
+         virtual ~XMLScript();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param script the script to copy
+        * @return the copied object
+        **/
+        XMLScript operator=(XMLScript script);
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec file
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @param szIndent Indent string
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut,
+                                  const char* szIndent = "");
+
+       /**
+        * Converts the object into an RPM structure
+        * .
+        * @param pSB Pointer to the string buffer
+        * @return none
+        **/
+       virtual void toRPMStruct(StringBuf* pSB);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Gets the script value
+        * .
+        * @param none
+        * @return string containing the script
+        **/
+        const char* getValue()
+        {
+               return m_sValue.c_str();
+        }
+
+       /**
+        * Checks if we have a direcory
+        * .
+        * @param none
+        * @return true if we have a directory, false otherwise
+        **/
+       bool hasDirectory()
+       {
+               return m_sDir.length() ? true : false;
+       }
+
+       /**
+        * Gets the directory
+        * .
+        * @param none
+        * @return string contating the directory
+        **/
+       const char* getDirectory()
+       {
+               return m_sDir.c_str();
+       }
+
+       /**
+        * Gets the length of the directory string
+        * .
+        * @param none
+        * @return length of the description string
+        **/
+        unsigned int getDirectoryLen()
+        {
+               return m_sDir.length();
+        }
+
+//
+// member variables
+//
+public:
+       string m_sValue;
+       string m_sDir;
+};
+
+//<prep,build,install,clean ...>
+class XMLScripts : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       static bool addPrepScript(XMLAttrs* pAttrs,
+                                                         const char* szScript,
+                                                         XMLSpec* pSpec);
+
+       static bool addBuildScript(XMLAttrs* pAttrs,
+                                                          const char* szScript,
+                                                          XMLSpec* pSpec);
+
+       static bool addInstallScript(XMLAttrs* pAttrs,
+                                                                const char* szScript,
+                                                                XMLSpec* pSpec);
+
+       static bool addCleanScript(XMLAttrs* pAttrs,
+                                                          const char* szScript,
+                                                          XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param none
+        * @return none
+        **/
+       XMLScripts();
+
+       /**
+        * Copy constructor
+        * .
+        * @param rContainer the object to copy
+        * @return none
+        **/
+        XMLScripts(const XMLScripts& rContainer);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       virtual ~XMLScripts();
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec file
+        * .
+        * @param rOut Output stream
+        * @param szTag The tag name
+        * @return none
+        **/
+       virtual void toSpecFile(ostream& rOut,
+                                                       const char* szTag);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @param szTag The tag name
+        * @return none
+        **/
+       void toXMLFile(ostream& rOut,
+                                  const char* szTag);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Gets the number of script entries
+        * .
+        * @param none
+        * @return the number of scripts
+        **/
+       unsigned int numScripts()
+       {
+               return m_vScripts.size();
+       }
+
+       /**
+        * Gets a specific script entry
+        * .
+        * @param nNum The entry number
+        * @return Reference to the script entry
+        **/
+       XMLScript& getScript(unsigned int nNum)
+       {
+               return m_vScripts[nNum];
+       }
+
+       /**
+        * Adds an script entry
+        * .
+        * @param szScript the script to add
+        * @return none
+        **/
+       void add(XMLScript& rScript)
+       {
+               m_vScripts.push_back(rScript);
+       }
+
+//
+// member variables
+//
+protected:
+       vector<XMLScript> m_vScripts;
+};
+
+//<post, postun, ...>
+class XMLPackageScripts : public XMLScripts
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Adds a pre script
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script to add
+        * @param pSpec The spec to which we are adding
+        * @return true on success, false otherwise
+        **/
+       static bool addPreScript(XMLAttrs* pAttrs,
+                                                        const char* szScript,
+                                                        XMLSpec* pSpec);
+
+       /**
+        * Adds a post script
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script to add
+        * @param pSpec The spec to which we are adding
+        * @return true on success, false otherwise
+        **/
+       static bool addPostScript(XMLAttrs* pAttrs,
+                                                         const char* szScript,
+                                                         XMLSpec* pSpec);
+
+       /**
+        * Adds a preun script
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script to add
+        * @param pSpec The spec to which we are adding
+        * @return true on success, false otherwise
+        **/
+       static bool addPreUnScript(XMLAttrs* pAttrs,
+                                                          const char* szScript,
+                                                          XMLSpec* pSpec);
+
+       /**
+        * Adds a postun script
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script to add
+        * @param pSpec The spec to which we are adding
+        * @return true on success, false otherwise
+        **/
+       static bool addPostUnScript(XMLAttrs* pAttrs,
+                                                               const char* szScript,
+                                                               XMLSpec* pSpec);
+
+       /**
+        * Adds a verify script
+        * .
+        * @param pAttrs The XML attributes
+        * @param szScript The script to add
+        * @param pSpec The spec to which we are adding
+        * @return true on success, false otherwise
+        **/
+       static bool addVerifyScript(XMLAttrs* pAttrs,
+                                                               const char* szScript,
+                                                               XMLSpec* pSpec);
+//
+// constructors/destructors
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param none
+        * @return none
+        **/
+       XMLPackageScripts();
+
+       /**
+        * Copy constructor
+        * .
+        * @param rScripts Reference to the object to copy
+        * @return none
+        **/
+       XMLPackageScripts(const XMLPackageScripts& rScripts);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLPackageScripts();
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec
+        * .
+        * @param rOut Output stream
+        * @param szTag The tag name
+        * @return none
+        **/
+       virtual void toSpecFile(ostream& rOut,
+                                                       const char* szTag);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @param szTag The tag name
+        * @return none
+        **/
+       virtual void toXMLFile(ostream& rOut,
+                                                  const char* szTag);
+
+};
+
+#endif
diff --git a/xmlspec/XMLSource.cpp b/xmlspec/XMLSource.cpp
new file mode 100644 (file)
index 0000000..a01e1e9
--- /dev/null
@@ -0,0 +1,362 @@
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLSource.h"
+#include "XMLSpec.h"
+
+// rpm includes
+#include <rpmspec.h>
+
+using namespace std;
+
+bool XMLSource::structCreate(Source* pSource,
+                                                        XMLSpec* pSpec)
+{
+       if (!pSpec || !pSource)
+               return false;
+
+       do {
+               // create our mirror
+               XMLMirror *pMirror = NULL;
+               if (pSource->source != pSource->fullSource) {
+                       unsigned int nLen = pSource->source-pSource->fullSource;
+                       char szPath[nLen+1];
+                       strncpy(szPath, pSource->fullSource, nLen);
+                       szPath[nLen] = '\0';
+                       pMirror = new XMLMirror(szPath, NULL, NULL);
+               }
+
+               // generate the source, nosource, patch
+               XMLSource* pXSource = NULL;
+               XMLNoSource* pXNoSource = NULL;
+               XMLPatch* pXPatch = NULL;
+               switch (pSource->flags) {
+                       case RPMBUILD_ISSOURCE:
+                       pXSource = new XMLSource(pSource->source,
+                                                                                pSource->num,
+                                                                                NULL,
+                                                                                NULL,
+                                                                                NULL);
+                               pSpec->addSource(*pXSource);
+                               if (pMirror)
+                                       pSpec->lastSource().addMirror(*pMirror);
+                               delete pXSource;
+                               break;
+                       case RPMBUILD_ISNO:
+                               pXNoSource = new XMLNoSource(pSource->source,
+                                                                                        pSource->num,
+                                                                                        NULL,
+                                                                                        NULL,
+                                                                                        NULL);
+                               pSpec->addNoSource(*pXNoSource);
+                               if (pMirror)
+                                       pSpec->lastNoSource().addMirror(*pMirror);
+                               delete pXNoSource;
+                               break;
+                       case RPMBUILD_ISPATCH:
+                               pXPatch = new XMLPatch(pSource->source,
+                                                                          pSource->num,
+                                                                          NULL,
+                                                                          NULL);
+                               pSpec->addPatch(*pXPatch);
+                               if (pMirror)
+                                       pSpec->lastPatch().addMirror(*pMirror);
+                               delete pXPatch;
+                               break;
+                       default:
+                               break;
+               }
+               if (pMirror)
+                       delete pMirror;
+       } while ((pSource = pSource->next));
+       return true;
+}
+
+// attribute structure for XMLSource
+structValidAttrs g_paSourceAttrs[] =
+{
+       {0x0000,    true,  false, "name"},
+       {0x0001,    false, false, "num"},
+       {0x0002,    false, false, "dir"},
+       {0x0003,    false, false, "size"},
+       {0x0004,    false, false, "md5"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLSource::parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paSourceAttrs, (XMLBase*)pSpec))
+               return false;
+
+       // create and return
+       unsigned int nNum = 0;
+       if (pAttrs->get("num"))
+               nNum = atoi(pAttrs->get("num"));
+       XMLSource source(pAttrs->get("name"),
+                                        nNum,
+                                        pAttrs->get("dir"),
+                                        pAttrs->get("size"),
+                                        pAttrs->get("md5"));
+       pSpec->addSource(source);
+
+       return true;
+}
+
+XMLSource::XMLSource(const char* szName,
+                                        unsigned int nNum,
+                                        const char* szDir,
+                                        const char* szSize,
+                                        const char* szMD5)
+       : XMLBase()
+{
+       if (szName)
+               m_sName.assign(szName);
+       m_nNum = nNum;
+       if (szDir)
+               m_sDir.assign(szDir);
+       if (szSize)
+               m_sSize.assign(szSize);
+       if (szMD5)
+               m_sMD5.assign(szMD5);
+}
+
+XMLSource::XMLSource(const XMLSource& rSource)
+       : XMLBase()
+{
+       m_sName.assign(rSource.m_sName);
+       m_nNum = rSource.m_nNum;
+       m_sDir.assign(rSource.m_sDir);
+       m_sSize.assign(rSource.m_sSize);
+       m_sMD5.assign(rSource.m_sMD5);
+       m_vMirrors = rSource.m_vMirrors;
+}
+
+XMLSource::~XMLSource()
+{
+}
+
+XMLSource XMLSource::operator=(XMLSource source)
+{
+       m_sName.assign(source.m_sName);
+       m_nNum = source.m_nNum;
+       m_sDir.assign(source.m_sDir);
+       m_sSize.assign(source.m_sSize);
+       m_sMD5.assign(source.m_sMD5);
+       m_vMirrors = source.m_vMirrors;
+       return *this;
+}
+
+void XMLSource::toSpecFile(ostream& rOut)
+{
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toSpecFile(rOut);
+
+       rOut << endl << "source";
+       rOut << getNum();
+       rOut << ":        ";
+       if (numMirrors())
+               rOut << getMirror(0).getPath();
+       rOut << getName();
+}
+
+void XMLSource::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t<source name=\"" << getName() << "\"";
+       rOut << endl << "\t        num=\"";
+       rOut << getNum();
+       rOut << "\"";
+       if (hasSize())
+               rOut << endl << "\t        size=\"" << getSize() << "\"";
+       if (hasMD5())
+               rOut << endl << "\t        md5=\"" << getMD5() << "\"";
+       if (hasDir())
+               rOut << endl << "\t        dir=\"" << getDir() << "\"";
+       rOut << ">";
+
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toXMLFile(rOut);
+
+       rOut << endl << "\t</source>";
+}
+
+void XMLSource::toRPMStruct(Spec pRPMSpec)
+{
+       /*Source* pCurr = new Source;
+       unsigned int nNameLen = strlen(getName());
+       unsigned int nMirrorLen = 0;
+       if (pPrev)
+               pPrev->next = pCurr;
+       pCurr->next = NULL;
+       if (numMirrors())
+               nMirrorlen = strlen(getMirror(0).getPath());
+       pCurr->fullSource = new char[nNamelen+nMirrorLen+1];
+       pCurr->fullSources[0] = '\0';
+       if (numMirrors())
+               strcpy(pCurr->fullSource, getMirror(0).getPath());
+       strcat(pCurr->fullSource, getName());
+       pCurr->source = pCurr->fullSource+nMirrorLen;
+       pCurr->num = getNum();
+       pCurr->flags = RPMBUILD_ISSOURCE;
+       return pCurr;*/
+}
+
+bool XMLNoSource::parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paSourceAttrs, (XMLBase*)pSpec))
+               return false;
+
+       unsigned int nNum = 0;
+       if (pAttrs->get("num"))
+               nNum = atoi(pAttrs->get("num"));
+       XMLNoSource source(pAttrs->get("name"),
+                                          nNum,
+                                          pAttrs->get("dir"),
+                                          pAttrs->get("size"),
+                                          pAttrs->get("md5"));
+       pSpec->addNoSource(source);
+       return true;
+}
+
+XMLNoSource::XMLNoSource(const char* szName,
+                                                unsigned int nNum,
+                                                const char* szDir,
+                                                const char* szSize,
+                                                const char* szMD5)
+       : XMLSource(szName,
+                               nNum,
+                               szDir,
+                               szSize,
+                               szMD5)
+{
+}
+
+XMLNoSource::XMLNoSource(const XMLNoSource& rNoSource)
+       : XMLSource(rNoSource.m_sName.c_str(),
+                               rNoSource.m_nNum,
+                               rNoSource.m_sDir.c_str(),
+                               rNoSource.m_sSize.c_str(),
+                               rNoSource.m_sMD5.c_str())
+{
+}
+
+XMLNoSource::~XMLNoSource()
+{
+}
+
+void XMLNoSource::toSpecFile(ostream& rOut)
+{
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toSpecFile(rOut);
+
+       rOut << endl << "nosource";
+       rOut << getNum();
+       rOut << ":      " << getName();
+}
+
+void XMLNoSource::toXMLFile(ostream& rOut)
+{
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toXMLFile(rOut);
+}
+
+void XMLNoSource::toRPMStruct(Spec pRPMSpec)
+{
+       //Source* pCurr = XMLSource::toRPMStruct(pPrev);
+       //pCurr->flags = RPMBUILD_ISNO;
+       //return pCurr;
+}
+
+// attribute structure for XMLPatch
+structValidAttrs g_paPatchAttrs[] =
+{
+       {0x0000,    true,  false, "name"},
+       {0x0001,    false, false, "num"},
+       {0x0002,    false, false, "size"},
+       {0x0003,    false, false, "md5"},
+       {XATTR_END, false, false, "end"}
+};
+
+bool XMLPatch::parseCreate(XMLAttrs* pAttrs,
+                                                  XMLSpec* pSpec)
+{
+       // validate the attributes
+       if (!pAttrs->validate(g_paPatchAttrs, (XMLBase*)pSpec))
+               return false;
+
+       unsigned int nNum = 0;
+       if (pAttrs->get("num"))
+               nNum = atoi(pAttrs->get("num"));
+       XMLPatch patch(pAttrs->get("name"),
+                                  nNum,
+                                  pAttrs->get("size"),
+                                  pAttrs->get("md5"));
+       pSpec->addPatch(patch);
+       return true;
+}
+
+XMLPatch::XMLPatch(const char* szName,
+                                  unsigned int nNum,
+                                  const char* szSize,
+                                  const char* szMD5)
+       : XMLSource(szName,
+                               nNum,
+                               NULL,
+                               szSize,
+                               szMD5)
+{
+}
+
+XMLPatch::XMLPatch(const XMLPatch& rPatch)
+       : XMLSource(rPatch.m_sName.c_str(),
+                               rPatch.m_nNum,
+                               NULL,
+                               rPatch.m_sSize.c_str(),
+                               rPatch.m_sMD5.c_str())
+{
+}
+
+XMLPatch::~XMLPatch()
+{
+}
+
+void XMLPatch::toSpecFile(ostream& rOut)
+{
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toSpecFile(rOut);
+       rOut << endl << "patch";
+       rOut << getNum();
+       rOut << ":         " << getName();
+}
+
+void XMLPatch::toXMLFile(ostream& rOut)
+{
+       rOut << endl << "\t<patch name=\"" << getName() << "\"";
+       rOut << endl << "\t       num=\"";
+       rOut << getNum();
+       rOut << "\"";
+       if (hasSize())
+               rOut << endl << "\t       size=\"" << getSize() << "\"";
+       if (hasMD5())
+               rOut << endl << "\t       md5=\"" << getMD5() << "\"";
+       if (hasDir())
+               rOut << endl << "\t       dir=\"" << getDir() << "\"";
+       rOut << ">";
+
+       for (unsigned int i = 0; i < numMirrors(); i++)
+               getMirror(i).toXMLFile(rOut);
+
+       rOut << endl << "\t</patch>";
+}
+
+void XMLPatch::toRPMStruct(Spec pRPMSpec)
+{
+
+       //Source* pCurr = XMLSource::toRPMStruct(pPrev);
+       //pCurr->flags = RPMBUILD_ISPATCH;
+       //return pCurr;
+}
diff --git a/xmlspec/XMLSource.h b/xmlspec/XMLSource.h
new file mode 100644 (file)
index 0000000..9457bb4
--- /dev/null
@@ -0,0 +1,452 @@
+#ifndef _H_XMLSOURCE_
+#define _H_XMLSOURCE_
+
+// standard C++ includes
+#include <string>
+#include <vector>
+#include <iostream>
+
+// standard includes
+#include <stdio.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+#include "XMLMirror.h"
+
+// rpm includes
+#include <rpmbuild.h>
+
+// forward declaration
+class XMLSpec;
+
+using namespace std;
+
+// <source ...>
+class XMLSource : public XMLBase
+{
+//
+// factory functions
+//
+public:
+       /**
+        * Static factory function for the creation of XMLSource, XMLPatch, ...
+        * objects from RPM Source* structure.
+        * .
+        * @param pSpource Pointer to a list of sources
+        * @param pSpec pointer to our spec object
+        * @return true on success, false otherwise
+        **/
+       static bool structCreate(Source* pSource,
+                                                       XMLSpec* pSpec);
+
+       /**
+        * Static factory function for the creation of an XMLSource
+        * object from details parsed from an XML spec.
+        * .
+        * @param pAttrs Pointer to an XML attribute object
+        * @param pspec Ponter to our spec object
+        * @param bPatch True if this source is a patch
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default contructor
+        * .
+        * @param szName The name
+        * @param szNum The source number
+        * @param szDir The unpack directory
+        * @param szSize The size of the source archive
+        * @param szMD5 The MD5 sum of the archive
+        * @return none
+        **/
+       XMLSource(const char* szName,
+                         unsigned int nNum,
+                         const char* szDir,
+                         const char* szSize,
+                         const char* szMD5);
+
+       /**
+        * Copy contructor
+        * .
+        * @param rSource The source that we are to copy
+        * @return none
+        **/
+       XMLSource(const XMLSource& rSource);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       virtual ~XMLSource();
+
+//
+// operators
+//
+public:
+       /**
+        * Assignment operator
+        * .
+        * @param source The source to copy
+        * @return copied object
+        **/
+       XMLSource operator=(XMLSource source);
+
+//
+// Member functions
+//
+public:
+       /**
+        * Convert the object into an RPM spec file
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       virtual void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       virtual void toXMLFile(ostream& rOut);
+
+       /**
+        * Converts the object into an RPM structure
+        * .
+        * @param spec the RPM structure to use
+        * @return none
+        **/
+       virtual void toRPMStruct(Spec spec);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Checks if we have a source name
+        * .
+        * @param none
+        * @return true if we have a name, false otherwise
+        **/
+       bool hasName()
+       {
+               return m_sName.length() ? true : false;
+       }
+
+       /**
+        * Get the source name
+        * .
+        * @param none
+        * @return string containing the name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Get the length of the name
+        * .
+        * @param none
+        * @return the length of the name
+        **/
+       unsigned int getNameLen()
+       {
+               return m_sName.length();
+       }
+
+       /**
+        * Get the source number
+        * .
+        * @param none
+        * @return the number
+        **/
+       unsigned int getNum()
+       {
+               return m_nNum;
+       }
+
+       /**
+        * Checks to see if we have an unpack directory
+        * .
+        * @param none
+        * @return true if we have a specified directory, false otherwise
+        **/
+       bool hasDir()
+       {
+               return m_sDir.length() ? true : false;
+       }
+
+       /**
+        * Gets the directory that we are to unpack this source to
+        * .
+        * @param none
+        * @return string contating the directory
+        **/
+       const char* getDir()
+       {
+               return m_sDir.c_str();
+       }
+
+       /**
+        * Checks to see if we have a source size
+        * .
+        * @param none
+        * @return true if we have a size, false otherwise
+        **/
+       bool hasSize()
+       {
+               return m_sSize.length() ? true : false;
+       }
+
+       /**
+        * Gets the size of the source
+        * .
+        * @param none
+        * @return string contating the size
+        **/
+       const char* getSize()
+       {
+               return m_sSize.c_str();
+       }
+
+       /**
+        * Checks to see if this source has an MD5 sum
+        * .
+        * @param none
+        * @return true if we have an MD5, false oterwise
+        **/
+       bool hasMD5()
+       {
+               return m_sMD5.length() ? true : false;
+       }
+
+       /**
+        * Gets the MD5 sum for this source
+        * .
+        * @param none
+        * @return string contating the MD5
+        **/
+       const char* getMD5()
+       {
+               return m_sMD5.c_str();
+       }
+
+       /**
+        * Add a mirror for this source
+        * .
+        * @param rMirror The mirror to add
+        * @return none
+        **/
+       void addMirror(XMLMirror& rMirror)
+       {
+               m_vMirrors.push_back(rMirror);
+       }
+
+       /**
+        * Gets the number of mirrors for this source
+        * .
+        * @param none
+        * @return the number oif mirrors
+        **/
+       unsigned int numMirrors()
+       {
+               return m_vMirrors.size();
+       }
+
+       /**
+        * Gets a specific mirror by number
+        * .
+        * @param nNum The mirror to get
+        * @param the mirror
+        **/
+       XMLMirror& getMirror(unsigned int nNum)
+       {
+               return m_vMirrors[nNum];
+       }
+
+//
+// member variables
+//
+protected:
+       string            m_sName;
+       unsigned int      m_nNum;
+       string            m_sDir;
+       string            m_sSize;
+       string            m_sMD5;
+       vector<XMLMirror> m_vMirrors;
+};
+
+// <nosource ...>
+class XMLNoSource : public XMLSource
+{
+//
+// factory methods
+//
+public:
+       /**
+        * Create an XMLNoSource object
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpec The spec to add the object o
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName The name
+        * @param nNum source number
+        * @param szDir Thje director to extract to
+        * @param szSize size of the archive
+        * @param szMD5 the MD5 sum of the archive
+        * @return none
+        **/
+       XMLNoSource(const char* szName,
+                               unsigned int nNum,
+                               const char* szDir,
+                               const char* szSize,
+                               const char* szMD5);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rNoSource Reference to the object ot copy
+        * @return none
+        **/
+       XMLNoSource(const XMLNoSource& rNoSource);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       virtual ~XMLNoSource();
+
+//
+// public member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec file
+        * .
+        * @param rOut Output stream
+        * @param none
+        **/
+       virtual void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       virtual void toXMLFile(ostream& rOut);
+
+       /**
+        * Converts the object into an RPM structure
+        * .
+        * @param spec The RPM spec structure
+        * @return none
+        **/
+        virtual void toRPMStruct(Spec spec);
+};
+
+// <patch ...>
+class XMLPatch : public XMLSource
+{
+//
+// factory methods
+//
+public:
+       /**
+        * Create an XMLPatch object
+        * .
+        * @param pAttrs XML attributes
+        * @param pSpec The spec to add the object o
+        * @return true on success, false otherwise
+        **/
+       static bool parseCreate(XMLAttrs* pAttrs,
+                                                       XMLSpec* pSpec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szName archive name
+        * @param nNum source number
+        * @param szSize size of the archive
+        * @param szMD5 MD5 sum
+        * @return none
+        **/
+       XMLPatch(const char* szName,
+                        unsigned int nNum,
+                        const char* szSize,
+                        const char* szMD5);
+
+       /**
+        * Copy constructor
+        * .
+        * @param rPatch Reference to the object to copy
+        * @return none
+        **/
+       XMLPatch(const XMLPatch& rPatch);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return nonew
+        **/
+       virtual ~XMLPatch();
+
+//
+// member functions
+//
+public:
+       /**
+        * Converts the object into an RPM spec file
+        * .
+        * @param rOut Output stream
+        * @param none
+        **/
+       virtual void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the object into an XML spec
+        * .
+        * @param rOut Output stream
+        * @return none
+        **/
+       virtual void toXMLFile(ostream& rOut);
+
+       /**
+        * Converts the object into an RPM structure
+        * .
+        * @param spec The RPM spec structure
+        * @return none
+        **/
+       virtual void toRPMStruct(Spec spec);
+};
+
+#endif
diff --git a/xmlspec/XMLSpec.cpp b/xmlspec/XMLSpec.cpp
new file mode 100644 (file)
index 0000000..0e18640
--- /dev/null
@@ -0,0 +1,239 @@
+// 3rd party includes
+#include <expat.h>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLSpec.h"
+
+using namespace std;
+
+// attribute structure for XMLSpec
+structValidAttrs g_paSpecAttrs[] =
+{
+       {0x0000,    true,  false, "name"},
+       {0x0001,    true,  false, "version"},
+       {0x0002,    true,  false, "release"},
+       {0x0003,    false, false, "epoch"},
+       {0x0004,    false, false, "distribution"},
+       {0x0005,    false, false, "vendor"},
+       {0x0006,    false, false, "packager"},
+       {0x0007,    false, false, "packager-email"},
+       {0x0008,    false, false, "copyright"},
+       {0x0009,    false, false, "url"},
+       {0x000A,    false, false, "buildroot"},
+       {XATTR_END, false, false, "end"}
+};
+
+XMLSpec* XMLSpec::parseCreate(XMLAttrs* pAttrs,
+                                                         const char* szFilename)
+{
+       // verify the attributes
+       if (!pAttrs->validate(g_paSpecAttrs, (XMLBase*)pAttrs))
+               return NULL;
+
+       // create and return
+       return new XMLSpec(szFilename,
+                                          pAttrs->get("name"),
+                                          pAttrs->get("version"),
+                                          pAttrs->get("release"),
+                                          pAttrs->get("epoch"),
+                                          pAttrs->get("distribution"),
+                                          pAttrs->get("vendor"),
+                                          pAttrs->get("packager"),
+                                          pAttrs->get("packager-email"),
+                                          pAttrs->get("copyright"),
+                                          pAttrs->get("url"),
+                                          pAttrs->get("buildroot"));
+}
+
+XMLSpec* XMLSpec::structCreate(Spec spec)
+{
+       if (!spec)
+               return NULL;
+
+       XMLSpec* pSpec = new XMLSpec(spec->specFile,
+                                                                spec->specFile,
+                                                                "1.0",
+                                                                "1",
+                                                                "0",
+                                                                NULL,
+                                                                NULL,
+                                                                NULL,
+                                                                NULL,
+                                                                NULL,
+                                                                NULL,
+                                                                spec->buildRootURL);
+
+       XMLSource::structCreate(spec->sources,
+                                                       pSpec);
+       return pSpec;
+}
+
+XMLSpec::XMLSpec(const char* szFilename,
+                                const char* szName,
+                                const char* szVersion,
+                                const char* szRelease,
+                                const char* szEpoch,
+                                const char* szDistribution,
+                                const char* szVendor,
+                                const char* szPackager,
+                                const char* szPkgrEmail,
+                                const char* szCopyright,
+                                const char* szURL,
+                                const char* szBuildRoot) : XMLBase()
+{
+       if (szFilename)
+               m_sFilename.assign(szFilename);
+       if (szName)
+               m_sName.assign(szName);
+       if (szVersion)
+               m_sVersion.assign(szVersion);
+       if (szRelease)
+               m_sRelease.assign(szRelease);
+       if (szEpoch)
+               m_sEpoch.assign(szEpoch);
+       if (szDistribution)
+               m_sDistribution.assign(szDistribution);
+       if (szVendor)
+               m_sVendor.assign(szVendor);
+       if (szPackager)
+               m_sPackager.assign(szPackager);
+       if (szPkgrEmail)
+               m_sPkgrEmail.assign(szPkgrEmail);
+       if (szCopyright)
+               m_sCopyright.assign(szCopyright);
+       if (szURL)
+               m_sURL.assign(szURL);
+       if (szBuildRoot)
+               m_sBuildRoot.assign(szBuildRoot);
+}
+
+XMLSpec::~XMLSpec()
+{
+}
+
+void XMLSpec::toSpecFile(ostream& rOut)
+{
+       for (unsigned int i = 0; i < numXMacros(); i++)
+               getXMacro(i).toSpecFile(rOut);
+
+       rOut << "name:           " << getName() << endl;
+       rOut << "version:        " << getVersion() << endl;
+       rOut << "release:        " << getRelease() << endl;
+       if (hasEpoch())
+               rOut << "epoch:          " << getEpoch() << endl;
+       if (hasCopyright())
+               rOut << "copyright:      " << getCopyright() << endl;
+       if (hasURL())
+               rOut << "url:            " << getURL() << endl;
+       if (hasBuildRoot())
+               rOut << "buildroot:      " << getBuildRoot() << endl;
+       if (hasDistribution())
+               rOut << "distribution:   " << getDistribution() << endl;
+       if (hasVendor())
+               rOut << "vendor:         " << getVendor() << endl;
+       if (hasPackager()) {
+               rOut << "packager:       " << getPackager();
+               if (hasPkgrEmail())
+                       rOut << " <" << getPkgrEmail() << ">";
+               rOut << endl;
+       }
+
+       for (unsigned int i = 0; i < numSources(); i++)
+               getSource(i).toSpecFile(rOut);
+       for (unsigned int i = 0; i < numNoSources(); i++)
+               getNoSource(i).toSpecFile(rOut);
+       for (unsigned int i = 0; i < numPatches(); i++)
+               getPatch(i).toSpecFile(rOut);
+       for (unsigned int i = 0; i < numPackages(); i++)
+               getPackage(i).toSpecFile(rOut);
+
+       getPrep().toSpecFile(rOut, "prep");
+       getBuild().toSpecFile(rOut, "build");
+       getInstall().toSpecFile(rOut, "install");
+       getClean().toSpecFile(rOut, "clean");
+
+       for (unsigned int i = 0; i < numPackages(); i++)
+               getPackage(i).toScriptsSpecFile(rOut);
+
+       for (unsigned int i = 0; i < numPackages(); i++)
+               getPackage(i).toFilesSpecFile(rOut);
+
+       getChangelog().toSpecFile(rOut);
+}
+
+void XMLSpec::toXMLFile(ostream& rOut)
+{
+       // spec start
+       rOut << "<?xml version=\"1.0\"?>";
+       rOut << endl << "<spec name=\"" << getName() << "\"";
+       rOut << endl << "      version=\"" << getVersion() << "\"";
+       rOut << endl << "      release=\"" << getRelease() << "\"";
+       if (hasEpoch())
+               rOut << endl << "      epoch=\"" << getEpoch() << "\"";
+       if (hasCopyright())
+               rOut << endl << "      copyright=\"" << getCopyright() << "\"";
+       if (hasURL())
+               rOut << endl << "      url=\"" << getURL() << "\"";
+       if (hasBuildRoot())
+               rOut << endl << "      buildroot=\"" << getBuildRoot() << "\"";
+       if (hasDistribution())
+               rOut << endl << "      distribution=\"" << getDistribution() << "\"";
+       if (hasVendor())
+               rOut << endl << "      vendor=\"" << getVendor() << "\"";
+       if (hasPackager()) {
+               rOut << endl << "      packager=\"" << getPackager() << "\"";
+               if (hasPkgrEmail())
+                       rOut << endl << "      packager-email=\"" << getPkgrEmail() << "\"";
+       }
+       rOut << ">";
+
+       for (unsigned int i = 0; i < numXMacros(); i++)
+               getXMacro(i).toXMLFile(rOut);
+       for (unsigned int i = 0; i < numSources(); i++)
+               getSource(i).toXMLFile(rOut);
+       for (unsigned int i = 0; i < numNoSources(); i++)
+               getNoSource(i).toXMLFile(rOut);
+       for (unsigned int i = 0; i < numPatches(); i++)
+               getPatch(i).toXMLFile(rOut);
+       for (unsigned int i = 0; i < numPackages(); i++)
+               getPackage(i).toXMLFile(rOut);
+
+       getPrep().toXMLFile(rOut, "prep");
+       getBuild().toXMLFile(rOut, "build");
+       getInstall().toXMLFile(rOut, "install");
+       getClean().toXMLFile(rOut, "clean");
+
+       getChangelog().toXMLFile(rOut);
+
+       rOut << endl << "</spec>";
+}
+
+void XMLSpec::toRPMStruct(Spec* pRPMSpec)
+{
+       Spec spec = newSpec();
+       if (hasBuildRoot()) {
+               spec->gotBuildRootURL = 1;
+               spec->buildRootURL = strdup(getBuildRoot());
+               addMacro(spec->macros, "buildroot", NULL, getBuildRoot(), RMIL_SPEC);
+       }
+       addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
+       spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
+
+       //getChangelog().toRPMStruct(spec);
+       /*for (unsigned int i = 0; i < numPackages(); i++)
+               getPackage(i).toRPMStruct(pRPMSpec);
+       for (unsigned int i = 0; i < numSources(); i++)
+               getSource(i).toRPMStruct(pRPMSpec);
+       for (unsigned int i = 0; i < numNoSources(); i++)
+               getNoSource(i).toRPMStruct(pRPMSpec);
+       for (unsigned int i = 0; i < numPatches(); i++)
+               getPatch(i).toRPMStruct(pRPMSpec);*/
+
+       //getPrep().toRPMStruct(spec);
+       //getBuild().toRPMStruct(spec);
+       //getInstall().toRPMStruct(spec);
+       //getClean().toRPMStruct(spec);
+
+       *pRPMSpec = spec;
+}
diff --git a/xmlspec/XMLSpec.h b/xmlspec/XMLSpec.h
new file mode 100644 (file)
index 0000000..5550a5a
--- /dev/null
@@ -0,0 +1,678 @@
+#ifndef _H_XMLSPEC_
+#define _H_XMLSPEC_
+
+// standard C++ includes
+#include <iostream>
+#include <string>
+#include <vector>
+
+// our includes
+#include "XMLAttrs.h"
+#include "XMLBase.h"
+#include "XMLChangelog.h"
+#include "XMLMacro.h"
+#include "XMLPackage.h"
+#include "XMLScript.h"
+#include "XMLSource.h"
+
+// rpm includes
+#include <rpmbuild.h>
+
+using namespace std;
+
+// <spec ...>
+class XMLSpec : public XMLBase
+{
+//
+// static object creation functions
+//
+public:
+       /**
+        * Creates an XMLSpec from values parsed
+        * .
+        * @param pAttrs The XML attributes
+        * @param szFilename The XML spec filename
+        * @return Pointer to the created spec
+        **/
+       static XMLSpec* parseCreate(XMLAttrs* pAttrs,
+                                                               const char* szFilename);
+
+       /**
+        * Creates and XMLSpec from an RPM Spec structure
+        * .
+        * @param spec The RPM spec structure
+        * @return Pointer to the created spec
+        **/
+       static XMLSpec* structCreate(Spec spec);
+
+//
+// constructors/destructor
+//
+public:
+       /**
+        * Default constructor
+        * .
+        * @param szFilename Filename of the spec on disk
+        * @param szName spec name
+        * @param szVersion Spec version
+        * @param szRelease spec release
+        * @param szEpoch spec epoch
+        * @param szDistribution spec distribution
+        * @param szVendor spec vendor
+        * @param szPackage spec packager
+        * @param szPkgEmail email address for the packager
+        * @param szCopyright spec copyright/licence
+        * @param szURL main package url
+        * @param szBuildRoot buildroot
+        * @return none
+        **/
+       XMLSpec(const char* szFilename,
+                       const char* szName,
+                       const char* szVersion,
+                       const char* szRelease,
+                       const char* szEpoch,
+                       const char* szDistribution,
+                       const char* szVendor,
+                       const char* szPackager,
+                       const char* szPkgrEmail,
+                       const char* szCopyright,
+                       const char* szURL,
+                       const char* szBuildRoot);
+
+       /**
+        * Destructor
+        * .
+        * @param none
+        * @return none
+        **/
+       ~XMLSpec();
+
+//
+// public member functions
+//
+public:
+       /**
+        * Converts the spec object to a normal RPM spec file
+        * .
+        * @param rOut Reference to the stream to write the information to
+        * @return none
+        **/
+       void toSpecFile(ostream& rOut);
+
+       /**
+        * Converts the spec object to an XML spec file
+        * .
+        * @param rOut Reference to the stream to write the information to
+        * @return none
+        **/
+        void toXMLFile(ostream& rOut);
+
+        /**
+         * Converts the spec object to an internal RPM structure
+         * .
+         * @param none
+         * @return the created RPM structure
+         **/
+         void toRPMStruct(Spec* pRPMSpec);
+
+//
+// member variable get/set functions
+//
+public:
+       /**
+        * Adds a package to the internal list
+        * .
+        * @param rPkg Reference to the package to add
+        * @return none
+        **/
+       void addPackage(XMLPackage& rPkg)
+       {
+               m_vPackages.push_back(rPkg);
+       }
+
+       /**
+        * Gets the number of packages
+        * .
+        * @param none
+        * @return the number of packages
+        **/
+       unsigned int numPackages()
+       {
+               return m_vPackages.size();
+       }
+
+       /**
+        * Gets a specific package
+        * .
+        * @param nNum The package number
+        * @return the required package
+        **/
+       XMLPackage& getPackage(unsigned int nNum)
+       {
+               return m_vPackages[nNum];
+       }
+
+       /**
+        * Gets the last package added
+        * .
+        * @param none
+        * @return the last package added
+        **/
+       XMLPackage& lastPackage()
+       {
+               return m_vPackages[numPackages()-1];
+       }
+
+       /**
+        * Adds a source to the internal list
+        * .
+        * @param rSource Reference to the source to add
+        * @return none
+        **/
+       void addSource(XMLSource& rSource)
+       {
+               m_vSources.push_back(rSource);
+       }
+
+       /**
+        * Gets the number of sources
+        * .
+        * @param none
+        * @return the number of sources
+        **/
+       unsigned int numSources()
+       {
+               return m_vSources.size();
+       }
+
+       /**
+        * Gets a specific source
+        * .
+        * @param nNum The source number
+        * @return the required source
+        **/
+       XMLSource& getSource(unsigned int nNum)
+       {
+               return m_vSources[nNum];
+       }
+
+       /**
+        * Gets the last source added
+        * .
+        * @param none
+        * @return the last source added
+        **/
+       XMLSource& lastSource()
+       {
+               return m_vSources[numSources()-1];
+       }
+
+       /**
+        * Adds a source to the internal list
+        * .
+        * @param rSource Reference to the source to add
+        * @return none
+        **/
+       void addNoSource(XMLNoSource& rSource)
+       {
+               m_vNoSources.push_back(rSource);
+       }
+
+       /**
+        * Gets the number of nosources
+        * .
+        * @param none
+        * @return the number of nsources
+        **/
+       unsigned int numNoSources()
+       {
+               return m_vNoSources.size();
+       }
+
+       /**
+        * Gets a specific nosource
+        * .
+        * @param nNum The nosource number
+        * @return the required nosource
+        **/
+       XMLNoSource& getNoSource(unsigned int nNum)
+       {
+               return m_vNoSources[nNum];
+       }
+
+       /**
+        * Gets the last nosource added
+        * .
+        * @param none
+        * @return the last nosource added
+        **/
+       XMLNoSource& lastNoSource()
+       {
+               return m_vNoSources[numNoSources()-1];
+       }
+
+       /**
+        * Adds a patch to the internal list
+        * .
+        * @param rSource Reference to the patch to add
+        * @return none
+        **/
+       void addPatch(XMLPatch& rSource)
+       {
+               m_vPatches.push_back(rSource);
+       }
+
+       /**
+        * Gets the number of patches
+        * .
+        * @param none
+        * @return the number of patches
+        **/
+       unsigned int numPatches()
+       {
+               return m_vPatches.size();
+       }
+
+       /**
+        * Gets a specific patch
+        * .
+        * @param nNum The patch number
+        * @return the required patch
+        **/
+       XMLPatch& getPatch(unsigned int nNum)
+       {
+               return m_vPatches[nNum];
+       }
+
+       /**
+        * Gets the last patch added
+        * .
+        * @param none
+        * @return the last patch added
+        **/
+       XMLPatch& lastPatch()
+       {
+               return m_vPatches[numPatches()-1];
+       }
+
+       /**
+        * Adds a macro to the internal list
+        * .
+        * @param rMacro Reference to the macro to add
+        * @return none
+        **/
+       void addXMacro(XMLMacro& rMacro)
+       {
+               m_vMacros.push_back(rMacro);
+       }
+
+       /**
+        * Gets the number of macros
+        * .
+        * @param none
+        * @return the number of macros
+        **/
+       unsigned int numXMacros()
+       {
+               return m_vMacros.size();
+       }
+
+       /**
+        * Gets a specific macro
+        * .
+        * @param nNum The macro number
+        * @return the required macro
+        **/
+       XMLMacro& getXMacro(unsigned int nNum)
+       {
+               return m_vMacros[nNum];
+       }
+
+       /**
+        * Checks if we have a filename
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasFilename()
+       {
+               return m_sFilename.length() ? true : false;
+       }
+
+       /**
+        * Gets the filename
+        * .
+        * @param none
+        * @return string containing the filename
+        **/
+       const char* getFilename()
+       {
+               return m_sFilename.c_str();
+       }
+
+       /**
+        * Checks if we have a name
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasName()
+       {
+               return m_sName.length() ? true : false;
+       }
+
+       /**
+        * Gets the name
+        * .
+        * @param none
+        * @return string containing the name
+        **/
+       const char* getName()
+       {
+               return m_sName.c_str();
+       }
+
+       /**
+        * Checks if we have a version
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasVersion()
+       {
+               return m_sVersion.length() ? true : false;
+       }
+
+       /**
+        * Gets the version
+        * .
+        * @param none
+        * @return string containing the version
+        **/
+       const char* getVersion()
+       {
+               return m_sVersion.c_str();
+       }
+
+       /**
+        * Checks if we have a release
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasRelease()
+       {
+               return m_sRelease.length() ? true : false;
+       }
+
+       /**
+        * Gets the release
+        * .
+        * @param none
+        * @return string containing the release
+        **/
+       const char* getRelease()
+       {
+               return m_sRelease.c_str();
+       }
+
+       /**
+        * Checks if we have a epoch
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasEpoch()
+       {
+               return m_sEpoch.length() ? true : false;
+       }
+
+       /**
+        * Gets the epoch
+        * .
+        * @param none
+        * @return string containing the epoch
+        **/
+       const char* getEpoch()
+       {
+               return m_sEpoch.c_str();
+       }
+
+       /**
+        * Checks if we have a distribution
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasDistribution()
+       {
+               return m_sDistribution.length() ? true : false;
+       }
+
+       /**
+        * Gets the distribution
+        * .
+        * @param none
+        * @return string containing the distribution
+        **/
+       const char* getDistribution()
+       {
+               return m_sDistribution.c_str();
+       }
+
+       /**
+        * Checks if we have a vendor
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasVendor()
+       {
+               return m_sVendor.length() ? true : false;
+       }
+
+       /**
+        * Gets the vendor
+        * .
+        * @param none
+        * @return string containing the vendor
+        **/
+       const char* getVendor()
+       {
+               return m_sVendor.c_str();
+       }
+
+       /**
+        * Checks if we have a packager
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasPackager()
+       {
+               return m_sPackager.length() ? true : false;
+       }
+
+       /**
+        * Gets the packager
+        * .
+        * @param none
+        * @return string containing the packager
+        **/
+       const char* getPackager()
+       {
+               return m_sPackager.c_str();
+       }
+
+       /**
+        * Checks if we have a packager email
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasPkgrEmail()
+       {
+               return m_sPkgrEmail.length() ? true : false;
+       }
+
+       /**
+        * Gets the packager's email address
+        * .
+        * @param none
+        * @return string containing the packager's email address
+        **/
+       const char* getPkgrEmail()
+       {
+               return m_sPkgrEmail.c_str();
+       }
+
+       /**
+        * Checks if we have a copyright
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasCopyright()
+       {
+               return m_sCopyright.length() ? true : false;
+       }
+
+       /**
+        * Gets the copyright
+        * .
+        * @param none
+        * @return string containing the copyright
+        **/
+       const char* getCopyright()
+       {
+               return m_sCopyright.c_str();
+       }
+
+       /**
+        * Checks if we have an URL
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasURL()
+       {
+               return m_sURL.length() ? true : false;
+       }
+
+       /**
+        * Gets the URL
+        * .
+        * @param none
+        * @return string containing the URL
+        **/
+       const char* getURL()
+       {
+               return m_sURL.c_str();
+       }
+
+       /**
+        * Checks if we have a BuildRoot
+        * .
+        * @param none
+        * @return true if available, false otherwise
+        **/
+       bool hasBuildRoot()
+       {
+               return m_sBuildRoot.length() ? true : false;
+       }
+
+       /**
+        * Gets the buildroot
+        * .
+        * @param none
+        * @return string containing the buildroor
+        **/
+       const char* getBuildRoot()
+       {
+               return m_sBuildRoot.c_str();
+       }
+
+       /**
+        * Gets the prep section
+        * .
+        * @param none
+        * @return reference to the prep section
+        **/
+       XMLScripts& getPrep()
+       {
+               return m_Prep;
+       }
+
+       /**
+        * Gets the build section
+        * .
+        * @param none
+        * @return reference to the build section
+        **/
+       XMLScripts& getBuild()
+       {
+               return m_Build;
+       }
+
+       /**
+        * Gets the install section
+        * .
+        * @param none
+        * @return reference to the install section
+        **/
+       XMLScripts& getInstall()
+       {
+               return m_Install;
+       }
+
+       /**
+        * Gets the clean section
+        * .
+        * @param none
+        * @return reference to the clean section
+        **/
+       XMLScripts& getClean()
+       {
+               return m_Clean;
+       }
+
+       /**
+        * Gets the changelog section
+        * .
+        * @param none
+        * @return reference to the changelog section
+        **/
+       XMLChangelog& getChangelog()
+       {
+               return m_Changelog;
+       }
+
+//
+// internal member variables
+//
+protected:
+       string              m_sFilename;
+       string              m_sName;
+       string              m_sVersion;
+       string              m_sRelease;
+       string              m_sEpoch;
+       string              m_sDistribution;
+       string              m_sVendor;
+       string              m_sPackager;
+       string              m_sPkgrEmail;
+       string              m_sCopyright;
+       string              m_sURL;
+       string              m_sBuildRoot;
+       vector<XMLPackage>  m_vPackages;
+       vector<XMLSource>   m_vSources;
+       vector<XMLNoSource> m_vNoSources;
+       vector<XMLPatch>    m_vPatches;
+       vector<XMLMacro>    m_vMacros;
+       XMLScripts          m_Prep;
+       XMLScripts          m_Build;
+       XMLScripts          m_Install;
+       XMLScripts          m_Clean;
+       XMLChangelog        m_Changelog;
+};
+
+#endif
diff --git a/xmlspec/example.spec.xml b/xmlspec/example.spec.xml
new file mode 100644 (file)
index 0000000..791c260
--- /dev/null
@@ -0,0 +1,167 @@
+<?xml version="1.0"?>
+<!--
+       This is an example XML spec file to demonstrate the xml2spec
+       conversion program. By running "xml2spec example.spec.xml" it
+       will create an output spec in "normal" RPM spec format, ready
+       for comsumption by rpmbuild.
+-->
+<spec name="example"
+         version="1.0"
+         release="03"
+         copyright="GPL"
+         url="http://www.rpm.org/"
+         distribution="Any distribution"
+         vendor="rpm.org"
+         packager="Jaco Greeff"
+         packager-email="jaco@puxedo.org"
+         buildroot="%{tmppath}/lvr-%{name}-build">
+
+       <macro name="test">value is this</macro>
+
+       <source name="rpm-4.0.4.tar.bz2"
+                       num="0"
+                       size="4296845"
+                       md5="bb80a5d06a48623ecbe3f2d41cac15f9">
+               <mirror path="ftp://ftp.rpm.org/"
+                               description="Main RPM FTP site" />
+               <mirror path="http://www.puxedo.org/downloads/source/"
+                               description="puxedo.org source distribution"
+                               country="za" />
+       </source>
+       <source name="expat-1.95.2.tar.bz2"
+                       num="1"
+                       size="156575"
+                       md5="919c78ddaf7f319b7e07792309ae2f22">
+               <mirror path="http://expat.sourceforge.net/"
+                               description="SourceForge Mirror"
+                               country="us" />
+       </source>
+
+       <patch name="example-1.0-1.patch.bz2"
+                  num="0"
+                  size="3276"
+                  md5="467c78cbdf75619b7e0abc2309ae2f11" />
+
+       <nosource name="nosource-sample-0.98.bz2"
+                          num="33" />
+
+       <package group="System/Libraries">
+               <buildrequires>
+                       <package name="automake" />
+                       <package name="autoconf" />
+                       <package name="bash" />
+                       <package name="binutils" />
+                       <package name="gcc" />
+                       <package name="glibc-devel" />
+               </buildrequires>
+               <requires>
+                       <package name="gcc" cmp="ge" version="2.95" />
+                       <package name="glibc" cmp="ge" version="2.2" />
+                       <package name="libogg" />
+               </requires>
+               <provides>
+                       <package name="%{name}" />
+               </provides>
+               <obsoletes>
+                       <package name="old-example" />
+               </obsoletes>
+               <summary>This spec is just an example for some funny purpose.</summary>
+               <description>%{summary}</description>
+                <post>
+                       <script>/sbin/ldconfig</script>
+               </post>
+               <postun>
+                       <script>/sbin/ldconfig</script>
+               </postun>
+               <files>
+                       <file uid="root" gid="root">/usr/lib/*.so*</file>
+               </files>
+       </package>
+
+       <package name="devel"
+                        group="Development/Libraries">
+               <requires>
+                       <package name="%{name}" />
+                       <package name="libtool" />
+                       <package name="m4" />
+               </requires>
+               <summary>The libvorbis-devel package contains development headers.</summary>
+               <description>%{summary}</description>
+               <pre>
+                       <script>some pre stuff under devel</script>
+                       <script dir="/here/while/we/are/at/it">That ^^^ changed directory</script>
+               </pre>
+               <files uid="root"
+                               gid="root">
+                       <file>/usr/include/*.h</file>
+                       <file gid="rpm">/usr/lib/*.la</file>
+                       <file uid="rpm">/usr/share/aclocal/*</file>
+                       <file attr="777">/usr/share/m4/*</file>
+                       <file uid="uid" gid="gid" attr="444">/usr/share/man/*</file>
+               </files>
+       </package>
+
+       <package name="toys" sub="no">
+               <requires>
+                       <package name="%{name}" />
+               </requires>
+               <obsoletes>
+                       <package name="oldtoys" />
+               </obsoletes>
+               <summary>The toys package contains toys</summary>
+               <description>%{summary}</description>
+               <preun>
+                       <script>some preun stuff under toys</script>
+               </preun>
+               <verify>
+                       <script>Some verify stuff under toys</script>
+               </verify>
+               <files>
+                       <file>/usr/doc/*</file>
+               </files>
+       </package>
+
+       <prep>
+               <script>rm -rf $RPM_BUILD_DIR/%{name}-%{version}rc3</script>
+               <script>rm -rf %{buildroot}</script>
+               <setup path="%{name}-%{version}rc3" />
+       </prep>
+
+       <build>
+               <script>./configure --prefix=/usr</script>
+               <script>make PROFILE=&apos;-Wall -W -pg -g -O2 -ffast-math -D_REENTRANT -fsigned-char -fno-inline -static' CFLAGS='-O2 -ffast-math -D_REENTRANT -fsigned-char -DUSE_MEMORY_H&apos;</script>
+       </build>
+
+       <install>
+               <script>make DESTDIR=%{buildroot} install</script>
+       </install>
+
+       <clean>
+               <script>rm -rf %{buildroot}</script>
+               <script>rm -rf $RPM_BUILD_DIR/%{name}-%{version}rc3</script>
+       </clean>
+
+       <changelog>
+               <changes date="Sat May 25 2002"
+                                author="Jaco Greeff"
+                                author-email="jaco@puxedo.org"
+                                version="1.0-03">
+                       <change>Moved &lt;files&gt; into &lt;package&gt; structure</change>
+                       <change>Added &lt;nosource&gt; tag as example</change>
+                       <change>Changed &lt;shell&gt; to &lt;script&gt;</change>
+               </changes>
+               <changes date="Sun May 19 2002"
+                                author="Jaco Greeff"
+                                author-email="jaco@puxedo.org"
+                                version="1.0-02">
+                       <change>Changed the formatting of the XML file to fit in with new implementation</change>
+                       <change>Commented the spec to allow others to understand it as well</change>
+               </changes>
+               <changes date="Wed May 15 2002"
+                                author="Jaco Greeff"
+                                author-email="jaco@puxedo.org"
+                                version="1.0-01">
+                       <change>Converted spec file to .spec.xml file for illustrative purposes</change>
+               </changes>
+       </changelog>
+</spec>
diff --git a/xmlspec/xml2spec.cpp b/xmlspec/xml2spec.cpp
new file mode 100644 (file)
index 0000000..b6408c5
--- /dev/null
@@ -0,0 +1,54 @@
+// TODO: Comment properly
+
+// standard C++ includes
+#include <fstream>
+
+// our includes
+#include "XMLParser.h"
+#include "XMLSpec.h"
+
+// display some usage
+int usage()
+{
+               printf("Usage: xml2spec input [output]\n");
+               printf("Converts the input pkg.spec.xml file to a pkg.spec\n");
+               printf("file for use in an rpmbuild command.\n\n");
+               return 1;
+}
+
+// program entry point
+int main(int argc,
+                char** argv)
+{
+       if (argc != 2 && argc != 3) {
+               usage();
+               return 1;
+       }
+
+       XMLSpec* pSpec = NULL;
+       if (parseXMLSpec(argv[1], pSpec) == 0 && pSpec) {
+               if (argc == 3) {
+                       printf("Writing spec to %s ... ", argv[2]);
+                       ofstream fOut(argv[2]);
+                       if (fOut.is_open()) {
+                               pSpec->toSpecFile(fOut);
+                               fOut.close();
+                               printf("Ok.\n");
+                       }
+                       else {
+                               delete pSpec;
+                               printf("Failed.\n");
+                               return 2;
+                       }
+               }
+               else if (argc == 2) {
+                       pSpec->toSpecFile(cout);
+                       pSpec->toXMLFile(cout);
+               }
+
+               delete pSpec;
+               return 0;
+       }
+
+       return 3;
+}