1/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
2   See the file COPYING for copying permission.
3*/
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <stddef.h>
8#include <string.h>
9
10#include "expat.h"
11#include "codepage.h"
12#include "internal.h"  /* for UNUSED_P only */
13#include "xmlfile.h"
14#include "xmltchar.h"
15
16#ifdef _MSC_VER
17#include <crtdbg.h>
18#endif
19
20#if defined(__amigaos__) && defined(__USE_INLINE__)
21#include <proto/expat.h>
22#endif
23
24/* This ensures proper sorting. */
25
26#define NSSEP T('\001')
27
28static void XMLCALL
29characterData(void *userData, const XML_Char *s, int len)
30{
31  FILE *fp = (FILE *)userData;
32  for (; len > 0; --len, ++s) {
33    switch (*s) {
34    case T('&'):
35      fputts(T("&amp;"), fp);
36      break;
37    case T('<'):
38      fputts(T("&lt;"), fp);
39      break;
40    case T('>'):
41      fputts(T("&gt;"), fp);
42      break;
43#ifdef W3C14N
44    case 13:
45      fputts(T("&#xD;"), fp);
46      break;
47#else
48    case T('"'):
49      fputts(T("&quot;"), fp);
50      break;
51    case 9:
52    case 10:
53    case 13:
54      ftprintf(fp, T("&#%d;"), *s);
55      break;
56#endif
57    default:
58      puttc(*s, fp);
59      break;
60    }
61  }
62}
63
64static void
65attributeValue(FILE *fp, const XML_Char *s)
66{
67  puttc(T('='), fp);
68  puttc(T('"'), fp);
69  for (;;) {
70    switch (*s) {
71    case 0:
72    case NSSEP:
73      puttc(T('"'), fp);
74      return;
75    case T('&'):
76      fputts(T("&amp;"), fp);
77      break;
78    case T('<'):
79      fputts(T("&lt;"), fp);
80      break;
81    case T('"'):
82      fputts(T("&quot;"), fp);
83      break;
84#ifdef W3C14N
85    case 9:
86      fputts(T("&#x9;"), fp);
87      break;
88    case 10:
89      fputts(T("&#xA;"), fp);
90      break;
91    case 13:
92      fputts(T("&#xD;"), fp);
93      break;
94#else
95    case T('>'):
96      fputts(T("&gt;"), fp);
97      break;
98    case 9:
99    case 10:
100    case 13:
101      ftprintf(fp, T("&#%d;"), *s);
102      break;
103#endif
104    default:
105      puttc(*s, fp);
106      break;
107    }
108    s++;
109  }
110}
111
112/* Lexicographically comparing UTF-8 encoded attribute values,
113is equivalent to lexicographically comparing based on the character number. */
114
115static int
116attcmp(const void *att1, const void *att2)
117{
118  return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
119}
120
121static void XMLCALL
122startElement(void *userData, const XML_Char *name, const XML_Char **atts)
123{
124  int nAtts;
125  const XML_Char **p;
126  FILE *fp = (FILE *)userData;
127  puttc(T('<'), fp);
128  fputts(name, fp);
129
130  p = atts;
131  while (*p)
132    ++p;
133  nAtts = (int)((p - atts) >> 1);
134  if (nAtts > 1)
135    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp);
136  while (*atts) {
137    puttc(T(' '), fp);
138    fputts(*atts++, fp);
139    attributeValue(fp, *atts);
140    atts++;
141  }
142  puttc(T('>'), fp);
143}
144
145static void XMLCALL
146endElement(void *userData, const XML_Char *name)
147{
148  FILE *fp = (FILE *)userData;
149  puttc(T('<'), fp);
150  puttc(T('/'), fp);
151  fputts(name, fp);
152  puttc(T('>'), fp);
153}
154
155static int
156nsattcmp(const void *p1, const void *p2)
157{
158  const XML_Char *att1 = *(const XML_Char **)p1;
159  const XML_Char *att2 = *(const XML_Char **)p2;
160  int sep1 = (tcsrchr(att1, NSSEP) != 0);
161  int sep2 = (tcsrchr(att1, NSSEP) != 0);
162  if (sep1 != sep2)
163    return sep1 - sep2;
164  return tcscmp(att1, att2);
165}
166
167static void XMLCALL
168startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
169{
170  int nAtts;
171  int nsi;
172  const XML_Char **p;
173  FILE *fp = (FILE *)userData;
174  const XML_Char *sep;
175  puttc(T('<'), fp);
176
177  sep = tcsrchr(name, NSSEP);
178  if (sep) {
179    fputts(T("n1:"), fp);
180    fputts(sep + 1, fp);
181    fputts(T(" xmlns:n1"), fp);
182    attributeValue(fp, name);
183    nsi = 2;
184  }
185  else {
186    fputts(name, fp);
187    nsi = 1;
188  }
189
190  p = atts;
191  while (*p)
192    ++p;
193  nAtts = (int)((p - atts) >> 1);
194  if (nAtts > 1)
195    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp);
196  while (*atts) {
197    name = *atts++;
198    sep = tcsrchr(name, NSSEP);
199    puttc(T(' '), fp);
200    if (sep) {
201      ftprintf(fp, T("n%d:"), nsi);
202      fputts(sep + 1, fp);
203    }
204    else
205      fputts(name, fp);
206    attributeValue(fp, *atts);
207    if (sep) {
208      ftprintf(fp, T(" xmlns:n%d"), nsi++);
209      attributeValue(fp, name);
210    }
211    atts++;
212  }
213  puttc(T('>'), fp);
214}
215
216static void XMLCALL
217endElementNS(void *userData, const XML_Char *name)
218{
219  FILE *fp = (FILE *)userData;
220  const XML_Char *sep;
221  puttc(T('<'), fp);
222  puttc(T('/'), fp);
223  sep = tcsrchr(name, NSSEP);
224  if (sep) {
225    fputts(T("n1:"), fp);
226    fputts(sep + 1, fp);
227  }
228  else
229    fputts(name, fp);
230  puttc(T('>'), fp);
231}
232
233#ifndef W3C14N
234
235static void XMLCALL
236processingInstruction(void *userData, const XML_Char *target,
237                      const XML_Char *data)
238{
239  FILE *fp = (FILE *)userData;
240  puttc(T('<'), fp);
241  puttc(T('?'), fp);
242  fputts(target, fp);
243  puttc(T(' '), fp);
244  fputts(data, fp);
245  puttc(T('?'), fp);
246  puttc(T('>'), fp);
247}
248
249#endif /* not W3C14N */
250
251static void XMLCALL
252defaultCharacterData(void *userData, const XML_Char *UNUSED_P(s), int UNUSED_P(len))
253{
254  XML_DefaultCurrent((XML_Parser) userData);
255}
256
257static void XMLCALL
258defaultStartElement(void *userData, const XML_Char *UNUSED_P(name),
259                    const XML_Char **UNUSED_P(atts))
260{
261  XML_DefaultCurrent((XML_Parser) userData);
262}
263
264static void XMLCALL
265defaultEndElement(void *userData, const XML_Char *UNUSED_P(name))
266{
267  XML_DefaultCurrent((XML_Parser) userData);
268}
269
270static void XMLCALL
271defaultProcessingInstruction(void *userData, const XML_Char *UNUSED_P(target),
272                             const XML_Char *UNUSED_P(data))
273{
274  XML_DefaultCurrent((XML_Parser) userData);
275}
276
277static void XMLCALL
278nopCharacterData(void *UNUSED_P(userData), const XML_Char *UNUSED_P(s), int UNUSED_P(len))
279{
280}
281
282static void XMLCALL
283nopStartElement(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
284{
285}
286
287static void XMLCALL
288nopEndElement(void *UNUSED_P(userData), const XML_Char *UNUSED_P(name))
289{
290}
291
292static void XMLCALL
293nopProcessingInstruction(void *UNUSED_P(userData), const XML_Char *UNUSED_P(target),
294                         const XML_Char *UNUSED_P(data))
295{
296}
297
298static void XMLCALL
299markup(void *userData, const XML_Char *s, int len)
300{
301  FILE *fp = (FILE *)XML_GetUserData((XML_Parser) userData);
302  for (; len > 0; --len, ++s)
303    puttc(*s, fp);
304}
305
306static void
307metaLocation(XML_Parser parser)
308{
309  const XML_Char *uri = XML_GetBase(parser);
310  if (uri)
311    ftprintf((FILE *)XML_GetUserData(parser), T(" uri=\"%s\""), uri);
312  ftprintf((FILE *)XML_GetUserData(parser),
313           T(" byte=\"%" XML_FMT_INT_MOD "d\" nbytes=\"%d\" \
314			 line=\"%" XML_FMT_INT_MOD "u\" col=\"%" XML_FMT_INT_MOD "u\""),
315           XML_GetCurrentByteIndex(parser),
316           XML_GetCurrentByteCount(parser),
317           XML_GetCurrentLineNumber(parser),
318           XML_GetCurrentColumnNumber(parser));
319}
320
321static void
322metaStartDocument(void *userData)
323{
324  fputts(T("<document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
325}
326
327static void
328metaEndDocument(void *userData)
329{
330  fputts(T("</document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
331}
332
333static void XMLCALL
334metaStartElement(void *userData, const XML_Char *name,
335                 const XML_Char **atts)
336{
337  XML_Parser parser = (XML_Parser) userData;
338  FILE *fp = (FILE *)XML_GetUserData(parser);
339  const XML_Char **specifiedAttsEnd
340    = atts + XML_GetSpecifiedAttributeCount(parser);
341  const XML_Char **idAttPtr;
342  int idAttIndex = XML_GetIdAttributeIndex(parser);
343  if (idAttIndex < 0)
344    idAttPtr = 0;
345  else
346    idAttPtr = atts + idAttIndex;
347
348  ftprintf(fp, T("<starttag name=\"%s\""), name);
349  metaLocation(parser);
350  if (*atts) {
351    fputts(T(">\n"), fp);
352    do {
353      ftprintf(fp, T("<attribute name=\"%s\" value=\""), atts[0]);
354      characterData(fp, atts[1], (int)tcslen(atts[1]));
355      if (atts >= specifiedAttsEnd)
356        fputts(T("\" defaulted=\"yes\"/>\n"), fp);
357      else if (atts == idAttPtr)
358        fputts(T("\" id=\"yes\"/>\n"), fp);
359      else
360        fputts(T("\"/>\n"), fp);
361    } while (*(atts += 2));
362    fputts(T("</starttag>\n"), fp);
363  }
364  else
365    fputts(T("/>\n"), fp);
366}
367
368static void XMLCALL
369metaEndElement(void *userData, const XML_Char *name)
370{
371  XML_Parser parser = (XML_Parser) userData;
372  FILE *fp = (FILE *)XML_GetUserData(parser);
373  ftprintf(fp, T("<endtag name=\"%s\""), name);
374  metaLocation(parser);
375  fputts(T("/>\n"), fp);
376}
377
378static void XMLCALL
379metaProcessingInstruction(void *userData, const XML_Char *target,
380                          const XML_Char *data)
381{
382  XML_Parser parser = (XML_Parser) userData;
383  FILE *fp = (FILE *)XML_GetUserData(parser);
384  ftprintf(fp, T("<pi target=\"%s\" data=\""), target);
385  characterData(fp, data, (int)tcslen(data));
386  puttc(T('"'), fp);
387  metaLocation(parser);
388  fputts(T("/>\n"), fp);
389}
390
391static void XMLCALL
392metaComment(void *userData, const XML_Char *data)
393{
394  XML_Parser parser = (XML_Parser) userData;
395  FILE *fp = (FILE *)XML_GetUserData(parser);
396  fputts(T("<comment data=\""), fp);
397  characterData(fp, data, (int)tcslen(data));
398  puttc(T('"'), fp);
399  metaLocation(parser);
400  fputts(T("/>\n"), fp);
401}
402
403static void XMLCALL
404metaStartCdataSection(void *userData)
405{
406  XML_Parser parser = (XML_Parser) userData;
407  FILE *fp = (FILE *)XML_GetUserData(parser);
408  fputts(T("<startcdata"), fp);
409  metaLocation(parser);
410  fputts(T("/>\n"), fp);
411}
412
413static void XMLCALL
414metaEndCdataSection(void *userData)
415{
416  XML_Parser parser = (XML_Parser) userData;
417  FILE *fp = (FILE *)XML_GetUserData(parser);
418  fputts(T("<endcdata"), fp);
419  metaLocation(parser);
420  fputts(T("/>\n"), fp);
421}
422
423static void XMLCALL
424metaCharacterData(void *userData, const XML_Char *s, int len)
425{
426  XML_Parser parser = (XML_Parser) userData;
427  FILE *fp = (FILE *)XML_GetUserData(parser);
428  fputts(T("<chars str=\""), fp);
429  characterData(fp, s, len);
430  puttc(T('"'), fp);
431  metaLocation(parser);
432  fputts(T("/>\n"), fp);
433}
434
435static void XMLCALL
436metaStartDoctypeDecl(void *userData,
437                     const XML_Char *doctypeName,
438                     const XML_Char *UNUSED_P(sysid),
439                     const XML_Char *UNUSED_P(pubid),
440                     int UNUSED_P(has_internal_subset))
441{
442  XML_Parser parser = (XML_Parser) userData;
443  FILE *fp = (FILE *)XML_GetUserData(parser);
444  ftprintf(fp, T("<startdoctype name=\"%s\""), doctypeName);
445  metaLocation(parser);
446  fputts(T("/>\n"), fp);
447}
448
449static void XMLCALL
450metaEndDoctypeDecl(void *userData)
451{
452  XML_Parser parser = (XML_Parser) userData;
453  FILE *fp = (FILE *)XML_GetUserData(parser);
454  fputts(T("<enddoctype"), fp);
455  metaLocation(parser);
456  fputts(T("/>\n"), fp);
457}
458
459static void XMLCALL
460metaNotationDecl(void *userData,
461                 const XML_Char *notationName,
462                 const XML_Char *UNUSED_P(base),
463                 const XML_Char *systemId,
464                 const XML_Char *publicId)
465{
466  XML_Parser parser = (XML_Parser) userData;
467  FILE *fp = (FILE *)XML_GetUserData(parser);
468  ftprintf(fp, T("<notation name=\"%s\""), notationName);
469  if (publicId)
470    ftprintf(fp, T(" public=\"%s\""), publicId);
471  if (systemId) {
472    fputts(T(" system=\""), fp);
473    characterData(fp, systemId, (int)tcslen(systemId));
474    puttc(T('"'), fp);
475  }
476  metaLocation(parser);
477  fputts(T("/>\n"), fp);
478}
479
480
481static void XMLCALL
482metaEntityDecl(void *userData,
483               const XML_Char *entityName,
484               int  UNUSED_P(is_param),
485               const XML_Char *value,
486               int  value_length,
487               const XML_Char *UNUSED_P(base),
488               const XML_Char *systemId,
489               const XML_Char *publicId,
490               const XML_Char *notationName)
491{
492  XML_Parser parser = (XML_Parser) userData;
493  FILE *fp = (FILE *)XML_GetUserData(parser);
494
495  if (value) {
496    ftprintf(fp, T("<entity name=\"%s\""), entityName);
497    metaLocation(parser);
498    puttc(T('>'), fp);
499    characterData(fp, value, value_length);
500    fputts(T("</entity/>\n"), fp);
501  }
502  else if (notationName) {
503    ftprintf(fp, T("<entity name=\"%s\""), entityName);
504    if (publicId)
505      ftprintf(fp, T(" public=\"%s\""), publicId);
506    fputts(T(" system=\""), fp);
507    characterData(fp, systemId, (int)tcslen(systemId));
508    puttc(T('"'), fp);
509    ftprintf(fp, T(" notation=\"%s\""), notationName);
510    metaLocation(parser);
511    fputts(T("/>\n"), fp);
512  }
513  else {
514    ftprintf(fp, T("<entity name=\"%s\""), entityName);
515    if (publicId)
516      ftprintf(fp, T(" public=\"%s\""), publicId);
517    fputts(T(" system=\""), fp);
518    characterData(fp, systemId, (int)tcslen(systemId));
519    puttc(T('"'), fp);
520    metaLocation(parser);
521    fputts(T("/>\n"), fp);
522  }
523}
524
525static void XMLCALL
526metaStartNamespaceDecl(void *userData,
527                       const XML_Char *prefix,
528                       const XML_Char *uri)
529{
530  XML_Parser parser = (XML_Parser) userData;
531  FILE *fp = (FILE *)XML_GetUserData(parser);
532  fputts(T("<startns"), fp);
533  if (prefix)
534    ftprintf(fp, T(" prefix=\"%s\""), prefix);
535  if (uri) {
536    fputts(T(" ns=\""), fp);
537    characterData(fp, uri, (int)tcslen(uri));
538    fputts(T("\"/>\n"), fp);
539  }
540  else
541    fputts(T("/>\n"), fp);
542}
543
544static void XMLCALL
545metaEndNamespaceDecl(void *userData, const XML_Char *prefix)
546{
547  XML_Parser parser = (XML_Parser) userData;
548  FILE *fp = (FILE *)XML_GetUserData(parser);
549  if (!prefix)
550    fputts(T("<endns/>\n"), fp);
551  else
552    ftprintf(fp, T("<endns prefix=\"%s\"/>\n"), prefix);
553}
554
555static int XMLCALL
556unknownEncodingConvert(void *data, const char *p)
557{
558  return codepageConvert(*(int *)data, p);
559}
560
561static int XMLCALL
562unknownEncoding(void *UNUSED_P(userData), const XML_Char *name, XML_Encoding *info)
563{
564  int cp;
565  static const XML_Char prefixL[] = T("windows-");
566  static const XML_Char prefixU[] = T("WINDOWS-");
567  int i;
568
569  for (i = 0; prefixU[i]; i++)
570    if (name[i] != prefixU[i] && name[i] != prefixL[i])
571      return 0;
572
573  cp = 0;
574  for (; name[i]; i++) {
575    static const XML_Char digits[] = T("0123456789");
576    const XML_Char *s = tcschr(digits, name[i]);
577    if (!s)
578      return 0;
579    cp *= 10;
580    cp += (int)(s - digits);
581    if (cp >= 0x10000)
582      return 0;
583  }
584  if (!codepageMap(cp, info->map))
585    return 0;
586  info->convert = unknownEncodingConvert;
587  /* We could just cast the code page integer to a void *,
588  and avoid the use of release. */
589  info->release = free;
590  info->data = malloc(sizeof(int));
591  if (!info->data)
592    return 0;
593  *(int *)info->data = cp;
594  return 1;
595}
596
597static int XMLCALL
598notStandalone(void *UNUSED_P(userData))
599{
600  return 0;
601}
602
603static void
604showVersion(XML_Char *prog)
605{
606  XML_Char *s = prog;
607  XML_Char ch;
608  const XML_Feature *features = XML_GetFeatureList();
609  while ((ch = *s) != 0) {
610    if (ch == '/'
611#if (defined(WIN32) || defined(__WATCOMC__))
612        || ch == '\\'
613#endif
614        )
615      prog = s + 1;
616    ++s;
617  }
618  ftprintf(stdout, T("%s using %s\n"), prog, XML_ExpatVersion());
619  if (features != NULL && features[0].feature != XML_FEATURE_END) {
620    int i = 1;
621    ftprintf(stdout, T("%s"), features[0].name);
622    if (features[0].value)
623      ftprintf(stdout, T("=%ld"), features[0].value);
624    while (features[i].feature != XML_FEATURE_END) {
625      ftprintf(stdout, T(", %s"), features[i].name);
626      if (features[i].value)
627        ftprintf(stdout, T("=%ld"), features[i].value);
628      ++i;
629    }
630    ftprintf(stdout, T("\n"));
631  }
632}
633
634static void
635usage(const XML_Char *prog, int rc)
636{
637  ftprintf(stderr,
638           T("usage: %s [-s] [-n] [-p] [-x] [-e encoding] [-w] [-d output-dir] [-c] [-m] [-r] [-t] [file ...]\n"), prog);
639  exit(rc);
640}
641
642int
643tmain(int argc, XML_Char **argv)
644{
645  int i, j;
646  const XML_Char *outputDir = NULL;
647  const XML_Char *encoding = NULL;
648  unsigned processFlags = XML_MAP_FILE;
649  int windowsCodePages = 0;
650  int outputType = 0;
651  int useNamespaces = 0;
652  int requireStandalone = 0;
653  enum XML_ParamEntityParsing paramEntityParsing =
654    XML_PARAM_ENTITY_PARSING_NEVER;
655  int useStdin = 0;
656
657#ifdef _MSC_VER
658  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
659#endif
660
661  i = 1;
662  j = 0;
663  while (i < argc) {
664    if (j == 0) {
665      if (argv[i][0] != T('-'))
666        break;
667      if (argv[i][1] == T('-') && argv[i][2] == T('\0')) {
668        i++;
669        break;
670      }
671      j++;
672    }
673    switch (argv[i][j]) {
674    case T('r'):
675      processFlags &= ~XML_MAP_FILE;
676      j++;
677      break;
678    case T('s'):
679      requireStandalone = 1;
680      j++;
681      break;
682    case T('n'):
683      useNamespaces = 1;
684      j++;
685      break;
686    case T('p'):
687      paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS;
688      /* fall through */
689    case T('x'):
690      processFlags |= XML_EXTERNAL_ENTITIES;
691      j++;
692      break;
693    case T('w'):
694      windowsCodePages = 1;
695      j++;
696      break;
697    case T('m'):
698      outputType = 'm';
699      j++;
700      break;
701    case T('c'):
702      outputType = 'c';
703      useNamespaces = 0;
704      j++;
705      break;
706    case T('t'):
707      outputType = 't';
708      j++;
709      break;
710    case T('d'):
711      if (argv[i][j + 1] == T('\0')) {
712        if (++i == argc)
713          usage(argv[0], 2);
714        outputDir = argv[i];
715      }
716      else
717        outputDir = argv[i] + j + 1;
718      i++;
719      j = 0;
720      break;
721    case T('e'):
722      if (argv[i][j + 1] == T('\0')) {
723        if (++i == argc)
724          usage(argv[0], 2);
725        encoding = argv[i];
726      }
727      else
728        encoding = argv[i] + j + 1;
729      i++;
730      j = 0;
731      break;
732    case T('h'):
733      usage(argv[0], 0);
734      return 0;
735    case T('v'):
736      showVersion(argv[0]);
737      return 0;
738    case T('\0'):
739      if (j > 1) {
740        i++;
741        j = 0;
742        break;
743      }
744      /* fall through */
745    default:
746      usage(argv[0], 2);
747    }
748  }
749  if (i == argc) {
750    useStdin = 1;
751    processFlags &= ~XML_MAP_FILE;
752    i--;
753  }
754  for (; i < argc; i++) {
755    FILE *fp = 0;
756    XML_Char *outName = 0;
757    int result;
758    XML_Parser parser;
759    if (useNamespaces)
760      parser = XML_ParserCreateNS(encoding, NSSEP);
761    else
762      parser = XML_ParserCreate(encoding);
763
764    if (! parser) {
765      tperror("Could not instantiate parser");
766      exit(1);
767    }
768
769    if (requireStandalone)
770      XML_SetNotStandaloneHandler(parser, notStandalone);
771    XML_SetParamEntityParsing(parser, paramEntityParsing);
772    if (outputType == 't') {
773      /* This is for doing timings; this gives a more realistic estimate of
774         the parsing time. */
775      outputDir = 0;
776      XML_SetElementHandler(parser, nopStartElement, nopEndElement);
777      XML_SetCharacterDataHandler(parser, nopCharacterData);
778      XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction);
779    }
780    else if (outputDir) {
781      const XML_Char * delim = T("/");
782      const XML_Char *file = useStdin ? T("STDIN") : argv[i];
783      if (!useStdin) {
784        /* Jump after last (back)slash */
785        const XML_Char * lastDelim = tcsrchr(file, delim[0]);
786        if (lastDelim)
787          file = lastDelim + 1;
788#if (defined(WIN32) || defined(__WATCOMC__))
789        else {
790          const XML_Char * winDelim = T("\\");
791          lastDelim = tcsrchr(file, winDelim[0]);
792          if (lastDelim) {
793            file = lastDelim + 1;
794            delim = winDelim;
795          }
796        }
797#endif
798      }
799      outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2)
800                       * sizeof(XML_Char));
801      tcscpy(outName, outputDir);
802      tcscat(outName, delim);
803      tcscat(outName, file);
804      fp = tfopen(outName, T("wb"));
805      if (!fp) {
806        tperror(outName);
807        exit(1);
808      }
809      setvbuf(fp, NULL, _IOFBF, 16384);
810#ifdef XML_UNICODE
811      puttc(0xFEFF, fp);
812#endif
813      XML_SetUserData(parser, fp);
814      switch (outputType) {
815      case 'm':
816        XML_UseParserAsHandlerArg(parser);
817        XML_SetElementHandler(parser, metaStartElement, metaEndElement);
818        XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction);
819        XML_SetCommentHandler(parser, metaComment);
820        XML_SetCdataSectionHandler(parser, metaStartCdataSection,
821                                   metaEndCdataSection);
822        XML_SetCharacterDataHandler(parser, metaCharacterData);
823        XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl,
824                                  metaEndDoctypeDecl);
825        XML_SetEntityDeclHandler(parser, metaEntityDecl);
826        XML_SetNotationDeclHandler(parser, metaNotationDecl);
827        XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl,
828                                    metaEndNamespaceDecl);
829        metaStartDocument(parser);
830        break;
831      case 'c':
832        XML_UseParserAsHandlerArg(parser);
833        XML_SetDefaultHandler(parser, markup);
834        XML_SetElementHandler(parser, defaultStartElement, defaultEndElement);
835        XML_SetCharacterDataHandler(parser, defaultCharacterData);
836        XML_SetProcessingInstructionHandler(parser,
837                                            defaultProcessingInstruction);
838        break;
839      default:
840        if (useNamespaces)
841          XML_SetElementHandler(parser, startElementNS, endElementNS);
842        else
843          XML_SetElementHandler(parser, startElement, endElement);
844        XML_SetCharacterDataHandler(parser, characterData);
845#ifndef W3C14N
846        XML_SetProcessingInstructionHandler(parser, processingInstruction);
847#endif /* not W3C14N */
848        break;
849      }
850    }
851    if (windowsCodePages)
852      XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0);
853    result = XML_ProcessFile(parser, useStdin ? NULL : argv[i], processFlags);
854    if (outputDir) {
855      if (outputType == 'm')
856        metaEndDocument(parser);
857      fclose(fp);
858      if (!result) {
859        tremove(outName);
860        exit(2);
861      }
862      free(outName);
863    }
864    XML_ParserFree(parser);
865  }
866  return 0;
867}
868