blob: 5c16660981732f875ae0095fd5d150fd4461a495 [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 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * daniel@veillard.com
Daniel Veillardce8b83b2000-04-05 18:38:42 +00007 */
8
Bjorn Reese70a9da52001-04-21 16:57:29 +00009#include "libxml.h"
Daniel Veillardce8b83b2000-04-05 18:38:42 +000010
Daniel Veillardce8b83b2000-04-05 18:38:42 +000011#include <string.h>
Daniel Veillardce8b83b2000-04-05 18:38:42 +000012#include <stdarg.h>
Daniel Veillard28ae6362001-07-14 16:44:32 +000013
Daniel Veillard3c5ed912002-01-08 10:36:16 +000014#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard2d90de42001-04-16 17:46:18 +000015#ifdef _MSC_VER
16#include <winsock2.h>
17#pragma comment(lib, "ws2_32.lib")
18#define gettimeofday(p1,p2)
Daniel Veillardf216d462002-02-08 13:44:24 +000019#include <time.h>
Daniel Veillard28ae6362001-07-14 16:44:32 +000020#else /* _MSC_VER */
21#include <sys/time.h>
Daniel Veillard2d90de42001-04-16 17:46:18 +000022#endif /* _MSC_VER */
23#else /* _WIN32 */
Daniel Veillarded472f32001-12-13 08:48:14 +000024#ifdef HAVE_SYS_TIME_H
Daniel Veillard48b2f892001-02-25 16:11:03 +000025#include <sys/time.h>
Daniel Veillarded472f32001-12-13 08:48:14 +000026#endif
Daniel Veillard01db67c2001-12-18 07:09:59 +000027#ifdef HAVE_TIME_H
28#include <time.h>
29#endif
Daniel Veillard2d90de42001-04-16 17:46:18 +000030#endif /* _WIN32 */
Daniel Veillard48b2f892001-02-25 16:11:03 +000031
Daniel Veillard90bc3712002-03-07 15:12:58 +000032#ifdef HAVE_SYS_TIMEB_H
33#include <sys/timeb.h>
34#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +000035
36#ifdef HAVE_SYS_TYPES_H
37#include <sys/types.h>
38#endif
39#ifdef HAVE_SYS_STAT_H
40#include <sys/stat.h>
41#endif
42#ifdef HAVE_FCNTL_H
43#include <fcntl.h>
44#endif
45#ifdef HAVE_UNISTD_H
46#include <unistd.h>
47#endif
Daniel Veillard46e370e2000-07-21 20:32:03 +000048#ifdef HAVE_SYS_MMAN_H
49#include <sys/mman.h>
Daniel Veillard87b95392000-08-12 21:12:04 +000050/* seems needed for Solaris */
51#ifndef MAP_FAILED
52#define MAP_FAILED ((void *) -1)
53#endif
Daniel Veillard46e370e2000-07-21 20:32:03 +000054#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +000055#ifdef HAVE_STDLIB_H
56#include <stdlib.h>
57#endif
58#ifdef HAVE_LIBREADLINE
59#include <readline/readline.h>
60#ifdef HAVE_LIBHISTORY
61#include <readline/history.h>
62#endif
63#endif
64
65#include <libxml/xmlmemory.h>
66#include <libxml/parser.h>
67#include <libxml/parserInternals.h>
68#include <libxml/HTMLparser.h>
69#include <libxml/HTMLtree.h>
70#include <libxml/tree.h>
71#include <libxml/xpath.h>
72#include <libxml/debugXML.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000073#include <libxml/xmlerror.h>
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000074#ifdef LIBXML_XINCLUDE_ENABLED
75#include <libxml/xinclude.h>
76#endif
Daniel Veillard81418e32001-05-22 15:08:55 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard89cad532001-10-22 09:46:13 +000080#ifdef LIBXML_DOCB_ENABLED
81#include <libxml/DOCBparser.h>
82#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000083#include <libxml/globals.h>
Daniel Veillardce8b83b2000-04-05 18:38:42 +000084
85#ifdef LIBXML_DEBUG_ENABLED
86static int debug = 0;
87static int shell = 0;
88static int debugent = 0;
89#endif
90static int copy = 0;
91static int recovery = 0;
92static int noent = 0;
93static int noout = 0;
94static int nowrap = 0;
95static int valid = 0;
96static int postvalid = 0;
Daniel Veillardcd429612000-10-11 15:57:05 +000097static char * dtdvalid = NULL;
Daniel Veillardce8b83b2000-04-05 18:38:42 +000098static int repeat = 0;
99static int insert = 0;
100static int compress = 0;
Daniel Veillard89cad532001-10-22 09:46:13 +0000101#ifdef LIBXML_DOCB_ENABLED
102static int sgml = 0;
103#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000104static int html = 0;
105static int htmlout = 0;
106static int push = 0;
Daniel Veillard46e370e2000-07-21 20:32:03 +0000107#ifdef HAVE_SYS_MMAN_H
108static int memory = 0;
109#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000110static int noblanks = 0;
Daniel Veillard90493a92001-08-14 14:12:47 +0000111static int format = 0;
Daniel Veillard5e873c42000-04-12 13:27:38 +0000112static int testIO = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +0000113static char *encoding = NULL;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000114#ifdef LIBXML_XINCLUDE_ENABLED
115static int xinclude = 0;
116#endif
Daniel Veillard48da9102001-08-07 01:10:10 +0000117static int dtdattrs = 0;
Daniel Veillard10ea86c2001-06-20 13:55:33 +0000118static int loaddtd = 0;
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000119static int progresult = 0;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000120static int timing = 0;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000121static int generate = 0;
Daniel Veillard29e43992001-12-13 22:21:58 +0000122static int dropdtd = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000123#ifdef LIBXML_CATALOG_ENABLED
124static int catalogs = 0;
125static int nocatalogs = 0;
126#endif
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000127static const char *output = NULL;
128
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000129
Daniel Veillard01db67c2001-12-18 07:09:59 +0000130/*
131 * Internal timing routines to remove the necessity to have unix-specific
132 * function calls
133 */
134
Daniel Veillard8c1ae602002-03-07 11:21:00 +0000135#ifndef HAVE_GETTIMEOFDAY
136#ifdef HAVE_SYS_TIMEB_H
137#ifdef HAVE_SYS_TIME_H
138#ifdef HAVE_FTIME
139
Daniel Veillard01c13b52002-12-10 15:19:08 +0000140static int
Daniel Veillard8c1ae602002-03-07 11:21:00 +0000141my_gettimeofday(struct timeval *tvp, void *tzp)
142{
143 struct timeb timebuffer;
144
145 ftime(&timebuffer);
146 if (tvp) {
147 tvp->tv_sec = timebuffer.time;
148 tvp->tv_usec = timebuffer.millitm * 1000L;
149 }
150 return (0);
151}
152#define HAVE_GETTIMEOFDAY 1
153#define gettimeofday my_gettimeofday
154
155#endif /* HAVE_FTIME */
156#endif /* HAVE_SYS_TIME_H */
157#endif /* HAVE_SYS_TIMEB_H */
158#endif /* !HAVE_GETTIMEOFDAY */
159
Daniel Veillard01db67c2001-12-18 07:09:59 +0000160#if defined(HAVE_GETTIMEOFDAY)
161static struct timeval begin, end;
162
163/*
164 * startTimer: call where you want to start timing
165 */
166static void
167startTimer(void)
168{
169 gettimeofday(&begin, NULL);
170}
171
172/*
173 * endTimer: call where you want to stop timing and to print out a
174 * message about the timing performed; format is a printf
175 * type argument
176 */
177static void
Daniel Veillard118aed72002-09-24 14:13:13 +0000178endTimer(const char *fmt, ...)
Daniel Veillard01db67c2001-12-18 07:09:59 +0000179{
180 long msec;
181 va_list ap;
182
183 gettimeofday(&end, NULL);
184 msec = end.tv_sec - begin.tv_sec;
185 msec *= 1000;
186 msec += (end.tv_usec - begin.tv_usec) / 1000;
187
188#ifndef HAVE_STDARG_H
189#error "endTimer required stdarg functions"
190#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000191 va_start(ap, fmt);
192 vfprintf(stderr, fmt, ap);
Daniel Veillard01db67c2001-12-18 07:09:59 +0000193 va_end(ap);
194
195 fprintf(stderr, " took %ld ms\n", msec);
196}
197#elif defined(HAVE_TIME_H)
Daniel Veillard01db67c2001-12-18 07:09:59 +0000198/*
199 * No gettimeofday function, so we have to make do with calling clock.
200 * This is obviously less accurate, but there's little we can do about
201 * that.
202 */
Daniel Veillard90bc3712002-03-07 15:12:58 +0000203#ifndef CLOCKS_PER_SEC
204#define CLOCKS_PER_SEC 100
205#endif
Daniel Veillard01db67c2001-12-18 07:09:59 +0000206
207static clock_t begin, end;
208static void
209startTimer(void)
210{
211 begin = clock();
212}
213static void
214endTimer(const char *fmt, ...)
215{
216 long msec;
217 va_list ap;
218
219 end = clock();
220 msec = ((end - begin) * 1000) / CLOCKS_PER_SEC;
221
222#ifndef HAVE_STDARG_H
223#error "endTimer required stdarg functions"
224#endif
225 va_start(ap, fmt);
226 vfprintf(stderr, fmt, ap);
227 va_end(ap);
228 fprintf(stderr, " took %ld ms\n", msec);
229}
230#else
231
232/*
233 * We don't have a gettimeofday or time.h, so we just don't do timing
234 */
235static void
236startTimer(void)
237{
238 /*
239 * Do nothing
240 */
241}
242static void
243endTimer(char *format, ...)
244{
245 /*
246 * We cannot do anything because we don't have a timing function
247 */
248#ifdef HAVE_STDARG_H
249 va_start(ap, format);
250 vfprintf(stderr, format, ap);
251 va_end(ap);
252 fprintf(stderr, " was not timed\n", msec);
253#else
254 /* We don't have gettimeofday, time or stdarg.h, what crazy world is
255 * this ?!
256 */
257#endif
258}
259#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000260/************************************************************************
261 * *
262 * HTML ouput *
263 * *
264 ************************************************************************/
265char buffer[50000];
266
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000267static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000268xmlHTMLEncodeSend(void) {
269 char *result;
270
271 result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer);
272 if (result) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000273 xmlGenericError(xmlGenericErrorContext, "%s", result);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000274 xmlFree(result);
275 }
276 buffer[0] = 0;
277}
278
279/**
280 * xmlHTMLPrintFileInfo:
281 * @input: an xmlParserInputPtr input
282 *
283 * Displays the associated file and line informations for the current input
284 */
285
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000286static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000287xmlHTMLPrintFileInfo(xmlParserInputPtr input) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000288 int len;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000289 xmlGenericError(xmlGenericErrorContext, "<p>");
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000290
291 len = strlen(buffer);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000292 if (input != NULL) {
293 if (input->filename) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000294 snprintf(&buffer[len], sizeof(buffer) - len, "%s:%d: ", input->filename,
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000295 input->line);
296 } else {
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000297 snprintf(&buffer[len], sizeof(buffer) - len, "Entity: line %d: ", input->line);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000298 }
299 }
300 xmlHTMLEncodeSend();
301}
302
303/**
304 * xmlHTMLPrintFileContext:
305 * @input: an xmlParserInputPtr input
306 *
307 * Displays current context within the input content for error tracking
308 */
309
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000310static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000311xmlHTMLPrintFileContext(xmlParserInputPtr input) {
312 const xmlChar *cur, *base;
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000313 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000314 int n;
315
316 if (input == NULL) return;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000317 xmlGenericError(xmlGenericErrorContext, "<pre>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000318 cur = input->cur;
319 base = input->base;
320 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
321 cur--;
322 }
323 n = 0;
324 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
325 cur--;
326 if ((*cur == '\n') || (*cur == '\r')) cur++;
327 base = cur;
328 n = 0;
329 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000330 len = strlen(buffer);
331 snprintf(&buffer[len], sizeof(buffer) - len, "%c",
332 (unsigned char) *cur++);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000333 n++;
334 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000335 len = strlen(buffer);
336 snprintf(&buffer[len], sizeof(buffer) - len, "\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000337 cur = input->cur;
338 while ((*cur == '\n') || (*cur == '\r'))
339 cur--;
340 n = 0;
341 while ((cur != base) && (n++ < 80)) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000342 len = strlen(buffer);
343 snprintf(&buffer[len], sizeof(buffer) - len, " ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000344 base++;
345 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000346 len = strlen(buffer);
347 snprintf(&buffer[len], sizeof(buffer) - len, "^\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000348 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000349 xmlGenericError(xmlGenericErrorContext, "</pre>");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000350}
351
352/**
353 * xmlHTMLError:
354 * @ctx: an XML parser context
355 * @msg: the message to display/transmit
356 * @...: extra parameters for the message display
357 *
358 * Display and format an error messages, gives file, line, position and
359 * extra parameters.
360 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000361static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000362xmlHTMLError(void *ctx, const char *msg, ...)
363{
364 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
365 xmlParserInputPtr input;
366 xmlParserInputPtr cur = NULL;
367 va_list args;
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000368 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000369
370 buffer[0] = 0;
371 input = ctxt->input;
372 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
373 cur = input;
374 input = ctxt->inputTab[ctxt->inputNr - 2];
375 }
376
377 xmlHTMLPrintFileInfo(input);
378
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000379 xmlGenericError(xmlGenericErrorContext, "<b>error</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000380 va_start(args, msg);
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000381 len = strlen(buffer);
382 vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000383 va_end(args);
384 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000385 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000386
387 xmlHTMLPrintFileContext(input);
388 xmlHTMLEncodeSend();
389}
390
391/**
392 * xmlHTMLWarning:
393 * @ctx: an XML parser context
394 * @msg: the message to display/transmit
395 * @...: extra parameters for the message display
396 *
397 * Display and format a warning messages, gives file, line, position and
398 * extra parameters.
399 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000400static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000401xmlHTMLWarning(void *ctx, const char *msg, ...)
402{
403 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
404 xmlParserInputPtr input;
405 xmlParserInputPtr cur = NULL;
406 va_list args;
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000407 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000408
409 buffer[0] = 0;
410 input = ctxt->input;
411 if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
412 cur = input;
413 input = ctxt->inputTab[ctxt->inputNr - 2];
414 }
415
416
417 xmlHTMLPrintFileInfo(input);
418
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000419 xmlGenericError(xmlGenericErrorContext, "<b>warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000420 va_start(args, msg);
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000421 len = strlen(buffer);
422 vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000423 va_end(args);
424 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000425 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000426
427 xmlHTMLPrintFileContext(input);
428 xmlHTMLEncodeSend();
429}
430
431/**
432 * xmlHTMLValidityError:
433 * @ctx: an XML parser context
434 * @msg: the message to display/transmit
435 * @...: extra parameters for the message display
436 *
437 * Display and format an validity error messages, gives file,
438 * line, position and extra parameters.
439 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000440static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000441xmlHTMLValidityError(void *ctx, const char *msg, ...)
442{
443 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
444 xmlParserInputPtr input;
445 va_list args;
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000446 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000447
448 buffer[0] = 0;
449 input = ctxt->input;
450 if ((input->filename == NULL) && (ctxt->inputNr > 1))
451 input = ctxt->inputTab[ctxt->inputNr - 2];
452
453 xmlHTMLPrintFileInfo(input);
454
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000455 xmlGenericError(xmlGenericErrorContext, "<b>validity error</b>: ");
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000456 len = strlen(buffer);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000457 va_start(args, msg);
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000458 vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000459 va_end(args);
460 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000461 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000462
463 xmlHTMLPrintFileContext(input);
464 xmlHTMLEncodeSend();
465}
466
467/**
468 * xmlHTMLValidityWarning:
469 * @ctx: an XML parser context
470 * @msg: the message to display/transmit
471 * @...: extra parameters for the message display
472 *
473 * Display and format a validity warning messages, gives file, line,
474 * position and extra parameters.
475 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000476static void
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000477xmlHTMLValidityWarning(void *ctx, const char *msg, ...)
478{
479 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
480 xmlParserInputPtr input;
481 va_list args;
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000482 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000483
484 buffer[0] = 0;
485 input = ctxt->input;
486 if ((input->filename == NULL) && (ctxt->inputNr > 1))
487 input = ctxt->inputTab[ctxt->inputNr - 2];
488
489 xmlHTMLPrintFileInfo(input);
490
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000491 xmlGenericError(xmlGenericErrorContext, "<b>validity warning</b>: ");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000492 va_start(args, msg);
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000493 len = strlen(buffer);
494 vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000495 va_end(args);
496 xmlHTMLEncodeSend();
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000497 xmlGenericError(xmlGenericErrorContext, "</p>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000498
499 xmlHTMLPrintFileContext(input);
500 xmlHTMLEncodeSend();
501}
502
503/************************************************************************
504 * *
505 * Shell Interface *
506 * *
507 ************************************************************************/
508/**
509 * xmlShellReadline:
510 * @prompt: the prompt value
511 *
512 * Read a string
513 *
514 * Returns a pointer to it or NULL on EOF the caller is expected to
515 * free the returned string.
516 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000517static char *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000518xmlShellReadline(char *prompt) {
519#ifdef HAVE_LIBREADLINE
520 char *line_read;
521
522 /* Get a line from the user. */
523 line_read = readline (prompt);
524
525 /* If the line has any text in it, save it on the history. */
526 if (line_read && *line_read)
527 add_history (line_read);
528
529 return (line_read);
530#else
531 char line_read[501];
Daniel Veillard29e43992001-12-13 22:21:58 +0000532 char *ret;
533 int len;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000534
535 if (prompt != NULL)
536 fprintf(stdout, "%s", prompt);
537 if (!fgets(line_read, 500, stdin))
538 return(NULL);
539 line_read[500] = 0;
Daniel Veillard29e43992001-12-13 22:21:58 +0000540 len = strlen(line_read);
541 ret = (char *) malloc(len + 1);
542 if (ret != NULL) {
543 memcpy (ret, line_read, len + 1);
544 }
545 return(ret);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000546#endif
547}
548
549/************************************************************************
550 * *
Daniel Veillard5e873c42000-04-12 13:27:38 +0000551 * I/O Interfaces *
552 * *
553 ************************************************************************/
554
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000555static int myRead(FILE *f, char * buf, int len) {
556 return(fread(buf, 1, len, f));
Daniel Veillard5e873c42000-04-12 13:27:38 +0000557}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000558static void myClose(FILE *f) {
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000559 if (f != stdin) {
Daniel Veillard5e873c42000-04-12 13:27:38 +0000560 fclose(f);
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000561 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000562}
563
564/************************************************************************
565 * *
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000566 * Test processing *
567 * *
568 ************************************************************************/
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000569static void parseAndPrintFile(char *filename) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000570 xmlDocPtr doc = NULL, tmp;
571
Daniel Veillard48b2f892001-02-25 16:11:03 +0000572 if ((timing) && (!repeat))
Daniel Veillard01db67c2001-12-18 07:09:59 +0000573 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000574
575
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000576 if (filename == NULL) {
577 if (generate) {
578 xmlNodePtr n;
579
580 doc = xmlNewDoc(BAD_CAST "1.0");
581 n = xmlNewNode(NULL, BAD_CAST "info");
582 xmlNodeSetContent(n, BAD_CAST "abc");
583 xmlDocSetRootElement(doc, n);
584 }
585 }
Daniel Veillard89cad532001-10-22 09:46:13 +0000586#ifdef LIBXML_DOCB_ENABLED
587 /*
588 * build an SGML tree from a string;
589 */
590 else if ((sgml) && (push)) {
591 FILE *f;
592
593 f = fopen(filename, "r");
594 if (f != NULL) {
595 int res, size = 3;
596 char chars[4096];
597 docbParserCtxtPtr ctxt;
598
599 /* if (repeat) */
600 size = 4096;
601 res = fread(chars, 1, 4, f);
602 if (res > 0) {
603 ctxt = docbCreatePushParserCtxt(NULL, NULL,
604 chars, res, filename, 0);
605 while ((res = fread(chars, 1, size, f)) > 0) {
606 docbParseChunk(ctxt, chars, res, 0);
607 }
608 docbParseChunk(ctxt, chars, 0, 1);
609 doc = ctxt->myDoc;
610 docbFreeParserCtxt(ctxt);
611 }
612 fclose(f);
613 }
614 } else if (sgml) {
615 doc = docbParseFile(filename, NULL);
616 }
617#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000618#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000619 else if (html) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000620 doc = htmlParseFile(filename, NULL);
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000621 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000622#endif /* LIBXML_HTML_ENABLED */
Daniel Veillardd2f3ec72001-04-11 07:50:02 +0000623 else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000624 /*
625 * build an XML tree from a string;
626 */
627 if (push) {
628 FILE *f;
629
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000630 /* '-' Usually means stdin -<sven@zen.org> */
631 if ((filename[0] == '-') && (filename[1] == 0)) {
632 f = stdin;
633 } else {
634 f = fopen(filename, "r");
635 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000636 if (f != NULL) {
Daniel Veillarde715dd22000-08-29 18:29:38 +0000637 int ret;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000638 int res, size = 3;
639 char chars[1024];
640 xmlParserCtxtPtr ctxt;
641
642 if (repeat)
643 size = 1024;
644 res = fread(chars, 1, 4, f);
645 if (res > 0) {
646 ctxt = xmlCreatePushParserCtxt(NULL, NULL,
647 chars, res, filename);
648 while ((res = fread(chars, 1, size, f)) > 0) {
649 xmlParseChunk(ctxt, chars, res, 0);
650 }
651 xmlParseChunk(ctxt, chars, 0, 1);
652 doc = ctxt->myDoc;
Daniel Veillarde715dd22000-08-29 18:29:38 +0000653 ret = ctxt->wellFormed;
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000654 xmlFreeParserCtxt(ctxt);
Daniel Veillarde715dd22000-08-29 18:29:38 +0000655 if (!ret) {
656 xmlFreeDoc(doc);
657 doc = NULL;
658 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000659 }
660 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000661 } else if (testIO) {
662 int ret;
663 FILE *f;
664
Daniel Veillard4a6845d2001-01-03 13:32:39 +0000665 /* '-' Usually means stdin -<sven@zen.org> */
666 if ((filename[0] == '-') && (filename[1] == 0)) {
667 f = stdin;
668 } else {
669 f = fopen(filename, "r");
670 }
Daniel Veillard5e873c42000-04-12 13:27:38 +0000671 if (f != NULL) {
672 xmlParserCtxtPtr ctxt;
673
674 ctxt = xmlCreateIOParserCtxt(NULL, NULL,
675 (xmlInputReadCallback) myRead,
676 (xmlInputCloseCallback) myClose,
677 f, XML_CHAR_ENCODING_NONE);
678 xmlParseDocument(ctxt);
679
680 ret = ctxt->wellFormed;
681 doc = ctxt->myDoc;
682 xmlFreeParserCtxt(ctxt);
683 if (!ret) {
684 xmlFreeDoc(doc);
685 doc = NULL;
686 }
687 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000688 } else if (recovery) {
689 doc = xmlRecoverFile(filename);
690 } else if (htmlout) {
691 int ret;
692 xmlParserCtxtPtr ctxt;
693 xmlSAXHandler silent, *old;
694
695 ctxt = xmlCreateFileParserCtxt(filename);
Daniel Veillard88a172f2000-08-04 18:23:10 +0000696
697 if (ctxt == NULL) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000698 /* If xmlCreateFileParserCtxt() return NULL something
Daniel Veillard88a172f2000-08-04 18:23:10 +0000699 strange happened so we don't want to do anything. Do
700 we want to print an error message here?
701 <sven@zen.org> */
Daniel Veillard7ebb1ee2000-08-04 18:24:45 +0000702 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000703 } else {
704 memcpy(&silent, ctxt->sax, sizeof(silent));
705 old = ctxt->sax;
706 silent.error = xmlHTMLError;
707 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000708 silent.warning = xmlHTMLWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000709 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000710 silent.warning = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000711 silent.fatalError = xmlHTMLError;
712 ctxt->sax = &silent;
713 ctxt->vctxt.error = xmlHTMLValidityError;
714 if (xmlGetWarningsDefaultValue)
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000715 ctxt->vctxt.warning = xmlHTMLValidityWarning;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000716 else
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000717 ctxt->vctxt.warning = NULL;
718
Daniel Veillard88a172f2000-08-04 18:23:10 +0000719 xmlParseDocument(ctxt);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000720
Daniel Veillard88a172f2000-08-04 18:23:10 +0000721 ret = ctxt->wellFormed;
722 doc = ctxt->myDoc;
723 ctxt->sax = old;
724 xmlFreeParserCtxt(ctxt);
725 if (!ret) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000726 xmlFreeDoc(doc);
727 doc = NULL;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000728 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000729 }
Daniel Veillard46e370e2000-07-21 20:32:03 +0000730#ifdef HAVE_SYS_MMAN_H
731 } else if (memory) {
732 int fd;
733 struct stat info;
734 const char *base;
735 if (stat(filename, &info) < 0)
736 return;
737 if ((fd = open(filename, O_RDONLY)) < 0)
738 return;
739 base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ;
Daniel Veillard29579362000-08-14 17:57:48 +0000740 if (base == (void *) MAP_FAILED)
Daniel Veillard46e370e2000-07-21 20:32:03 +0000741 return;
742
743 doc = xmlParseMemory((char *) base, info.st_size);
744 munmap((char *) base, info.st_size);
745#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000746 } else if (valid) {
747 int ret;
748 xmlParserCtxtPtr ctxt;
749
750 ctxt = xmlCreateFileParserCtxt(filename);
751
752 if (ctxt == NULL) {
753 doc = NULL;
754 } else {
755 xmlParseDocument(ctxt);
756 if (ctxt->valid == 0)
757 progresult = 4;
758 ret = ctxt->wellFormed;
759 doc = ctxt->myDoc;
760 xmlFreeParserCtxt(ctxt);
761 if (!ret) {
762 xmlFreeDoc(doc);
763 doc = NULL;
764 }
765 }
766 } else {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000767 doc = xmlParseFile(filename);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000768 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000769 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000770
Daniel Veillard88a172f2000-08-04 18:23:10 +0000771 /*
772 * If we don't have a document we might as well give up. Do we
773 * want an error message here? <sven@zen.org> */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000774 if (doc == NULL) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000775 progresult = 1;
Daniel Veillard88a172f2000-08-04 18:23:10 +0000776 return;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000777 }
778
Daniel Veillard48b2f892001-02-25 16:11:03 +0000779 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000780 endTimer("Parsing");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000781 }
782
Daniel Veillard29e43992001-12-13 22:21:58 +0000783 /*
784 * Remove DOCTYPE nodes
785 */
786 if (dropdtd) {
787 xmlDtdPtr dtd;
788
789 dtd = xmlGetIntSubset(doc);
790 if (dtd != NULL) {
791 xmlUnlinkNode((xmlNodePtr)dtd);
792 xmlFreeDtd(dtd);
793 }
794 }
795
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000796#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard48b2f892001-02-25 16:11:03 +0000797 if (xinclude) {
798 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000799 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000800 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000801 xmlXIncludeProcess(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000802 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000803 endTimer("Xinclude processing");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000804 }
805 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000806#endif
Daniel Veillard88a172f2000-08-04 18:23:10 +0000807
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000808#ifdef LIBXML_DEBUG_ENABLED
809 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000810 * shell interaction
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000811 */
812 if (shell)
813 xmlShell(doc, filename, xmlShellReadline, stdout);
814#endif
815
816 /*
817 * test intermediate copy if needed.
818 */
819 if (copy) {
820 tmp = doc;
821 doc = xmlCopyDoc(doc, 1);
822 xmlFreeDoc(tmp);
823 }
824
825 if ((insert) && (!html)) {
826 const xmlChar* list[256];
827 int nb, i;
828 xmlNodePtr node;
829
830 if (doc->children != NULL) {
831 node = doc->children;
832 while ((node != NULL) && (node->last == NULL)) node = node->next;
833 if (node != NULL) {
834 nb = xmlValidGetValidElements(node->last, NULL, list, 256);
835 if (nb < 0) {
836 printf("could not get valid list of elements\n");
837 } else if (nb == 0) {
MDT 2001 John Fleckbbb9e432001-09-24 03:08:43 +0000838 printf("No element can be inserted under root\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000839 } else {
MDT 2001 John Fleckbbb9e432001-09-24 03:08:43 +0000840 printf("%d element types can be inserted under root:\n",
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000841 nb);
842 for (i = 0;i < nb;i++) {
843 printf("%s\n", list[i]);
844 }
845 }
846 }
847 }
848 }else if (noout == 0) {
849 /*
850 * print it.
851 */
852#ifdef LIBXML_DEBUG_ENABLED
853 if (!debug) {
854#endif
Daniel Veillard48b2f892001-02-25 16:11:03 +0000855 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000856 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000857 }
Daniel Veillard3b2c2612001-04-04 00:09:00 +0000858#ifdef HAVE_SYS_MMAN_H
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000859 if (memory) {
860 xmlChar *result;
861 int len;
862
863 if (encoding != NULL) {
Daniel Veillardd536f702001-11-08 17:32:47 +0000864 if ( format ) {
865 xmlDocDumpFormatMemoryEnc(doc, &result, &len, encoding, 1);
866 } else {
867 xmlDocDumpMemoryEnc(doc, &result, &len, encoding);
868 }
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000869 } else {
Daniel Veillard90493a92001-08-14 14:12:47 +0000870 if (format)
871 xmlDocDumpFormatMemory(doc, &result, &len, 1);
872 else
873 xmlDocDumpMemory(doc, &result, &len);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000874 }
875 if (result == NULL) {
876 fprintf(stderr, "Failed to save\n");
877 } else {
878 write(1, result, len);
879 xmlFree(result);
880 }
Daniel Veillard3b2c2612001-04-04 00:09:00 +0000881 } else
882#endif /* HAVE_SYS_MMAN_H */
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000883 if (compress) {
884 xmlSaveFile(output ? output : "-", doc);
885 }
Daniel Veillardd536f702001-11-08 17:32:47 +0000886 else if (encoding != NULL) {
887 if ( format ) {
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000888 xmlSaveFormatFileEnc(output ? output : "-", doc, encoding, 1);
889 }
Daniel Veillardd536f702001-11-08 17:32:47 +0000890 else {
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000891 xmlSaveFileEnc(output ? output : "-", doc, encoding);
Daniel Veillardd536f702001-11-08 17:32:47 +0000892 }
893 }
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000894 else if (format) {
895 xmlSaveFormatFile(output ? output : "-", doc, 1);
896 }
897 else {
898 FILE *out;
899 if (output == NULL)
900 out = stdout;
901 else {
902 out = fopen(output,"wb");
903 }
904 xmlDocDump(out, doc);
905
906 if (output)
907 fclose(out);
908 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000909 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000910 endTimer("Saving");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000911 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000912#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000913 } else {
Daniel Veillard1df3dfc2001-12-18 11:14:16 +0000914 FILE *out;
915 if (output == NULL)
916 out = stdout;
917 else {
918 out = fopen(output,"wb");
919 }
920 xmlDebugDumpDocument(out, doc);
921
922 if (output)
923 fclose(out);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000924 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000925#endif
926 }
927
928 /*
929 * A posteriori validation test
930 */
Daniel Veillardcd429612000-10-11 15:57:05 +0000931 if (dtdvalid != NULL) {
932 xmlDtdPtr dtd;
933
Daniel Veillard48b2f892001-02-25 16:11:03 +0000934 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000935 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000936 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000937 dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000938 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000939 endTimer("Parsing DTD");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000940 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000941 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000942 xmlGenericError(xmlGenericErrorContext,
943 "Could not parse DTD %s\n", dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000944 progresult = 2;
Daniel Veillardcd429612000-10-11 15:57:05 +0000945 } else {
946 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000947 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000948 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000949 }
Daniel Veillard01db67c2001-12-18 07:09:59 +0000950 cvp.userData = (void *) stderr;
951 cvp.error = (xmlValidityErrorFunc) fprintf;
952 cvp.warning = (xmlValidityWarningFunc) fprintf;
Daniel Veillardcd429612000-10-11 15:57:05 +0000953 if (!xmlValidateDtd(&cvp, doc, dtd)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000954 xmlGenericError(xmlGenericErrorContext,
955 "Document %s does not validate against %s\n",
Daniel Veillardcd429612000-10-11 15:57:05 +0000956 filename, dtdvalid);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000957 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000958 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000959 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000960 endTimer("Validating against DTD");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000961 }
Daniel Veillardcd429612000-10-11 15:57:05 +0000962 xmlFreeDtd(dtd);
963 }
964 } else if (postvalid) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000965 xmlValidCtxt cvp;
Daniel Veillard48b2f892001-02-25 16:11:03 +0000966 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000967 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000968 }
Daniel Veillardb7664f42001-08-19 13:00:43 +0000969 cvp.userData = (void *) stderr;
970 cvp.error = (xmlValidityErrorFunc) fprintf;
971 cvp.warning = (xmlValidityWarningFunc) fprintf;
Daniel Veillardcd429612000-10-11 15:57:05 +0000972 if (!xmlValidateDocument(&cvp, doc)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000973 xmlGenericError(xmlGenericErrorContext,
974 "Document %s does not validate\n", filename);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000975 progresult = 3;
Daniel Veillardcd429612000-10-11 15:57:05 +0000976 }
Daniel Veillard48b2f892001-02-25 16:11:03 +0000977 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000978 endTimer("Validating");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000979 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000980 }
981
982#ifdef LIBXML_DEBUG_ENABLED
983 if ((debugent) && (!html))
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000984 xmlDebugDumpEntities(stderr, doc);
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000985#endif
986
987 /*
988 * free it.
989 */
Daniel Veillard48b2f892001-02-25 16:11:03 +0000990 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000991 startTimer();
Daniel Veillard48b2f892001-02-25 16:11:03 +0000992 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000993 xmlFreeDoc(doc);
Daniel Veillard48b2f892001-02-25 16:11:03 +0000994 if ((timing) && (!repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +0000995 endTimer("Freeing");
Daniel Veillard48b2f892001-02-25 16:11:03 +0000996 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +0000997}
998
Daniel Veillard10ea86c2001-06-20 13:55:33 +0000999/************************************************************************
1000 * *
1001 * Usage and Main *
1002 * *
1003 ************************************************************************/
1004
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00001005static void showVersion(const char *name) {
1006 fprintf(stderr, "%s: using libxml version %s\n", name, xmlParserVersion);
1007 fprintf(stderr, " compiled with: ");
1008#ifdef LIBXML_FTP_ENABLED
1009 fprintf(stderr, "FTP ");
1010#endif
1011#ifdef LIBXML_HTTP_ENABLED
1012 fprintf(stderr, "HTTP ");
1013#endif
1014#ifdef LIBXML_HTML_ENABLED
1015 fprintf(stderr, "HTML ");
1016#endif
1017#ifdef LIBXML_C14N_ENABLED
1018 fprintf(stderr, "C14N ");
1019#endif
1020#ifdef LIBXML_CATALOG_ENABLED
1021 fprintf(stderr, "Catalog ");
1022#endif
1023#ifdef LIBXML_DOCB_ENABLED
1024 fprintf(stderr, "DocBook ");
1025#endif
1026#ifdef LIBXML_XPATH_ENABLED
1027 fprintf(stderr, "XPath ");
1028#endif
1029#ifdef LIBXML_XPTR_ENABLED
1030 fprintf(stderr, "XPointer ");
1031#endif
1032#ifdef LIBXML_XINCLUDE_ENABLED
1033 fprintf(stderr, "XInclude ");
1034#endif
1035#ifdef LIBXML_ICONV_ENABLED
1036 fprintf(stderr, "Iconv ");
1037#endif
1038#ifdef DEBUG_MEMORY_LOCATION
1039 fprintf(stderr, "MemDebug ");
1040#endif
1041#ifdef LIBXML_UNICODE_ENABLED
1042 fprintf(stderr, "Unicode ");
1043#endif
1044#ifdef LIBXML_REGEXP_ENABLED
1045 fprintf(stderr, "Regexps ");
1046#endif
1047#ifdef LIBXML_AUTOMATA_ENABLED
1048 fprintf(stderr, "Automata ");
1049#endif
1050#ifdef LIBXML_SCHEMAS_ENABLED
1051 fprintf(stderr, "Schemas ");
1052#endif
1053 fprintf(stderr, "\n");
1054}
1055
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001056static void usage(const char *name) {
1057 printf("Usage : %s [options] XMLfiles ...\n", name);
1058 printf("\tParse the XML files and output the result of the parsing\n");
1059 printf("\t--version : display the version of the XML library used\n");
1060#ifdef LIBXML_DEBUG_ENABLED
1061 printf("\t--debug : dump a debug tree of the in-memory document\n");
1062 printf("\t--shell : run a navigating shell\n");
1063 printf("\t--debugent : debug the entities defined in the document\n");
1064#endif
1065 printf("\t--copy : used to test the internal copy implementation\n");
1066 printf("\t--recover : output what was parsable on broken XML documents\n");
1067 printf("\t--noent : substitute entity references by their value\n");
1068 printf("\t--noout : don't output the result tree\n");
1069 printf("\t--htmlout : output results as HTML\n");
Daniel Veillard05c13a22001-09-09 08:38:09 +00001070 printf("\t--nowrap : do not put HTML doc wrapper\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001071 printf("\t--valid : validate the document in addition to std well-formed check\n");
1072 printf("\t--postvalid : do a posteriori validation, i.e after parsing\n");
1073 printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
1074 printf("\t--timing : print some timings\n");
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001075 printf("\t--output file or -o file: save to a given file\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001076 printf("\t--repeat : repeat 100 times, for timing or profiling\n");
1077 printf("\t--insert : ad-hoc test for valid insertions\n");
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001078#ifdef HAVE_ZLIB_H
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001079 printf("\t--compress : turn on gzip compression of output\n");
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001080#endif
Daniel Veillard89cad532001-10-22 09:46:13 +00001081#ifdef LIBXML_DOCB_ENABLED
1082 printf("\t--sgml : use the DocBook SGML parser\n");
1083#endif
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001084#ifdef LIBXML_HTML_ENABLED
1085 printf("\t--html : use the HTML parser\n");
1086#endif
1087 printf("\t--push : use the push mode of the parser\n");
1088#ifdef HAVE_SYS_MMAN_H
1089 printf("\t--memory : parse from memory\n");
1090#endif
1091 printf("\t--nowarning : do not emit warnings from parser/validator\n");
1092 printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
Daniel Veillard90493a92001-08-14 14:12:47 +00001093 printf("\t--format : reformat/reindent the input\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001094 printf("\t--testIO : test user I/O support\n");
1095 printf("\t--encode encoding : output in the given encoding\n");
1096#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardbd9b0e82001-11-26 10:32:08 +00001097 printf("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n");
1098 printf("\t otherwise XML Catalogs starting from \n");
1099 printf("\t file:///etc/xml/catalog are activated by default\n");
Daniel Veillard05c13a22001-09-09 08:38:09 +00001100 printf("\t--nocatalogs: deactivate all catalogs\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001101#endif
1102 printf("\t--auto : generate a small doc on the fly\n");
1103#ifdef LIBXML_XINCLUDE_ENABLED
1104 printf("\t--xinclude : do XInclude processing\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001105#endif
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001106 printf("\t--loaddtd : fetch external DTD\n");
Daniel Veillard48da9102001-08-07 01:10:10 +00001107 printf("\t--dtdattr : loaddtd + populate the tree with inherited attributes \n");
Daniel Veillard29e43992001-12-13 22:21:58 +00001108 printf("\t--dropdtd : remove the DOCTYPE of the input docs\n");
Daniel Veillarda42f25f2002-01-25 14:15:40 +00001109 printf("\nLibxml project home page: http://xmlsoft.org/\n");
1110 printf("To report bugs or get some help check: http://xmlsoft.org/bugs.html\n");
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001111}
Daniel Veillard4a6845d2001-01-03 13:32:39 +00001112int
1113main(int argc, char **argv) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001114 int i, count;
1115 int files = 0;
Daniel Veillard845cce42002-01-09 11:51:37 +00001116 int version = 0;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001117
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001118 if (argc <= 1) {
1119 usage(argv[0]);
1120 return(1);
1121 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001122 LIBXML_TEST_VERSION
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001123 for (i = 1; i < argc ; i++) {
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001124 if (!strcmp(argv[i], "-"))
1125 break;
1126
1127 if (argv[i][0] != '-')
1128 continue;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001129#ifdef LIBXML_DEBUG_ENABLED
1130 if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
1131 debug++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001132 else if ((!strcmp(argv[i], "-shell")) ||
1133 (!strcmp(argv[i], "--shell"))) {
1134 shell++;
1135 noout = 1;
1136 } else
1137#endif
1138 if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
1139 copy++;
1140 else if ((!strcmp(argv[i], "-recover")) ||
1141 (!strcmp(argv[i], "--recover")))
1142 recovery++;
1143 else if ((!strcmp(argv[i], "-noent")) ||
1144 (!strcmp(argv[i], "--noent")))
1145 noent++;
Daniel Veillard4ec885a2001-06-17 10:31:07 +00001146 else if ((!strcmp(argv[i], "-version")) ||
Daniel Veillard845cce42002-01-09 11:51:37 +00001147 (!strcmp(argv[i], "--version"))) {
Daniel Veillard0f04f8e2002-09-17 23:04:40 +00001148 showVersion(argv[0]);
Daniel Veillard845cce42002-01-09 11:51:37 +00001149 version = 1;
1150 } else if ((!strcmp(argv[i], "-noout")) ||
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001151 (!strcmp(argv[i], "--noout")))
1152 noout++;
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001153 else if ((!strcmp(argv[i], "-o")) ||
1154 (!strcmp(argv[i], "-output")) ||
1155 (!strcmp(argv[i], "--output"))) {
1156 i++;
Daniel Veillard6e4f1c02002-04-09 09:55:20 +00001157 output = argv[i];
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001158 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001159 else if ((!strcmp(argv[i], "-htmlout")) ||
1160 (!strcmp(argv[i], "--htmlout")))
1161 htmlout++;
Daniel Veillard89cad532001-10-22 09:46:13 +00001162#ifdef LIBXML_DOCB_ENABLED
1163 else if ((!strcmp(argv[i], "-sgml")) ||
1164 (!strcmp(argv[i], "--sgml"))) {
1165 sgml++;
1166 }
1167#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001168#ifdef LIBXML_HTML_ENABLED
1169 else if ((!strcmp(argv[i], "-html")) ||
1170 (!strcmp(argv[i], "--html"))) {
1171 html++;
1172 }
1173#endif /* LIBXML_HTML_ENABLED */
1174 else if ((!strcmp(argv[i], "-nowrap")) ||
1175 (!strcmp(argv[i], "--nowrap")))
1176 nowrap++;
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001177 else if ((!strcmp(argv[i], "-loaddtd")) ||
1178 (!strcmp(argv[i], "--loaddtd")))
1179 loaddtd++;
Daniel Veillard48da9102001-08-07 01:10:10 +00001180 else if ((!strcmp(argv[i], "-dtdattr")) ||
1181 (!strcmp(argv[i], "--dtdattr"))) {
1182 loaddtd++;
1183 dtdattrs++;
1184 } else if ((!strcmp(argv[i], "-valid")) ||
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001185 (!strcmp(argv[i], "--valid")))
1186 valid++;
1187 else if ((!strcmp(argv[i], "-postvalid")) ||
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001188 (!strcmp(argv[i], "--postvalid"))) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001189 postvalid++;
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001190 loaddtd++;
1191 } else if ((!strcmp(argv[i], "-dtdvalid")) ||
Daniel Veillardcd429612000-10-11 15:57:05 +00001192 (!strcmp(argv[i], "--dtdvalid"))) {
1193 i++;
1194 dtdvalid = argv[i];
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001195 loaddtd++;
Daniel Veillardcd429612000-10-11 15:57:05 +00001196 }
Daniel Veillard29e43992001-12-13 22:21:58 +00001197 else if ((!strcmp(argv[i], "-dropdtd")) ||
1198 (!strcmp(argv[i], "--dropdtd")))
1199 dropdtd++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001200 else if ((!strcmp(argv[i], "-insert")) ||
1201 (!strcmp(argv[i], "--insert")))
1202 insert++;
Daniel Veillard48b2f892001-02-25 16:11:03 +00001203 else if ((!strcmp(argv[i], "-timing")) ||
1204 (!strcmp(argv[i], "--timing")))
1205 timing++;
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001206 else if ((!strcmp(argv[i], "-auto")) ||
1207 (!strcmp(argv[i], "--auto")))
1208 generate++;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001209 else if ((!strcmp(argv[i], "-repeat")) ||
1210 (!strcmp(argv[i], "--repeat")))
1211 repeat++;
1212 else if ((!strcmp(argv[i], "-push")) ||
1213 (!strcmp(argv[i], "--push")))
1214 push++;
Daniel Veillard46e370e2000-07-21 20:32:03 +00001215#ifdef HAVE_SYS_MMAN_H
1216 else if ((!strcmp(argv[i], "-memory")) ||
1217 (!strcmp(argv[i], "--memory")))
1218 memory++;
1219#endif
Daniel Veillard5e873c42000-04-12 13:27:38 +00001220 else if ((!strcmp(argv[i], "-testIO")) ||
1221 (!strcmp(argv[i], "--testIO")))
1222 testIO++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001223#ifdef LIBXML_XINCLUDE_ENABLED
1224 else if ((!strcmp(argv[i], "-xinclude")) ||
1225 (!strcmp(argv[i], "--xinclude")))
1226 xinclude++;
1227#endif
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001228#ifdef HAVE_ZLIB_H
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001229 else if ((!strcmp(argv[i], "-compress")) ||
1230 (!strcmp(argv[i], "--compress"))) {
1231 compress++;
1232 xmlSetCompressMode(9);
1233 }
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001234#endif
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001235 else if ((!strcmp(argv[i], "-nowarning")) ||
1236 (!strcmp(argv[i], "--nowarning"))) {
1237 xmlGetWarningsDefaultValue = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001238 xmlPedanticParserDefault(0);
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001239 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001240 else if ((!strcmp(argv[i], "-pedantic")) ||
1241 (!strcmp(argv[i], "--pedantic"))) {
1242 xmlGetWarningsDefaultValue = 1;
1243 xmlPedanticParserDefault(1);
1244 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +00001245#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001246 else if ((!strcmp(argv[i], "-debugent")) ||
1247 (!strcmp(argv[i], "--debugent"))) {
1248 debugent++;
1249 xmlParserDebugEntities = 1;
1250 }
Daniel Veillard64c20ed2000-09-22 16:07:02 +00001251#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00001252#ifdef LIBXML_CATALOG_ENABLED
1253 else if ((!strcmp(argv[i], "-catalogs")) ||
1254 (!strcmp(argv[i], "--catalogs"))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001255 catalogs++;
1256 } else if ((!strcmp(argv[i], "-nocatalogs")) ||
1257 (!strcmp(argv[i], "--nocatalogs"))) {
1258 nocatalogs++;
Daniel Veillard81418e32001-05-22 15:08:55 +00001259 }
1260#endif
Daniel Veillardbe803962000-06-28 23:40:59 +00001261 else if ((!strcmp(argv[i], "-encode")) ||
1262 (!strcmp(argv[i], "--encode"))) {
1263 i++;
1264 encoding = argv[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001265 /*
1266 * OK it's for testing purposes
1267 */
1268 xmlAddEncodingAlias("UTF-8", "DVEnc");
Daniel Veillardbe803962000-06-28 23:40:59 +00001269 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001270 else if ((!strcmp(argv[i], "-noblanks")) ||
1271 (!strcmp(argv[i], "--noblanks"))) {
1272 noblanks++;
1273 xmlKeepBlanksDefault(0);
Daniel Veillard90493a92001-08-14 14:12:47 +00001274 }
1275 else if ((!strcmp(argv[i], "-format")) ||
1276 (!strcmp(argv[i], "--format"))) {
1277 noblanks++;
1278 format++;
1279 xmlKeepBlanksDefault(0);
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001280 } else {
1281 fprintf(stderr, "Unknown option %s\n", argv[i]);
1282 usage(argv[0]);
1283 return(1);
1284 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001285 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001286
1287#ifdef LIBXML_CATALOG_ENABLED
1288 if (nocatalogs == 0) {
1289 if (catalogs) {
1290 const char *catal;
1291
1292 catal = getenv("SGML_CATALOG_FILES");
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00001293 if (catal != NULL) {
1294 xmlLoadCatalogs(catal);
1295 } else {
1296 fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n");
1297 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001298 }
1299 }
1300#endif
Daniel Veillardd9bad132001-07-23 19:39:43 +00001301 xmlLineNumbersDefault(1);
Daniel Veillard48da9102001-08-07 01:10:10 +00001302 if (loaddtd != 0)
1303 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
1304 if (dtdattrs)
1305 xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001306 if (noent != 0) xmlSubstituteEntitiesDefault(1);
1307 if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
1308 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001310 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001311 xmlGenericError(xmlGenericErrorContext,
1312 "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
1313 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001314 "<html><head><title>%s output</title></head>\n",
1315 argv[0]);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001317 "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
1318 argv[0]);
1319 }
1320 for (i = 1; i < argc ; i++) {
Daniel Veillardbe803962000-06-28 23:40:59 +00001321 if ((!strcmp(argv[i], "-encode")) ||
1322 (!strcmp(argv[i], "--encode"))) {
1323 i++;
1324 continue;
Daniel Veillard1df3dfc2001-12-18 11:14:16 +00001325 } else if ((!strcmp(argv[i], "-o")) ||
1326 (!strcmp(argv[i], "-output")) ||
1327 (!strcmp(argv[i], "--output"))) {
1328 i++;
1329 continue;
Daniel Veillardbe803962000-06-28 23:40:59 +00001330 }
Daniel Veillardcd429612000-10-11 15:57:05 +00001331 if ((!strcmp(argv[i], "-dtdvalid")) ||
1332 (!strcmp(argv[i], "--dtdvalid"))) {
1333 i++;
1334 continue;
1335 }
Daniel Veillard48b2f892001-02-25 16:11:03 +00001336 if ((timing) && (repeat))
Daniel Veillard01db67c2001-12-18 07:09:59 +00001337 startTimer();
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001338 /* Remember file names. "-" means stdin. <sven@zen.org> */
Daniel Veillard4a6845d2001-01-03 13:32:39 +00001339 if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001340 if (repeat) {
1341 for (count = 0;count < 100 * repeat;count++)
1342 parseAndPrintFile(argv[i]);
1343 } else
1344 parseAndPrintFile(argv[i]);
1345 files ++;
Daniel Veillarda7866932001-12-04 13:14:44 +00001346 if ((timing) && (repeat)) {
Daniel Veillard01db67c2001-12-18 07:09:59 +00001347 endTimer("100 iterations");
Daniel Veillarda7866932001-12-04 13:14:44 +00001348 }
Daniel Veillard48b2f892001-02-25 16:11:03 +00001349 }
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001350 }
Daniel Veillardd2f3ec72001-04-11 07:50:02 +00001351 if (generate)
1352 parseAndPrintFile(NULL);
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001353 if ((htmlout) && (!nowrap)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001354 xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001355 }
Daniel Veillard845cce42002-01-09 11:51:37 +00001356 if ((files == 0) && (!generate) && (version == 0)) {
Daniel Veillard10ea86c2001-06-20 13:55:33 +00001357 usage(argv[0]);
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001358 }
1359 xmlCleanupParser();
1360 xmlMemoryDump();
1361
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001362 return(progresult);
Daniel Veillardce8b83b2000-04-05 18:38:42 +00001363}
Daniel Veillard88a172f2000-08-04 18:23:10 +00001364