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