blob: 332146a28642eefba241b3f2a5c0201c5a7b0554 [file] [log] [blame]
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001/*
2 * xmllint.c : a small tester program for XML input.
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel.Veillard@w3.org
7 */
8
9#ifdef WIN32
10#include "win32config.h"
11#else
12#include "config.h"
13#endif
14
15#include <stdio.h>
16#include <string.h>
17#include <stdio.h>
18#include <stdarg.h>
Daniel Veillard48b2f892001-02-25 16:11:03 +000019#include <sys/time.h>
20
Daniel Veillardce8b83b2000-04-05 18:38:42 +000021
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_SYS_STAT_H
26#include <sys/stat.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
31#ifdef HAVE_UNISTD_H
32#include <unistd.h>
33#endif
Daniel Veillard46e370e2000-07-21 20:32:03 +000034#ifdef HAVE_SYS_MMAN_H
35#include <sys/mman.h>
Daniel Veillard87b95392000-08-12 21:12:04 +000036/* seems needed for Solaris */
37#ifndef MAP_FAILED
38#define MAP_FAILED ((void *) -1)
39#endif
Daniel Veillard46e370e2000-07-21 20:32:03 +000040#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +000041#ifdef HAVE_STDLIB_H
42#include <stdlib.h>
43#endif
44#ifdef HAVE_LIBREADLINE
45#include <readline/readline.h>
46#ifdef HAVE_LIBHISTORY
47#include <readline/history.h>
48#endif
49#endif
50
51#include <libxml/xmlmemory.h>
52#include <libxml/parser.h>
53#include <libxml/parserInternals.h>
54#include <libxml/HTMLparser.h>
55#include <libxml/HTMLtree.h>
56#include <libxml/tree.h>
57#include <libxml/xpath.h>
58#include <libxml/debugXML.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000059#include <libxml/xmlerror.h>
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000060#ifdef LIBXML_XINCLUDE_ENABLED
61#include <libxml/xinclude.h>
62#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +000063
64#ifdef LIBXML_DEBUG_ENABLED
65static int debug = 0;
66static int shell = 0;
67static int debugent = 0;
68#endif
69static int copy = 0;
70static int recovery = 0;
71static int noent = 0;
72static int noout = 0;
73static int nowrap = 0;
74static int valid = 0;
75static int postvalid = 0;
Daniel Veillardcd429612000-10-11 15:57:05 +000076static char * dtdvalid = NULL;
Daniel Veillardce8b83b2000-04-05 18:38:42 +000077static int repeat = 0;
78static int insert = 0;
79static int compress = 0;
80static int html = 0;
81static int htmlout = 0;
82static int push = 0;
Daniel Veillard46e370e2000-07-21 20:32:03 +000083#ifdef HAVE_SYS_MMAN_H
84static int memory = 0;
85#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +000086static int noblanks = 0;
Daniel Veillard5e873c42000-04-12 13:27:38 +000087static int testIO = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +000088static char *encoding = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000089#ifdef LIBXML_XINCLUDE_ENABLED
90static int xinclude = 0;
91#endif
Daniel Veillardf7cd4812001-02-23 18:44:52 +000092static int progresult = 0;
Daniel Veillard48b2f892001-02-25 16:11:03 +000093static int timing = 0;
94static struct timeval begin, end;
Daniel Veillardce8b83b2000-04-05 18:38:42 +000095
Daniel Veillardce6e98d2000-11-25 09:54:49 +000096
97#ifdef VMS
98extern int xmlDoValidityCheckingDefaultVal;
99#define xmlDoValidityCheckingDefaultValue xmlDoValidityCheckingDefaultVal
100#else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000101extern int xmlDoValidityCheckingDefaultValue;
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000102#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000103extern int xmlGetWarningsDefaultValue;
104
105/************************************************************************
106 * *
107 * HTML ouput *
108 * *
109 ************************************************************************/
110char buffer[50000];
111
112void
113xmlHTMLEncodeSend(void) {
114 char *result;
115
116 result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer);
117 if (result) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000118 xmlGenericError(xmlGenericErrorContext, "%s", result);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000119 xmlFree(result);
120 }
121 buffer[0] = 0;
122}
123
124/**
125 * xmlHTMLPrintFileInfo:
126 * @input: an xmlParserInputPtr input
127 *
128 * Displays the associated file and line informations for the current input
129 */
130
131void
132xmlHTMLPrintFileInfo(xmlParserInputPtr input) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000133 xmlGenericError(xmlGenericErrorContext, "<p>");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000134 if (input != NULL) {
135 if (input->filename) {
136 sprintf(&buffer[strlen(buffer)], "%s:%d: ", input->filename,
137 input->line);
138 } else {
139 sprintf(&buffer[strlen(buffer)], "Entity: line %d: ", input->line);
140 }
141 }
142 xmlHTMLEncodeSend();
143}
144
145/**
146 * xmlHTMLPrintFileContext:
147 * @input: an xmlParserInputPtr input
148 *
149 * Displays current context within the input content for error tracking
150 */
151
152void
153xmlHTMLPrintFileContext(xmlParserInputPtr input) {
154 const xmlChar *cur, *base;
155 int n;
156
157 if (input == NULL) return;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000158 xmlGenericError(xmlGenericErrorContext, "<pre>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000159 cur = input->cur;
160 base = input->base;
161 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
162 cur--;
163 }
164 n = 0;
165 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
166 cur--;
167 if ((*cur == '\n') || (*cur == '\r')) cur++;
168 base = cur;
169 n = 0;
170 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
171 sprintf(&buffer[strlen(buffer)], "%c", (unsigned char) *cur++);
172 n++;
173 }
174 sprintf(&buffer[strlen(buffer)], "\n");
175 cur = input->cur;
176 while ((*cur == '\n') || (*cur == '\r'))
177 cur--;
178 n = 0;
179 while ((cur != base) && (n++ < 80)) {
180 sprintf(&buffer[strlen(buffer)], " ");
181 base++;
182 }
183 sprintf(&buffer[strlen(buffer)],"^\n");
184 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000185 xmlGenericError(xmlGenericErrorContext, "</pre>");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000186}
187
188/**
189 * xmlHTMLError:
190 * @ctx: an XML parser context
191 * @msg: the message to display/transmit
192 * @...: extra parameters for the message display
193 *
194 * Display and format an error messages, gives file, line, position and
195 * extra parameters.
196 */
197void
198xmlHTMLError(void *ctx, const char *msg, ...)
199{
200 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
201 xmlParserInputPtr input;
202 xmlParserInputPtr cur = NULL;
203 va_list args;
204
205 buffer[0] = 0;
206 input = ctxt->input;
207 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
208 cur = input;
209 input = ctxt->inputTab[ctxt->inputNr - 2];
210 }
211
212 xmlHTMLPrintFileInfo(input);
213
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000214 xmlGenericError(xmlGenericErrorContext, "<b>error</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000215 va_start(args, msg);
216 vsprintf(&buffer[strlen(buffer)], msg, args);
217 va_end(args);
218 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000219 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000220
221 xmlHTMLPrintFileContext(input);
222 xmlHTMLEncodeSend();
223}
224
225/**
226 * xmlHTMLWarning:
227 * @ctx: an XML parser context
228 * @msg: the message to display/transmit
229 * @...: extra parameters for the message display
230 *
231 * Display and format a warning messages, gives file, line, position and
232 * extra parameters.
233 */
234void
235xmlHTMLWarning(void *ctx, const char *msg, ...)
236{
237 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
238 xmlParserInputPtr input;
239 xmlParserInputPtr cur = NULL;
240 va_list args;
241
242 buffer[0] = 0;
243 input = ctxt->input;
244 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
245 cur = input;
246 input = ctxt->inputTab[ctxt->inputNr - 2];
247 }
248
249
250 xmlHTMLPrintFileInfo(input);
251
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000252 xmlGenericError(xmlGenericErrorContext, "<b>warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000253 va_start(args, msg);
254 vsprintf(&buffer[strlen(buffer)], msg, args);
255 va_end(args);
256 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000257 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000258
259 xmlHTMLPrintFileContext(input);
260 xmlHTMLEncodeSend();
261}
262
263/**
264 * xmlHTMLValidityError:
265 * @ctx: an XML parser context
266 * @msg: the message to display/transmit
267 * @...: extra parameters for the message display
268 *
269 * Display and format an validity error messages, gives file,
270 * line, position and extra parameters.
271 */
272void
273xmlHTMLValidityError(void *ctx, const char *msg, ...)
274{
275 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
276 xmlParserInputPtr input;
277 va_list args;
278
279 buffer[0] = 0;
280 input = ctxt->input;
281 if ((input->filename == NULL) && (ctxt->inputNr > 1))
282 input = ctxt->inputTab[ctxt->inputNr - 2];
283
284 xmlHTMLPrintFileInfo(input);
285
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000286 xmlGenericError(xmlGenericErrorContext, "<b>validity error</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000287 va_start(args, msg);
288 vsprintf(&buffer[strlen(buffer)], msg, args);
289 va_end(args);
290 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000291 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000292
293 xmlHTMLPrintFileContext(input);
294 xmlHTMLEncodeSend();
295}
296
297/**
298 * xmlHTMLValidityWarning:
299 * @ctx: an XML parser context
300 * @msg: the message to display/transmit
301 * @...: extra parameters for the message display
302 *
303 * Display and format a validity warning messages, gives file, line,
304 * position and extra parameters.
305 */
306void
307xmlHTMLValidityWarning(void *ctx, const char *msg, ...)
308{
309 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
310 xmlParserInputPtr input;
311 va_list args;
312
313 buffer[0] = 0;
314 input = ctxt->input;
315 if ((input->filename == NULL) && (ctxt->inputNr > 1))
316 input = ctxt->inputTab[ctxt->inputNr - 2];
317
318 xmlHTMLPrintFileInfo(input);
319
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000320 xmlGenericError(xmlGenericErrorContext, "<b>validity warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000321 va_start(args, msg);
322 vsprintf(&buffer[strlen(buffer)], msg, args);
323 va_end(args);
324 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000325 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000326
327 xmlHTMLPrintFileContext(input);
328 xmlHTMLEncodeSend();
329}
330
331/************************************************************************
332 * *
333 * Shell Interface *
334 * *
335 ************************************************************************/
336/**
337 * xmlShellReadline:
338 * @prompt: the prompt value
339 *
340 * Read a string
341 *
342 * Returns a pointer to it or NULL on EOF the caller is expected to
343 * free the returned string.
344 */
345char *
346xmlShellReadline(char *prompt) {
347#ifdef HAVE_LIBREADLINE
348 char *line_read;
349
350 /* Get a line from the user. */
351 line_read = readline (prompt);
352
353 /* If the line has any text in it, save it on the history. */
354 if (line_read && *line_read)
355 add_history (line_read);
356
357 return (line_read);
358#else
359 char line_read[501];
360
361 if (prompt != NULL)
362 fprintf(stdout, "%s", prompt);
363 if (!fgets(line_read, 500, stdin))
364 return(NULL);
365 line_read[500] = 0;
366 return(strdup(line_read));
367#endif
368}
369
370/************************************************************************
371 * *
Daniel Veillard5e873c42000-04-12 13:27:38 +0000372 * I/O Interfaces *
373 * *
374 ************************************************************************/
375
376int myRead(FILE *f, char * buffer, int len) {
377 return(fread(buffer, 1, len, f));
378}
379void myClose(FILE *f) {
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000380 if (f != stdin) {
Daniel Veillard5e873c42000-04-12 13:27:38 +0000381 fclose(f);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000382 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000383}
384
385/************************************************************************
386 * *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000387 * Test processing *
388 * *
389 ************************************************************************/
390void parseAndPrintFile(char *filename) {
391 xmlDocPtr doc = NULL, tmp;
392
Daniel Veillard48b2f892001-02-25 16:11:03 +0000393 if ((timing) && (!repeat))
394 gettimeofday(&begin, NULL);
395
396
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000397#ifdef LIBXML_HTML_ENABLED
398 if (html) {
399 doc = htmlParseFile(filename, NULL);
400 } else {
401#endif /* LIBXML_HTML_ENABLED */
402 /*
403 * build an XML tree from a string;
404 */
405 if (push) {
406 FILE *f;
407
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000408 /* '-' Usually means stdin -<sven@zen.org> */
409 if ((filename[0] == '-') && (filename[1] == 0)) {
410 f = stdin;
411 } else {
412 f = fopen(filename, "r");
413 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000414 if (f != NULL) {
Daniel Veillarde715dd22000-08-29 18:29:38 +0000415 int ret;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000416 int res, size = 3;
417 char chars[1024];
418 xmlParserCtxtPtr ctxt;
419
420 if (repeat)
421 size = 1024;
422 res = fread(chars, 1, 4, f);
423 if (res > 0) {
424 ctxt = xmlCreatePushParserCtxt(NULL, NULL,
425 chars, res, filename);
426 while ((res = fread(chars, 1, size, f)) > 0) {
427 xmlParseChunk(ctxt, chars, res, 0);
428 }
429 xmlParseChunk(ctxt, chars, 0, 1);
430 doc = ctxt->myDoc;
Daniel Veillarde715dd22000-08-29 18:29:38 +0000431 ret = ctxt->wellFormed;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000432 xmlFreeParserCtxt(ctxt);
Daniel Veillarde715dd22000-08-29 18:29:38 +0000433 if (!ret) {
434 xmlFreeDoc(doc);
435 doc = NULL;
436 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000437 }
438 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000439 } else if (testIO) {
440 int ret;
441 FILE *f;
442
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000443 /* '-' Usually means stdin -<sven@zen.org> */
444 if ((filename[0] == '-') && (filename[1] == 0)) {
445 f = stdin;
446 } else {
447 f = fopen(filename, "r");
448 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000449 if (f != NULL) {
450 xmlParserCtxtPtr ctxt;
451
452 ctxt = xmlCreateIOParserCtxt(NULL, NULL,
453 (xmlInputReadCallback) myRead,
454 (xmlInputCloseCallback) myClose,
455 f, XML_CHAR_ENCODING_NONE);
456 xmlParseDocument(ctxt);
457
458 ret = ctxt->wellFormed;
459 doc = ctxt->myDoc;
460 xmlFreeParserCtxt(ctxt);
461 if (!ret) {
462 xmlFreeDoc(doc);
463 doc = NULL;
464 }
465 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000466 } else if (recovery) {
467 doc = xmlRecoverFile(filename);
468 } else if (htmlout) {
469 int ret;
470 xmlParserCtxtPtr ctxt;
471 xmlSAXHandler silent, *old;
472
473 ctxt = xmlCreateFileParserCtxt(filename);
Daniel Veillard88a172f2000-08-04 18:23:10 +0000474
475 if (ctxt == NULL) {
476 /* If xmlCreateFileParseCtxt() return NULL something
477 strange happened so we don't want to do anything. Do
478 we want to print an error message here?
479 <sven@zen.org> */
Daniel Veillard7ebb1ee2000-08-04 18:24:45 +0000480 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000481 } else {
482 memcpy(&silent, ctxt->sax, sizeof(silent));
483 old = ctxt->sax;
484 silent.error = xmlHTMLError;
485 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000486 silent.warning = xmlHTMLWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000487 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000488 silent.warning = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000489 silent.fatalError = xmlHTMLError;
490 ctxt->sax = &silent;
491 ctxt->vctxt.error = xmlHTMLValidityError;
492 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000493 ctxt->vctxt.warning = xmlHTMLValidityWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000494 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000495 ctxt->vctxt.warning = NULL;
496
Daniel Veillard88a172f2000-08-04 18:23:10 +0000497 xmlParseDocument(ctxt);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000498
Daniel Veillard88a172f2000-08-04 18:23:10 +0000499 ret = ctxt->wellFormed;
500 doc = ctxt->myDoc;
501 ctxt->sax = old;
502 xmlFreeParserCtxt(ctxt);
503 if (!ret) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000504 xmlFreeDoc(doc);
505 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000506 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000507 }
Daniel Veillard46e370e2000-07-21 20:32:03 +0000508#ifdef HAVE_SYS_MMAN_H
509 } else if (memory) {
510 int fd;
511 struct stat info;
512 const char *base;
513 if (stat(filename, &info) < 0)
514 return;
515 if ((fd = open(filename, O_RDONLY)) < 0)
516 return;
517 base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
Daniel Veillard29579362000-08-14 17:57:48 +0000518 if (base == (void *) MAP_FAILED)
Daniel Veillard46e370e2000-07-21 20:32:03 +0000519 return;
520
521 doc = xmlParseMemory((char *) base, info.st_size);
522 munmap((char *) base, info.st_size);
523#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000524 } else
525 doc = xmlParseFile(filename);
526#ifdef LIBXML_HTML_ENABLED
527 }
528#endif
529
Daniel Veillard88a172f2000-08-04 18:23:10 +0000530 /*
531 * If we don't have a document we might as well give up. Do we
532 * want an error message here? <sven@zen.org> */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000533 if (doc == NULL) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000534 progresult = 1;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000535 return;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000536 }
537
Daniel Veillard48b2f892001-02-25 16:11:03 +0000538 if ((timing) && (!repeat)) {
539 long msec;
540 gettimeofday(&end, NULL);
541 msec = end.tv_sec - begin.tv_sec;
542 msec *= 1000;
543 msec += (end.tv_usec - begin.tv_usec) / 1000;
544 fprintf(stderr, "Parsing took %ld ms\n", msec);
545 }
546
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000547#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard48b2f892001-02-25 16:11:03 +0000548 if (xinclude) {
549 if ((timing) && (!repeat)) {
550 gettimeofday(&begin, NULL);
551 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000552 xmlXIncludeProcess(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000553 if ((timing) && (!repeat)) {
554 long msec;
555 gettimeofday(&end, NULL);
556 msec = end.tv_sec - begin.tv_sec;
557 msec *= 1000;
558 msec += (end.tv_usec - begin.tv_usec) / 1000;
559 fprintf(stderr, "Xinclude processing took %ld ms\n", msec);
560 }
561 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000562#endif
Daniel Veillard88a172f2000-08-04 18:23:10 +0000563
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000564#ifdef LIBXML_DEBUG_ENABLED
565 /*
566 * shell interraction
567 */
568 if (shell)
569 xmlShell(doc, filename, xmlShellReadline, stdout);
570#endif
571
572 /*
573 * test intermediate copy if needed.
574 */
575 if (copy) {
576 tmp = doc;
577 doc = xmlCopyDoc(doc, 1);
578 xmlFreeDoc(tmp);
579 }
580
581 if ((insert) && (!html)) {
582 const xmlChar* list[256];
583 int nb, i;
584 xmlNodePtr node;
585
586 if (doc->children != NULL) {
587 node = doc->children;
588 while ((node != NULL) && (node->last == NULL)) node = node->next;
589 if (node != NULL) {
590 nb = xmlValidGetValidElements(node->last, NULL, list, 256);
591 if (nb < 0) {
592 printf("could not get valid list of elements\n");
593 } else if (nb == 0) {
594 printf("No element can be indersted under root\n");
595 } else {
596 printf("%d element types can be indersted under root:\n",
597 nb);
598 for (i = 0;i < nb;i++) {
599 printf("%s\n", list[i]);
600 }
601 }
602 }
603 }
604 }else if (noout == 0) {
605 /*
606 * print it.
607 */
608#ifdef LIBXML_DEBUG_ENABLED
609 if (!debug) {
610#endif
Daniel Veillard48b2f892001-02-25 16:11:03 +0000611 if ((timing) && (!repeat)) {
612 gettimeofday(&begin, NULL);
613 }
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000614 if (memory) {
615 xmlChar *result;
616 int len;
617
618 if (encoding != NULL) {
619 xmlDocDumpMemoryEnc(doc, &result, &len, encoding);
620 } else {
621 xmlDocDumpMemory(doc, &result, &len);
622 }
623 if (result == NULL) {
624 fprintf(stderr, "Failed to save\n");
625 } else {
626 write(1, result, len);
627 xmlFree(result);
628 }
629 } else if (compress)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000630 xmlSaveFile("-", doc);
Daniel Veillardbe803962000-06-28 23:40:59 +0000631 else if (encoding != NULL)
632 xmlSaveFileEnc("-", doc, encoding);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000633 else
634 xmlDocDump(stdout, doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000635 if ((timing) && (!repeat)) {
636 long msec;
637 gettimeofday(&end, NULL);
638 msec = end.tv_sec - begin.tv_sec;
639 msec *= 1000;
640 msec += (end.tv_usec - begin.tv_usec) / 1000;
641 fprintf(stderr, "Saving took %ld ms\n", msec);
642 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000643#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000644 } else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000645 xmlDebugDumpDocument(stdout, doc);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000646 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000647#endif
648 }
649
650 /*
651 * A posteriori validation test
652 */
Daniel Veillardcd429612000-10-11 15:57:05 +0000653 if (dtdvalid != NULL) {
654 xmlDtdPtr dtd;
655
Daniel Veillard48b2f892001-02-25 16:11:03 +0000656 if ((timing) && (!repeat)) {
657 gettimeofday(&begin, NULL);
658 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000659 dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000660 if ((timing) && (!repeat)) {
661 long msec;
662 gettimeofday(&end, NULL);
663 msec = end.tv_sec - begin.tv_sec;
664 msec *= 1000;
665 msec += (end.tv_usec - begin.tv_usec) / 1000;
666 fprintf(stderr, "Parsing DTD took %ld ms\n", msec);
667 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000668 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000669 xmlGenericError(xmlGenericErrorContext,
670 "Could not parse DTD %s\n", dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000671 progresult = 2;
Daniel Veillardcd429612000-10-11 15:57:05 +0000672 } else {
673 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000674 if ((timing) && (!repeat)) {
675 gettimeofday(&begin, NULL);
676 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000677 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
678 if (!xmlValidateDtd(&cvp, doc, dtd)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000679 xmlGenericError(xmlGenericErrorContext,
680 "Document %s does not validate against %s\n",
Daniel Veillardcd429612000-10-11 15:57:05 +0000681 filename, dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000682 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000683 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000684 if ((timing) && (!repeat)) {
685 long msec;
686 gettimeofday(&end, NULL);
687 msec = end.tv_sec - begin.tv_sec;
688 msec *= 1000;
689 msec += (end.tv_usec - begin.tv_usec) / 1000;
690 fprintf(stderr, "Validating against DTD took %ld ms\n", msec);
691 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000692 xmlFreeDtd(dtd);
693 }
694 } else if (postvalid) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000695 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000696 if ((timing) && (!repeat)) {
697 gettimeofday(&begin, NULL);
698 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000699 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
Daniel Veillardcd429612000-10-11 15:57:05 +0000700 if (!xmlValidateDocument(&cvp, doc)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000701 xmlGenericError(xmlGenericErrorContext,
702 "Document %s does not validate\n", filename);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000703 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000704 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000705 if ((timing) && (!repeat)) {
706 long msec;
707 gettimeofday(&end, NULL);
708 msec = end.tv_sec - begin.tv_sec;
709 msec *= 1000;
710 msec += (end.tv_usec - begin.tv_usec) / 1000;
711 fprintf(stderr, "Validating took %ld ms\n", msec);
712 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000713 }
714
715#ifdef LIBXML_DEBUG_ENABLED
716 if ((debugent) && (!html))
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000717 xmlDebugDumpEntities(stderr, doc);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000718#endif
719
720 /*
721 * free it.
722 */
Daniel Veillard48b2f892001-02-25 16:11:03 +0000723 if ((timing) && (!repeat)) {
724 gettimeofday(&begin, NULL);
725 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000726 xmlFreeDoc(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000727 if ((timing) && (!repeat)) {
728 long msec;
729 gettimeofday(&end, NULL);
730 msec = end.tv_sec - begin.tv_sec;
731 msec *= 1000;
732 msec += (end.tv_usec - begin.tv_usec) / 1000;
733 fprintf(stderr, "Freeing took %ld ms\n", msec);
734 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000735}
736
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000737int
738main(int argc, char **argv) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000739 int i, count;
740 int files = 0;
741
Daniel Veillardbe803962000-06-28 23:40:59 +0000742 LIBXML_TEST_VERSION
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000743 for (i = 1; i < argc ; i++) {
744#ifdef LIBXML_DEBUG_ENABLED
745 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
746 debug++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000747 else if ((!strcmp(argv[i], "-shell")) ||
748 (!strcmp(argv[i], "--shell"))) {
749 shell++;
750 noout = 1;
751 } else
752#endif
753 if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
754 copy++;
755 else if ((!strcmp(argv[i], "-recover")) ||
756 (!strcmp(argv[i], "--recover")))
757 recovery++;
758 else if ((!strcmp(argv[i], "-noent")) ||
759 (!strcmp(argv[i], "--noent")))
760 noent++;
761 else if ((!strcmp(argv[i], "-noout")) ||
762 (!strcmp(argv[i], "--noout")))
763 noout++;
764 else if ((!strcmp(argv[i], "-htmlout")) ||
765 (!strcmp(argv[i], "--htmlout")))
766 htmlout++;
767#ifdef LIBXML_HTML_ENABLED
768 else if ((!strcmp(argv[i], "-html")) ||
769 (!strcmp(argv[i], "--html"))) {
770 html++;
771 }
772#endif /* LIBXML_HTML_ENABLED */
773 else if ((!strcmp(argv[i], "-nowrap")) ||
774 (!strcmp(argv[i], "--nowrap")))
775 nowrap++;
776 else if ((!strcmp(argv[i], "-valid")) ||
777 (!strcmp(argv[i], "--valid")))
778 valid++;
779 else if ((!strcmp(argv[i], "-postvalid")) ||
780 (!strcmp(argv[i], "--postvalid")))
781 postvalid++;
Daniel Veillardcd429612000-10-11 15:57:05 +0000782 else if ((!strcmp(argv[i], "-dtdvalid")) ||
783 (!strcmp(argv[i], "--dtdvalid"))) {
784 i++;
785 dtdvalid = argv[i];
786 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000787 else if ((!strcmp(argv[i], "-insert")) ||
788 (!strcmp(argv[i], "--insert")))
789 insert++;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000790 else if ((!strcmp(argv[i], "-timing")) ||
791 (!strcmp(argv[i], "--timing")))
792 timing++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000793 else if ((!strcmp(argv[i], "-repeat")) ||
794 (!strcmp(argv[i], "--repeat")))
795 repeat++;
796 else if ((!strcmp(argv[i], "-push")) ||
797 (!strcmp(argv[i], "--push")))
798 push++;
Daniel Veillard46e370e2000-07-21 20:32:03 +0000799#ifdef HAVE_SYS_MMAN_H
800 else if ((!strcmp(argv[i], "-memory")) ||
801 (!strcmp(argv[i], "--memory")))
802 memory++;
803#endif
Daniel Veillard5e873c42000-04-12 13:27:38 +0000804 else if ((!strcmp(argv[i], "-testIO")) ||
805 (!strcmp(argv[i], "--testIO")))
806 testIO++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000807#ifdef LIBXML_XINCLUDE_ENABLED
808 else if ((!strcmp(argv[i], "-xinclude")) ||
809 (!strcmp(argv[i], "--xinclude")))
810 xinclude++;
811#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000812 else if ((!strcmp(argv[i], "-compress")) ||
813 (!strcmp(argv[i], "--compress"))) {
814 compress++;
815 xmlSetCompressMode(9);
816 }
817 else if ((!strcmp(argv[i], "-nowarning")) ||
818 (!strcmp(argv[i], "--nowarning"))) {
819 xmlGetWarningsDefaultValue = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000820 xmlPedanticParserDefault(0);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000821 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000822 else if ((!strcmp(argv[i], "-pedantic")) ||
823 (!strcmp(argv[i], "--pedantic"))) {
824 xmlGetWarningsDefaultValue = 1;
825 xmlPedanticParserDefault(1);
826 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000827#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000828 else if ((!strcmp(argv[i], "-debugent")) ||
829 (!strcmp(argv[i], "--debugent"))) {
830 debugent++;
831 xmlParserDebugEntities = 1;
832 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000833#endif
Daniel Veillardbe803962000-06-28 23:40:59 +0000834 else if ((!strcmp(argv[i], "-encode")) ||
835 (!strcmp(argv[i], "--encode"))) {
836 i++;
837 encoding = argv[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000838 /*
839 * OK it's for testing purposes
840 */
841 xmlAddEncodingAlias("UTF-8", "DVEnc");
Daniel Veillardbe803962000-06-28 23:40:59 +0000842 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000843 else if ((!strcmp(argv[i], "-noblanks")) ||
844 (!strcmp(argv[i], "--noblanks"))) {
845 noblanks++;
846 xmlKeepBlanksDefault(0);
847 }
848 }
849 if (noent != 0) xmlSubstituteEntitiesDefault(1);
850 if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
851 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000852 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000853 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000854 xmlGenericError(xmlGenericErrorContext,
855 "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
856 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000857 "<html><head><title>%s output</title></head>\n",
858 argv[0]);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000860 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
861 argv[0]);
862 }
863 for (i = 1; i < argc ; i++) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000864 if ((!strcmp(argv[i], "-encode")) ||
865 (!strcmp(argv[i], "--encode"))) {
866 i++;
867 continue;
868 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000869 if ((!strcmp(argv[i], "-dtdvalid")) ||
870 (!strcmp(argv[i], "--dtdvalid"))) {
871 i++;
872 continue;
873 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000874 if ((timing) && (repeat))
875 gettimeofday(&begin, NULL);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000876 /* Remember file names. "-" means stding. <sven@zen.org> */
877 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000878 if (repeat) {
879 for (count = 0;count < 100 * repeat;count++)
880 parseAndPrintFile(argv[i]);
881 } else
882 parseAndPrintFile(argv[i]);
883 files ++;
884 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000885 if ((timing) && (repeat)) {
886 long msec;
887 gettimeofday(&end, NULL);
888 msec = end.tv_sec - begin.tv_sec;
889 msec *= 1000;
890 msec += (end.tv_usec - begin.tv_usec) / 1000;
891 fprintf(stderr, "100 iteration took %ld ms\n", msec);
892 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000893 }
894 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000895 xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000896 }
897 if (files == 0) {
Daniel Veillard48b2f892001-02-25 16:11:03 +0000898 printf("Usage : %s [options] XMLfiles ...\n",
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000899 argv[0]);
900 printf("\tParse the XML files and output the result of the parsing\n");
901#ifdef LIBXML_DEBUG_ENABLED
902 printf("\t--debug : dump a debug tree of the in-memory document\n");
903 printf("\t--shell : run a navigating shell\n");
904 printf("\t--debugent : debug the entities defined in the document\n");
905#endif
906 printf("\t--copy : used to test the internal copy implementation\n");
907 printf("\t--recover : output what was parsable on broken XML documents\n");
908 printf("\t--noent : substitute entity references by their value\n");
909 printf("\t--noout : don't output the result tree\n");
910 printf("\t--htmlout : output results as HTML\n");
911 printf("\t--nowarp : do not put HTML doc wrapper\n");
912 printf("\t--valid : validate the document in addition to std well-formed check\n");
913 printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
Daniel Veillardcd429612000-10-11 15:57:05 +0000914 printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000915 printf("\t--timing : print some timings\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000916 printf("\t--repeat : repeat 100 times, for timing or profiling\n");
917 printf("\t--insert : ad-hoc test for valid insertions\n");
918 printf("\t--compress : turn on gzip compression of output\n");
919#ifdef LIBXML_HTML_ENABLED
920 printf("\t--html : use the HTML parser\n");
921#endif
922 printf("\t--push : use the push mode of the parser\n");
Daniel Veillard46e370e2000-07-21 20:32:03 +0000923#ifdef HAVE_SYS_MMAN_H
924 printf("\t--memory : parse from memory\n");
925#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000926 printf("\t--nowarning : do not emit warnings from parser/validator\n");
927 printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
Daniel Veillard5e873c42000-04-12 13:27:38 +0000928 printf("\t--testIO : test user I/O support\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000929 printf("\t--encode encoding : output in the given encoding\n");
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000930#ifdef LIBXML_XINCLUDE_ENABLED
931 printf("\t--xinclude : do XInclude processing\n");
932#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000933 }
934 xmlCleanupParser();
935 xmlMemoryDump();
936
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000937 return(progresult);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000938}
Daniel Veillard88a172f2000-08-04 18:23:10 +0000939