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