fixed an uninitialized variable extended the API to add the parser,
* valid.c: fixed an uninitialized variable
* xmlregexp.c include/libxml/xmlregexp.h: extended the API to
add the parser, serializer and some debugging
* include/libxml/xmlversion.h.in: made the new support compiled
by default if Schemas is included
* testRegexp.c: cleanup and integration of the first part of the
new code with a special switch
* xmllint.c: show up Expr in --version if compiled in
* include/libxml/tree.h: moved the xmlBuffer definition up
Daniel
diff --git a/ChangeLog b/ChangeLog
index 408ecf3..b2b4ee8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Mon Aug 22 13:49:18 CEST 2005 Daniel Veillard <daniel@veillard.com>
+
+ * valid.c: fixed an uninitialized variable
+ * xmlregexp.c include/libxml/xmlregexp.h: extended the API to
+ add the parser, serializer and some debugging
+ * include/libxml/xmlversion.h.in: made the new support compiled
+ by default if Schemas is included
+ * testRegexp.c: cleanup and integration of the first part of the
+ new code with a special switch
+ * xmllint.c: show up Expr in --version if compiled in
+ * include/libxml/tree.h: moved the xmlBuffer definition up
+
Mon Aug 22 12:11:10 CEST 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
* xmlschemas.c: Some preparation for the creation of a graph
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index d995e5c..bd62d0a 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -55,6 +55,33 @@
#define BASE_BUFFER_SIZE 4096
/**
+ * xmlBufferAllocationScheme:
+ *
+ * A buffer allocation scheme can be defined to either match exactly the
+ * need or double it's allocated size each time it is found too small.
+ */
+
+typedef enum {
+ XML_BUFFER_ALLOC_DOUBLEIT,
+ XML_BUFFER_ALLOC_EXACT,
+ XML_BUFFER_ALLOC_IMMUTABLE
+} xmlBufferAllocationScheme;
+
+/**
+ * xmlBuffer:
+ *
+ * A buffer structure.
+ */
+typedef struct _xmlBuffer xmlBuffer;
+typedef xmlBuffer *xmlBufferPtr;
+struct _xmlBuffer {
+ xmlChar *content; /* The buffer content UTF8 */
+ unsigned int use; /* The buffer size used */
+ unsigned int size; /* The buffer size */
+ xmlBufferAllocationScheme alloc; /* The realloc method */
+};
+
+/**
* XML_XML_NAMESPACE:
*
* This is the namespace for the special xml: prefix predefined in the
@@ -402,33 +429,6 @@
};
/**
- * xmlBufferAllocationScheme:
- *
- * A buffer allocation scheme can be defined to either match exactly the
- * need or double it's allocated size each time it is found too small.
- */
-
-typedef enum {
- XML_BUFFER_ALLOC_DOUBLEIT,
- XML_BUFFER_ALLOC_EXACT,
- XML_BUFFER_ALLOC_IMMUTABLE
-} xmlBufferAllocationScheme;
-
-/**
- * xmlBuffer:
- *
- * A buffer structure.
- */
-typedef struct _xmlBuffer xmlBuffer;
-typedef xmlBuffer *xmlBufferPtr;
-struct _xmlBuffer {
- xmlChar *content; /* The buffer content UTF8 */
- unsigned int use; /* The buffer size used */
- unsigned int size; /* The buffer size */
- xmlBufferAllocationScheme alloc; /* The realloc method */
-};
-
-/**
* xmlNode:
*
* A node in an XML tree.
diff --git a/include/libxml/xmlregexp.h b/include/libxml/xmlregexp.h
index 7dcb875..cd342c8 100644
--- a/include/libxml/xmlregexp.h
+++ b/include/libxml/xmlregexp.h
@@ -40,6 +40,7 @@
}
#endif
#include <libxml/tree.h>
+#include <libxml/dict.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -115,10 +116,24 @@
xmlExpNewCtxt (int maxNodes,
xmlDictPtr dict);
+XMLPUBFUN int XMLCALL
+ xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt);
+XMLPUBFUN int XMLCALL
+ xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt);
+
/* Expressions are trees but the tree is opaque */
typedef struct _xmlExpNode xmlExpNode;
typedef xmlExpNode *xmlExpNodePtr;
+typedef enum {
+ XML_EXP_EMPTY = 0,
+ XML_EXP_FORBID = 1,
+ XML_EXP_ATOM = 2,
+ XML_EXP_SEQ = 3,
+ XML_EXP_OR = 4,
+ XML_EXP_COUNT = 5
+} xmlExpNodeType;
+
/*
* 2 core expressions shared by all for the empty language set
* and for the set with just the empty token
@@ -131,30 +146,45 @@
*/
XMLPUBFUN void XMLCALL
xmlExpFree (xmlExpCtxtPtr ctxt,
- xmlExpNodePtr exp);
+ xmlExpNodePtr expr);
XMLPUBFUN void XMLCALL
- xmlExpRef (xmlExpNodePtr exp);
+ xmlExpRef (xmlExpNodePtr expr);
+
+/*
+ * constructors can be either manual or from a string
+ */
+XMLPUBFUN xmlExpNodePtr XMLCALL
+ xmlExpParse (xmlExpCtxtPtr ctxt,
+ const char *expr);
+/*
+ * The really interesting APIs
+ */
XMLPUBFUN int XMLCALL
- xmlExpIsNillable(xmlExpNodePtr exp);
+ xmlExpIsNillable(xmlExpNodePtr expr);
+XMLPUBFUN int XMLCALL
+ xmlExpMaxToken (xmlExpNodePtr expr);
XMLPUBFUN int XMLCALL
xmlExpGetLanguage(xmlExpCtxtPtr ctxt,
- xmlExpNodePtr exp,
+ xmlExpNodePtr expr,
const xmlChar**list,
int len);
XMLPUBFUN int XMLCALL
xmlExpGetStart (xmlExpCtxtPtr ctxt,
- xmlExpNodePtr exp,
+ xmlExpNodePtr expr,
const xmlChar**list,
int len);
XMLPUBFUN xmlExpNodePtr XMLCALL
xmlExpStringDerive(xmlExpCtxtPtr ctxt,
- xmlExpNodePtr exp,
+ xmlExpNodePtr expr,
const xmlChar *str,
int len);
XMLPUBFUN int XMLCALL
xmlExpSubsume (xmlExpCtxtPtr ctxt,
- xmlExpNodePtr exp,
+ xmlExpNodePtr expr,
xmlExpNodePtr sub);
+XMLPUBFUN void XMLCALL
+ xmlExpDump (xmlBufferPtr buf,
+ xmlExpNodePtr exp);
#endif /* LIBXML_EXPR_ENABLED */
#ifdef __cplusplus
}
diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in
index f97aa35..24c3ca0 100644
--- a/include/libxml/xmlversion.h.in
+++ b/include/libxml/xmlversion.h.in
@@ -331,6 +331,15 @@
#endif
/**
+ * LIBXML_EXPR_ENABLED:
+ *
+ * Whether the formal expressions interfaces are compiled in
+ */
+#if @WITH_SCHEMAS@
+#define LIBXML_EXPR_ENABLED
+#endif
+
+/**
* LIBXML_SCHEMAS_ENABLED:
*
* Whether the Schemas validation interfaces are compiled in
diff --git a/testRegexp.c b/testRegexp.c
index 1e9f35b..fd09fa1 100644
--- a/testRegexp.c
+++ b/testRegexp.c
@@ -85,13 +85,121 @@
xmlRegFreeRegexp(comp);
}
+#ifdef LIBXML_EXPR_ENABLED
+static void
+runFileTest(xmlExpCtxtPtr ctxt, const char *filename) {
+ xmlExpNodePtr expr = NULL, sub;
+ FILE *input;
+ char expression[5000];
+ int len;
+
+ input = fopen(filename, "r");
+ if (input == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "Cannot open %s for reading\n", filename);
+ return;
+ }
+ while (fgets(expression, 4500, input) != NULL) {
+ len = strlen(expression);
+ len--;
+ while ((len >= 0) &&
+ ((expression[len] == '\n') || (expression[len] == '\t') ||
+ (expression[len] == '\r') || (expression[len] == ' '))) len--;
+ expression[len + 1] = 0;
+ if (len >= 0) {
+ if (expression[0] == '#')
+ continue;
+ if ((expression[0] == '=') && (expression[1] == '>')) {
+ char *str = &expression[2];
+
+ if (expr != NULL) {
+ xmlExpFree(ctxt, expr);
+ if (xmlExpCtxtNbNodes(ctxt) != 0)
+ printf(" Parse/free of Expression leaked %d\n",
+ xmlExpCtxtNbNodes(ctxt));
+ expr = NULL;
+ }
+ printf("Expression: %s\n", str) ;
+ expr = xmlExpParse(ctxt, str);
+ if (expr == NULL) {
+ printf(" parsing Failed\n");
+ break;
+ }
+ } else if (expr != NULL) {
+ int expect = -1;
+ int nodes1, nodes2;
+
+ if (expression[0] == '0')
+ expect = 0;
+ if (expression[0] == '1')
+ expect = 1;
+ printf("Subexp: %s", expression + 2) ;
+ nodes1 = xmlExpCtxtNbNodes(ctxt);
+ sub = xmlExpParse(ctxt, expression + 2);
+ if (sub == NULL) {
+ printf(" parsing Failed\n");
+ break;
+ } else {
+ int ret;
+
+ nodes2 = xmlExpCtxtNbNodes(ctxt);
+ ret = xmlExpSubsume(ctxt, expr, sub);
+
+ if ((expect == 1) && (ret == 1)) {
+ printf(" => accept, Ok\n");
+ } else if ((expect == 0) && (ret == 0)) {
+ printf(" => reject, Ok\n");
+ } else if ((expect == 1) && (ret == 0)) {
+ printf(" => reject, Failed\n");
+ } else if ((expect == 0) && (ret == 1)) {
+ printf(" => accept, Failed\n");
+ } else {
+ printf(" => fail internally\n");
+ }
+ if (xmlExpCtxtNbNodes(ctxt) > nodes2) {
+ printf(" Subsume leaked %d\n",
+ xmlExpCtxtNbNodes(ctxt) - nodes2);
+ nodes1 += xmlExpCtxtNbNodes(ctxt) - nodes2;
+ }
+ xmlExpFree(ctxt, sub);
+ if (xmlExpCtxtNbNodes(ctxt) > nodes1) {
+ printf(" Parse/free leaked %d\n",
+ xmlExpCtxtNbNodes(ctxt) - nodes1);
+ }
+ }
+
+ }
+ }
+ }
+ if (expr != NULL) {
+ xmlExpFree(ctxt, expr);
+ if (xmlExpCtxtNbNodes(ctxt) != 0)
+ printf(" Parse/free of Expression leaked %d\n",
+ xmlExpCtxtNbNodes(ctxt));
+ }
+ fclose(input);
+}
+#endif
static void usage(const char *name) {
- fprintf(stderr, "Usage: %s\n", name);
+ fprintf(stderr, "Usage: %s [flags]\n", name);
+ fprintf(stderr, "Testing tool for libxml2 string and pattern regexps\n");
+ fprintf(stderr, " --debug: switch on debugging\n");
+ fprintf(stderr, " --repeat: loop on the operation\n");
+#ifdef LIBXML_EXPR_ENABLED
+ fprintf(stderr, " --expr: test xmlExp and not xmlRegexp\n");
+#endif
+ fprintf(stderr, " --input filename: use the given filename for regexp\n");
+ fprintf(stderr, " --input filename: use the given filename for exp\n");
}
int main(int argc, char **argv) {
xmlRegexpPtr comp = NULL;
+#ifdef LIBXML_EXPR_ENABLED
+ xmlExpNodePtr expr = NULL;
+ int use_exp = 0;
+ xmlExpCtxtPtr ctxt = NULL;
+#endif
const char *pattern = NULL;
char *filename = NULL;
int i;
@@ -113,15 +221,32 @@
} else if ((!strcmp(argv[i], "-repeat")) ||
(!strcmp(argv[i], "--repeat"))) {
repeat++;
- } else if ((!strcmp(argv[i], "-i")) || (!strcmp(argv[i], "--input")))
+#ifdef LIBXML_EXPR_ENABLED
+ } else if ((!strcmp(argv[i], "-expr")) ||
+ (!strcmp(argv[i], "--expr"))) {
+ use_exp++;
+#endif
+ } else if ((!strcmp(argv[i], "-i")) || (!strcmp(argv[i], "-f")) ||
+ (!strcmp(argv[i], "--input")))
filename = argv[++i];
else {
fprintf(stderr, "Unknown option %s\n", argv[i]);
usage(argv[0]);
}
}
+
+#ifdef LIBXML_EXPR_ENABLED
+ if (use_exp)
+ ctxt = xmlExpNewCtxt(0, NULL);
+#endif
+
if (filename != NULL) {
- testRegexpFile(filename);
+#ifdef LIBXML_EXPR_ENABLED
+ if (use_exp)
+ runFileTest(ctxt, filename);
+ else
+#endif
+ testRegexpFile(filename);
} else {
for (i = 1; i < argc ; i++) {
if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
@@ -143,6 +268,13 @@
if (comp != NULL)
xmlRegFreeRegexp(comp);
}
+#ifdef LIBXML_EXPR_ENABLED
+ if (ctxt != NULL) {
+ printf("Ops: %d nodes, %d cons\n",
+ xmlExpCtxtNbNodes(ctxt), xmlExpCtxtNbCons(ctxt));
+ xmlExpFreeCtxt(ctxt);
+ }
+#endif
xmlCleanupParser();
xmlMemoryDump();
return(0);
diff --git a/valid.c b/valid.c
index a4a9b61..35c21ae 100644
--- a/valid.c
+++ b/valid.c
@@ -2716,7 +2716,7 @@
} else if (elem == NULL) {
return(0);
} else {
- xmlAttributePtr attrDecl;
+ xmlAttributePtr attrDecl = NULL;
xmlChar felem[50], fattr[50];
xmlChar *fullelemname, *fullattrname;
diff --git a/xmllint.c b/xmllint.c
index ca94c6c..65e17b3 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -2752,6 +2752,9 @@
#ifdef LIBXML_REGEXP_ENABLED
fprintf(stderr, "Regexps ");
#endif
+#ifdef LIBXML_EXPR_ENABLED
+ fprintf(stderr, "Expr ");
+#endif
#ifdef LIBXML_AUTOMATA_ENABLED
fprintf(stderr, "Automata ");
#endif
diff --git a/xmlregexp.c b/xmlregexp.c
index 7214cc2..b4953e0 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -5491,15 +5491,6 @@
* Formal Expression handling code *
* *
************************************************************************/
-static void xmlExpDump(xmlBufferPtr buf, xmlExpNodePtr exp, int glob);
-#define PRINT_EXP(exp) { \
- xmlBufferPtr xmlExpBuf; \
- xmlExpBuf = xmlBufferCreate(); \
- xmlExpDump(xmlExpBuf, exp, 0); \
- xmlBufferWriteChar(xmlExpBuf, "\n"); \
- xmlBufferDump(stdout, xmlExpBuf); \
- xmlBufferFree(xmlExpBuf); \
-}
/************************************************************************
* *
* Expression handling context *
@@ -5515,7 +5506,6 @@
const char *expr;
const char *cur;
int nb_cons;
- int nb_del;
int tabSize;
};
@@ -5583,14 +5573,22 @@
* Structure associated to an expression node *
* *
************************************************************************/
-typedef enum {
- XML_EXP_EMPTY = 0,
- XML_EXP_FORBID = 1,
- XML_EXP_ATOM = 2,
- XML_EXP_SEQ = 3,
- XML_EXP_OR = 4,
- XML_EXP_COUNT = 5
-} xmlExpNodeType;
+#define MAX_NODES 10000
+
+/* #define DEBUG_DERIV */
+
+/*
+ * TODO:
+ * - Wildcards
+ * - public API for creation
+ *
+ * Started
+ * - regression testing
+ *
+ * Done
+ * - split into module and test tool
+ * - memleaks
+ */
typedef enum {
XML_EXP_NILABLE = (1 << 0)
@@ -5993,7 +5991,6 @@
xmlExpFree(ctxt, exp->exp_left);
}
xmlFree(exp);
- ctxt->nb_del++;
ctxt->nb_nodes--;
}
}
@@ -6877,6 +6874,326 @@
xmlExpFree(ctxt, tmp);
return(0);
}
+
+/************************************************************************
+ * *
+ * Parsing expression *
+ * *
+ ************************************************************************/
+
+static xmlExpNodePtr xmlExpParseExpr(xmlExpCtxtPtr ctxt);
+
+#undef CUR
+#define CUR (*ctxt->cur)
+#undef NEXT
+#define NEXT ctxt->cur++;
+#undef IS_BLANK
+#define IS_BLANK(c) ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))
+#define SKIP_BLANKS while (IS_BLANK(*ctxt->cur)) ctxt->cur++;
+
+static int
+xmlExpParseNumber(xmlExpCtxtPtr ctxt) {
+ int ret = 0;
+
+ SKIP_BLANKS
+ if (CUR == '*') {
+ NEXT
+ return(-1);
+ }
+ if ((CUR < '0') || (CUR > '9'))
+ return(-1);
+ while ((CUR >= '0') && (CUR <= '9')) {
+ ret = ret * 10 + (CUR - '0');
+ NEXT
+ }
+ return(ret);
+}
+
+static xmlExpNodePtr
+xmlExpParseOr(xmlExpCtxtPtr ctxt) {
+ const char *base;
+ xmlExpNodePtr ret;
+ const xmlChar *val;
+
+ SKIP_BLANKS
+ base = ctxt->cur;
+ if (*ctxt->cur == '(') {
+ NEXT
+ ret = xmlExpParseExpr(ctxt);
+ SKIP_BLANKS
+ if (*ctxt->cur != ')') {
+ fprintf(stderr, "unbalanced '(' : %s\n", base);
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ NEXT;
+ SKIP_BLANKS
+ goto parse_quantifier;
+ }
+ while ((CUR != 0) && (!(IS_BLANK(CUR))) && (CUR != '(') &&
+ (CUR != ')') && (CUR != '|') && (CUR != ',') && (CUR != '{') &&
+ (CUR != '*') && (CUR != '+') && (CUR != '?') && (CUR != '}'))
+ NEXT;
+ val = xmlDictLookup(ctxt->dict, BAD_CAST base, ctxt->cur - base);
+ if (val == NULL)
+ return(NULL);
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, val, 0, 0);
+ if (ret == NULL)
+ return(NULL);
+ SKIP_BLANKS
+parse_quantifier:
+ if (CUR == '{') {
+ int min, max;
+
+ NEXT
+ min = xmlExpParseNumber(ctxt);
+ if (min < 0) {
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ SKIP_BLANKS
+ if (CUR == ',') {
+ NEXT
+ max = xmlExpParseNumber(ctxt);
+ SKIP_BLANKS
+ } else
+ max = min;
+ if (CUR != '}') {
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ NEXT
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
+ min, max);
+ SKIP_BLANKS
+ } else if (CUR == '?') {
+ NEXT
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
+ 0, 1);
+ SKIP_BLANKS
+ } else if (CUR == '+') {
+ NEXT
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
+ 1, -1);
+ SKIP_BLANKS
+ } else if (CUR == '*') {
+ NEXT
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
+ 0, -1);
+ SKIP_BLANKS
+ }
+ return(ret);
+}
+
+
+static xmlExpNodePtr
+xmlExpParseSeq(xmlExpCtxtPtr ctxt) {
+ xmlExpNodePtr ret, right;
+
+ ret = xmlExpParseOr(ctxt);
+ SKIP_BLANKS
+ while (CUR == '|') {
+ NEXT
+ right = xmlExpParseOr(ctxt);
+ if (right == NULL) {
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, right, NULL, 0, 0);
+ if (ret == NULL)
+ return(NULL);
+ }
+ return(ret);
+}
+
+static xmlExpNodePtr
+xmlExpParseExpr(xmlExpCtxtPtr ctxt) {
+ xmlExpNodePtr ret, right;
+
+ ret = xmlExpParseSeq(ctxt);
+ SKIP_BLANKS
+ while (CUR == ',') {
+ NEXT
+ right = xmlExpParseSeq(ctxt);
+ if (right == NULL) {
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, right, NULL, 0, 0);
+ if (ret == NULL)
+ return(NULL);
+ }
+ return(ret);
+}
+
+/**
+ * xmlExpParse:
+ * @ctxt: the expressions context
+ * @expr: the 0 terminated string
+ *
+ * Minimal parser for regexps, it understand the following constructs
+ * - string terminals
+ * - choice operator |
+ * - sequence operator ,
+ * - subexpressions (...)
+ * - usual cardinality operators + * and ?
+ * - finite sequences { min, max }
+ * - infinite sequences { min, * }
+ * There is minimal checkings made especially no checking on strings values
+ *
+ * Returns a new expression or NULL in case of failure
+ */
+xmlExpNodePtr
+xmlExpParse(xmlExpCtxtPtr ctxt, const char *expr) {
+ xmlExpNodePtr ret;
+
+ ctxt->expr = expr;
+ ctxt->cur = expr;
+
+ ret = xmlExpParseExpr(ctxt);
+ SKIP_BLANKS
+ if (*ctxt->cur != 0) {
+ xmlExpFree(ctxt, ret);
+ return(NULL);
+ }
+ return(ret);
+}
+
+static void
+xmlExpDumpInt(xmlBufferPtr buf, xmlExpNodePtr expr, int glob) {
+ xmlExpNodePtr c;
+
+ if (expr == NULL) return;
+ if (glob) xmlBufferWriteChar(buf, "(");
+ switch (expr->type) {
+ case XML_EXP_EMPTY:
+ xmlBufferWriteChar(buf, "empty");
+ break;
+ case XML_EXP_FORBID:
+ xmlBufferWriteChar(buf, "forbidden");
+ break;
+ case XML_EXP_ATOM:
+ xmlBufferWriteCHAR(buf, expr->exp_str);
+ break;
+ case XML_EXP_SEQ:
+ c = expr->exp_left;
+ if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
+ xmlExpDumpInt(buf, c, 1);
+ else
+ xmlExpDumpInt(buf, c, 0);
+ xmlBufferWriteChar(buf, " , ");
+ c = expr->exp_right;
+ if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
+ xmlExpDumpInt(buf, c, 1);
+ else
+ xmlExpDumpInt(buf, c, 0);
+ break;
+ case XML_EXP_OR:
+ c = expr->exp_left;
+ if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
+ xmlExpDumpInt(buf, c, 1);
+ else
+ xmlExpDumpInt(buf, c, 0);
+ xmlBufferWriteChar(buf, " | ");
+ c = expr->exp_right;
+ if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
+ xmlExpDumpInt(buf, c, 1);
+ else
+ xmlExpDumpInt(buf, c, 0);
+ break;
+ case XML_EXP_COUNT: {
+ char rep[40];
+
+ c = expr->exp_left;
+ if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
+ xmlExpDumpInt(buf, c, 1);
+ else
+ xmlExpDumpInt(buf, c, 0);
+ if ((expr->exp_min == 0) && (expr->exp_max == 1)) {
+ rep[0] = '?';
+ rep[1] = 0;
+ } else if ((expr->exp_min == 0) && (expr->exp_max == -1)) {
+ rep[0] = '*';
+ rep[1] = 0;
+ } else if ((expr->exp_min == 1) && (expr->exp_max == -1)) {
+ rep[0] = '+';
+ rep[1] = 0;
+ } else if (expr->exp_max == expr->exp_min) {
+ snprintf(rep, 39, "{%d}", expr->exp_min);
+ } else if (expr->exp_max < 0) {
+ snprintf(rep, 39, "{%d,inf}", expr->exp_min);
+ } else {
+ snprintf(rep, 39, "{%d,%d}", expr->exp_min, expr->exp_max);
+ }
+ rep[39] = 0;
+ xmlBufferWriteChar(buf, rep);
+ break;
+ }
+ default:
+ fprintf(stderr, "Error in tree\n");
+ }
+ if (glob)
+ xmlBufferWriteChar(buf, ")");
+}
+/**
+ * xmlExpDump:
+ * @buf: a buffer to receive the output
+ * @expr: the compiled expression
+ *
+ * Serialize the expression as compiled to the buffer
+ */
+void
+xmlExpDump(xmlBufferPtr buf, xmlExpNodePtr exp) {
+ if ((buf == NULL) || (exp == NULL))
+ return;
+ xmlExpDumpInt(buf, exp, 0);
+}
+
+/**
+ * xmlExpMaxToken:
+ * @expr: a compiled expression
+ *
+ * Indicate the maximum number of input a expression can accept
+ *
+ * Returns the maximum length or -1 in case of error
+ */
+int
+xmlExpMaxToken(xmlExpNodePtr expr) {
+ if (expr == NULL)
+ return(-1);
+ return(expr->c_max);
+}
+
+/**
+ * xmlExpCtxtNbNodes:
+ * @ctxt: an expression context
+ *
+ * Debugging facility provides the number of allocated nodes at a that point
+ *
+ * Returns the number of nodes in use or -1 in case of error
+ */
+int
+xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(-1);
+ return(ctxt->nb_nodes);
+}
+
+/**
+ * xmlExpCtxtNbCons:
+ * @ctxt: an expression context
+ *
+ * Debugging facility provides the number of allocated nodes over lifetime
+ *
+ * Returns the number of nodes ever allocated or -1 in case of error
+ */
+int
+xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(-1);
+ return(ctxt->nb_cons);
+}
+
#endif /* LIBXML_EXPR_ENABLED */
#define bottom_xmlregexp
#include "elfgcchack.h"