Skip to content

Commit

Permalink
main: introduce experimental libxml2 based xpath metaparser
Browse files Browse the repository at this point in the history
TODO: qualified-tags
Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed Jan 21, 2016
1 parent 01cedde commit a086aff
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 2 deletions.
9 changes: 9 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ MAIN_SRCS += $(REGEX_SRCS)
MAIN_HEADS += $(REGEX_HEADS)
endif

if HAVE_LIBXML
PARSER_SRCS += $(XML_SRCS)
PARSER_HEADS += $(XML_HEADS)
endif

ctags_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/main
if ENABLE_DEBUGGING
ctags_CPPFLAGS+= $(DEBUG_CPPFLAGS)
Expand All @@ -34,6 +39,10 @@ ctags_CFLAGS += $(EXTRA_CFLAGS)
ctags_CFLAGS += $(WARNING_CFLAGS)
ctags_CFLAGS += $(COVERAGE_CFLAGS)
ctags_CFLAGS += $(CGCC_CFLAGS)
ctags_CFLAGS += $(LIBXML_CFLAGS)

ctags_LDADD =
ctags_LDADD += $(LIBXML_LIBS)

nodist_ctags_SOURCES = $(REPOINFO_HEADS)
BUILT_SOURCES = $(REPOINFO_HEADS)
Expand Down
9 changes: 9 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,15 @@ AC_CHECK_FUNCS(scandir)
AC_CHECK_FUNCS(fork waitpid execv pipe,[enable_xcmd=yes],[enable_xcmd=no])
AM_CONDITIONAL([ENABLE_XCMD], [test "xyes" = "x$enable_xcmd"])

AH_TEMPLATE([HAVE_LIBXML],
[Define this value if libxml is available.])
PKG_CHECK_MODULES(LIBXML, libxml-2.0,
[have_libxml=yes
AC_DEFINE(HAVE_LIBXML)],
[have_libxml=no])
AM_CONDITIONAL(HAVE_LIBXML, test "x$have_libxml" = xyes)


# Checks for missing prototypes
# -----------------------------
AC_MSG_NOTICE(checking for new missing prototypes)
Expand Down
183 changes: 183 additions & 0 deletions main/lxpath.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2015, Masatake YAMATO
* Copyright (c) 2015, Red Hat, Inc.
*
* This source code is released for free distribution under the terms of the
* GNU General Public License version 2 or (at your option) any later version.
*
* This module contains functions for applying regular expression matching.
*
* The code for utilizing the Gnu regex package with regards to processing the
* regex option and checking for regex matches was adapted from routines in
* Gnu etags.
*/

#include "general.h" /* must always come first */
#include "debug.h"
#include "entry.h"
#include "options.h"
#include "parse.h"
#include "read.h"
#include "routines.h"
#include "xtag.h"

#ifdef HAVE_LIBXML
#include <libxml/xpath.h>
#include <libxml/tree.h>

static void simpleXpathMakeTag (xmlNode *node,
const tagXpathMakeTagSpec *spec,
const kindOption* const kinds,
void *userData)
{
tagEntryInfo tag;
xmlChar* str;
const kindOption *kind;

str = xmlNodeGetContent(node);
if (str == NULL)
return;

kind = kinds + spec->kind;

if (spec->role == ROLE_INDEX_DEFINITION)
initTagEntry (&tag, (char *)str, kind);
else if (isXtagEnabled(XTAG_REFERENCE_TAGS))
initRefTagEntry (&tag, (char *)str,
kind,
spec->role);
else
goto out;


tag.lineNumber = xmlGetLineNo (node);
tag.filePosition = getInputFilePositionForLine (tag.lineNumber);

if (spec->make)
spec->make (node, spec, &tag, userData);
else
makeTagEntry (&tag);

out:
xmlFree (str);
}

extern void addTagXpath (const langType language, tagXpathTable *xpathTable)
{
Assert (xpathTable->xpath);
Assert (!xpathTable->xpathCompiled);

verbose ("compile a xpath expression: %s\n", (xmlChar *)xpathTable->xpath);
xpathTable->xpathCompiled = xmlXPathCompile ((xmlChar *)xpathTable->xpath);
if (!xpathTable->xpathCompiled)
error (WARNING, "Failed to compile the Xpath expression: %s", xpathTable->xpath);
}

static void findXMLTagsCore (xmlXPathContext *ctx, xmlNode *root,
const tagXpathTableTable *xpathTableTable,
const kindOption* const kinds,void *userData)
{
unsigned int i, j;
xmlNode * node;

Assert (root);
Assert (xpathTableTable);

for (i = 0; i < xpathTableTable->count; ++i)
{
xmlXPathObject *object;
xmlNodeSet *set;
const tagXpathTable *elt = xpathTableTable->table + i;

if (! elt->xpathCompiled)
continue;

#if 0
/* Older version of libxml2 doesn't have xmlXPathSetContextNode. */
if (xmlXPathSetContextNode (root, ctx) != 0)
{
error (WARNING, "Failed to set node to XpathContext");
return;
}
#else
ctx->node = root;
#endif

object = xmlXPathCompiledEval (elt->xpathCompiled, ctx);
if (!object)
continue;

set = object->nodesetval;

if (set)
{
for (j = 0; j < set->nodeNr; ++j)
{
node = set->nodeTab[j];
if (elt->specType == LXPATH_TABLE_DO_MAKE)
simpleXpathMakeTag (node, &(elt->makeTagSpec), kinds, userData);
else
elt->recurSpec.enter (node, &(elt->recurSpec), ctx, userData);
}
}
xmlXPathFreeObject (object);
}
}

extern void findXMLTags (xmlXPathContext *ctx, xmlNode *root,
const tagXpathTableTable *xpathTableTable,
const kindOption* const kinds,void *userData)
{
boolean usedAsEnterPoint = FALSE;
xmlDocPtr doc = NULL;

if (ctx == NULL)
{
usedAsEnterPoint = TRUE;

findRegexTags ();
doc = xmlParseFile(getInputFileName());
if (doc == NULL)
{
verbose ("could not parse %s as a XML file\n", getInputFileName());
return;
}

ctx = xmlXPathNewContext (doc);
if (ctx == NULL)
error (FATAL, "failed to make a new xpath context for %s", getInputFileName());

root = xmlDocGetRootElement(doc);
if (root == NULL)
{
verbose ("could not get the root node for %s\n", getInputFileName());
goto out;
}
}

findXMLTagsCore (ctx, root, xpathTableTable, kinds, userData);

out:
if (usedAsEnterPoint)
{
xmlXPathFreeContext (ctx);
xmlFreeDoc (doc);
}
}

#else

extern void addTagXpath (const langType language, tagXpathTable *xpathTable)
{
xpathTable->xpathCompiled = NULL;
}

extern void findXMLTags (xmlXPathContext *ctx, xmlNode *root,
const tagXpathTableTable *xpathTableTable,
const kindOption* const kinds, void *userData)
{
}

#endif

/* vi:set tabstop=4 shiftwidth=4: */
3 changes: 3 additions & 0 deletions main/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ static const char *const Features [] = {
#endif
#ifdef HAVE_COPROC
"coproc",
#endif
#ifdef HAVE_LIBXML
"xpath",
#endif
NULL
};
Expand Down
33 changes: 31 additions & 2 deletions main/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ static void initializeParser (langType lang);
static parserDefinition *CTagsSelfTestParser (void);
static parserDefinitionFunc* BuiltInParsers[] = {
CTagsSelfTestParser,
PARSER_LIST
PARSER_LIST,
XML_PARSER_LIST
};
static parserDefinition** LanguageTable = NULL;
static unsigned int LanguageCount = 0;
Expand Down Expand Up @@ -112,7 +113,8 @@ extern boolean isLanguageEnabled (const langType language)
if ((lang->method & METHOD_XCMD) &&
(!(lang->method & METHOD_XCMD_AVAILABLE)) &&
(lang->kinds == NULL) &&
(!(lang->method & METHOD_REGEX)))
(!(lang->method & METHOD_REGEX)) &&
(!(lang->method & METHOD_XPATH)))
return FALSE;
else
return TRUE;
Expand Down Expand Up @@ -1104,6 +1106,7 @@ static void initializeParser (langType lang)

installKeywordTable (lang);
installTagRegexTable (lang);
installTagXpathTable (lang);

if (hasScopeActionInRegex (lang))
parser->useCork = TRUE;
Expand Down Expand Up @@ -1979,6 +1982,15 @@ extern void useXcmdMethod (const langType language)
lang->method |= METHOD_XCMD;
}

extern void useXpathMethod (const langType language)
{
parserDefinition* lang;

Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];
lang->method |= METHOD_XPATH;
}

extern void notifyAvailabilityXcmdMethod (const langType language)
{
parserDefinition* lang;
Expand Down Expand Up @@ -2027,6 +2039,23 @@ extern void installKeywordTable (const langType language)
}
}

extern void installTagXpathTable (const langType language)
{
parserDefinition* lang;
unsigned int i, j;

Assert (0 <= language && language < (int) LanguageCount);
lang = LanguageTable [language];

if ((lang->tagXpathTableTable != NULL) && (lang->tagXpathInstalled == FALSE))
{
for (i = 0; i < lang->tagXpathTableCount; ++i)
for (j = 0; j < lang->tagXpathTableTable[i].count; ++j)
addTagXpath (language, lang->tagXpathTableTable[i].table + j);
lang->tagXpathInstalled = TRUE;
}
}

/*
* A parser for CTagsSelfTest (CTST)
*/
Expand Down
Loading

0 comments on commit a086aff

Please sign in to comment.