preparing 1.0.7 cleanup similar to libxml2 one finished cleaning up
[platform/upstream/libxslt.git] / xsltproc / xsltproc.c
1 /*
2  * xsltproc.c: user program for the XSL Transformation 1.0 engine
3  *
4  * See Copyright for the status of this software.
5  *
6  * daniel@veillard.com
7  */
8
9 #include "libxslt/libxslt.h"
10 #include "libexslt/exslt.h"
11 #ifdef HAVE_STRING_H
12 #include <string.h>
13 #endif
14 #ifdef HAVE_SYS_TIME_H
15 #include <sys/time.h>
16 #endif
17 #ifdef HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26 #ifdef HAVE_STDARG_H
27 #include <stdarg.h>
28 #endif
29 #include <libxml/xmlmemory.h>
30 #include <libxml/debugXML.h>
31 #include <libxml/HTMLtree.h>
32 #include <libxml/xmlIO.h>
33 #ifdef LIBXML_DOCB_ENABLED
34 #include <libxml/DOCBparser.h>
35 #endif
36 #ifdef LIBXML_XINCLUDE_ENABLED
37 #include <libxml/xinclude.h>
38 #endif
39 #ifdef LIBXML_CATALOG_ENABLED
40 #include <libxml/catalog.h>
41 #endif
42 #include <libxml/parserInternals.h>
43
44 #include <libxslt/xslt.h>
45 #include <libxslt/xsltInternals.h>
46 #include <libxslt/transform.h>
47 #include <libxslt/xsltutils.h>
48 #include <libxslt/extensions.h>
49
50 #include <libexslt/exsltconfig.h>
51
52 #ifdef WIN32
53 #ifdef _MSC_VER
54 #include <winsock2.h>
55 #pragma comment(lib, "ws2_32.lib")
56 #define gettimeofday(p1,p2)
57 #endif /* _MS_VER */
58 #else /* WIN32 */
59 #if defined(HAVE_SYS_TIME_H)
60 #include <sys/time.h>
61 #elif defined(HAVE_TIME_H)
62 #include <time.h>
63 #endif
64 #endif /* WIN32 */
65
66 #ifndef HAVE_STAT
67 #  ifdef HAVE__STAT
68      /* MS C library seems to define stat and _stat. The definition
69       *         is identical. Still, mapping them to each other causes a warning. */
70 #    ifndef _MSC_VER
71 #      define stat(x,y) _stat(x,y)
72 #    endif
73 #    define HAVE_STAT
74 #  endif
75 #endif
76
77 xmlParserInputPtr xmlNoNetExternalEntityLoader(const char *URL,
78                                                const char *ID,
79                                                xmlParserCtxtPtr ctxt);
80
81 static int debug = 0;
82 static int repeat = 0;
83 static int timing = 0;
84 static int novalid = 0;
85 static int noout = 0;
86 #ifdef LIBXML_DOCB_ENABLED
87 static int docbook = 0;
88 #endif
89 #ifdef LIBXML_HTML_ENABLED
90 static int html = 0;
91 #endif
92 #ifdef LIBXML_XINCLUDE_ENABLED
93 static int xinclude = 0;
94 #endif
95 static int profile = 0;
96
97 static const char *params[16 + 1];
98 static int nbparams = 0;
99 static const char *output = NULL;
100
101 /*
102  * Internal timing routines to remove the necessity to have unix-specific
103  * function calls
104  */
105
106 #if defined(HAVE_GETTIMEOFDAY)
107 static struct timeval begin, end;
108 /*
109  * startTimer: call where you want to start timing
110  */
111 static void startTimer(void)
112 {
113     gettimeofday(&begin,NULL);
114 }
115 /*
116  * endTimer: call where you want to stop timing and to print out a
117  *           message about the timing performed; format is a printf
118  *           type argument
119  */
120 static void endTimer(const char *format, ...)
121 {
122     long msec;
123     va_list ap;
124
125     gettimeofday(&end, NULL);
126     msec = end.tv_sec - begin.tv_sec;
127     msec *= 1000;
128     msec += (end.tv_usec - begin.tv_usec) / 1000;
129
130 #ifndef HAVE_STDARG_H
131 #error "endTimer required stdarg functions"
132 #endif
133     va_start(ap, format);
134     vfprintf(stderr,format,ap);
135     va_end(ap);
136
137     fprintf(stderr, " took %ld ms\n", msec);
138 }
139 #elif defined(HAVE_TIME_H)
140 /*
141  * No gettimeofday function, so we have to make do with calling clock.
142  * This is obviously less accurate, but there's little we can do about
143  * that.
144  */
145
146 clock_t begin, end;
147 static void startTimer(void)
148 {
149     begin=clock();
150 }
151 static void endTimer(char *format, ...)
152 {
153     long msec;
154     va_list ap;
155
156     end=clock();
157     msec = ((end-begin) * 1000) / CLOCKS_PER_SEC;
158
159 #ifndef HAVE_STDARG_H
160 #error "endTimer required stdarg functions"
161 #endif
162     va_start(ap, format);
163     vfprintf(stderr,format,ap);
164     va_end(ap);
165     fprintf(stderr, " took %ld ms\n", msec);
166 }
167 #else
168 /*
169  * We don't have a gettimeofday or time.h, so we just don't do timing
170  */
171 static void startTimer(void)
172 {
173   /*
174    * Do nothing
175    */
176 }
177 static void endTimer(char *format, ...)
178 {
179   /*
180    * We cannot do anything because we don't have a timing function
181    */
182 #ifdef HAVE_STDARG_H
183     va_start(ap, format);
184     vfprintf(stderr,format,ap);
185     va_end(ap);
186     fprintf(stderr, " was not timed\n", msec);
187 #else
188   /* We don't have gettimeofday, time or stdarg.h, what crazy world is
189    * this ?!
190    */
191 #endif
192 }
193 #endif
194
195 static void
196 xsltProcess(xmlDocPtr doc, xsltStylesheetPtr cur, const char *filename) {
197     xmlDocPtr res;
198
199 #ifdef LIBXML_XINCLUDE_ENABLED
200     if (xinclude) {
201         if (timing)
202             startTimer();
203         xmlXIncludeProcess(doc);
204         if (timing) {
205             endTimer("XInclude processing %s", filename);
206         }
207     }
208 #endif
209     if (timing)
210         startTimer();
211     if (output == NULL) {
212         if (repeat) {
213             int j;
214
215             for (j = 1; j < repeat; j++) {
216                 res = xsltApplyStylesheet(cur, doc, params);
217                 xmlFreeDoc(res);
218                 xmlFreeDoc(doc);
219 #ifdef LIBXML_HTML_ENABLED
220                 if (html)
221                     doc = htmlParseFile(filename, NULL);
222                 else
223 #endif
224 #ifdef LIBXML_DOCB_ENABLED
225                 if (docbook)
226                     doc = docbParseFile(filename, NULL);
227                 else
228 #endif
229                     doc = xmlParseFile(filename);
230             }
231         }
232         if (profile) {
233             res = xsltProfileStylesheet(cur, doc, params, stderr);
234         } else {
235             res = xsltApplyStylesheet(cur, doc, params);
236         }
237         if (timing) {
238             if (repeat)
239                 endTimer("Applying stylesheet %d times", repeat);
240             else
241                 endTimer("Applying stylesheet");
242         }
243         xmlFreeDoc(doc);
244         if (res == NULL) {
245             fprintf(stderr, "no result for %s\n", filename);
246             return;
247         }
248         if (noout) {
249             xmlFreeDoc(res);
250             return;
251         }
252 #ifdef LIBXML_DEBUG_ENABLED
253         if (debug)
254             xmlDebugDumpDocument(stdout, res);
255         else {
256 #endif
257             if (cur->methodURI == NULL) {
258                 if (timing)
259                     startTimer();
260                 xsltSaveResultToFile(stdout, res, cur);
261                 if (timing)
262                     endTimer("Saving result");
263             } else {
264                 if (xmlStrEqual
265                     (cur->method, (const xmlChar *) "xhtml")) {
266                     fprintf(stderr, "non standard output xhtml\n");
267                     if (timing)
268                         startTimer();
269                     xsltSaveResultToFile(stdout, res, cur);
270                     if (timing)
271                         endTimer("Saving result");
272                 } else {
273                     fprintf(stderr,
274                             "Unsupported non standard output %s\n",
275                             cur->method);
276                 }
277             }
278 #ifdef LIBXML_DEBUG_ENABLED
279         }
280 #endif
281
282         xmlFreeDoc(res);
283     } else {
284         xsltRunStylesheet(cur, doc, params, output, NULL, NULL);
285         if (timing)
286             endTimer("Running stylesheet and saving result");
287         xmlFreeDoc(doc);
288     }
289 }
290
291 static void usage(const char *name) {
292     printf("Usage: %s [options] stylesheet file [file ...]\n", name);
293     printf("   Options:\n");
294     printf("      --version or -V: show the version of libxml and libxslt used\n");
295     printf("      --verbose or -v: show logs of what's happening\n");
296     printf("      --output file or -o file: save to a given file\n");
297     printf("      --timing: display the time used\n");
298     printf("      --repeat: run the transformation 20 times\n");
299     printf("      --debug: dump the tree of the result instead\n");
300     printf("      --novalid: skip the Dtd loading phase\n");
301     printf("      --noout: do not dump the result\n");
302     printf("      --maxdepth val : increase the maximum depth\n");
303 #ifdef LIBXML_HTML_ENABLED
304     printf("      --html: the input document is(are) an HTML file(s)\n");
305 #endif
306 #ifdef LIBXML_DOCB_ENABLED
307     printf("      --docbook: the input document is SGML docbook\n");
308 #endif
309     printf("      --param name value : pass a (parameter,value) pair\n");
310     printf("            string values must be quoted like \"'string'\"\n");
311     printf("      --nonet refuse to fetch DTDs or entities over network\n");
312 #ifdef LIBXML_CATALOG_ENABLED
313     printf("      --catalogs : use the catalogs from $SGML_CATALOG_FILES\n");
314 #endif
315 #ifdef LIBXML_XINCLUDE_ENABLED
316     printf("      --xinclude : do XInclude processing on document intput\n");
317 #endif
318     printf("      --profile or --norman : dump profiling informations \n");
319 }
320
321 int
322 main(int argc, char **argv)
323 {
324     int i;
325     xsltStylesheetPtr cur = NULL;
326     xmlDocPtr doc, style;
327
328     if (argc <= 1) {
329         usage(argv[0]);
330         return (1);
331     }
332
333     xmlInitMemory();
334
335     LIBXML_TEST_VERSION
336
337     xmlLineNumbersDefault(1);
338
339     if (novalid == 0)
340         xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
341     else
342         xmlLoadExtDtdDefaultValue = 0;
343     for (i = 1; i < argc; i++) {
344         if (!strcmp(argv[i], "-"))
345             break;
346
347         if (argv[i][0] != '-')
348             continue;
349 #ifdef LIBXML_DEBUG_ENABLED
350         if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) {
351             debug++;
352         } else
353 #endif
354         if ((!strcmp(argv[i], "-v")) ||
355                 (!strcmp(argv[i], "-verbose")) ||
356                 (!strcmp(argv[i], "--verbose"))) {
357             xsltSetGenericDebugFunc(stderr, NULL);
358         } else if ((!strcmp(argv[i], "-o")) ||
359                    (!strcmp(argv[i], "-output")) ||
360                    (!strcmp(argv[i], "--output"))) {
361             i++;
362             output = argv[i++];
363         } else if ((!strcmp(argv[i], "-V")) ||
364                    (!strcmp(argv[i], "-version")) ||
365                    (!strcmp(argv[i], "--version"))) {
366             printf("Using libxml %s, libxslt %s and libexslt %s\n",
367                    xmlParserVersion, xsltEngineVersion, exsltLibraryVersion);
368             printf
369     ("xsltproc was compiled against libxml %d, libxslt %d and libexslt %d\n",
370                  LIBXML_VERSION, LIBXSLT_VERSION, LIBEXSLT_VERSION);
371             printf("libxslt %d was compiled against libxml %d\n",
372                    xsltLibxsltVersion, xsltLibxmlVersion);
373             printf("libexslt %d was compiled against libxml %d\n",
374                    exsltLibexsltVersion, exsltLibxmlVersion);
375         } else if ((!strcmp(argv[i], "-repeat"))
376                    || (!strcmp(argv[i], "--repeat"))) {
377             if (repeat == 0)
378                 repeat = 20;
379             else
380                 repeat = 100;
381         } else if ((!strcmp(argv[i], "-novalid")) ||
382                    (!strcmp(argv[i], "--novalid"))) {
383             novalid++;
384         } else if ((!strcmp(argv[i], "-noout")) ||
385                    (!strcmp(argv[i], "--noout"))) {
386             noout++;
387 #ifdef LIBXML_DOCB_ENABLED
388         } else if ((!strcmp(argv[i], "-docbook")) ||
389                    (!strcmp(argv[i], "--docbook"))) {
390             docbook++;
391 #endif
392 #ifdef LIBXML_HTML_ENABLED
393         } else if ((!strcmp(argv[i], "-html")) ||
394                    (!strcmp(argv[i], "--html"))) {
395             html++;
396 #endif
397         } else if ((!strcmp(argv[i], "-timing")) ||
398                    (!strcmp(argv[i], "--timing"))) {
399             timing++;
400         } else if ((!strcmp(argv[i], "-profile")) ||
401                    (!strcmp(argv[i], "--profile"))) {
402             profile++;
403         } else if ((!strcmp(argv[i], "-norman")) ||
404                    (!strcmp(argv[i], "--norman"))) {
405             profile++;
406         } else if ((!strcmp(argv[i], "-nonet")) ||
407                    (!strcmp(argv[i], "--nonet"))) {
408             xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
409 #ifdef LIBXML_CATALOG_ENABLED
410         } else if ((!strcmp(argv[i], "-catalogs")) ||
411                    (!strcmp(argv[i], "--catalogs"))) {
412             const char *catalogs;
413
414             catalogs = getenv("SGML_CATALOG_FILES");
415             if (catalogs == NULL) {
416                 fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n");
417             } else {
418                 xmlLoadCatalogs(catalogs);
419             }
420 #endif
421 #ifdef LIBXML_XINCLUDE_ENABLED
422         } else if ((!strcmp(argv[i], "-xinclude")) ||
423                    (!strcmp(argv[i], "--xinclude"))) {
424             xinclude++;
425             xsltSetXIncludeDefault(1);
426 #endif
427         } else if ((!strcmp(argv[i], "-param")) ||
428                    (!strcmp(argv[i], "--param"))) {
429             i++;
430             params[nbparams++] = argv[i++];
431             params[nbparams++] = argv[i];
432             if (nbparams >= 16) {
433                 fprintf(stderr, "too many params\n");
434                 return (1);
435             }
436         } else if ((!strcmp(argv[i], "-maxdepth")) ||
437                    (!strcmp(argv[i], "--maxdepth"))) {
438             int value;
439
440             i++;
441             if (sscanf(argv[i], "%d", &value) == 1) {
442                 if (value > 0)
443                     xsltMaxDepth = value;
444             }
445         } else {
446             fprintf(stderr, "Unknown option %s\n", argv[i]);
447             usage(argv[0]);
448             return (1);
449         }
450     }
451     params[nbparams] = NULL;
452
453     /*
454      * Replace entities with their content.
455      */
456     xmlSubstituteEntitiesDefault(1);
457
458     /*
459      * Register the EXSLT extensions and the test module
460      */
461     exsltRegisterAll();
462     xsltRegisterTestModule();
463
464     for (i = 1; i < argc; i++) {
465         if ((!strcmp(argv[i], "-maxdepth")) ||
466             (!strcmp(argv[i], "--maxdepth"))) {
467             i++;
468             continue;
469         } else if ((!strcmp(argv[i], "-o")) ||
470                    (!strcmp(argv[i], "-output")) ||
471                    (!strcmp(argv[i], "--output"))) {
472             i++;
473             continue;
474         }
475         if ((!strcmp(argv[i], "-param")) || (!strcmp(argv[i], "--param"))) {
476             i += 2;
477             continue;
478         }
479         if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
480             if (timing)
481                 startTimer();
482             style = xmlParseFile((const char *) argv[i]);
483             if (timing) 
484                 endTimer("Parsing stylesheet %s", argv[i]);
485             if (style == NULL) {
486                 fprintf(stderr,  "cannot parse %s\n", argv[i]);
487                 cur = NULL;
488             } else {
489                 cur = xsltLoadStylesheetPI(style);
490                 if (cur != NULL) {
491                     /* it is an embedded stylesheet */
492                     xsltProcess(style, cur, argv[i]);
493                     xsltFreeStylesheet(cur);
494                     goto done;
495                 }
496                 cur = xsltParseStylesheetDoc(style);
497                 if (cur != NULL) {
498                     if (cur->indent == 1)
499                         xmlIndentTreeOutput = 1;
500                     else
501                         xmlIndentTreeOutput = 0;
502                     i++;
503                 } else {
504                     xmlFreeDoc(style);
505                     goto done;
506                 }
507             }
508             break;
509
510         }
511     }
512
513     /*
514      * disable CDATA from being built in the document tree
515      */
516     xmlDefaultSAXHandlerInit();
517     xmlDefaultSAXHandler.cdataBlock = NULL;
518
519     if ((cur != NULL) && (cur->errors == 0)) {
520         for (; i < argc; i++) {
521             doc = NULL;
522             if (timing)
523                 startTimer();
524 #ifdef LIBXML_HTML_ENABLED
525             if (html)
526                 doc = htmlParseFile(argv[i], NULL);
527             else
528 #endif
529 #ifdef LIBXML_DOCB_ENABLED
530             if (docbook)
531                 doc = docbParseFile(argv[i], NULL);
532             else
533 #endif
534                 doc = xmlParseFile(argv[i]);
535             if (doc == NULL) {
536                 fprintf(stderr, "unable to parse %s\n", argv[i]);
537                 continue;
538             }
539             if (timing)
540                 endTimer("Parsing document %s", argv[i]);
541             xsltProcess(doc, cur, argv[i]);
542         }
543     }
544     if (cur != NULL)
545         xsltFreeStylesheet(cur);
546 done:
547     xsltCleanupGlobals();
548     xmlCleanupParser();
549     xmlMemoryDump();
550     return (0);
551 }
552