blob: 0df7cebffe3289a0ff3b9320a0adcda031953a06 [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;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +000094static int generate = 0;
Daniel Veillard48b2f892001-02-25 16:11:03 +000095static struct timeval begin, end;
Daniel Veillardce8b83b2000-04-05 18:38:42 +000096
Daniel Veillardce6e98d2000-11-25 09:54:49 +000097
98#ifdef VMS
99extern int xmlDoValidityCheckingDefaultVal;
100#define xmlDoValidityCheckingDefaultValue xmlDoValidityCheckingDefaultVal
101#else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000102extern int xmlDoValidityCheckingDefaultValue;
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000103#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000104extern int xmlGetWarningsDefaultValue;
105
106/************************************************************************
107 * *
108 * HTML ouput *
109 * *
110 ************************************************************************/
111char buffer[50000];
112
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000113static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000114xmlHTMLEncodeSend(void) {
115 char *result;
116
117 result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer);
118 if (result) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000119 xmlGenericError(xmlGenericErrorContext, "%s", result);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000120 xmlFree(result);
121 }
122 buffer[0] = 0;
123}
124
125/**
126 * xmlHTMLPrintFileInfo:
127 * @input: an xmlParserInputPtr input
128 *
129 * Displays the associated file and line informations for the current input
130 */
131
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000132static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000133xmlHTMLPrintFileInfo(xmlParserInputPtr input) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000134 xmlGenericError(xmlGenericErrorContext, "<p>");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000135 if (input != NULL) {
136 if (input->filename) {
137 sprintf(&buffer[strlen(buffer)], "%s:%d: ", input->filename,
138 input->line);
139 } else {
140 sprintf(&buffer[strlen(buffer)], "Entity: line %d: ", input->line);
141 }
142 }
143 xmlHTMLEncodeSend();
144}
145
146/**
147 * xmlHTMLPrintFileContext:
148 * @input: an xmlParserInputPtr input
149 *
150 * Displays current context within the input content for error tracking
151 */
152
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000153static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000154xmlHTMLPrintFileContext(xmlParserInputPtr input) {
155 const xmlChar *cur, *base;
156 int n;
157
158 if (input == NULL) return;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000159 xmlGenericError(xmlGenericErrorContext, "<pre>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000160 cur = input->cur;
161 base = input->base;
162 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
163 cur--;
164 }
165 n = 0;
166 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
167 cur--;
168 if ((*cur == '\n') || (*cur == '\r')) cur++;
169 base = cur;
170 n = 0;
171 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
172 sprintf(&buffer[strlen(buffer)], "%c", (unsigned char) *cur++);
173 n++;
174 }
175 sprintf(&buffer[strlen(buffer)], "\n");
176 cur = input->cur;
177 while ((*cur == '\n') || (*cur == '\r'))
178 cur--;
179 n = 0;
180 while ((cur != base) && (n++ < 80)) {
181 sprintf(&buffer[strlen(buffer)], " ");
182 base++;
183 }
184 sprintf(&buffer[strlen(buffer)],"^\n");
185 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000186 xmlGenericError(xmlGenericErrorContext, "</pre>");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000187}
188
189/**
190 * xmlHTMLError:
191 * @ctx: an XML parser context
192 * @msg: the message to display/transmit
193 * @...: extra parameters for the message display
194 *
195 * Display and format an error messages, gives file, line, position and
196 * extra parameters.
197 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000198static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000199xmlHTMLError(void *ctx, const char *msg, ...)
200{
201 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
202 xmlParserInputPtr input;
203 xmlParserInputPtr cur = NULL;
204 va_list args;
205
206 buffer[0] = 0;
207 input = ctxt->input;
208 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
209 cur = input;
210 input = ctxt->inputTab[ctxt->inputNr - 2];
211 }
212
213 xmlHTMLPrintFileInfo(input);
214
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000215 xmlGenericError(xmlGenericErrorContext, "<b>error</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000216 va_start(args, msg);
217 vsprintf(&buffer[strlen(buffer)], msg, args);
218 va_end(args);
219 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000220 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000221
222 xmlHTMLPrintFileContext(input);
223 xmlHTMLEncodeSend();
224}
225
226/**
227 * xmlHTMLWarning:
228 * @ctx: an XML parser context
229 * @msg: the message to display/transmit
230 * @...: extra parameters for the message display
231 *
232 * Display and format a warning messages, gives file, line, position and
233 * extra parameters.
234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000235static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000236xmlHTMLWarning(void *ctx, const char *msg, ...)
237{
238 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
239 xmlParserInputPtr input;
240 xmlParserInputPtr cur = NULL;
241 va_list args;
242
243 buffer[0] = 0;
244 input = ctxt->input;
245 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
246 cur = input;
247 input = ctxt->inputTab[ctxt->inputNr - 2];
248 }
249
250
251 xmlHTMLPrintFileInfo(input);
252
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000253 xmlGenericError(xmlGenericErrorContext, "<b>warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000254 va_start(args, msg);
255 vsprintf(&buffer[strlen(buffer)], msg, args);
256 va_end(args);
257 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000258 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000259
260 xmlHTMLPrintFileContext(input);
261 xmlHTMLEncodeSend();
262}
263
264/**
265 * xmlHTMLValidityError:
266 * @ctx: an XML parser context
267 * @msg: the message to display/transmit
268 * @...: extra parameters for the message display
269 *
270 * Display and format an validity error messages, gives file,
271 * line, position and extra parameters.
272 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000273static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000274xmlHTMLValidityError(void *ctx, const char *msg, ...)
275{
276 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
277 xmlParserInputPtr input;
278 va_list args;
279
280 buffer[0] = 0;
281 input = ctxt->input;
282 if ((input->filename == NULL) && (ctxt->inputNr > 1))
283 input = ctxt->inputTab[ctxt->inputNr - 2];
284
285 xmlHTMLPrintFileInfo(input);
286
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000287 xmlGenericError(xmlGenericErrorContext, "<b>validity error</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000288 va_start(args, msg);
289 vsprintf(&buffer[strlen(buffer)], msg, args);
290 va_end(args);
291 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000292 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000293
294 xmlHTMLPrintFileContext(input);
295 xmlHTMLEncodeSend();
296}
297
298/**
299 * xmlHTMLValidityWarning:
300 * @ctx: an XML parser context
301 * @msg: the message to display/transmit
302 * @...: extra parameters for the message display
303 *
304 * Display and format a validity warning messages, gives file, line,
305 * position and extra parameters.
306 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000307static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000308xmlHTMLValidityWarning(void *ctx, const char *msg, ...)
309{
310 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
311 xmlParserInputPtr input;
312 va_list args;
313
314 buffer[0] = 0;
315 input = ctxt->input;
316 if ((input->filename == NULL) && (ctxt->inputNr > 1))
317 input = ctxt->inputTab[ctxt->inputNr - 2];
318
319 xmlHTMLPrintFileInfo(input);
320
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000321 xmlGenericError(xmlGenericErrorContext, "<b>validity warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000322 va_start(args, msg);
323 vsprintf(&buffer[strlen(buffer)], msg, args);
324 va_end(args);
325 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000326 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000327
328 xmlHTMLPrintFileContext(input);
329 xmlHTMLEncodeSend();
330}
331
332/************************************************************************
333 * *
334 * Shell Interface *
335 * *
336 ************************************************************************/
337/**
338 * xmlShellReadline:
339 * @prompt: the prompt value
340 *
341 * Read a string
342 *
343 * Returns a pointer to it or NULL on EOF the caller is expected to
344 * free the returned string.
345 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000346static char *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000347xmlShellReadline(char *prompt) {
348#ifdef HAVE_LIBREADLINE
349 char *line_read;
350
351 /* Get a line from the user. */
352 line_read = readline (prompt);
353
354 /* If the line has any text in it, save it on the history. */
355 if (line_read && *line_read)
356 add_history (line_read);
357
358 return (line_read);
359#else
360 char line_read[501];
361
362 if (prompt != NULL)
363 fprintf(stdout, "%s", prompt);
364 if (!fgets(line_read, 500, stdin))
365 return(NULL);
366 line_read[500] = 0;
367 return(strdup(line_read));
368#endif
369}
370
371/************************************************************************
372 * *
Daniel Veillard5e873c42000-04-12 13:27:38 +0000373 * I/O Interfaces *
374 * *
375 ************************************************************************/
376
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000377static int myRead(FILE *f, char * buf, int len) {
378 return(fread(buf, 1, len, f));
Daniel Veillard5e873c42000-04-12 13:27:38 +0000379}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000380static void myClose(FILE *f) {
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000381 if (f != stdin) {
Daniel Veillard5e873c42000-04-12 13:27:38 +0000382 fclose(f);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000383 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000384}
385
386/************************************************************************
387 * *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000388 * Test processing *
389 * *
390 ************************************************************************/
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000391static void parseAndPrintFile(char *filename) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000392 xmlDocPtr doc = NULL, tmp;
393
Daniel Veillard48b2f892001-02-25 16:11:03 +0000394 if ((timing) && (!repeat))
395 gettimeofday(&begin, NULL);
396
397
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000398 if (filename == NULL) {
399 if (generate) {
400 xmlNodePtr n;
401
402 doc = xmlNewDoc(BAD_CAST "1.0");
403 n = xmlNewNode(NULL, BAD_CAST "info");
404 xmlNodeSetContent(n, BAD_CAST "abc");
405 xmlDocSetRootElement(doc, n);
406 }
407 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000408#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000409 else if (html) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000410 doc = htmlParseFile(filename, NULL);
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000411 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000412#endif /* LIBXML_HTML_ENABLED */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000413 else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000414 /*
415 * build an XML tree from a string;
416 */
417 if (push) {
418 FILE *f;
419
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000420 /* '-' Usually means stdin -<sven@zen.org> */
421 if ((filename[0] == '-') && (filename[1] == 0)) {
422 f = stdin;
423 } else {
424 f = fopen(filename, "r");
425 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000426 if (f != NULL) {
Daniel Veillarde715dd22000-08-29 18:29:38 +0000427 int ret;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000428 int res, size = 3;
429 char chars[1024];
430 xmlParserCtxtPtr ctxt;
431
432 if (repeat)
433 size = 1024;
434 res = fread(chars, 1, 4, f);
435 if (res > 0) {
436 ctxt = xmlCreatePushParserCtxt(NULL, NULL,
437 chars, res, filename);
438 while ((res = fread(chars, 1, size, f)) > 0) {
439 xmlParseChunk(ctxt, chars, res, 0);
440 }
441 xmlParseChunk(ctxt, chars, 0, 1);
442 doc = ctxt->myDoc;
Daniel Veillarde715dd22000-08-29 18:29:38 +0000443 ret = ctxt->wellFormed;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000444 xmlFreeParserCtxt(ctxt);
Daniel Veillarde715dd22000-08-29 18:29:38 +0000445 if (!ret) {
446 xmlFreeDoc(doc);
447 doc = NULL;
448 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000449 }
450 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000451 } else if (testIO) {
452 int ret;
453 FILE *f;
454
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000455 /* '-' Usually means stdin -<sven@zen.org> */
456 if ((filename[0] == '-') && (filename[1] == 0)) {
457 f = stdin;
458 } else {
459 f = fopen(filename, "r");
460 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000461 if (f != NULL) {
462 xmlParserCtxtPtr ctxt;
463
464 ctxt = xmlCreateIOParserCtxt(NULL, NULL,
465 (xmlInputReadCallback) myRead,
466 (xmlInputCloseCallback) myClose,
467 f, XML_CHAR_ENCODING_NONE);
468 xmlParseDocument(ctxt);
469
470 ret = ctxt->wellFormed;
471 doc = ctxt->myDoc;
472 xmlFreeParserCtxt(ctxt);
473 if (!ret) {
474 xmlFreeDoc(doc);
475 doc = NULL;
476 }
477 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000478 } else if (recovery) {
479 doc = xmlRecoverFile(filename);
480 } else if (htmlout) {
481 int ret;
482 xmlParserCtxtPtr ctxt;
483 xmlSAXHandler silent, *old;
484
485 ctxt = xmlCreateFileParserCtxt(filename);
Daniel Veillard88a172f2000-08-04 18:23:10 +0000486
487 if (ctxt == NULL) {
488 /* If xmlCreateFileParseCtxt() return NULL something
489 strange happened so we don't want to do anything. Do
490 we want to print an error message here?
491 <sven@zen.org> */
Daniel Veillard7ebb1ee2000-08-04 18:24:45 +0000492 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000493 } else {
494 memcpy(&silent, ctxt->sax, sizeof(silent));
495 old = ctxt->sax;
496 silent.error = xmlHTMLError;
497 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000498 silent.warning = xmlHTMLWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000499 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000500 silent.warning = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000501 silent.fatalError = xmlHTMLError;
502 ctxt->sax = &silent;
503 ctxt->vctxt.error = xmlHTMLValidityError;
504 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000505 ctxt->vctxt.warning = xmlHTMLValidityWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000506 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000507 ctxt->vctxt.warning = NULL;
508
Daniel Veillard88a172f2000-08-04 18:23:10 +0000509 xmlParseDocument(ctxt);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000510
Daniel Veillard88a172f2000-08-04 18:23:10 +0000511 ret = ctxt->wellFormed;
512 doc = ctxt->myDoc;
513 ctxt->sax = old;
514 xmlFreeParserCtxt(ctxt);
515 if (!ret) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000516 xmlFreeDoc(doc);
517 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000518 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000519 }
Daniel Veillard46e370e2000-07-21 20:32:03 +0000520#ifdef HAVE_SYS_MMAN_H
521 } else if (memory) {
522 int fd;
523 struct stat info;
524 const char *base;
525 if (stat(filename, &info) < 0)
526 return;
527 if ((fd = open(filename, O_RDONLY)) < 0)
528 return;
529 base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
Daniel Veillard29579362000-08-14 17:57:48 +0000530 if (base == (void *) MAP_FAILED)
Daniel Veillard46e370e2000-07-21 20:32:03 +0000531 return;
532
533 doc = xmlParseMemory((char *) base, info.st_size);
534 munmap((char *) base, info.st_size);
535#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000536 } else
537 doc = xmlParseFile(filename);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000538 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000539
Daniel Veillard88a172f2000-08-04 18:23:10 +0000540 /*
541 * If we don't have a document we might as well give up. Do we
542 * want an error message here? <sven@zen.org> */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000543 if (doc == NULL) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000544 progresult = 1;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000545 return;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000546 }
547
Daniel Veillard48b2f892001-02-25 16:11:03 +0000548 if ((timing) && (!repeat)) {
549 long msec;
550 gettimeofday(&end, NULL);
551 msec = end.tv_sec - begin.tv_sec;
552 msec *= 1000;
553 msec += (end.tv_usec - begin.tv_usec) / 1000;
554 fprintf(stderr, "Parsing took %ld ms\n", msec);
555 }
556
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000557#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard48b2f892001-02-25 16:11:03 +0000558 if (xinclude) {
559 if ((timing) && (!repeat)) {
560 gettimeofday(&begin, NULL);
561 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000562 xmlXIncludeProcess(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000563 if ((timing) && (!repeat)) {
564 long msec;
565 gettimeofday(&end, NULL);
566 msec = end.tv_sec - begin.tv_sec;
567 msec *= 1000;
568 msec += (end.tv_usec - begin.tv_usec) / 1000;
569 fprintf(stderr, "Xinclude processing took %ld ms\n", msec);
570 }
571 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000572#endif
Daniel Veillard88a172f2000-08-04 18:23:10 +0000573
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000574#ifdef LIBXML_DEBUG_ENABLED
575 /*
576 * shell interraction
577 */
578 if (shell)
579 xmlShell(doc, filename, xmlShellReadline, stdout);
580#endif
581
582 /*
583 * test intermediate copy if needed.
584 */
585 if (copy) {
586 tmp = doc;
587 doc = xmlCopyDoc(doc, 1);
588 xmlFreeDoc(tmp);
589 }
590
591 if ((insert) && (!html)) {
592 const xmlChar* list[256];
593 int nb, i;
594 xmlNodePtr node;
595
596 if (doc->children != NULL) {
597 node = doc->children;
598 while ((node != NULL) && (node->last == NULL)) node = node->next;
599 if (node != NULL) {
600 nb = xmlValidGetValidElements(node->last, NULL, list, 256);
601 if (nb < 0) {
602 printf("could not get valid list of elements\n");
603 } else if (nb == 0) {
604 printf("No element can be indersted under root\n");
605 } else {
606 printf("%d element types can be indersted under root:\n",
607 nb);
608 for (i = 0;i < nb;i++) {
609 printf("%s\n", list[i]);
610 }
611 }
612 }
613 }
614 }else if (noout == 0) {
615 /*
616 * print it.
617 */
618#ifdef LIBXML_DEBUG_ENABLED
619 if (!debug) {
620#endif
Daniel Veillard48b2f892001-02-25 16:11:03 +0000621 if ((timing) && (!repeat)) {
622 gettimeofday(&begin, NULL);
623 }
Daniel Veillard3b2c2612001-04-04 00:09:00 +0000624#ifdef HAVE_SYS_MMAN_H
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000625 if (memory) {
626 xmlChar *result;
627 int len;
628
629 if (encoding != NULL) {
630 xmlDocDumpMemoryEnc(doc, &result, &len, encoding);
631 } else {
632 xmlDocDumpMemory(doc, &result, &len);
633 }
634 if (result == NULL) {
635 fprintf(stderr, "Failed to save\n");
636 } else {
637 write(1, result, len);
638 xmlFree(result);
639 }
Daniel Veillard3b2c2612001-04-04 00:09:00 +0000640 } else
641#endif /* HAVE_SYS_MMAN_H */
642 if (compress)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000643 xmlSaveFile("-", doc);
Daniel Veillardbe803962000-06-28 23:40:59 +0000644 else if (encoding != NULL)
645 xmlSaveFileEnc("-", doc, encoding);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000646 else
647 xmlDocDump(stdout, doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000648 if ((timing) && (!repeat)) {
649 long msec;
650 gettimeofday(&end, NULL);
651 msec = end.tv_sec - begin.tv_sec;
652 msec *= 1000;
653 msec += (end.tv_usec - begin.tv_usec) / 1000;
654 fprintf(stderr, "Saving took %ld ms\n", msec);
655 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000656#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000657 } else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000658 xmlDebugDumpDocument(stdout, doc);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000659 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000660#endif
661 }
662
663 /*
664 * A posteriori validation test
665 */
Daniel Veillardcd429612000-10-11 15:57:05 +0000666 if (dtdvalid != NULL) {
667 xmlDtdPtr dtd;
668
Daniel Veillard48b2f892001-02-25 16:11:03 +0000669 if ((timing) && (!repeat)) {
670 gettimeofday(&begin, NULL);
671 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000672 dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000673 if ((timing) && (!repeat)) {
674 long msec;
675 gettimeofday(&end, NULL);
676 msec = end.tv_sec - begin.tv_sec;
677 msec *= 1000;
678 msec += (end.tv_usec - begin.tv_usec) / 1000;
679 fprintf(stderr, "Parsing DTD took %ld ms\n", msec);
680 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000681 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000682 xmlGenericError(xmlGenericErrorContext,
683 "Could not parse DTD %s\n", dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000684 progresult = 2;
Daniel Veillardcd429612000-10-11 15:57:05 +0000685 } else {
686 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000687 if ((timing) && (!repeat)) {
688 gettimeofday(&begin, NULL);
689 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000690 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
691 if (!xmlValidateDtd(&cvp, doc, dtd)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000692 xmlGenericError(xmlGenericErrorContext,
693 "Document %s does not validate against %s\n",
Daniel Veillardcd429612000-10-11 15:57:05 +0000694 filename, dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000695 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000696 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000697 if ((timing) && (!repeat)) {
698 long msec;
699 gettimeofday(&end, NULL);
700 msec = end.tv_sec - begin.tv_sec;
701 msec *= 1000;
702 msec += (end.tv_usec - begin.tv_usec) / 1000;
703 fprintf(stderr, "Validating against DTD took %ld ms\n", msec);
704 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000705 xmlFreeDtd(dtd);
706 }
707 } else if (postvalid) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000708 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000709 if ((timing) && (!repeat)) {
710 gettimeofday(&begin, NULL);
711 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000712 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
Daniel Veillardcd429612000-10-11 15:57:05 +0000713 if (!xmlValidateDocument(&cvp, doc)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000714 xmlGenericError(xmlGenericErrorContext,
715 "Document %s does not validate\n", filename);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000716 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000717 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000718 if ((timing) && (!repeat)) {
719 long msec;
720 gettimeofday(&end, NULL);
721 msec = end.tv_sec - begin.tv_sec;
722 msec *= 1000;
723 msec += (end.tv_usec - begin.tv_usec) / 1000;
724 fprintf(stderr, "Validating took %ld ms\n", msec);
725 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000726 }
727
728#ifdef LIBXML_DEBUG_ENABLED
729 if ((debugent) && (!html))
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000730 xmlDebugDumpEntities(stderr, doc);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000731#endif
732
733 /*
734 * free it.
735 */
Daniel Veillard48b2f892001-02-25 16:11:03 +0000736 if ((timing) && (!repeat)) {
737 gettimeofday(&begin, NULL);
738 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000739 xmlFreeDoc(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000740 if ((timing) && (!repeat)) {
741 long msec;
742 gettimeofday(&end, NULL);
743 msec = end.tv_sec - begin.tv_sec;
744 msec *= 1000;
745 msec += (end.tv_usec - begin.tv_usec) / 1000;
746 fprintf(stderr, "Freeing took %ld ms\n", msec);
747 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000748}
749
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000750int
751main(int argc, char **argv) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000752 int i, count;
753 int files = 0;
754
Daniel Veillardbe803962000-06-28 23:40:59 +0000755 LIBXML_TEST_VERSION
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000756 for (i = 1; i < argc ; i++) {
757#ifdef LIBXML_DEBUG_ENABLED
758 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
759 debug++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000760 else if ((!strcmp(argv[i], "-shell")) ||
761 (!strcmp(argv[i], "--shell"))) {
762 shell++;
763 noout = 1;
764 } else
765#endif
766 if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
767 copy++;
768 else if ((!strcmp(argv[i], "-recover")) ||
769 (!strcmp(argv[i], "--recover")))
770 recovery++;
771 else if ((!strcmp(argv[i], "-noent")) ||
772 (!strcmp(argv[i], "--noent")))
773 noent++;
774 else if ((!strcmp(argv[i], "-noout")) ||
775 (!strcmp(argv[i], "--noout")))
776 noout++;
777 else if ((!strcmp(argv[i], "-htmlout")) ||
778 (!strcmp(argv[i], "--htmlout")))
779 htmlout++;
780#ifdef LIBXML_HTML_ENABLED
781 else if ((!strcmp(argv[i], "-html")) ||
782 (!strcmp(argv[i], "--html"))) {
783 html++;
784 }
785#endif /* LIBXML_HTML_ENABLED */
786 else if ((!strcmp(argv[i], "-nowrap")) ||
787 (!strcmp(argv[i], "--nowrap")))
788 nowrap++;
789 else if ((!strcmp(argv[i], "-valid")) ||
790 (!strcmp(argv[i], "--valid")))
791 valid++;
792 else if ((!strcmp(argv[i], "-postvalid")) ||
793 (!strcmp(argv[i], "--postvalid")))
794 postvalid++;
Daniel Veillardcd429612000-10-11 15:57:05 +0000795 else if ((!strcmp(argv[i], "-dtdvalid")) ||
796 (!strcmp(argv[i], "--dtdvalid"))) {
797 i++;
798 dtdvalid = argv[i];
799 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000800 else if ((!strcmp(argv[i], "-insert")) ||
801 (!strcmp(argv[i], "--insert")))
802 insert++;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000803 else if ((!strcmp(argv[i], "-timing")) ||
804 (!strcmp(argv[i], "--timing")))
805 timing++;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000806 else if ((!strcmp(argv[i], "-auto")) ||
807 (!strcmp(argv[i], "--auto")))
808 generate++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000809 else if ((!strcmp(argv[i], "-repeat")) ||
810 (!strcmp(argv[i], "--repeat")))
811 repeat++;
812 else if ((!strcmp(argv[i], "-push")) ||
813 (!strcmp(argv[i], "--push")))
814 push++;
Daniel Veillard46e370e2000-07-21 20:32:03 +0000815#ifdef HAVE_SYS_MMAN_H
816 else if ((!strcmp(argv[i], "-memory")) ||
817 (!strcmp(argv[i], "--memory")))
818 memory++;
819#endif
Daniel Veillard5e873c42000-04-12 13:27:38 +0000820 else if ((!strcmp(argv[i], "-testIO")) ||
821 (!strcmp(argv[i], "--testIO")))
822 testIO++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000823#ifdef LIBXML_XINCLUDE_ENABLED
824 else if ((!strcmp(argv[i], "-xinclude")) ||
825 (!strcmp(argv[i], "--xinclude")))
826 xinclude++;
827#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000828 else if ((!strcmp(argv[i], "-compress")) ||
829 (!strcmp(argv[i], "--compress"))) {
830 compress++;
831 xmlSetCompressMode(9);
832 }
833 else if ((!strcmp(argv[i], "-nowarning")) ||
834 (!strcmp(argv[i], "--nowarning"))) {
835 xmlGetWarningsDefaultValue = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000836 xmlPedanticParserDefault(0);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000837 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000838 else if ((!strcmp(argv[i], "-pedantic")) ||
839 (!strcmp(argv[i], "--pedantic"))) {
840 xmlGetWarningsDefaultValue = 1;
841 xmlPedanticParserDefault(1);
842 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000843#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000844 else if ((!strcmp(argv[i], "-debugent")) ||
845 (!strcmp(argv[i], "--debugent"))) {
846 debugent++;
847 xmlParserDebugEntities = 1;
848 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +0000849#endif
Daniel Veillardbe803962000-06-28 23:40:59 +0000850 else if ((!strcmp(argv[i], "-encode")) ||
851 (!strcmp(argv[i], "--encode"))) {
852 i++;
853 encoding = argv[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000854 /*
855 * OK it's for testing purposes
856 */
857 xmlAddEncodingAlias("UTF-8", "DVEnc");
Daniel Veillardbe803962000-06-28 23:40:59 +0000858 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000859 else if ((!strcmp(argv[i], "-noblanks")) ||
860 (!strcmp(argv[i], "--noblanks"))) {
861 noblanks++;
862 xmlKeepBlanksDefault(0);
863 }
864 }
865 if (noent != 0) xmlSubstituteEntitiesDefault(1);
866 if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
867 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000868 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000869 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000870 xmlGenericError(xmlGenericErrorContext,
871 "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
872 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000873 "<html><head><title>%s output</title></head>\n",
874 argv[0]);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000875 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000876 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
877 argv[0]);
878 }
879 for (i = 1; i < argc ; i++) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000880 if ((!strcmp(argv[i], "-encode")) ||
881 (!strcmp(argv[i], "--encode"))) {
882 i++;
883 continue;
884 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000885 if ((!strcmp(argv[i], "-dtdvalid")) ||
886 (!strcmp(argv[i], "--dtdvalid"))) {
887 i++;
888 continue;
889 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000890 if ((timing) && (repeat))
891 gettimeofday(&begin, NULL);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000892 /* Remember file names. "-" means stding. <sven@zen.org> */
893 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000894 if (repeat) {
895 for (count = 0;count < 100 * repeat;count++)
896 parseAndPrintFile(argv[i]);
897 } else
898 parseAndPrintFile(argv[i]);
899 files ++;
900 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000901 if ((timing) && (repeat)) {
902 long msec;
903 gettimeofday(&end, NULL);
904 msec = end.tv_sec - begin.tv_sec;
905 msec *= 1000;
906 msec += (end.tv_usec - begin.tv_usec) / 1000;
907 fprintf(stderr, "100 iteration took %ld ms\n", msec);
908 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000909 }
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000910 if (generate)
911 parseAndPrintFile(NULL);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000912 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000913 xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000914 }
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000915 if ((files == 0) && (!generate)) {
Daniel Veillard48b2f892001-02-25 16:11:03 +0000916 printf("Usage : %s [options] XMLfiles ...\n",
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000917 argv[0]);
918 printf("\tParse the XML files and output the result of the parsing\n");
919#ifdef LIBXML_DEBUG_ENABLED
920 printf("\t--debug : dump a debug tree of the in-memory document\n");
921 printf("\t--shell : run a navigating shell\n");
922 printf("\t--debugent : debug the entities defined in the document\n");
923#endif
924 printf("\t--copy : used to test the internal copy implementation\n");
925 printf("\t--recover : output what was parsable on broken XML documents\n");
926 printf("\t--noent : substitute entity references by their value\n");
927 printf("\t--noout : don't output the result tree\n");
928 printf("\t--htmlout : output results as HTML\n");
929 printf("\t--nowarp : do not put HTML doc wrapper\n");
930 printf("\t--valid : validate the document in addition to std well-formed check\n");
931 printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
Daniel Veillardcd429612000-10-11 15:57:05 +0000932 printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000933 printf("\t--timing : print some timings\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000934 printf("\t--repeat : repeat 100 times, for timing or profiling\n");
935 printf("\t--insert : ad-hoc test for valid insertions\n");
936 printf("\t--compress : turn on gzip compression of output\n");
937#ifdef LIBXML_HTML_ENABLED
938 printf("\t--html : use the HTML parser\n");
939#endif
940 printf("\t--push : use the push mode of the parser\n");
Daniel Veillard46e370e2000-07-21 20:32:03 +0000941#ifdef HAVE_SYS_MMAN_H
942 printf("\t--memory : parse from memory\n");
943#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000944 printf("\t--nowarning : do not emit warnings from parser/validator\n");
945 printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
Daniel Veillard5e873c42000-04-12 13:27:38 +0000946 printf("\t--testIO : test user I/O support\n");
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000947 printf("\t--encode encoding : output in the given encoding\n");
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000948 printf("\t--auto : generate a small doc on the fly\n");
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000949#ifdef LIBXML_XINCLUDE_ENABLED
950 printf("\t--xinclude : do XInclude processing\n");
951#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000952 }
953 xmlCleanupParser();
954 xmlMemoryDump();
955
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000956 return(progresult);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000957}
Daniel Veillard88a172f2000-08-04 18:23:10 +0000958