--- /dev/null
+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='-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'</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 "interpreter" to script</change>
++ </changes>
++ <changes date="Sat May 25 2002"
++ author="Jaco Greeff"
++ author-email="jaco@puxedo.org"
++ version="1.0-03">
++ <change>Moved <files> into <package> structure</change>
++ <change>Added <nosource> tag as example</change>
++ <change>Changed <shell> to <script></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,