blob: b1f56f03d6ca0515890c2f4a276f3b2ac079dd96 [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
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000112static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000113xmlHTMLEncodeSend(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
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000131static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000132xmlHTMLPrintFileInfo(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
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000152static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000153xmlHTMLPrintFileContext(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 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000197static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000198xmlHTMLError(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 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000234static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000235xmlHTMLWarning(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 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000272static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000273xmlHTMLValidityError(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 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000306static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000307xmlHTMLValidityWarning(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 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000345static char *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000346xmlShellReadline(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
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000376static int myRead(FILE *f, char * buf, int len) {
377 return(fread(buf, 1, len, f));
Daniel Veillard5e873c42000-04-12 13:27:38 +0000378}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000379static void 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 ************************************************************************/
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000390static void parseAndPrintFile(char *filename) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000391 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 Veillard3b2c2612001-04-04 00:09:00 +0000614#ifdef HAVE_SYS_MMAN_H
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000615 if (memory) {
616 xmlChar *result;
617 int len;
618
619 if (encoding != NULL) {
620 xmlDocDumpMemoryEnc(doc, &result, &len, encoding);
621 } else {
622 xmlDocDumpMemory(doc, &result, &len);
623 }
624 if (result == NULL) {
625 fprintf(stderr, "Failed to save\n");
626 } else {
627 write(1, result, len);
628 xmlFree(result);
629 }
Daniel Veillard3b2c2612001-04-04 00:09:00 +0000630 } else
631#endif /* HAVE_SYS_MMAN_H */
632 if (compress)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000633 xmlSaveFile("-", doc);
Daniel Veillardbe803962000-06-28 23:40:59 +0000634 else if (encoding != NULL)
635 xmlSaveFileEnc("-", doc, encoding);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000636 else
637 xmlDocDump(stdout, doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000638 if ((timing) && (!repeat)) {
639 long msec;
640 gettimeofday(&end, NULL);
641 msec = end.tv_sec - begin.tv_sec;
642 msec *= 1000;
643 msec += (end.tv_usec - begin.tv_usec) / 1000;
644 fprintf(stderr, "Saving took %ld ms\n", msec);
645 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000646#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000647 } else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000648 xmlDebugDumpDocument(stdout, doc);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000649 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000650#endif
651 }
652
653 /*
654 * A posteriori validation test
655 */
Daniel Veillardcd429612000-10-11 15:57:05 +0000656 if (dtdvalid != NULL) {
657 xmlDtdPtr dtd;
658
Daniel Veillard48b2f892001-02-25 16:11:03 +0000659 if ((timing) && (!repeat)) {
660 gettimeofday(&begin, NULL);
661 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000662 dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000663 if ((timing) && (!repeat)) {
664 long msec;
665 gettimeofday(&end, NULL);
666 msec = end.tv_sec - begin.tv_sec;
667 msec *= 1000;
668 msec += (end.tv_usec - begin.tv_usec) / 1000;
669 fprintf(stderr, "Parsing DTD took %ld ms\n", msec);
670 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000671 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000672 xmlGenericError(xmlGenericErrorContext,
673 "Could not parse DTD %s\n", dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000674 progresult = 2;
Daniel Veillardcd429612000-10-11 15:57:05 +0000675 } else {
676 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000677 if ((timing) && (!repeat)) {
678 gettimeofday(&begin, NULL);
679 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000680 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
681 if (!xmlValidateDtd(&cvp, doc, dtd)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000682 xmlGenericError(xmlGenericErrorContext,
683 "Document %s does not validate against %s\n",
Daniel Veillardcd429612000-10-11 15:57:05 +0000684 filename, dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000685 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000686 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000687 if ((timing) && (!repeat)) {
688 long msec;
689 gettimeofday(&end, NULL);
690 msec = end.tv_sec - begin.tv_sec;
691 msec *= 1000;
692 msec += (end.tv_usec - begin.tv_usec) / 1000;
693 fprintf(stderr, "Validating against DTD took %ld ms\n", msec);
694 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000695 xmlFreeDtd(dtd);
696 }
697 } else if (postvalid) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000698 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000699 if ((timing) && (!repeat)) {
700 gettimeofday(&begin, NULL);
701 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000702 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
Daniel Veillardcd429612000-10-11 15:57:05 +0000703 if (!xmlValidateDocument(&cvp, doc)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000704 xmlGenericError(xmlGenericErrorContext,
705 "Document %s does not validate\n", filename);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000706 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000707 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000708 if ((timing) && (!repeat)) {
709 long msec;
710 gettimeofday(&end, NULL);
711 msec = end.tv_sec - begin.tv_sec;
712 msec *= 1000;
713 msec += (end.tv_usec - begin.tv_usec) / 1000;
714 fprintf(stderr, "Validating took %ld ms\n", msec);
715 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000716 }
717
718#ifdef LIBXML_DEBUG_ENABLED
719 if ((debugent) && (!html))
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000720 xmlDebugDumpEntities(stderr, doc);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000721#endif
722
723 /*
724 * free it.
725 */
Daniel Veillard48b2f892001-02-25 16:11:03 +0000726 if ((timing) && (!repeat)) {
727 gettimeofday(&begin, NULL);
728 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000729 xmlFreeDoc(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000730 if ((timing) && (!repeat)) {
731 long msec;
732 gettimeofday(&end, NULL);
733 msec = end.tv_sec - begin.tv_sec;
734 msec *= 1000;
735 msec += (end.tv_usec - begin.tv_usec) / 1000;
736 fprintf(stderr, "Freeing took %ld ms\n", msec);
737 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000738}
739
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000740int
741main(int argc, char **argv) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000742 int i, count;
743 int files = 0;
744
Daniel Veillardbe803962000-06-28 23:40:59 +0000745 LIBXML_TEST_VERSION
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000746 for (i = 1; i < argc ; i++) {
747#ifdef LIBXML_DEBUG_ENABLED
748 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
749 debug++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000750 else if ((!strcmp(argv[i], "-shell")) ||
751 (!strcmp(argv[i], "--shell"))) {
752 shell++;
753 noout = 1;
754 } else
755#endif
756 if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
757 copy++;
758 else if ((!strcmp(argv[i], "-recover")) ||
759 (!strcmp(argv[i], "--recover")))
760 recovery++;
761 else if ((!strcmp(argv[i], "-noent")) ||
762 (!strcmp(argv[i], "--noent")))
763 noent++;
764 else if ((!strcmp(argv[i], "-noout")) ||
765 (!strcmp(argv[i], "--noout")))
766 noout++;
767 else if ((!strcmp(argv[i], "-htmlout")) ||
768 (!strcmp(argv[i], "--htmlout")))
769 htmlout++;
770#ifdef LIBXML_HTML_ENABLED
771 else if ((!strcmp(argv[i], "-html")) ||
772 (!strcmp(argv[i], "--html"))) {
773 html++;
774 }
775#endif /* LIBXML_HTML_ENABLED */
776 else if ((!strcmp(argv[i], "-nowrap")) ||
777 (!strcmp(argv[i], "--nowrap")))
778 nowrap++;
779 else if ((!strcmp(argv[i], "-valid")) ||
780 (!strcmp(argv[i], "--valid")))
781 valid++;
782 else if ((!strcmp(argv[i], "-postvalid")) ||
783 (!strcmp(argv[i], "--postvalid")))
784 postvalid++;
Daniel Veillardcd429612000-10-11 15:57:05 +0000785 else if ((!strcmp(argv[i], "-dtdvalid")) ||
786 (!strcmp(argv[i], "--dtdvalid"))) {
787 i++;
788 dtdvalid = argv[i];
789 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000790 else if ((!strcmp(argv[i], "-insert")) ||
791 (!strcmp(argv[i], "--insert")))
792 insert++;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000793 else if ((!strcmp(argv[i], "-timing")) ||
794 (!strcmp(argv[i], "--timing")))
795 timing++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000796 else if ((!strcmp(argv[i], "-repeat")) ||
797 (!strcmp(argv[i], "--repeat")))
798 repeat++;
799 else if ((!strcmp(argv[i], "-push")) ||
800 (!strcmp(argv[i], "--push")))
801 push++;
Daniel Veillard46e370e2000-07-21 20:32:03 +0000802#ifdef HAVE_SYS_MMAN_H
803 else if ((!strcmp(argv[i], "-memory")) ||
804 (!strcmp(argv[i], "--memory")))
805 memory++;
806#endif
Daniel Veillard5e873c42000-04-12 13:27:38 +0000807 else if ((!strcmp(argv[i], "-testIO")) ||
808 (!strcmp(argv[i], "--testIO")))
809 testIO++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000810#ifdef LIBXML_XINCLUDE_ENABLED
811 else if ((!strcmp(argv[i], "-xinclude")) ||
812 (!strcmp(argv[i], "--xinclude")))
813 xinclude++;
814#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000815 else if ((!strcmp(argv[i], "-compress")) ||
816 (!strcmp(argv[i], "--compress"))) {
817 compress++;
818 xmlSetCompressMode(9);
819 }
820 else if ((!strcmp(argv[i], "-nowarning")) ||
821 (!strcmp(argv[i], "--nowarning"))) {
822 xmlGetWarningsDefaultValue = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000823 xmlPedanticParserDefault(0);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000824 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000825 else if ((!strcmp(argv[i], "-pedantic")) ||
826 (!strcmp(argv[i], "--pedantic"))) {
827 xmlGetWarningsDefaultValue = 1;
828 xmlPedanticParserDefault(1);
829 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000830#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000831 else if ((!strcmp(argv[i], "-debugent")) ||
832 (!strcmp(argv[i], "--debugent"))) {
833 debugent++;
834 xmlParserDebugEntities = 1;
835 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000836#endif
Daniel Veillardbe803962000-06-28 23:40:59 +0000837 else if ((!strcmp(argv[i], "-encode")) ||
838 (!strcmp(argv[i], "--encode"))) {
839 i++;
840 encoding = argv[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000841 /*
842 * OK it's for testing purposes
843 */
844 xmlAddEncodingAlias("UTF-8", "DVEnc");
Daniel Veillardbe803962000-06-28 23:40:59 +0000845 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000846 else if ((!strcmp(argv[i], "-noblanks")) ||
847 (!strcmp(argv[i], "--noblanks"))) {
848 noblanks++;
849 xmlKeepBlanksDefault(0);
850 }
851 }
852 if (noent != 0) xmlSubstituteEntitiesDefault(1);
853 if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
854 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000855 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000856 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000857 xmlGenericError(xmlGenericErrorContext,
858 "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000860 "<html><head><title>%s output</title></head>\n",
861 argv[0]);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000862 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000863 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
864 argv[0]);
865 }
866 for (i = 1; i < argc ; i++) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000867 if ((!strcmp(argv[i], "-encode")) ||
868 (!strcmp(argv[i], "--encode"))) {
869 i++;
870 continue;
871 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000872 if ((!strcmp(argv[i], "-dtdvalid")) ||
873 (!strcmp(argv[i], "--dtdvalid"))) {
874 i++;
875 continue;
876 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000877 if ((timing) && (repeat))
878 gettimeofday(&begin, NULL);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000879 /* Remember file names. "-" means stding. <sven@zen.org> */
880 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000881 if (repeat) {
882 for (count = 0;count < 100 * repeat;count++)
883 parseAndPrintFile(argv[i]);
884 } else
885 parseAndPrintFile(argv[i]);
886 files ++;
887 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000888 if ((timing) && (repeat)) {
889 long msec;
890 gettimeofday(&end, NULL);
891 msec = end.tv_sec - begin.tv_sec;
892 msec *= 1000;
893 msec += (end.tv_usec - begin.tv_usec) / 1000;
894 fprintf(stderr, "100 iteration took %ld ms\n", msec);
895 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000896 }
897 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000898 xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000899 }
900 if (files == 0) {
Daniel Veillard48b2f892001-02-25 16:11:03 +0000901 printf("Usage : %s [options] XMLfiles ...\n",
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000902 argv[0]);
903 printf("\tParse the XML files and output the result of the parsing\n");
904#ifdef LIBXML_DEBUG_ENABLED
905 printf("\t--debug : dump a debug tree of the in-memory document\n");
906 printf("\t--shell : run a navigating shell\n");
907 printf("\t--debugent : debug the entities defined in the document\n");
908#endif
909 printf("\t--copy : used to test the internal copy implementation\n");
910 printf("\t--recover : output what was parsable on broken XML documents\n");
911 printf("\t--noent : substitute entity references by their value\n");
912 printf("\t--noout : don't output the result tree\n");
913 printf("\t--htmlout : output results as HTML\n");
914 printf("\t--nowarp : do not put HTML doc wrapper\n");
915 printf("\t--valid : validate the document in addition to std well-formed check\n");
916 printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
Daniel Veillardcd429612000-10-11 15:57:05 +0000917 printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000918 printf("\t--timing : print some timings\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000919 printf("\t--repeat : repeat 100 times, for timing or profiling\n");
920 printf("\t--insert : ad-hoc test for valid insertions\n");
921 printf("\t--compress : turn on gzip compression of output\n");
922#ifdef LIBXML_HTML_ENABLED
923 printf("\t--html : use the HTML parser\n");
924#endif
925 printf("\t--push : use the push mode of the parser\n");
Daniel Veillard46e370e2000-07-21 20:32:03 +0000926#ifdef HAVE_SYS_MMAN_H
927 printf("\t--memory : parse from memory\n");
928#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000929 printf("\t--nowarning : do not emit warnings from parser/validator\n");
930 printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
Daniel Veillard5e873c42000-04-12 13:27:38 +0000931 printf("\t--testIO : test user I/O support\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000932 printf("\t--encode encoding : output in the given encoding\n");
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000933#ifdef LIBXML_XINCLUDE_ENABLED
934 printf("\t--xinclude : do XInclude processing\n");
935#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000936 }
937 xmlCleanupParser();
938 xmlMemoryDump();
939
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000940 return(progresult);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000941}
Daniel Veillard88a172f2000-08-04 18:23:10 +0000942