5455974f5cbe502f9309fc664cac038921fcf840
[platform/upstream/linaro-glibc.git] / iconv / iconv_prog.c
1 /* Convert text in given files from the specified from-set to the to-set.
2    Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <argp.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <error.h>
26 #include <fcntl.h>
27 #include <iconv.h>
28 #include <langinfo.h>
29 #include <locale.h>
30 #include <search.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <libintl.h>
37 #ifdef _POSIX_MAPPED_FILES
38 # include <sys/mman.h>
39 #endif
40 #include <charmap.h>
41 #include <gconv_int.h>
42 #include "iconv_prog.h"
43 #include "iconvconfig.h"
44
45 /* Get libc version number.  */
46 #include "../version.h"
47
48 #define PACKAGE _libc_intl_domainname
49
50
51 /* Name and version of program.  */
52 static void print_version (FILE *stream, struct argp_state *state);
53 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
54
55 #define OPT_VERBOSE     1000
56 #define OPT_LIST        'l'
57
58 /* Definitions of arguments for argp functions.  */
59 static const struct argp_option options[] =
60 {
61   { NULL, 0, NULL, 0, N_("Input/Output format specification:") },
62   { "from-code", 'f', "NAME", 0, N_("encoding of original text") },
63   { "to-code", 't', "NAME", 0, N_("encoding for output") },
64   { NULL, 0, NULL, 0, N_("Information:") },
65   { "list", 'l', NULL, 0, N_("list all known coded character sets") },
66   { NULL, 0, NULL, 0, N_("Output control:") },
67   { NULL, 'c', NULL, 0, N_("omit invalid characters from output") },
68   { "output", 'o', "FILE", 0, N_("output file") },
69   { "silent", 's', NULL, 0, N_("suppress warnings") },
70   { "verbose", OPT_VERBOSE, NULL, 0, N_("print progress information") },
71   { NULL, 0, NULL, 0, NULL }
72 };
73
74 /* Short description of program.  */
75 static const char doc[] = N_("\
76 Convert encoding of given files from one encoding to another.");
77
78 /* Strings for arguments in help texts.  */
79 static const char args_doc[] = N_("[FILE...]");
80
81 /* Prototype for option handler.  */
82 static error_t parse_opt (int key, char *arg, struct argp_state *state);
83
84 /* Function to print some extra text in the help message.  */
85 static char *more_help (int key, const char *text, void *input);
86
87 /* Data structure to communicate with argp functions.  */
88 static struct argp argp =
89 {
90   options, parse_opt, args_doc, doc, NULL, more_help
91 };
92
93 /* Code sets to convert from and to respectively.  An empty string as the
94    default causes the 'iconv_open' function to look up the charset of the
95    currently selected locale and use it.  */
96 static const char *from_code = "";
97 static const char *to_code = "";
98
99 /* File to write output to.  If NULL write to stdout.  */
100 static const char *output_file;
101
102 /* Nonzero if verbose ouput is wanted.  */
103 int verbose;
104
105 /* Nonzero if list of all coded character sets is wanted.  */
106 static int list;
107
108 /* If nonzero omit invalid character from output.  */
109 int omit_invalid;
110
111 /* Prototypes for the functions doing the actual work.  */
112 static int process_block (iconv_t cd, char *addr, size_t len, FILE *output);
113 static int process_fd (iconv_t cd, int fd, FILE *output);
114 static int process_file (iconv_t cd, FILE *input, FILE *output);
115 static void print_known_names (void) internal_function;
116
117
118 int
119 main (int argc, char *argv[])
120 {
121   int status = EXIT_SUCCESS;
122   int remaining;
123   FILE *output;
124   iconv_t cd;
125   const char *orig_to_code;
126   struct charmap_t *from_charmap = NULL;
127   struct charmap_t *to_charmap = NULL;
128
129   /* Set locale via LC_ALL.  */
130   setlocale (LC_ALL, "");
131
132   /* Set the text message domain.  */
133   textdomain (_libc_intl_domainname);
134
135   /* Parse and process arguments.  */
136   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
137
138   /* List all coded character sets if wanted.  */
139   if (list)
140     {
141       print_known_names ();
142       exit (EXIT_SUCCESS);
143     }
144
145   /* If we have to ignore errors make sure we use the appropriate name for
146      the to-character-set.  */
147   orig_to_code = to_code;
148   if (omit_invalid)
149     {
150       const char *errhand = strchrnul (to_code, '/');
151       int nslash = 2;
152       char *newp;
153       char *cp;
154
155       if (*errhand == '/')
156         {
157           --nslash;
158           errhand = strchrnul (errhand, '/');
159
160           if (*errhand == '/')
161             {
162               --nslash;
163               errhand = strchr (errhand, '\0');
164             }
165         }
166
167       newp = (char *) alloca (errhand - to_code + nslash + 7 + 1);
168       cp = mempcpy (newp, to_code, errhand - to_code);
169       while (nslash-- > 0)
170         *cp++ = '/';
171       if (cp[-1] != '/')
172         *cp++ = ',';
173       memcpy (cp, "IGNORE", sizeof ("IGNORE"));
174
175       to_code = newp;
176     }
177
178   /* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f
179      can be file names of charmaps.  In this case iconv will have to read
180      those charmaps and use them to do the conversion.  But there are
181      holes in the specification.  There is nothing said that if -f is a
182      charmap filename that -t must be, too.  And vice versa.  There is
183      also no word about the symbolic names used.  What if they don't
184      match?  */
185   if (strchr (from_code, '/') != NULL)
186     /* The from-name might be a charmap file name.  Try reading the
187        file.  */
188     from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0);
189
190   if (strchr (orig_to_code, '/') != NULL)
191     /* The to-name might be a charmap file name.  Try reading the
192        file.  */
193     to_charmap = charmap_read (orig_to_code, /*0, 1,*/1,0, 0);
194
195
196   /* Determine output file.  */
197   if (output_file != NULL && strcmp (output_file, "-") != 0)
198     {
199       output = fopen (output_file, "w");
200       if (output == NULL)
201         error (EXIT_FAILURE, errno, _("cannot open output file"));
202     }
203   else
204     output = stdout;
205
206   /* At this point we have to handle two cases.  The first one is
207      where a charmap is used for the from- or to-charset, or both.  We
208      handle this special since it is very different from the sane way of
209      doing things.  The other case allows converting using the iconv()
210      function.  */
211   if (from_charmap != NULL || to_charmap != NULL)
212     /* Construct the conversion table and do the conversion.  */
213     status = charmap_conversion (from_code, from_charmap, to_code, to_charmap,
214                                  argc, remaining, argv, output);
215   else
216     {
217       /* Let's see whether we have these coded character sets.  */
218       cd = iconv_open (to_code, from_code);
219       if (cd == (iconv_t) -1)
220         {
221           if (errno == EINVAL)
222             {
223               /* Try to be nice with the user and tell her which of the
224                  two encoding names is wrong.  This is possible because
225                  all supported encodings can be converted from/to Unicode,
226                  in other words, because the graph of encodings is
227                  connected.  */
228               bool from_wrong =
229                 (iconv_open ("UTF-8", from_code) == (iconv_t) -1
230                  && errno == EINVAL);
231               bool to_wrong =
232                 (iconv_open (to_code, "UTF-8") == (iconv_t) -1
233                  && errno == EINVAL);
234               const char *from_pretty =
235                 (from_code[0] ? from_code : nl_langinfo (CODESET));
236               const char *to_pretty =
237                 (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
238
239               if (from_wrong)
240                 {
241                   if (to_wrong)
242                     error (EXIT_FAILURE, 0,
243                            _("\
244 conversion from `%s' and to `%s' are not supported"),
245                            from_pretty, to_pretty);
246                   else
247                     error (EXIT_FAILURE, 0,
248                            _("conversion from `%s' is not supported"),
249                            from_pretty);
250                 }
251               else
252                 {
253                   if (to_wrong)
254                     error (EXIT_FAILURE, 0,
255                            _("conversion to `%s' is not supported"),
256                            to_pretty);
257                   else
258                     error (EXIT_FAILURE, 0,
259                            _("conversion from `%s' to `%s' is not supported"),
260                            from_pretty, to_pretty);
261                 }
262             }
263           else
264             error (EXIT_FAILURE, errno,
265                    _("failed to start conversion processing"));
266         }
267
268       /* Now process the remaining files.  Write them to stdout or the file
269          specified with the `-o' parameter.  If we have no file given as
270          the parameter process all from stdin.  */
271       if (remaining == argc)
272         {
273           if (process_file (cd, stdin, output) != 0)
274             status = EXIT_FAILURE;
275         }
276       else
277         do
278           {
279 #ifdef _POSIX_MAPPED_FILES
280             struct stat st;
281             char *addr;
282 #endif
283             int fd, ret;
284
285             if (verbose)
286               printf ("%s:\n", argv[remaining]);
287             if (strcmp (argv[remaining], "-") == 0)
288               fd = 0;
289             else
290               {
291                 fd = open (argv[remaining], O_RDONLY);
292
293                 if (fd == -1)
294                   {
295                     error (0, errno, _("cannot open input file `%s'"),
296                            argv[remaining]);
297                     status = EXIT_FAILURE;
298                     continue;
299                   }
300               }
301
302 #ifdef _POSIX_MAPPED_FILES
303             /* We have possibilities for reading the input file.  First try
304                to mmap() it since this will provide the fastest solution.  */
305             if (fstat (fd, &st) == 0
306                 && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
307                                   fd, 0)) != MAP_FAILED))
308               {
309                 /* Yes, we can use mmap().  The descriptor is not needed
310                    anymore.  */
311                 if (close (fd) != 0)
312                   error (EXIT_FAILURE, errno,
313                          _("error while closing input `%s'"),
314                          argv[remaining]);
315
316                 ret = process_block (cd, addr, st.st_size, output);
317
318                 /* We don't need the input data anymore.  */
319                 munmap ((void *) addr, st.st_size);
320
321                 if (ret != 0)
322                   {
323                     status = EXIT_FAILURE;
324
325                     if (ret < 0)
326                       /* We cannot go on with producing output since it might
327                          lead to problem because the last output might leave
328                          the output stream in an undefined state.  */
329                       break;
330                   }
331               }
332             else
333 #endif  /* _POSIX_MAPPED_FILES */
334               {
335                 /* Read the file in pieces.  */
336                 ret = process_fd (cd, fd, output);
337
338                 /* Now close the file.  */
339                 close (fd);
340
341                 if (ret != 0)
342                   {
343                     /* Something went wrong.  */
344                     status = EXIT_FAILURE;
345
346                     if (ret < 0)
347                       /* We cannot go on with producing output since it might
348                          lead to problem because the last output might leave
349                          the output stream in an undefined state.  */
350                       break;
351                   }
352               }
353           }
354         while (++remaining < argc);
355     }
356
357   /* Close the output file now.  */
358   if (fclose (output))
359     error (EXIT_FAILURE, errno, _("error while closing output file"));
360
361   return status;
362 }
363
364
365 /* Handle program arguments.  */
366 static error_t
367 parse_opt (int key, char *arg, struct argp_state *state)
368 {
369   switch (key)
370     {
371     case 'f':
372       from_code = arg;
373       break;
374     case 't':
375       to_code = arg;
376       break;
377     case 'o':
378       output_file = arg;
379       break;
380     case 's':
381       /* Nothing, for now at least.  We are not giving out any information
382          about missing character or so.  */
383       break;
384     case 'c':
385       /* Omit invalid characters from output.  */
386       omit_invalid = 1;
387       break;
388     case OPT_VERBOSE:
389       verbose = 1;
390       break;
391     case OPT_LIST:
392       list = 1;
393       break;
394     default:
395       return ARGP_ERR_UNKNOWN;
396     }
397   return 0;
398 }
399
400
401 static char *
402 more_help (int key, const char *text, void *input)
403 {
404   switch (key)
405     {
406     case ARGP_KEY_HELP_EXTRA:
407       /* We print some extra information.  */
408       return strdup (gettext ("\
409 Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
410     default:
411       break;
412     }
413   return (char *) text;
414 }
415
416
417 /* Print the version information.  */
418 static void
419 print_version (FILE *stream, struct argp_state *state)
420 {
421   fprintf (stream, "iconv (GNU %s) %s\n", PACKAGE, VERSION);
422   fprintf (stream, gettext ("\
423 Copyright (C) %s Free Software Foundation, Inc.\n\
424 This is free software; see the source for copying conditions.  There is NO\n\
425 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
426 "), "2004");
427   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
428 }
429
430
431 static int
432 process_block (iconv_t cd, char *addr, size_t len, FILE *output)
433 {
434 #define OUTBUF_SIZE     32768
435   const char *start = addr;
436   char outbuf[OUTBUF_SIZE];
437   char *outptr;
438   size_t outlen;
439   size_t n;
440   int ret = 0;
441
442   while (len > 0)
443     {
444       outptr = outbuf;
445       outlen = OUTBUF_SIZE;
446       n = iconv (cd, &addr, &len, &outptr, &outlen);
447
448       if (n == (size_t) -1 && omit_invalid && errno == EILSEQ)
449         {
450           ret = 1;
451           if (len == 0)
452             n = 0;
453           else
454             errno = E2BIG;
455         }
456
457       if (outptr != outbuf)
458         {
459           /* We have something to write out.  */
460           int errno_save = errno;
461
462           if (fwrite (outbuf, 1, outptr - outbuf, output)
463               < (size_t) (outptr - outbuf)
464               || ferror (output))
465             {
466               /* Error occurred while printing the result.  */
467               error (0, 0, _("\
468 conversion stopped due to problem in writing the output"));
469               return -1;
470             }
471
472           errno = errno_save;
473         }
474
475       if (n != (size_t) -1)
476         {
477           /* All the input test is processed.  For state-dependent
478              character sets we have to flush the state now.  */
479           outptr = outbuf;
480           outlen = OUTBUF_SIZE;
481           n = iconv (cd, NULL, NULL, &outptr, &outlen);
482
483           if (outptr != outbuf)
484             {
485               /* We have something to write out.  */
486               int errno_save = errno;
487
488               if (fwrite (outbuf, 1, outptr - outbuf, output)
489                   < (size_t) (outptr - outbuf)
490                   || ferror (output))
491                 {
492                   /* Error occurred while printing the result.  */
493                   error (0, 0, _("\
494 conversion stopped due to problem in writing the output"));
495                   return -1;
496                 }
497
498               errno = errno_save;
499             }
500
501           if (n != (size_t) -1)
502             break;
503
504           if (omit_invalid && errno == EILSEQ)
505             {
506               ret = 1;
507               break;
508             }
509         }
510
511       if (errno != E2BIG)
512         {
513           /* iconv() ran into a problem.  */
514           switch (errno)
515             {
516             case EILSEQ:
517               if (! omit_invalid)
518                 error (0, 0, _("illegal input sequence at position %ld"),
519                        (long int) (addr - start));
520               break;
521             case EINVAL:
522               error (0, 0, _("\
523 incomplete character or shift sequence at end of buffer"));
524               break;
525             case EBADF:
526               error (0, 0, _("internal error (illegal descriptor)"));
527               break;
528             default:
529               error (0, 0, _("unknown iconv() error %d"), errno);
530               break;
531             }
532
533           return -1;
534         }
535     }
536
537   return ret;
538 }
539
540
541 static int
542 process_fd (iconv_t cd, int fd, FILE *output)
543 {
544   /* we have a problem with reading from a desriptor since we must not
545      provide the iconv() function an incomplete character or shift
546      sequence at the end of the buffer.  Since we have to deal with
547      arbitrary encodings we must read the whole text in a buffer and
548      process it in one step.  */
549   static char *inbuf = NULL;
550   static size_t maxlen = 0;
551   char *inptr = NULL;
552   size_t actlen = 0;
553
554   while (actlen < maxlen)
555     {
556       ssize_t n = read (fd, inptr, maxlen - actlen);
557
558       if (n == 0)
559         /* No more text to read.  */
560         break;
561
562       if (n == -1)
563         {
564           /* Error while reading.  */
565           error (0, errno, _("error while reading the input"));
566           return -1;
567         }
568
569       inptr += n;
570       actlen += n;
571     }
572
573   if (actlen == maxlen)
574     while (1)
575       {
576         ssize_t n;
577         char *new_inbuf;
578
579         /* Increase the buffer.  */
580         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
581         if (new_inbuf == NULL)
582           {
583             error (0, errno, _("unable to allocate buffer for input"));
584             return -1;
585           }
586         inbuf = new_inbuf;
587         maxlen += 32768;
588         inptr = inbuf + actlen;
589
590         do
591           {
592             n = read (fd, inptr, maxlen - actlen);
593
594             if (n == 0)
595               /* No more text to read.  */
596               break;
597
598             if (n == -1)
599               {
600                 /* Error while reading.  */
601                 error (0, errno, _("error while reading the input"));
602                 return -1;
603               }
604
605             inptr += n;
606             actlen += n;
607           }
608         while (actlen < maxlen);
609
610         if (n == 0)
611           /* Break again so we leave both loops.  */
612           break;
613       }
614
615   /* Now we have all the input in the buffer.  Process it in one run.  */
616   return process_block (cd, inbuf, actlen, output);
617 }
618
619
620 static int
621 process_file (iconv_t cd, FILE *input, FILE *output)
622 {
623   /* This should be safe since we use this function only for `stdin' and
624      we haven't read anything so far.  */
625   return process_fd (cd, fileno (input), output);
626 }
627
628
629 /* Print all known character sets/encodings.  */
630 static void *printlist;
631 static size_t column;
632 static int not_first;
633
634 static void
635 insert_print_list (const void *nodep, VISIT value, int level)
636 {
637   if (value == leaf || value == postorder)
638     {
639       const struct gconv_alias *s = *(const struct gconv_alias **) nodep;
640       tsearch (s->fromname, &printlist, (__compar_fn_t) strverscmp);
641     }
642 }
643
644 static void
645 do_print_human  (const void *nodep, VISIT value, int level)
646 {
647   if (value == leaf || value == postorder)
648     {
649       const char *s = *(const char **) nodep;
650       size_t len = strlen (s);
651       size_t cnt;
652
653       while (len > 0 && s[len - 1] == '/')
654         --len;
655
656       for (cnt = 0; cnt < len; ++cnt)
657         if (isalnum (s[cnt]))
658           break;
659       if (cnt == len)
660         return;
661
662       if (not_first)
663         {
664           putchar (',');
665           ++column;
666
667           if (column > 2 && column + len > 77)
668             {
669               fputs ("\n  ", stdout);
670               column = 2;
671             }
672           else
673             {
674               putchar (' ');
675               ++column;
676             }
677         }
678       else
679         not_first = 1;
680
681       fwrite (s, len, 1, stdout);
682       column += len;
683     }
684 }
685
686 static void
687 do_print  (const void *nodep, VISIT value, int level)
688 {
689   if (value == leaf || value == postorder)
690     {
691       const char *s = *(const char **) nodep;
692
693       puts (s);
694     }
695 }
696
697 static void
698 internal_function
699 add_known_names (struct gconv_module *node)
700 {
701   if (node->left != NULL)
702     add_known_names (node->left);
703   if (node->right != NULL)
704     add_known_names (node->right);
705   do
706     {
707       if (strcmp (node->from_string, "INTERNAL"))
708         tsearch (node->from_string, &printlist,
709                  (__compar_fn_t) strverscmp);
710       if (strcmp (node->to_string, "INTERNAL") != 0)
711         tsearch (node->to_string, &printlist, (__compar_fn_t) strverscmp);
712
713       node = node->same;
714     }
715   while (node != NULL);
716 }
717
718
719 static void
720 insert_cache (void)
721 {
722   const struct gconvcache_header *header;
723   const char *strtab;
724   const struct hash_entry *hashtab;
725   size_t cnt;
726
727   header = (const struct gconvcache_header *) __gconv_get_cache ();
728   strtab = (char *) header + header->string_offset;
729   hashtab = (struct hash_entry *) ((char *) header + header->hash_offset);
730
731   for (cnt = 0; cnt < header->hash_size; ++cnt)
732     if (hashtab[cnt].string_offset != 0)
733       {
734         const char *str = strtab + hashtab[cnt].string_offset;
735
736         if (strcmp (str, "INTERNAL") != 0)
737           tsearch (str, &printlist, (__compar_fn_t) strverscmp);
738       }
739 }
740
741
742 static void
743 internal_function
744 print_known_names (void)
745 {
746   iconv_t h;
747   void *cache;
748
749   /* We must initialize the internal databases first.  */
750   h = iconv_open ("L1", "L1");
751   iconv_close (h);
752
753   /* See whether we have a cache.  */
754   cache = __gconv_get_cache ();
755   if (cache != NULL)
756     /* Yep, use only this information.  */
757     insert_cache ();
758   else
759     {
760       struct gconv_module *modules;
761
762       /* No, then use the information read from the gconv-modules file.
763          First add the aliases.  */
764       twalk (__gconv_get_alias_db (), insert_print_list);
765
766       /* Add the from- and to-names from the known modules.  */
767       modules = __gconv_get_modules_db ();
768       if (modules != NULL)
769         add_known_names (modules);
770     }
771
772   fputs (_("\
773 The following list contain all the coded character sets known.  This does\n\
774 not necessarily mean that all combinations of these names can be used for\n\
775 the FROM and TO command line parameters.  One coded character set can be\n\
776 listed with several different names (aliases).\n\n  "), stdout);
777
778   /* Now print the collected names.  */
779   column = 2;
780   if (isatty (fileno (stdout)))
781     {
782       twalk (printlist, do_print_human);
783
784       if (column != 0)
785         puts ("");
786     }
787   else
788     twalk (printlist, do_print);
789 }