Imported Upstream version 0.6.27 97/194197/1 upstream/0.6.27
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 30 Nov 2018 03:40:36 +0000 (12:40 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 30 Nov 2018 03:40:36 +0000 (12:40 +0900)
Change-Id: I4feccd10bd9fe0514ff13520136e962b6c093175
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
54 files changed:
CMakeLists.txt
NEWS
VERSION.cmake
bindings/python3/CMakeLists.txt
bindings/solv.i
ext/CMakeLists.txt
ext/pool_fileconflicts.c
ext/repo_appdata.c
ext/repo_comps.c
ext/repo_content.c
ext/repo_cudf.c
ext/repo_deltainfoxml.c
ext/repo_helix.c
ext/repo_mdk.c
ext/repo_products.c
ext/repo_pubkey.c
ext/repo_repomdxml.c
ext/repo_rpmdb.c
ext/repo_rpmmd.c
ext/repo_susetags.c
ext/repo_updateinfoxml.c
ext/repo_zyppdb.c
ext/repodata_diskusage.c [new file with mode: 0644]
ext/repodata_diskusage.h [new file with mode: 0644]
ext/solv_xfopen.c
ext/solv_xmlparser.c [new file with mode: 0644]
ext/solv_xmlparser.h [new file with mode: 0644]
ext/testcase.c
package/libsolv.changes
package/libsolv.spec.in
src/pool.c
src/pool.h
src/poolid.c
src/queue.c
src/repodata.c
src/rules.c
src/solver.c
src/solvversion.h.in
test/testcases/testcase/nested.t [new file with mode: 0644]
tools/appdata2solv.c
tools/archrepo2solv.c
tools/common_write.c
tools/comps2solv.c
tools/deltainfoxml2solv.c
tools/helix2solv.c
tools/installcheck.c
tools/mdk2solv.c
tools/mergesolv.c
tools/patchcheck.c
tools/repomdxml2solv.c
tools/rpmdb2solv.c
tools/rpmmd2solv.c
tools/susetags2solv.c
tools/updateinfoxml2solv.c

index 838f9d0..bcdeee6 100644 (file)
@@ -32,6 +32,8 @@ OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OF
 OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF)
 OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF)
 
+OPTION (WITH_LIBXML2  "Build with libxml2 instead of libexpat?" OFF)
+
 #IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
 #ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
 
@@ -153,16 +155,29 @@ IF (${have_system} STRGREATER xx)
     MESSAGE (FATAL_ERROR "Can only compile for one system type.")
 ENDIF (${have_system} STRGREATER xx)
 
+SET (ENABLE_ZLIB_COMPRESSION ON)
 IF (ENABLE_ARCHREPO)
 SET (ENABLE_LZMA_COMPRESSION ON)
 ENDIF (ENABLE_ARCHREPO)
 
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (WITH_LIBXML2 )
+FIND_PACKAGE (LibXml2 REQUIRED)
+INCLUDE_DIRECTORIES (${LIBXML2_INCLUDE_DIR})
+ELSE(WITH_LIBXML2 )
 FIND_PACKAGE (EXPAT REQUIRED)
 INCLUDE_DIRECTORIES (${EXPAT_INCLUDE_DIRS})
+ENDIF (WITH_LIBXML2 )
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+
+IF (ENABLE_ZLIB_COMPRESSION)
 FIND_PACKAGE (ZLIB REQUIRED)
+ENDIF (ENABLE_ZLIB_COMPRESSION)
+
 IF (ENABLE_LZMA_COMPRESSION)
 FIND_PACKAGE (LZMA REQUIRED)
 ENDIF (ENABLE_LZMA_COMPRESSION)
+
 IF (ENABLE_BZIP2_COMPRESSION)
 FIND_PACKAGE (BZip2 REQUIRED)
 ENDIF (ENABLE_BZIP2_COMPRESSION)
@@ -250,7 +265,7 @@ ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2)
 
 # should create config.h with #cmakedefine instead...
 FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
-  HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS)
+  HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS WITH_LIBXML2 )
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
@@ -271,7 +286,8 @@ FOREACH (VAR
   ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER
   ENABLE_SUSEREPO ENABLE_COMPS
   ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
-  ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA)
+  ENABLE_ZLIB_COMPRESSION ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION
+  ENABLE_PGPVRFY ENABLE_APPDATA)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
@@ -355,7 +371,19 @@ set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3")
 set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O3")
 set (CMAKE_C_FLAGS_DEBUG     "${CMAKE_C_FLAGS} -g3 -O0")
 
-SET (SYSTEM_LIBRARIES ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+# set system libraries
+SET (SYSTEM_LIBRARIES "")
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (WITH_LIBXML2 )
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LIBXML2_LIBRARIES})
+ELSE (WITH_LIBXML2 )
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${EXPAT_LIBRARY})
+ENDIF (WITH_LIBXML2 )
+
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (ENABLE_ZLIB_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZLIB_LIBRARY})
+ENDIF (ENABLE_ZLIB_COMPRESSION)
 IF (ENABLE_LZMA_COMPRESSION)
 SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LZMA_LIBRARY})
 ENDIF (ENABLE_LZMA_COMPRESSION)
diff --git a/NEWS b/NEWS
index c4d9f11..ed1a963 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@
 This file contains the major changes between
 libsolv versions:
 
+Version 0.6.27
+- new features:
+  * allow building with libxml2 instead of libexpat
+  * better handing of "forcebest with uninstall"
+  * speed improvements for "name = md5sum" dependencies
+
 Version 0.6.26
 - export solvable_matchesdep function, as we now
   use it in the bindings
index 1d0be13..55b1018 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "26")
+SET(LIBSOLV_PATCH "27")
 
index 7a2dca3..09c8e29 100644 (file)
@@ -6,9 +6,9 @@
 # we cannot use FIND_PACKAGE PythonLibs here, as this would
 # clash with the python variables.
 #
-IF (NOT DEFINED ${PYTHON3_EXECUTABLE})
+IF (NOT DEFINED PYTHON3_EXECUTABLE)
 SET (PYTHON3_EXECUTABLE "/usr/bin/python3")
-ENDIF (NOT DEFINED ${PYTHON3_EXECUTABLE})
+ENDIF (NOT DEFINED PYTHON3_EXECUTABLE)
 
 EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON3_INSTALL_DIR)
 EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_inc())" OUTPUT_VARIABLE PYTHON3_INCLUDE_DIR)
index 61dc640..7302d3a 100644 (file)
@@ -932,12 +932,18 @@ typedef int Id;
 %constant int REL_EQ;
 %constant int REL_GT;
 %constant int REL_LT;
-%constant int REL_ARCH;
 %constant int REL_AND;
 %constant int REL_OR;
 %constant int REL_WITH;
+%constant int REL_NAMESPACE;
+%constant int REL_ARCH;
+%constant int REL_FILECONFLICT;
 %constant int REL_COND;
+%constant int REL_COMPAT;
+%constant int REL_KIND;
+%constant int REL_MULTIARCH;
 %constant int REL_ELSE;
+%constant int REL_ERROR;
 
 typedef struct {
   Pool* const pool;
index 586eda8..bdc6ee9 100644 (file)
@@ -116,6 +116,16 @@ IF (ENABLE_APPDATA)
        repo_appdata.h)
 ENDIF (ENABLE_APPDATA)
 
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repodata_diskusage.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_xmlparser.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+
 SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 IF (HAVE_LINKER_VERSION_SCRIPT)
 SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
index 6c9119f..cb55d58 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <stdio.h>
 #include <sys/stat.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 
 #include "pool.h"
index 2b9844e..62faf2d 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <dirent.h>
-#include <expat.h>
 #include <errno.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
+#include "solv_xmlparser.h"
 #include "repo_appdata.h"
 
 
@@ -53,15 +50,8 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
 
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,       "applications",  STATE_START,         0 },
   { STATE_START,       "components",    STATE_START,         0 },
   { STATE_START,       "application",   STATE_APPLICATION,   0 },
@@ -86,23 +76,15 @@ static struct stateswitch stateswitches[] = {
 };
 
 struct parsedata {
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
+  int ret;
 
   Solvable *solvable;
   Id handle;
 
+  int skiplang;
   char *description;
   int licnt;
   int skip_depth;
@@ -111,74 +93,30 @@ struct parsedata {
   int havesummary;
   const char *filename;
   Queue *owners;
-};
-
 
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    if (!strcmp(*atts, txt))
-      return atts[1];
-  return 0;
-}
+  struct solv_xmlparser xmlp;
+};
 
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
-  struct stateswitch *sw;
   const char *type;
 
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  if (!pd->skip_depth && find_attr("xml:lang", atts))
-    pd->skip_depth = pd->depth;
-  if (pd->skip_depth)
+  /* ignore all language tags */
+  if (pd->skiplang || solv_xmlparser_find_attr("xml:lang", atts))
     {
-      pd->docontent = 0;
+      pd->skiplang++;
       return;
     }
 
-  switch(pd->state)
+  switch(state)
     {
     case STATE_APPLICATION:
-      type = find_attr("type", atts);
+      type = solv_xmlparser_find_attr("type", atts);
       if (!type || !*type)
         type = "desktop";
       if (strcmp(type, "desktop") != 0)
@@ -206,51 +144,55 @@ startElement(void *userData, const char *name, const char **atts)
 
 /* replace whitespace with one space/newline */
 /* also strip starting/ending whitespace */
-static void
+static char *
 wsstrip(struct parsedata *pd)
 {
+  struct solv_xmlparser *xmlp = &pd->xmlp;
   int i, j;
   int ws = 0;
-  for (i = j = 0; pd->content[i]; i++)
+  for (i = j = 0; xmlp->content[i]; i++)
     {
-      if (pd->content[i] == ' ' || pd->content[i] == '\t' || pd->content[i] == '\n')
+      if (xmlp->content[i] == ' ' || xmlp->content[i] == '\t' || xmlp->content[i] == '\n')
        {
-         ws |= pd->content[i] == '\n' ? 2 : 1;
+         ws |= xmlp->content[i] == '\n' ? 2 : 1;
          continue;
        }
       if (ws && j)
-       pd->content[j++] = (ws & 2) ? '\n' : ' ';
+       xmlp->content[j++] = (ws & 2) ? '\n' : ' ';
       ws = 0;
-      pd->content[j++] = pd->content[i];
+      xmlp->content[j++] = xmlp->content[i];
     }
-  pd->content[j] = 0;
-  pd->lcontent = j;
+  xmlp->content[j] = 0;
+  xmlp->lcontent = j;
+  return xmlp->content;
 }
 
 /* indent all lines */
-static void
+static char *
 indent(struct parsedata *pd, int il)
 {
+  struct solv_xmlparser *xmlp = &pd->xmlp;
   int i, l;
-  for (l = 0; pd->content[l]; )
+  for (l = 0; xmlp->content[l]; )
     {
-      if (pd->content[l] == '\n')
+      if (xmlp->content[l] == '\n')
        {
          l++;
          continue;
        }
-      if (pd->lcontent + il + 1 > pd->acontent)
+      if (xmlp->lcontent + il + 1 > xmlp->acontent)
        {
-         pd->acontent = pd->lcontent + il + 256;
-         pd->content = realloc(pd->content, pd->acontent);
+         xmlp->acontent = xmlp->lcontent + il + 256;
+         xmlp->content = realloc(xmlp->content, xmlp->acontent);
        }
-      memmove(pd->content + l + il, pd->content + l, pd->lcontent - l + 1);
+      memmove(xmlp->content + l + il, xmlp->content + l, xmlp->lcontent - l + 1);
       for (i = 0; i < il; i++)
-       pd->content[l + i] = ' ';
-      pd->lcontent += il;
-      while (pd->content[l] && pd->content[l] != '\n')
+       xmlp->content[l + i] = ' ';
+      xmlp->lcontent += il;
+      while (xmlp->content[l] && xmlp->content[l] != '\n')
        l++;
     }
+  return xmlp->content;
 }
 
 static void
@@ -346,47 +288,23 @@ guess_filename_from_id(Pool *pool, const char *id)
   return r;
 }
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
   Id id;
 
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  if (pd->skip_depth && pd->depth + 1 >= pd->skip_depth)
+  if (pd->skiplang)
     {
-      if (pd->depth + 1 == pd->skip_depth)
-       pd->skip_depth = 0;
-      pd->state = pd->sbtab[pd->state];
-      pd->docontent = 0;
+      pd->skiplang--;
       return;
     }
-  pd->skip_depth = 0;
-
   if (!s)
-    {
-      pd->state = pd->sbtab[pd->state];
-      pd->docontent = 0;
-      return;
-    }
+    return;
 
-  switch (pd->state)
+  switch (state)
     {
     case STATE_APPLICATION:
       if (!s->arch)
@@ -434,26 +352,26 @@ endElement(void *userData, const char *name)
       pd->desktop_file = solv_free(pd->desktop_file);
       break;
     case STATE_ID:
-      pd->desktop_file = solv_strdup(pd->content);
+      pd->desktop_file = solv_strdup(content);
       break;
     case STATE_NAME:
-      s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", pd->content, 0), 1);
+      s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", content, 0), 1);
       break;
     case STATE_LICENCE:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, pd->content);
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, content);
       break;
     case STATE_SUMMARY:
       pd->havesummary = 1;
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
       break;
     case STATE_URL:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, pd->content);
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, content);
       break;
     case STATE_GROUP:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, pd->content);
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, content);
       break;
     case STATE_EXTENDS:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, pd->content);
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, content);
       break;
     case STATE_DESCRIPTION:
       if (pd->description)
@@ -466,83 +384,60 @@ endElement(void *userData, const char *name)
        }
       break;
     case STATE_P:
-      wsstrip(pd);
-      pd->description = solv_dupappend(pd->description, pd->content, "\n\n");
+      content = wsstrip(pd);
+      pd->description = solv_dupappend(pd->description, content, "\n\n");
       break;
     case STATE_UL_LI:
       wsstrip(pd);
-      indent(pd, 4);
-      pd->content[2] = '-';
-      pd->description = solv_dupappend(pd->description, pd->content, "\n");
+      content = indent(pd, 4);
+      content[2] = '-';
+      pd->description = solv_dupappend(pd->description, content, "\n");
       break;
     case STATE_OL_LI:
       wsstrip(pd);
-      indent(pd, 4);
+      content = indent(pd, 4);
       if (++pd->licnt >= 10)
-       pd->content[0] = '0' + (pd->licnt / 10) % 10;
-      pd->content[1] = '0' + pd->licnt  % 10;
-      pd->content[2] = '.';
-      pd->description = solv_dupappend(pd->description, pd->content, "\n");
+       content[0] = '0' + (pd->licnt / 10) % 10;
+      content[1] = '0' + pd->licnt  % 10;
+      content[2] = '.';
+      pd->description = solv_dupappend(pd->description, content, "\n");
       break;
     case STATE_UL:
     case STATE_OL:
       pd->description = solv_dupappend(pd->description, "\n", 0);
       break;
     case STATE_PKGNAME:
-      id = pool_str2id(pd->pool, pd->content, 1);
+      id = pool_str2id(pd->pool, content, 1);
       s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
-      id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pd->content, ")"), 1);
+      id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", content, ")"), 1);
       s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
       break;
     case STATE_KEYWORD:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, pd->content);
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, content);
       break;
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-  fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->acontent = l + 256;
-      pd->content = realloc(pd->content, pd->acontent);
+  struct parsedata *pd = xmlp->userdata;
+  pool_debug(pd->pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", errstr, line, column);
+  pd->ret = -1;
+  if (pd->solvable)
+    {   
+      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); 
+      pd->solvable = 0;
     }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
 }
 
-#define BUFF_SIZE 8192
-
 static int
 repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners)
 {
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  struct stateswitch *sw;
   Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  int ret = 0;
+  struct parsedata pd;
 
   data = repo_add_repodata(repo, flags);
   memset(&pd, 0, sizeof(pd));
@@ -553,47 +448,17 @@ repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue
   pd.filename = filename;
   pd.owners = owners;
 
-  pd.content = malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  XML_Parser parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
 
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_error(pool, -1, "repo_appdata: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         if (pd.solvable)
-           {
-             repo_free_solvable(repo, pd.solvable - pd.pool->solvables, 1);
-             pd.solvable = 0;
-           }
-         ret = -1;
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
+  solv_free(pd.desktop_file);
+  solv_free(pd.description);
 
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
 
-  solv_free(pd.content);
-  solv_free(pd.desktop_file);
-  solv_free(pd.description);
-  return ret;
+  return pd.ret;
 }
 
 int
index 8f364dd..255ecb1 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
-#include <dirent.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
+#include "solv_xmlparser.h"
 #define DISABLE_SPLIT
 #include "tools_util.h"
 #include "repo_comps.h"
@@ -62,15 +58,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,       "comps",         STATE_COMPS,         0 },
   { STATE_COMPS,       "group",         STATE_GROUP,         0 },
   { STATE_COMPS,       "category",      STATE_CATEGORY,      0 },
@@ -84,11 +72,11 @@ static struct stateswitch stateswitches[] = {
   { STATE_GROUP,       "lang_only",     STATE_LANG_ONLY,     1 },
   { STATE_GROUP,       "packagelist",   STATE_PACKAGELIST,   0 },
   { STATE_PACKAGELIST, "packagereq",    STATE_PACKAGEREQ,    1 },
-  { STATE_CATEGORY,    "id",            STATE_CID,           1 },
-  { STATE_CATEGORY,    "name",          STATE_CNAME,         1 },
-  { STATE_CATEGORY,    "description",   STATE_CDESCRIPTION,  1 },
+  { STATE_CATEGORY,    "id",            STATE_ID,            1 },
+  { STATE_CATEGORY,    "name",          STATE_NAME,          1 },
+  { STATE_CATEGORY,    "description",   STATE_DESCRIPTION,   1 },
   { STATE_CATEGORY ,   "grouplist",     STATE_GROUPLIST,     0 },
-  { STATE_CATEGORY ,   "display_order", STATE_CDISPLAY_ORDER, 1 },
+  { STATE_CATEGORY ,   "display_order", STATE_DISPLAY_ORDER, 1 },
   { STATE_GROUPLIST,   "groupid",       STATE_GROUPID,       1 },
   { NUMSTATES }
 };
@@ -99,16 +87,8 @@ struct parsedata {
   Repodata *data;
   const char *filename;
   const char *basename;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
+
+  struct solv_xmlparser xmlp;
   struct joindata jd;
 
   const char *tmplang;
@@ -116,100 +96,43 @@ struct parsedata {
   Id condreq;
 
   Solvable *solvable;
+  const char *kind;
   Id handle;
 };
 
 
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-      fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
 
-  switch(pd->state)
+  switch(state)
     {
     case STATE_GROUP:
     case STATE_CATEGORY:
       s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
       pd->handle = s - pool->solvables;
+      pd->kind = state == STATE_GROUP ? "group" : "category";
       break;
 
     case STATE_NAME:
     case STATE_CNAME:
     case STATE_DESCRIPTION:
     case STATE_CDESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("xml:lang", atts));
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts));
       break;
 
     case STATE_PACKAGEREQ:
       {
-       const char *type = find_attr("type", atts);
+       const char *type = solv_xmlparser_find_attr("type", atts);
        pd->condreq = 0;
        pd->reqtype = SOLVABLE_RECOMMENDS;
        if (type && !strcmp(type, "conditional"))
          {
-           const char *requires = find_attr("requires", atts);
+           const char *requires = solv_xmlparser_find_attr("requires", atts);
            if (requires && *requires)
              pd->condreq = pool_str2id(pool, requires, 1);
          }
@@ -226,29 +149,14 @@ startElement(void *userData, const char *name, const char **atts)
 }
 
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Solvable *s = pd->solvable;
   Id id;
 
-#if 0
-      fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
+  switch (state)
     {
     case STATE_GROUP:
     case STATE_CATEGORY:
@@ -262,29 +170,26 @@ endElement(void *userData, const char *name)
       break;
 
     case STATE_ID:
-    case STATE_CID:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->state == STATE_ID ? "group" : "category", ":", pd->content), 1);
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1);
       break;
 
     case STATE_NAME:
-    case STATE_CNAME:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
       break;
 
     case STATE_DESCRIPTION:
-    case STATE_CDESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
       break;
 
     case STATE_PACKAGEREQ:
-      id = pool_str2id(pd->pool, pd->content, 1);
+      id = pool_str2id(pd->pool, content, 1);
       if (pd->condreq)
        id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
       repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
       break;
 
     case STATE_GROUPID:
-      id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", pd->content), 1);
+      id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1);
       s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
       break;
 
@@ -293,63 +198,27 @@ endElement(void *userData, const char *name)
       break;
 
     case STATE_DISPLAY_ORDER:
-    case STATE_CDISPLAY_ORDER:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, pd->content);
-      break;
-
-    case STATE_DEFAULT:
-      break;
-
-    case STATE_LANGONLY:
-    case STATE_LANG_ONLY:
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content);
       break;
 
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-      fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pool_debug(pd->pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", errstr, line, column);
 }
 
-#define BUFF_SIZE 8192
-
 
 int
 repo_add_comps(Repo *repo, FILE *fp, int flags)
 {
   Repodata *data;
   struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
 
   data = repo_add_repodata(repo, flags);
 
@@ -357,35 +226,9 @@ repo_add_comps(Repo *repo, FILE *fp, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-
-  solv_free(pd.content);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
 
   if (!(flags & REPO_NO_INTERNALIZE))
index b12c4cd..68af2d5 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 00a4f87..14ddcc9 100644 (file)
@@ -11,7 +11,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <zlib.h>
 #include <errno.h>
 
 #include "pool.h"
index 06df1a3..4eb340f 100644 (file)
@@ -5,20 +5,16 @@
  * for further information
  */
 
-#define DO_ARRAY 1
-
 #define _GNU_SOURCE
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "chksum.h"
+#include "solv_xmlparser.h"
 #include "repo_deltainfoxml.h"
 
 /*
@@ -52,15 +48,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   /* compatibility with old yum-presto */
   { STATE_START,       "prestodelta",     STATE_START, 0 },
   { STATE_START,       "deltainfo",       STATE_START, 0 },
@@ -93,19 +81,10 @@ struct deltarpm {
 
 struct parsedata {
   int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
 
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
   struct deltarpm delta;
   Id newpkgevr;
   Id newpkgname;
@@ -113,22 +92,9 @@ struct parsedata {
 
   Id *handles;
   int nhandles;
-};
 
-/*
- * find attribute
- */
-
-static const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
+  struct solv_xmlparser xmlp;
+};
 
 
 /*
@@ -139,7 +105,7 @@ static Id
 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
 {
   const char *e, *v, *r, *v2;
-  char *c;
+  char *c, *space;
   int l;
 
   e = v = r = 0;
@@ -174,12 +140,7 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
     l += strlen(v);
   if (r)
     l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
   if (e)
     {
       strcpy(c, e);
@@ -198,59 +159,28 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
       c += strlen(c);
     }
   *c = 0;
-  if (!*pd->content)
+  if (!*space)
     return 0;
 #if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
+  fprintf(stderr, "evr: %s\n", space);
 #endif
-  return pool_str2id(pool, pd->content, 1);
+  return pool_str2id(pool, space, 1);
 }
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
-  struct stateswitch *sw;
   const char *str;
 
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
+  switch(state)
     {
-#if 0
-      fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_START:
-      break;
     case STATE_NEWPACKAGE:
-      if ((str = find_attr("name", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("name", atts)) != 0)
        pd->newpkgname = pool_str2id(pool, str, 1);
       pd->newpkgevr = makeevr_atts(pool, pd, atts);
-      if ((str = find_attr("arch", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("arch", atts)) != 0)
        pd->newpkgarch = pool_str2id(pool, str, 1);
       break;
 
@@ -259,62 +189,44 @@ startElement(void *userData, const char *name, const char **atts)
       pd->delta.bevr = solv_extend(pd->delta.bevr, pd->delta.nbevr, 1, sizeof(Id), 7);
       pd->delta.bevr[pd->delta.nbevr++] = makeevr_atts(pool, pd, atts);
       break;
+
     case STATE_FILENAME:
-      if ((str = find_attr("xml:base", atts)))
+      if ((str = solv_xmlparser_find_attr("xml:base", atts)))
         pd->delta.locbase = solv_strdup(str);
       break;
+
     case STATE_LOCATION:
-      pd->delta.location = solv_strdup(find_attr("href", atts));
-      if ((str = find_attr("xml:base", atts)))
+      pd->delta.location = solv_strdup(solv_xmlparser_find_attr("href", atts));
+      if ((str = solv_xmlparser_find_attr("xml:base", atts)))
         pd->delta.locbase = solv_strdup(str);
       break;
-    case STATE_SIZE:
-      break;
+
     case STATE_CHECKSUM:
       pd->delta.filechecksum = 0;
       pd->delta.filechecksumtype = REPOKEY_TYPE_SHA1;
-      if ((str = find_attr("type", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("type", atts)) != 0)
        {
          pd->delta.filechecksumtype = solv_chksum_str2type(str);
          if (!pd->delta.filechecksumtype)
            pool_debug(pool, SOLV_ERROR, "unknown checksum type: '%s'\n", str);
        }
       break;
-    case STATE_SEQUENCE:
-      break;
+
     default:
       break;
     }
 }
 
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   const char *str;
 
-#if 0
-  fprintf(stderr, "end: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
+  switch (state)
     {
-    case STATE_START:
-      break;
-    case STATE_NEWPACKAGE:
-      break;
     case STATE_DELTA:
       {
        /* read all data for a deltarpm. commit into attributes */
@@ -356,16 +268,16 @@ endElement(void *userData, const char *name)
       pd->delta.locbase = solv_free(pd->delta.locbase);
       break;
     case STATE_FILENAME:
-      pd->delta.location = solv_strdup(pd->content);
+      pd->delta.location = solv_strdup(content);
       break;
     case STATE_CHECKSUM:
-      pd->delta.filechecksum = solv_strdup(pd->content);
+      pd->delta.filechecksum = solv_strdup(content);
       break;
     case STATE_SIZE:
-      pd->delta.downloadsize = strtoull(pd->content, 0, 10);
+      pd->delta.downloadsize = strtoull(content, 0, 10);
       break;
     case STATE_SEQUENCE:
-      if ((str = pd->content))
+      if ((str = content) != 0)
        {
          const char *s1, *s2;
          s1 = strrchr(str, '-');
@@ -392,80 +304,32 @@ endElement(void *userData, const char *name)
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pd->ret = pool_error(pd->pool, -1, "repo_deltainfoxml: %s at line %u:%u", errstr, line, column);
 }
 
-#define BUFF_SIZE 8192
-
 int
 repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
 {
   Pool *pool = repo->pool;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
   Repodata *data;
-  XML_Parser parser;
+  struct parsedata pd;
+  int i;
 
   data = repo_add_repodata(repo, flags);
 
   memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
 
   /* now commit all handles */
   if (!pd.ret)
index 6358f72..3c2c6d1 100644 (file)
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <expat.h>
 
+#include "queue.h"
+#include "solv_xmlparser.h"
 #include "repo_helix.h"
 #include "evr.h"
 
@@ -75,22 +74,10 @@ enum state {
   STATE_PATCH,
   STATE_PRODUCT,
 
-  STATE_PEPOCH,
-  STATE_PVERSION,
-  STATE_PRELEASE,
-  STATE_PARCH,
-
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,       "channel",         STATE_CHANNEL, 0 },
   { STATE_CHANNEL,     "subchannel",      STATE_SUBCHANNEL, 0 },
   { STATE_SUBCHANNEL,  "package",         STATE_PACKAGE, 0 },
@@ -104,10 +91,10 @@ static struct stateswitch stateswitches[] = {
   { STATE_PACKAGE,     "name",            STATE_NAME, 1 },
   { STATE_PACKAGE,     "vendor",          STATE_VENDOR, 1 },
   { STATE_PACKAGE,     "buildtime",       STATE_BUILDTIME, 1 },
-  { STATE_PACKAGE,     "epoch",           STATE_PEPOCH, 1 },
-  { STATE_PACKAGE,     "version",         STATE_PVERSION, 1 },
-  { STATE_PACKAGE,     "release",         STATE_PRELEASE, 1 },
-  { STATE_PACKAGE,     "arch",            STATE_PARCH, 1 },
+  { STATE_PACKAGE,     "epoch",           STATE_EPOCH, 1 },
+  { STATE_PACKAGE,     "version",         STATE_VERSION, 1 },
+  { STATE_PACKAGE,     "release",         STATE_RELEASE, 1 },
+  { STATE_PACKAGE,     "arch",            STATE_ARCH, 1 },
   { STATE_PACKAGE,     "history",         STATE_HISTORY, 0 },
   { STATE_PACKAGE,     "provides",        STATE_PROVIDES, 0 },
   { STATE_PACKAGE,     "requires",        STATE_REQUIRES, 0 },
@@ -119,6 +106,7 @@ static struct stateswitch stateswitches[] = {
   { STATE_PACKAGE,     "suggests",        STATE_SUGGESTS, 0 },
   { STATE_PACKAGE,     "enhances",        STATE_ENHANCES, 0 },
   { STATE_PACKAGE,     "freshens",        STATE_FRESHENS, 0 },
+  { STATE_PACKAGE,     "deps",            STATE_PACKAGE, 0 },  /* ignore deps element */
 
   { STATE_HISTORY,     "update",          STATE_UPDATE, 0 },
   { STATE_UPDATE,      "epoch",           STATE_EPOCH, 1 },
@@ -144,17 +132,8 @@ static struct stateswitch stateswitches[] = {
  * parser data
  */
 
-typedef struct _parsedata {
+struct parsedata {
   int ret;
-  /* XML parser data */
-  int depth;
-  enum state state;    /* current state */
-  int statedepth;
-  char *content;       /* buffer for content of node */
-  int lcontent;                /* actual length of current content */
-  int acontent;                /* actual buffer size */
-  int docontent;       /* handle content */
-
   /* repo data */
   Pool *pool;          /* current pool */
   Repo *repo;          /* current repo */
@@ -163,6 +142,7 @@ typedef struct _parsedata {
   Offset freshens;     /* current freshens vector */
 
   /* package data */
+  int  srcpackage;     /* is srcpackage element */
   int  epoch;          /* epoch (as offset into evrspace) */
   int  version;                /* version (as offset into evrspace) */
   int  release;                /* release (as offset into evrspace) */
@@ -171,9 +151,8 @@ typedef struct _parsedata {
   int  levrspace;      /* actual evr length */
   char *kind;
 
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-} Parsedata;
+  struct solv_xmlparser xmlp;
+};
 
 
 /*------------------------------------------------------------------*/
@@ -182,9 +161,9 @@ typedef struct _parsedata {
 /* create Id from epoch:version-release */
 
 static Id
-evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
+evr2id(Pool *pool, struct parsedata *pd, const char *e, const char *v, const char *r)
 {
-  char *c;
+  char *c, *space;
   int l;
 
   /* treat explitcit 0 as NULL */
@@ -211,15 +190,10 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
   if (r)
     l += strlen(r) + 1;  /* -r */
 
-  /* extend content if not sufficient */
-  if (l > pd->acontent)
-    {
-      pd->content = (char *)realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
+  /* get content space */
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
 
-  /* copy e-v-r to content */
-  c = pd->content;
+  /* copy e-v-r */
   if (e)
     {
       strcpy(c, e);
@@ -239,13 +213,13 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
     }
   *c = 0;
   /* if nothing inserted, return Id 0 */
-  if (!*pd->content)
-    return ID_NULL;
+  if (!*space)
+    return 0;
 #if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
+  fprintf(stderr, "evr: %s\n", space);
 #endif
   /* intern and create */
-  return pool_str2id(pool, pd->content, 1);
+  return pool_str2id(pool, space, 1);
 }
 
 
@@ -255,7 +229,7 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
  *   odd index is value
  */
 static Id
-evr_atts2id(Pool *pool, Parsedata *pd, const char **atts)
+evr_atts2id(Pool *pool, struct parsedata *pd, const char **atts)
 {
   const char *e, *v, *r;
   e = v = r = 0;
@@ -312,7 +286,7 @@ static struct flagtab flagtab[] = {
  */
 
 static unsigned int
-adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
 {
   Id id, name;
   const char *n, *f, *k;
@@ -342,13 +316,9 @@ adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id ma
   if (k)                              /* if kind!=package, intern <kind>:<name> */
     {
       int l = strlen(k) + 1 + strlen(n) + 1;
-      if (l > pd->acontent)           /* extend buffer if needed */
-       {
-         pd->content = (char *)realloc(pd->content, l + 256);
-         pd->acontent = l + 256;
-       }
-      sprintf(pd->content, "%s:%s", k, n);
-      name = pool_str2id(pool, pd->content, 1);
+      char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+      sprintf(space, "%s:%s", k, n);
+      name = pool_str2id(pool, space, 1);
     }
   else
     {
@@ -382,76 +352,30 @@ adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id ma
 
 /*----------------------------------------------------------------*/
 
-/*
- * XML callback
- * <name>
- *
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  Parsedata *pd = (Parsedata *)userData;
-  struct stateswitch *sw;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
 
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  /* ignore deps element */
-  if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
-    return;
-
-  pd->depth++;
-
-  /* find node name in stateswitch */
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-  {
-    if (!strcmp(sw->ename, name))
-      break;
-  }
-
-  /* check if we're at the right level */
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s\n", name);
-#endif
-      return;
-    }
-
-  /* set new state */
-  pd->state = sw->to;
-
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-
-  /* start with empty content */
-  /* (will collect data until end element) */
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch (pd->state)
+  switch (state)
     {
 
     case STATE_NAME:
       if (pd->kind)                   /* if kind is set (non package) */
         {
-          strcpy(pd->content, pd->kind);
-          pd->lcontent = strlen(pd->content);
-         pd->content[pd->lcontent++] = ':';   /* prefix name with '<kind>:' */
-         pd->content[pd->lcontent] = 0;
+          strcpy(xmlp->content, pd->kind);
+          xmlp->lcontent = strlen(xmlp->content);
+         xmlp->content[xmlp->lcontent++] = ':';   /* prefix name with '<kind>:' */
+         xmlp->content[xmlp->lcontent] = 0;
        }
       break;
 
     case STATE_PACKAGE:                       /* solvable name */
       pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+      pd->srcpackage = 0;
+      pd->kind = NULL;                /* default is (src)package */
       if (!strcmp(name, "selection"))
         pd->kind = "selection";
       else if (!strcmp(name, "pattern"))
@@ -464,8 +388,8 @@ startElement(void *userData, const char *name, const char **atts)
         pd->kind = "patch";
       else if (!strcmp(name, "application"))
         pd->kind = "application";
-      else
-        pd->kind = NULL;              /* default is package */
+      else if (!strcmp(name, "srcpackage"))
+       pd->srcpackage = 1;
       pd->levrspace = 1;
       pd->epoch = 0;
       pd->version = 0;
@@ -542,7 +466,8 @@ startElement(void *userData, const char *name, const char **atts)
     }
 }
 
-static const char *findKernelFlavor(Parsedata *pd, Solvable *s)
+static const char *
+findKernelFlavor(struct parsedata *pd, Solvable *s)
 {
   Pool *pool = pd->pool;
   Id pid, *pidp;
@@ -589,41 +514,21 @@ static const char *findKernelFlavor(Parsedata *pd, Solvable *s)
 }
 
 
-/*
- * XML callback
- * </name>
- *
- * create Solvable from collected data
- */
-
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  Parsedata *pd = (Parsedata *)userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
   Id evr;
   unsigned int t = 0;
   const char *flavor;
 
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-      return;
-    }
-
-  /* ignore deps element */
-  if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
-    return;
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
+  switch (state)
     {
 
     case STATE_PACKAGE:                       /* package complete */
-      if (name[0] == 's' && name[1] == 'r' && name[2] == 'c' && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+      if (pd->srcpackage && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
        s->arch = ARCH_SRC;
       if (!s->arch)                    /* default to "noarch" */
        s->arch = ARCH_NOARCH;
@@ -720,13 +625,13 @@ endElement(void *userData, const char *name)
        }
       break;
     case STATE_NAME:
-      s->name = pool_str2id(pool, pd->content, 1);
+      s->name = pool_str2id(pool, content, 1);
       break;
     case STATE_VENDOR:
-      s->vendor = pool_str2id(pool, pd->content, 1);
+      s->vendor = pool_str2id(pool, content, 1);
       break;
     case STATE_BUILDTIME:
-      t = atoi (pd->content);
+      t = atoi(content);
       if (t)
        repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
       break;   
@@ -746,72 +651,38 @@ endElement(void *userData, const char *name)
     case STATE_EPOCH:
     case STATE_VERSION:
     case STATE_RELEASE:
-    case STATE_PEPOCH:
-    case STATE_PVERSION:
-    case STATE_PRELEASE:
       /* ensure buffer space */
-      if (pd->lcontent + 1 + pd->levrspace > pd->aevrspace)
+      if (xmlp->lcontent + 1 + pd->levrspace > pd->aevrspace)
        {
-         pd->evrspace = (char *)realloc(pd->evrspace, pd->lcontent + 1 + pd->levrspace + 256);
-         pd->aevrspace = pd->lcontent + 1 + pd->levrspace + 256;
+         pd->aevrspace = xmlp->lcontent + 1 + pd->levrspace + 256;
+         pd->evrspace = (char *)realloc(pd->evrspace, pd->aevrspace);
        }
-      memcpy(pd->evrspace + pd->levrspace, pd->content, pd->lcontent + 1);
-      if (pd->state == STATE_EPOCH || pd->state == STATE_PEPOCH)
+      memcpy(pd->evrspace + pd->levrspace, xmlp->content, xmlp->lcontent + 1);
+      if (state == STATE_EPOCH)
        pd->epoch = pd->levrspace;
-      else if (pd->state == STATE_VERSION || pd->state == STATE_PVERSION)
+      else if (state == STATE_VERSION)
        pd->version = pd->levrspace;
       else
        pd->release = pd->levrspace;
-      pd->levrspace += pd->lcontent + 1;
+      pd->levrspace += xmlp->lcontent + 1;
       break;
     case STATE_ARCH:
-    case STATE_PARCH:
-      s->arch = pool_str2id(pool, pd->content, 1);
+      s->arch = pool_str2id(pool, content, 1);
       break;
     default:
       break;
     }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-  /* printf("back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
 }
 
-
-/*
- * XML callback
- * character data
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  Parsedata *pd = (Parsedata *)userData;
-  int l;
-  char *c;
-
-  /* check if current nodes content is interesting */
-  if (!pd->docontent)
-    return;
-
-  /* adapt content buffer */
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = (char *)realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  /* append new content to buffer */
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pd->ret = pool_error(pd->pool, -1, "%s at line %u", errstr, line);
 }
 
-/*-------------------------------------------------------------------*/
 
-#define BUFF_SIZE 8192
+/*-------------------------------------------------------------------*/
 
 /*
  * read 'helix' type xml from fp
@@ -823,60 +694,29 @@ int
 repo_add_helix(Repo *repo, FILE *fp, int flags)
 {
   Pool *pool = repo->pool;
-  Parsedata pd;
+  struct parsedata pd;
   Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
   unsigned int now;
-  XML_Parser parser;
 
   now = solv_timems(0);
   data = repo_add_repodata(repo, flags);
 
   /* prepare parsedata */
   memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
   pd.pool = pool;
   pd.repo = repo;
-
-  pd.content = (char *)malloc(256);    /* must hold all solvable kinds! */
-  pd.acontent = 256;
-  pd.lcontent = 0;
-
-  pd.evrspace = (char *)malloc(256);
-  pd.aevrspace= 256;
-  pd.levrspace = 1;
   pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
 
-  /* set up XML parser */
+  pd.evrspace = (char *)solv_malloc(256);
+  pd.aevrspace = 256;
+  pd.levrspace = 1;
 
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);       /* make parserdata available to XML callbacks */
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
 
-  /* read/parse XML file */
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "%s at line %u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  free(pd.content);
-  free(pd.evrspace);
+  solv_free(pd.evrspace);
 
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
index 345d416..418bc61 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
 #include "chksum.h"
+#include "solv_xmlparser.h"
 #include "repo_mdk.h"
 
 static Offset
@@ -246,15 +246,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
   { STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
   { STATE_MEDIA_INFO, "files", STATE_FILES, 1 },
@@ -265,31 +257,12 @@ struct parsedata {
   Pool *pool;
   Repo *repo;
   Repodata *data;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
   Solvable *solvable;
   Hashtable joinhash;
   Hashval joinhashmask;
+  struct solv_xmlparser xmlp;
 };
 
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
 static Hashtable
 joinhash_init(Repo *repo, Hashval *hmp)
 {
@@ -380,56 +353,37 @@ joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn, const char
   return 0;
 }
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
-  struct stateswitch *sw;
 
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
-    return;
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-  switch (pd->state)
+  switch (state)
     {
     case STATE_INFO:
       {
-       const char *fn = find_attr("fn", atts);
-       const char *distepoch = find_attr("distepoch", atts);
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
        const char *str;
        pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
        if (!pd->solvable)
          break;
-       str = find_attr("url", atts);
+       str = solv_xmlparser_find_attr("url", atts);
        if (str && *str)
          repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
-       str = find_attr("license", atts);
+       str = solv_xmlparser_find_attr("license", atts);
        if (str && *str)
          repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
-       str = find_attr("sourcerpm", atts);
+       str = solv_xmlparser_find_attr("sourcerpm", atts);
        if (str && *str)
          repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str);
         break;
       }
     case STATE_FILES:
       {
-       const char *fn = find_attr("fn", atts);
-       const char *distepoch = find_attr("distepoch", atts);
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
        pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
         break;
       }
@@ -438,29 +392,22 @@ startElement(void *userData, const char *name, const char **atts)
     }
 }
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Solvable *s = pd->solvable;
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      return;
-    }
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
+  switch (state)
     {
     case STATE_INFO:
-      if (s && *pd->content)
-        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, pd->content);
+      if (s && *content)
+        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, content);
       break;
     case STATE_FILES:
-      if (s && *pd->content)
+      if (s && *content)
        {
          char *np, *p, *sl;
-         for (p = pd->content; p && *p; p = np)
+         for (p = content; p && *p; p = np)
            {
              Id id;
              np = strchr(p, '\n');
@@ -488,42 +435,21 @@ endElement(void *userData, const char *name)
     default:
       break;
     }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
 }
 
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pool_debug(pd->pool, SOLV_ERROR, "%s at line %u:%u\n", errstr, line, column);
 }
 
-#define BUFF_SIZE 8192
 
 int
 repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
 {
   Repodata *data;
   struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
 
   if (!(flags & REPO_EXTEND_SOLVABLES))
     {
@@ -537,36 +463,10 @@ repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
   pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-        {
-          pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-          break;
-        }
-      if (l == 0)
-        break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
   solv_free(pd.joinhash);
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
index 326f8fd..154a909 100644 (file)
 #include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <dirent.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
+#include "solv_xmlparser.h"
 #define DISABLE_SPLIT
 #include "tools_util.h"
 #include "repo_content.h"
@@ -68,15 +65,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,     "product",       STATE_PRODUCT,       0 },
   { STATE_PRODUCT,   "vendor",        STATE_VENDOR,        1 },
   { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
@@ -107,19 +96,11 @@ static struct stateswitch stateswitches[] = {
 struct parsedata {
   const char *filename;
   const char *basename;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
 
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
+  struct solv_xmlparser xmlp;
   struct joindata jd;
 
   const char *tmplang;
@@ -139,26 +120,6 @@ struct parsedata {
 };
 
 
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
 static time_t
 datestr2timestamp(const char *date)
 {
@@ -183,58 +144,19 @@ datestr2timestamp(const char *date)
   return timegm(&tm);
 }
 
-/*
- * XML callback: startElement
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
 
-  switch(pd->state)
+  switch(state)
     {
     case STATE_PRODUCT:
       /* parse 'schemeversion' and store in global variable */
       {
-        const char * scheme = find_attr("schemeversion", atts);
+        const char * scheme = solv_xmlparser_find_attr("schemeversion", atts);
         pd->productscheme = (scheme && *scheme) ? atoi(scheme) : -1;
       }
       if (!s)
@@ -247,14 +169,14 @@ startElement(void *userData, const char *name, const char **atts)
       /* <summary lang="xy">... */
     case STATE_SUMMARY:
     case STATE_DESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
       break;
     case STATE_URL:
-      pd->urltype = pool_str2id(pd->pool, find_attr("name", atts), 1);
+      pd->urltype = pool_str2id(pd->pool, solv_xmlparser_find_attr("name", atts), 1);
       break;
     case STATE_REGUPDREPO:
       {
-        const char *repoid = find_attr("repoid", atts);
+        const char *repoid = solv_xmlparser_find_attr("repoid", atts);
        if (repoid && *repoid)
          {
            Id h = repodata_new_handle(pd->data);
@@ -269,28 +191,13 @@ startElement(void *userData, const char *name, const char **atts)
 }
 
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Solvable *s = pd->solvable;
 
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
+  switch (state)
     {
     case STATE_PRODUCT:
       /* product done, finish solvable */
@@ -326,144 +233,74 @@ endElement(void *userData, const char *name)
       pd->solvable = 0;
       break;
     case STATE_VENDOR:
-      s->vendor = pool_str2id(pd->pool, pd->content, 1);
+      s->vendor = pool_str2id(pd->pool, content, 1);
       break;
     case STATE_NAME:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
       break;
     case STATE_VERSION:
-      pd->tmpvers = solv_strdup(pd->content);
+      pd->tmpvers = solv_strdup(content);
       break;
     case STATE_RELEASE:
-      pd->tmprel = solv_strdup(pd->content);
+      pd->tmprel = solv_strdup(content);
       break;
     case STATE_ARCH:
-      s->arch = pool_str2id(pd->pool, pd->content, 1);
+      s->arch = pool_str2id(pd->pool, content, 1);
       break;
     case STATE_PRODUCTLINE:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, pd->content);
+      repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, content);
     break;
     case STATE_UPDATEREPOKEY:
       /** obsolete **/
       break;
     case STATE_SUMMARY:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
       break;
     case STATE_SHORTSUMMARY:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content);
+      repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, content);
       break;
     case STATE_DESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
       break;
     case STATE_URL:
       if (pd->urltype)
         {
-          repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content);
+          repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, content);
           repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, pd->urltype);
         }
       break;
     case STATE_TARGET:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, pd->content);
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, content);
       break;
     case STATE_REGRELEASE:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, pd->content);
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, content);
       break;
     case STATE_REGFLAVOR:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, pd->content);
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, content);
       break;
     case STATE_CPEID:
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, pd->content);
+      if (*content)
+        repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, content);
       break;
     case STATE_ENDOFLIFE:
       /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
-      repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*pd->content ? datestr2timestamp(pd->content) : 0));
+      repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*content ? datestr2timestamp(content) : 0));
       break;
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-      fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
 static void
-add_code11_product(struct parsedata *pd, FILE *fp)
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  char buf[BUFF_SIZE];
-  int l;
-  struct stat st;
-  XML_Parser parser;
-
-  if (!fstat(fileno(fp), &st))
-    {
-      pd->currentproduct = st.st_ino;
-      pd->ctime = (unsigned int)st.st_ctime;
-    }
-  else
-    {
-      pd->currentproduct = pd->baseproduct + 1; /* make it != baseproduct if stat fails */
-      pool_error(pd->pool, 0, "fstat: %s", strerror(errno));
-      pd->ctime = 0;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         XML_ParserFree(parser);
-         if (pd->solvable)
-           {
-             repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
-             pd->solvable = 0;
-           }
-         return;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
+  struct parsedata *pd = xmlp->userdata;
+  pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, errstr, line, column);
+  if (pd->solvable)
+    {   
+      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); 
+      pd->solvable = 0;
+    }   
 }
 
 
@@ -472,9 +309,7 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
 {
   Repodata *data;
   struct parsedata pd;
-  struct stateswitch *sw;
   DIR *dir;
-  int i;
 
   data = repo_add_repodata(repo, flags);
 
@@ -483,15 +318,7 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
   pd.pool = repo->pool;
   pd.data = data;
 
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
 
   if (flags & REPO_USE_ROOTDIR)
     dirpath = pool_prepend_rootdir(repo->pool, dirpath);
@@ -521,14 +348,22 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
              pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
              continue;
            }
+         if (fstat(fileno(fp), &st))
+           {
+             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+             fclose(fp);
+             continue;
+           }
+         pd.currentproduct = st.st_ino;
+         pd.ctime = (unsigned int)st.st_ctime;
          pd.filename = fullpath;
          pd.basename = entry->d_name;
-         add_code11_product(&pd, fp);
+         solv_xmlparser_parse(&pd.xmlp, fp);
          fclose(fp);
        }
       closedir(dir);
     }
-  solv_free(pd.content);
+  solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
   if (flags & REPO_USE_ROOTDIR)
     solv_free((char *)dirpath);
index d8496dc..eb83839 100644 (file)
@@ -14,8 +14,6 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 1d1197e..760d481 100644 (file)
@@ -5,20 +5,16 @@
  * for further information
  */
 
-#define DO_ARRAY 1
-
 #define _GNU_SOURCE
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "chksum.h"
+#include "solv_xmlparser.h"
 #include "repo_repomdxml.h"
 
 /*
@@ -110,15 +106,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   /* suseinfo tags */
   { STATE_START,       "repomd",          STATE_REPOMD, 0 },
   { STATE_START,       "suseinfo",        STATE_SUSEINFO, 0 },
@@ -153,20 +141,12 @@ static struct stateswitch stateswitches[] = {
 
 struct parsedata {
   int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
 
-  XML_Parser *parser;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
+  struct solv_xmlparser xmlp;
+
   int timestamp;
   /* handles for collection
      structures */
@@ -180,66 +160,20 @@ struct parsedata {
   Id chksumtype;
 };
 
-/*
- * find attribute
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
-  /*Pool *pool = pd->pool;*/
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
+  struct parsedata *pd = xmlp->userdata;
 
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
+  switch(state)
     {
     case STATE_REPOMD:
       {
         const char *updstr;
 
         /* this should be OBSOLETE soon */
-        updstr = find_attr("updates", atts);
+        updstr = solv_xmlparser_find_attr("updates", atts);
         if (updstr)
           {
             char *value = solv_strdup(updstr);
@@ -253,7 +187,7 @@ startElement(void *userData, const char *name, const char **atts)
                  repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
                value = p;
              }
-           free(fvalue);
+           solv_free(fvalue);
           }
         break;
       }
@@ -261,7 +195,7 @@ startElement(void *userData, const char *name, const char **atts)
       {
         /* this is extra metadata about the product this repository
            was designed for */
-        const char *cpeid = find_attr("cpeid", atts);
+        const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
         pd->rphandle = repodata_new_handle(pd->data);
         /* set the cpeid for the product
            the label is set in the content of the tag */
@@ -273,7 +207,7 @@ startElement(void *userData, const char *name, const char **atts)
       {
         /* this is extra metadata about the product this repository
            was designed for */
-        const char *cpeid = find_attr("cpeid", atts);
+        const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
         pd->ruhandle = repodata_new_handle(pd->data);
         /* set the cpeid for the product
            the label is set in the content of the tag */
@@ -283,7 +217,7 @@ startElement(void *userData, const char *name, const char **atts)
       }
     case STATE_DATA:
       {
-        const char *type= find_attr("type", atts);
+        const char *type= solv_xmlparser_find_attr("type", atts);
         pd->rdhandle = repodata_new_handle(pd->data);
        if (type)
           repodata_set_poolstr(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TYPE, type);
@@ -291,7 +225,7 @@ startElement(void *userData, const char *name, const char **atts)
       }
     case STATE_LOCATION:
       {
-        const char *href = find_attr("href", atts);
+        const char *href = solv_xmlparser_find_attr("href", atts);
        if (href)
           repodata_set_str(pd->data, pd->rdhandle, REPOSITORY_REPOMD_LOCATION, href);
         break;
@@ -299,10 +233,10 @@ startElement(void *userData, const char *name, const char **atts)
     case STATE_CHECKSUM:
     case STATE_OPENCHECKSUM:
       {
-        const char *type= find_attr("type", atts);
+        const char *type= solv_xmlparser_find_attr("type", atts);
         pd->chksumtype = type && *type ? solv_chksum_str2type(type) : 0;
        if (!pd->chksumtype)
-          pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), type ? type : "NULL");
+          pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), type ? type : "NULL");
         break;
       }
     default:
@@ -311,27 +245,11 @@ startElement(void *userData, const char *name, const char **atts)
   return;
 }
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
-  /* Pool *pool = pd->pool; */
-
-#if 0
-  fprintf(stderr, "endElement: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
+  struct parsedata *pd = xmlp->userdata;
+  switch (state)
     {
     case STATE_REPOMD:
       if (pd->timestamp > 0)
@@ -347,10 +265,10 @@ endElement(void *userData, const char *name)
     case STATE_OPENCHECKSUM:
       if (!pd->chksumtype)
        break;
-      if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype))
-        pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
+      if (strlen(content) != 2 * solv_chksum_len(pd->chksumtype))
+        pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
       else
-        repodata_set_checksum(pd->data, pd->rdhandle, pd->state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, pd->content);
+        repodata_set_checksum(pd->data, pd->rdhandle, state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, content);
       break;
 
     case STATE_TIMESTAMP:
@@ -360,7 +278,7 @@ endElement(void *userData, const char *name)
          * of all resources to save it as the time
          * the metadata was generated
          */
-        int timestamp = atoi(pd->content);
+        int timestamp = atoi(content);
        if (timestamp)
           repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TIMESTAMP, timestamp);
         if (timestamp > pd->timestamp)
@@ -369,7 +287,7 @@ endElement(void *userData, const char *name)
       }
     case STATE_EXPIRE:
       {
-        int expire = atoi(pd->content);
+        int expire = atoi(content);
        if (expire > 0)
          repodata_set_num(pd->data, SOLVID_META, REPOSITORY_EXPIRE, expire);
         break;
@@ -377,119 +295,69 @@ endElement(void *userData, const char *name)
       /* repomd.xml content and suseinfo.xml keywords are equivalent */
     case STATE_CONTENT:
     case STATE_KEYWORD:
-      if (*pd->content)
-       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, pd->content);
+      if (*content)
+       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, content);
       break;
     case STATE_REVISION:
-      if (*pd->content)
-       repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, pd->content);
+      if (*content)
+       repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, content);
       break;
     case STATE_DISTRO:
       /* distro tag is used in repomd.xml to say the product this repo is
          made for */
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, pd->content);
+      if (*content)
+        repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, content);
       repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_DISTROS, pd->rphandle);
       break;
     case STATE_UPDATES:
       /* updates tag is used in suseinfo.xml to say the repo updates a product
          however it s not yet a tag standarized for repomd.xml */
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, pd->content);
+      if (*content)
+        repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, content);
       repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_UPDATES, pd->ruhandle);
       break;
     case STATE_REPO:
-      if (*pd->content)
-       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, pd->content);
+      if (*content)
+       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, content);
       break;
     case STATE_SIZE:
-      if (*pd->content)
-       repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(pd->content, 0, 10));
+      if (*content)
+       repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(content, 0, 10));
       break;
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-  return;
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pd->ret = pool_error(pd->pool, -1, "repo_repomdxml: %s at line %u:%u", errstr, line, column);
 }
 
-#define BUFF_SIZE 8192
-
 int
 repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
 {
   Pool *pool = repo->pool;
   struct parsedata pd;
   Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
 
   data = repo_add_repodata(repo, flags);
 
   memset(&pd, 0, sizeof(pd));
   pd.timestamp = 0;
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
 
-  pd.content = malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  pd.parser = &parser;
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_repomdxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
 
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
 
-  free(pd.content);
   return pd.ret;
 }
 
index fe05bec..40a1e3e 100644 (file)
@@ -624,6 +624,24 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf,
   return olddeps;
 }
 
+static Id
+repodata_str2dir_rooted(Repodata *data, char *str, int create)
+{
+  char buf[256], *bp;
+  int l = strlen(str);
+  Id id;
+
+  if (l + 2 <= sizeof(buf))
+    bp = buf;
+  else
+    bp = solv_malloc(l + 2);
+  bp[0] = '/';
+  strcpy(bp + 1, str);
+  id = repodata_str2dir(data, bp, create);
+  if (bp != buf)
+    solv_free(bp);
+  return id;
+}
 
 static void
 adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc)
@@ -765,15 +783,16 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *
     {
       if (!fn[i])
        continue;
-      did = repodata_str2dir(data, dn[i], 1);
-      if (!did)
+      if (dn[i][0] != '/')
        {
           Solvable *s = data->repo->pool->solvables + handle;
           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
            did = repodata_str2dir(data, "/usr/src", 1);
          else
-           continue;   /* work around rpm bug */
+           did = repodata_str2dir_rooted(data, dn[i], 1);
        }
+      else
+        did = repodata_str2dir(data, dn[i], 1);
       repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]);
     }
   solv_free(fn);
@@ -803,7 +822,7 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
   unsigned int *di;
   int bnc, dnc, dic;
   int i;
-  Id lastdid = 0;
+  Id did;
   unsigned int lastdii = -1;
   int lastfiltered = 0;
 
@@ -833,17 +852,16 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
 
   adddudata(data, handle, rpmhead, dn, di, bnc, dnc);
 
+  did = -1;
   for (i = 0; i < bnc; i++)
     {
-      Id did;
       char *b = bn[i];
 
-      if (lastdid && di[i] == lastdii)
-       did = lastdid;
-      else
+      if (did < 0 || di[i] != lastdii)
        {
          if (di[i] >= dnc)
            continue;   /* corrupt entry */
+         did = 0;
          lastdii = di[i];
          if ((flags & RPM_ADD_FILTERED_FILELIST) != 0)
            {
@@ -851,18 +869,17 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
              if (lastfiltered == 1)
                continue;
            }
-         did = repodata_str2dir(data, dn[lastdii], 1);
-         if (!did)
-           did = repodata_str2dir(data, "/", 1);
-         lastdid = did;
+         if (dn[lastdii][0] != '/')
+           did = repodata_str2dir_rooted(data, dn[lastdii], 1);
+         else
+           did = repodata_str2dir(data, dn[lastdii], 1);
        }
-      if (b && *b == '/')      /* work around rpm bug */
+      if (!b)
+       continue;
+      if (*b == '/')   /* work around rpm bug */
        b++;
-      if (lastfiltered)
-       {
-         if (lastfiltered != 2 || strcmp(b, "sendmail"))
-           continue;
-       }
+      if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail")))
+        continue;
       repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b);
     }
   solv_free(bn);
@@ -1652,12 +1669,14 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
       id = kv->id;
       id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
+      if (id)
+        repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
       break;
     case REPOKEY_TYPE_DIRSTRARRAY:
       id = kv->id;
       id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      repodata_add_dirstr(data, handle, keyname, id, kv->str);
+      if (id)
+        repodata_add_dirstr(data, handle, keyname, id, kv->str);
       break;
     case REPOKEY_TYPE_FLEXARRAY:
       if (kv->eof == 2)
index 8854bca..6c05281 100644 (file)
@@ -6,12 +6,9 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "tools_util.h"
 #include "repo_rpmmd.h"
 #include "chksum.h"
+#include "solv_xmlparser.h"
 #ifdef ENABLE_COMPLEX_DEPS
 #include "pool_parserpmrichdep.h"
 #endif
+#include "repodata_diskusage.h"
 
 enum state {
   STATE_START,
@@ -85,8 +84,7 @@ enum state {
   STATE_OPTIONALURL,
   STATE_FLAG,
 
-  /* rpm-md dependencies inside the
-     format tag */
+  /* rpm-md dependencies inside the format tag */
   STATE_PROVIDES,
   STATE_REQUIRES,
   STATE_OBSOLETES,
@@ -117,18 +115,13 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
-  /** fake tag used to enclose 2 different xml files in one **/
+static struct solv_xmlparser_element stateswitches[] = {
+  /** fake tag used to enclose multiple xml files in one **/
   { STATE_START,       "rpmmd",           STATE_START,    0 },
 
-  /** tags for different package data, we just ignore the tag **/
+  /** tags for different package data, just ignore them **/
+  { STATE_START,       "patterns",        STATE_START,    0 },
+  { STATE_START,       "products",        STATE_START,    0 },
   { STATE_START,       "metadata",        STATE_START,    0 },
   { STATE_START,       "otherdata",       STATE_START,    0 },
   { STATE_START,       "filelists",       STATE_START,    0 },
@@ -140,6 +133,8 @@ static struct stateswitch stateswitches[] = {
   { STATE_START,       "patch",           STATE_SOLVABLE, 0 },
   { STATE_START,       "package",         STATE_SOLVABLE, 0 },
 
+  { STATE_SOLVABLE,    "format",          STATE_SOLVABLE, 0 },
+
   { STATE_SOLVABLE,    "name",            STATE_NAME, 1 },
   { STATE_SOLVABLE,    "arch",            STATE_ARCH, 1 },
   { STATE_SOLVABLE,    "version",         STATE_VERSION, 0 },
@@ -230,25 +225,16 @@ struct parsedata {
   Repo *repo;
   Repodata *data;
   char *kind;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Solvable *solvable;
   Offset freshens;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
+
+  struct solv_xmlparser xmlp;
   struct joindata jd;
   /* temporal to store attribute tag language */
   const char *tmplang;
   Id chksumtype;
   Id handle;
-  XML_Parser *parser;
-  Id (*dirs)[3]; /* dirid, size, nfiles */
-  int ndirs;
+  Queue diskusageq;
   const char *language;                        /* default language */
   Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
 
@@ -287,74 +273,6 @@ langtag(struct parsedata *pd, Id tag, const char *language)
   return pd->langcache[tag];
 }
 
-static int
-id3_cmp (const void *v1, const void *v2, void *dp)
-{
-  Id *i1 = (Id*)v1;
-  Id *i2 = (Id*)v2;
-  return i1[0] - i2[0];
-}
-
-static void
-commit_diskusage (struct parsedata *pd, Id handle)
-{
-  int i;
-  Dirpool *dp = &pd->data->dirpool;
-  /* Now sort in dirid order.  This ensures that parents come before
-     their children.  */
-  if (pd->ndirs > 1)
-    solv_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0);
-  /* Substract leaf numbers from all parents to make the numbers
-     non-cumulative.  This must be done post-order (i.e. all leafs
-     adjusted before parents).  We ensure this by starting at the end of
-     the array moving to the start, hence seeing leafs before parents.  */
-  for (i = pd->ndirs; i--;)
-    {
-      Id p = dirpool_parent(dp, pd->dirs[i][0]);
-      int j = i;
-      for (; p; p = dirpool_parent(dp, p))
-        {
-          for (; j--;)
-           if (pd->dirs[j][0] == p)
-             break;
-         if (j >= 0)
-           {
-             if (pd->dirs[j][1] < pd->dirs[i][1])
-               pd->dirs[j][1] = 0;
-             else
-               pd->dirs[j][1] -= pd->dirs[i][1];
-             if (pd->dirs[j][2] < pd->dirs[i][2])
-               pd->dirs[j][2] = 0;
-             else
-               pd->dirs[j][2] -= pd->dirs[i][2];
-           }
-         else
-           /* Haven't found this parent in the list, look further if
-              we maybe find the parents parent.  */
-           j = i;
-       }
-    }
-#if 0
-  char sbuf[1024];
-  char *buf = sbuf;
-  unsigned slen = sizeof (sbuf);
-  for (i = 0; i < pd->ndirs; i++)
-    {
-      dir2str (attr, pd->dirs[i][0], &buf, &slen);
-      fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
-    }
-  if (buf != sbuf)
-    free (buf);
-#endif
-  for (i = 0; i < pd->ndirs; i++)
-    if (pd->dirs[i][1] || pd->dirs[i][2])
-      {
-       repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
-      }
-  pd->ndirs = 0;
-}
-
-
 /*
  * makeevr_atts
  * parse 'epoch', 'ver' and 'rel', return evr Id
@@ -365,7 +283,7 @@ static Id
 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
 {
   const char *e, *v, *r, *v2;
-  char *c;
+  char *c, *space;
   int l;
 
   e = v = r = 0;
@@ -394,12 +312,7 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
     l += strlen(v);
   if (r)
     l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
   if (e)
     {
       strcpy(c, e);
@@ -418,33 +331,12 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
       c += strlen(c);
     }
   *c = 0;
-  if (!*pd->content)
+  if (!*space)
     return 0;
 #if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
+  fprintf(stderr, "evr: %s\n", space);
 #endif
-  return pool_str2id(pool, pd->content, 1);
-}
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
+  return pool_str2id(pool, space, 1);
 }
 
 
@@ -495,13 +387,9 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts
   if (k)
     {
       int l = strlen(k) + 1 + strlen(n) + 1;
-      if (l > pd->acontent)
-       {
-         pd->content = solv_realloc(pd->content, l + 256);
-         pd->acontent = l + 256;
-       }
-      sprintf(pd->content, "%s:%s", k, n);
-      id = pool_str2id(pool, pd->content, 1);
+      char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+      sprintf(space, "%s:%s", k, n);
+      id = pool_str2id(pool, space, 1);
     }
 #ifdef ENABLE_COMPLEX_DEPS
   else if (!f && n[0] == '(')
@@ -734,63 +622,22 @@ fill_cshash_from_new_solvables(struct parsedata *pd)
 
 /*
  * startElement
- * XML callback
- *
  */
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-  const char *str;
   Id handle = pd->handle;
+  const char *str;
   const char *pkgid;
 
-  /* fprintf(stderr, "into %s, from %d, depth %d, statedepth %d\n", name, pd->state, pd->depth, pd->statedepth); */
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  if (pd->state == STATE_START && !strcmp(name, "patterns"))
-    return;
-  if (pd->state == STATE_START && !strcmp(name, "products"))
-    return;
-#if 0
-  if (pd->state == STATE_START && !strcmp(name, "metadata"))
-    return;
-#endif
-  if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
-    return;
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
+  if (!s && state != STATE_SOLVABLE)
     return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s\n", name);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
 
-  if (!s && pd->state != STATE_SOLVABLE)
-    return;
-
-  switch(pd->state)
+  switch(state)
     {
     case STATE_SOLVABLE:
       pd->kind = 0;
@@ -818,7 +665,7 @@ startElement(void *userData, const char *name, const char **atts)
          one.
       */
       pd->extending = 0;
-      if ((pkgid = find_attr("pkgid", atts)) != NULL)
+      if ((pkgid = solv_xmlparser_find_attr("pkgid", atts)) != NULL)
         {
          unsigned char chk[256];
          int l;
@@ -859,7 +706,7 @@ startElement(void *userData, const char *name, const char **atts)
       if (pd->kind && pd->kind[1] == 'r')
        {
          /* products can have a type */
-         const char *type = find_attr("type", atts);
+         const char *type = solv_xmlparser_find_attr("type", atts);
          if (type && *type)
            repodata_set_str(pd->data, handle, PRODUCT_TYPE, type);
        }
@@ -931,27 +778,27 @@ startElement(void *userData, const char *name, const char **atts)
     case STATE_SUMMARY:
     case STATE_CATEGORY:
     case STATE_DESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
       break;
     case STATE_USERVISIBLE:
       repodata_set_void(pd->data, handle, SOLVABLE_ISVISIBLE);
       break;
     case STATE_INCLUDESENTRY:
-      str = find_attr("pattern", atts);
+      str = solv_xmlparser_find_attr("pattern", atts);
       if (str)
        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_INCLUDES, join2(&pd->jd, "pattern", ":", str));
       break;
     case STATE_EXTENDSENTRY:
-      str = find_attr("pattern", atts);
+      str = solv_xmlparser_find_attr("pattern", atts);
       if (str)
        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_EXTENDS, join2(&pd->jd, "pattern", ":", str));
       break;
     case STATE_LOCATION:
-      str = find_attr("href", atts);
+      str = solv_xmlparser_find_attr("href", atts);
       if (str)
        {
          int medianr = 0;
-         const char *base = find_attr("xml:base", atts);
+         const char *base = solv_xmlparser_find_attr("xml:base", atts);
          if (base  && !strncmp(base, "media:", 6))
            {
              /* check for the media number in the fragment */
@@ -967,29 +814,29 @@ startElement(void *userData, const char *name, const char **atts)
        }
       break;
     case STATE_CHECKSUM:
-      str = find_attr("type", atts);
+      str = solv_xmlparser_find_attr("type", atts);
       pd->chksumtype = str && *str ? solv_chksum_str2type(str) : 0;
       if (!pd->chksumtype)
-       pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), str ? str : "NULL");
+       pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), str ? str : "NULL");
       break;
     case STATE_TIME:
       {
         unsigned int t;
-        str = find_attr("build", atts);
+        str = solv_xmlparser_find_attr("build", atts);
         if (str && (t = atoi(str)) != 0)
           repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t);
        break;
       }
     case STATE_SIZE:
-      if ((str = find_attr("installed", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("installed", atts)) != 0)
        repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, strtoull(str, 0, 10));
-      if ((str = find_attr("package", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("package", atts)) != 0)
        repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(str, 0, 10));
       break;
     case STATE_HEADERRANGE:
       {
         unsigned int end;
-        str = find_attr("end", atts);
+        str = solv_xmlparser_find_attr("end", atts);
        if (str && (end = atoi(str)) != 0)
          repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end);
        break;
@@ -1013,41 +860,43 @@ startElement(void *userData, const char *name, const char **atts)
     case STATE_DIR:
       {
         long filesz = 0, filenum = 0;
-        Id dirid;
-        if ((str = find_attr("name", atts)) == 0)
+        Id did;
+
+        if ((str = solv_xmlparser_find_attr("name", atts)) == 0)
          {
            pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute");
             break;
          }
        if (*str != '/')
          {
-           int l = strlen(str) + 2;
-           if (l > pd->acontent)
+           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+             str = "/usr/src";
+           else
              {
-               pd->content = solv_realloc(pd->content, l + 256);
-               pd->acontent = l + 256;
-             }
-           *pd->content = '/';
-           strcpy(pd->content + 1, str);
-           str = pd->content;
+               int l = strlen(str) + 2;
+               char *space = solv_xmlparser_contentspace(xmlp, l);
+               space[0] = '/';
+               memcpy(space + 1, str, l - 1);
+               str = space;
+           }
          }
-        dirid = repodata_str2dir(pd->data, str, 1);
-        if ((str = find_attr("size", atts)) != 0)
+        did = repodata_str2dir(pd->data, str, 1);
+        if ((str = solv_xmlparser_find_attr("size", atts)) != 0)
           filesz = strtol(str, 0, 0);
-        if ((str = find_attr("count", atts)) != 0)
+        if ((str = solv_xmlparser_find_attr("count", atts)) != 0)
           filenum = strtol(str, 0, 0);
-        pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
-        pd->dirs[pd->ndirs][0] = dirid;
-        pd->dirs[pd->ndirs][1] = filesz;
-        pd->dirs[pd->ndirs][2] = filenum;
-        pd->ndirs++;
+        if (filesz || filenum)
+          {
+            queue_push(&pd->diskusageq, did);
+            queue_push2(&pd->diskusageq, filesz, filenum);
+          }
         break;
       }
     case STATE_CHANGELOG:
       pd->changelog_handle = repodata_new_handle(pd->data);
-      if ((str = find_attr("date", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("date", atts)) != 0)
        repodata_set_num(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TIME, strtoull(str, 0, 10));
-      if ((str = find_attr("author", atts)) != 0)
+      if ((str = solv_xmlparser_find_attr("author", atts)) != 0)
        repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_AUTHOR, str);
       break;
     default:
@@ -1058,14 +907,12 @@ startElement(void *userData, const char *name, const char **atts)
 
 /*
  * endElement
- * XML callback
- *
  */
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
   Repo *repo = pd->repo;
@@ -1073,37 +920,10 @@ endElement(void *userData, const char *name)
   Id id;
   char *p;
 
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-      return;
-    }
-
-  /* ignore patterns & metadata */
-  if (pd->state == STATE_START && !strcmp(name, "patterns"))
-    return;
-  if (pd->state == STATE_START && !strcmp(name, "products"))
-    return;
-#if 0
-  if (pd->state == STATE_START && !strcmp(name, "metadata"))
-    return;
-#endif
-  if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
-    return;
-
-  pd->depth--;
-  pd->statedepth--;
-
-
   if (!s)
-    {
-      pd->state = pd->sbtab[pd->state];
-      pd->docontent = 0;
-      return;
-    }
+    return;
 
-  switch (pd->state)
+  switch (state)
     {
     case STATE_SOLVABLE:
       if (pd->extending)
@@ -1126,32 +946,32 @@ endElement(void *userData, const char *name)
       break;
     case STATE_NAME:
       if (pd->kind)
-        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", pd->content), 1);
+        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", content), 1);
       else
-        s->name = pool_str2id(pool, pd->content, 1);
+        s->name = pool_str2id(pool, content, 1);
       break;
     case STATE_ARCH:
-      s->arch = pool_str2id(pool, pd->content, 1);
+      s->arch = pool_str2id(pool, content, 1);
       break;
     case STATE_VENDOR:
-      s->vendor = pool_str2id(pool, pd->content, 1);
+      s->vendor = pool_str2id(pool, content, 1);
       break;
     case STATE_RPM_GROUP:
-      repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, pd->content);
+      repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, content);
       break;
     case STATE_RPM_LICENSE:
-      repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, pd->content);
+      repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, content);
       break;
     case STATE_CHECKSUM:
       {
        unsigned char chk[256];
        int l = solv_chksum_len(pd->chksumtype);
-       const char *str = pd->content;
+       const char *str = content;
        if (!l || l > sizeof(chk))
          break;
-       if (solv_hex2bin(&str, chk, l) != l || pd->content[2 * l])
+       if (solv_hex2bin(&str, chk, l) != l || content[2 * l])
           {
-           pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
+           pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
            break;
           }
         repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk);
@@ -1161,152 +981,124 @@ endElement(void *userData, const char *name)
         break;
       }
     case STATE_FILE:
-#if 0
-      id = pool_str2id(pool, pd->content, 1);
-      s->provides = repo_addid_dep(repo, s->provides, id, SOLVABLE_FILEMARKER);
-#endif
-      if ((p = strrchr(pd->content, '/')) != 0)
+      if ((p = strrchr(content, '/')) != 0)
        {
          *p++ = 0;
-         if (pd->lastdir && !strcmp(pd->lastdirstr, pd->content))
+         if (pd->lastdir && !strcmp(pd->lastdirstr, content))
            {
              id = pd->lastdir;
            }
          else
            {
-             int l;
-             id = repodata_str2dir(pd->data, pd->content, 1);
-             l = strlen(pd->content) + 1;
-             if (l > pd->lastdirstrl)
+             int l = p - content;
+             if (l + 1 > pd->lastdirstrl)      /* + 1 for the possible leading / we need to insert */
                {
                  pd->lastdirstrl = l + 128;
                  pd->lastdirstr = solv_realloc(pd->lastdirstr, pd->lastdirstrl);
                }
-             strcpy(pd->lastdirstr, pd->content);
+             if (content[0] != '/')
+               {
+                 pd->lastdirstr[0] = '/';
+                 memcpy(pd->lastdirstr + 1, content, l);
+                 id = repodata_str2dir(pd->data, pd->lastdirstr, 1);
+               }
+             else
+               id = repodata_str2dir(pd->data, content, 1);
              pd->lastdir = id;
+             memcpy(pd->lastdirstr, content, l);
            }
        }
       else
        {
-         p = pd->content;
-         id = 0;
+         p = content;
+         id = repodata_str2dir(pd->data, "/", 1);
        }
-      if (!id)
-       id = repodata_str2dir(pd->data, "/", 1);
       repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p);
       break;
     case STATE_SUMMARY:
-      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
+      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), content);
       break;
     case STATE_DESCRIPTION:
-      set_description_author(pd->data, handle, pd->content, pd);
+      set_description_author(pd->data, handle, content, pd);
       break;
     case STATE_CATEGORY:
-      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), pd->content);
+      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), content);
       break;
     case STATE_DISTRIBUTION:
-        repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, pd->content);
+        repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, content);
         break;
     case STATE_URL:
-      if (pd->content[0])
-       repodata_set_str(pd->data, handle, SOLVABLE_URL, pd->content);
+      if (*content)
+       repodata_set_str(pd->data, handle, SOLVABLE_URL, content);
       break;
     case STATE_PACKAGER:
-      if (pd->content[0])
-       repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, pd->content);
+      if (*content)
+       repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, content);
       break;
     case STATE_SOURCERPM:
-      if (pd->content[0])
-       repodata_set_sourcepkg(pd->data, handle, pd->content);
+      if (*content)
+       repodata_set_sourcepkg(pd->data, handle, content);
       break;
     case STATE_RELNOTESURL:
-      if (pd->content[0])
+      if (*content)
         {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
           repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "releasenotes", 1));
         }
       break;
     case STATE_UPDATEURL:
-      if (pd->content[0])
+      if (*content)
         {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
           repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "update", 1));
         }
       break;
     case STATE_OPTIONALURL:
-      if (pd->content[0])
+      if (*content)
         {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
           repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "optional", 1));
         }
       break;
     case STATE_FLAG:
-      if (pd->content[0])
-        repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, pd->content);
+      if (*content)
+        repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, content);
       break;
     case STATE_EULA:
-      if (pd->content[0])
-       repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), pd->content);
+      if (*content)
+       repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), content);
       break;
     case STATE_KEYWORD:
-      if (pd->content[0])
-        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, pd->content);
+      if (*content)
+        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, content);
       break;
     case STATE_DISKUSAGE:
-      if (pd->ndirs)
-        commit_diskusage(pd, handle);
+      if (pd->diskusageq.count)
+        repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
       break;
     case STATE_ORDER:
-      if (pd->content[0])
-        repodata_set_str(pd->data, handle, SOLVABLE_ORDER, pd->content);
+      if (*content)
+        repodata_set_str(pd->data, handle, SOLVABLE_ORDER, content);
       break;
     case STATE_CHANGELOG:
-      repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, pd->content);
+      repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, content);
       repodata_add_flexarray(pd->data, handle, SOLVABLE_CHANGELOG, pd->changelog_handle);
       pd->changelog_handle = 0;
       break;
     default:
       break;
     }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-  /* fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
 }
 
-
-/*
- * characterData
- * XML callback
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pd->ret = pool_error(pd->pool, -1, "repo_rpmmd: %s at line %u:%u", errstr, line, column);
 }
 
 
 /*-----------------------------------------------*/
-/* 'main' */
-
-#define BUFF_SIZE 8192
 
 /*
  * repo_add_rpmmd
@@ -1319,32 +1111,20 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
 {
   Pool *pool = repo->pool;
   struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
   Repodata *data;
   unsigned int now;
-  XML_Parser parser;
 
   now = solv_timems(0);
   data = repo_add_repodata(repo, flags);
 
   memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
 
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
   pd.kind = 0;
   pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0;
+  queue_init(&pd.diskusageq);
 
   init_cshash(&pd);
   if ((flags & REPO_EXTEND_SOLVABLES) != 0)
@@ -1354,28 +1134,15 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
       fill_cshash_from_repo(&pd);
     }
 
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  pd.parser = &parser;
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
+
   solv_free(pd.lastdirstr);
   join_freemem(&pd.jd);
   free_cshash(&pd);
   repodata_free_dircache(data);
+  queue_free(&pd.diskusageq);
 
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
index 83967e0..41c7a78 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -21,6 +19,7 @@
 #ifdef ENABLE_COMPLEX_DEPS
 #include "pool_parserpmrichdep.h"
 #endif
+#include "repodata_diskusage.h"
 
 struct datashare {
   Id name;
@@ -38,8 +37,7 @@ struct parsedata {
   int last_found_source;
   struct datashare *share_with;
   int nshare;
-  Id (*dirs)[3];                       /* dirid, size, nfiles */
-  int ndirs;
+  Queue diskusageq;
   struct joindata jd;
   char *language;                      /* the default language */
   Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
@@ -180,39 +178,6 @@ add_source(struct parsedata *pd, char *line, Solvable *s, Id handle)
   repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch);
 }
 
-/*
- * add_dirline
- * add a line with directory information
- *
- */
-
-static void
-add_dirline(struct parsedata *pd, char *line)
-{
-  char *sp[6];
-  long filesz;
-  long filenum;
-  Id dirid;
-  if (split(line, sp, 6) != 5)
-    return;
-  pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
-  filesz = strtol(sp[1], 0, 0);
-  filesz += strtol(sp[2], 0, 0);
-  filenum = strtol(sp[3], 0, 0);
-  filenum += strtol(sp[4], 0, 0);
-  /* hack: we know that there's room for a / */
-  if (*sp[0] != '/')
-    *--sp[0] = '/';
-  dirid = repodata_str2dir(pd->data, sp[0], 1);
-#if 0
-fprintf(stderr, "%s -> %d\n", sp[0], dirid);
-#endif
-  pd->dirs[pd->ndirs][0] = dirid;
-  pd->dirs[pd->ndirs][1] = filesz;
-  pd->dirs[pd->ndirs][2] = filenum;
-  pd->ndirs++;
-}
-
 static void
 set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *line)
 {
@@ -238,86 +203,6 @@ set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *
 }
 
 
-/*
- * id3_cmp
- * compare
- *
- */
-
-static int
-id3_cmp(const void *v1, const void *v2, void *dp)
-{
-  Id *i1 = (Id*)v1;
-  Id *i2 = (Id*)v2;
-  return i1[0] - i2[0];
-}
-
-
-/*
- * commit_diskusage
- *
- */
-
-static void
-commit_diskusage(struct parsedata *pd, Id handle)
-{
-  int i;
-  Dirpool *dp = &pd->data->dirpool;
-  /* Now sort in dirid order.  This ensures that parents come before
-     their children.  */
-  if (pd->ndirs > 1)
-    solv_sort(pd->dirs, pd->ndirs, sizeof(pd->dirs[0]), id3_cmp, 0);
-  /* Substract leaf numbers from all parents to make the numbers
-     non-cumulative.  This must be done post-order (i.e. all leafs
-     adjusted before parents).  We ensure this by starting at the end of
-     the array moving to the start, hence seeing leafs before parents.  */
-  for (i = pd->ndirs; i--;)
-    {
-      Id p = dirpool_parent(dp, pd->dirs[i][0]);
-      int j = i;
-      for (; p; p = dirpool_parent(dp, p))
-        {
-          for (; j--;)
-           if (pd->dirs[j][0] == p)
-             break;
-         if (j >= 0)
-           {
-             if (pd->dirs[j][1] < pd->dirs[i][1])
-               pd->dirs[j][1] = 0;
-             else
-               pd->dirs[j][1] -= pd->dirs[i][1];
-             if (pd->dirs[j][2] < pd->dirs[i][2])
-               pd->dirs[j][2] = 0;
-             else
-               pd->dirs[j][2] -= pd->dirs[i][2];
-           }
-         else
-           /* Haven't found this parent in the list, look further if
-              we maybe find the parents parent.  */
-           j = i;
-       }
-    }
-#if 0
-  char sbuf[1024];
-  char *buf = sbuf;
-  unsigned slen = sizeof(sbuf);
-  for (i = 0; i < pd->ndirs; i++)
-    {
-      dir2str(attr, pd->dirs[i][0], &buf, &slen);
-      fprintf(stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
-    }
-  if (buf != sbuf)
-    free (buf);
-#endif
-  for (i = 0; i < pd->ndirs; i++)
-    if (pd->dirs[i][1] || pd->dirs[i][2])
-      {
-       repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
-      }
-  pd->ndirs = 0;
-}
-
-
 /* Unfortunately "a"[0] is no constant expression in the C languages,
    so we need to pass the four characters individually :-/  */
 #define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \
@@ -385,13 +270,13 @@ finish_solvable(struct parsedata *pd, Solvable *s, Offset freshens)
        }
       pd->nfilelist = 0;
     }
-  /* A self provide, except for source packages.  This is harmless
+  /* Add self provide, except for source packages.  This is harmless
      to do twice (in case we see the same package twice).  */
   if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
     s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
   repo_rewrite_suse_deps(s, freshens);
-  if (pd->ndirs)
-    commit_diskusage(pd, handle);
+  if (pd->diskusageq.count)
+    repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
 }
 
 static Hashtable
@@ -484,7 +369,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
   int indelta = 0;
   int last_found_pack = 0;
   Id first_new_pkg = 0;
-  char *sp[5];
+  char *sp[6];
   struct parsedata pd;
   Repodata *data = 0;
   Id handle = 0;
@@ -509,6 +394,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
   pd.data = data;
   pd.flags = flags;
   pd.language = language && *language ? solv_strdup(language) : 0;
+  queue_init(&pd.diskusageq);
 
   linep = line;
   s = 0;
@@ -1034,8 +920,22 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
              continue;
            }
          case CTAG('=', 'D', 'i', 'r'):
-           add_dirline(&pd, line + 6);
-           continue;
+           if (split(line + 6, sp, 6) == 5)
+             {
+               long filesz, filenum;
+               Id did;
+
+               filesz = strtol(sp[1], 0, 0);
+               filesz += strtol(sp[2], 0, 0);
+               filenum = strtol(sp[3], 0, 0);
+               filenum += strtol(sp[4], 0, 0);
+               if (*sp[0] != '/')
+                 *--sp[0] = '/';       /* hack: we know that there's room for a / */
+               did = repodata_str2dir(data, sp[0], 1);
+               queue_push(&pd.diskusageq, did);
+               queue_push2(&pd.diskusageq, (Id)filesz, (Id)filenum);
+             }
+           break;
          case CTAG('=', 'C', 'a', 't'):
            repodata_set_poolstr(data, handle, langtag(&pd, SOLVABLE_CATEGORY, line_lang), line + 3 + keylen);
            break;
@@ -1065,27 +965,22 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
 
          case CTAG('=', 'F', 'l', 's'):
            {
-             char *p = strrchr(line + 6, '/');
+             char *p, *file = line + 6;
              Id did;
-             /* strip trailing slash */
-             if (p && p != line + 6 && !p[1])
+
+             if (*file != '/')
+               *--file = '/';          /* hack: we know there is room */
+             p  = strrchr(file, '/');
+             /* strip trailing slashes */
+             while (p != file && !p[1])
                {
                  *p = 0;
-                 p = strrchr(line + 6, '/');
-               }
-             if (p)
-               {
-                 *p++ = 0;
-                 did = repodata_str2dir(data, line + 6, 1);
-               }
-             else
-               {
-                 p = line + 6;
-                 did = 0;
+                 p = strrchr(file, '/');
                }
-             if (!did)
-               did = repodata_str2dir(data, "/", 1);
+             *p++ = 0;
+             did = repodata_str2dir(data, *file ? file : "/", 1);
              repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, p);
+             line[5] = ' ';
              break;
            }
          case CTAG('=', 'H', 'd', 'r'):
@@ -1178,5 +1073,6 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
   solv_free(pd.language);
   solv_free(line);
   join_freemem(&pd.jd);
+  queue_free(&pd.diskusageq);
   return pd.ret;
 }
index 6af74f2..7ba0062 100644 (file)
@@ -8,16 +8,14 @@
 #define _GNU_SOURCE
 #define _XOPEN_SOURCE /* glibc2 needs this */
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <expat.h>
 #include <time.h>
 
 #include "pool.h"
 #include "repo.h"
+#include "solv_xmlparser.h"
 #include "repo_updateinfoxml.h"
 #define DISABLE_SPLIT
 #include "tools_util.h"
@@ -75,16 +73,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,       "updates",         STATE_UPDATES,     0 },
   { STATE_START,       "update",          STATE_UPDATE,      0 },
   { STATE_UPDATES,     "update",          STATE_UPDATE,      0 },
@@ -112,13 +101,6 @@ static struct stateswitch stateswitches[] = {
 
 struct parsedata {
   int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
@@ -126,10 +108,8 @@ struct parsedata {
   Solvable *solvable;
   time_t buildtime;
   Id collhandle;
+  struct solv_xmlparser xmlp;
   struct joindata jd;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
 };
 
 /*
@@ -161,7 +141,7 @@ static Id
 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
 {
   const char *e, *v, *r, *v2;
-  char *c;
+  char *c, *space;
   int l;
 
   e = v = r = 0;
@@ -190,12 +170,8 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
     l += strlen(v);
   if (r)
     l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
+  
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
   if (e)
     {
       strcpy(c, e);
@@ -214,60 +190,25 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
       c += strlen(c);
     }
   *c = 0;
-  if (!*pd->content)
+  if (!*space)
     return 0;
 #if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
+  fprintf(stderr, "evr: %s\n", space);
 #endif
-  return pool_str2id(pool, pd->content, 1);
+  return pool_str2id(pool, space, 1);
 }
 
 
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *solvable = pd->solvable;
-  struct stateswitch *sw;
-  /*const char *str; */
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
 
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
+  switch(state)
     {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_START:
-      break;
-    case STATE_UPDATES:
-      break;
       /*
        * <update from="rel-eng@fedoraproject.org"
        *         status="stable"
@@ -297,26 +238,11 @@ startElement(void *userData, const char *name, const char **atts)
         pd->buildtime = (time_t)0;
       }
       break;
-      /* <id>FEDORA-2007-4594</id> */
-    case STATE_ID:
-      break;
-      /* <title>imlib-1.9.15-6.fc8</title> */
-    case STATE_TITLE:
-      break;
-      /* <release>Fedora 8</release> */
-    case STATE_RELEASE:
-      break;
-      /*  <issued date="2008-03-21 21:36:55"/>
-      */
+
     case STATE_ISSUED:
     case STATE_UPDATED:
       {
-       const char *date = 0;
-       for (; *atts; atts += 2)
-         {
-           if (!strcmp(*atts, "date"))
-             date = atts[1];
-         }
+       const char *date = solv_xmlparser_find_attr("date", atts);
        if (date)
          {
            time_t t = datestr2timestamp(date);
@@ -325,13 +251,7 @@ startElement(void *userData, const char *name, const char **atts)
          }
       }
       break;
-    case STATE_REFERENCES:
-      break;
-      /*  <reference href="https://bugzilla.redhat.com/show_bug.cgi?id=330471"
-       *             id="330471"
-       *             title="LDAP schema file missing for dhcpd"
-       *             type="bugzilla"/>
-       */
+
     case STATE_REFERENCE:
       {
         const char *href = 0, *id = 0, *title = 0, *type = 0;
@@ -359,20 +279,7 @@ startElement(void *userData, const char *name, const char **atts)
        repodata_add_flexarray(pd->data, pd->handle, UPDATE_REFERENCE, refhandle);
       }
       break;
-      /* <description>This update ...</description> */
-    case STATE_DESCRIPTION:
-      break;
-      /* <message type="confirm">This update ...</message> */
-    case STATE_MESSAGE:
-      break;
-    case STATE_PKGLIST:
-      break;
-      /* <collection short="F8" */
-    case STATE_COLLECTION:
-      break;
-      /* <name>Fedora 8</name> */
-    case STATE_NAME:
-      break;
+
       /*   <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
        *            src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
        *            version="1.9.15">
@@ -414,19 +321,7 @@ startElement(void *userData, const char *name, const char **atts)
          repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
         break;
       }
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-    case STATE_FILENAME:
-      break;
-      /* <reboot_suggested>True</reboot_suggested> */
-    case STATE_REBOOT:
-      break;
-      /* <restart_suggested>True</restart_suggested> */
-    case STATE_RESTART:
-      break;
-      /* <relogin_suggested>True</relogin_suggested> */
-    case STATE_RELOGIN:
-      break;
+
     default:
       break;
     }
@@ -434,34 +329,16 @@ startElement(void *userData, const char *name, const char **atts)
 }
 
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
   Repo *repo = pd->repo;
 
-#if 0
-      fprintf(stderr, "end: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
+  switch (state)
     {
-    case STATE_START:
-      break;
-    case STATE_UPDATES:
-      break;
     case STATE_UPDATE:
       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
       if (pd->buildtime)
@@ -470,80 +347,75 @@ endElement(void *userData, const char *name)
          pd->buildtime = (time_t)0;
        }
       break;
+
     case STATE_ID:
-      s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", pd->content), 1);
+      s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", content), 1);
       break;
+
       /* <title>imlib-1.9.15-6.fc8</title> */
     case STATE_TITLE:
-      while (pd->lcontent > 0 && pd->content[pd->lcontent - 1] == '\n')
-        pd->content[--pd->lcontent] = 0;
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
+      /* strip trailing newlines */
+      while (pd->xmlp.lcontent > 0 && content[pd->xmlp.lcontent - 1] == '\n')
+        content[--pd->xmlp.lcontent] = 0;
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
       break;
+
     case STATE_SEVERITY:
-      repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, pd->content);
+      repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, content);
       break;
+
     case STATE_RIGHTS:
-      repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, pd->content);
-      break;
-      /*
-       * <release>Fedora 8</release>
-       */
-    case STATE_RELEASE:
-      break;
-    case STATE_ISSUED:
-      break;
-    case STATE_REFERENCES:
-      break;
-    case STATE_REFERENCE:
+      repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, content);
       break;
+
       /*
        * <description>This update ...</description>
        */
     case STATE_DESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->content);
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, content);
       break;
+
       /*
        * <message>Warning! ...</message>
        */
     case STATE_MESSAGE:
-      repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, pd->content);
-      break;
-    case STATE_PKGLIST:
-      break;
-    case STATE_COLLECTION:
-      break;
-    case STATE_NAME:
+      repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, content);
       break;
+
     case STATE_PACKAGE:
       repodata_add_flexarray(pd->data, pd->handle, UPDATE_COLLECTION, pd->collhandle);
       pd->collhandle = 0;
       break;
+
       /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
       /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
     case STATE_FILENAME:
-      repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content);
+      repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, content);
       break;
+
       /* <reboot_suggested>True</reboot_suggested> */
     case STATE_REBOOT:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
        {
          /* FIXME: this is per-package, the global flag should be computed at runtime */
          repodata_set_void(pd->data, pd->handle, UPDATE_REBOOT);
          repodata_set_void(pd->data, pd->collhandle, UPDATE_REBOOT);
        }
       break;
+
       /* <restart_suggested>True</restart_suggested> */
     case STATE_RESTART:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
        {
          /* FIXME: this is per-package, the global flag should be computed at runtime */
          repodata_set_void(pd->data, pd->handle, UPDATE_RESTART);
          repodata_set_void(pd->data, pd->collhandle, UPDATE_RESTART);
        }
       break;
+
       /* <relogin_suggested>True</relogin_suggested> */
     case STATE_RELOGIN:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
        {
          /* FIXME: this is per-package, the global flag should be computed at runtime */
          repodata_set_void(pd->data, pd->handle, UPDATE_RELOGIN);
@@ -553,86 +425,31 @@ endElement(void *userData, const char *name)
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
 }
 
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-
-  if (!pd->docontent)
-    {
-#if 0
-      fprintf(stderr, "Content: [%d]'%.*s'\n", pd->state, len, s);
-#endif
-      return;
-    }
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
+  struct parsedata *pd = xmlp->userdata;
+  pd->ret = pool_error(pd->pool, -1, "repo_updateinfoxml: %s at line %u:%u", errstr, line, column);
 }
 
-
-#define BUFF_SIZE 8192
-
 int
 repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
 {
   Pool *pool = repo->pool;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
   Repodata *data;
-  XML_Parser parser;
+  struct parsedata pd;
 
   data = repo_add_repodata(repo, flags);
 
   memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  free(pd.content);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
 
   if (!(flags & REPO_NO_INTERNALIZE))
index 5200c29..d73a900 100644 (file)
@@ -4,7 +4,6 @@
  * Parses legacy /var/lib/zypp/db/products/... files.
  * They are old (pre Code11) product descriptions. See bnc#429177
  *
- *
  * Copyright (c) 2008, Novell Inc.
  *
  * This program is licensed under the BSD license, read LICENSE.BSD
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <dirent.h>
-#include <expat.h>
 #include <errno.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
+#include "solv_xmlparser.h"
 #define DISABLE_SPLIT
 #include "tools_util.h"
 #include "repo_zyppdb.h"
@@ -45,15 +41,7 @@ enum state {
   NUMSTATES
 };
 
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
   { STATE_START,     "product",       STATE_PRODUCT,       0 },
   { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
   { STATE_PRODUCT,   "version",       STATE_VERSION,       0 },
@@ -65,101 +53,32 @@ static struct stateswitch stateswitches[] = {
 };
 
 struct parsedata {
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
   Pool *pool;
   Repo *repo;
   Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct joindata jd;
-
+  const char *filename;
   const char *tmplang;
-
   Solvable *solvable;
   Id handle;
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
 };
 
 
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
 
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Pool *pool = pd->pool;
   Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
 
-  switch(pd->state)
+  switch(state)
     {
     case STATE_PRODUCT:
       {
        /* parse 'type' */
-       const char *type = find_attr("type", atts);
+       const char *type = solv_xmlparser_find_attr("type", atts);
        s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
        pd->handle = s - pool->solvables;
        if (type)
@@ -168,15 +87,14 @@ startElement(void *userData, const char *name, const char **atts)
       break;
     case STATE_VERSION:
       {
-       const char *ver = find_attr("ver", atts);
-       const char *rel = find_attr("rel", atts);
-       /* const char *epoch = find_attr("epoch", atts); ignored */
+       const char *ver = solv_xmlparser_find_attr("ver", atts);
+       const char *rel = solv_xmlparser_find_attr("rel", atts);
+       /* const char *epoch = solv_xmlparser_find_attr("epoch", atts); ignored */
        s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel));
       }
       break;
-      /* <summary lang="xy">... */
-    case STATE_SUMMARY:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+    case STATE_SUMMARY:                /* <summary lang="xy">... */
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
       break;
     default:
       break;
@@ -184,28 +102,13 @@ startElement(void *userData, const char *name, const char **atts)
 }
 
 
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
 {
-  struct parsedata *pd = userData;
+  struct parsedata *pd = xmlp->userdata;
   Solvable *s = pd->solvable;
 
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
+  switch (state)
     {
     case STATE_PRODUCT:
       if (!s->arch)
@@ -217,89 +120,34 @@ endElement(void *userData, const char *name)
       pd->solvable = 0;
       break;
     case STATE_NAME:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
       break;
     case STATE_ARCH:
-      s->arch = pool_str2id(pd->pool, pd->content, 1);
+      s->arch = pool_str2id(pd->pool, content, 1);
       break;
     case STATE_SUMMARY:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
       break;
     case STATE_VENDOR:
-      s->vendor = pool_str2id(pd->pool, pd->content, 1);
+      s->vendor = pool_str2id(pd->pool, content, 1);
       break;
     case STATE_INSTALLTIME:
-      repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(pd->content));
+      repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(content));
     default:
       break;
     }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-  fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
 }
 
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
 static void
-add_zyppdb_product(struct parsedata *pd, FILE *fp)
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
 {
-  char buf[BUFF_SIZE];
-  int l;
-
-  XML_Parser parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  for (;;)
+  struct parsedata *pd = xmlp->userdata;
+  pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd->filename, errstr, line, column);
+  if (pd->solvable)
     {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         if (pd->solvable)
-           {
-             repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
-             pd->solvable = 0;
-           }
-         return;
-       }
-      if (l == 0)
-       break;
+      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
+      pd->solvable = 0;
     }
-  XML_ParserFree(parser);
 }
 
 
@@ -312,9 +160,7 @@ add_zyppdb_product(struct parsedata *pd, FILE *fp)
 int
 repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
 {
-  int i;
   struct parsedata pd;
-  struct stateswitch *sw;
   struct dirent *entry;
   char *fullpath;
   DIR *dir;
@@ -326,16 +172,7 @@ repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
 
   if (flags & REPO_USE_ROOTDIR)
     dirpath = pool_prepend_rootdir(repo->pool, dirpath);
@@ -344,21 +181,22 @@ repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
     {
       while ((entry = readdir(dir)))
        {
-         if (strlen(entry->d_name) < 3)
-           continue;   /* skip '.' and '..' */
+         if (entry->d_name[0] == '.')
+           continue;   /* skip dot files */
          fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
          if ((fp = fopen(fullpath, "r")) == 0)
            {
              pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
              continue;
            }
-         add_zyppdb_product(&pd, fp);
+          pd.filename = entry->d_name;
+         solv_xmlparser_parse(&pd.xmlp, fp);
          fclose(fp);
        }
     }
   closedir(dir);
 
-  free(pd.content);
+  solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
   if (flags & REPO_USE_ROOTDIR)
     solv_free((char *)dirpath);
diff --git a/ext/repodata_diskusage.c b/ext/repodata_diskusage.c
new file mode 100644 (file)
index 0000000..fd9c5cc
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * repodata_diskusage.c
+ *
+ * Small helper to convert diskusage data from sustags or rpmmd
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "repodata_diskusage.h"
+
+/* The queue contains (dirid, kbytes, inodes) triplets */
+
+static int
+add_diskusage_sortfn(const void *ap, const void *bp, void *dp)
+{
+  return *(Id *)ap - *(Id *)bp;
+}
+
+void
+repodata_add_diskusage(Repodata *data, Id handle, Queue *q)
+{
+  int i, j;
+  Dirpool *dp = &data->dirpool;
+
+  /* Sort in dirid order. This ensures that parents come before
+   * their children. */
+  if (q->count > 3)
+    solv_sort(q->elements, q->count / 3, 3 * sizeof(Id), add_diskusage_sortfn, 0);
+  for (i = 3; i < q->count; i += 3)
+    {
+      /* subtract data from parent */
+      Id did = q->elements[i];
+      if (i + 3 < q->count && q->elements[i + 3] == did)
+       {
+         /* identical directory entry! zero this one */
+         q->elements[i + 1] = 0;
+         q->elements[i + 2] = 0;
+         continue;
+       }
+      while (did)
+       {
+         did = dirpool_parent(dp, did);
+         for (j = i - 3; j >= 0; j -= 3)
+           if (q->elements[j] == did)
+             break;
+         if (j >= 0)
+           {
+             if ((unsigned int)q->elements[j + 1] > (unsigned int)q->elements[i + 1])
+               q->elements[j + 1] -= q->elements[i + 1];
+             else
+               q->elements[j + 1] = 0;
+             if ((unsigned int)q->elements[j + 2] > (unsigned int)q->elements[i + 2])
+               q->elements[j + 2] -= q->elements[i + 2];
+             else
+               q->elements[j + 2] = 0;
+             break;
+           }
+       }
+    }
+  /* now commit data */
+  for (i = 0; i < q->count; i += 3)
+    if (q->elements[i + 1] || q->elements[i + 2])
+      repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, q->elements[i], q->elements[i + 1], q->elements[i + 2]);
+  /* empty queue */
+  queue_empty(q);
+}
+
diff --git a/ext/repodata_diskusage.h b/ext/repodata_diskusage.h
new file mode 100644 (file)
index 0000000..1beafea
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern void repodata_add_diskusage(Repodata *data, Id handle, Queue *q);
+
+
index b0421bf..967984e 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <zlib.h>
 #include <fcntl.h>
 
 #include "solv_xfopen.h"
 #include "util.h"
 
 
-/* Evil hack for Haiku: fopencookie() is implemented internally, but not
-   exported by a header. */
-#ifdef __HAIKU__
-
-typedef struct {
-       ssize_t (*read)(void*, char*, size_t);
-       ssize_t (*write)(void*, const char*, size_t);
-       int (*seek)(off_t*, int);
-       int (*close)(void*);
-} cookie_io_functions_t;
-
-
-FILE *fopencookie(void*, const char*, cookie_io_functions_t);
-
-#endif /* __HAIKU__ */
-
-
 static FILE *cookieopen(void *cookie, const char *mode,
        ssize_t (*cread)(void *, char *, size_t),
        ssize_t (*cwrite)(void *, const char *, size_t),
@@ -66,8 +48,12 @@ static FILE *cookieopen(void *cookie, const char *mode,
 }
 
 
+#ifdef ENABLE_ZLIB_COMPRESSION
+
 /* gzip compression */
 
+#include <zlib.h>
+
 static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
 {
   return gzread((gzFile)cookie, buf, nbytes);
@@ -95,12 +81,15 @@ static inline FILE *mygzfdopen(int fd, const char *mode)
   return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
 }
 
-#ifdef ENABLE_BZIP2_COMPRESSION
+#endif
 
-#include <bzlib.h>
+
+#ifdef ENABLE_BZIP2_COMPRESSION
 
 /* bzip2 compression */
 
+#include <bzlib.h>
+
 static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
 {
   return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
@@ -134,10 +123,10 @@ static inline FILE *mybzfdopen(int fd, const char *mode)
 
 #ifdef ENABLE_LZMA_COMPRESSION
 
-#include <lzma.h>
-
 /* lzma code written by me in 2008 for rpm's rpmio.c */
 
+#include <lzma.h>
+
 typedef struct lzfile {
   unsigned char buf[1 << 15];
   lzma_stream strm;
@@ -338,8 +327,13 @@ solv_xfopen(const char *fn, const char *mode)
   if (!mode)
     mode = "r";
   suf = strrchr(fn, '.');
+#ifdef ENABLE_ZLIB_COMPRESSION
   if (suf && !strcmp(suf, ".gz"))
     return mygzfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".gz"))
+    return 0;
+#endif
 #ifdef ENABLE_LZMA_COMPRESSION
   if (suf && !strcmp(suf, ".xz"))
     return myxzfopen(fn, mode);
@@ -384,8 +378,13 @@ solv_xfopen_fd(const char *fn, int fd, const char *mode)
       else
        mode = simplemode = "r";
     }
+#ifdef ENABLE_ZLIB_COMPRESSION
   if (suf && !strcmp(suf, ".gz"))
     return mygzfdopen(fd, simplemode);
+#else
+    return 0;
+  if (suf && !strcmp(suf, ".gz"))
+#endif
 #ifdef ENABLE_LZMA_COMPRESSION
   if (suf && !strcmp(suf, ".xz"))
     return myxzfdopen(fd, simplemode);
@@ -413,8 +412,12 @@ solv_xfopen_iscompressed(const char *fn)
   const char *suf = fn ? strrchr(fn, '.') : 0;
   if (!suf)
     return 0;
+#ifdef ENABLE_ZLIB_COMPRESSION
   if (!strcmp(suf, ".gz"))
     return 1;
+#else
+    return -1;
+#endif
   if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
 #ifdef ENABLE_LZMA_COMPRESSION
     return 1;
diff --git a/ext/solv_xmlparser.c b/ext/solv_xmlparser.c
new file mode 100644 (file)
index 0000000..170520f
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * solv_xmlparser.c
+ *
+ * XML parser abstraction
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WITH_LIBXML2
+#include <libxml/parser.h>
+#else
+#include <expat.h>
+#endif
+
+#include "util.h"
+#include "queue.h"
+#include "solv_xmlparser.h"
+
+static inline void
+add_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+  l += xmlp->lcontent + 1;     /* plus room for trailing zero */
+  if (l > xmlp->acontent)
+    {    
+      xmlp->acontent = l + 256; 
+      xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+    }    
+}
+
+
+#ifdef WITH_LIBXML2
+static void
+character_data(void *userData, const xmlChar *s, int len)
+#else
+static void XMLCALL
+character_data(void *userData, const XML_Char *s, int len) 
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+
+  if (!xmlp->docontent || !len)
+    return;
+  add_contentspace(xmlp, len);
+  memcpy(xmlp->content + xmlp->lcontent, s, len);
+  xmlp->lcontent += len; 
+}
+
+#ifdef WITH_LIBXML2
+static void
+start_element(void *userData, const xmlChar *name, const xmlChar **atts)
+#else
+static void XMLCALL
+start_element(void *userData, const char *name, const char **atts)
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+  struct solv_xmlparser_element *elements;
+  Id *elementhelper;
+  struct solv_xmlparser_element *el;
+  int i, oldstate;
+
+  if (xmlp->unknowncnt)
+    {
+      xmlp->unknowncnt++;
+      return;
+    }
+  elementhelper = xmlp->elementhelper;
+  elements = xmlp->elements;
+  oldstate = xmlp->state;
+  for (i = elementhelper[xmlp->nelements + oldstate]; i; i = elementhelper[i - 1])
+    if (!strcmp(elements[i - 1].element, (char *)name))
+      break;
+  if (!i)
+    {
+#if 0
+      fprintf(stderr, "into unknown: %s\n", name);
+#endif
+      xmlp->unknowncnt++;
+      return;
+    }
+  el = xmlp->elements + i - 1;
+  queue_push(&xmlp->elementq, xmlp->state);
+  xmlp->state = el->tostate;
+  xmlp->docontent = el->docontent;
+  xmlp->lcontent = 0;
+#ifdef WITH_LIBXML2
+  if (!atts)
+    {
+      static const char *nullattr;
+      atts = (const xmlChar **)&nullattr;
+    }
+#endif
+  if (xmlp->state != oldstate)
+    xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts);
+}
+
+#ifdef WITH_LIBXML2
+static void
+end_element(void *userData, const xmlChar *name)
+#else
+static void XMLCALL
+end_element(void *userData, const char *name)
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+
+  if (xmlp->unknowncnt)
+    {
+      xmlp->unknowncnt--;
+      xmlp->lcontent = 0;
+      xmlp->docontent = 0;
+      return;
+    }
+  xmlp->content[xmlp->lcontent] = 0;
+  if (xmlp->elementq.count && xmlp->state != xmlp->elementq.elements[xmlp->elementq.count - 1])
+    xmlp->endelement(xmlp, xmlp->state, xmlp->content);
+  xmlp->state = queue_pop(&xmlp->elementq);
+  xmlp->docontent = 0;
+  xmlp->lcontent = 0;
+}
+
+void
+solv_xmlparser_init(struct solv_xmlparser *xmlp,
+    struct solv_xmlparser_element *elements,
+    void *userdata,
+    void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts),
+    void (*endelement)(struct solv_xmlparser *, int state, char *content),
+    void (*errorhandler)(struct solv_xmlparser *, const char *errstr, unsigned int line, unsigned int column))
+{
+  int i, nstates, nelements;
+  struct solv_xmlparser_element *el;
+  Id *elementhelper;
+
+  memset(xmlp, 0, sizeof(*xmlp));
+  nstates = 0;
+  nelements = 0;
+  for (el = elements; el->element; el++)
+    {
+      nelements++;
+      if (el->fromstate > nstates)
+       nstates = el->fromstate;
+      if (el->tostate > nstates)
+       nstates = el->tostate;
+    }
+  nstates++;
+
+  xmlp->elements = elements;
+  xmlp->nelements = nelements;
+  elementhelper = solv_calloc(nelements + nstates, sizeof(Id));
+  for (i = nelements - 1; i >= 0; i--)
+    {
+      int fromstate = elements[i].fromstate;
+      elementhelper[i] = elementhelper[nelements + fromstate];
+      elementhelper[nelements + fromstate] = i + 1;
+    }
+  xmlp->elementhelper = elementhelper;
+  queue_init(&xmlp->elementq);
+  xmlp->acontent = 256;
+  xmlp->content = solv_malloc(xmlp->acontent);
+
+  xmlp->userdata = userdata;
+  xmlp->startelement = startelement;
+  xmlp->endelement = endelement;
+  xmlp->errorhandler = errorhandler;
+}
+
+void
+solv_xmlparser_free(struct solv_xmlparser *xmlp)
+{
+  xmlp->elementhelper = solv_free(xmlp->elementhelper);
+  queue_free(&xmlp->elementq);
+  xmlp->content = solv_free(xmlp->content);
+}
+
+#ifdef WITH_LIBXML2
+
+static inline int
+create_parser(struct solv_xmlparser *xmlp)
+{
+  /* delayed to parse_block so that we have the first bytes */
+  return 1;
+}
+
+static inline void
+free_parser(struct solv_xmlparser *xmlp)
+{
+  if (xmlp->parser)
+    xmlFreeParserCtxt(xmlp->parser);
+  xmlp->parser = 0;
+}
+
+static xmlParserCtxtPtr create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  xmlSAXHandler sax;
+  memset(&sax, 0, sizeof(sax));
+  sax.startElement = start_element;
+  sax.endElement = end_element;
+  sax.characters = character_data;
+  return xmlCreatePushParserCtxt(&sax, xmlp, buf, l, NULL);
+}
+
+static inline int
+parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  if (!xmlp->parser)
+    {
+      int l2 = l > 4 ? 4 : 0;
+      xmlp->parser = create_parser_ctx(xmlp, buf, l2);
+      if (!xmlp->parser)
+       {
+         xmlp->errorhandler(xmlp, "could not create parser", 0, 0);
+         return 0;
+       }
+      buf += l2;
+      l -= l2;
+      if (l2 && !l)
+       return 1;
+    }
+  if (xmlParseChunk(xmlp->parser, buf, l, l == 0 ? 1 : 0))
+    {
+      xmlErrorPtr err = xmlCtxtGetLastError(xmlp->parser);
+      xmlp->errorhandler(xmlp, err->message, err->line, err->int2);
+      return 0;
+    }
+  return 1;
+}
+
+unsigned int
+solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
+{
+  return (unsigned int)xmlSAX2GetLineNumber(xmlp->parser);
+}
+
+#else
+
+static inline int
+create_parser(struct solv_xmlparser *xmlp)
+{
+  xmlp->parser = XML_ParserCreate(NULL);
+  if (!xmlp->parser)
+    return 0;
+  XML_SetUserData(xmlp->parser, xmlp);
+  XML_SetElementHandler(xmlp->parser, start_element, end_element);
+  XML_SetCharacterDataHandler(xmlp->parser, character_data);
+  return 1;
+}
+
+static inline void
+free_parser(struct solv_xmlparser *xmlp)
+{
+  XML_ParserFree(xmlp->parser);
+  xmlp->parser = 0;
+}
+
+static inline int
+parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR)
+    {
+      unsigned int line = XML_GetCurrentLineNumber(xmlp->parser);
+      unsigned int column = XML_GetCurrentColumnNumber(xmlp->parser);
+      xmlp->errorhandler(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), line, column);
+      return 0;
+    }
+  return 1;
+}
+
+unsigned int
+solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
+{
+  return (unsigned int)XML_GetCurrentLineNumber(xmlp->parser);
+}
+
+#endif
+
+void
+solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
+{
+  char buf[8192];
+  int l;
+
+  xmlp->state = 0;
+  xmlp->unknowncnt = 0;
+  xmlp->docontent = 0;
+  xmlp->lcontent = 0;
+  queue_empty(&xmlp->elementq);
+
+  if (!create_parser(xmlp))
+    {
+      xmlp->errorhandler(xmlp, "could not create xml parser", 0, 0);
+      return;
+    }
+  for (;;)
+    {
+      l = fread(buf, 1, sizeof(buf), fp);
+      if (!parse_block(xmlp, buf, l) || !l)
+       break;
+    }
+  free_parser(xmlp);
+}
+
+char *
+solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+  xmlp->lcontent = 0;
+  if (l > xmlp->acontent)
+    {    
+      xmlp->acontent = l + 256; 
+      xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+    }    
+  return xmlp->content;
+}
+
diff --git a/ext/solv_xmlparser.h b/ext/solv_xmlparser.h
new file mode 100644 (file)
index 0000000..9fb342f
--- /dev/null
@@ -0,0 +1,52 @@
+
+struct solv_xmlparser_element {
+  int fromstate;
+  char *element;
+  int tostate;
+  int docontent;
+};
+
+struct solv_xmlparser {
+  void *userdata;
+
+  int state;
+  int docontent;
+
+  Queue elementq;
+  int unknowncnt;
+
+  char *content;
+  int lcontent;                /* current content length */
+  int acontent;                /* allocated content length */
+
+  struct solv_xmlparser_element *elements;
+  int nelements;
+
+  void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts);
+  void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content);
+  void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column);
+
+  Id *elementhelper;
+  void *parser;
+};
+
+static inline const char *
+solv_xmlparser_find_attr(const char *txt, const char **atts)
+{
+  for (; *atts; atts += 2)
+    if (!strcmp(*atts, txt))
+      return atts[1];
+  return 0;
+}
+
+extern void solv_xmlparser_init(struct solv_xmlparser *xmlp, struct solv_xmlparser_element *elements, void *userdata,
+    void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts),
+    void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content),
+    void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column));
+
+extern void solv_xmlparser_free(struct solv_xmlparser *xmlp);
+extern void solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp);
+unsigned int solv_xmlparser_lineno(struct solv_xmlparser *xmlp);
+char *solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l);
+
+
index ccfcb61..f515057 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -387,41 +385,42 @@ struct oplist {
   { REL_COMPAT,  "compat >=" },
   { REL_KIND,  "<KIND>" },
   { REL_ELSE, "<ELSE>" },
+  { REL_ERROR, "<ERROR>" },
   { REL_LT, "<" },
   { 0, 0 }
 };
 
-static const char *
-testcase_dep2str_complex(Pool *pool, Id id, int addparens)
+static char *
+testcase_dep2str_complex(Pool *pool, char *s, Id id, int addparens)
 {
   Reldep *rd;
-  char *s;
   const char *s2;
   int needparens;
   struct oplist *op;
 
   if (!ISRELDEP(id))
-    return testcase_id2str(pool, id, 1);
+    {
+      s2 = testcase_id2str(pool, id, 1);
+      s = pool_tmpappend(pool, s, s2, 0);
+      pool_freetmpspace(pool, s2);
+      return s;
+    }
   rd = GETRELDEP(pool, id);
 
   /* check for special shortcuts */
   if (rd->flags == REL_NAMESPACE && !ISRELDEP(rd->name) && !strncmp(pool_id2str(pool, rd->name), "namespace:", 10))
     {
-      const char *ns = pool_id2str(pool, rd->name);
-      int nslen = strlen(ns);
-      /* special namespace formatting */
-      const char *evrs = testcase_dep2str_complex(pool, rd->evr, 0);
-      s = pool_tmpappend(pool, evrs, ns, "()");
-      memmove(s + nslen + 1, s, strlen(s) - nslen - 2);
-      memcpy(s, ns, nslen);
-      s[nslen] = '(';
-      return s;
+      s = pool_tmpappend(pool, s, pool_id2str(pool, rd->name), "(");
+      s = testcase_dep2str_complex(pool, s, rd->evr, 0);
+      return pool_tmpappend(pool, s, ")", 0);
     }
   if (rd->flags == REL_MULTIARCH && !ISRELDEP(rd->name) && rd->evr == ARCH_ANY)
     {
-      /* special :any suffix */
-      const char *ns = testcase_id2str(pool, rd->name, 1);
-      return pool_tmpappend(pool, ns, ":any", 0);
+      /* append special :any suffix */
+      s2 = testcase_id2str(pool, rd->name, 1);
+      s = pool_tmpappend(pool, s, s2, ":any");
+      pool_freetmpspace(pool, s2);
+      return s;
     }
 
   needparens = 0;
@@ -432,14 +431,11 @@ testcase_dep2str_complex(Pool *pool, Id id, int addparens)
       if (rd->flags > 7 && rd->flags != REL_COMPAT && rd2->flags && rd2->flags <= 7)
        needparens = 0;
     }
-  s = (char *)testcase_dep2str_complex(pool, rd->name, needparens);
 
   if (addparens)
-    {
-      s = pool_tmpappend(pool, s, "(", 0);
-      memmove(s + 1, s, strlen(s + 1));
-      s[0] = '(';
-    }
+    s = pool_tmpappend(pool, s, "(", 0);
+  s = testcase_dep2str_complex(pool, s, rd->name, needparens);
+
   for (op = oplist; op->flags; op++)
     if (rd->flags == op->flags)
       break;
@@ -470,21 +466,27 @@ testcase_dep2str_complex(Pool *pool, Id id, int addparens)
        needparens = 0; /* chain */
     }
   if (!ISRELDEP(rd->evr))
-    s2 = testcase_id2str(pool, rd->evr, 0);
+    {
+      s2 = testcase_id2str(pool, rd->evr, 0);
+      s = pool_tmpappend(pool, s, s2, 0);
+      pool_freetmpspace(pool, s2);
+    }
   else
-    s2 = testcase_dep2str_complex(pool, rd->evr, needparens);
+    s = (char *)testcase_dep2str_complex(pool, s, rd->evr, needparens);
   if (addparens)
-    s = pool_tmpappend(pool, s, s2, ")");
-  else
-    s = pool_tmpappend(pool, s, s2, 0);
-  pool_freetmpspace(pool, s2);
+    s = pool_tmpappend(pool, s, ")", 0);
   return s;
 }
 
 const char *
 testcase_dep2str(Pool *pool, Id id)
 {
-  return testcase_dep2str_complex(pool, id, 0);
+  char *s;
+  if (!ISRELDEP(id))
+    return testcase_id2str(pool, id, 1);
+  s = pool_alloctmpspace(pool, 1);
+  *s = 0;
+  return testcase_dep2str_complex(pool, s, id, 0);
 }
 
 
@@ -1111,7 +1113,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
   return job;
 }
 
-int
+static int
 addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
 {
   Id job;
index f772422..94bb400 100644 (file)
@@ -1,8 +1,20 @@
 -------------------------------------------------------------------
+Tue Apr 25 14:11:05 CEST 2017 - mls@suse.de
+
+- change queue resize code to use adaptive chunk sizes
+- fix potential segfault in testcase_depstr [bnc#1036002]
+- fix performance issues with name = md5sum dependencies
+  [bnc#1035946]
+- improve "forcebest with uninstall" handling
+- make dirid handling more robust
+- build with libxml2 instead of libexpat
+- bump version to 0.6.27
+
+-------------------------------------------------------------------
 Wed Feb 15 11:34:59 CET 2017 - mls@suse.de
 
 - export solvable_matchesdep function, as we now use it in
-  the bindings
+  the bindings [bnc#1025440]
 - bump version to 0.6.26
 
 -------------------------------------------------------------------
index 0009287..d21562c 100644 (file)
@@ -37,21 +37,13 @@ BuildRequires:  libneon0.26-devel
 %if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
 BuildRequires:  db-devel
 %endif
-%if 0%{?suse_version}
-%if 0%{?suse_version} < 1030
-BuildRequires:  expat
-%else
-BuildRequires:  libexpat-devel
-%endif
-%if 0%{?suse_version} < 1100
+BuildRequires:  libxml2-devel
+%if 0%{?suse_version} && 0%{?suse_version} < 1100
 BuildRequires:  graphviz
 %endif
 %if 0%{?suse_version} > 1020
 BuildRequires:  fdupes
 %endif
-%else
-BuildRequires:  expat-devel
-%endif
 BuildRequires:  cmake
 BuildRequires:  gcc-c++
 BuildRequires:  rpm-devel
@@ -186,6 +178,7 @@ cmake       $CMAKE_FLAGS \
        -DLIB=%{_lib} \
        -DCMAKE_VERBOSE_MAKEFILE=TRUE \
        -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+       -DWITH_LIBXML2=1 \
        %{?with_enable_static:-DENABLE_STATIC=1} \
        %{?with_disable_shared:-DDISABLE_SHARED=1} \
        %{?with_perl_binding:-DENABLE_PERL=1} \
@@ -256,7 +249,7 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_mandir}/man1/helix2solv*
 %endif
 %{_datadir}/cmake/Modules/*
-%{_libdir}/pkgconfig/libsolv.pc
+%{_libdir}/pkgconfig/libsolv*.pc
 %{_mandir}/man3/*
 
 %files demo
index 1adf70e..bd97026 100644 (file)
@@ -998,6 +998,64 @@ pool_is_kind(Pool *pool, Id name, Id kind)
 }
 
 /*
+ * rpm eq magic:
+ *
+ * some dependencies are of the from "foo = md5sum", like the
+ * buildid provides. There's not much we can do to speed up
+ * getting the providers, because rpm's complex evr comparison
+ * rules get in the way. But we can use the first character(s)
+ * of the md5sum to do a simple pre-check.
+ */
+static inline int
+rpmeqmagic(Pool *pool, Id evr)
+{
+  const char *s = pool_id2str(pool, evr);
+  if (*s == '0')
+    {
+      while (*s == '0' && s[1] >= '0' && s[1] <= '9')
+       s++;
+      /* ignore epoch 0 */
+      if (*s == '0' && s[1] == ':')
+       {
+         s += 2;
+         while (*s == '0' && s[1] >= '0' && s[1] <= '9')
+           s++;
+       }
+    }
+  if (*s >= '0' && *s <= '9')
+    {
+      if (s[1] >= '0' && s[1] <= '9')
+        return *s + (s[1] << 8);
+      return *s;
+    }
+  if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z'))
+    {
+      if ((s[1] >= 'a' && s[1] <= 'z') || (s[1] >= 'A' && s[1] <= 'Z'))
+        return *s + (s[1] << 8);
+      return *s;
+    }
+  return -1;
+}
+
+static inline int
+rpmeqmagic_init(Pool *pool, int flags, Id evr)
+{
+  if (flags != REL_EQ || pool->disttype != DISTTYPE_RPM || pool->promoteepoch || ISRELDEP(evr))
+    return -1;
+  else
+    return rpmeqmagic(pool, evr);
+}
+
+static inline int
+rpmeqmagic_cantmatch(Pool *pool, int flags, Id evr, int eqmagic)
+{
+  int peqmagic = rpmeqmagic(pool, evr);
+  if (peqmagic > 0 && peqmagic != eqmagic)
+    return 1;
+  return 0;
+}
+
+/*
  * addrelproviders
  *
  * add packages fulfilling the relation to whatprovides array
@@ -1218,6 +1276,7 @@ pool_addrelproviders(Pool *pool, Id d)
   else if (flags)
     {
       Id *ppaux = 0;
+      int eqmagic = 0;
       /* simple version comparison relation */
 #if 0
       POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
@@ -1253,6 +1312,11 @@ pool_addrelproviders(Pool *pool, Id d)
                      prd = GETRELDEP(pool, pid);
                      if (prd->name != name)
                        continue;               /* wrong provides name */
+                     if (!eqmagic)
+                       eqmagic = rpmeqmagic_init(pool, flags, evr);
+                     if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) &&
+                         rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic))
+                       continue;
                      /* right package, both deps are rels. check flags/evr */
                      if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
                        continue;
@@ -1269,6 +1333,8 @@ pool_addrelproviders(Pool *pool, Id d)
              continue;
            }
          /* solvable p provides name in some rels */
+         if (!eqmagic)
+           eqmagic = rpmeqmagic_init(pool, flags, evr);
          pidp = s->repo->idarraydata + s->provides;
          while ((pid = *pidp++) != 0)
            {
@@ -1284,6 +1350,9 @@ pool_addrelproviders(Pool *pool, Id d)
              if (prd->name != name)
                continue;               /* wrong provides name */
              /* right package, both deps are rels. check flags/evr */
+             if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) &&
+                 rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic))
+               continue;
              if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
                break;  /* matches */
            }
index 1ae3b11..3eeea06 100644 (file)
@@ -228,6 +228,7 @@ struct _Pool {
 #define REL_KIND       24      /* for filters only */
 #define REL_MULTIARCH  25      /* debian multiarch annotation */
 #define REL_ELSE       26      /* only as evr part of REL_COND */
+#define REL_ERROR      27      /* parse errors and the like */
 
 #if !defined(__GNUC__) && !defined(__attribute__)
 # define __attribute__(x)
index 91eba34..3a8a3c8 100644 (file)
@@ -194,6 +194,8 @@ pool_id2rel(const Pool *pool, Id id)
       return " KIND ";
     case REL_ELSE:
       return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
+    case REL_ERROR:
+      return " ERROR ";
     default:
       break;
     }
index 37ea381..ceb1062 100644 (file)
 #include "queue.h"
 #include "util.h"
 
-#define EXTRA_SPACE 8
-#define EXTRA_SPACE_HEAD 8
+static inline int
+queue_extra_space(int size)
+{
+  if (size < 32)
+    return 8;
+  if (size < 64)
+    return 16;
+  if (size < 128)
+    return 32;
+  return 64;
+}
 
 void
 queue_init(Queue *q)
@@ -29,17 +38,19 @@ queue_init(Queue *q)
 void
 queue_init_clone(Queue *t, Queue *s)
 {
+  int extra_space;
   if (!s->elements)
     {
       t->alloc = t->elements = 0;
       t->count = t->left = 0;
       return;
     }
-  t->alloc = t->elements = solv_malloc2(s->count + EXTRA_SPACE, sizeof(Id));
+  extra_space = queue_extra_space(s->count);
+  t->alloc = t->elements = solv_malloc2(s->count + extra_space, sizeof(Id));
   if (s->count)
     memcpy(t->alloc, s->elements, s->count * sizeof(Id));
   t->count = s->count;
-  t->left = EXTRA_SPACE;
+  t->left = extra_space;
 }
 
 void
@@ -60,19 +71,13 @@ queue_free(Queue *q)
   q->count = q->left = 0;
 }
 
+/* make room for one element at the tail of the queue */
 void
 queue_alloc_one(Queue *q)
 {
-  if (!q->alloc)
-    {
-      q->alloc = solv_malloc2(q->count + EXTRA_SPACE, sizeof(Id));
-      if (q->count)
-       memcpy(q->alloc, q->elements, q->count * sizeof(Id));
-      q->elements = q->alloc;
-      q->left = EXTRA_SPACE;
-    }
-  else if (q->alloc != q->elements)
+  if (q->alloc && q->alloc != q->elements)
     {
+      /* there's room at the front. just move data */
       int l = q->elements - q->alloc;
       if (q->count)
         memmove(q->alloc, q->elements, q->count * sizeof(Id));
@@ -81,8 +86,17 @@ queue_alloc_one(Queue *q)
     }
   else
     {
-      q->elements = q->alloc = solv_realloc2(q->alloc, q->count + EXTRA_SPACE, sizeof(Id));
-      q->left = EXTRA_SPACE;
+      int extra_space = queue_extra_space(q->count);
+      if (!q->alloc)
+       {
+         q->alloc = solv_malloc2(q->count + extra_space, sizeof(Id));
+         if (q->count)
+           memcpy(q->alloc, q->elements, q->count * sizeof(Id));
+       }
+      else
+       q->alloc = solv_realloc2(q->alloc, q->count + extra_space, sizeof(Id));
+      q->elements = q->alloc;
+      q->left = extra_space;
     }
 }
 
@@ -90,10 +104,11 @@ queue_alloc_one(Queue *q)
 void
 queue_alloc_one_head(Queue *q)
 {
-  int l;
+  int l, extra_space;
   if (!q->alloc || !q->left)
-    queue_alloc_one(q);
-  l = q->left > EXTRA_SPACE_HEAD ? EXTRA_SPACE_HEAD : q->left;
+    queue_alloc_one(q);                /* easy way to make room */
+  extra_space = queue_extra_space(q->count);
+  l = q->left > extra_space ? extra_space : q->left;
   if (q->count)
     memmove(q->elements + l, q->elements, q->count * sizeof(Id));
   q->elements += l;
@@ -160,15 +175,7 @@ queue_insertn(Queue *q, int pos, int n, Id *elements)
   if (pos > q->count)
     pos = q->count;
   if (q->left < n)
-    {
-      int off;
-      if (!q->alloc)
-       queue_alloc_one(q);
-      off = q->elements - q->alloc;
-      q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
-      q->elements = q->alloc + off;
-      q->left = n + EXTRA_SPACE;
-    }
+    queue_prealloc(q, n);
   if (pos < q->count)
     memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id));
   if (elements)
@@ -192,18 +199,19 @@ queue_deleten(Queue *q, int pos, int n)
   q->count -= n;
 }
 
-/* allocate room for n more elements */
+/* pre-allocate room for n more elements */
 void
 queue_prealloc(Queue *q, int n)
 {
-  int off;
+  int off, extra_space;
   if (n <= 0 || q->left >= n)
     return;
   if (!q->alloc)
     queue_alloc_one(q);
   off = q->elements - q->alloc;
-  q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
+  extra_space = queue_extra_space(q->count + n);
+  q->alloc = solv_realloc2(q->alloc, off + q->count + n + extra_space, sizeof(Id));
   q->elements = q->alloc + off;
-  q->left = n + EXTRA_SPACE;
+  q->left = n + extra_space;
 }
 
index 027c24c..06b2ea3 100644 (file)
@@ -351,6 +351,8 @@ repodata_dir2str(Repodata *data, Id did, const char *suf)
 
   if (!did)
     return suf ? suf : "";
+  if (did == 1 && !suf)
+    return "/";
   parent = did;
   while (parent)
     {
index 33f5350..26b93ea 100644 (file)
@@ -3485,6 +3485,12 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
 
   if (solv->bestupdatemap_all || solv->bestupdatemap.size)
     {
+      Map m;
+
+      if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+       map_init(&m, pool->nsolvables);
+      else
+       map_init(&m, 0);
       FOR_REPO_SOLVABLES(installed, p, s)
        {
          Id d, p2, pp2;
@@ -3543,6 +3549,29 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
                    queue_pushunique(&q, q2.elements[j]);
                }
            }
+         if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start)))
+           {
+             /* package is flagged both for allowuninstall and best, add negative rules */
+             d = q.count == 1 ? q.elements[0] : -pool_queuetowhatprovides(pool, &q);
+             for (i = 0; i < q.count; i++)
+               MAPSET(&m, q.elements[i]);
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (!r->p)        /* identical to update rule? */
+               r = solv->rules + solv->updaterules + (p - installed->start);
+             FOR_RULELITERALS(p2, pp2, r)
+               {
+                 if (MAPTST(&m, p2))
+                   continue;
+                 if (d >= 0)
+                   solver_addrule(solv, -p2, d, 0);
+                 else
+                   solver_addrule(solv, -p2, 0, -d);
+                 queue_push(&r2pkg, p);
+               }
+             for (i = 0; i < q.count; i++)
+               MAPCLR(&m, q.elements[i]);
+             continue;
+           }
          p2 = queue_shift(&q);
          if (q.count < 2)
            solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
@@ -3550,6 +3579,7 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
            solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
          queue_push(&r2pkg, p);
        }
+      map_free(&m);
     }
   if (r2pkg.count)
     solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id));
index c759746..fb1554a 100644 (file)
@@ -3528,7 +3528,7 @@ solver_solve(Solver *solv, Queue *job)
   Map installcandidatemap;
   Id how, what, select, name, weak, p, pp, d;
   Queue q;
-  Solvable *s;
+  Solvable *s, *name_s;
   Rule *r;
   int now, solve_start;
   int needduprules = 0;
@@ -4020,6 +4020,7 @@ solver_solve(Solver *solv, Queue *job)
            map_grow(&solv->cleandepsmap, installed->end - installed->start);
          /* specific solvable: by id or by nevra */
          name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
+         name_s = 0;
          if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
            {
              FOR_POOL_SOLVABLES(p)
@@ -4046,7 +4047,10 @@ solver_solve(Solver *solv, Queue *job)
            {
              s = pool->solvables + p;
              if (installed && s->repo == installed)
-               name = !name ? s->name : -1;
+               {
+                 name = !name ? s->name : -1;
+                 name_s = s;
+               }
              solver_addjobrule(solv, -p, 0, 0, i, weak);
            }
          /* special case for "erase a specific solvable": we also
@@ -4070,6 +4074,8 @@ solver_solve(Solver *solv, Queue *job)
                  /* keep installcandidates of other jobs */
                  if (MAPTST(&installcandidatemap, p))
                    continue;
+                 if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, name_s, s))
+                   continue;
                  /* don't add the same rule twice */
                  for (j = oldnrules; j < k; j++)
                    if (solv->rules[j].p == -p)
index 9f59d75..7d107f9 100644 (file)
@@ -38,9 +38,9 @@ extern int solv_version_patch;
 #cmakedefine LIBSOLVEXT_FEATURE_HELIXREPO
 #cmakedefine LIBSOLVEXT_FEATURE_DEBIAN
 #cmakedefine LIBSOLVEXT_FEATURE_ARCHREPO
-#cmakedefine LIBSOLVEXT_FEATURE_CUDFREPO
 #cmakedefine LIBSOLVEXT_FEATURE_HAIKU
 #cmakedefine LIBSOLVEXT_FEATURE_APPDATA
+#cmakedefine LIBSOLVEXT_FEATURE_ZLIB_COMPRESSION
 #cmakedefine LIBSOLVEXT_FEATURE_LZMA_COMPRESSION
 #cmakedefine LIBSOLVEXT_FEATURE_BZIP2_COMPRESSION
 
diff --git a/test/testcases/testcase/nested.t b/test/testcases/testcase/nested.t
new file mode 100644 (file)
index 0000000..355f014
--- /dev/null
@@ -0,0 +1,56 @@
+# regression test for testcase_dep2str of deeply nested dependencies
+# this used to segfault or return wrong roundtrip results
+genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y |z
+result genid <inline>
+#>genid  1: genid lit a
+#>genid  2: genid lit b
+#>genid  3: genid lit c
+#>genid  4: genid lit d
+#>genid  5: genid lit e
+#>genid  6: genid lit f
+#>genid  7: genid lit g
+#>genid  8: genid lit h
+#>genid  9: genid lit i
+#>genid 10: genid lit j
+#>genid 11: genid lit k
+#>genid 12: genid lit l
+#>genid 13: genid lit m
+#>genid 14: genid lit n
+#>genid 15: genid lit o
+#>genid 16: genid lit p
+#>genid 17: genid lit q
+#>genid 18: genid lit r
+#>genid 19: genid lit s
+#>genid 20: genid lit t
+#>genid 21: genid lit u
+#>genid 22: genid lit v
+#>genid 23: genid lit w
+#>genid 24: genid lit x
+#>genid 25: genid lit y
+#>genid 26: genid lit z
+#>genid 27: genid op |
+#>genid 28: genid op |
+#>genid 29: genid op |
+#>genid 30: genid op |
+#>genid 31: genid op |
+#>genid 32: genid op |
+#>genid 33: genid op |
+#>genid 34: genid op |
+#>genid 35: genid op |
+#>genid 36: genid op |
+#>genid 37: genid op |
+#>genid 38: genid op |
+#>genid 39: genid op |
+#>genid 40: genid op |
+#>genid 41: genid op |
+#>genid 42: genid op |
+#>genid 43: genid op |
+#>genid 44: genid op |
+#>genid 45: genid op |
+#>genid 46: genid op |
+#>genid 47: genid op |
+#>genid 48: genid op |
+#>genid 49: genid op |
+#>genid 50: genid op |
+#>genid 51: genid op |
+#>genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z
index a8753a1..ce6c98c 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 6dcb076..5f8eade 100644 (file)
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <getopt.h>
+#include <unistd.h>
 
 #include "pool.h"
 #include "repo.h"
index 1336b3f..e20f64f 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 73854d2..cdbcf74 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 41616ba..7d6348f 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index d893fb1..04c6b48 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index b0fdb33..6c090d8 100644 (file)
@@ -15,7 +15,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <zlib.h>
 
 #include "pool.h"
 #include "poolarch.h"
index dcf9d6f..bd77fb7 100644 (file)
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <getopt.h>
+#include <unistd.h>
 
 #include "pool.h"
 #include "repo.h"
index 6719c8c..ae6e163 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <sys/types.h>
 #include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 6a5c3f7..4025f92 100644 (file)
@@ -14,7 +14,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-#include <zlib.h>
 
 #include "pool.h"
 #include "evr.h"
index f32c35d..e3159de 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index 99c4880..aa978d8 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index d4fe2ff..437c83d 100644 (file)
@@ -8,13 +8,10 @@
 #define _GNU_SOURCE
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <zlib.h>
 
 #include "pool.h"
 #include "repo.h"
index 71c65d8..19278db 100644 (file)
@@ -8,14 +8,11 @@
 #define _GNU_SOURCE
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <dirent.h>
-#include <zlib.h>
-#include <getopt.h>
+#include <unistd.h>
 
 #include "pool.h"
 #include "repo.h"
index 5432150..6a97b0d 100644 (file)
@@ -6,8 +6,6 @@
  */
 
 #include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>