From 97330b5a608c2213fdf3f49bfbaa268bf9627920 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Fri, 30 Nov 2018 12:40:36 +0900 Subject: [PATCH 1/1] Imported Upstream version 0.6.27 Change-Id: I4feccd10bd9fe0514ff13520136e962b6c093175 Signed-off-by: DongHun Kwak --- CMakeLists.txt | 34 ++- NEWS | 6 + VERSION.cmake | 2 +- bindings/python3/CMakeLists.txt | 4 +- bindings/solv.i | 8 +- ext/CMakeLists.txt | 10 + ext/pool_fileconflicts.c | 2 - ext/repo_appdata.c | 293 +++++++---------------- ext/repo_comps.c | 225 +++--------------- ext/repo_content.c | 2 - ext/repo_cudf.c | 1 - ext/repo_deltainfoxml.c | 216 ++++------------- ext/repo_helix.c | 300 ++++++------------------ ext/repo_mdk.c | 158 +++---------- ext/repo_products.c | 265 ++++----------------- ext/repo_pubkey.c | 2 - ext/repo_repomdxml.c | 220 ++++-------------- ext/repo_rpmdb.c | 59 +++-- ext/repo_rpmmd.c | 489 ++++++++++----------------------------- ext/repo_susetags.c | 174 +++----------- ext/repo_updateinfoxml.c | 291 +++++------------------ ext/repo_zyppdb.c | 234 +++---------------- ext/repodata_diskusage.c | 78 +++++++ ext/repodata_diskusage.h | 10 + ext/solv_xfopen.c | 47 ++-- ext/solv_xmlparser.c | 321 +++++++++++++++++++++++++ ext/solv_xmlparser.h | 52 +++++ ext/testcase.c | 66 +++--- package/libsolv.changes | 14 +- package/libsolv.spec.in | 15 +- src/pool.c | 69 ++++++ src/pool.h | 1 + src/poolid.c | 2 + src/queue.c | 70 +++--- src/repodata.c | 2 + src/rules.c | 30 +++ src/solver.c | 10 +- src/solvversion.h.in | 2 +- test/testcases/testcase/nested.t | 56 +++++ tools/appdata2solv.c | 2 - tools/archrepo2solv.c | 4 +- tools/common_write.c | 2 - tools/comps2solv.c | 2 - tools/deltainfoxml2solv.c | 2 - tools/helix2solv.c | 2 - tools/installcheck.c | 1 - tools/mdk2solv.c | 4 +- tools/mergesolv.c | 2 - tools/patchcheck.c | 1 - tools/repomdxml2solv.c | 2 - tools/rpmdb2solv.c | 2 - tools/rpmmd2solv.c | 3 - tools/susetags2solv.c | 5 +- tools/updateinfoxml2solv.c | 2 - 54 files changed, 1443 insertions(+), 2433 deletions(-) create mode 100644 ext/repodata_diskusage.c create mode 100644 ext/repodata_diskusage.h create mode 100644 ext/solv_xmlparser.c create mode 100644 ext/solv_xmlparser.h create mode 100644 test/testcases/testcase/nested.t diff --git a/CMakeLists.txt b/CMakeLists.txt index 838f9d0..bcdeee6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 --- 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 diff --git a/VERSION.cmake b/VERSION.cmake index 1d0be13..55b1018 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0") SET(LIBSOLV_MAJOR "0") SET(LIBSOLV_MINOR "6") -SET(LIBSOLV_PATCH "26") +SET(LIBSOLV_PATCH "27") diff --git a/bindings/python3/CMakeLists.txt b/bindings/python3/CMakeLists.txt index 7a2dca3..09c8e29 100644 --- a/bindings/python3/CMakeLists.txt +++ b/bindings/python3/CMakeLists.txt @@ -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) diff --git a/bindings/solv.i b/bindings/solv.i index 61dc640..7302d3a 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -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; diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 586eda8..bdc6ee9 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -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") diff --git a/ext/pool_fileconflicts.c b/ext/pool_fileconflicts.c index 6c9119f..cb55d58 100644 --- a/ext/pool_fileconflicts.c +++ b/ext/pool_fileconflicts.c @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include "pool.h" diff --git a/ext/repo_appdata.c b/ext/repo_appdata.c index 2b9844e..62faf2d 100644 --- a/ext/repo_appdata.c +++ b/ext/repo_appdata.c @@ -14,20 +14,17 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include #include #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 diff --git a/ext/repo_comps.c b/ext/repo_comps.c index 8f364dd..255ecb1 100644 --- a/ext/repo_comps.c +++ b/ext/repo_comps.c @@ -12,19 +12,15 @@ #include #include #include -#include -#include -#include #include #include #include #include -#include -#include #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)) diff --git a/ext/repo_content.c b/ext/repo_content.c index b12c4cd..68af2d5 100644 --- a/ext/repo_content.c +++ b/ext/repo_content.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include diff --git a/ext/repo_cudf.c b/ext/repo_cudf.c index 00a4f87..14ddcc9 100644 --- a/ext/repo_cudf.c +++ b/ext/repo_cudf.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "pool.h" diff --git a/ext/repo_deltainfoxml.c b/ext/repo_deltainfoxml.c index 06df1a3..4eb340f 100644 --- a/ext/repo_deltainfoxml.c +++ b/ext/repo_deltainfoxml.c @@ -5,20 +5,16 @@ * for further information */ -#define DO_ARRAY 1 - #define _GNU_SOURCE #include -#include -#include #include #include #include -#include #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) diff --git a/ext/repo_helix.c b/ext/repo_helix.c index 6358f72..3c2c6d1 100644 --- a/ext/repo_helix.c +++ b/ext/repo_helix.c @@ -21,13 +21,12 @@ */ #include -#include -#include #include #include #include -#include +#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 : */ { 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 - * - * - */ - -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 ':' */ - pd->content[pd->lcontent] = 0; + strcpy(xmlp->content, pd->kind); + xmlp->lcontent = strlen(xmlp->content); + xmlp->content[xmlp->lcontent++] = ':'; /* prefix name with ':' */ + 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 - * - * - * 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); diff --git a/ext/repo_mdk.c b/ext/repo_mdk.c index 345d416..418bc61 100644 --- a/ext/repo_mdk.c +++ b/ext/repo_mdk.c @@ -11,12 +11,12 @@ #include #include #include -#include #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); diff --git a/ext/repo_products.c b/ext/repo_products.c index 326f8fd..154a909 100644 --- a/ext/repo_products.c +++ b/ext/repo_products.c @@ -18,19 +18,16 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include #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) /* ... */ 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); diff --git a/ext/repo_pubkey.c b/ext/repo_pubkey.c index d8496dc..eb83839 100644 --- a/ext/repo_pubkey.c +++ b/ext/repo_pubkey.c @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include #include diff --git a/ext/repo_repomdxml.c b/ext/repo_repomdxml.c index 1d1197e..760d481 100644 --- a/ext/repo_repomdxml.c +++ b/ext/repo_repomdxml.c @@ -5,20 +5,16 @@ * for further information */ -#define DO_ARRAY 1 - #define _GNU_SOURCE #include -#include -#include #include #include #include -#include #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; } diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index fe05bec..40a1e3e 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -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) diff --git a/ext/repo_rpmmd.c b/ext/repo_rpmmd.c index 8854bca..6c05281 100644 --- a/ext/repo_rpmmd.c +++ b/ext/repo_rpmmd.c @@ -6,12 +6,9 @@ */ #include -#include -#include #include #include #include -#include #include "pool.h" #include "repo.h" @@ -19,9 +16,11 @@ #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, " 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); diff --git a/ext/repo_susetags.c b/ext/repo_susetags.c index 83967e0..41c7a78 100644 --- a/ext/repo_susetags.c +++ b/ext/repo_susetags.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -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; } diff --git a/ext/repo_updateinfoxml.c b/ext/repo_updateinfoxml.c index 6af74f2..7ba0062 100644 --- a/ext/repo_updateinfoxml.c +++ b/ext/repo_updateinfoxml.c @@ -8,16 +8,14 @@ #define _GNU_SOURCE #define _XOPEN_SOURCE /* glibc2 needs this */ #include -#include -#include #include #include #include -#include #include #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; /* * buildtime = (time_t)0; } break; - /* FEDORA-2007-4594 */ - case STATE_ID: - break; - /* imlib-1.9.15-6.fc8 */ - case STATE_TITLE: - break; - /* Fedora 8 */ - case STATE_RELEASE: - break; - /* - */ + 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; - /* - */ + 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; - /* This update ... */ - case STATE_DESCRIPTION: - break; - /* This update ... */ - case STATE_MESSAGE: - break; - case STATE_PKGLIST: - break; - /* Fedora 8 */ - case STATE_NAME: - break; + /* @@ -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; } - /* libntlm-0.4.2-1.fc8.x86_64.rpm */ - /* libntlm-0.4.2-1.fc8.x86_64.rpm */ - case STATE_FILENAME: - break; - /* True */ - case STATE_REBOOT: - break; - /* True */ - case STATE_RESTART: - break; - /* True */ - 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; + /* imlib-1.9.15-6.fc8 */ 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; - /* - * Fedora 8 - */ - 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; + /* * This update ... */ 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; + /* * Warning! ... */ 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; + /* libntlm-0.4.2-1.fc8.x86_64.rpm */ /* libntlm-0.4.2-1.fc8.x86_64.rpm */ 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; + /* True */ 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; + /* True */ 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; + /* True */ 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)) diff --git a/ext/repo_zyppdb.c b/ext/repo_zyppdb.c index 5200c29..d73a900 100644 --- a/ext/repo_zyppdb.c +++ b/ext/repo_zyppdb.c @@ -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 @@ -14,20 +13,17 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include #include #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; - /* ... */ - case STATE_SUMMARY: - pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts)); + case STATE_SUMMARY: /* ... */ + 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 index 0000000..fd9c5cc --- /dev/null +++ b/ext/repodata_diskusage.c @@ -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 +#include +#include +#include + +#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 index 0000000..1beafea --- /dev/null +++ b/ext/repodata_diskusage.h @@ -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); + + diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c index b0421bf..967984e 100644 --- a/ext/solv_xfopen.c +++ b/ext/solv_xfopen.c @@ -10,30 +10,12 @@ #include #include #include -#include #include #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 + 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 + +#ifdef ENABLE_BZIP2_COMPRESSION /* bzip2 compression */ +#include + 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 code written by me in 2008 for rpm's rpmio.c */ +#include + 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 index 0000000..170520f --- /dev/null +++ b/ext/solv_xmlparser.c @@ -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 +#include +#include +#include + +#ifdef WITH_LIBXML2 +#include +#else +#include +#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 index 0000000..9fb342f --- /dev/null +++ b/ext/solv_xmlparser.h @@ -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); + + diff --git a/ext/testcase.c b/ext/testcase.c index ccfcb61..f515057 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include #include @@ -387,41 +385,42 @@ struct oplist { { REL_COMPAT, "compat >=" }, { REL_KIND, "" }, { REL_ELSE, "" }, + { REL_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; diff --git a/package/libsolv.changes b/package/libsolv.changes index f772422..94bb400 100644 --- a/package/libsolv.changes +++ b/package/libsolv.changes @@ -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 ------------------------------------------------------------------- diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in index 0009287..d21562c 100644 --- a/package/libsolv.spec.in +++ b/package/libsolv.spec.in @@ -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 diff --git a/src/pool.c b/src/pool.c index 1adf70e..bd97026 100644 --- a/src/pool.c +++ b/src/pool.c @@ -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 */ } diff --git a/src/pool.h b/src/pool.h index 1ae3b11..3eeea06 100644 --- a/src/pool.h +++ b/src/pool.h @@ -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) diff --git a/src/poolid.c b/src/poolid.c index 91eba34..3a8a3c8 100644 --- a/src/poolid.c +++ b/src/poolid.c @@ -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; } diff --git a/src/queue.c b/src/queue.c index 37ea381..ceb1062 100644 --- a/src/queue.c +++ b/src/queue.c @@ -16,8 +16,17 @@ #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; } diff --git a/src/repodata.c b/src/repodata.c index 027c24c..06b2ea3 100644 --- a/src/repodata.c +++ b/src/repodata.c @@ -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) { diff --git a/src/rules.c b/src/rules.c index 33f5350..26b93ea 100644 --- a/src/rules.c +++ b/src/rules.c @@ -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)); diff --git a/src/solver.c b/src/solver.c index c759746..fb1554a 100644 --- a/src/solver.c +++ b/src/solver.c @@ -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) diff --git a/src/solvversion.h.in b/src/solvversion.h.in index 9f59d75..7d107f9 100644 --- a/src/solvversion.h.in +++ b/src/solvversion.h.in @@ -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 index 0000000..355f014 --- /dev/null +++ b/test/testcases/testcase/nested.t @@ -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 +#>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 diff --git a/tools/appdata2solv.c b/tools/appdata2solv.c index a8753a1..ce6c98c 100644 --- a/tools/appdata2solv.c +++ b/tools/appdata2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/archrepo2solv.c b/tools/archrepo2solv.c index 6dcb076..5f8eade 100644 --- a/tools/archrepo2solv.c +++ b/tools/archrepo2solv.c @@ -15,12 +15,10 @@ */ #include -#include -#include #include #include #include -#include +#include #include "pool.h" #include "repo.h" diff --git a/tools/common_write.c b/tools/common_write.c index 1336b3f..e20f64f 100644 --- a/tools/common_write.c +++ b/tools/common_write.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/comps2solv.c b/tools/comps2solv.c index 73854d2..cdbcf74 100644 --- a/tools/comps2solv.c +++ b/tools/comps2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/deltainfoxml2solv.c b/tools/deltainfoxml2solv.c index 41616ba..7d6348f 100644 --- a/tools/deltainfoxml2solv.c +++ b/tools/deltainfoxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/helix2solv.c b/tools/helix2solv.c index d893fb1..04c6b48 100644 --- a/tools/helix2solv.c +++ b/tools/helix2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/installcheck.c b/tools/installcheck.c index b0fdb33..6c090d8 100644 --- a/tools/installcheck.c +++ b/tools/installcheck.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "pool.h" #include "poolarch.h" diff --git a/tools/mdk2solv.c b/tools/mdk2solv.c index dcf9d6f..bd77fb7 100644 --- a/tools/mdk2solv.c +++ b/tools/mdk2solv.c @@ -15,12 +15,10 @@ */ #include -#include -#include #include #include #include -#include +#include #include "pool.h" #include "repo.h" diff --git a/tools/mergesolv.c b/tools/mergesolv.c index 6719c8c..ae6e163 100644 --- a/tools/mergesolv.c +++ b/tools/mergesolv.c @@ -12,8 +12,6 @@ #include #include -#include -#include #include #include #include diff --git a/tools/patchcheck.c b/tools/patchcheck.c index 6a5c3f7..4025f92 100644 --- a/tools/patchcheck.c +++ b/tools/patchcheck.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "pool.h" #include "evr.h" diff --git a/tools/repomdxml2solv.c b/tools/repomdxml2solv.c index f32c35d..e3159de 100644 --- a/tools/repomdxml2solv.c +++ b/tools/repomdxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/rpmdb2solv.c b/tools/rpmdb2solv.c index 99c4880..aa978d8 100644 --- a/tools/rpmdb2solv.c +++ b/tools/rpmdb2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include diff --git a/tools/rpmmd2solv.c b/tools/rpmmd2solv.c index d4fe2ff..437c83d 100644 --- a/tools/rpmmd2solv.c +++ b/tools/rpmmd2solv.c @@ -8,13 +8,10 @@ #define _GNU_SOURCE #include -#include -#include #include #include #include #include -#include #include "pool.h" #include "repo.h" diff --git a/tools/susetags2solv.c b/tools/susetags2solv.c index 71c65d8..19278db 100644 --- a/tools/susetags2solv.c +++ b/tools/susetags2solv.c @@ -8,14 +8,11 @@ #define _GNU_SOURCE #include -#include -#include #include #include #include #include -#include -#include +#include #include "pool.h" #include "repo.h" diff --git a/tools/updateinfoxml2solv.c b/tools/updateinfoxml2solv.c index 5432150..6a97b0d 100644 --- a/tools/updateinfoxml2solv.c +++ b/tools/updateinfoxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include -- 2.7.4