blob: ff9c0fc81cd18f29316fabd212b8a6f203fcc8ff [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * testRegexp.c: simple module for testing regular expressions
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
9#include <string.h>
10#include "libxml.h"
11#ifdef LIBXML_REGEXP_ENABLED
12#include <libxml/tree.h>
13#include <libxml/xmlregexp.h>
14
Daniel Veillard24505b02005-07-28 23:49:35 +000015static int repeat = 0;
16static int debug = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +000017
18static void testRegexp(xmlRegexpPtr comp, const char *value) {
19 int ret;
20
21 ret = xmlRegexpExec(comp, (const xmlChar *) value);
22 if (ret == 1)
23 printf("%s: Ok\n", value);
24 else if (ret == 0)
25 printf("%s: Fail\n", value);
26 else
27 printf("%s: Error: %d\n", value, ret);
28 if (repeat) {
29 int j;
30 for (j = 0;j < 999999;j++)
31 xmlRegexpExec(comp, (const xmlChar *) value);
32 }
33}
34
35static void
36testRegexpFile(const char *filename) {
37 xmlRegexpPtr comp = NULL;
38 FILE *input;
39 char expression[5000];
40 int len;
41
42 input = fopen(filename, "r");
43 if (input == NULL) {
44 xmlGenericError(xmlGenericErrorContext,
45 "Cannot open %s for reading\n", filename);
46 return;
47 }
48 while (fgets(expression, 4500, input) != NULL) {
49 len = strlen(expression);
50 len--;
51 while ((len >= 0) &&
52 ((expression[len] == '\n') || (expression[len] == '\t') ||
53 (expression[len] == '\r') || (expression[len] == ' '))) len--;
54 expression[len + 1] = 0;
55 if (len >= 0) {
56 if (expression[0] == '#')
57 continue;
58 if ((expression[0] == '=') && (expression[1] == '>')) {
59 char *pattern = &expression[2];
60
61 if (comp != NULL) {
62 xmlRegFreeRegexp(comp);
63 comp = NULL;
64 }
65 printf("Regexp: %s\n", pattern) ;
66 comp = xmlRegexpCompile((const xmlChar *) pattern);
67 if (comp == NULL) {
68 printf(" failed to compile\n");
69 break;
70 }
71 } else if (comp == NULL) {
72 printf("Regexp: %s\n", expression) ;
73 comp = xmlRegexpCompile((const xmlChar *) expression);
74 if (comp == NULL) {
75 printf(" failed to compile\n");
76 break;
77 }
78 } else if (comp != NULL) {
79 testRegexp(comp, expression);
80 }
81 }
82 }
83 fclose(input);
84 if (comp != NULL)
85 xmlRegFreeRegexp(comp);
86}
87
Daniel Veillard465a0002005-08-22 12:07:04 +000088#ifdef LIBXML_EXPR_ENABLED
89static void
90runFileTest(xmlExpCtxtPtr ctxt, const char *filename) {
91 xmlExpNodePtr expr = NULL, sub;
92 FILE *input;
93 char expression[5000];
94 int len;
95
96 input = fopen(filename, "r");
97 if (input == NULL) {
98 xmlGenericError(xmlGenericErrorContext,
99 "Cannot open %s for reading\n", filename);
100 return;
101 }
102 while (fgets(expression, 4500, input) != NULL) {
103 len = strlen(expression);
104 len--;
105 while ((len >= 0) &&
106 ((expression[len] == '\n') || (expression[len] == '\t') ||
107 (expression[len] == '\r') || (expression[len] == ' '))) len--;
108 expression[len + 1] = 0;
109 if (len >= 0) {
110 if (expression[0] == '#')
111 continue;
112 if ((expression[0] == '=') && (expression[1] == '>')) {
113 char *str = &expression[2];
114
115 if (expr != NULL) {
116 xmlExpFree(ctxt, expr);
117 if (xmlExpCtxtNbNodes(ctxt) != 0)
118 printf(" Parse/free of Expression leaked %d\n",
119 xmlExpCtxtNbNodes(ctxt));
120 expr = NULL;
121 }
122 printf("Expression: %s\n", str) ;
123 expr = xmlExpParse(ctxt, str);
124 if (expr == NULL) {
125 printf(" parsing Failed\n");
126 break;
127 }
128 } else if (expr != NULL) {
129 int expect = -1;
130 int nodes1, nodes2;
131
132 if (expression[0] == '0')
133 expect = 0;
134 if (expression[0] == '1')
135 expect = 1;
136 printf("Subexp: %s", expression + 2) ;
137 nodes1 = xmlExpCtxtNbNodes(ctxt);
138 sub = xmlExpParse(ctxt, expression + 2);
139 if (sub == NULL) {
140 printf(" parsing Failed\n");
141 break;
142 } else {
143 int ret;
144
145 nodes2 = xmlExpCtxtNbNodes(ctxt);
146 ret = xmlExpSubsume(ctxt, expr, sub);
147
148 if ((expect == 1) && (ret == 1)) {
149 printf(" => accept, Ok\n");
150 } else if ((expect == 0) && (ret == 0)) {
151 printf(" => reject, Ok\n");
152 } else if ((expect == 1) && (ret == 0)) {
153 printf(" => reject, Failed\n");
154 } else if ((expect == 0) && (ret == 1)) {
155 printf(" => accept, Failed\n");
156 } else {
157 printf(" => fail internally\n");
158 }
159 if (xmlExpCtxtNbNodes(ctxt) > nodes2) {
160 printf(" Subsume leaked %d\n",
161 xmlExpCtxtNbNodes(ctxt) - nodes2);
162 nodes1 += xmlExpCtxtNbNodes(ctxt) - nodes2;
163 }
164 xmlExpFree(ctxt, sub);
165 if (xmlExpCtxtNbNodes(ctxt) > nodes1) {
166 printf(" Parse/free leaked %d\n",
167 xmlExpCtxtNbNodes(ctxt) - nodes1);
168 }
169 }
170
171 }
172 }
173 }
174 if (expr != NULL) {
175 xmlExpFree(ctxt, expr);
176 if (xmlExpCtxtNbNodes(ctxt) != 0)
177 printf(" Parse/free of Expression leaked %d\n",
178 xmlExpCtxtNbNodes(ctxt));
179 }
180 fclose(input);
181}
Daniel Veillard0090bd52005-08-22 14:43:43 +0000182
183static void
184testReduce(xmlExpCtxtPtr ctxt, xmlExpNodePtr expr, const char *tst) {
185 xmlBufferPtr xmlExpBuf;
186 xmlExpNodePtr sub, deriv;
187 xmlExpBuf = xmlBufferCreate();
188
189 sub = xmlExpParse(ctxt, tst);
190 if (sub == NULL) {
191 printf("Subset %s failed to parse\n", tst);
192 return;
193 }
Daniel Veillarda4181222005-08-22 15:50:57 +0000194 xmlExpDump(xmlExpBuf, sub);
Daniel Veillard0090bd52005-08-22 14:43:43 +0000195 printf("Subset parsed as: %s\n",
196 (const char *) xmlBufferContent(xmlExpBuf));
197 deriv = xmlExpExpDerive(ctxt, expr, sub);
198 if (deriv == NULL) {
199 printf("Derivation led to an internal error, report this !\n");
200 return;
201 } else {
202 xmlBufferEmpty(xmlExpBuf);
203 xmlExpDump(xmlExpBuf, deriv);
204 if (xmlExpIsNillable(deriv))
205 printf("Resulting nillable derivation: %s\n",
206 (const char *) xmlBufferContent(xmlExpBuf));
207 else
208 printf("Resulting derivation: %s\n",
209 (const char *) xmlBufferContent(xmlExpBuf));
210 xmlExpFree(ctxt, deriv);
211 }
212 xmlExpFree(ctxt, sub);
213}
214
215static void
216exprDebug(xmlExpCtxtPtr ctxt, xmlExpNodePtr expr) {
217 xmlBufferPtr xmlExpBuf;
218 xmlExpNodePtr deriv;
219 const char *list[40];
220 int ret;
221
222 xmlExpBuf = xmlBufferCreate();
223
224 if (expr == NULL) {
225 printf("Failed to parse\n");
226 return;
227 }
228 xmlExpDump(xmlExpBuf, expr);
229 printf("Parsed as: %s\n", (const char *) xmlBufferContent(xmlExpBuf));
230 printf("Max token input = %d\n", xmlExpMaxToken(expr));
231 if (xmlExpIsNillable(expr) == 1)
232 printf("Is nillable\n");
233 ret = xmlExpGetLanguage(ctxt, expr, (const xmlChar **) &list[0], 40);
234 if (ret < 0)
235 printf("Failed to get list: %d\n", ret);
236 else {
237 int i;
238
239 printf("Language has %d strings, testing string derivations\n", ret);
240 for (i = 0;i < ret;i++) {
241 deriv = xmlExpStringDerive(ctxt, expr, BAD_CAST list[i], -1);
242 if (deriv == NULL) {
243 printf(" %s -> derivation failed\n", list[i]);
244 } else {
245 xmlBufferEmpty(xmlExpBuf);
246 xmlExpDump(xmlExpBuf, deriv);
247 printf(" %s -> %s\n", list[i],
248 (const char *) xmlBufferContent(xmlExpBuf));
249 }
250 xmlExpFree(ctxt, deriv);
251 }
252 }
253 xmlBufferFree(xmlExpBuf);
254}
Daniel Veillard465a0002005-08-22 12:07:04 +0000255#endif
Daniel Veillard4255d502002-04-16 15:50:10 +0000256
257static void usage(const char *name) {
Daniel Veillard465a0002005-08-22 12:07:04 +0000258 fprintf(stderr, "Usage: %s [flags]\n", name);
259 fprintf(stderr, "Testing tool for libxml2 string and pattern regexps\n");
260 fprintf(stderr, " --debug: switch on debugging\n");
261 fprintf(stderr, " --repeat: loop on the operation\n");
262#ifdef LIBXML_EXPR_ENABLED
263 fprintf(stderr, " --expr: test xmlExp and not xmlRegexp\n");
264#endif
265 fprintf(stderr, " --input filename: use the given filename for regexp\n");
266 fprintf(stderr, " --input filename: use the given filename for exp\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000267}
268
269int main(int argc, char **argv) {
270 xmlRegexpPtr comp = NULL;
Daniel Veillard465a0002005-08-22 12:07:04 +0000271#ifdef LIBXML_EXPR_ENABLED
272 xmlExpNodePtr expr = NULL;
273 int use_exp = 0;
274 xmlExpCtxtPtr ctxt = NULL;
275#endif
Daniel Veillard4255d502002-04-16 15:50:10 +0000276 const char *pattern = NULL;
277 char *filename = NULL;
278 int i;
279
280 xmlInitMemory();
281
282 if (argc <= 1) {
283 usage(argv[0]);
284 return(1);
285 }
286 for (i = 1; i < argc ; i++) {
287 if (!strcmp(argv[i], "-"))
288 break;
289
290 if (argv[i][0] != '-')
291 continue;
292 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) {
293 debug++;
294 } else if ((!strcmp(argv[i], "-repeat")) ||
295 (!strcmp(argv[i], "--repeat"))) {
296 repeat++;
Daniel Veillard465a0002005-08-22 12:07:04 +0000297#ifdef LIBXML_EXPR_ENABLED
298 } else if ((!strcmp(argv[i], "-expr")) ||
299 (!strcmp(argv[i], "--expr"))) {
300 use_exp++;
301#endif
302 } else if ((!strcmp(argv[i], "-i")) || (!strcmp(argv[i], "-f")) ||
303 (!strcmp(argv[i], "--input")))
Daniel Veillard4255d502002-04-16 15:50:10 +0000304 filename = argv[++i];
305 else {
306 fprintf(stderr, "Unknown option %s\n", argv[i]);
307 usage(argv[0]);
308 }
309 }
Daniel Veillard465a0002005-08-22 12:07:04 +0000310
311#ifdef LIBXML_EXPR_ENABLED
312 if (use_exp)
313 ctxt = xmlExpNewCtxt(0, NULL);
314#endif
315
Daniel Veillard4255d502002-04-16 15:50:10 +0000316 if (filename != NULL) {
Daniel Veillard465a0002005-08-22 12:07:04 +0000317#ifdef LIBXML_EXPR_ENABLED
318 if (use_exp)
319 runFileTest(ctxt, filename);
320 else
321#endif
322 testRegexpFile(filename);
Daniel Veillard4255d502002-04-16 15:50:10 +0000323 } else {
Daniel Veillard0090bd52005-08-22 14:43:43 +0000324#ifdef LIBXML_EXPR_ENABLED
325 if (use_exp) {
326 for (i = 1; i < argc ; i++) {
327 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
328 if (pattern == NULL) {
329 pattern = argv[i];
330 printf("Testing expr %s:\n", pattern);
331 expr = xmlExpParse(ctxt, pattern);
332 if (expr == NULL) {
333 printf(" failed to compile\n");
334 break;
335 }
336 if (debug) {
337 exprDebug(ctxt, expr);
338 }
339 } else {
340 testReduce(ctxt, expr, argv[i]);
Daniel Veillard4255d502002-04-16 15:50:10 +0000341 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000342 }
343 }
Daniel Veillard0090bd52005-08-22 14:43:43 +0000344 if (expr != NULL)
345 xmlExpFree(ctxt, expr);
346 } else
347#endif
348 {
349 for (i = 1; i < argc ; i++) {
350 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
351 if (pattern == NULL) {
352 pattern = argv[i];
353 printf("Testing %s:\n", pattern);
354 comp = xmlRegexpCompile((const xmlChar *) pattern);
355 if (comp == NULL) {
356 printf(" failed to compile\n");
357 break;
358 }
359 if (debug)
360 xmlRegexpPrint(stdout, comp);
361 } else {
362 testRegexp(comp, argv[i]);
363 }
364 }
365 }
366 if (comp != NULL)
367 xmlRegFreeRegexp(comp);
368 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000369 }
Daniel Veillard465a0002005-08-22 12:07:04 +0000370#ifdef LIBXML_EXPR_ENABLED
371 if (ctxt != NULL) {
372 printf("Ops: %d nodes, %d cons\n",
373 xmlExpCtxtNbNodes(ctxt), xmlExpCtxtNbCons(ctxt));
374 xmlExpFreeCtxt(ctxt);
375 }
376#endif
Daniel Veillard4255d502002-04-16 15:50:10 +0000377 xmlCleanupParser();
Daniel Veillard99c394d2005-07-14 12:58:49 +0000378 xmlMemoryDump();
Daniel Veillard4255d502002-04-16 15:50:10 +0000379 return(0);
380}
381
382#else
383#include <stdio.h>
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000384int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000385 printf("%s : Regexp support not compiled in\n", argv[0]);
386 return(0);
387}
388#endif /* LIBXML_REGEXP_ENABLED */