]> git.pld-linux.org Git - packages/rpm.git/commitdiff
- update from rpm cvs
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Mon, 11 Nov 2002 14:33:46 +0000 (14:33 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    rpm-4.1-branch.patch -> 1.1
    rpm-SIGCHLD.patch -> 1.2
    rpm-db4.patch -> 1.4

rpm-4.1-branch.patch [new file with mode: 0644]
rpm-SIGCHLD.patch [deleted file]
rpm-db4.patch [deleted file]

diff --git a/rpm-4.1-branch.patch b/rpm-4.1-branch.patch
new file mode 100644 (file)
index 0000000..29055c1
--- /dev/null
@@ -0,0 +1,11092 @@
+Index: CHANGES
+===================================================================
+RCS file: rpm/CHANGES,v
+retrieving revision 1.1130.2.23
+retrieving revision 1.1130.2.27
+diff -u -u -r1.1130.2.23 -r1.1130.2.27
+--- rpm/CHANGES        17 Sep 2002 15:18:23 -0000      1.1130.2.23
++++ rpm/CHANGES        6 Nov 2002 17:28:19 -0000       1.1130.2.27
+@@ -286,6 +286,13 @@
+       - fix: register SIGCHLD handler before forking (#73134).
+       - better diagnostics on failed header parsing.
+       - lclint clean.
++      - rpm-4.1 release.
++      - fix: make sure that psm->child pid is set before SIGCHLD is handled.
++      - fix: use size_t consistently, avoid segfault on ia64.
++      - use %%{_lib} for libraries.
++      - fix: permit build with --disable-nls (#76258).
++      - backport db-4.1.17 changes.
++      - add _noDirTokens macro for 6x builds.
+ 4.0.3 -> 4.0.4:
+       - solaris: translate i86pc to i386 (#57182).
+Index: autogen.sh
+===================================================================
+RCS file: rpm/autogen.sh,v
+retrieving revision 2.39
+retrieving revision 2.39.2.1
+diff -u -u -r2.39 -r2.39.2.1
+--- rpm/autogen.sh     8 Aug 2002 22:20:26 -0000       2.39
++++ rpm/autogen.sh     25 Oct 2002 17:31:37 -0000      2.39.2.1
+@@ -4,13 +4,13 @@
+ export LDFLAGS
+ LTV="libtoolize (GNU libtool) 1.4.2"
+-ACV="autoconf (GNU Autoconf) 2.53"
++ACV="autoconf (GNU Autoconf) 2.54"
+ AMV="automake (GNU automake) 1.6.3"
+ USAGE="
+ This script documents the versions of the tools I'm using to build rpm:
+       libtool-1.4.2
+-      autoconf-2.53
+-      automake-1.6.2
++      autoconf-2.54
++      automake-1.6.3
+ Simply edit this script to change the libtool/autoconf/automake versions
+ checked if you need to, as rpm should build (and has built) with all
+ recent versions of libtool/autoconf/automake.
+Index: configure.ac
+===================================================================
+RCS file: rpm/configure.ac,v
+retrieving revision 2.6.2.2
+retrieving revision 2.6.2.3
+diff -u -u -r2.6.2.2 -r2.6.2.3
+--- rpm/configure.ac   22 Aug 2002 19:18:56 -0000      2.6.2.2
++++ rpm/configure.ac   9 Oct 2002 19:05:38 -0000       2.6.2.3
+@@ -1094,6 +1094,7 @@
+ dnl Determine the canonical arch-vendor-os for the build machine
+ case "${build_cpu}" in
+ *86)          RPMCANONARCH=i386 ;;
++x86_64*)      RPMCANONARCH=x86_64 ;;
+ alpha*)               RPMCANONARCH=alpha ;;
+ sparc*)               RPMCANONARCH=sparc ;;
+ ia64*)                RPMCANONARCH=ia64 ;;
+Index: installplatform
+===================================================================
+RCS file: rpm/installplatform,v
+retrieving revision 2.34
+retrieving revision 2.34.2.2
+diff -u -u -r2.34 -r2.34.2.2
+--- rpm/installplatform        30 Jul 2002 17:07:39 -0000      2.34
++++ rpm/installplatform        11 Oct 2002 17:23:27 -0000      2.34.2.2
+@@ -34,6 +34,7 @@
+   alpha*) SUBSTS='s_alpha_alpha_ s_alpha_alphaev5_ s_alpha_alphaev56_ s_alpha_alphapca56_ s_alpha_alphaev6_ s_alpha_alphaev67_' ;;
+   sparc*) SUBSTS='s_sparc\(64\|v9\)_sparc_ s_sparc64_sparcv9_;s_sparc\([^v]\|$\)_sparcv9\1_ s_sparcv9_sparc64_;s_sparc\([^6]\|$\)_sparc64\1_' ;;
+   powerpc*|ppc*) SUBSTS='s_ppc64_ppc_ s_ppc\([^6]\|$\)_ppc64\1_' ;;
++  s390*) SUBSTS='s_s390x_s390_ s_s390\([^x]\|$\)_s390x\1_' ;;
+   *) SUBSTS=y___ ;;
+ esac
+@@ -60,6 +61,12 @@
+     sparc-linux) MULTILIBNO=1 ;;
+     sparcv9-linux) MULTILIBNO=1 ;;
+     sparc64-linux) ARCH_INSTALL_POST=${pkglibdir}/brp-sparc64-linux; LIB=lib64; MULTILIBNO=2 ;;
++    s390-linux) MULTILIBNO=1 ;;
++    s390x-linux) LIB=lib64; MULTILIBNO=2 ;;
++    ppc-linux) MULTILIBNO=1 ;;
++    ppc64-linux) LIB=lib64; MULTILIBNO=2 ;;
++    i?86-linux|athlon-linux) MULTILIBNO=1 ;;
++    x86_64-linux) LIB=lib64; MULTILIBNO=2 ;;
+   esac
+   if [ -n "$MULTILIBNO" ]; then
+Index: rpmqv.c
+===================================================================
+RCS file: rpm/rpmqv.c,v
+retrieving revision 1.98
+retrieving revision 1.98.2.2
+diff -u -u -r1.98 -r1.98.2.2
+--- rpm/rpmqv.c        6 Aug 2002 01:41:46 -0000       1.98
++++ rpm/rpmqv.c        6 Nov 2002 17:28:19 -0000       1.98.2.2
+@@ -271,6 +271,7 @@
+     freeSpecVec = freeSpec;
+     /*@=type@*/
++#if defined(ENABLE_NLS)
+     /* set up the correct locale */
+     (void) setlocale(LC_ALL, "" );
+@@ -279,6 +280,7 @@
+ #endif
+     bindtextdomain(PACKAGE, LOCALEDIR);
+     textdomain(PACKAGE);
++#endif
+     rpmSetVerbosity(RPMMESS_NORMAL);  /* XXX silly use by showrc */
+@@ -614,6 +616,8 @@
+       (void) close(p[1]);
+     }
+       
++    _noDirTokens = rpmExpandNumeric("%{?_noDirTokens}");
++
+     ts = rpmtsCreate();
+     (void) rpmtsSetRootDir(ts, rpmcliRootDir);
+     switch (bigMode) {
+Index: beecrypt/base64.c
+===================================================================
+RCS file: rpm/beecrypt/base64.c,v
+retrieving revision 1.20
+retrieving revision 1.20.2.1
+diff -u -u -r1.20 -r1.20.2.1
+--- rpm/beecrypt/base64.c      2 Jul 2002 23:54:35 -0000       1.20
++++ rpm/beecrypt/base64.c      9 Oct 2002 19:05:39 -0000       1.20.2.1
+@@ -246,7 +246,7 @@
+ /*@-boundswrite@*/
+ /*@-internalglobs -modfilesys @*/
+-char * b64encode (const void * data, int ns)
++char * b64encode (const void * data, size_t ns)
+ {
+     static char b64enc[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+@@ -275,7 +275,7 @@
+     lc = 0;
+     if (te)
+-    while (ns) {
++    while (ns > 0) {
+ if (_debug)
+ fprintf(stderr, "%7u %02x %02x %02x -> %02x %02x %02x %02x\n",
+@@ -335,7 +335,7 @@
+ #define CRC24_POLY 0x1864cfbL
+ /*@-boundsread@*/
+-char * b64crc (const unsigned char * data, int ns)
++char * b64crc (const unsigned char * data, size_t ns)
+ {
+     const unsigned char *s = data;
+     uint32 crc = CRC24_INIT;
+@@ -367,7 +367,7 @@
+ /*@-internalglobs -modfilesys @*/
+ /*@-boundswrite@*/
+-int b64decode (const char * s, void ** datap, int *lenp)
++int b64decode (const char * s, void ** datap, size_t *lenp)
+ {
+     unsigned char b64dec[256];
+     const unsigned char *t;
+Index: beecrypt/base64.h
+===================================================================
+RCS file: rpm/beecrypt/base64.h,v
+retrieving revision 1.14
+retrieving revision 1.14.2.2
+diff -u -u -r1.14 -r1.14.2.2
+--- rpm/beecrypt/base64.h      13 May 2002 22:45:31 -0000      1.14
++++ rpm/beecrypt/base64.h      6 Nov 2002 17:28:19 -0000       1.14.2.2
+@@ -68,17 +68,17 @@
+  * @return            (malloc'd) base64 string
+  */
+ BEECRYPTAPI /*@only@*/ /*@null@*/ /*@unused@*/
+-char * b64encode (const void * data, int ns)
++char * b64encode (const void * data, size_t ns)
+       /*@*/;
+ /**
+  * Encode crc of binary input data into 5 bytes of base64 output.
+  * @param data                binary data
+- * @param ns          crc of data
++ * @param ns          no. bytes of binary data
+  * @return            (malloc'd) base64 string
+  */
+ BEECRYPTAPI /*@only@*/ /*@null@*/ /*@unused@*/
+-char * b64crc (const unsigned char * data, int ns)
++char * b64crc (const unsigned char * data, size_t ns)
+       /*@*/;
+ /**
+@@ -89,7 +89,7 @@
+  * @return            0 on success, 1: s == NULL, 2: bad length, 3: bad char
+  */
+ BEECRYPTAPI /*@unused@*/
+-int b64decode (const char * s, /*@out@*/ void ** datap, /*@out@*/ int *lenp)
++int b64decode (const char * s, /*@out@*/ void ** datap, /*@out@*/ size_t *lenp)
+       /*@modifies *datap, *lenp @*/;
+ /**
+Index: db3/configure
+===================================================================
+RCS file: rpm/db3/configure,v
+retrieving revision 1.20
+retrieving revision 1.20.2.1
+diff -u -u -r1.20 -r1.20.2.1
+--- rpm/db3/configure  30 Jul 2002 16:39:09 -0000      1.20
++++ rpm/db3/configure  6 Nov 2002 17:28:20 -0000       1.20.2.1
+@@ -4,10 +4,6 @@
+ rm -f config.cache
+-# XXX hacks to get db-3.3.4 to configure properly
+-#ln -sf ../dist $db_dist/../db/dist
+-#ln -sf ../dist $db_dist
+-
+ # XXX edit CFLAGS= ... out of invocation args ???
+ ARGS="`echo $* | sed -e 's% [^ ]*CFLAGS=[^ ]*%%' -e 's% -[^-][^ ]*%%g' -e 's%--cache-file=.*$%%'`"
+@@ -15,18 +11,15 @@
+       --enable-shared --enable-static --enable-rpc \
+       --with-uniquename=_rpmdb --srcdir=$db_dist
+-# XXX hack to get db-3.3.4 to configure properly
+-#rm -f $db_dist/../db/dist $db_dist/dist
+-
+ mv Makefile Makefile.orig
+-cat Makefile.orig | sed -e 's/ -g$/ -g -O2/' -e '/^install:/c\
++cat Makefile.orig | sed -e '/^install[:-]/c\
+ .PHONY: listobjs\
+ listobjs:\
+       @echo $(OBJS) $(C_OBJS) \
+ \
+ distdir install check:\
+ \
+-db3_install: all install_setip' > Makefile
++db4_install: all install_setip' > Makefile
+ mv db.h db.h.orig
+ cat db.h.orig | sed \
+@@ -36,7 +29,7 @@
+ /*@=incondefs@*/' \
+       -e '/^#define   db_create/i\
+ /*@-declundef -noparams -fcnuse@*/' \
+-      -e '/^#define db_xa_switch/a\
++      -e '/^int txn_commit __P((/a\
+ /*@=declundef =noparams =fcnuse =fielduse =enummemuse =typeuse @*/' > db.h
+ # Generate manifest for rpmdb.
+Index: lib/formats.c
+===================================================================
+RCS file: rpm/lib/formats.c,v
+retrieving revision 2.71.2.1
+retrieving revision 2.71.2.2
+diff -u -u -r2.71.2.1 -r2.71.2.2
+--- rpm/lib/formats.c  19 Aug 2002 22:21:20 -0000      2.71.2.1
++++ rpm/lib/formats.c  9 Oct 2002 19:05:39 -0000       2.71.2.2
+@@ -145,7 +145,8 @@
+     char * t;
+     char * val;
+     int atype;
+-    int lc, ns, nt;
++    size_t ns, nt;
++    int lc;
+     switch (type) {
+     case RPM_BIN_TYPE:
+@@ -238,7 +239,7 @@
+       const char * enc;
+       char * t;
+       int lc;
+-      int nt = ((element + 2) / 3) * 4;
++      size_t nt = ((element + 2) / 3) * 4;
+ /*@-boundswrite@*/
+       /*@-globs@*/
+Index: lib/package.c
+===================================================================
+RCS file: rpm/lib/package.c,v
+retrieving revision 2.112.2.10
+retrieving revision 2.112.2.11
+diff -u -u -r2.112.2.10 -r2.112.2.11
+--- rpm/lib/package.c  17 Sep 2002 15:18:23 -0000      2.112.2.10
++++ rpm/lib/package.c  9 Oct 2002 19:05:39 -0000       2.112.2.11
+@@ -360,7 +360,7 @@
+     if (uc > 0 && pvlen != uc) {
+       (void) snprintf(buf, sizeof(buf),
+               _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
+-              uc, il, dl);
++              (int)uc, (int)il, (int)dl);
+       goto exit;
+     }
+@@ -652,7 +652,7 @@
+     memset(block, 0, sizeof(block));
+     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
+       (void) snprintf(buf, sizeof(buf),
+-              _("hdr size(%d): BAD, read returned %d\n"), sizeof(block), xx);
++              _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
+       goto exit;
+     }
+     if (memcmp(block, header_magic, sizeof(header_magic))) {
+Index: lib/poptALL.c
+===================================================================
+RCS file: rpm/lib/poptALL.c,v
+retrieving revision 2.10.2.2
+retrieving revision 2.10.2.3
+diff -u -u -r2.10.2.2 -r2.10.2.3
+--- rpm/lib/poptALL.c  27 Aug 2002 20:42:17 -0000      2.10.2.2
++++ rpm/lib/poptALL.c  25 Oct 2002 17:31:37 -0000      2.10.2.3
+@@ -332,9 +332,12 @@
+     }
+ /*@=globs =mods@*/
+-#if !defined(__LCLINT__)
++#if defined(ENABLE_NLS)
+     (void) setlocale(LC_ALL, "" );
++#ifdef        __LCLINT__
++#define LOCALEDIR     "/usr/share/locale"
++#endif
+     (void) bindtextdomain(PACKAGE, LOCALEDIR);
+     (void) textdomain(PACKAGE);
+ #endif
+Index: lib/psm.c
+===================================================================
+RCS file: rpm/lib/psm.c,v
+retrieving revision 2.126.2.7
+retrieving revision 2.126.2.9
+diff -u -u -r2.126.2.7 -r2.126.2.9
+--- rpm/lib/psm.c      17 Sep 2002 15:18:23 -0000      2.126.2.7
++++ rpm/lib/psm.c      9 Oct 2002 19:05:39 -0000       2.126.2.9
+@@ -695,15 +695,19 @@
+       (void) sigaddset(&caught, signum);
+       switch (signum) {
+       case SIGCHLD:
+-      {   int status = 0;
+-          pid_t reaped = waitpid(0, &status, WNOHANG);
+-          int i;
+-
+-          if (psmtbl.psms)
+-          for (i = 0; i < psmtbl.npsms; i++) {
+-              rpmpsm psm = psmtbl.psms[i];
+-              if (psm->child != reaped)
+-                  /*@innercontinue@*/ continue;
++          while (1) {
++              int status = 0;
++              pid_t reaped = waitpid(0, &status, WNOHANG);
++              int i;
++
++              if (reaped <= 0)
++                  /*@innerbreak@*/ break;
++
++              if (psmtbl.psms)
++              for (i = 0; i < psmtbl.npsms; i++) {
++                  rpmpsm psm = psmtbl.psms[i];
++                  if (psm->child != reaped)
++                      /*@innercontinue@*/ continue;
+ #if _PSM_DEBUG
+ /*@-modfilesys@*/
+@@ -712,11 +716,12 @@
+ /*@=modfilesys@*/
+ #endif
+-              psm->reaped = reaped;
+-              psm->status = status;
+-              /*@innerbreak@*/ break;
++                  psm->reaped = reaped;
++                  psm->status = status;
++                  /*@innerbreak@*/ break;
++              }
+           }
+-      }   /*@switchbreak@*/ break;
++          /*@switchbreak@*/ break;
+       default:
+           /*@switchbreak@*/ break;
+       }
+@@ -782,26 +787,6 @@
+ }
+ /**
+- * Fork a new process.
+- * @param psm         package state machine data
+- * @return            fork(2) pid
+- */
+-static pid_t psmFork(rpmpsm psm)
+-      /*@globals fileSystem, internalState @*/
+-      /*@modifies fileSystem, internalState @*/
+-{
+-    pid_t pid;
+-
+-    if ((pid = fork()) != 0) {
+-/*@-modfilesys@*/
+-if (_psm_debug)
+-fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, pid);
+-/*@=modfilesys@*/
+-    }
+-    return pid;
+-}
+-
+-/**
+  * Register a child reaper, then fork a child.
+  * @param psm         package state machine data
+  * @return            fork(2) pid
+@@ -835,7 +820,6 @@
+       }
+       empty = psmtbl.npsms++;
+     }
+-    psm->reaped = 0;
+     if (psmtbl.psms)  /* XXX can't happen */
+       psmtbl.psms[empty] = rpmpsmLink(psm, "psmRegister");
+ /*@-modfilesys@*/
+@@ -844,15 +828,24 @@
+ /*@=modfilesys@*/
+     (void) enableSignal(SIGCHLD);
++
++    psm->reaped = 0;
++    if ((psm->child = fork()) != 0) {
++/*@-modfilesys@*/
++if (_psm_debug)
++fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
++/*@=modfilesys@*/
++    }
++
+     (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
+-    return psmFork(psm);
++    return psm->child;
+ }
+ /**
+  * Unregister a child reaper.
+  */
+-static int psmUnregister(rpmpsm psm, pid_t child)
++static int psmWaitUnregister(rpmpsm psm, pid_t child)
+       /*@globals psmtbl, fileSystem, internalState @*/
+       /*@modifies psmtbl, fileSystem, internalState @*/
+ {
+@@ -862,6 +855,19 @@
+     (void) sigfillset(&newMask);              /* block all signals */
+     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
+     
++    /*@-infloops@*/
++    while (psm->reaped != psm->child) {
++      (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
++      sleep(1);       /* XXX sleep guarantees loop traversal. */
++      (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
++    }
++    /*@=infloops@*/
++
++/*@-modfilesys@*/
++if (_psm_debug)
++fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
++/*@=modfilesys@*/
++
+     if (psmtbl.psms)
+     for (i = 0; i < psmtbl.npsms; i++) {
+       if (psmtbl.psms[i] == NULL)
+@@ -893,25 +899,6 @@
+ }
+ /**
+- * Return reaped pid safely (i.e. with signals blocked).
+- * @param psm         package state machine data
+- * @return            
+- */
+-static inline pid_t psmGetReaped(rpmpsm psm)
+-      /*@globals fileSystem @*/
+-      /*@modifies fileSystem @*/
+-{
+-    sigset_t newMask, oldMask;
+-    pid_t reaped;
+-
+-    (void) sigfillset(&newMask);              /* block all signals */
+-    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
+-    reaped = psm->reaped;
+-    (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
+-    return reaped;
+-}
+-
+-/**
+  * Wait for child process to be reaped.
+  * @param psm         package state machine data
+  * @return            
+@@ -921,15 +908,7 @@
+       /*@modifies psm, fileSystem, internalState @*/
+ {
+     if (psm->reaper) {
+-      /*@-infloops@*/
+-      while (psmGetReaped(psm) == 0)
+-          (void) pause();
+-      /*@=infloops@*/
+-/*@-modfilesys@*/
+-if (_psm_debug)
+-fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
+-/*@=modfilesys@*/
+-      (void) psmUnregister(psm, psm->child);
++      (void) psmWaitUnregister(psm, psm->child);
+     } else {
+       do {
+           psm->reaped = waitpid(psm->child, &psm->status, 0);
+@@ -997,7 +976,6 @@
+     FD_t out;
+     rpmRC rc = RPMRC_OK;
+     const char *n, *v, *r;
+-    pid_t pid;
+     if (progArgv == NULL && script == NULL)
+       return rc;
+@@ -1119,8 +1097,7 @@
+     if (out == NULL) return RPMRC_FAIL;       /* XXX can't happen */
+     
+     /*@-branchstate@*/
+-    pid = psmRegisterFork(psm);
+-    psm->child = pid;
++    (void) psmRegisterFork(psm);
+     if (psm->child == 0) {
+       const char * rootDir;
+       int pipes[2];
+Index: lib/query.c
+===================================================================
+RCS file: rpm/lib/query.c,v
+retrieving revision 2.138.2.8
+retrieving revision 2.138.2.9
+diff -u -u -r2.138.2.8 -r2.138.2.9
+--- rpm/lib/query.c    17 Sep 2002 15:18:23 -0000      2.138.2.8
++++ rpm/lib/query.c    9 Oct 2002 19:05:39 -0000       2.138.2.9
+@@ -266,7 +266,7 @@
+ /*@=boundswrite@*/
+       if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
+-          sprintf(te, "%s %d %d %s 0%o ", fn, fsize, fmtime, fmd5, fmode);
++          sprintf(te, "%s %d %d %s 0%o ", fn, (int)fsize, fmtime, fmd5, fmode);
+           te += strlen(te);
+           if (fuser && fgroup) {
+Index: lib/rpmcli.h
+===================================================================
+RCS file: rpm/lib/rpmcli.h,v
+retrieving revision 2.47.2.2
+retrieving revision 2.47.2.3
+diff -u -u -r2.47.2.2 -r2.47.2.3
+--- rpm/lib/rpmcli.h   17 Sep 2002 15:18:24 -0000      2.47.2.2
++++ rpm/lib/rpmcli.h   9 Oct 2002 19:05:39 -0000       2.47.2.3
+@@ -557,7 +557,7 @@
+  * @param argv                array of package file names (NULL terminated)
+  * @return            0 on success
+  */
+-int rpmErase(rpmts ts, const struct rpmInstallArguments_s * ia,
++int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
+               /*@null@*/ const char ** argv)
+       /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
+       /*@modifies ts, ia, rpmGlobalMacroContext,
+Index: lib/rpmds.h
+===================================================================
+RCS file: rpm/lib/rpmds.h,v
+retrieving revision 2.36
+retrieving revision 2.36.2.1
+diff -u -u -r2.36 -r2.36.2.1
+--- rpm/lib/rpmds.h    3 Aug 2002 22:31:39 -0000       2.36
++++ rpm/lib/rpmds.h    6 Nov 2002 17:28:20 -0000       2.36.2.1
+@@ -232,6 +232,7 @@
+ /**
+  * Set "Don't promote Epoch:" flag.
+  * @param ds          dependency set
++ * @param nopromote   Should an unspecified Epoch: be treated as Epoch: 0?
+  * @return            previous "Don't promote Epoch:" flag
+  */
+ int rpmdsSetNoPromote(/*@null@*/ rpmds ds, int nopromote)
+Index: lib/rpminstall.c
+===================================================================
+RCS file: rpm/lib/rpminstall.c,v
+retrieving revision 1.118.2.5
+retrieving revision 1.118.2.6
+diff -u -u -r1.118.2.5 -r1.118.2.6
+--- rpm/lib/rpminstall.c       31 Aug 2002 22:30:22 -0000      1.118.2.5
++++ rpm/lib/rpminstall.c       9 Oct 2002 19:05:39 -0000       1.118.2.6
+@@ -723,8 +723,7 @@
+ }
+ /*@=bounds@*/
+-int rpmErase(rpmts ts,
+-              const struct rpmInstallArguments_s * ia,
++int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
+               const char ** argv)
+ {
+     int count;
+Index: lib/signature.c
+===================================================================
+RCS file: rpm/lib/signature.c,v
+retrieving revision 2.139.2.7
+retrieving revision 2.139.2.8
+diff -u -u -r2.139.2.7 -r2.139.2.8
+--- rpm/lib/signature.c        17 Sep 2002 15:18:24 -0000      2.139.2.7
++++ rpm/lib/signature.c        9 Oct 2002 19:05:39 -0000       2.139.2.8
+@@ -178,7 +178,7 @@
+     memset(block, 0, sizeof(block));
+     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
+       (void) snprintf(buf, sizeof(buf),
+-              _("sigh size(%d): BAD, read returned %d\n"), sizeof(block), xx);
++              _("sigh size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
+       goto exit;
+     }
+     if (memcmp(block, header_magic, sizeof(header_magic))) {
+@@ -215,7 +215,7 @@
+     dataStart = (unsigned char *) (pe + il);
+     if ((xx = timedRead(fd, (char *)pe, nb)) != nb) {
+       (void) snprintf(buf, sizeof(buf),
+-              _("sigh blob(%d): BAD, read returned %d\n"), nb, xx);
++              _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
+       goto exit;
+     }
+     
+@@ -985,11 +985,11 @@
+     if (size != dig->nbytes) {
+       res = RPMRC_FAIL;
+       t = stpcpy(t, rpmSigString(res));
+-      sprintf(t, " Expected(%d) != (%d)\n", size, dig->nbytes);
++      sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes);
+     } else {
+       res = RPMRC_OK;
+       t = stpcpy(t, rpmSigString(res));
+-      sprintf(t, " (%d)", dig->nbytes);
++      sprintf(t, " (%d)", (int)dig->nbytes);
+     }
+ exit:
+Index: lib/transaction.c
+===================================================================
+RCS file: rpm/lib/transaction.c,v
+retrieving revision 1.274.2.6
+retrieving revision 1.274.2.7
+diff -u -u -r1.274.2.6 -r1.274.2.7
+--- rpm/lib/transaction.c      31 Aug 2002 22:30:22 -0000      1.274.2.6
++++ rpm/lib/transaction.c      25 Oct 2002 17:31:38 -0000      1.274.2.7
+@@ -1018,7 +1018,7 @@
+      * - count files.
+      */
+-rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elments\n"), rpmtsNElements(ts));
++rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
+     ps = rpmtsProblems(ts);
+     /* The ordering doesn't matter here */
+     pi = rpmtsiInit(ts);
+Index: python/_rpmdb.c
+===================================================================
+RCS file: rpm/python/_rpmdb.c,v
+retrieving revision 1.4
+retrieving revision 1.4.2.1
+diff -u -u -r1.4 -r1.4.2.1
+--- rpm/python/_rpmdb.c        7 Jun 2002 13:12:34 -0000       1.4
++++ rpm/python/_rpmdb.c        6 Nov 2002 16:47:02 -0000       1.4.2.1
+@@ -90,9 +90,9 @@
+ /* 40 = 4.0, 33 = 3.3; this will break if the second number is > 9 */
+ #define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR)
+-#define PY_BSDDB_VERSION "3.3.1"
++#define PY_BSDDB_VERSION "3.4.2"
+-static char *rcs_id = "$Id$";
++static char *rcs_id = "$Id$";
+ #ifdef WITH_THREAD
+@@ -410,6 +410,7 @@
+     switch (err) {
+         case 0:                     /* successful, no error */      break;
++#if (DBVER < 41)
+         case DB_INCOMPLETE:
+ #if INCOMPLETE_IS_WARNING
+             strcpy(errTxt, db_strerror(err));
+@@ -429,6 +430,7 @@
+         errObj = DBIncompleteError;
+ #endif
+         break;
++#endif
+         case DB_KEYEMPTY:           errObj = DBKeyEmptyError;       break;
+         case DB_KEYEXIST:           errObj = DBKeyExistError;       break;
+@@ -1023,12 +1025,29 @@
+     secondaryDB->associateCallback = callback;
+     secondaryDB->primaryDBType = _DB_get_type(self);
+-
++    /* PyEval_InitThreads is called here due to a quirk in python 1.5
++     * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
++     * The global interepreter lock is not initialized until the first
++     * thread is created using thread.start_new_thread() or fork() is
++     * called.  that would cause the ALLOW_THREADS here to segfault due
++     * to a null pointer reference if no threads or child processes
++     * have been created.  This works around that and is a no-op if
++     * threads have already been initialized.
++     *  (see pybsddb-users mailing list post on 2002-08-07)
++     */
++    PyEval_InitThreads();
+     MYDB_BEGIN_ALLOW_THREADS;
++#if (DBVER >= 41)
++    err = self->db->associate(self->db, NULL,
++                              secondaryDB->db,
++                              _db_associateCallback,
++                              flags);
++#else
+     err = self->db->associate(self->db,
+                               secondaryDB->db,
+                               _db_associateCallback,
+                               flags);
++#endif
+     MYDB_END_ALLOW_THREADS;
+     if (err) {
+@@ -1498,7 +1517,11 @@
+     }
+     MYDB_BEGIN_ALLOW_THREADS;
++#if (DBVER >= 41)
++    err = self->db->open(self->db, NULL, filename, dbname, type, flags, mode);
++#else
+     err = self->db->open(self->db, filename, dbname, type, flags, mode);
++#endif
+     MYDB_END_ALLOW_THREADS;
+     if (makeDBError(err)) {
+         self->db = NULL;
+@@ -1851,7 +1874,9 @@
+         MAKE_HASH_ENTRY(nkeys);
+         MAKE_HASH_ENTRY(ndata);
+         MAKE_HASH_ENTRY(pagesize);
++#if (DBVER < 41)
+         MAKE_HASH_ENTRY(nelem);
++#endif
+         MAKE_HASH_ENTRY(ffactor);
+         MAKE_HASH_ENTRY(buckets);
+         MAKE_HASH_ENTRY(free);
+@@ -1896,7 +1921,7 @@
+         MAKE_QUEUE_ENTRY(re_len);
+         MAKE_QUEUE_ENTRY(re_pad);
+         MAKE_QUEUE_ENTRY(pgfree);
+-#if (DBVER >= 31) && (DBVER < 40)
++#if (DBVER == 31)
+         MAKE_QUEUE_ENTRY(start);
+ #endif
+         MAKE_QUEUE_ENTRY(first_recno);
+@@ -2334,8 +2359,6 @@
+     if (!PyArg_ParseTuple(args, ":close"))
+         return NULL;
+-    CHECK_CURSOR_NOT_CLOSED(self);
+-
+     if (self->dbc != NULL) {
+         MYDB_BEGIN_ALLOW_THREADS;
+         err = self->dbc->c_close(self->dbc);
+@@ -2424,7 +2447,7 @@
+ static PyObject*
+ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
+ {
+-    int err, flags;
++    int err, flags=0;
+     PyObject* keyobj = NULL;
+     PyObject* dataobj = NULL;
+     PyObject* retval = NULL;
+@@ -3309,7 +3332,7 @@
+     int err;
+     DB_LOCK_STAT* sp;
+     PyObject* d = NULL;
+-    u_int32_t flags;
++    u_int32_t flags = 0;
+     if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags))
+         return NULL;
+@@ -3337,7 +3360,9 @@
+ #define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
++#if (DBVER < 41)
+     MAKE_ENTRY(lastid);
++#endif
+     MAKE_ENTRY(nmodes);
+ #if (DBVER >= 32)
+     MAKE_ENTRY(maxlocks);
+@@ -3421,7 +3446,7 @@
+     int err;
+     DB_TXN_STAT* sp;
+     PyObject* d = NULL;
+-    u_int32_t flags;
++    u_int32_t flags=0;
+     if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
+         return NULL;
+@@ -4116,7 +4141,9 @@
+     ADD_INT(d, DB_APPEND);
+     ADD_INT(d, DB_BEFORE);
+     ADD_INT(d, DB_CACHED_COUNTS);
++#if (DBVER < 41)
+     ADD_INT(d, DB_CHECKPOINT);
++#endif
+ #if (DBVER >= 33)
+     ADD_INT(d, DB_COMMIT);
+ #endif
+@@ -4124,7 +4151,9 @@
+ #if (DBVER >= 32)
+     ADD_INT(d, DB_CONSUME_WAIT);
+ #endif
++#if (DBVER < 41)
+     ADD_INT(d, DB_CURLSN);
++#endif
+     ADD_INT(d, DB_CURRENT);
+ #if (DBVER >= 33)
+     ADD_INT(d, DB_FAST_STAT);
+@@ -4164,7 +4193,9 @@
+     ADD_INT(d, DB_DONOTINDEX);
+ #endif
++#if (DBVER < 41)
+     ADD_INT(d, DB_INCOMPLETE);
++#endif
+     ADD_INT(d, DB_KEYEMPTY);
+     ADD_INT(d, DB_KEYEXIST);
+     ADD_INT(d, DB_LOCK_DEADLOCK);
+Index: python/header-py.c
+===================================================================
+RCS file: rpm/python/header-py.c,v
+retrieving revision 1.20
+retrieving revision 1.20.2.1
+diff -u -u -r1.20 -r1.20.2.1
+--- rpm/python/header-py.c     7 Aug 2002 23:19:10 -0000       1.20
++++ rpm/python/header-py.c     15 Oct 2002 19:03:22 -0000      1.20.2.1
+@@ -336,6 +336,11 @@
+     return rpmVersionCompare(a->h, b->h);
+ }
++static long hdr_hash(hdrObject *h)
++{
++    return h;
++}
++
+ /** \ingroup python
+  */
+ /*@unchecked@*/ /*@observer@*/
+@@ -594,7 +599,7 @@
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       &hdr_as_mapping,                /* tp_as_mapping */
+-      0,                              /* tp_hash */
++      hdr_hash,                       /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       0,                              /* tp_getattro */
+Index: python/rpmdb/__init__.py
+===================================================================
+RCS file: rpm/python/rpmdb/__init__.py,v
+retrieving revision 1.2
+retrieving revision 1.2.2.1
+diff -u -u -r1.2 -r1.2.2.1
+--- rpm/python/rpmdb/__init__.py       3 Jun 2002 20:44:08 -0000       1.2
++++ rpm/python/rpmdb/__init__.py       6 Nov 2002 16:47:02 -0000       1.2.2.1
+@@ -152,7 +152,7 @@
+     flags = _checkflag(flag)
+     d = _db.DB()
+     d.set_flags(hflags)
+-    if cachesize is not None: d.set_cachesize(cachesize)
++    if cachesize is not None: d.set_cachesize(0, cachesize)
+     if pgsize is not None:    d.set_pagesize(pgsize)
+     if lorder is not None:    d.set_lorder(lorder)
+     if ffactor is not None:   d.set_h_ffactor(ffactor)
+@@ -168,7 +168,7 @@
+     flags = _checkflag(flag)
+     d = _db.DB()
+-    if cachesize is not None: d.set_cachesize(cachesize)
++    if cachesize is not None: d.set_cachesize(0, cachesize)
+     if pgsize is not None: d.set_pagesize(pgsize)
+     if lorder is not None: d.set_lorder(lorder)
+     d.set_flags(btflags)
+@@ -186,7 +186,7 @@
+     flags = _checkflag(flag)
+     d = _db.DB()
+-    if cachesize is not None: d.set_cachesize(cachesize)
++    if cachesize is not None: d.set_cachesize(0, cachesize)
+     if pgsize is not None: d.set_pagesize(pgsize)
+     if lorder is not None: d.set_lorder(lorder)
+     d.set_flags(rnflags)
+Index: python/rpmdb/dbshelve.py
+===================================================================
+RCS file: rpm/python/rpmdb/dbshelve.py,v
+retrieving revision 1.2
+retrieving revision 1.2.2.1
+diff -u -u -r1.2 -r1.2.2.1
+--- rpm/python/rpmdb/dbshelve.py       5 Jun 2002 20:28:03 -0000       1.2
++++ rpm/python/rpmdb/dbshelve.py       6 Nov 2002 16:47:02 -0000       1.2.2.1
+@@ -53,7 +53,7 @@
+     if type(flags) == type(''):
+         sflag = flags
+         if sflag == 'r':
+-            flags = db.DB_READONLY
++            flags = db.DB_RDONLY
+         elif sflag == 'rw':
+             flags = 0
+         elif sflag == 'w':
+Index: python/rpmdb/dbtables.py
+===================================================================
+RCS file: rpm/python/rpmdb/dbtables.py,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+diff -u -u -r1.1 -r1.1.2.1
+--- rpm/python/rpmdb/dbtables.py       3 Jun 2002 20:44:08 -0000       1.1
++++ rpm/python/rpmdb/dbtables.py       6 Nov 2002 16:47:02 -0000       1.1.2.1
+@@ -1,6 +1,7 @@
+ #-----------------------------------------------------------------------
+ #
+ # Copyright (C) 2000, 2001 by Autonomous Zone Industries
++# Copyright (C) 2002 Gregory P. Smith
+ #
+ # License:      This is free software.  You may use this software for any
+ #               purpose including modification/redistribution, so long as
+@@ -54,6 +55,13 @@
+     def __call__(self, s):
+         return s[:len(self.prefix)] == self.prefix
++class PostfixCond(Cond):
++    """Acts as a condition function for matching a string postfix"""
++    def __init__(self, postfix):
++        self.postfix = postfix
++    def __call__(self, s):
++        return s[-len(self.postfix):] == self.postfix
++
+ class LikeCond(Cond):
+     """
+     Acts as a function that will match using an SQL 'LIKE' style
+@@ -523,17 +531,10 @@
+                         # if no condition was specified or the condition
+                         # succeeds, add row to our match list.
+                         if not condition or condition(data) :
+-                            # only create new entries in matcing_rowids on
+-                            # the first pass, otherwise reject the
+-                            # rowid as it must not have matched
+-                            # the previous passes
+-                            if column_num == 0 :
+-                                if not matching_rowids.has_key(rowid) :
+-                                    matching_rowids[rowid] = {}
+-                                if savethiscolumndata :
+-                                    matching_rowids[rowid][column] = data
+-                            else :
+-                                rejected_rowids[rowid] = rowid
++                            if not matching_rowids.has_key(rowid) :
++                                matching_rowids[rowid] = {}
++                            if savethiscolumndata :
++                                matching_rowids[rowid][column] = data
+                         else :
+                             if matching_rowids.has_key(rowid) :
+                                 del matching_rowids[rowid]
+Index: python/rpmdb/dbutils.py
+===================================================================
+RCS file: rpm/python/rpmdb/dbutils.py,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+diff -u -u -r1.1 -r1.1.2.1
+--- rpm/python/rpmdb/dbutils.py        3 Jun 2002 20:44:08 -0000       1.1
++++ rpm/python/rpmdb/dbutils.py        6 Nov 2002 16:47:02 -0000       1.1.2.1
+@@ -1,11 +1,5 @@
+ #------------------------------------------------------------------------
+ #
+-# In my performance tests, using this (as in dbtest.py test4) is
+-# slightly slower than simply compiling _db.c with MYDB_THREAD
+-# undefined to prevent multithreading support in the C module.
+-# Using NoDeadlockDb also prevent deadlocks from mutliple processes
+-# accessing the same database.
+-#
+ # Copyright (C) 2000 Autonomous Zone Industries
+ #
+ # License:      This is free software.  You may use this software for any
+@@ -18,7 +12,7 @@
+ # Author: Gregory P. Smith <greg@electricrain.com>
+ #
+ # Note: I don't know how useful this is in reality since when a
+-#       DBDeadlockError happens the current transaction is supposed to be
++#       DBLockDeadlockError happens the current transaction is supposed to be
+ #       aborted.  If it doesn't then when the operation is attempted again
+ #       the deadlock is still happening...
+ #       --Robin
+@@ -36,33 +30,45 @@
+ import _rpmdb as _db
+-_deadlock_MinSleepTime = 1.0/64  # always sleep at least N seconds between retrys
+-_deadlock_MaxSleepTime = 1.0     # never sleep more than N seconds between retrys
++_deadlock_MinSleepTime = 1.0/64   # always sleep at least N seconds between retrys
++_deadlock_MaxSleepTime = 3.14159  # never sleep more than N seconds between retrys
++_deadlock_VerboseFile = None      # Assign a file object to this for a "sleeping"
++                                  # message to be written to it each retry
+ def DeadlockWrap(function, *_args, **_kwargs):
+     """DeadlockWrap(function, *_args, **_kwargs) - automatically retries
+     function in case of a database deadlock.
+-    This is a DeadlockWrapper method which DB calls can be made using to
+-    preform infinite retrys with sleeps in between when a DBLockDeadlockError
+-    exception is raised in a database call:
++    This is a function intended to be used to wrap database calls such
++    that they perform retrys with exponentially backing off sleeps in
++    between when a DBLockDeadlockError exception is raised.
++
++    A 'max_retries' parameter may optionally be passed to prevent it
++    from retrying forever (in which case the exception will be reraised).
+         d = DB(...)
+         d.open(...)
+         DeadlockWrap(d.put, "foo", data="bar")  # set key "foo" to "bar"
+     """
+     sleeptime = _deadlock_MinSleepTime
+-    while (1) :
++    max_retries = _kwargs.get('max_retries', -1)
++    if _kwargs.has_key('max_retries'):
++        del _kwargs['max_retries']
++    while 1:
+         try:
+             return apply(function, _args, _kwargs)
+         except _db.DBLockDeadlockError:
+-            print 'DeadlockWrap sleeping ', sleeptime
++            if _deadlock_VerboseFile:
++                _deadlock_VerboseFile.write('dbutils.DeadlockWrap: sleeping %1.3f\n' % sleeptime)
+             _sleep(sleeptime)
+             # exponential backoff in the sleep time
+             sleeptime = sleeptime * 2
+             if sleeptime > _deadlock_MaxSleepTime :
+                 sleeptime = _deadlock_MaxSleepTime
++            max_retries = max_retries - 1
++            if max_retries == -1:
++                raise
+ #------------------------------------------------------------------------
+Index: python/test/test_dbshelve.py
+===================================================================
+RCS file: rpm/python/test/test_dbshelve.py,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+diff -u -u -r1.1 -r1.1.2.1
+--- rpm/python/test/test_dbshelve.py   3 Jun 2002 20:44:08 -0000       1.1
++++ rpm/python/test/test_dbshelve.py   6 Nov 2002 16:47:02 -0000       1.1.2.1
+@@ -210,7 +210,7 @@
+ class HashShelveTestCase(BasicShelveTestCase):
+-    dbtype = db.DB_BTREE
++    dbtype = db.DB_HASH
+     dbflags = db.DB_CREATE
+@@ -220,7 +220,7 @@
+ class ThreadHashShelveTestCase(BasicShelveTestCase):
+-    dbtype = db.DB_BTREE
++    dbtype = db.DB_HASH
+     dbflags = db.DB_CREATE | db.DB_THREAD
+@@ -261,7 +261,7 @@
+ class EnvHashShelveTestCase(BasicEnvShelveTestCase):
+     envflags = 0
+-    dbtype = db.DB_BTREE
++    dbtype = db.DB_HASH
+     dbflags = db.DB_CREATE
+@@ -273,7 +273,7 @@
+ class EnvThreadHashShelveTestCase(BasicEnvShelveTestCase):
+     envflags = db.DB_THREAD
+-    dbtype = db.DB_BTREE
++    dbtype = db.DB_HASH
+     dbflags = db.DB_CREATE | db.DB_THREAD
+Index: python/test/test_dbtables.py
+===================================================================
+RCS file: rpm/python/test/test_dbtables.py,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+diff -u -u -r1.1 -r1.1.2.1
+--- rpm/python/test/test_dbtables.py   3 Jun 2002 20:44:08 -0000       1.1
++++ rpm/python/test/test_dbtables.py   6 Nov 2002 16:47:02 -0000       1.1.2.1
+@@ -5,6 +5,7 @@
+ #-----------------------------------------------------------------------
+ #
+ # Copyright (C) 2000, 2001 by Autonomous Zone Industries
++# Copyright (C) 2002 Gregory P. Smith
+ #
+ # March 20, 2000
+ #
+@@ -157,6 +158,40 @@
+             conditions={'c': lambda c: c == 'meep'})
+         assert len(values) == 1
+         assert values[0]['b'] == "bad"
++
++
++    def test04_MultiCondSelect(self):
++        tabname = "test04_MultiCondSelect"
++        try:
++            self.tdb.Drop(tabname)
++        except dbtables.TableDBError:
++            pass
++        self.tdb.CreateTable(tabname, ['a', 'b', 'c', 'd', 'e'])
++
++        try:
++            self.tdb.Insert(tabname, {'a': "", 'e': pickle.dumps([{4:5, 6:7}, 'foo'], 1), 'f': "Zero"})
++            assert 0
++        except dbtables.TableDBError:
++            pass
++
++        self.tdb.Insert(tabname, {'a': "A", 'b': "B", 'c': "C", 'd': "D", 'e': "E"})
++        self.tdb.Insert(tabname, {'a': "-A", 'b': "-B", 'c': "-C", 'd': "-D", 'e': "-E"})
++        self.tdb.Insert(tabname, {'a': "A-", 'b': "B-", 'c': "C-", 'd': "D-", 'e': "E-"})
++
++        if verbose:
++            self.tdb._db_print()
++
++        # This select should return 0 rows.  it is designed to test
++        # the bug identified and fixed in sourceforge bug # 590449
++        # (Big Thanks to "Rob Tillotson (n9mtb)" for tracking this down
++        # and supplying a fix!!  This one caused many headaches to say
++        # the least...)
++        values = self.tdb.Select(tabname, ['b', 'a', 'd'],
++            conditions={'e': dbtables.ExactCond('E'),
++                        'a': dbtables.ExactCond('A'),
++                        'd': dbtables.PrefixCond('-')
++                       } )
++        assert len(values) == 0, values
+     def test_CreateOrExtend(self):
+Index: python/test/test_thread.py
+===================================================================
+RCS file: rpm/python/test/test_thread.py,v
+retrieving revision 1.1
+retrieving revision 1.1.2.1
+diff -u -u -r1.1 -r1.1.2.1
+--- rpm/python/test/test_thread.py     3 Jun 2002 20:44:08 -0000       1.1
++++ rpm/python/test/test_thread.py     6 Nov 2002 16:47:02 -0000       1.1.2.1
+@@ -18,7 +18,7 @@
+ import unittest
+ from test_all import verbose
+-from rpmdb import db
++from rpmdb import db, dbutils
+ #----------------------------------------------------------------------
+@@ -31,6 +31,9 @@
+     def setUp(self):
++        if verbose:
++            dbutils._deadlock_VerboseFile = sys.stdout
++
+         homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home')
+         self.homeDir = homeDir
+         try: os.mkdir(homeDir)
+@@ -109,7 +112,7 @@
+         for x in range(start, stop):
+             key = '%04d' % x
+-            d.put(key, self.makeData(key))
++            dbutils.DeadlockWrap(d.put, key, self.makeData(key), max_retries=12)
+             if verbose and x % 100 == 0:
+                 print "%s: records %d - %d finished" % (name, start, x)
+@@ -212,7 +215,7 @@
+         # create a bunch of records
+         for x in xrange(start, stop):
+             key = '%04d' % x
+-            d.put(key, self.makeData(key))
++            dbutils.DeadlockWrap(d.put, key, self.makeData(key), max_retries=12)
+             if verbose and x % 100 == 0:
+                 print "%s: records %d - %d finished" % (name, start, x)
+@@ -221,12 +224,12 @@
+             if random() <= 0.05:
+                 for y in xrange(start, x):
+                     key = '%04d' % x
+-                    data = d.get(key)
++                    data = dbutils.DeadlockWrap(d.get, key, max_retries=12)
+                     assert data == self.makeData(key)
+         # flush them
+         try:
+-            d.sync()
++            dbutils.DeadlockWrap(d.sync, max_retries=12)
+         except db.DBIncompleteError, val:
+             if verbose:
+                 print "could not complete sync()..."
+@@ -234,12 +237,12 @@
+         # read them back, deleting a few
+         for x in xrange(start, stop):
+             key = '%04d' % x
+-            data = d.get(key)
++            data = dbutils.DeadlockWrap(d.get, key, max_retries=12)
+             if verbose and x % 100 == 0:
+                 print "%s: fetched record (%s, %s)" % (name, key, data)
+-            assert data == self.makeData(key)
++            assert data == self.makeData(key), (key, data, self.makeData(key))
+             if random() <= 0.10:
+-                d.delete(key)
++                dbutils.DeadlockWrap(d.delete, key, max_retries=12)
+                 if verbose:
+                     print "%s: deleted record %s" % (name, key)
+@@ -273,7 +276,7 @@
+ class HashSimpleThreaded(SimpleThreadedBase):
+-    dbtype = db.DB_BTREE
++    dbtype = db.DB_HASH
+ #----------------------------------------------------------------------
+Index: rpmdb/db3.c
+===================================================================
+RCS file: rpm/rpmdb/db3.c,v
+retrieving revision 1.45
+retrieving revision 1.45.2.1
+diff -u -u -r1.45 -r1.45.2.1
+--- rpm/rpmdb/db3.c    13 Aug 2002 20:42:39 -0000      1.45
++++ rpm/rpmdb/db3.c    6 Nov 2002 17:29:34 -0000       1.45.2.1
+@@ -266,11 +266,22 @@
+   { int xx;
+     /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
++
++ /* 4.1: dbenv->set_app_dispatch(???) */
++ /* 4.1: dbenv->set_alloc(???) */
++ /* 4.1: dbenv->set_data_dir(???) */
++ /* 4.1: dbenv->set_encrypt(???) */
++
+     dbenv->set_errcall(dbenv, rpmdb->db_errcall);
+     dbenv->set_errfile(dbenv, rpmdb->db_errfile);
+     dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
+     /*@=noeffectuncon@*/
++
++ /* 4.1: dbenv->set_feedback(???) */
++ /* 4.1: dbenv->set_flags(???) */
++
+  /* dbenv->set_paniccall(???) */
++
+     xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
+               (dbi->dbi_verbose & DB_VERB_CHKPOINT));
+     xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
+@@ -279,16 +290,35 @@
+               (dbi->dbi_verbose & DB_VERB_RECOVERY));
+     xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
+               (dbi->dbi_verbose & DB_VERB_WAITSFOR));
+- /* dbenv->set_lg_max(???) */
++
+  /* dbenv->set_lk_conflicts(???) */
+  /* dbenv->set_lk_detect(???) */
+- /* dbenv->set_lk_max(???) */
+-    xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mp_mmapsize);
+-    xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
+-    xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_mp_size, 0);
+-    xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
++ /* 4.1: dbenv->set_lk_max_lockers(???) */
++ /* 4.1: dbenv->set_lk_max_locks(???) */
++ /* 4.1: dbenv->set_lk_max_objects(???) */
++
++ /* 4.1: dbenv->set_lg_bsize(???) */
++ /* 4.1: dbenv->set_lg_dir(???) */
++ /* 4.1: dbenv->set_lg_max(???) */
++ /* 4.1: dbenv->set_lg_regionmax(???) */
++
++    if (dbi->dbi_mmapsize) {
++      xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize);
++      xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
++    }
++    if (dbi->dbi_cachesize) {
++      xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0);
++      xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
++    }
++
++ /* 4.1 dbenv->set_timeout(???) */
+  /* dbenv->set_tx_max(???) */
++ /* 4.1: dbenv->set_tx_timestamp(???) */
+  /* dbenv->set_tx_recover(???) */
++
++ /* dbenv->set_rep_transport(???) */
++ /* dbenv->set_rep_limit(???) */
++
+     if (dbi->dbi_no_fsync) {
+ #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
+       xx = db_env_set_func_fsync(db3_fsync_disable);
+@@ -366,7 +396,11 @@
+     if (db != NULL)
+       rc = db->sync(db, flags);
+     /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
++#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1)
++    _printit = _debug;
++#else
+     _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
++#endif
+     rc = cvtdberr(dbi, "db->sync", rc, _printit);
+     return rc;
+ }
+@@ -599,10 +633,17 @@
+ {
+     DB * db = dbi->dbi_db;
+     DB * secondary = dbisecondary->dbi_db;
++#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1)
++    DB_TXN * txnid = NULL;
++#endif
+     int rc;
+ /*@-moduncon@*/ /* FIX: annotate db3 methods */
++#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1)
++    rc = db->associate(db, txnid, secondary, callback, flags);
++#else
+     rc = db->associate(db, secondary, callback, flags);
++#endif
+ /*@=moduncon@*/
+     rc = cvtdberr(dbi, "db->associate", rc, _debug);
+     return rc;
+@@ -789,6 +830,9 @@
+     DB * db = NULL;
+     DB_ENV * dbenv = NULL;
++#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1)
++    DB_TXN * txnid = NULL;
++#endif
+     u_int32_t oflags;
+     int _printit;
+@@ -981,18 +1025,7 @@
+       /*@=moduncon@*/
+       rc = cvtdberr(dbi, "db_create", rc, _debug);
+       if (rc == 0 && db != NULL) {
+-          if (rc == 0 && dbi->dbi_lorder) {
+-              rc = db->set_lorder(db, dbi->dbi_lorder);
+-              rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
+-          }
+-          if (rc == 0 && dbi->dbi_cachesize) {
+-              rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
+-              rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
+-          }
+-          if (rc == 0 && dbi->dbi_pagesize) {
+-              rc = db->set_pagesize(db, dbi->dbi_pagesize);
+-              rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
+-          }
++
+ /* XXX 3.3.4 change. */
+ #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
+           if (rc == 0 &&
+@@ -1008,6 +1041,27 @@
+               rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
+           }
+ #endif
++
++/* 4.1: db->set_cache_priority(???) */
++          if (rc == 0 && !dbi->dbi_use_dbenv && dbi->dbi_cachesize) {
++              rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
++              rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
++          }
++/* 4.1: db->set_encrypt(???) */
++/* 4.1: db->set_errcall(dbenv, rpmdb->db_errcall); */
++/* 4.1: db->set_errfile(dbenv, rpmdb->db_errfile); */
++/* 4.1: db->set_errpfx(dbenv, rpmdb->db_errpfx); */
++ /* 4.1: db->set_feedback(???) */
++
++          if (rc == 0 && dbi->dbi_lorder) {
++              rc = db->set_lorder(db, dbi->dbi_lorder);
++              rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
++          }
++          if (rc == 0 && dbi->dbi_pagesize) {
++              rc = db->set_pagesize(db, dbi->dbi_pagesize);
++              rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
++          }
++ /* 4.1: db->set_paniccall(???) */
+           if (rc == 0 && oflags & DB_CREATE) {
+               switch(dbi->dbi_type) {
+               default:
+@@ -1042,6 +1096,7 @@
+ #endif
+                   break;
+               case DB_BTREE:
++/* 4.1: db->set_append_recno(???) */
+                   if (dbi->dbi_bt_flags) {
+                       rc = db->set_flags(db, dbi->dbi_bt_flags);
+                       rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
+@@ -1073,6 +1128,7 @@
+                   break;
+               case DB_RECNO:
+                   if (dbi->dbi_re_delim) {
++/* 4.1: db->set_append_recno(???) */
+                       rc = db->set_re_delim(db, dbi->dbi_re_delim);
+                       rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
+                       if (rc) break;
+@@ -1124,8 +1180,13 @@
+                       ? dbfullpath : dbfile;
+ #endif
++#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1)
++              rc = db->open(db, txnid, dbpath, dbsubfile,
++                  dbi->dbi_type, oflags, dbi->dbi_perms);
++#else
+               rc = db->open(db, dbpath, dbsubfile,
+                   dbi->dbi_type, oflags, dbi->dbi_perms);
++#endif
+               if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
+ #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
+Index: rpmdb/dbconfig.c
+===================================================================
+RCS file: rpm/rpmdb/dbconfig.c,v
+retrieving revision 1.33
+retrieving revision 1.33.2.1
+diff -u -u -r1.33 -r1.33.2.1
+--- rpm/rpmdb/dbconfig.c       3 Aug 2002 22:31:39 -0000       1.33
++++ rpm/rpmdb/dbconfig.c       6 Nov 2002 17:29:34 -0000       1.33.2.1
+@@ -190,9 +190,11 @@
+  { "lorder",  0,POPT_ARG_INT,         &db3dbi.dbi_lorder, 0,
+       NULL, NULL },
+- { "mp_mmapsize", 0,POPT_ARG_INT,     &db3dbi.dbi_mp_mmapsize, 0,
++ { "mmapsize", 0,POPT_ARG_INT,                &db3dbi.dbi_mmapsize, 0,
+       NULL, NULL },
+- { "mp_size", 0,POPT_ARG_INT,         &db3dbi.dbi_mp_size, 0,
++ { "mp_mmapsize", 0,POPT_ARG_INT,     &db3dbi.dbi_mmapsize, 0,
++      NULL, NULL },
++ { "mp_size", 0,POPT_ARG_INT,         &db3dbi.dbi_cachesize, 0,
+       NULL, NULL },
+  { "pagesize",        0,POPT_ARG_INT,         &db3dbi.dbi_pagesize, 0,
+       NULL, NULL },
+@@ -259,7 +261,7 @@
+ /** @todo Set a reasonable "last gasp" default db config. */
+ /*@observer@*/ /*@unchecked@*/
+ static const char *db3_config_default =
+-    "db3:hash:mpool:cdb:usecursors:verbose:mp_mmapsize=8Mb:mp_size=512Kb:pagesize=512:perms=0644";
++    "db3:hash:mpool:cdb:usecursors:verbose:mp_mmapsize=8Mb:cachesize=512Kb:pagesize=512:perms=0644";
+ /*@-bounds@*/
+ dbiIndex db3New(rpmdb rpmdb, rpmTag rpmtag)
+@@ -432,8 +434,8 @@
+     if (!dbi->dbi_use_dbenv) {                /* db3 dbenv is always used now. */
+       dbi->dbi_use_dbenv = 1;
+       dbi->dbi_eflags |= (DB_INIT_MPOOL|DB_JOINENV);
+-      dbi->dbi_mp_mmapsize = 16 * 1024 * 1024;
+-      dbi->dbi_mp_size = 1 * 1024 * 1024;
++      dbi->dbi_mmapsize = 16 * 1024 * 1024;
++      dbi->dbi_cachesize = 1 * 1024 * 1024;
+     }
+     if ((dbi->dbi_bt_flags | dbi->dbi_h_flags) & DB_DUP)
+Index: rpmdb/header.c
+===================================================================
+RCS file: rpm/rpmdb/header.c,v
+retrieving revision 1.17.2.11
+retrieving revision 1.17.2.12
+diff -u -u -r1.17.2.11 -r1.17.2.12
+--- rpm/rpmdb/header.c 17 Sep 2002 15:19:45 -0000      1.17.2.11
++++ rpm/rpmdb/header.c 6 Nov 2002 17:29:34 -0000       1.17.2.12
+@@ -2825,6 +2825,7 @@
+     }
+     
+     /*@-branchstate@*/
++    if (data)
+     switch (type) {
+     case RPM_STRING_ARRAY_TYPE:
+       strarray = (const char **)data;
+Index: rpmdb/header.h
+===================================================================
+RCS file: rpm/rpmdb/header.h,v
+retrieving revision 1.6
+retrieving revision 1.6.2.1
+diff -u -u -r1.6 -r1.6.2.1
+--- rpm/rpmdb/header.h 13 Jul 2002 19:10:02 -0000      1.6
++++ rpm/rpmdb/header.h 6 Nov 2002 17:29:34 -0000       1.6.2.1
+@@ -78,7 +78,7 @@
+ /* RPM - Copyright (C) 1995-2001 Red Hat Software */
+ #include <stdio.h>
+-#include <rpmio.h>
++#include "rpmio.h"
+ #ifdef __cplusplus
+ extern "C" {
+@@ -717,7 +717,7 @@
+ }
+ #if !defined(__HEADER_PROTOTYPES__)
+-#include <hdrinline.h>
++#include "hdrinline.h"
+ #endif
+ #ifdef __cplusplus
+Index: rpmdb/rpmdb.h
+===================================================================
+RCS file: rpm/rpmdb/rpmdb.h,v
+retrieving revision 1.46.2.2
+retrieving revision 1.46.2.3
+diff -u -u -r1.46.2.2 -r1.46.2.3
+--- rpm/rpmdb/rpmdb.h  17 Sep 2002 15:19:46 -0000      1.46.2.2
++++ rpm/rpmdb/rpmdb.h  6 Nov 2002 17:29:34 -0000       1.46.2.3
+@@ -8,8 +8,8 @@
+  */
+ #include <assert.h>
+-#include <rpmlib.h>
+-#include <db.h>
++#include "rpmlib.h"
++#include "db.h"
+ /*@-exportlocal@*/
+ /*@unchecked@*/
+@@ -321,8 +321,8 @@
+     int       dbi_region_init;
+     int       dbi_tas_spins;
+       /* mpool sub-system parameters */
+-    int       dbi_mp_mmapsize;        /*!< (10Mb) */
+-    int       dbi_mp_size;    /*!< (128Kb) */
++    int       dbi_mmapsize;   /*!< (10Mb) */
++    int       dbi_cachesize;  /*!< (128Kb) */
+       /* lock sub-system parameters */
+     unsigned int dbi_lk_max;
+     unsigned int dbi_lk_detect;
+@@ -340,7 +340,6 @@
+       /*@modifies fileSystem @*/;
+ #endif
+       /* dbinfo parameters */
+-    int       dbi_cachesize;          /*!< */
+     int       dbi_pagesize;           /*!< (fs blksize) */
+ /*@unused@*/ /*@null@*/
+     void * (*dbi_malloc) (size_t nbytes)
+Index: rpmio/rpmlog.c
+===================================================================
+RCS file: rpm/rpmio/rpmlog.c,v
+retrieving revision 2.27
+retrieving revision 2.27.2.1
+diff -u -u -r2.27 -r2.27.2.1
+--- rpm/rpmio/rpmlog.c 2 Jul 2002 23:54:38 -0000       2.27
++++ rpm/rpmio/rpmlog.c 20 Sep 2002 16:33:49 -0000      2.27.2.1
+@@ -179,6 +179,7 @@
+       else                    /* glibc 2.0 */
+           msgnb *= 2;
+       msgbuf = xrealloc(msgbuf, msgnb);
++      va_end(apc);
+     }
+     msgbuf[msgnb - 1] = '\0';
+     msg = msgbuf;
+Index: rpmio/rpmrpc.c
+===================================================================
+RCS file: rpm/rpmio/rpmrpc.c,v
+retrieving revision 2.27.2.2
+retrieving revision 2.27.2.3
+diff -u -u -r2.27.2.2 -r2.27.2.3
+--- rpm/rpmio/rpmrpc.c 17 Sep 2002 15:19:46 -0000      2.27.2.2
++++ rpm/rpmio/rpmrpc.c 9 Oct 2002 19:06:24 -0000       2.27.2.3
+@@ -1023,7 +1023,7 @@
+       (unsigned)st->st_dev,
+       (unsigned)st->st_ino,
+       st->st_mode,
+-      st->st_nlink,
++      (unsigned)st->st_nlink,
+       st->st_uid,
+       st->st_gid,
+       (unsigned)st->st_rdev,
+Index: tools/sections.c
+===================================================================
+RCS file: rpm/tools/sections.c,v
+retrieving revision 1.1.2.2
+retrieving revision 1.1.2.4
+diff -u -u -r1.1.2.2 -r1.1.2.4
+--- rpm/tools/sections.c       22 Aug 2002 19:19:47 -0000      1.1.2.2
++++ rpm/tools/sections.c       9 Oct 2002 19:06:24 -0000       1.1.2.4
+@@ -24,38 +24,168 @@
+ } UnstripInfo32;
+ typedef struct {
+-  Elf32_Off orig_e_shoff;
+-  Elf32_Off n_sections;
++  Elf64_Off orig_e_shoff;
++  Elf64_Off n_sections;
+   UnstripInfoSection64 sections[1];
+ } UnstripInfo64;
++static uint32_t
++elf_32_to_file (uint32_t x, int file_is_little_endian)
++{
++  volatile uint32_t out;
++  unsigned char *outbytes;
++
++  outbytes = (unsigned char *)&out;
++  if (file_is_little_endian)
++    {
++      outbytes[0] = (x >> 0) & 0xff;
++      outbytes[1] = (x >> 8) & 0xff;
++      outbytes[2] = (x >> 16) & 0xff;
++      outbytes[3] = (x >> 24) & 0xff;
++    }
++  else /* big endian */
++    {
++      outbytes[0] = (x >> 24) & 0xff;
++      outbytes[1] = (x >> 16) & 0xff;
++      outbytes[2] = (x >> 8) & 0xff;
++      outbytes[3] = (x >> 0) & 0xff;
++    }
++  
++  return out;
++}
++
++static uint64_t
++elf_64_to_file (uint64_t x, int file_is_little_endian)
++{
++  volatile uint64_t out;
++  unsigned char *outbytes;
++  int i;
++
++  outbytes = (unsigned char *)&out;
++  if (file_is_little_endian)
++    {
++      for (i = 0; i < 8; i++)
++      outbytes[i] = (x >> (8*i)) & 0xff;
++    }
++  else /* big endian */
++    {
++      for (i = 0; i < 8; i++)
++      outbytes[7-i] = (x >> (8*i)) & 0xff;
++    }
++  
++  return out;
++}
+ static Elf32_Word
+ word32_to_file (Elf32_Word x, Elf *elf)
+ {
+-  /* FIXME: implement */
+-  return x;
++  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
++  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
+ }
+ static Elf32_Off
+ off32_to_file (Elf32_Off x, Elf *elf)
+ {
+-  /* FIXME: implement */
+-  return x;
++  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
++  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
++}
++
++static Elf64_Word
++word64_to_file (Elf64_Word x, Elf *elf)
++{
++  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
++  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
++}
++
++static Elf64_Off
++off64_to_file (Elf64_Off x, Elf *elf)
++{
++  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
++  return elf_64_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
++}
++
++static uint32_t
++elf_32_from_file (uint32_t x, int file_is_little_endian)
++{
++  unsigned char *inbytes;
++
++  inbytes = (unsigned char *)&x;
++  if (file_is_little_endian)
++    {
++      return 
++      (inbytes[0] << 0) |
++      (inbytes[1] << 8) |
++      (inbytes[2] << 16) |
++      (inbytes[3] << 24);
++    }
++  else /* big endian */
++    {
++      return 
++      (inbytes[0] << 24) |
++      (inbytes[1] << 16) |
++      (inbytes[2] << 8) |
++      (inbytes[3] << 0);
++    }
++}
++
++static uint64_t
++elf_64_from_file (uint64_t x, int file_is_little_endian)
++{
++  unsigned char *inbytes;
++
++  inbytes = (unsigned char *)&x;
++  if (file_is_little_endian)
++    {
++      return 
++      ((uint64_t)inbytes[0] << 0) |
++      ((uint64_t)inbytes[1] << 8) |
++      ((uint64_t)inbytes[2] << 16) |
++      ((uint64_t)inbytes[3] << 24) |
++      ((uint64_t)inbytes[4] << 32) |
++      ((uint64_t)inbytes[5] << 40) |
++      ((uint64_t)inbytes[6] << 48) |
++      ((uint64_t)inbytes[7] << 56);
++    }
++  else /* big endian */
++    {
++      return 
++      ((uint64_t)inbytes[0] << 56) |
++      ((uint64_t)inbytes[1] << 48) |
++      ((uint64_t)inbytes[2] << 40) |
++      ((uint64_t)inbytes[3] << 32) |
++      ((uint64_t)inbytes[4] << 24) |
++      ((uint64_t)inbytes[5] << 16) |
++      ((uint64_t)inbytes[6] << 8) |
++      ((uint64_t)inbytes[7] << 0);
++    }
+ }
+ static Elf32_Word
+ word32_from_file (Elf32_Word x, Elf *elf)
+ {
+-  /* FIXME: implement */
+-  return x;
++  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
++  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
+ }
+ static Elf32_Off
+ off32_from_file (Elf32_Off x, Elf *elf)
+ {
+-  /* FIXME: implement */
+-  return x;
++  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
++  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
++}
++
++static Elf64_Word
++word64_from_file (Elf64_Word x, Elf *elf)
++{
++  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
++  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
++}
++
++static Elf64_Off
++off64_from_file (Elf64_Off x, Elf *elf)
++{
++  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
++  return elf_64_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
+ }
+ static void
+@@ -93,7 +223,29 @@
+                       Elf *elf,
+                       Elf_Data *data)
+ {
++  UnstripInfo64 *info64;
++  int i;
++  
+   data->d_align = 8;
++  
++  data->d_size =
++    /* orig_e_shoff */ sizeof (Elf64_Off) +
++    /* n_sections */ sizeof (Elf64_Off) +
++    /* sections */ info->n_sections * sizeof (UnstripInfoSection64);
++
++  data->d_buf = calloc (1, data->d_size);
++
++  info64 = (UnstripInfo64 *) data->d_buf;
++
++  info64->orig_e_shoff = off64_to_file (info->orig_e_shoff, elf);
++  info64->n_sections = off64_to_file (info->n_sections, elf);
++
++  for (i = 0; i < info->n_sections; i++)
++    {
++      info64->sections[i].debug_section = word64_to_file (info->sections[i].debug_section, elf);
++      info64->sections[i].name = word64_to_file (info->sections[i].name, elf);
++      info64->sections[i].orig_offset = off64_to_file (info->sections[i].orig_offset, elf);
++    }
+ }
+ void
+@@ -101,14 +253,21 @@
+                     Elf *elf,
+                     Elf_Data *data)
+ {
++  GElf_Ehdr ehdr;
++  
+   data->d_type = ELF_T_BYTE;
+   data->d_off = 0;
+-  /* FIXME: use right version */
+-  unstrip_info_to_data32 (info, elf, data);
++  gelf_getehdr (elf, &ehdr);
++  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
++    unstrip_info_to_data32 (info, elf, data);
++  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
++    unstrip_info_to_data64 (info, elf, data);
++  else
++    fprintf (stderr, "Warning. unsupported elf class\n");
+ }
+-void
++static void
+ unstrip_info_from_data32 (UnstripInfo *info,
+                         Elf *elf,
+                         Elf_Data *data)
+@@ -130,23 +289,49 @@
+     }
+ }
++static void
++unstrip_info_from_data64 (UnstripInfo *info,
++                        Elf *elf,
++                        Elf_Data *data)
++{
++  UnstripInfo64 *info64;
++  int i;
++  
++  info64 = (UnstripInfo64 *) data->d_buf;
++  
++  info->orig_e_shoff = off64_from_file (info64->orig_e_shoff, elf);
++  info->n_sections = off64_from_file (info64->n_sections, elf);
++
++  info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
++  for (i = 0; i < info->n_sections; i++)
++    {
++      info->sections[i].debug_section = word64_from_file (info64->sections[i].debug_section, elf);
++      info->sections[i].name = word64_from_file (info64->sections[i].name, elf);
++      info->sections[i].orig_offset = off64_from_file (info64->sections[i].orig_offset, elf);
++    }
++}
++
+ UnstripInfo *
+ unstrip_info_from_data (Elf *elf,
+                       Elf_Data *data)
+ {
++  GElf_Ehdr ehdr;
++  
+   UnstripInfo *info;
+   info = malloc (sizeof (UnstripInfo));
+-  /* FIXME: use right version */
+-  unstrip_info_from_data32 (info,
+-                          elf,
+-                          data);
++  gelf_getehdr (elf, &ehdr);
++  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
++    unstrip_info_from_data32 (info, elf, data);
++  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
++    unstrip_info_from_data64 (info, elf, data);
++  else
++    fprintf (stderr, "Warning. unsupported elf class\n");
+   
+   return info;
+ }
+-
+ static void
+ debug_link_to_data32 (DebugLink *debuglink,
+                     Elf *elf,
+@@ -166,23 +351,53 @@
+   data->d_buf = calloc (1, data->d_size);
+   strcpy (data->d_buf, debuglink->filename);
+-  p = data->d_buf + namelen_aligned;
++  p = ((char *)data->d_buf) + namelen_aligned;
+   
+   *(Elf32_Word *)p = word32_to_file (debuglink->checksum, elf);
+-  p += sizeof (Elf32_Word);
++}
++
++static void
++debug_link_to_data64 (DebugLink *debuglink,
++                    Elf *elf,
++                    Elf_Data *data)
++{
++  size_t namelen_aligned;
++  char *p;
++  
++  data->d_align = 4;
++
++  namelen_aligned = align_up (strlen(debuglink->filename) + 1, 4);
++
++  data->d_size =
++    /* name */ namelen_aligned +
++    /* checksum */ sizeof (Elf64_Word);
++
++  data->d_buf = calloc (1, data->d_size);
++
++  strcpy (data->d_buf, debuglink->filename);
++  p = ((char *)data->d_buf) + namelen_aligned;
++  
++  *(Elf64_Word *)p = word64_to_file (debuglink->checksum, elf);
+ }
+ void
+ debug_link_to_data (DebugLink *debuglink, Elf *elf, Elf_Data *data)
+ {
++  GElf_Ehdr ehdr;
++  
+   data->d_type = ELF_T_BYTE;
+   data->d_off = 0;
+-  /* FIXME: use right version */
+-  debug_link_to_data32 (debuglink, elf, data);
++  gelf_getehdr (elf, &ehdr);
++  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
++    debug_link_to_data32 (debuglink, elf, data);
++  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
++    debug_link_to_data64 (debuglink, elf, data);
++  else
++    fprintf (stderr, "Warning. unsupported elf class\n");
+ }
+-void
++static void
+ debug_link_from_data32 (DebugLink *debuglink,
+                       Elf *elf,
+                       Elf_Data *data)
+@@ -194,24 +409,44 @@
+   namelen_aligned = align_up (strlen (debuglink->filename) + 1, 4);
+-  p = data->d_buf + namelen_aligned;
++  p = ((char *)data->d_buf) + namelen_aligned;
+   
+   debuglink->checksum = word32_from_file (*(Elf32_Word *)p, elf);
+-  p += sizeof (Elf32_Word);
++}
++
++static void
++debug_link_from_data64 (DebugLink *debuglink,
++                      Elf *elf,
++                      Elf_Data *data)
++{
++  size_t namelen_aligned;
++  char *p;
++  
++  debuglink->filename = strdup (data->d_buf);
++
++  namelen_aligned = align_up (strlen (debuglink->filename) + 1, 4);
++
++  p = ((char *)data->d_buf) + namelen_aligned;
++  
++  debuglink->checksum = word64_from_file (*(Elf64_Word *)p, elf);
+ }
+ DebugLink *
+ debug_link_from_data (Elf *elf, Elf_Data *data)
+ {
++  GElf_Ehdr ehdr;
+   DebugLink *debuglink;
+   debuglink = malloc (sizeof (DebugLink));
+-  /* FIXME: use right version */
+-  debug_link_from_data32 (debuglink,
+-                        elf,
+-                        data);
++  gelf_getehdr (elf, &ehdr);
++  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
++    debug_link_from_data32 (debuglink, elf, data);
++  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
++    debug_link_from_data64 (debuglink, elf, data);
++  else
++    fprintf (stderr, "Warning. unsupported elf class\n");
+   
+   return debuglink;
+ }
+Index: tools/striptofile.c
+===================================================================
+RCS file: rpm/tools/striptofile.c,v
+retrieving revision 1.1.2.2
+retrieving revision 1.1.2.4
+diff -u -u -r1.1.2.2 -r1.1.2.4
+--- rpm/tools/striptofile.c    22 Aug 2002 19:19:47 -0000      1.1.2.2
++++ rpm/tools/striptofile.c    9 Oct 2002 19:06:24 -0000       1.1.2.4
+@@ -15,7 +15,8 @@
+ int keep_all_section_headers = 1;
+ int add_unstrip_info = 0;
+-void
++#if defined(NhUNUSED)
++static void
+ copy_to_file(Elf *elf, Elf *out_elf)
+ {
+   GElf_Ehdr ehdr;
+@@ -67,8 +68,9 @@
+       }
+     }
+ }
++#endif
+-void
++static void
+ strip_to_file(Elf *elf, Elf *out_elf, DebugLink *debuglink)
+ {
+   GElf_Ehdr ehdr;
+@@ -82,7 +84,8 @@
+   int keep_section;
+   int changed_offsets;
+   GElf_Off last_offset;
+-  int i, debuglink_name;
++  int i;
++  int debuglink_name = 0;
+   elf_flagelf (out_elf, ELF_C_SET, ELF_F_LAYOUT);
+   
+@@ -201,7 +204,7 @@
+   /* Update section header stringtab ref */
+   gelf_getehdr (out_elf, &out_ehdr);
+   out_ehdr.e_shstrndx = section_map[out_ehdr.e_shstrndx];
+-  out_ehdr.e_shoff = align_up (last_offset, 4);
++  out_ehdr.e_shoff = align_up (last_offset, 8);
+   gelf_update_ehdr(out_elf, &out_ehdr);
+   /* Update section header links */
+@@ -220,7 +223,7 @@
+     }
+ }
+-void
++static void
+ copy_debuginfo_to_file(Elf *elf, Elf *out_elf)
+ {
+   GElf_Ehdr ehdr;
+@@ -231,7 +234,7 @@
+   unsigned char *section_strtab;
+   int keep_section;
+   UnstripInfo *info;
+-  int unstripinfo_name;
++  int unstripinfo_name = 0;
+   info = malloc (sizeof (UnstripInfo));
+   
+@@ -402,6 +405,7 @@
+   Elf *elf, *out_elf;
+   int fd, out;
+   const char *origname;
++  char *origname_base;
+   char *debugname, *strippedname;
+   DebugLink *debuglink;
+   poptContext optCon;   /* context for parsing command-line options */
+@@ -433,14 +437,13 @@
+   
+   origname = args[0];
+-  if (output_dir) {
+-    const char * bn = strrchr(origname, '/');
+-    if ((bn = strrchr(origname, '/')) != NULL)
+-      bn++;
+-    else
+-      bn = origname;
+-    debugname = strconcat (output_dir, "/", bn, ".debug", NULL);
+-  } else
++  if (output_dir)
++    {
++      origname_base = path_basename (origname);
++      debugname = strconcat (output_dir, "/", origname_base, ".debug", NULL);
++      free (origname_base);
++    }
++  else
+     debugname = strconcat (origname, ".debug", NULL);
+   
+   strippedname = strconcat (origname, ".XXXXXX", NULL);
+Index: tools/unstripfile.c
+===================================================================
+RCS file: rpm/tools/unstripfile.c,v
+retrieving revision 1.1.2.2
+retrieving revision 1.1.2.3
+diff -u -u -r1.1.2.2 -r1.1.2.3
+--- rpm/tools/unstripfile.c    22 Aug 2002 19:19:47 -0000      1.1.2.2
++++ rpm/tools/unstripfile.c    9 Oct 2002 19:06:24 -0000       1.1.2.3
+@@ -9,7 +9,7 @@
+ #include "debug.h"
+-DebugLink *
++static DebugLink *
+ read_debuglink (Elf *elf)
+ {
+   GElf_Ehdr ehdr;
+@@ -47,7 +47,7 @@
+   return NULL;
+ }
+-Elf_Scn *
++static Elf_Scn *
+ find_section (Elf *elf, const unsigned char *name, const unsigned char *strtab)
+ {
+   Elf_Scn *section;
+@@ -69,7 +69,7 @@
+   return section;
+ }
+-size_t
++static size_t
+ find_in_strtab (char *name, char *strtab, size_t strtab_len)
+ {
+   int name_len, i;
+@@ -82,7 +82,7 @@
+   return 0;
+ }
+-void
++static void
+ unstrip_file (Elf *elf, Elf *debug_elf, Elf *out_elf)
+ {
+   UnstripInfo *info;
+Index: tools/utils.c
+===================================================================
+RCS file: rpm/tools/utils.c,v
+retrieving revision 1.1.2.3
+retrieving revision 1.1.2.4
+diff -u -u -r1.1.2.3 -r1.1.2.4
+--- rpm/tools/utils.c  4 Sep 2002 18:13:35 -0000       1.1.2.3
++++ rpm/tools/utils.c  9 Oct 2002 19:06:24 -0000       1.1.2.4
+@@ -6,7 +6,7 @@
+ #include "debug.h"
+-char *
++static char *
+ my_stpcpy (char       *dest,
+          const char *src)
+ {
+@@ -146,7 +146,7 @@
+   0x2d02ef8d
+ };
+-unsigned int crc32 (unsigned int crc, unsigned char *buf, size_t len)
++static unsigned int crc32 (unsigned int crc, unsigned char *buf, size_t len)
+ {
+   unsigned char *end;
+Index: xmlspec/Makefile
+===================================================================
+RCS file: rpm/xmlspec/Makefile,v
+retrieving revision 1.5.2.2
+retrieving revision 1.5.2.3
+diff -u -u -r1.5.2.2 -r1.5.2.3
+--- rpm/xmlspec/Makefile       28 Aug 2002 10:53:03 -0000      1.5.2.2
++++ rpm/xmlspec/Makefile       10 Oct 2002 22:47:59 -0000      1.5.2.3
+@@ -7,7 +7,9 @@
+ CFLAGS        = -O2 -Wall -Wpointer-arith -Wno-char-subscripts
+ INCDIR        = -I. -I.. -I../build -I../lib -I../misc -I../popt -I../rpmdb -I../rpmio
+ RPMDIR        = ..
+-DESTDIR       = /usr/local
++
++prefix        = /usr
++DESTDIR       = 
+ XMLBUILD      = rpmxmlbuild
+ XMLBUILD_SRC  = rpmxmlbuild.c
+@@ -21,6 +23,7 @@
+ LIBS          = $(XMLLIB) $(RPMDIR)/build/.libs/librpmbuild.a \
+               $(RPMDIR)/lib/.libs/librpm.a $(RPMDIR)/rpmdb/.libs/librpmdb.a \
+               $(RPMDIR)/rpmio/.libs/librpmio.a $(RPMDIR)/popt/.libs/libpopt.a \
++              $(RPMDIR)/libelf/lib/.libs/libelf.a \
+               -lz -lexpat -lbz2
+ LIBDIR        = -L. -L$(RPMDIR)/.libs -L/usr/lib
+@@ -33,9 +36,9 @@
+       $(STRIP) $(XMLBUILD)
+ install:
+-      @(cp $(XMLBUILD) $(DESTDIR)/bin)
+-      @(cp $(XMLLIB) $(DESTDIR)/lib)
+-      @(cp $(XMLLIB_H) $(DESTDIR)/include)
++      @(install -m 755 $(XMLBUILD) $(DESTDIR)$(prefix)/bin)
++      @(install -m 644 $(XMLLIB) $(DESTDIR)$(prefix)/lib)
++      @(install -m 644 $(XMLLIB_H) $(DESTDIR)$(prefix)/include/rpm)
+ $(XMLLIB): $(XMLLIB_OBJ)
+       $(AR) $(ARFLAGS) $(XMLLIB) $(XMLLIB_OBJ)
+Index: xmlspec/XMLAttrs.cpp
+===================================================================
+RCS file: xmlspec/XMLAttrs.cpp
+diff -N xmlspec/XMLAttrs.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLAttrs.cpp   28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,168 @@
++// standard C++ includes
++#include <string>
++
++// standard includes
++#include <string.h>
++
++// our includes
++#include "XMLAttrs.h"
++#include "XMLMisc.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 validateAttr(structValidAttrs& rAttr,
++                                const char* szValue)
++{
++      switch (rAttr.m_nType) {
++              case XATTRTYPE_STRING:
++                      return findStr(rAttr.m_szaMatches, szValue) != -1 ? true : false;
++                      break;
++              case XATTRTYPE_INTEGER:
++                      return isInteger(szValue);
++                      break;
++              case XATTRTYPE_BOOL:
++                      return isBool(szValue);
++                      break;
++              case XATTRTYPE_DATE:
++                      return isDate(szValue);
++                      break;
++              case XATTRTYPE_MAIL:
++                      return isEmail(szValue);
++                      break;
++              case XATTRTYPE_NONE:
++              default:
++                      return true;
++                      break;
++      }
++      return false;
++}
++
++static char* szaTypeDesc[] = { "string",
++                                                         "integer",
++                                                         "bool [Values: true|false]",
++                                                         "date [Format: DDD MMM DD YYYY]",
++                                                         "e-mail" };
++
++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[j].m_bFound = true;
++                              if (!validateAttr(paValids[j], get(i).asString())) {
++                                      char szTmp[1024];
++                                      sprintf(szTmp, "Attribute value '%s' is not a valid %s.",
++                                                                      get(i).asString(), szaTypeDesc[paValids[j].m_nType]);
++                                      pError->setError(szTmp);
++                                      return false;
++                              }
++                              else
++                                      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;
++}
++
++unsigned int getPos(const char* szName,
++                                      XMLAttrs* pAttrs)
++{
++      if (szName) {
++              for (unsigned int i = 0; i < pAttrs->num(); i++) {
++                      if (strcasecmp(szName, pAttrs->get(i).getName()) == 0)
++                              return i;
++              }
++      }
++      return XATTR_END;
++}
++
++const char* XMLAttrs::asString(const char* szName)
++{
++      unsigned int nPos = getPos(szName, this);
++      return (nPos == XATTR_END) ? NULL : get(nPos).asString();
++}
++
++unsigned int XMLAttrs::asInteger(const char* szName)
++{
++      unsigned int nPos = getPos(szName, this);
++      return (nPos == XATTR_END) ? 0 : get(nPos).asInteger();
++}
++
++bool XMLAttrs::asBool(const char* szName)
++{
++      unsigned int nPos = getPos(szName, this);
++      return (nPos == XATTR_END) ? true : get(nPos).asBool();
++}
+Index: xmlspec/XMLAttrs.h
+===================================================================
+RCS file: xmlspec/XMLAttrs.h
+diff -N xmlspec/XMLAttrs.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLAttrs.h     28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,255 @@
++#ifndef _H_XMLATTRS_
++#define _H_XMLATTRS_
++
++// standard C++ includes
++#include <string>
++#include <vector>
++
++// standard C includes
++#include <string.h>
++
++// our includes
++#include "XMLBase.h"
++
++using namespace std;
++
++// definition for the end of the attributes
++#define XATTR_END        0xFFFF
++#define XATTR_NUM_VALSTR 5
++
++enum eAttrType
++{
++      XATTRTYPE_STRING = 0,
++      XATTRTYPE_INTEGER,
++      XATTRTYPE_BOOL,
++      XATTRTYPE_DATE,
++      XATTRTYPE_MAIL,
++      XATTRTYPE_NONE = XATTR_END
++};
++
++struct structValidAttrs
++{
++      unsigned int m_nValue;
++      bool         m_bMandatory;
++      bool         m_bFound;
++      char*        m_szName;
++      unsigned int m_nType;
++      char*        m_szaMatches[XATTR_NUM_VALSTR+1];
++};
++
++// 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 (as string)
++       * .
++       * @param none
++       * @return string containing the attribute value
++       **/
++      const char* asString()
++      {
++              return m_sValue.c_str();
++      }
++
++      /**
++       * Returns the attribute value (as integer)
++       * .
++       * @param none
++       * @return the attribute as an integer
++       **/
++      unsigned int asInteger()
++      {
++              return atoi(m_sValue.c_str());
++      }
++
++      /**
++       * Returns the attribute value as a boolean
++       * .
++       * @param none
++       * @return true if set, false otherwise
++       **/
++      bool asBool()
++      {
++              bool isSet = true;
++              if (strcasecmp(m_sValue.c_str(), "no") == 0 ||
++                      strcasecmp(m_sValue.c_str(), "0") == 0 ||
++                      strcasecmp(m_sValue.c_str(), "false") == 0)
++                      isSet = false;
++              return isSet;
++      }
++
++//
++// 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);
++
++//
++// 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];
++      }
++
++      /**
++       * Returns the attribute as specified by the name
++       * .
++       * @param szName The name of the attribute whose value we are
++       *               to return
++       * @return The attribute as a string
++       **/
++      const char* asString(const char* szName);
++
++      /**
++       * Returns the attribute as specified by the name
++       * .
++       * @param szName The name of the attribute whose value we are
++       *               to return
++       * @return The attribute as an integer
++       **/
++      unsigned int asInteger(const char* szName);
++
++      /**
++       * Returns the attribute as specified by the name
++       * .
++       * @param szName The name of the attribute whose value we are
++       *               to return
++       * @return The attribute as a bool
++       **/
++      bool asBool(const char* szName);
++
++//
++// protected data members
++//
++protected:
++      vector<XMLAttr> m_vAttrs;
++};
++
++#endif
+Index: xmlspec/XMLBase.h
+===================================================================
+RCS file: xmlspec/XMLBase.h
+diff -N xmlspec/XMLBase.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLBase.h      28 Aug 2002 10:52:43 -0000      1.1.1.1.2.1
+@@ -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
+Index: xmlspec/XMLChangelog.cpp
+===================================================================
+RCS file: xmlspec/XMLChangelog.cpp
+diff -N xmlspec/XMLChangelog.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLChangelog.cpp       28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,237 @@
++// standard C++ includes
++#include <string>
++
++// our includes
++#include "XMLChangelog.h"
++#include "XMLMisc.h"
++#include "XMLRPMWrap.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;
++}
++
++bool XMLChangelogEntry::structCreate(const char* szEntries,
++                                                                       XMLSpec* pXSpec)
++{
++      if (!pXSpec || !szEntries)
++              return false;
++      char* szIn = (char*)szEntries;
++      char* szOut = NULL;
++      int nLen = -1;
++      string sChange;
++      while (nLen != 0) {
++              szOut = splitStr(szIn, '\n', nLen);
++              if (strncmp(szIn, "- ", 2) == 0) {
++                      szIn += 2;
++                      nLen -= 2;
++                      if (sChange.length()) {
++                              XMLChangelogEntry change(sChange.c_str());
++                              pXSpec->getChangelog().lastDate().addEntry(change);
++                      }
++                      sChange.assign("");
++              }
++              sChange.append(szIn, nLen);
++              szIn = szOut;
++      }
++      if (sChange.length()) {
++              XMLChangelogEntry change(sChange.c_str());
++              pXSpec->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",         XATTRTYPE_DATE,   {NULL}},
++      {0x0001,    true,  false, "author",       XATTRTYPE_STRING, {"*", NULL}},
++      {0x0002,    false, false, "author-email", XATTRTYPE_MAIL,   {NULL}},
++      {0x0003,    false, false, "version",      XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",          XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLChangelogDate::parseCreate(XMLAttrs* pAttrs,
++                                                                 XMLSpec* pSpec)
++{
++      // validate our attributes
++      if (!pAttrs->validate(g_paChangelogDateAttrs, (XMLBase*)pSpec))
++              return false;
++
++      XMLChangelogDate date(pAttrs->asString("date"),
++                                                pAttrs->asString("author"),
++                                                pAttrs->asString("author-email"),
++                                                pAttrs->asString("version"));
++      pSpec->getChangelog().addDate(date);
++      return true;
++}
++
++bool XMLChangelogDate::structCreate(const char* szDate,
++                                                                      const char* szName,
++                                                                      const char* szEntries,
++                                                                      XMLSpec* pXSpec)
++{
++      if (!szDate || !szName || !szEntries || ! pXSpec)
++              return false;
++      time_t tTime = (time_t)(atol(szDate)) - timezone;
++      struct tm *sTime = gmtime(&tTime);
++      sTime->tm_year += 1900;
++      char szTmp[32];
++      sprintf(szTmp,"%s %s %d %d", g_szaDays[sTime->tm_wday],
++                                                                g_szaMonths[sTime->tm_mon],
++                                                                sTime->tm_mday, sTime->tm_year);
++      XMLChangelogDate date(szTmp, szName, NULL, NULL);
++      pXSpec->getChangelog().addDate(date);
++      XMLChangelogEntry::structCreate(szEntries, pXSpec);
++      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)
++{
++      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)
++{
++      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>";
++}
++
++bool XMLChangelog::structCreate(Spec pSpec,
++                                                              XMLSpec* pXSpec)
++{
++      if (!pXSpec || !pSpec || !pSpec->packages || !pSpec->packages->header)
++              return false;
++      // FIXME: it looks like RPM only stores the tomost date in the
++      // spec file so we are only allowed to get that one instead of an
++      // array of time_t's
++      string sDates;
++      t_StrVector svChanges;
++      t_StrVector svNames;
++      getRPMHeader(pSpec->packages->header, RPMTAG_CHANGELOGTIME, sDates);
++      getRPMHeaderArray(pSpec->packages->header, RPMTAG_CHANGELOGNAME, svNames);
++      getRPMHeaderArray(pSpec->packages->header, RPMTAG_CHANGELOGTEXT, svChanges);
++      for (unsigned int i = 0; i < svNames.size(); i++)
++              XMLChangelogDate::structCreate(sDates.c_str(), svNames[i].c_str(),
++                                                                         svChanges[i].c_str(), pXSpec);
++      return true;
++}
++
++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)
++{
++}
+Index: xmlspec/XMLChangelog.h
+===================================================================
+RCS file: xmlspec/XMLChangelog.h
+diff -N xmlspec/XMLChangelog.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLChangelog.h 28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,458 @@
++#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);
++
++
++      /**
++       * Creates changelog entries from the data provided to us by RPM
++       * @param szEntries The netries we are to evaluate
++       * @param pXSpec pointer to the XML spec we are working with
++       * @return true on success,. false otherwise
++       **/
++      static bool structCreate(const char* szEntries,
++                                                       XMLSpec* pXSpec);
++
++//
++// 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);
++
++      /**
++       * Creates an XMLChangelogDate object from the information provided to
++       * us by RPM
++       * .
++       * @param szDate The date to generate this for
++       * @param szEntries The entries to add to this date
++       * @param pXSpec The XML spec we are working with
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(const char* szDate,
++                                                       const char* szName,
++                                                       const char* szEntries,
++                                                       XMLSpec* pXSpec);
++
++//
++// 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
++{
++//
++// static factory functions
++//
++public:
++      /**
++       * Creates changelog objects from an RPM Spec structure
++       * .
++       * @param pSpec Pointer to the RPM spec
++       * @param pXSpec pointer to the XMLSpec object to populate
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(Spec pSpec,
++                                                       XMLSpec* pXSpec);
++
++//
++// 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
+Index: xmlspec/XMLFiles.cpp
+===================================================================
+RCS file: xmlspec/XMLFiles.cpp
+diff -N xmlspec/XMLFiles.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLFiles.cpp   28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,200 @@
++// standard includes
++#include <stdio.h>
++
++// our includes
++#include "XMLAttrs.h"
++#include "XMLFiles.h"
++#include "XMLPackage.h"
++#include "XMLSpec.h"
++
++// rpm includes
++#include <rpmlib.h>
++#include <stringbuf.h>
++
++using namespace std;
++
++// attribute structure for XMLFile
++structValidAttrs g_paFileAttrs[] =
++{
++      {0x0000,    false, false, "mode",   XATTRTYPE_INTEGER, {NULL}},
++      {0x0001,    false, false, "group",  XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0002,    false, false, "user",   XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0003,    false, false, "config", XATTRTYPE_STRING,  {"noreplace",
++                                                                                                                      "*", NULL}},
++      {XATTR_END, false, false, "end",    XATTRTYPE_NONE,    {NULL}}
++};
++
++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->asString("mode"), pAttrs->asString("user"),
++                               pAttrs->asString("group"), pAttrs->asString("config"), szPath);
++      pSpec->lastPackage().getFiles().addFile(file);
++      return true;
++}
++
++XMLFile::XMLFile(const char* szMode,
++                               const char* szOwner,
++                               const char* szGroup,
++                               const char* szConfig,
++                               const char* szPath)
++      : XMLBase()
++{
++      if (szMode)
++              m_sMode.assign(szMode);
++      if (szOwner)
++              m_sOwner.assign(szOwner);
++      if (szGroup)
++              m_sGroup.assign(szGroup);
++      if (szConfig)
++              m_sConfig.assign(szConfig);
++      if (szPath)
++              m_sPath.assign(szPath);
++}
++
++XMLFile::XMLFile(const XMLFile& rFile)
++      : XMLBase()
++{
++      setMode(rFile.m_sMode.c_str());
++      setOwner(rFile.m_sOwner.c_str());
++      setGroup(rFile.m_sGroup.c_str());
++      setConfig(rFile.m_sConfig.c_str());
++      setPath(rFile.m_sPath.c_str());
++}
++
++XMLFile::~XMLFile()
++{
++}
++
++XMLFile XMLFile::operator=(XMLFile file)
++{
++      setMode(file.m_sMode.c_str());
++      setOwner(file.m_sOwner.c_str());
++      setGroup(file.m_sGroup.c_str());
++      setConfig(file.m_sConfig.c_str());
++      setPath(file.m_sPath.c_str());
++}
++
++void XMLFile::toSpecFile(ostream& rOut)
++{
++      if (hasMode() || hasOwner() || hasGroup()) {
++              rOut << "%attr(";
++              rOut << (hasMode() ? getMode() : "-");
++              rOut << "," << (hasOwner() ? getOwner() : "-");
++              rOut << "," << (hasGroup() ? getGroup() : "-");
++              rOut << ") ";
++      }
++      if (hasConfig()) {
++              rOut << "%config(" << getConfig() << ") ";
++      }
++      rOut << getPath() << endl;
++}
++
++void XMLFile::toXMLFile(ostream& rOut)
++{
++      rOut << endl << "\t\t\t<file";
++      if (hasMode())
++              rOut << " mode=\"" << getMode() << "\"";
++      if (hasOwner())
++              rOut << " user=\"" << getOwner() << "\"";
++      if (hasGroup())
++              rOut << " group=\"" << getGroup() << "\"";
++      if (hasConfig())
++              rOut << " config=\"" << getConfig() << "\"";
++      rOut << ">";
++      rOut << getPath() << "</file>";
++}
++
++// attribute structure for XMLFiles
++structValidAttrs g_paFilesAttrs[] =
++{
++      {0x0000,    false, false, "mode",  XATTRTYPE_INTEGER, {NULL}},
++      {0x0001,    false, false, "group", XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0002,    false, false, "user",  XATTRTYPE_STRING,  {"*", NULL}},
++      {XATTR_END, false, false, "end",   XATTRTYPE_NONE,    {NULL}}
++};
++
++bool XMLFiles::parseCreate(XMLAttrs* pAttrs,
++                                                 XMLSpec* pSpec)
++{
++      if (!pSpec || !pAttrs->validate(g_paFilesAttrs, (XMLBase*)pSpec))
++              return false;
++      pSpec->lastPackage().getFiles().setDefMode(pAttrs->asString("mode"));
++      pSpec->lastPackage().getFiles().setDefOwner(pAttrs->asString("user"));
++      pSpec->lastPackage().getFiles().setDefGroup(pAttrs->asString("group"));
++      return true;
++}
++
++bool XMLFiles::structCreate(PackageStruct* pPackage,
++                                                      Spec pSpec,
++                                                      XMLSpec* pXSpec)
++{
++      if (!pXSpec || !pSpec || !pPackage || !pPackage->fileList)
++              return false;
++      return true;
++}
++
++XMLFiles::XMLFiles()
++      : XMLBase()
++{
++}
++
++XMLFiles::XMLFiles(const XMLFiles& rFiles)
++      : XMLBase()
++{
++      setDefMode(rFiles.m_sMode.c_str());
++      setDefOwner(rFiles.m_sOwner.c_str());
++      setDefGroup(rFiles.m_sGroup.c_str());
++      m_vFiles = rFiles.m_vFiles;
++}
++
++XMLFiles::~XMLFiles()
++{
++}
++
++XMLFiles XMLFiles::operator=(XMLFiles files)
++{
++      setDefMode(files.m_sMode.c_str());
++      setDefOwner(files.m_sOwner.c_str());
++      setDefGroup(files.m_sGroup.c_str());
++      m_vFiles = files.m_vFiles;
++      return *this;
++}
++
++void XMLFiles::toSpecFile(ostream& rOut)
++{
++      if (numFiles()) {
++              if (hasDefMode() || hasDefOwner() || hasDefGroup()) {
++                      rOut << "%defattr(";
++                      rOut << (hasDefMode() ? getDefMode() : "-");
++                      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 (hasDefMode())
++                      rOut << " mode=\"" << getDefMode() << "\"";
++              if (hasDefOwner())
++                      rOut << " user=\"" << getDefOwner() << "\"";
++              if (hasDefGroup())
++                      rOut << " group=\"" << getDefGroup() << "\"";
++              rOut << ">";
++              for (unsigned int i = 0; i < numFiles(); i++)
++                      getFile(i).toXMLFile(rOut);
++              rOut << endl << "\t\t</files>";
++      }
++}
+Index: xmlspec/XMLFiles.h
+===================================================================
+RCS file: xmlspec/XMLFiles.h
+diff -N xmlspec/XMLFiles.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLFiles.h     28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,526 @@
++#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"
++
++// rpm includes
++#include <rpmbuild.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 szMode The file's mode (NULL if default)
++       * @param szOwner The file's owner (NULL if default)
++       * @param szGroup The file's group (NULL if default)
++       * @param szConfig The configuration parameter
++       * @param szPath The file path
++       * @return none
++       **/
++      XMLFile(const char* szMode,
++                      const char* szUser,
++                      const char* szGroup,
++                      const char* szConfig,
++                      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();
++      }
++
++      /**
++       * Sets the file path
++       * .
++       * @param szPath The path to set
++       * @return none
++       **/
++      void setPath(const char* szPath)
++      {
++              if (szPath)
++                      m_sPath.assign(szPath);
++      }
++
++      /**
++       * Checks for a file mode
++       * .
++       * @param none
++       * @return true if we have one, false otherwise
++       **/
++      bool hasMode()
++      {
++              return m_sMode.length() ? true : false;
++      }
++
++      /**
++       * Returns the file mode
++       * .
++       * @param none
++       * @return the mode string
++       **/
++      const char* getMode()
++      {
++              return m_sMode.c_str();
++      }
++
++      /**
++       * Sets the file mode
++       * .
++       * @param szMode The mode to set
++       * @return none
++       **/
++      void setMode(const char* szMode)
++      {
++              if (szMode)
++                      m_sMode.assign(szMode);
++      }
++
++      /**
++       * 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 none
++       * @return the owner as a string
++       **/
++      const char* getOwner()
++      {
++              return m_sOwner.c_str();
++      }
++
++      /**
++       * Sets the file owner
++       * .
++       * @param szOwner The file owner
++       * @return none
++       **/
++      void setOwner(const char* szOwner)
++      {
++              if (szOwner)
++                      m_sOwner.assign(szOwner);
++      }
++
++      /**
++       * 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();
++      }
++
++      /**
++       * Sets the file group
++       * .
++       * @param szGroup The group to set
++       * @return none
++       **/
++      void setGroup(const char* szGroup)
++      {
++              if (szGroup)
++                      m_sGroup.assign(szGroup);
++      }
++
++      /**
++       * Checks for config directives
++       * .
++       * @param none
++       * @return true if we have one, false otherwise
++       **/
++      bool hasConfig()
++      {
++              return m_sConfig.length() ? true : false;
++      }
++
++      /**
++       * Returns the config attribute
++       * .
++       * @param none
++       * @return the sttribute string
++       **/
++      const char* getConfig()
++      {
++              return m_sConfig.c_str();
++      }
++
++      /**
++       * Sets the config attribute
++       * .
++       * @param szConfig The configuration
++       * @return none
++       **/
++      void setConfig(const char* szConfig)
++      {
++              if (szConfig)
++                      m_sConfig.assign(szConfig);
++      }
++
++//
++// member variables
++//
++protected:
++      string m_sPath;
++      string m_sMode;
++      string m_sOwner;
++      string m_sGroup;
++      string m_sConfig;
++};
++
++// <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);
++
++      /**
++       * Creates file objects from an RPM Spec structure
++       * .
++       * @param pPackage Pointer to the package
++       * @param pSpec Pointer to the RPM spec
++       * @param pXSpec pointer to the XMLSpec object to populate
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(PackageStruct* pPackage,
++                                                       Spec pSpec,
++                                                       XMLSpec* pXSpec);
++
++//
++// 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 mode
++       * .
++       * @param none
++       * @return true if we have a default mode, false otherwise
++       **/
++      bool hasDefMode()
++      {
++              return m_sMode.length() ? true : false;
++      }
++
++      /**
++       * Sets the default mode
++       * .
++       * @param szMode The mode value
++       * @return none
++       **/
++      void setDefMode(const char* szMode)
++      {
++              if (szMode)
++                      m_sMode.assign(szMode);
++      }
++
++      /**
++       * Returns the default mode
++       * .
++       * @param none
++       * @return string containing the mode
++       **/
++      const char* getDefMode()
++      {
++              return m_sMode.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_sMode;
++      string          m_sOwner;
++      string          m_sGroup;
++      vector<XMLFile> m_vFiles;
++};
++
++#endif
+Index: xmlspec/XMLMacro.cpp
+===================================================================
+RCS file: xmlspec/XMLMacro.cpp
+diff -N xmlspec/XMLMacro.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMacro.cpp   28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -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", XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",  XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLMacro::parseCreate(XMLAttrs* pAttrs,
++                                                 const char* szMacro,
++                                                 XMLSpec* pSpec)
++{
++      if (!pSpec || !szMacro || !pAttrs->validate(g_paMacroAttrs, (XMLBase*)pAttrs))
++              return false;
++      XMLMacro macro(pAttrs->asString("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>";
++}
+Index: xmlspec/XMLMacro.h
+===================================================================
+RCS file: xmlspec/XMLMacro.h
+diff -N xmlspec/XMLMacro.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMacro.h     28 Aug 2002 10:52:43 -0000      1.1.1.1.2.1
+@@ -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
+Index: xmlspec/XMLMirror.cpp
+===================================================================
+RCS file: xmlspec/XMLMirror.cpp
+diff -N xmlspec/XMLMirror.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMirror.cpp  28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -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",        XATTRTYPE_STRING, {"*", NULL}},
++      {0x0001,    false, false, "description", XATTRTYPE_STRING, {"*", NULL}},
++      {0x0002,    false, false, "country",     XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",         XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLMirror::parseCreate(XMLAttrs* pAttrs,
++                                                      XMLSpec* pSpec,
++                                                      bool bPatch)
++{
++      // validate the attributes
++      if (!pAttrs->validate(g_paMirrorAttrs, (XMLBase*)pSpec))
++              return false;
++
++      XMLMirror mirror(pAttrs->asString("path"),
++                                       pAttrs->asString("description"),
++                                       pAttrs->asString("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 << " />";
++}
+Index: xmlspec/XMLMirror.h
+===================================================================
+RCS file: xmlspec/XMLMirror.h
+diff -N xmlspec/XMLMirror.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMirror.h    28 Aug 2002 10:52:43 -0000      1.1.1.1.2.1
+@@ -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
+Index: xmlspec/XMLMisc.cpp
+===================================================================
+RCS file: xmlspec/XMLMisc.cpp
+diff -N xmlspec/XMLMisc.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMisc.cpp    28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,96 @@
++// standard c includes
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++using namespace std;
++
++char* g_szaDays[]   = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
++char* g_szaMonths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
++                             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
++int g_naLengths[]   = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
++char* g_szaBools[]  = { "no", "yes", "false", "true", "0", "1", NULL };
++
++char* splitStr(const char* szInput,
++                         char cTerm,
++                         int& nLen)
++{
++      nLen = 0;
++      while (szInput[nLen] != cTerm && szInput[nLen] != '\0') {
++              nLen++;
++      }
++      char* szTemp = ((char*)szInput)+nLen;
++      while (*szTemp == cTerm && *szTemp != '\0')
++              szTemp++;
++      return szTemp;
++}
++
++int findStr(char* szaMatches[],
++                      const char* szValue,
++                      int nLen = -1)
++{
++      for (unsigned int i = 0; szaMatches[i] != NULL; i++) {
++              if (strcmp(szaMatches[i], "*") == 0)
++                      return i;
++              else if (nLen == -1) {
++                      if (strcasecmp(szaMatches[i], szValue) == 0)
++                              return i;
++              }
++              else if (strncasecmp(szaMatches[i], szValue, nLen) == 0)
++                      return i;
++      }
++      return -1;
++}
++
++bool isInteger(const char* szValue,
++                         int nLen = -1)
++{
++      if (nLen == -1)
++              nLen = strlen(szValue);
++      for (unsigned int i = 0; i < strlen(szValue); i++) {
++              if (szValue[i] < '0' || szValue[i] > '9')
++                      return false;
++      }
++      return true;
++}
++
++bool isBool(const char* szValue,
++                      int nLen = -1)
++{
++      return findStr(g_szaBools, szValue, nLen) != -1 ? true : false;
++}
++
++bool isDate(const char* szValue)
++{
++      int nLen, nPos;
++      char* szTemp = splitStr(szValue, ' ', nLen);
++      if ((nPos = findStr(g_szaDays, szValue, nLen)) != -1) {
++              if ((nPos = findStr(g_szaMonths, szTemp, nLen)) != -1) {
++                      szTemp = splitStr(szTemp, ' ', nLen);
++                      char* szBuffer = new char[nLen+1];
++                      sprintf(szBuffer, "%s", szTemp);
++                      szBuffer[nLen] = '\0';
++                      if (atoi(szBuffer) <= g_naLengths[nPos]) {
++                              delete[] szBuffer;
++                              szTemp = splitStr(szTemp, ' ', nLen);
++                              return isInteger(szTemp, nLen);
++                      }
++                      delete[] szBuffer;
++              }
++      }
++      return false;
++}
++
++bool isEmail(const char* szValue)
++{
++      bool bFound = false;
++      for (unsigned int j = 0; j < strlen(szValue); j++) {
++              if (szValue[j] == '@') {
++                      if (bFound)
++                              return false;
++                      else
++                              bFound = true;
++              }
++      }
++      return bFound;
++}
+Index: xmlspec/XMLMisc.h
+===================================================================
+RCS file: xmlspec/XMLMisc.h
+diff -N xmlspec/XMLMisc.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLMisc.h      28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,66 @@
++#ifndef _H_XMLMISC_
++#define _H_XMLMISC_
++
++extern char* g_szaDays[];
++extern char* g_szaMonths[];
++
++/**
++ * Splits the input string according to the terminator, returning
++ * the length and the new search position
++ * .
++ * @param szInput The input string
++ * @param cTerm The terminating character
++ * @param nLen the length buffer
++ * @return The next string position
++ **/
++extern char* splitStr(const char* szInput,
++                                        char cTerm,
++                                        int& nLen);
++
++/**
++ * Finds a string in an array of potential matches
++ * .
++ * @param szaMatches The potential matches
++ * @param szValue The value to search for
++ * @return The position on success, -1 if not found
++ **/
++extern int findStr(char* szaMatches[],
++                                 const char* szValue,
++                                 int nLen = -1);
++
++/**
++ * Checks if a string contains an integer
++ * .
++ * @param szValue The string to check
++ * @param nLen The length to check, -1 to end of string
++ * @return true if the string is an integer, false otherwise
++ **/
++extern bool isInteger(const char* szValue,
++                                        int nLen = -1);
++
++/**
++ * Checks if a string contains a boolean value
++ * .
++ * @param szValue The value to check
++ * @return true if we have a boolean, false otherwise
++ **/
++extern bool isBool(const char* szValue,
++                                 int nLen = -1);
++
++/**
++ * Checks if a string is in a valid date format
++ * .
++ * @param szValue The string to check
++ * @return true is this is a date, false otherwise
++ **/
++extern bool isDate(const char* szValue);
++
++/**
++ * Checks if a string contains a valid e-mail address
++ * .
++ * @param szValue the string to check
++ * @return true if this is an email address, false otherwise
++ **/
++extern bool isEmail(const char* szValue);
++
++#endif
+Index: xmlspec/XMLPackage.cpp
+===================================================================
+RCS file: xmlspec/XMLPackage.cpp
+diff -N xmlspec/XMLPackage.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLPackage.cpp 28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,327 @@
++// standard C++ includes
++#include <string>
++
++// our includes
++#include "XMLPackage.h"
++#include "XMLRPMWrap.h"
++#include "XMLSpec.h"
++
++// rpm includes
++#include <rpmlib.h>
++
++// attribute structure for XMLPackage
++structValidAttrs g_paPackageAttrs[] =
++{
++      {0x0000,    false, false, "name",        XATTRTYPE_STRING, {"*", NULL}},
++      {0x0001,    true,  false, "group",       XATTRTYPE_STRING, {"*", NULL}},
++      {0x0002,    false, false, "autoreq",     XATTRTYPE_BOOL,   {NULL}},
++      {0x0003,    false, false, "autoprov",    XATTRTYPE_BOOL,   {NULL}},
++      {0x0004,    false, false, "autoreqprov", XATTRTYPE_BOOL,   {NULL}},
++      {0x0005,    false, false, "sub",         XATTRTYPE_BOOL,   {NULL}},
++      {XATTR_END, false, false, "end",         XATTRTYPE_NONE,   {NULL}}
++};
++
++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->asString("name"))
++              sName.assign(pAttrs->asString("name"));
++
++      // if we have a name, cool, now test if the package already exists
++      if (sName.length()) {
++              XMLPackage package(sName.c_str(), pAttrs->asString("group"),
++                                                 pAttrs->asBool("autoreq") || pAttrs->asBool("autoreqprov"),
++                                                 pAttrs->asBool("autoprov") || pAttrs->asBool("autoreqprov"),
++                                                 pAttrs->asBool("sub"));
++              pSpec->addPackage(package);
++      }
++
++      // already something existing with %{name} ?
++      else {
++              XMLPackage package(NULL, pAttrs->asString("group"),
++                                                 pAttrs->asBool("autoreq") || pAttrs->asBool("autoreqprov"),
++                                                 pAttrs->asBool("autoprov") || pAttrs->asBool("autoreqprov"),
++                                                 pAttrs->asBool("sub"));
++              pSpec->addPackage(package);
++      }
++      return true;
++}
++
++bool XMLPackage::structCreate(PackageStruct* pPackage,
++                                                        Spec pSpec,
++                                                        XMLSpec* pXSpec)
++{
++      if (!pXSpec || !pSpec || !pPackage || !pPackage->header)
++              return false;
++
++      string sGroup, sName;
++      if (!getRPMHeader(pPackage->header, RPMTAG_GROUP, sGroup))
++              return false;
++      getRPMHeader(pPackage->header, RPMTAG_NAME, sName);
++      bool bSub = false;
++      if (sName.compare(pXSpec->getName()) == 0) {
++              bSub = true;
++      }
++
++      XMLPackage package(bSub ? NULL : sName.c_str(), sGroup.c_str(),
++                                         pPackage->autoReq ? true : false,
++                                         pPackage->autoProv ? true : false,
++                                         bSub);
++      t_StrVector svText;
++      t_StrVector svLang;
++      getRPMHeaderArray(pPackage->header, RPMTAG_HEADERI18NTABLE, svLang);
++      if (getRPMHeaderArray(pPackage->header, RPMTAG_SUMMARY, svText)) {
++              for (unsigned int i = 0; i < svText.size(); i++)
++                      package.addSummary(svText[i].c_str(), svLang[i].c_str());
++      }
++      if (getRPMHeaderArray(pPackage->header, RPMTAG_DESCRIPTION, svText)) {
++              for (unsigned int i = 0; i < svText.size(); i++)
++                      package.addDescription(svText[i].c_str(), svLang[i].c_str());
++      }
++      pXSpec->addPackage(package);
++
++      XMLPackageContainer::structCreate(pPackage, pSpec, pXSpec);
++      XMLFiles::structCreate(pPackage, pSpec, pXSpec);
++
++      // do the next package and return
++      XMLPackage::structCreate(pPackage->next, pSpec, pXSpec);
++      return true;
++}
++
++// attribute structure for summaries
++structValidAttrs g_paDescriptionAttrs[] =
++{
++      {0x0000,    false, false, "lang", XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",  XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLPackage::addDescription(XMLAttrs* pAttrs,
++                                                              const char* szDescription,
++                                                              XMLSpec* pSpec)
++{
++      if (pSpec && pAttrs->validate(g_paDescriptionAttrs, (XMLBase*)pSpec)) {
++              pSpec->lastPackage().addDescription(szDescription, pAttrs->asString("lang"));
++              return true;
++      }
++      else
++              return false;
++}
++
++// attribute structure for summaries
++structValidAttrs g_paSummaryAttrs[] =
++{
++      {0x0000,    false, false, "lang", XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",  XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLPackage::addSummary(XMLAttrs* pAttrs,
++                                                      const char* szSummary,
++                                                      XMLSpec* pSpec)
++{
++      if (pSpec && pAttrs->validate(g_paSummaryAttrs, (XMLBase*)pSpec)) {
++              pSpec->lastPackage().addSummary(szSummary, pAttrs->asString("lang"));
++              return true;
++      }
++      else
++              return false;
++}
++
++XMLPackage::XMLPackage(const char* szName,
++                                         const char* szGroup,
++                                         bool bAutoReq,
++                                         bool bAutoProv,
++                                         bool bSub)
++      : XMLBase()
++{
++      setName(szName);
++      setGroup(szGroup);
++      setSubPackage(bSub);
++      setAutoRequires(bAutoReq);
++      setAutoProvides(bAutoProv);
++}
++
++XMLPackage::XMLPackage(const XMLPackage& rPackage)
++      : XMLBase()
++{
++      setName(rPackage.m_sName.c_str());
++      setGroup(rPackage.m_sGroup.c_str());
++      setSubPackage(rPackage.m_bSub);
++      setAutoRequires(rPackage.m_bAutoReq);
++      setAutoProvides(rPackage.m_bAutoProv);
++      m_vSummaries = rPackage.m_vSummaries;
++      m_vDescriptions = rPackage.m_vDescriptions;
++      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;
++
++      for (unsigned int i = 0; i < numSummaries(); i++) {
++              rOut << "summary";
++              if (getSummary(i).hasLang())
++                      rOut << "(" << getSummary(i).getLang() << "):";
++              else
++                      rOut << ":    ";
++              rOut << "    " << getSummary(i).getText() << endl;
++      }
++      if (hasGroup())
++              rOut << "group:          " << getGroup() << endl;
++      if (!hasAutoRequires() && !hasAutoProvides())
++              rOut << "autoreqprov:    no" << endl;
++      else {
++              if (!hasAutoRequires())
++                      rOut << "autoreq:        no" << endl;
++              if (!hasAutoProvides())
++                      rOut << "autoprov:       no" << endl;
++      }
++
++      getProvides().toSpecFile(rOut, "provides");
++      getObsoletes().toSpecFile(rOut, "obsoletes");
++      getRequires().toSpecFile(rOut, "requires");
++      getBuildRequires().toSpecFile(rOut, "buildrequires");
++
++      // add the description
++      for (unsigned int i = 0; i < numDescriptions(); i++) {
++              rOut << "%description ";
++              if (getDescription(i).hasLang())
++                      rOut << "-l " << getDescription(i).getLang() << " ";
++              if (hasName()) {
++                      rOut << (!isSubPackage() ? "-n " : "");
++                      rOut << getName();
++              }
++              rOut << endl << getDescription(i).getText() << 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() << "\"";
++      if (!hasAutoRequires() && !hasAutoProvides())
++              rOut << " autoreqprov=\"no\"";
++      else {
++              if (!hasAutoRequires())
++                      rOut << " autoreq=\"no\"";
++              if (!hasAutoProvides())
++                      rOut << " autoprov=\"no\"";
++      }
++      rOut << ">";
++
++      for (unsigned int i = 0; i < numSummaries(); i++) {
++              rOut << endl << "\t\t<summary";
++              if (getSummary(i).hasLang())
++                      rOut << " lang=\"" << getSummary(i).getLang() << "\"";
++              rOut << ">" << getSummary(i).getText() << "</summary>";
++      }
++      for (unsigned int i = 0; i < numDescriptions(); i++) {
++              rOut << endl << "\t\t<description";
++              if (getDescription(i).hasLang())
++                      rOut << " lang=\"" << getDescription(i).getLang() << "\"";
++              rOut << ">" << getDescription(i).getText() << "</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);
++}
+Index: xmlspec/XMLPackage.h
+===================================================================
+RCS file: xmlspec/XMLPackage.h
+diff -N xmlspec/XMLPackage.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLPackage.h   28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,507 @@
++#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"
++#include "XMLText.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);
++
++      /**
++       * Creates package objects from an RPM Spec structure
++       * .
++       * @param pPackage Pointer to the start package
++       * @param pSpec pointer to the RPM spec
++       * @param pXSpec Pointer to the spec object to populate
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(PackageStruct* pPackage,
++                                                       Spec pSpec,
++                                                       XMLSpec* pXSpec);
++
++      /**
++       * Adds a description for the last package
++       * .
++       * @param pAttrs The attributes
++       * @param szDescription the description
++       * @param pSpec The spec containing the package
++       * @return true on success, false otherwise
++       **/
++      static bool addDescription(XMLAttrs* pAttrs,
++                                                         const char* szDescription,
++                                                         XMLSpec* pSpec);
++
++      /**
++       * Adds the summary for the last added package
++       * .
++       * @param pAttrs The attributes
++       * @param szSummary The summary to set
++       * @param pSpec The spec contraining the package
++       * @return trus on success, false otherwise
++       **/
++      static bool addSummary(XMLAttrs* pAttrs,
++                                                 const char* szSummary,
++                                                 XMLSpec* pSpec);
++
++//
++// constructors/destructors
++//
++public:
++      /**
++       * Default constructor
++       * .
++       * @param szName The package name
++       * @param szGroup The group this package belongs to
++       * @param bAutoReq Auto Requires
++       * @param bAutoProv Auto Provides
++       * @param bSub true if this is a sub-package
++       * @return none
++       **/
++      XMLPackage(const char* szName,
++                         const char* szGroup,
++                         bool bAutoReq,
++                         bool bAutoProv,
++                         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();
++      }
++
++      /**
++       * Sets the package name
++       * .
++       * @param szName The name to set
++       * @return none
++       **/
++      void setName(const char* szName)
++      {
++              if (szName)
++                      m_sName.assign(szName);
++      }
++
++      /**
++       * 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();
++      }
++
++      /**
++       * Sets the group
++       * .
++       * @param szGroup The group to set
++       * @return none
++       **/
++      void setGroup(const char* szGroup)
++      {
++              if (szGroup)
++                      m_sGroup.assign(szGroup);
++      }
++
++      /**
++       * Tests if we are a sub-package
++       * .
++       * @param none
++       * @return true if this is a sub-package
++       **/
++      bool isSubPackage()
++      {
++              return m_bSub;
++      }
++
++      /**
++       * Sets the sub-package status
++       * .
++       * @param bSub The sub-package status
++       * @return none
++       **/
++      void setSubPackage(bool bSub)
++      {
++              m_bSub = bSub;
++      }
++
++      /**
++       * Tests for auto requires
++       * .
++       * @param none
++       * @return true if we have auto requires, false otherwise
++       **/
++      bool hasAutoRequires()
++      {
++              return m_bAutoReq;
++      }
++
++      /**
++       * Sets the auto requires state
++       * .
++       * @param bAutoReq The auto requires state
++       * @return none
++       **/
++      void setAutoRequires(bool bAutoReq)
++      {
++              m_bAutoReq = bAutoReq;
++      }
++
++      /**
++       * Tests for auto requires
++       * .
++       * @param none
++       * @return true if we have auto requires, false otherwise
++       **/
++      bool hasAutoProvides()
++      {
++              return m_bAutoProv;
++      }
++
++      /**
++       * Sets the auto provides status
++       * .
++       * @param bAutoProv The auto provides status
++       * @return none
++       **/
++      void setAutoProvides(bool bAutoProv)
++      {
++              m_bAutoProv = bAutoProv;
++      }
++
++      /**
++       * Gets the number of summaries
++       * .
++       * @param none
++       * @return the number of summaries
++       **/
++      unsigned int numSummaries()
++      {
++              return m_vSummaries.size();
++      }
++
++      /**
++       * Gets a summary
++       * .
++       * @param nNum The number to get
++       * @return the summary
++       **/
++      XMLText& getSummary(unsigned int nNum)
++      {
++              return m_vSummaries[nNum];
++      }
++
++      /**
++       * Adds a summary
++       * .
++       * @param szSummary the summary
++       * @param szLang the language
++       * @return none
++       **/
++      void addSummary(const char* szSummary,
++                                      const char* szLang = NULL)
++      {
++              if (szSummary && strlen(szSummary)) {
++                      XMLText summary(szSummary, szLang);
++                      m_vSummaries.push_back(summary);
++              }
++      }
++
++      /**
++       * Gets the number of descriptions
++       * .
++       * @param none
++       * @return the number in our list
++       **/
++      unsigned int numDescriptions()
++      {
++              return m_vDescriptions.size();
++      }
++
++      /**
++       * Get a description
++       * .
++       * @param nNum The description to get
++       * @return Reference to XMLText object
++       **/
++      XMLText& getDescription(unsigned int nNum)
++      {
++              return m_vDescriptions[nNum];
++      }
++
++      /**
++       * Adds a description
++       * .
++       * @param szDescription The description string
++       * @param szLang The language
++       * @return nonew
++       **/
++      void addDescription(const char* szDescription,
++                                              const char* szLang = NULL)
++      {
++              if (szDescription && strlen(szDescription)) {
++                      XMLText description(szDescription, szLang);
++                      m_vDescriptions.push_back(description);
++              }
++      }
++
++      /**
++       * 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;
++      bool                m_bSub;
++      bool                m_bAutoReq;
++      bool                m_bAutoProv;
++      vector<XMLText>     m_vSummaries;
++      vector<XMLText>     m_vDescriptions;
++      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
+Index: xmlspec/XMLParser.cpp
+===================================================================
+RCS file: xmlspec/XMLParser.cpp
+diff -N xmlspec/XMLParser.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLParser.cpp  28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,982 @@
++// 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_EXCLUDEARCH,
++      XTAG_EXCLUDEOS,
++      XTAG_EXCLUSIVEARCH,
++      XTAG_EXCLUSIVEOS,
++      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_PRE:
++                      if (!XMLPackageScripts::createPreScripts(pData->m_pAttrs, pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to parse 'pre' 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::createPostScripts(pData->m_pAttrs, pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to parse 'pre' 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::createPreUnScripts(pData->m_pAttrs, pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to parse 'pre' 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::createPostUnScripts(pData->m_pAttrs, pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to parse 'pre' 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::createVerifyScripts(pData->m_pAttrs, pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to parse 'pre' 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::addSummary(pData->m_pAttrs, pData->m_sData.c_str(),
++                                                                              pData->m_pSpec))
++                              createError(XMLERR_ERROR, pData,
++                                                      "Failed to add 'summary'.");
++                      break;
++              case XTAG_DESC:
++                      if (!XMLPackage::addDescription(pData->m_pAttrs, 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;
++}
+Index: xmlspec/XMLParser.h
+===================================================================
+RCS file: xmlspec/XMLParser.h
+diff -N xmlspec/XMLParser.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLParser.h    28 Aug 2002 10:52:43 -0000      1.1.1.1.2.1
+@@ -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
+Index: xmlspec/XMLRPMWrap.cpp
+===================================================================
+RCS file: xmlspec/XMLRPMWrap.cpp
+diff -N xmlspec/XMLRPMWrap.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLRPMWrap.cpp 28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,72 @@
++// standard c++ includes
++#include <string>
++#include <vector>
++
++// rpm includes
++#include <rpmlib.h>
++#include <rpmbuild.h>
++
++// type definitions
++typedef vector<string> t_StrVector;
++
++using namespace std;
++
++bool getRPMHeader(Header header,
++                                int_32 nTag,
++                                string& rResult)
++{
++      if (headerIsEntry(header, nTag)) {
++              int_32 nCount, nTagType;
++              void* pBuffer;
++              if (!headerGetEntry(header, nTag, &nTagType, &pBuffer, &nCount))
++                      return false;
++              char szTemp[32];
++              switch (nTagType) {
++                      case RPM_INT32_TYPE:
++                              sprintf(szTemp, "%d", *((int_32*)pBuffer));
++                              rResult.assign(szTemp);
++                      default:
++                              rResult.assign((char*)pBuffer);
++                              break;
++              }
++              headerFreeData(pBuffer, (rpmTagType_e)nTagType);
++              return true;
++      }
++      else
++              return false;
++}
++
++bool getRPMHeaderArray(Header header,
++                                         int_32 nTag,
++                                         t_StrVector& rvResult)
++{
++      rvResult.clear();
++      if (headerIsEntry(header, nTag)) {
++              int_32 nCount, nTagType;
++              void* pBuffer;
++              if (!headerGetEntry(header, nTag, &nTagType, &pBuffer, &nCount))
++                      return false;
++              if (nTagType == RPM_STRING_ARRAY_TYPE || nTagType == RPM_I18NSTRING_TYPE) {
++                      for (int_32 i = 0; i < nCount; i++)
++                              rvResult.push_back(((char**)pBuffer)[i]);
++              }
++              else
++                      rvResult.push_back((char*)pBuffer);
++              headerFreeData(pBuffer, (rpmTagType_e)nTagType);
++              return true;
++      }
++      else
++              return false;
++}
++
++bool getRPMMacro(const char* szMacro,
++                               string& rResult)
++{
++      char* szValue = rpmExpand(szMacro, NULL);
++      if (szValue) {
++              rResult.assign(szValue);
++              return true;
++      }
++      else
++              return false;
++}
+Index: xmlspec/XMLRPMWrap.h
+===================================================================
+RCS file: xmlspec/XMLRPMWrap.h
+diff -N xmlspec/XMLRPMWrap.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLRPMWrap.h   28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,49 @@
++#ifndef _H_XMLRPMWRAP_
++#define _H_XMLRPMWRAP_
++
++// standard C++ includes
++#include <string>
++#include <vector>
++
++// rpm includes
++#include <rpmlib.h>
++
++// type definitions
++typedef vector<string> t_StrVector;
++
++/**
++ * Gets an RPM header after checking that is does exist.
++ * .
++ * @param header The RPM header to interrogate
++ * @param nTag The header tag to extract
++ * @param rResult The string to populate with the result
++ * @return true on success, false otherwise
++ **/
++extern bool getRPMHeader(Header header,
++                                               int_32 nTag,
++                                               std::string& rResult);
++
++/**
++ * Gets an RPM header array into a vector after checking that it
++ * does indeed exist
++ * .
++ * @param header The RPM header to interrogate
++ * @param nTag The header tag to extract
++ * @param rvResult The vector<string> to populate with the result
++ * @return true on success, false otherwise
++ **/
++extern bool getRPMHeaderArray(Header header,
++                                                        int_32 nTag,
++                                                        t_StrVector& rvResult);
++
++/**
++ * Gets a specific RPM macro
++ * .
++ * @param szMacro The macro to get the value of
++ * @param rResult The string to populate with the result
++ * @return true on success, false otherwise
++ **/
++extern bool getRPMMacro(const char* szMacro,
++                                              std::string& rResult);
++
++#endif
+Index: xmlspec/XMLRequires.cpp
+===================================================================
+RCS file: xmlspec/XMLRequires.cpp
+diff -N xmlspec/XMLRequires.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLRequires.cpp        28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,189 @@
++// our includes
++#include "XMLAttrs.h"
++#include "XMLPackage.h"
++#include "XMLRequires.h"
++#include "XMLRPMWrap.h"
++#include "XMLSpec.h"
++
++// rpm includes
++#include <rpmlib.h>
++
++using namespace std;
++
++// attribute structure for XMLPackageEntry
++structValidAttrs g_paEntryAttrs[] =
++{
++      {0x0000,    true,  false, "name",    XATTRTYPE_STRING, {"*", NULL}},
++      {0x0001,    false, false, "version", XATTRTYPE_STRING, {"*", NULL}},
++      {0x0002,    false, false, "cmp",     XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",     XATTRTYPE_NONE,   {NULL}}
++};
++
++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->asString("name"), pAttrs->asString("version"),
++                                                pAttrs->asString("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());
++}
++
++bool XMLPackageContainer::structCreate(PackageStruct* pPackage,
++                                                                         Spec pSpec,
++                                                                         XMLSpec* pXSpec)
++{
++      if (!pXSpec || !pPackage || !pPackage->header)
++              return false;
++      return true;
++}
+Index: xmlspec/XMLRequires.h
+===================================================================
+RCS file: xmlspec/XMLRequires.h
+diff -N xmlspec/XMLRequires.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLRequires.h  28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,327 @@
++#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);
++
++      /**
++       * Adds requires/provides/obsoletes from RPM structures
++       * .
++       * @param pPackage pointer to the RPM package
++       * @param pSpec pointer to the RPM spec
++       * @param pXSpec pointer to the XML spec to populate
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(PackageStruct* pPackage,
++                                                       Spec pSpec,
++                                                       XMLSpec* pXSpec);
++
++//
++// 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
+Index: xmlspec/XMLScript.cpp
+===================================================================
+RCS file: xmlspec/XMLScript.cpp
+diff -N xmlspec/XMLScript.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLScript.cpp  28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,285 @@
++// 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",         XATTRTYPE_STRING, {"*", NULL}},
++      {0x0001,    false, false, "interpreter", XATTRTYPE_STRING, {"*", NULL}},
++      {XATTR_END, false, false, "end",         XATTRTYPE_NONE,   {NULL}}
++};
++
++bool XMLScript::parseCreate(XMLAttrs* pAttrs,
++                                                      const char* szScript,
++                                                      XMLScripts& rContainer)
++{
++      if (!pAttrs->validate(g_paScriptAttrs, (XMLBase*)pAttrs))
++              return false;
++      XMLScript script(szScript,
++                                       pAttrs->asString("interpreter"),
++                                       pAttrs->asString("dir"));
++      rContainer.add(script);
++      return true;
++}
++
++XMLScript::XMLScript(const char* szScript,
++                                       const char* szInterpreter,
++                                       const char* szDir)
++      : XMLBase()
++{
++      if (szScript)
++              m_sValue.assign(szScript);
++      if (szInterpreter)
++              m_sInterpreter.assign(szInterpreter);
++      if (szDir)
++              m_sDir.assign(szDir);
++}
++
++XMLScript::XMLScript(const XMLScript& rScript)
++      : XMLBase()
++{
++      m_sValue.assign(rScript.m_sValue);
++      m_sInterpreter.assign(rScript.m_sInterpreter);
++      m_sDir.assign(rScript.m_sDir);
++}
++
++XMLScript::~XMLScript()
++{
++}
++
++XMLScript XMLScript::operator=(XMLScript script)
++{
++      m_sValue.assign(script.m_sValue);
++      m_sInterpreter.assign(script.m_sInterpreter);
++      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]; // 3 == strlen("cd ")
++              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());
++}
++
++bool XMLPackageScripts::createPreScripts(XMLAttrs* pAttrs,
++                                                                               XMLSpec* pSpec)
++{
++      if (!pSpec)
++              return false;
++      pSpec->lastPackage().getPre().setInterpreter(pAttrs->asString("interpreter"));
++      return true;
++}
++
++bool XMLPackageScripts::createPostScripts(XMLAttrs* pAttrs,
++                                                                                XMLSpec* pSpec)
++{
++      if (!pSpec)
++              return false;
++      pSpec->lastPackage().getPost().setInterpreter(pAttrs->asString("interpreter"));
++      return true;
++}
++
++bool XMLPackageScripts::createPreUnScripts(XMLAttrs* pAttrs,
++                                                                                 XMLSpec* pSpec)
++{
++      if (!pSpec)
++              return false;
++      pSpec->lastPackage().getPreUn().setInterpreter(pAttrs->asString("interpreter"));
++      return true;
++}
++
++bool XMLPackageScripts::createPostUnScripts(XMLAttrs* pAttrs,
++                                                                                      XMLSpec* pSpec)
++{
++      if (!pSpec)
++              return false;
++      pSpec->lastPackage().getPostUn().setInterpreter(pAttrs->asString("interpreter"));
++      return true;
++}
++
++bool XMLPackageScripts::createVerifyScripts(XMLAttrs* pAttrs,
++                                                                                      XMLSpec* pSpec)
++{
++      if (!pSpec)
++              return false;
++      pSpec->lastPackage().getVerify().setInterpreter(pAttrs->asString("interpreter"));
++      return true;
++}
++
++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 << ">";
++      }
++}
+Index: xmlspec/XMLScript.h
+===================================================================
+RCS file: xmlspec/XMLScript.h
+diff -N xmlspec/XMLScript.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLScript.h    28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,519 @@
++#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 szInterpreter The interpreter to use for script execution
++       * @param szDir Directory to execute the script in
++       * @return none
++       **/
++       XMLScript(const char* szScript,
++                         const char* szInterpreter,
++                         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 an interpreter
++       * .
++       * @param none
++       * @return true if we have an interpreter, false otherwise
++       **/
++      bool hasInterpreter()
++      {
++              return m_sInterpreter.length() ? true : false;
++      }
++
++      /**
++       * Gets the interpreter
++       * .
++       * @param none
++       * @return string contating the interpreter
++       **/
++      const char* getInterpreter()
++      {
++              return m_sInterpreter.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_sInterpreter;
++      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:
++      /**
++       * Checks if we have an interpreter
++       * .
++       * @param none
++       * @return true if we have an interpreter, false otherwise
++       **/
++      bool hasInterpreter()
++      {
++              return m_sInterpreter.length() ? true : false;
++      }
++
++      /**
++       * Gets the interpreter
++       * .
++       * @param none
++       * @return string contatining the interpreter
++       **/
++      const char* getInterpreter()
++      {
++              return m_sInterpreter.c_str();
++      }
++
++      /**
++       * Sets the script interpreter
++       * .
++       * @param szInterpreter The interpreter
++       * @return none
++       **/
++      void setInterpreter(const char* szInterpreter)
++      {
++              if (szInterpreter)
++                      m_sInterpreter.assign(szInterpreter);
++      }
++
++      /**
++       * 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:
++      string            m_sInterpreter;
++      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);
++
++      /**
++       * Initialises a pre script container
++       * .
++       * @param pAttrs The XML attributes
++       * @param pSpec The spec to which we are adding
++       * @return true on success, false otherwise
++       **/
++      static bool createPreScripts(XMLAttrs* pAttrs,
++                                                               XMLSpec* pSpec);
++
++      /**
++       * Initialises a post script container
++       * .
++       * @param pAttrs The XML attributes
++       * @param pSpec The spec to which we are adding
++       * @return true on success, false otherwise
++       **/
++      static bool createPostScripts(XMLAttrs* pAttrs,
++                                                                XMLSpec* pSpec);
++
++      /**
++       * Initialises a preun script container
++       * .
++       * @param pAttrs The XML attributes
++       * @param pSpec The spec to which we are adding
++       * @return true on success, false otherwise
++       **/
++      static bool createPreUnScripts(XMLAttrs* pAttrs,
++                                                                 XMLSpec* pSpec);
++
++      /**
++       * Initialises a postun script container
++       * .
++       * @param pAttrs The XML attributes
++       * @param pSpec The spec to which we are adding
++       * @return true on success, false otherwise
++       **/
++      static bool createPostUnScripts(XMLAttrs* pAttrs,
++                                                                      XMLSpec* pSpec);
++
++      /**
++       * Initialises a verify script container
++       * .
++       * @param pAttrs The XML attributes
++       * @param pSpec The spec to which we are adding
++       * @return true on success, false otherwise
++       **/
++      static bool createVerifyScripts(XMLAttrs* pAttrs,
++                                                                      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
+Index: xmlspec/XMLSource.cpp
+===================================================================
+RCS file: xmlspec/XMLSource.cpp
+diff -N xmlspec/XMLSource.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLSource.cpp  28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,339 @@
++// 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,
++                                                       Spec pSpec,
++                                                       XMLSpec* pXSpec)
++{
++      if (!pXSpec || !pSpec || !pSource)
++              return false;
++
++      // 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);
++                      pXSpec->addSource(*pXSource);
++                      if (pMirror)
++                              pXSpec->lastSource().addMirror(*pMirror);
++                      delete pXSource;
++                      break;
++              case RPMBUILD_ISNO:
++                      pXNoSource = new XMLNoSource(pSource->source, pSource->num,
++                                                                               NULL, NULL, NULL);
++                      pXSpec->addNoSource(*pXNoSource);
++                      if (pMirror)
++                              pXSpec->lastNoSource().addMirror(*pMirror);
++                      delete pXNoSource;
++                      break;
++              case RPMBUILD_ISPATCH:
++                      pXPatch = new XMLPatch(pSource->source, pSource->num, NULL, NULL);
++                      pXSpec->addPatch(*pXPatch);
++                      if (pMirror)
++                              pXSpec->lastPatch().addMirror(*pMirror);
++                      delete pXPatch;
++                      break;
++              default:
++                      break;
++      }
++      if (pMirror)
++              delete pMirror;
++
++      // do the next source and return
++      XMLSource::structCreate(pSource->next, pSpec, pXSpec);
++      return true;
++}
++
++// attribute structure for XMLSource
++structValidAttrs g_paSourceAttrs[] =
++{
++      {0x0000,    true,  false, "name", XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0001,    false, false, "num",  XATTRTYPE_INTEGER, {NULL}},
++      {0x0002,    false, false, "dir",  XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0003,    false, false, "size", XATTRTYPE_INTEGER, {NULL}},
++      {0x0004,    false, false, "md5",  XATTRTYPE_STRING,  {"*", NULL}},
++      {XATTR_END, false, false, "end",  XATTRTYPE_NONE,    {NULL}}
++};
++
++bool XMLSource::parseCreate(XMLAttrs* pAttrs,
++                                                      XMLSpec* pSpec)
++{
++      // validate the attributes
++      if (!pAttrs->validate(g_paSourceAttrs, (XMLBase*)pSpec))
++              return false;
++
++      XMLSource source(pAttrs->asString("name"), pAttrs->asInteger("num"),
++                                       pAttrs->asString("dir"), pAttrs->asString("size"),
++                                       pAttrs->asString("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;
++
++      XMLNoSource source(pAttrs->asString("name"), pAttrs->asInteger("num"),
++                                         pAttrs->asString("dir"), pAttrs->asString("size"),
++                                         pAttrs->asString("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", XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0001,    false, false, "num",  XATTRTYPE_INTEGER, {NULL}},
++      {0x0002,    false, false, "size", XATTRTYPE_INTEGER, {NULL}},
++      {0x0003,    false, false, "md5",  XATTRTYPE_STRING,  {"*", NULL}},
++      {XATTR_END, false, false, "end",  XATTRTYPE_NONE,    {NULL}}
++};
++
++bool XMLPatch::parseCreate(XMLAttrs* pAttrs,
++                                                 XMLSpec* pSpec)
++{
++      // validate the attributes
++      if (!pAttrs->validate(g_paPatchAttrs, (XMLBase*)pSpec))
++              return false;
++
++      XMLPatch patch(pAttrs->asString("name"), pAttrs->asInteger("num"),
++                                 pAttrs->asString("size"), pAttrs->asString("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;
++}
+Index: xmlspec/XMLSource.h
+===================================================================
+RCS file: xmlspec/XMLSource.h
+diff -N xmlspec/XMLSource.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLSource.h    28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,454 @@
++#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 pSource Pointer to a list of sources
++       * @param pSpec pointer to the RPM spec
++       * @param pSpec pointer to our spec object
++       * @return true on success, false otherwise
++       **/
++      static bool structCreate(Source* pSource,
++                                                       Spec pSpec,
++                                                       XMLSpec* pXSpec);
++
++      /**
++       * 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
+Index: xmlspec/XMLSpec.cpp
+===================================================================
+RCS file: xmlspec/XMLSpec.cpp
+diff -N xmlspec/XMLSpec.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLSpec.cpp    28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,252 @@
++// 3rd party includes
++#include <expat.h>
++
++// our includes
++#include "XMLAttrs.h"
++#include "XMLRPMWrap.h"
++#include "XMLSpec.h"
++
++// rpm includes
++#include <rpmlib.h>
++
++using namespace std;
++
++// attribute structure for XMLSpec
++structValidAttrs g_paSpecAttrs[] =
++{
++      {0x0000,    true,  false, "name",           XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0001,    true,  false, "version",        XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0002,    true,  false, "release",        XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0003,    false, false, "epoch",          XATTRTYPE_INTEGER, {NULL}},
++      {0x0004,    false, false, "distribution",   XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0005,    false, false, "vendor",         XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0006,    false, false, "packager",       XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0007,    false, false, "packager-email", XATTRTYPE_MAIL,    {"*", NULL}},
++      {0x0008,    false, false, "copyright",      XATTRTYPE_STRING,  {"*", NULL}},
++      {0x0009,    false, false, "url",            XATTRTYPE_STRING,  {"*", NULL}},
++      {0x000A,    false, false, "buildroot",      XATTRTYPE_STRING,  {"*", NULL}},
++      {XATTR_END, false, false, "end",            XATTRTYPE_NONE,    {NULL}}
++};
++
++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->asString("name"),
++                                         pAttrs->asString("version"),
++                                         pAttrs->asString("release"),
++                                         pAttrs->asString("epoch"),
++                                         pAttrs->asString("distribution"),
++                                         pAttrs->asString("vendor"),
++                                         pAttrs->asString("packager"),
++                                         pAttrs->asString("packager-email"),
++                                         pAttrs->asString("copyright"),
++                                         pAttrs->asString("url"),
++                                         pAttrs->asString("buildroot"));
++}
++
++XMLSpec* XMLSpec::structCreate(Spec pSpec)
++{
++      if (!pSpec || !pSpec->packages || !pSpec->packages->header)
++              return NULL;
++
++      // create the spec with values from the RPM stuff
++      string sName, sVersion, sRelease, sEpoch, sDistro;
++      string sVendor, sPackager, sMail, sLicense, sURL;
++      if (!getRPMHeader(pSpec->packages->header, RPMTAG_NAME, sName) ||
++              !getRPMMacro("PACKAGE_VERSION", sVersion) ||
++              !getRPMMacro("PACKAGE_RELEASE", sRelease))
++              return NULL;
++      getRPMHeader(pSpec->packages->header, RPMTAG_EPOCH, sEpoch);
++      getRPMHeader(pSpec->packages->header, RPMTAG_DISTRIBUTION, sDistro);
++      getRPMHeader(pSpec->packages->header, RPMTAG_VENDOR, sVendor);
++      getRPMHeader(pSpec->packages->header, RPMTAG_PACKAGER, sPackager);
++      getRPMHeader(pSpec->packages->header, RPMTAG_LICENSE, sLicense);
++      getRPMHeader(pSpec->packages->header, RPMTAG_URL, sURL);
++      XMLSpec* pXSpec = new XMLSpec(pSpec->specFile, sName.c_str(), sVersion.c_str(),
++                                                                sRelease.c_str(), sEpoch.c_str(), sDistro.c_str(),
++                                                                sVendor.c_str(), sPackager.c_str(), sMail.c_str(),
++                                                                sLicense.c_str(), sURL.c_str(), pSpec->buildRootURL);
++
++      // add sources, packages all kinds of funny stuff
++      XMLChangelog::structCreate(pSpec, pXSpec);
++      XMLSource::structCreate(pSpec->sources, pSpec, pXSpec);
++      XMLPackage::structCreate(pSpec->packages, pSpec, pXSpec);
++
++      // return the created spec
++      return pXSpec;
++}
++
++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;
++}
+Index: xmlspec/XMLSpec.h
+===================================================================
+RCS file: xmlspec/XMLSpec.h
+diff -N xmlspec/XMLSpec.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLSpec.h      28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -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 pSpec The RPM spec structure
++       * @return Pointer to the created spec
++       **/
++      static XMLSpec* structCreate(Spec pSpec);
++
++//
++// 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
+Index: xmlspec/XMLText.cpp
+===================================================================
+RCS file: xmlspec/XMLText.cpp
+diff -N xmlspec/XMLText.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLText.cpp    28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,23 @@
++// our includes
++#include "XMLText.h"
++
++using namespace std;
++
++XMLText::XMLText(const char* szText,
++                               const char* szLang)
++      : XMLBase()
++{
++      setText(szText);
++      setLang(szLang);
++}
++
++XMLText::XMLText(const XMLText& rText)
++      : XMLBase()
++{
++      setText(rText.m_sText.c_str());
++      setLang(rText.m_sLang.c_str());
++}
++
++XMLText::~XMLText()
++{
++}
+Index: xmlspec/XMLText.h
+===================================================================
+RCS file: xmlspec/XMLText.h
+diff -N xmlspec/XMLText.h
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/XMLText.h      28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,119 @@
++#ifndef _H_XMLTEXT_
++#define _H_XMLTEXT_
++
++// standard c++ includes
++#include <string>
++
++// our includes
++#include "XMLBase.h"
++
++using namespace std;
++
++class XMLText : public XMLBase
++{
++//
++// constructors/destructor
++//
++public:
++      /**
++       * Default constructor
++       * .
++       * @param szText The text to add
++       * @param szLang The text's language
++       * @return none
++       **/
++      XMLText(const char* szText,
++                      const char* szLang = NULL);
++
++      /**
++       * Copy constructor
++       * .
++       * @param rText reference to the text to copy
++       * @return none
++       **/
++      XMLText(const XMLText& rText);
++
++      /**
++       * Default destructor
++       * .
++       * @param none
++       * @return none
++       **/
++      ~XMLText();
++
++//
++// get/set methods for internal variables
++//
++public:
++      /**
++       * Sets the text
++       * .
++       * @param szText The text
++       * @return none
++       **/
++      void setText(const char* szText)
++      {
++              if (szText)
++                      m_sText.assign(szText);
++      }
++
++      /**
++       * Gets the text
++       * .
++       * @param none
++       * @return string containing the text
++       **/
++      const char* getText()
++      {
++              return m_sText.c_str();
++      }
++
++      /**
++       * Tests if we have a language for this description
++       * .
++       * @param none
++       * @return true if we have a language, false otherwise
++       **/
++      bool hasLang()
++      {
++              return m_sLang.length() ? true : false;
++      }
++
++      /**
++       * Sets the language
++       * .
++       * @param szLang The language
++       * @return none
++       **/
++      void setLang(const char* szLang)
++      {
++              if (szLang) {
++                      // FIXME: We need to get the actual default language as specified
++                      // in one of the RPM headers (which I cannot find now) and
++                      // substitute it here. (I know the value is "C", bu we should
++                      // use the define.)
++                      if (strcmp(szLang, "C") != 0)
++                              m_sLang.assign(szLang);
++              }
++      }
++
++      /**
++       * Gets the language
++       * .
++       * @param none
++       * @return string containing the language
++       **/
++      const char* getLang()
++      {
++              return m_sLang.c_str();
++      }
++
++//
++// member variables
++//
++public:
++      string m_sText;
++      string m_sLang;
++};
++
++#endif
+Index: xmlspec/example.spec.xml
+===================================================================
+RCS file: xmlspec/example.spec.xml
+diff -N xmlspec/example.spec.xml
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/example.spec.xml       28 Aug 2002 10:52:43 -0000      1.3.2.1
+@@ -0,0 +1,188 @@
++<?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="06"
++        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>
++              <summary lang="af">Hierdie is net 'n toets vir i18n in die opsomming</summary>
++              <description>%{summary}</description>
++              <description lang="af">Nog 'n toets, hierdie keer in die beskrywing</description>
++               <post>
++                      <script interpreter="/bin/sh">/sbin/ldconfig</script>
++              </post>
++              <postun>
++                      <script>/sbin/ldconfig</script>
++              </postun>
++              <files>
++                      <file user="root" group="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 user="root"
++                              group="root">
++                      <file>/usr/include/*.h</file>
++                      <file group="rpm">/usr/lib/*.la</file>
++                      <file user="rpm">/usr/share/aclocal/*</file>
++                      <file mode="777">/usr/share/m4/*</file>
++                      <file user="user" group="group" mode="444">/usr/share/man/*</file>
++              </files>
++      </package>
++
++      <package name="toys" sub="no" group="Application/Toys">
++              <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="Wed Jun 05 2002"
++                               author="Jaco Greeff"
++                               author-email="jaco@puxedo.org"
++                               version="1.0-06">
++                      <change>Changed spec to make sure the output spec file can be understood by RPM</change>
++                      <change>Added languages (description/summary) and a test in Afrikaans</change>
++              </changes>
++              <changes date="Mon Jun 03 2002"
++                               author="Jaco Greeff"
++                               author-email="jaco@puxedo.org"
++                               version="1.0-05">
++                      <change>Changed file attributes to mode, user and group</change>
++              </changes>
++              <changes date="Thu May 30 2002"
++                               author="Jaco Greeff"
++                               author-email="jaco@puxedo.org"
++                               version="1.0-04">
++                      <change>Added attribute &quot;interpreter&quot; to script</change>
++              </changes>
++              <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>
+Index: xmlspec/spec2xml.cpp
+===================================================================
+RCS file: xmlspec/spec2xml.cpp
+diff -N xmlspec/spec2xml.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/spec2xml.cpp   28 Aug 2002 10:52:43 -0000      1.1.2.1
+@@ -0,0 +1,62 @@
++// standard C++ includes
++#include <fstream>
++
++// our includes
++#include "XMLSpec.h"
++
++// rpm includes
++#include <rpmbuild.h>
++
++// display some usage
++int usage()
++{
++              printf("Usage: spec2xml input [output]\n");
++              printf("Converts the input pkg.spec file to a pkg.spec.xml\n");
++              printf("file for use in an rpmbuild command.\n\n");
++              return 1;
++}
++
++// program entry point
++int main(int argc,
++               char** argv)
++{
++      printf("\nspec2xml, version 0.01\n");
++      if (argc != 2 && argc != 3) {
++              usage();
++              return 1;
++      }
++
++      Spec pSpec = NULL;
++      printf("Parsing RPM spec %s:\n", argv[1]);
++      if (!parseSpec(&pSpec, argv[1], "/", "/var/tmp", 0, NULL, NULL, 1, 0)) {
++              printf("\tOk, spec parsed.\n");
++              printf("Creating XML structures:\n");
++              XMLSpec* pXSpec = XMLSpec::structCreate(pSpec);
++              if (pXSpec) {
++                      printf("\tOk, structures created.\n");
++                      if (argc == 3) {
++                              printf("Writing XML to %s ... ", argv[2]);
++                              ofstream fOut(argv[2]);
++                              if (fOut.is_open()) {
++                                      pXSpec->toXMLFile(fOut);
++                                      fOut.close();
++                                      printf("Ok.\n");
++                              }
++                              else {
++                                      delete pSpec;
++                                      printf("Failed.\n");
++                                      return 2;
++                              }
++                      }
++                      else if (argc == 2) {
++                              pXSpec->toXMLFile(cout);
++                      }
++
++                      delete pSpec;
++                      return 0;
++              }
++      }
++
++      printf("\tFailed.\n");
++      return 3;
++}
+Index: xmlspec/xml2rpm.c
+===================================================================
+RCS file: rpm/xmlspec/xml2rpm.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.2
+diff -u -u -r1.2.2.1 -r1.2.2.2
+--- rpm/xmlspec/xml2rpm.c      28 Aug 2002 10:52:43 -0000      1.2.2.1
++++ rpm/xmlspec/xml2rpm.c      10 Oct 2002 22:47:59 -0000      1.2.2.2
+@@ -8,6 +8,10 @@
+ #include "xml2rpm.h"
+ #include "xmlstruct.h"
++#ifdef XML_DEBUG
++#include "header_internal.h"
++#endif
++
+ // This is where our packaged scripts start (or the largest number
+ // of the sources)
+ int g_nMaxSourceNum = 511;
+@@ -304,8 +308,14 @@
+                               createRPMSource(pScript->m_szScript, g_nMaxSourceNum+1,
+                                               pSpec, RPMBUILD_ISSOURCE);
+                       }
+-                      if (pScript->m_szEntry)
+-                              appendLineStringBuf(pSb, pScript->m_szEntry);
++                      if (pScript->m_szEntry) {
++                              // we do a newStrEx to make sure we expand all
++                              // macros, as is done in the case of the files
++                              // (done as part of the fileToStr call)
++                              newStrEx(pScript->m_szEntry, (char**)(&szTmp));
++                              appendLineStringBuf(pSb, szTmp);
++                              freeStr(&(szTmp));
++                      }
+                       pScript = pScript->m_pNext;
+               }
+       }
+@@ -335,6 +345,32 @@
+                              pScripts->m_szInterpreter, 1);
+ }
++void handleProvObsConf(Header pHeader, t_structXMLRequire* pReqs, rpmsenseFlags fSense)
++{
++      t_structXMLRequire* pReq = NULL;
++      int nFlags = 0;
++      int i = 0;
++      int nIndex = 0;
++
++      pReq = pReqs;
++      while (pReq) {
++              if (pReq->m_szName) {
++                      nFlags = 0;
++                      if (pReq->m_szCompare && pReq->m_szVersion) {
++                              for (i = 0; sReqComp[i].m_szCmp; i++) {
++                                      if (!strcasecmp(sReqComp[i].m_szCmp,
++                                          pReq->m_szCompare)) {
++                                              nFlags = (sReqComp[i].m_rpmCmp | RPMSENSE_ANY) & ~RPMSENSE_SENSEMASK;
++                                      }
++                              }
++                      }
++                      addReqProv(NULL, pHeader, fSense | nFlags,
++                                 pReq->m_szName, pReq->m_szVersion, nIndex++);
++              }
++              pReq = pReq->m_pNext;
++      }
++}
++
+ void convertXMLPackage(const t_structXMLPackage* pXMLPkg,
+                      const t_structXMLSpec* pXMLSpec,
+                      Spec pSpec)
+@@ -364,6 +400,11 @@
+       _free(szArch);
+       _free(szOs);
++      // do the provides, obsoletes, conflicts
++      handleProvObsConf(pPkg->header, pXMLPkg->m_pProvides, RPMSENSE_PROVIDES);
++      handleProvObsConf(pPkg->header, pXMLPkg->m_pObsoletes, RPMSENSE_OBSOLETES);
++      handleProvObsConf(pPkg->header, pXMLPkg->m_pConflicts, RPMSENSE_CONFLICTS);
++
+       if (pXMLPkg->m_szName)
+               headerAddOrAppendEntry(pPkg->header, RPMTAG_NAME,
+                                      RPM_STRING_TYPE, pXMLPkg->m_szName, 1);
+@@ -514,7 +555,7 @@
+       pSpec->build = scriptsToStringBuf(pXMLSpec->m_pBuild, pSpec);
+       pSpec->install = scriptsToStringBuf(pXMLSpec->m_pInstall, pSpec);
+       pSpec->clean = scriptsToStringBuf(pXMLSpec->m_pClean, pSpec);
+-      
++
+       convertXMLPackage(pXMLSpec->m_pPackages, pXMLSpec, pSpec);
+       initSourceHeader(pSpec);
+Index: xmlspec/xml2spec.cpp
+===================================================================
+RCS file: xmlspec/xml2spec.cpp
+diff -N xmlspec/xml2spec.cpp
+--- /dev/null  1 Jan 1970 00:00:00 -0000
++++ rpm/xmlspec/xml2spec.cpp   28 Aug 2002 10:52:43 -0000      1.2.2.1
+@@ -0,0 +1,52 @@
++// 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)
++{
++      printf("\nxml2spec, version 0.01\n");
++      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);
++              }
++
++              delete pSpec;
++              return 0;
++      }
++
++      return 3;
++}
+Index: xmlspec/xmlparse.c
+===================================================================
+RCS file: rpm/xmlspec/xmlparse.c,v
+retrieving revision 1.1.2.1
+retrieving revision 1.1.2.2
+diff -u -u -r1.1.2.1 -r1.1.2.2
+--- rpm/xmlspec/xmlparse.c     28 Aug 2002 10:52:43 -0000      1.1.2.1
++++ rpm/xmlspec/xmlparse.c     10 Oct 2002 22:47:59 -0000      1.1.2.2
+@@ -43,7 +43,15 @@
+                       addXMLMacro(pParse->m_pAttrs, &(pSpec->m_pMacros));
+                       break;
+               case TAGVAL_SOURCE:
+-                      addXMLSource(pParse->m_pAttrs, &(pSpec->m_pSources));
++                      if (pSpec->m_pSources)
++                              addXMLSource(pParse->m_pAttrs, &(pSpec->m_pSources));
++                      else {
++                              if ((addXMLSource(pParse->m_pAttrs, &(pSpec->m_pSources))) &&
++                                  (pSpec->m_pSources->m_szDirectory)) {
++                                      newStr(pSpec->m_pSources->m_szDirectory,
++                                             (char**)&(pSpec->m_szBuildSubdir));
++                              }
++                      }
+                       break;
+               case TAGVAL_PATCH:
+                       addXMLSource(pParse->m_pAttrs, &(pSpec->m_pPatches));
+@@ -178,6 +186,12 @@
+                                       appendStringBuf(pSb, szTmp);
+                                       appendStringBuf(pSb, pSource->m_szName);
+                               }
++                              else if (!strcasecmp(szTmp, "tgz")) {
++                                      szTmp = NULL;
++                                      newStrEx("%{_gzipbin} -dc ", &szTmp);
++                                      appendStringBuf(pSb, szTmp);
++                                      appendStringBuf(pSb, pSource->m_szName);
++                              }
+                               else if (!strcasecmp(szTmp, "zip")) {
+                                       szTmp = NULL;
+                                       newStrEx("%{_unzipbin} ", &szTmp);
+@@ -265,8 +279,8 @@
+                                       appendStringBuf(pSb, pSource->m_szName);
+                               }
+                               freeStr(&szTmp);
+-                              szTmp = malloc(strlen(" > patch -p1234567890 -s ")+strlen(pSource->m_szName)+1);
+-                              sprintf(szTmp, " | patch -p%d -s", nLevel);
++                              szTmp = malloc(strlen(" > patch -pN1234567890 -s ")+strlen(pSource->m_szName)+1);
++                              sprintf(szTmp, " | patch -Np%d -s", nLevel);
+                               appendStringBuf(pSb, szTmp);
+                               appendLineStringBuf(pSb, "");
+                               appendLineStringBuf(pSb, "STATUS=$?");
+@@ -290,6 +304,9 @@
+               case TAGVAL_SUMMARY:
+               case TAGVAL_DESCRIPTION:
+               case TAGVAL_REQUIRES:
++              case TAGVAL_PROVIDES:
++              case TAGVAL_OBSOLETES:
++              case TAGVAL_CONFLICTS:
+                       // we don't need to do anything
+                       break;
+               default:
+@@ -315,6 +332,18 @@
+                       pPkg = getLastXMLPackage(pSpec->m_pPackages);
+                       addXMLRequire(pParse->m_pAttrs, &(pPkg->m_pRequires));
+                       break;
++              case TAGVAL_PROVIDE:
++                      pPkg = getLastXMLPackage(pSpec->m_pPackages);
++                      addXMLRequire(pParse->m_pAttrs, &(pPkg->m_pProvides));
++                      break;
++              case TAGVAL_OBSOLETE:
++                      pPkg = getLastXMLPackage(pSpec->m_pPackages);
++                      addXMLRequire(pParse->m_pAttrs, &(pPkg->m_pObsoletes));
++                      break;
++              case TAGVAL_CONFLICT:
++                      pPkg = getLastXMLPackage(pSpec->m_pPackages);
++                      addXMLRequire(pParse->m_pAttrs, &(pPkg->m_pConflicts));
++                      break;
+               case TAGVAL_CHANGE:
+                       pChanges = getLastXMLChanges(pSpec->m_pChangelog);
+                       addXMLChange(pParse->m_pAttrs, &(pChanges->m_pChanges));
+@@ -544,32 +573,26 @@
+              int nLen)
+ {
+       t_structXMLParse* pParse = NULL;
++      char* szVal = NULL;
+       char* szTmp = NULL;
+-      char* szTmpValue = NULL;
+-      char* szPos = NULL;
+       if ((pParse = (t_structXMLParse*)pData)) {
+-              szTmp = malloc(nLen+2);
+-              szTmp[nLen] = '\0';
+-              snprintf(szTmp, nLen+1, "%s", szValue);
+-              szPos = szTmp;
+-              while ((*szPos == ' ') ||
+-                     (*szPos == '\t') ||
+-                     (*szPos == '\r') ||
+-                     (*szPos == '\n'))
+-                      szPos++;
+-
+-              if (strlen(szPos)) {
++              szVal = malloc(nLen+2);
++              szVal[nLen] = '\0';
++              snprintf(szVal, nLen+1, "%s", szValue);
++              if (strlen(szVal)) {
++                      while ((szTmp = strchr(szVal, '\t')))
++                              *szTmp = ' ';
+                       if (pParse->m_szValue) {
+-                              szTmpValue = malloc(strlen(szPos)+strlen(pParse->m_szValue)+1);
+-                              sprintf(szTmpValue, "%s%s", pParse->m_szValue, szPos);
+-                              newStr(szTmpValue, &(pParse->m_szValue));
+-                              free(szTmpValue);
++                              szTmp = malloc(strlen(szVal)+strlen(pParse->m_szValue)+1);
++                              sprintf(szTmp, "%s%s", pParse->m_szValue, szVal);
++                              newStr(szTmp, &(pParse->m_szValue));
++                              free(szTmp);
+                       }
+                       else
+-                              newStr(szPos, &(pParse->m_szValue));
++                              newStr(szVal, &(pParse->m_szValue));
+               }
+-              free(szTmp);
++              free(szVal);
+       }
+ }
+Index: xmlspec/xmlstruct.c
+===================================================================
+RCS file: rpm/xmlspec/xmlstruct.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.2
+diff -u -u -r1.2.2.1 -r1.2.2.2
+--- rpm/xmlspec/xmlstruct.c    28 Aug 2002 10:52:43 -0000      1.2.2.1
++++ rpm/xmlspec/xmlstruct.c    10 Oct 2002 22:47:59 -0000      1.2.2.2
+@@ -97,7 +97,7 @@
+ {
+       while (pAttr && (strcasecmp(szName, pAttr->m_szName) != 0))
+               pAttr = pAttr->m_pNext;
+-              
++
+       return pAttr;
+ }
+@@ -236,7 +236,7 @@
+                       attrSetInt(pAttr, "size", &(pSource->m_nSize));
+                       attrSetStr(pAttr, "md5", &(pSource->m_szMD5));
+                       attrSetStr(pAttr, "directory", &(pSource->m_szDirectory));
+-                      attrSetInt(pAttr, "number", &(pSource->m_nNum));
++                      attrSetInt(pAttr, "id", &(pSource->m_nNum));
+               } while ((pAttr = pAttr->m_pNext));
+       }
+@@ -365,6 +365,8 @@
+       if ((pScript = malloc(sizeof(t_structXMLScript)))) {
+               pScript->m_szInterpreter = NULL;
++              pScript->m_szArch = NULL;
++              pScript->m_szOS = NULL;
+               pScript->m_szScript = NULL;
+               pScript->m_szEntry = NULL;
+               pScript->m_pNext = NULL;
+@@ -373,6 +375,10 @@
+                       do {
+                               attrSetStr(pAttr, "interpreter",
+                                          &(pScript->m_szInterpreter));
++                              attrSetStr(pAttr, "arch",
++                                         &(pScript->m_szArch));
++                              attrSetStr(pAttr, "os",
++                                         &(pScript->m_szOS));
+                               attrSetStr(pAttr, "script",
+                                          &(pScript->m_szScript));
+                       } while ((pAttr = pAttr->m_pNext));
+@@ -386,6 +392,8 @@
+ {
+       if (*ppScript) {
+               freeStr(&((*ppScript)->m_szInterpreter));
++              freeStr(&((*ppScript)->m_szArch));
++              freeStr(&((*ppScript)->m_szOS));
+               freeStr(&((*ppScript)->m_szScript));
+               freeStr(&((*ppScript)->m_szEntry));
+               freeXMLScript(&((*ppScript)->m_pNext));
+@@ -485,6 +493,59 @@
+       return 0;
+ }
++t_structI18NStr* newI18NStr(const t_structXMLAttr* pAttrs)
++{
++      t_structI18NStr* pStr = NULL;
++      t_structXMLAttr* pAttr = NULL;
++
++      if ((pStr = malloc(sizeof(t_structI18NStr)))) {
++              pStr->m_szLang = NULL;
++              pStr->m_szText = NULL;
++              pStr->m_pNext = NULL;
++
++              pAttr = (t_structXMLAttr*)pAttrs;
++              do {
++                      attrSetStr(pAttr, "lang", &(pStr->m_szLang));
++              } while ((pAttr = pAttr->m_pNext));
++      }
++
++      return pStr;
++}
++
++int freeI18NStr(t_structI18NStr** ppStr)
++{
++      if (*ppStr) {
++              freeStr(&((*ppStr)->m_szLang));
++              freeStr(&((*ppStr)->m_szText));
++              freeI18NStr(&((*ppStr)->m_pNext));
++              free(*ppStr);
++      }
++      *ppStr = NULL;
++
++      return 0;
++}
++
++t_structI18NStr* addI18NStr(const t_structXMLAttr* pAttrs,
++                          t_structI18NStr** ppStr)
++{
++      t_structI18NStr* pStr = NULL;
++
++      if ((pStr = getLastI18NStr(*ppStr)))
++              pStr = (pStr->m_pNext = newI18NStr(pAttrs));
++      else
++              pStr = (*ppStr = newI18NStr(pAttrs));
++
++      return pStr;
++}
++
++t_structI18NStr* getLastI18NStr(t_structI18NStr* pStr)
++{
++      while (pStr && (pStr->m_pNext))
++              pStr = pStr->m_pNext;
++
++      return pStr;
++}
++
+ t_structXMLPackage* newXMLPackage(const t_structXMLAttr* pAttrs)
+ {
+       t_structXMLPackage* pPackage = NULL;
+@@ -492,6 +553,7 @@
+       if ((pPackage = malloc(sizeof(t_structXMLPackage)))) {
+               pPackage->m_szName = NULL;
++              pPackage->m_szVersion = NULL;
+               pPackage->m_szGroup = NULL;
+               pPackage->m_szSummary = NULL;
+               pPackage->m_szDescription = NULL;
+@@ -507,15 +569,21 @@
+               pPackage->m_pRequires = NULL;
+               pPackage->m_pSuggests = NULL;
+               pPackage->m_pObsoletes = NULL;
++              pPackage->m_pConflicts = NULL;
+               pPackage->m_pProvides = NULL;
+               pPackage->m_pNext = NULL;
+               pAttr = (t_structXMLAttr*)pAttrs;
+               do {
+                       attrSetStr(pAttr, "name", &(pPackage->m_szName));
++                      attrSetStr(pAttr, "version", &(pPackage->m_szVersion));
+                       attrSetStr(pAttr, "group", &(pPackage->m_szGroup));
+                       attrSetBool(pAttr, "autorequire", &(pPackage->m_nAutoRequire));
++                      attrSetBool(pAttr, "autoreq", &(pPackage->m_nAutoRequire));
+                       attrSetBool(pAttr, "autoprovide", &(pPackage->m_nAutoProvide));
++                      attrSetBool(pAttr, "autoprov", &(pPackage->m_nAutoProvide));
++                      attrSetBool(pAttr, "autoreqprov", &(pPackage->m_nAutoProvide));
++                      attrSetBool(pAttr, "autoreqprov", &(pPackage->m_nAutoRequire));
+                       attrSetBool(pAttr, "autosuggest", &(pPackage->m_nAutoSuggest));
+               } while ((pAttr = pAttr->m_pNext));
+       }
+@@ -527,6 +595,7 @@
+ {
+       if (*ppPackage) {
+               freeStr(&((*ppPackage)->m_szName));
++              freeStr(&((*ppPackage)->m_szVersion));
+               freeStr(&((*ppPackage)->m_szGroup));
+               freeStr(&((*ppPackage)->m_szSummary));
+               freeStr(&((*ppPackage)->m_szDescription));
+@@ -539,6 +608,7 @@
+               freeXMLRequire(&((*ppPackage)->m_pRequires));
+               freeXMLRequire(&((*ppPackage)->m_pSuggests));
+               freeXMLRequire(&((*ppPackage)->m_pObsoletes));
++              freeXMLRequire(&((*ppPackage)->m_pConflicts));
+               freeXMLRequire(&((*ppPackage)->m_pProvides));
+               freeXMLPackage(&((*ppPackage)->m_pNext));
+               free(*ppPackage);
+Index: xmlspec/xmlstruct.h
+===================================================================
+RCS file: rpm/xmlspec/xmlstruct.h,v
+retrieving revision 1.1.2.1
+retrieving revision 1.1.2.2
+diff -u -u -r1.1.2.1 -r1.1.2.2
+--- rpm/xmlspec/xmlstruct.h    28 Aug 2002 10:52:43 -0000      1.1.2.1
++++ rpm/xmlspec/xmlstruct.h    10 Oct 2002 22:47:59 -0000      1.1.2.2
+@@ -52,6 +52,8 @@
+ typedef struct structXMLScript
+ {
+       char*                   m_szInterpreter;
++      char*                   m_szArch;
++      char*                   m_szOS;
+       char*                   m_szScript;
+       char*                   m_szEntry;
+       struct structXMLScript* m_pNext;
+@@ -71,9 +73,17 @@
+       char* m_szGID;
+ } t_structXMLFiles;
++typedef struct structI18NStr
++{
++      char*                 m_szLang;
++      char*                 m_szText;
++      struct structI18NStr* m_pNext;
++} t_structI18NStr;
++
+ typedef struct structXMLPackage
+ {
+       char*                    m_szName;
++      char*                    m_szVersion;
+       char*                    m_szGroup;
+       char*                    m_szSummary;
+       char*                    m_szDescription;
+@@ -89,6 +99,7 @@
+       struct structXMLRequire* m_pRequires;
+       struct structXMLRequire* m_pSuggests;
+       struct structXMLRequire* m_pObsoletes;
++      struct structXMLRequire* m_pConflicts;
+       struct structXMLRequire* m_pProvides;
+       struct structXMLPackage* m_pNext;
+ } t_structXMLPackage;
+@@ -200,6 +211,12 @@
+ t_structXMLFiles* newXMLFiles(const t_structXMLAttr* pAttrs);
+ int freeXMLFiles(t_structXMLFiles** ppFiles);
++
++t_structI18NStr* newI18NStr(const t_structXMLAttr* pAttrs);
++int freeI18NStr(t_structI18NStr** ppStr);
++t_structI18NStr* addI18NStr(const t_structXMLAttr* pAttrs,
++                          t_structI18NStr** ppStr);
++t_structI18NStr* getLastI18NStr(t_structI18NStr* pStr);
+ t_structXMLPackage* newXMLPackage(const t_structXMLAttr* pAttrs);
+ int freeXMLPackage(t_structXMLPackage** ppPackage);
+Index: xmlspec/xmlverify.c
+===================================================================
+RCS file: rpm/xmlspec/xmlverify.c,v
+retrieving revision 1.1.2.1
+retrieving revision 1.1.2.2
+diff -u -u -r1.1.2.1 -r1.1.2.2
+--- rpm/xmlspec/xmlverify.c    28 Aug 2002 10:52:43 -0000      1.1.2.1
++++ rpm/xmlspec/xmlverify.c    10 Oct 2002 22:47:59 -0000      1.1.2.2
+@@ -58,7 +58,7 @@
+                       {"size",           ATTRTYPE_NUMERIC, 0},
+                       {"md5",            ATTRTYPE_MD5,     0},
+                       {"path",           ATTRTYPE_ANY,     0},
+-                      {"number",         ATTRTYPE_NUMERIC, 0},
++                      {"id",             ATTRTYPE_NUMERIC, 0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -89,7 +89,7 @@
+                       {"size",           ATTRTYPE_NUMERIC, 0},
+                       {"md5",            ATTRTYPE_MD5,     0},
+                       {"path",           ATTRTYPE_ANY,     0},
+-                      {"number",         ATTRTYPE_NUMERIC, 0},
++                      {"id",             ATTRTYPE_NUMERIC, 0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -165,6 +165,7 @@
+               },
+               {
+                       {"name",           ATTRTYPE_ANY,     0},
++                      {"version",        ATTRTYPE_ANY,     0},
+                       {"group",          ATTRTYPE_ANY,     1},
+                       {"autoreqprov",    ATTRTYPE_BOOL,    0},
+                       {"autoprov",       ATTRTYPE_BOOL,    0},
+@@ -219,6 +220,7 @@
+               },
+               {
+                       {"name",           ATTRTYPE_ANY,     1},
++                      {"version",        ATTRTYPE_ANY,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -243,6 +245,34 @@
+               },
+               {
+                       {"name",           ATTRTYPE_ANY,     1},
++                      {"version",        ATTRTYPE_ANY,     0},
++                      {"cmp",            ATTRTYPE_CMP,     0},
++                      {NULL,             ATTRTYPE_ANY,     1}
++              }
++      },
++      {
++              "conflicts", TAGVAL_CONFLICTS, 2,
++              {
++                      TAGVAL_SPEC,
++                      TAGVAL_PACKAGE,
++                      TAGVAL_LAST
++              },
++              {
++                      {NULL,             ATTRTYPE_ANY,     1}
++              }
++      },
++      {
++              "conflict", TAGVAL_CONFLICT, 3,
++              {
++                      TAGVAL_SPEC,
++                      TAGVAL_PACKAGE,
++                      TAGVAL_CONFLICTS,
++                      TAGVAL_LAST
++              },
++              {
++                      {"name",           ATTRTYPE_ANY,     1},
++                      {"version",        ATTRTYPE_ANY,     0},
++                      {"cmp",            ATTRTYPE_CMP,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -280,6 +310,7 @@
+                       TAGVAL_LAST
+               },
+               {
++                      {"lang",           ATTRTYPE_ANY,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -291,6 +322,7 @@
+                       TAGVAL_LAST
+               },
+               {
++                      {"lang",           ATTRTYPE_ANY,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+@@ -317,6 +349,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -344,6 +378,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -371,6 +407,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -398,11 +436,14 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+       },
+-      {"verify", TAGVAL_VERIFY, 2,
++      {
++              "verify", TAGVAL_VERIFY, 2,
+               {
+                       TAGVAL_SPEC,
+                       TAGVAL_PACKAGE,
+@@ -424,6 +465,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -463,6 +506,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -476,6 +521,8 @@
+               },
+               {
+                       {"source",         ATTRTYPE_NUMERIC, 0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"path",           ATTRTYPE_ANY,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -489,6 +536,8 @@
+               },
+               {
+                       {"patch",          ATTRTYPE_NUMERIC, 0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"level",          ATTRTYPE_NUMERIC, 0},
+                       {"path",           ATTRTYPE_ANY,     0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+@@ -515,6 +564,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -540,6 +591,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+@@ -565,6 +618,8 @@
+               },
+               {
+                       {"interpreter",    ATTRTYPE_ANY,     0},
++                      {"arch",           ATTRTYPE_ANY,     0},
++                      {"os",             ATTRTYPE_ANY,     0},
+                       {"script",         ATTRTYPE_SCRIPT,  0},
+                       {NULL,             ATTRTYPE_ANY,     1}
+               }
+Index: xmlspec/xmlverify.h
+===================================================================
+RCS file: rpm/xmlspec/xmlverify.h,v
+retrieving revision 1.1.2.1
+retrieving revision 1.1.2.2
+diff -u -u -r1.1.2.1 -r1.1.2.2
+--- rpm/xmlspec/xmlverify.h    28 Aug 2002 10:52:43 -0000      1.1.2.1
++++ rpm/xmlspec/xmlverify.h    10 Oct 2002 22:47:59 -0000      1.1.2.2
+@@ -22,6 +22,8 @@
+       TAGVAL_REQUIRE,
+       TAGVAL_OBSOLETES,
+       TAGVAL_OBSOLETE,
++      TAGVAL_CONFLICTS,
++      TAGVAL_CONFLICT,
+       TAGVAL_SUGGESTS,
+       TAGVAL_SUGGEST,
+       TAGVAL_SUMMARY,
diff --git a/rpm-SIGCHLD.patch b/rpm-SIGCHLD.patch
deleted file mode 100644 (file)
index e8c270f..0000000
+++ /dev/null
@@ -1,632 +0,0 @@
-diff -ruN rpm-4.1/lib/psm.c rpm-4.1-9/lib/psm.c
---- rpm-4.1/lib/psm.c  Tue Sep 17 16:18:50 2002
-+++ rpm-4.1-9/lib/psm.c        Mon Oct  7 12:36:35 2002
-@@ -695,15 +695,19 @@
-       (void) sigaddset(&caught, signum);
-       switch (signum) {
-       case SIGCHLD:
--      {   int status = 0;
--          pid_t reaped = waitpid(0, &status, WNOHANG);
--          int i;
--
--          if (psmtbl.psms)
--          for (i = 0; i < psmtbl.npsms; i++) {
--              rpmpsm psm = psmtbl.psms[i];
--              if (psm->child != reaped)
--                  /*@innercontinue@*/ continue;
-+          while (1) {
-+              int status = 0;
-+              pid_t reaped = waitpid(0, &status, WNOHANG);
-+              int i;
-+
-+              if (reaped <= 0)
-+                  /*@innerbreak@*/ break;
-+
-+              if (psmtbl.psms)
-+              for (i = 0; i < psmtbl.npsms; i++) {
-+                  rpmpsm psm = psmtbl.psms[i];
-+                  if (psm->child != reaped)
-+                      /*@innercontinue@*/ continue;
- #if _PSM_DEBUG
- /*@-modfilesys@*/
-@@ -712,11 +716,12 @@
- /*@=modfilesys@*/
- #endif
--              psm->reaped = reaped;
--              psm->status = status;
--              /*@innerbreak@*/ break;
-+                  psm->reaped = reaped;
-+                  psm->status = status;
-+                  /*@innerbreak@*/ break;
-+              }
-           }
--      }   /*@switchbreak@*/ break;
-+          /*@switchbreak@*/ break;
-       default:
-           /*@switchbreak@*/ break;
-       }
-@@ -782,26 +787,6 @@
- }
- /**
-- * Fork a new process.
-- * @param psm         package state machine data
-- * @return            fork(2) pid
-- */
--static pid_t psmFork(rpmpsm psm)
--      /*@globals fileSystem, internalState @*/
--      /*@modifies fileSystem, internalState @*/
--{
--    pid_t pid;
--
--    if ((pid = fork()) != 0) {
--/*@-modfilesys@*/
--if (_psm_debug)
--fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, pid);
--/*@=modfilesys@*/
--    }
--    return pid;
--}
--
--/**
-  * Register a child reaper, then fork a child.
-  * @param psm         package state machine data
-  * @return            fork(2) pid
-@@ -835,7 +820,6 @@
-       }
-       empty = psmtbl.npsms++;
-     }
--    psm->reaped = 0;
-     if (psmtbl.psms)  /* XXX can't happen */
-       psmtbl.psms[empty] = rpmpsmLink(psm, "psmRegister");
- /*@-modfilesys@*/
-@@ -844,15 +828,24 @@
- /*@=modfilesys@*/
-     (void) enableSignal(SIGCHLD);
-+
-+    psm->reaped = 0;
-+    if ((psm->child = fork()) != 0) {
-+/*@-modfilesys@*/
-+if (_psm_debug)
-+fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
-+/*@=modfilesys@*/
-+    }
-+
-     (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
--    return psmFork(psm);
-+    return psm->child;
- }
- /**
-  * Unregister a child reaper.
-  */
--static int psmUnregister(rpmpsm psm, pid_t child)
-+static int psmWaitUnregister(rpmpsm psm, pid_t child)
-       /*@globals psmtbl, fileSystem, internalState @*/
-       /*@modifies psmtbl, fileSystem, internalState @*/
- {
-@@ -862,6 +855,19 @@
-     (void) sigfillset(&newMask);              /* block all signals */
-     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-     
-+    /*@-infloops@*/
-+    while (psm->reaped != psm->child) {
-+      (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
-+      (void) pause();
-+      (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-+    }
-+    /*@=infloops@*/
-+
-+/*@-modfilesys@*/
-+if (_psm_debug)
-+fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
-+/*@=modfilesys@*/
-+
-     if (psmtbl.psms)
-     for (i = 0; i < psmtbl.npsms; i++) {
-       if (psmtbl.psms[i] == NULL)
-@@ -893,25 +899,6 @@
- }
- /**
-- * Return reaped pid safely (i.e. with signals blocked).
-- * @param psm         package state machine data
-- * @return            
-- */
--static inline pid_t psmGetReaped(rpmpsm psm)
--      /*@globals fileSystem @*/
--      /*@modifies fileSystem @*/
--{
--    sigset_t newMask, oldMask;
--    pid_t reaped;
--
--    (void) sigfillset(&newMask);              /* block all signals */
--    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
--    reaped = psm->reaped;
--    (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
--    return reaped;
--}
--
--/**
-  * Wait for child process to be reaped.
-  * @param psm         package state machine data
-  * @return            
-@@ -921,15 +908,7 @@
-       /*@modifies psm, fileSystem, internalState @*/
- {
-     if (psm->reaper) {
--      /*@-infloops@*/
--      while (psmGetReaped(psm) == 0)
--          (void) pause();
--      /*@=infloops@*/
--/*@-modfilesys@*/
--if (_psm_debug)
--fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
--/*@=modfilesys@*/
--      (void) psmUnregister(psm, psm->child);
-+      (void) psmWaitUnregister(psm, psm->child);
-     } else {
-       do {
-           psm->reaped = waitpid(psm->child, &psm->status, 0);
-@@ -997,7 +976,6 @@
-     FD_t out;
-     rpmRC rc = RPMRC_OK;
-     const char *n, *v, *r;
--    pid_t pid;
-     if (progArgv == NULL && script == NULL)
-       return rc;
-@@ -1119,8 +1097,7 @@
-     if (out == NULL) return RPMRC_FAIL;       /* XXX can't happen */
-     
-     /*@-branchstate@*/
--    pid = psmRegisterFork(psm);
--    psm->child = pid;
-+    (void) psmRegisterFork(psm);
-     if (psm->child == 0) {
-       const char * rootDir;
-       int pipes[2];
-
-diff -ruN rpm-4.1/rpmio/rpmlog.c rpm-4.1-9/rpmio/rpmlog.c
---- rpm-4.1/rpmio/rpmlog.c     Wed Jul  3 01:54:38 2002
-+++ rpm-4.1-9/rpmio/rpmlog.c   Fri Sep 20 18:33:06 2002
-@@ -179,6 +179,7 @@
-       else                    /* glibc 2.0 */
-           msgnb *= 2;
-       msgbuf = xrealloc(msgbuf, msgnb);
-+      va_end(apc);
-     }
-     msgbuf[msgnb - 1] = '\0';
-     msg = msgbuf;
-diff -ruN rpm-4.1/tools/sections.c rpm-4.1-9/tools/sections.c
---- rpm-4.1/tools/sections.c   Thu Aug 22 19:57:41 2002
-+++ rpm-4.1-9/tools/sections.c Sun Oct  6 07:30:41 2002
-@@ -24,38 +24,168 @@
- } UnstripInfo32;
- typedef struct {
--  Elf32_Off orig_e_shoff;
--  Elf32_Off n_sections;
-+  Elf64_Off orig_e_shoff;
-+  Elf64_Off n_sections;
-   UnstripInfoSection64 sections[1];
- } UnstripInfo64;
-+static uint32_t
-+elf_32_to_file (uint32_t x, int file_is_little_endian)
-+{
-+  volatile uint32_t out;
-+  unsigned char *outbytes;
-+
-+  outbytes = (unsigned char *)&out;
-+  if (file_is_little_endian)
-+    {
-+      outbytes[0] = (x >> 0) & 0xff;
-+      outbytes[1] = (x >> 8) & 0xff;
-+      outbytes[2] = (x >> 16) & 0xff;
-+      outbytes[3] = (x >> 24) & 0xff;
-+    }
-+  else /* big endian */
-+    {
-+      outbytes[0] = (x >> 24) & 0xff;
-+      outbytes[1] = (x >> 16) & 0xff;
-+      outbytes[2] = (x >> 8) & 0xff;
-+      outbytes[3] = (x >> 0) & 0xff;
-+    }
-+  
-+  return out;
-+}
-+
-+static uint64_t
-+elf_64_to_file (uint64_t x, int file_is_little_endian)
-+{
-+  volatile uint64_t out;
-+  unsigned char *outbytes;
-+  int i;
-+
-+  outbytes = (unsigned char *)&out;
-+  if (file_is_little_endian)
-+    {
-+      for (i = 0; i < 8; i++)
-+      outbytes[i] = (x >> (8*i)) & 0xff;
-+    }
-+  else /* big endian */
-+    {
-+      for (i = 0; i < 8; i++)
-+      outbytes[7-i] = (x >> (8*i)) & 0xff;
-+    }
-+  
-+  return out;
-+}
- static Elf32_Word
- word32_to_file (Elf32_Word x, Elf *elf)
- {
--  /* FIXME: implement */
--  return x;
-+  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
-+  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
- }
- static Elf32_Off
- off32_to_file (Elf32_Off x, Elf *elf)
- {
--  /* FIXME: implement */
--  return x;
-+  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
-+  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
-+}
-+
-+static Elf64_Word
-+word64_to_file (Elf64_Word x, Elf *elf)
-+{
-+  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
-+  return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
-+}
-+
-+static Elf64_Off
-+off64_to_file (Elf64_Off x, Elf *elf)
-+{
-+  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
-+  return elf_64_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
-+}
-+
-+static uint32_t
-+elf_32_from_file (uint32_t x, int file_is_little_endian)
-+{
-+  unsigned char *inbytes;
-+
-+  inbytes = (unsigned char *)&x;
-+  if (file_is_little_endian)
-+    {
-+      return 
-+      (inbytes[0] << 0) |
-+      (inbytes[1] << 8) |
-+      (inbytes[2] << 16) |
-+      (inbytes[3] << 24);
-+    }
-+  else /* big endian */
-+    {
-+      return 
-+      (inbytes[0] << 24) |
-+      (inbytes[1] << 16) |
-+      (inbytes[2] << 8) |
-+      (inbytes[3] << 0);
-+    }
-+}
-+
-+static uint64_t
-+elf_64_from_file (uint64_t x, int file_is_little_endian)
-+{
-+  unsigned char *inbytes;
-+
-+  inbytes = (unsigned char *)&x;
-+  if (file_is_little_endian)
-+    {
-+      return 
-+      ((uint64_t)inbytes[0] << 0) |
-+      ((uint64_t)inbytes[1] << 8) |
-+      ((uint64_t)inbytes[2] << 16) |
-+      ((uint64_t)inbytes[3] << 24) |
-+      ((uint64_t)inbytes[4] << 32) |
-+      ((uint64_t)inbytes[5] << 40) |
-+      ((uint64_t)inbytes[6] << 48) |
-+      ((uint64_t)inbytes[7] << 56);
-+    }
-+  else /* big endian */
-+    {
-+      return 
-+      ((uint64_t)inbytes[0] << 56) |
-+      ((uint64_t)inbytes[1] << 48) |
-+      ((uint64_t)inbytes[2] << 40) |
-+      ((uint64_t)inbytes[3] << 32) |
-+      ((uint64_t)inbytes[4] << 24) |
-+      ((uint64_t)inbytes[5] << 16) |
-+      ((uint64_t)inbytes[6] << 8) |
-+      ((uint64_t)inbytes[7] << 0);
-+    }
- }
- static Elf32_Word
- word32_from_file (Elf32_Word x, Elf *elf)
- {
--  /* FIXME: implement */
--  return x;
-+  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
-+  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
- }
- static Elf32_Off
- off32_from_file (Elf32_Off x, Elf *elf)
- {
--  /* FIXME: implement */
--  return x;
-+  Elf32_Ehdr *ehdr = elf32_getehdr (elf);
-+  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
-+}
-+
-+static Elf64_Word
-+word64_from_file (Elf64_Word x, Elf *elf)
-+{
-+  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
-+  return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
-+}
-+
-+static Elf64_Off
-+off64_from_file (Elf64_Off x, Elf *elf)
-+{
-+  Elf64_Ehdr *ehdr = elf64_getehdr (elf);
-+  return elf_64_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
- }
- static void
-@@ -93,7 +223,29 @@
-                       Elf *elf,
-                       Elf_Data *data)
- {
-+  UnstripInfo64 *info64;
-+  int i;
-+  
-   data->d_align = 8;
-+  
-+  data->d_size =
-+    /* orig_e_shoff */ sizeof (Elf64_Off) +
-+    /* n_sections */ sizeof (Elf64_Off) +
-+    /* sections */ info->n_sections * sizeof (UnstripInfoSection64);
-+
-+  data->d_buf = calloc (1, data->d_size);
-+
-+  info64 = (UnstripInfo64 *) data->d_buf;
-+
-+  info64->orig_e_shoff = off64_to_file (info->orig_e_shoff, elf);
-+  info64->n_sections = off64_to_file (info->n_sections, elf);
-+
-+  for (i = 0; i < info->n_sections; i++)
-+    {
-+      info64->sections[i].debug_section = word64_to_file (info->sections[i].debug_section, elf);
-+      info64->sections[i].name = word64_to_file (info->sections[i].name, elf);
-+      info64->sections[i].orig_offset = off64_to_file (info->sections[i].orig_offset, elf);
-+    }
- }
- void
-@@ -101,11 +253,18 @@
-                     Elf *elf,
-                     Elf_Data *data)
- {
-+  GElf_Ehdr ehdr;
-+  
-   data->d_type = ELF_T_BYTE;
-   data->d_off = 0;
--  /* FIXME: use right version */
--  unstrip_info_to_data32 (info, elf, data);
-+  gelf_getehdr (elf, &ehdr);
-+  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
-+    unstrip_info_to_data32 (info, elf, data);
-+  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
-+    unstrip_info_to_data64 (info, elf, data);
-+  else
-+    fprintf (stderr, "Warning. unsupported elf class\n");
- }
- void
-@@ -130,23 +289,49 @@
-     }
- }
-+void
-+unstrip_info_from_data64 (UnstripInfo *info,
-+                        Elf *elf,
-+                        Elf_Data *data)
-+{
-+  UnstripInfo64 *info64;
-+  int i;
-+  
-+  info64 = (UnstripInfo64 *) data->d_buf;
-+  
-+  info->orig_e_shoff = off64_from_file (info64->orig_e_shoff, elf);
-+  info->n_sections = off64_from_file (info64->n_sections, elf);
-+
-+  info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
-+  for (i = 0; i < info->n_sections; i++)
-+    {
-+      info->sections[i].debug_section = word64_from_file (info64->sections[i].debug_section, elf);
-+      info->sections[i].name = word64_from_file (info64->sections[i].name, elf);
-+      info->sections[i].orig_offset = off64_from_file (info64->sections[i].orig_offset, elf);
-+    }
-+}
-+
- UnstripInfo *
- unstrip_info_from_data (Elf *elf,
-                       Elf_Data *data)
- {
-+  GElf_Ehdr ehdr;
-+  
-   UnstripInfo *info;
-   info = malloc (sizeof (UnstripInfo));
--  /* FIXME: use right version */
--  unstrip_info_from_data32 (info,
--                          elf,
--                          data);
-+  gelf_getehdr (elf, &ehdr);
-+  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
-+    unstrip_info_from_data32 (info, elf, data);
-+  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
-+    unstrip_info_from_data64 (info, elf, data);
-+  else
-+    fprintf (stderr, "Warning. unsupported elf class\n");
-   
-   return info;
- }
--
- static void
- debug_link_to_data32 (DebugLink *debuglink,
-                     Elf *elf,
-@@ -169,17 +354,47 @@
-   p = data->d_buf + namelen_aligned;
-   
-   *(Elf32_Word *)p = word32_to_file (debuglink->checksum, elf);
--  p += sizeof (Elf32_Word);
-+}
-+
-+static void
-+debug_link_to_data64 (DebugLink *debuglink,
-+                    Elf *elf,
-+                    Elf_Data *data)
-+{
-+  size_t namelen_aligned;
-+  char *p;
-+  
-+  data->d_align = 4;
-+
-+  namelen_aligned = align_up (strlen(debuglink->filename) + 1, 4);
-+
-+  data->d_size =
-+    /* name */ namelen_aligned +
-+    /* checksum */ sizeof (Elf64_Word);
-+
-+  data->d_buf = calloc (1, data->d_size);
-+
-+  strcpy (data->d_buf, debuglink->filename);
-+  p = data->d_buf + namelen_aligned;
-+  
-+  *(Elf64_Word *)p = word64_to_file (debuglink->checksum, elf);
- }
- void
- debug_link_to_data (DebugLink *debuglink, Elf *elf, Elf_Data *data)
- {
-+  GElf_Ehdr ehdr;
-+  
-   data->d_type = ELF_T_BYTE;
-   data->d_off = 0;
--  /* FIXME: use right version */
--  debug_link_to_data32 (debuglink, elf, data);
-+  gelf_getehdr (elf, &ehdr);
-+  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
-+    debug_link_to_data32 (debuglink, elf, data);
-+  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
-+    debug_link_to_data64 (debuglink, elf, data);
-+  else
-+    fprintf (stderr, "Warning. unsupported elf class\n");
- }
- void
-@@ -197,21 +412,41 @@
-   p = data->d_buf + namelen_aligned;
-   
-   debuglink->checksum = word32_from_file (*(Elf32_Word *)p, elf);
--  p += sizeof (Elf32_Word);
-+}
-+
-+void
-+debug_link_from_data64 (DebugLink *debuglink,
-+                      Elf *elf,
-+                      Elf_Data *data)
-+{
-+  size_t namelen_aligned;
-+  char *p;
-+  
-+  debuglink->filename = strdup (data->d_buf);
-+
-+  namelen_aligned = align_up (strlen (debuglink->filename) + 1, 4);
-+
-+  p = data->d_buf + namelen_aligned;
-+  
-+  debuglink->checksum = word64_from_file (*(Elf64_Word *)p, elf);
- }
- DebugLink *
- debug_link_from_data (Elf *elf, Elf_Data *data)
- {
-+  GElf_Ehdr ehdr;
-   DebugLink *debuglink;
-   debuglink = malloc (sizeof (DebugLink));
--  /* FIXME: use right version */
--  debug_link_from_data32 (debuglink,
--                        elf,
--                        data);
-+  gelf_getehdr (elf, &ehdr);
-+  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
-+    debug_link_from_data32 (debuglink, elf, data);
-+  else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
-+    debug_link_from_data64 (debuglink, elf, data);
-+  else
-+    fprintf (stderr, "Warning. unsupported elf class\n");
-   
-   return debuglink;
- }
-diff -ruN rpm-4.1/tools/striptofile.c rpm-4.1-9/tools/striptofile.c
---- rpm-4.1/tools/striptofile.c        Thu Aug 22 21:08:25 2002
-+++ rpm-4.1-9/tools/striptofile.c      Sun Oct  6 07:30:41 2002
-@@ -201,7 +201,7 @@
-   /* Update section header stringtab ref */
-   gelf_getehdr (out_elf, &out_ehdr);
-   out_ehdr.e_shstrndx = section_map[out_ehdr.e_shstrndx];
--  out_ehdr.e_shoff = align_up (last_offset, 4);
-+  out_ehdr.e_shoff = align_up (last_offset, 8);
-   gelf_update_ehdr(out_elf, &out_ehdr);
-   /* Update section header links */
-@@ -402,6 +402,7 @@
-   Elf *elf, *out_elf;
-   int fd, out;
-   const char *origname;
-+  char *origname_base;
-   char *debugname, *strippedname;
-   DebugLink *debuglink;
-   poptContext optCon;   /* context for parsing command-line options */
-@@ -433,14 +434,13 @@
-   
-   origname = args[0];
--  if (output_dir) {
--    const char * bn = strrchr(origname, '/');
--    if ((bn = strrchr(origname, '/')) != NULL)
--      bn++;
--    else
--      bn = origname;
--    debugname = strconcat (output_dir, "/", bn, ".debug", NULL);
--  } else
-+  if (output_dir)
-+    {
-+      origname_base = path_basename (origname);
-+      debugname = strconcat (output_dir, "/", origname_base, ".debug", NULL);
-+      free (origname_base);
-+    }
-+  else
-     debugname = strconcat (origname, ".debug", NULL);
-   
-   strippedname = strconcat (origname, ".XXXXXX", NULL);
diff --git a/rpm-db4.patch b/rpm-db4.patch
deleted file mode 100644 (file)
index afa6a8f..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-diff -Nur rpm-4.1.orig/configure.ac rpm-4.1/configure.ac
---- rpm-4.1.orig/configure.ac  Sun Oct 20 16:34:30 2002
-+++ rpm-4.1/configure.ac       Sun Oct 20 16:37:39 2002
-@@ -437,10 +437,12 @@
- if test $withval = no ; then
- dnl ------------------ without internal db
--AC_CHECK_HEADERS(db3/db.h)
-+AC_CHECK_HEADERS(db.h)
- dnl Check for Berkeley db3 API.
- AC_CHECK_FUNC(db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"],
-+  AC_CHECK_LIB(db-4.1, db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"; libdb3="-ldb-4.1"],
-+  AC_CHECK_LIB(db-4.0, db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"; libdb3="-ldb-4.0"],
-   AC_CHECK_LIB(db-3.2, db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"; libdb3="-ldb-3.2"],
-     AC_CHECK_LIB(db-3.1, db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"; libdb3="-ldb-3.1"],
-       AC_CHECK_LIB(db-3.0, db_create, [DBLIBSRCS="$DBLIBSRCS db3.c"; libdb3="-ldb-3.0"],
-@@ -449,6 +451,8 @@
-       )
-     )
-   )
-+  )
-+  )
- )
- if test X"$DBLIBSRCS" = X; then
-diff -Nur rpm-4.1.orig/python/_rpmdb.c rpm-4.1/python/_rpmdb.c
---- rpm-4.1.orig/python/_rpmdb.c       Fri Jun  7 15:12:34 2002
-+++ rpm-4.1/python/_rpmdb.c    Sun Oct 20 16:36:39 2002
-@@ -410,25 +410,6 @@
-     switch (err) {
-         case 0:                     /* successful, no error */      break;
--        case DB_INCOMPLETE:
--#if INCOMPLETE_IS_WARNING
--            strcpy(errTxt, db_strerror(err));
--            if (_db_errmsg[0]) {
--                strcat(errTxt, " -- ");
--                strcat(errTxt, _db_errmsg);
--                _db_errmsg[0] = 0;
--            }
--#if PYTHON_API_VERSION >= 1010 /* if Python 2.1 or better use warning framework */
--            exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
--#else
--            fprintf(stderr, errTxt);
--            fprintf(stderr, "\n");
--#endif
--
--#else  /* do an exception instead */
--        errObj = DBIncompleteError;
--#endif
--        break;
-         case DB_KEYEMPTY:           errObj = DBKeyEmptyError;       break;
-         case DB_KEYEXIST:           errObj = DBKeyExistError;       break;
-@@ -1025,7 +1006,7 @@
-     MYDB_BEGIN_ALLOW_THREADS;
--    err = self->db->associate(self->db,
-+    err = self->db->associate(self->db, NULL,
-                               secondaryDB->db,
-                               _db_associateCallback,
-                               flags);
-@@ -1498,7 +1479,7 @@
-     }
-     MYDB_BEGIN_ALLOW_THREADS;
--    err = self->db->open(self->db, filename, dbname, type, flags, mode);
-+    err = self->db->open(self->db, NULL, filename, dbname, type, flags, mode);
-     MYDB_END_ALLOW_THREADS;
-     if (makeDBError(err)) {
-         self->db = NULL;
-@@ -1851,7 +1832,6 @@
-         MAKE_HASH_ENTRY(nkeys);
-         MAKE_HASH_ENTRY(ndata);
-         MAKE_HASH_ENTRY(pagesize);
--        MAKE_HASH_ENTRY(nelem);
-         MAKE_HASH_ENTRY(ffactor);
-         MAKE_HASH_ENTRY(buckets);
-         MAKE_HASH_ENTRY(free);
-@@ -3337,7 +3317,6 @@
- #define MAKE_ENTRY(name)  _addIntToDict(d, #name, sp->st_##name)
--    MAKE_ENTRY(lastid);
-     MAKE_ENTRY(nmodes);
- #if (DBVER >= 32)
-     MAKE_ENTRY(maxlocks);
-@@ -4116,7 +4095,6 @@
-     ADD_INT(d, DB_APPEND);
-     ADD_INT(d, DB_BEFORE);
-     ADD_INT(d, DB_CACHED_COUNTS);
--    ADD_INT(d, DB_CHECKPOINT);
- #if (DBVER >= 33)
-     ADD_INT(d, DB_COMMIT);
- #endif
-@@ -4124,7 +4102,6 @@
- #if (DBVER >= 32)
-     ADD_INT(d, DB_CONSUME_WAIT);
- #endif
--    ADD_INT(d, DB_CURLSN);
-     ADD_INT(d, DB_CURRENT);
- #if (DBVER >= 33)
-     ADD_INT(d, DB_FAST_STAT);
-@@ -4164,7 +4141,6 @@
-     ADD_INT(d, DB_DONOTINDEX);
- #endif
--    ADD_INT(d, DB_INCOMPLETE);
-     ADD_INT(d, DB_KEYEMPTY);
-     ADD_INT(d, DB_KEYEXIST);
-     ADD_INT(d, DB_LOCK_DEADLOCK);
-diff -Nur rpm-4.1.orig/rpmdb/db3.c rpm-4.1/rpmdb/db3.c
---- rpm-4.1.orig/rpmdb/db3.c   Tue Aug 13 22:42:39 2002
-+++ rpm-4.1/rpmdb/db3.c        Sun Oct 20 16:36:39 2002
-@@ -366,7 +366,7 @@
-     if (db != NULL)
-       rc = db->sync(db, flags);
-     /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
--    _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
-+    _printit = _debug;
-     rc = cvtdberr(dbi, "db->sync", rc, _printit);
-     return rc;
- }
-@@ -599,10 +599,11 @@
- {
-     DB * db = dbi->dbi_db;
-     DB * secondary = dbisecondary->dbi_db;
-+    DB_TXN * txnid = NULL;
-     int rc;
- /*@-moduncon@*/ /* FIX: annotate db3 methods */
--    rc = db->associate(db, secondary, callback, flags);
-+    rc = db->associate(db, txnid, secondary, callback, flags);
- /*@=moduncon@*/
-     rc = cvtdberr(dbi, "db->associate", rc, _debug);
-     return rc;
-@@ -789,6 +790,7 @@
-     DB * db = NULL;
-     DB_ENV * dbenv = NULL;
-+    DB_TXN * txnid = NULL;
-     u_int32_t oflags;
-     int _printit;
-@@ -1124,7 +1126,7 @@
-                       ? dbfullpath : dbfile;
- #endif
--              rc = db->open(db, dbpath, dbsubfile,
-+              rc = db->open(db, txnid, dbpath, dbsubfile,
-                   dbi->dbi_type, oflags, dbi->dbi_perms);
-               if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
This page took 0.967133 seconds and 4 git commands to generate.