blob: aa58625cf2e928762f27a4d7927683cfaec09693 [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>
19
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_LIBREADLINE
36#include <readline/readline.h>
37#ifdef HAVE_LIBHISTORY
38#include <readline/history.h>
39#endif
40#endif
41
42#include <libxml/xmlmemory.h>
43#include <libxml/parser.h>
44#include <libxml/parserInternals.h>
45#include <libxml/HTMLparser.h>
46#include <libxml/HTMLtree.h>
47#include <libxml/tree.h>
48#include <libxml/xpath.h>
49#include <libxml/debugXML.h>
50
51#ifdef LIBXML_DEBUG_ENABLED
52static int debug = 0;
53static int shell = 0;
54static int debugent = 0;
55#endif
56static int copy = 0;
57static int recovery = 0;
58static int noent = 0;
59static int noout = 0;
60static int nowrap = 0;
61static int valid = 0;
62static int postvalid = 0;
63static int repeat = 0;
64static int insert = 0;
65static int compress = 0;
66static int html = 0;
67static int htmlout = 0;
68static int push = 0;
69static int noblanks = 0;
70
71extern int xmlDoValidityCheckingDefaultValue;
72extern int xmlGetWarningsDefaultValue;
73
74/************************************************************************
75 * *
76 * HTML ouput *
77 * *
78 ************************************************************************/
79char buffer[50000];
80
81void
82xmlHTMLEncodeSend(void) {
83 char *result;
84
85 result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer);
86 if (result) {
87 fprintf(stderr, "%s", result);
88 xmlFree(result);
89 }
90 buffer[0] = 0;
91}
92
93/**
94 * xmlHTMLPrintFileInfo:
95 * @input: an xmlParserInputPtr input
96 *
97 * Displays the associated file and line informations for the current input
98 */
99
100void
101xmlHTMLPrintFileInfo(xmlParserInputPtr input) {
102 fprintf(stderr, "<p>");
103 if (input != NULL) {
104 if (input->filename) {
105 sprintf(&buffer[strlen(buffer)], "%s:%d: ", input->filename,
106 input->line);
107 } else {
108 sprintf(&buffer[strlen(buffer)], "Entity: line %d: ", input->line);
109 }
110 }
111 xmlHTMLEncodeSend();
112}
113
114/**
115 * xmlHTMLPrintFileContext:
116 * @input: an xmlParserInputPtr input
117 *
118 * Displays current context within the input content for error tracking
119 */
120
121void
122xmlHTMLPrintFileContext(xmlParserInputPtr input) {
123 const xmlChar *cur, *base;
124 int n;
125
126 if (input == NULL) return;
127 fprintf(stderr, "<pre>\n");
128 cur = input->cur;
129 base = input->base;
130 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
131 cur--;
132 }
133 n = 0;
134 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
135 cur--;
136 if ((*cur == '\n') || (*cur == '\r')) cur++;
137 base = cur;
138 n = 0;
139 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
140 sprintf(&buffer[strlen(buffer)], "%c", (unsigned char) *cur++);
141 n++;
142 }
143 sprintf(&buffer[strlen(buffer)], "\n");
144 cur = input->cur;
145 while ((*cur == '\n') || (*cur == '\r'))
146 cur--;
147 n = 0;
148 while ((cur != base) && (n++ < 80)) {
149 sprintf(&buffer[strlen(buffer)], " ");
150 base++;
151 }
152 sprintf(&buffer[strlen(buffer)],"^\n");
153 xmlHTMLEncodeSend();
154 fprintf(stderr, "</pre>");
155}
156
157/**
158 * xmlHTMLError:
159 * @ctx: an XML parser context
160 * @msg: the message to display/transmit
161 * @...: extra parameters for the message display
162 *
163 * Display and format an error messages, gives file, line, position and
164 * extra parameters.
165 */
166void
167xmlHTMLError(void *ctx, const char *msg, ...)
168{
169 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
170 xmlParserInputPtr input;
171 xmlParserInputPtr cur = NULL;
172 va_list args;
173
174 buffer[0] = 0;
175 input = ctxt->input;
176 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
177 cur = input;
178 input = ctxt->inputTab[ctxt->inputNr - 2];
179 }
180
181 xmlHTMLPrintFileInfo(input);
182
183 fprintf(stderr, "<b>error</b>: ");
184 va_start(args, msg);
185 vsprintf(&buffer[strlen(buffer)], msg, args);
186 va_end(args);
187 xmlHTMLEncodeSend();
188 fprintf(stderr, "</p>\n");
189
190 xmlHTMLPrintFileContext(input);
191 xmlHTMLEncodeSend();
192}
193
194/**
195 * xmlHTMLWarning:
196 * @ctx: an XML parser context
197 * @msg: the message to display/transmit
198 * @...: extra parameters for the message display
199 *
200 * Display and format a warning messages, gives file, line, position and
201 * extra parameters.
202 */
203void
204xmlHTMLWarning(void *ctx, const char *msg, ...)
205{
206 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
207 xmlParserInputPtr input;
208 xmlParserInputPtr cur = NULL;
209 va_list args;
210
211 buffer[0] = 0;
212 input = ctxt->input;
213 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
214 cur = input;
215 input = ctxt->inputTab[ctxt->inputNr - 2];
216 }
217
218
219 xmlHTMLPrintFileInfo(input);
220
221 fprintf(stderr, "<b>warning</b>: ");
222 va_start(args, msg);
223 vsprintf(&buffer[strlen(buffer)], msg, args);
224 va_end(args);
225 xmlHTMLEncodeSend();
226 fprintf(stderr, "</p>\n");
227
228 xmlHTMLPrintFileContext(input);
229 xmlHTMLEncodeSend();
230}
231
232/**
233 * xmlHTMLValidityError:
234 * @ctx: an XML parser context
235 * @msg: the message to display/transmit
236 * @...: extra parameters for the message display
237 *
238 * Display and format an validity error messages, gives file,
239 * line, position and extra parameters.
240 */
241void
242xmlHTMLValidityError(void *ctx, const char *msg, ...)
243{
244 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
245 xmlParserInputPtr input;
246 va_list args;
247
248 buffer[0] = 0;
249 input = ctxt->input;
250 if ((input->filename == NULL) && (ctxt->inputNr > 1))
251 input = ctxt->inputTab[ctxt->inputNr - 2];
252
253 xmlHTMLPrintFileInfo(input);
254
255 fprintf(stderr, "<b>validity error</b>: ");
256 va_start(args, msg);
257 vsprintf(&buffer[strlen(buffer)], msg, args);
258 va_end(args);
259 xmlHTMLEncodeSend();
260 fprintf(stderr, "</p>\n");
261
262 xmlHTMLPrintFileContext(input);
263 xmlHTMLEncodeSend();
264}
265
266/**
267 * xmlHTMLValidityWarning:
268 * @ctx: an XML parser context
269 * @msg: the message to display/transmit
270 * @...: extra parameters for the message display
271 *
272 * Display and format a validity warning messages, gives file, line,
273 * position and extra parameters.
274 */
275void
276xmlHTMLValidityWarning(void *ctx, const char *msg, ...)
277{
278 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
279 xmlParserInputPtr input;
280 va_list args;
281
282 buffer[0] = 0;
283 input = ctxt->input;
284 if ((input->filename == NULL) && (ctxt->inputNr > 1))
285 input = ctxt->inputTab[ctxt->inputNr - 2];
286
287 xmlHTMLPrintFileInfo(input);
288
289 fprintf(stderr, "<b>validity warning</b>: ");
290 va_start(args, msg);
291 vsprintf(&buffer[strlen(buffer)], msg, args);
292 va_end(args);
293 xmlHTMLEncodeSend();
294 fprintf(stderr, "</p>\n");
295
296 xmlHTMLPrintFileContext(input);
297 xmlHTMLEncodeSend();
298}
299
300/************************************************************************
301 * *
302 * Shell Interface *
303 * *
304 ************************************************************************/
305/**
306 * xmlShellReadline:
307 * @prompt: the prompt value
308 *
309 * Read a string
310 *
311 * Returns a pointer to it or NULL on EOF the caller is expected to
312 * free the returned string.
313 */
314char *
315xmlShellReadline(char *prompt) {
316#ifdef HAVE_LIBREADLINE
317 char *line_read;
318
319 /* Get a line from the user. */
320 line_read = readline (prompt);
321
322 /* If the line has any text in it, save it on the history. */
323 if (line_read && *line_read)
324 add_history (line_read);
325
326 return (line_read);
327#else
328 char line_read[501];
329
330 if (prompt != NULL)
331 fprintf(stdout, "%s", prompt);
332 if (!fgets(line_read, 500, stdin))
333 return(NULL);
334 line_read[500] = 0;
335 return(strdup(line_read));
336#endif
337}
338
339/************************************************************************
340 * *
341 * Test processing *
342 * *
343 ************************************************************************/
344void parseAndPrintFile(char *filename) {
345 xmlDocPtr doc = NULL, tmp;
346
347#ifdef LIBXML_HTML_ENABLED
348 if (html) {
349 doc = htmlParseFile(filename, NULL);
350 } else {
351#endif /* LIBXML_HTML_ENABLED */
352 /*
353 * build an XML tree from a string;
354 */
355 if (push) {
356 FILE *f;
357
358 f = fopen(filename, "r");
359 if (f != NULL) {
360 int res, size = 3;
361 char chars[1024];
362 xmlParserCtxtPtr ctxt;
363
364 if (repeat)
365 size = 1024;
366 res = fread(chars, 1, 4, f);
367 if (res > 0) {
368 ctxt = xmlCreatePushParserCtxt(NULL, NULL,
369 chars, res, filename);
370 while ((res = fread(chars, 1, size, f)) > 0) {
371 xmlParseChunk(ctxt, chars, res, 0);
372 }
373 xmlParseChunk(ctxt, chars, 0, 1);
374 doc = ctxt->myDoc;
375 xmlFreeParserCtxt(ctxt);
376 }
377 }
378 } else if (recovery) {
379 doc = xmlRecoverFile(filename);
380 } else if (htmlout) {
381 int ret;
382 xmlParserCtxtPtr ctxt;
383 xmlSAXHandler silent, *old;
384
385 ctxt = xmlCreateFileParserCtxt(filename);
386 memcpy(&silent, ctxt->sax, sizeof(silent));
387 old = ctxt->sax;
388 silent.error = xmlHTMLError;
389 if (xmlGetWarningsDefaultValue)
390 silent.warning = xmlHTMLWarning;
391 else
392 silent.warning = NULL;
393 silent.fatalError = xmlHTMLError;
394 ctxt->sax = &silent;
395 ctxt->vctxt.error = xmlHTMLValidityError;
396 if (xmlGetWarningsDefaultValue)
397 ctxt->vctxt.warning = xmlHTMLValidityWarning;
398 else
399 ctxt->vctxt.warning = NULL;
400
401 xmlParseDocument(ctxt);
402
403 ret = ctxt->wellFormed;
404 doc = ctxt->myDoc;
405 ctxt->sax = old;
406 xmlFreeParserCtxt(ctxt);
407 if (!ret) {
408 xmlFreeDoc(doc);
409 doc = NULL;
410 }
411 } else
412 doc = xmlParseFile(filename);
413#ifdef LIBXML_HTML_ENABLED
414 }
415#endif
416
417#ifdef LIBXML_DEBUG_ENABLED
418 /*
419 * shell interraction
420 */
421 if (shell)
422 xmlShell(doc, filename, xmlShellReadline, stdout);
423#endif
424
425 /*
426 * test intermediate copy if needed.
427 */
428 if (copy) {
429 tmp = doc;
430 doc = xmlCopyDoc(doc, 1);
431 xmlFreeDoc(tmp);
432 }
433
434 if ((insert) && (!html)) {
435 const xmlChar* list[256];
436 int nb, i;
437 xmlNodePtr node;
438
439 if (doc->children != NULL) {
440 node = doc->children;
441 while ((node != NULL) && (node->last == NULL)) node = node->next;
442 if (node != NULL) {
443 nb = xmlValidGetValidElements(node->last, NULL, list, 256);
444 if (nb < 0) {
445 printf("could not get valid list of elements\n");
446 } else if (nb == 0) {
447 printf("No element can be indersted under root\n");
448 } else {
449 printf("%d element types can be indersted under root:\n",
450 nb);
451 for (i = 0;i < nb;i++) {
452 printf("%s\n", list[i]);
453 }
454 }
455 }
456 }
457 }else if (noout == 0) {
458 /*
459 * print it.
460 */
461#ifdef LIBXML_DEBUG_ENABLED
462 if (!debug) {
463#endif
464 if (compress)
465 xmlSaveFile("-", doc);
466 else
467 xmlDocDump(stdout, doc);
468#ifdef LIBXML_DEBUG_ENABLED
469 } else
470 xmlDebugDumpDocument(stdout, doc);
471#endif
472 }
473
474 /*
475 * A posteriori validation test
476 */
477 if (postvalid) {
478 xmlValidCtxt cvp;
479 cvp.userData = (void *) stderr; cvp.error = (xmlValidityErrorFunc) fprintf; cvp.warning = (xmlValidityWarningFunc) fprintf;
480 xmlValidateDocument(&cvp, doc);
481 }
482
483#ifdef LIBXML_DEBUG_ENABLED
484 if ((debugent) && (!html))
485 xmlDebugDumpEntities(stdout, doc);
486#endif
487
488 /*
489 * free it.
490 */
491 xmlFreeDoc(doc);
492}
493
494int main(int argc, char **argv) {
495 int i, count;
496 int files = 0;
497
498 for (i = 1; i < argc ; i++) {
499#ifdef LIBXML_DEBUG_ENABLED
500 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
501 debug++;
502 else if ((!strcmp(argv[i], "-debugent")) || (!strcmp(argv[i], "--debugent")))
503 debugent++;
504 else if ((!strcmp(argv[i], "-shell")) ||
505 (!strcmp(argv[i], "--shell"))) {
506 shell++;
507 noout = 1;
508 } else
509#endif
510 if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
511 copy++;
512 else if ((!strcmp(argv[i], "-recover")) ||
513 (!strcmp(argv[i], "--recover")))
514 recovery++;
515 else if ((!strcmp(argv[i], "-noent")) ||
516 (!strcmp(argv[i], "--noent")))
517 noent++;
518 else if ((!strcmp(argv[i], "-noout")) ||
519 (!strcmp(argv[i], "--noout")))
520 noout++;
521 else if ((!strcmp(argv[i], "-htmlout")) ||
522 (!strcmp(argv[i], "--htmlout")))
523 htmlout++;
524#ifdef LIBXML_HTML_ENABLED
525 else if ((!strcmp(argv[i], "-html")) ||
526 (!strcmp(argv[i], "--html"))) {
527 html++;
528 }
529#endif /* LIBXML_HTML_ENABLED */
530 else if ((!strcmp(argv[i], "-nowrap")) ||
531 (!strcmp(argv[i], "--nowrap")))
532 nowrap++;
533 else if ((!strcmp(argv[i], "-valid")) ||
534 (!strcmp(argv[i], "--valid")))
535 valid++;
536 else if ((!strcmp(argv[i], "-postvalid")) ||
537 (!strcmp(argv[i], "--postvalid")))
538 postvalid++;
539 else if ((!strcmp(argv[i], "-insert")) ||
540 (!strcmp(argv[i], "--insert")))
541 insert++;
542 else if ((!strcmp(argv[i], "-repeat")) ||
543 (!strcmp(argv[i], "--repeat")))
544 repeat++;
545 else if ((!strcmp(argv[i], "-push")) ||
546 (!strcmp(argv[i], "--push")))
547 push++;
548 else if ((!strcmp(argv[i], "-compress")) ||
549 (!strcmp(argv[i], "--compress"))) {
550 compress++;
551 xmlSetCompressMode(9);
552 }
553 else if ((!strcmp(argv[i], "-nowarning")) ||
554 (!strcmp(argv[i], "--nowarning"))) {
555 xmlGetWarningsDefaultValue = 0;
556 }
557 else if ((!strcmp(argv[i], "-noblanks")) ||
558 (!strcmp(argv[i], "--noblanks"))) {
559 noblanks++;
560 xmlKeepBlanksDefault(0);
561 }
562 }
563 if (noent != 0) xmlSubstituteEntitiesDefault(1);
564 if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
565 if ((htmlout) && (!nowrap)) {
566 fprintf(stderr,
567 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
568 fprintf(stderr, "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
569 fprintf(stderr,
570 "<html><head><title>%s output</title></head>\n",
571 argv[0]);
572 fprintf(stderr,
573 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
574 argv[0]);
575 }
576 for (i = 1; i < argc ; i++) {
577 if (argv[i][0] != '-') {
578 if (repeat) {
579 for (count = 0;count < 100 * repeat;count++)
580 parseAndPrintFile(argv[i]);
581 } else
582 parseAndPrintFile(argv[i]);
583 files ++;
584 }
585 }
586 if ((htmlout) && (!nowrap)) {
587 fprintf(stderr, "</body></html>\n");
588 }
589 if (files == 0) {
590 printf("Usage : %s [--debug] [--debugent] [--copy] [--recover] [--noent] [--noout] [--valid] [--repeat] XMLfiles ...\n",
591 argv[0]);
592 printf("\tParse the XML files and output the result of the parsing\n");
593#ifdef LIBXML_DEBUG_ENABLED
594 printf("\t--debug : dump a debug tree of the in-memory document\n");
595 printf("\t--shell : run a navigating shell\n");
596 printf("\t--debugent : debug the entities defined in the document\n");
597#endif
598 printf("\t--copy : used to test the internal copy implementation\n");
599 printf("\t--recover : output what was parsable on broken XML documents\n");
600 printf("\t--noent : substitute entity references by their value\n");
601 printf("\t--noout : don't output the result tree\n");
602 printf("\t--htmlout : output results as HTML\n");
603 printf("\t--nowarp : do not put HTML doc wrapper\n");
604 printf("\t--valid : validate the document in addition to std well-formed check\n");
605 printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
606 printf("\t--repeat : repeat 100 times, for timing or profiling\n");
607 printf("\t--insert : ad-hoc test for valid insertions\n");
608 printf("\t--compress : turn on gzip compression of output\n");
609#ifdef LIBXML_HTML_ENABLED
610 printf("\t--html : use the HTML parser\n");
611#endif
612 printf("\t--push : use the push mode of the parser\n");
613 printf("\t--nowarning : do not emit warnings from parser/validator\n");
614 printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
615 }
616 xmlCleanupParser();
617 xmlMemoryDump();
618
619 return(0);
620}