[BZ #40]
[platform/upstream/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 For bug reporting instructions, please see:\n\
410 <http://www.gnu.org/software/libc/bugs.html>.\n"));
411     default:
412       break;
413     }
414   return (char *) text;
415 }
416
417
418 /* Print the version information.  */
419 static void
420 print_version (FILE *stream, struct argp_state *state)
421 {
422   fprintf (stream, "iconv (GNU %s) %s\n", PACKAGE, VERSION);
423   fprintf (stream, gettext ("\
424 Copyright (C) %s Free Software Foundation, Inc.\n\
425 This is free software; see the source for copying conditions.  There is NO\n\
426 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
427 "), "2004");
428   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
429 }
430
431
432 static int
433 process_block (iconv_t cd, char *addr, size_t len, FILE *output)
434 {
435 #define OUTBUF_SIZE     32768
436   const char *start = addr;
437   char outbuf[OUTBUF_SIZE];
438   char *outptr;
439   size_t outlen;
440   size_t n;
441   int ret = 0;
442
443   while (len > 0)
444     {
445       outptr = outbuf;
446       outlen = OUTBUF_SIZE;
447       n = iconv (cd, &addr, &len, &outptr, &outlen);
448
449       if (n == (size_t) -1 && omit_invalid && errno == EILSEQ)
450         {
451           ret = 1;
452           if (len == 0)
453             n = 0;
454           else
455             errno = E2BIG;
456         }
457
458       if (outptr != outbuf)
459         {
460           /* We have something to write out.  */
461           int errno_save = errno;
462
463           if (fwrite (outbuf, 1, outptr - outbuf, output)
464               < (size_t) (outptr - outbuf)
465               || ferror (output))
466             {
467               /* Error occurred while printing the result.  */
468               error (0, 0, _("\
469 conversion stopped due to problem in writing the output"));
470               return -1;
471             }
472
473           errno = errno_save;
474         }
475
476       if (n != (size_t) -1)
477         {
478           /* All the input test is processed.  For state-dependent
479              character sets we have to flush the state now.  */
480           outptr = outbuf;
481           outlen = OUTBUF_SIZE;
482           n = iconv (cd, NULL, NULL, &outptr, &outlen);
483
484           if (outptr != outbuf)
485             {
486               /* We have something to write out.  */
487               int errno_save = errno;
488
489               if (fwrite (outbuf, 1, outptr - outbuf, output)
490                   < (size_t) (outptr - outbuf)
491                   || ferror (output))
492                 {
493                   /* Error occurred while printing the result.  */
494                   error (0, 0, _("\
495 conversion stopped due to problem in writing the output"));
496                   return -1;
497                 }
498
499               errno = errno_save;
500             }
501
502           if (n != (size_t) -1)
503             break;
504
505           if (omit_invalid && errno == EILSEQ)
506             {
507               ret = 1;
508               break;
509             }
510         }
511
512       if (errno != E2BIG)
513         {
514           /* iconv() ran into a problem.  */
515           switch (errno)
516             {
517             case EILSEQ:
518               if (! omit_invalid)
519                 error (0, 0, _("illegal input sequence at position %ld"),
520                        (long int) (addr - start));
521               break;
522             case EINVAL:
523               error (0, 0, _("\
524 incomplete character or shift sequence at end of buffer"));
525               break;
526             case EBADF:
527               error (0, 0, _("internal error (illegal descriptor)"));
528               break;
529             default:
530               error (0, 0, _("unknown iconv() error %d"), errno);
531               break;
532             }
533
534           return -1;
535         }
536     }
537
538   return ret;
539 }
540
541
542 static int
543 process_fd (iconv_t cd, int fd, FILE *output)
544 {
545   /* we have a problem with reading from a desriptor since we must not
546      provide the iconv() function an incomplete character or shift
547      sequence at the end of the buffer.  Since we have to deal with
548      arbitrary encodings we must read the whole text in a buffer and
549      process it in one step.  */
550   static char *inbuf = NULL;
551   static size_t maxlen = 0;
552   char *inptr = NULL;
553   size_t actlen = 0;
554
555   while (actlen < maxlen)
556     {
557       ssize_t n = read (fd, inptr, maxlen - actlen);
558
559       if (n == 0)
560         /* No more text to read.  */
561         break;
562
563       if (n == -1)
564         {
565           /* Error while reading.  */
566           error (0, errno, _("error while reading the input"));
567           return -1;
568         }
569
570       inptr += n;
571       actlen += n;
572     }
573
574   if (actlen == maxlen)
575     while (1)
576       {
577         ssize_t n;
578         char *new_inbuf;
579
580         /* Increase the buffer.  */
581         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
582         if (new_inbuf == NULL)
583           {
584             error (0, errno, _("unable to allocate buffer for input"));
585             return -1;
586           }
587         inbuf = new_inbuf;
588         maxlen += 32768;
589         inptr = inbuf + actlen;
590
591         do
592           {
593             n = read (fd, inptr, maxlen - actlen);
594
595             if (n == 0)
596               /* No more text to read.  */
597               break;
598
599             if (n == -1)
600               {
601                 /* Error while reading.  */
602                 error (0, errno, _("error while reading the input"));
603                 return -1;
604               }
605
606             inptr += n;
607             actlen += n;
608           }
609         while (actlen < maxlen);
610
611         if (n == 0)
612           /* Break again so we leave both loops.  */
613           break;
614       }
615
616   /* Now we have all the input in the buffer.  Process it in one run.  */
617   return process_block (cd, inbuf, actlen, output);
618 }
619
620
621 static int
622 process_file (iconv_t cd, FILE *input, FILE *output)
623 {
624   /* This should be safe since we use this function only for `stdin' and
625      we haven't read anything so far.  */
626   return process_fd (cd, fileno (input), output);
627 }
628
629
630 /* Print all known character sets/encodings.  */
631 static void *printlist;
632 static size_t column;
633 static int not_first;
634
635 static void
636 insert_print_list (const void *nodep, VISIT value, int level)
637 {
638   if (value == leaf || value == postorder)
639     {
640       const struct gconv_alias *s = *(const struct gconv_alias **) nodep;
641       tsearch (s->fromname, &printlist, (__compar_fn_t) strverscmp);
642     }
643 }
644
645 static void
646 do_print_human  (const void *nodep, VISIT value, int level)
647 {
648   if (value == leaf || value == postorder)
649     {
650       const char *s = *(const char **) nodep;
651       size_t len = strlen (s);
652       size_t cnt;
653
654       while (len > 0 && s[len - 1] == '/')
655         --len;
656
657       for (cnt = 0; cnt < len; ++cnt)
658         if (isalnum (s[cnt]))
659           break;
660       if (cnt == len)
661         return;
662
663       if (not_first)
664         {
665           putchar (',');
666           ++column;
667
668           if (column > 2 && column + len > 77)
669             {
670               fputs ("\n  ", stdout);
671               column = 2;
672             }
673           else
674             {
675               putchar (' ');
676               ++column;
677             }
678         }
679       else
680         not_first = 1;
681
682       fwrite (s, len, 1, stdout);
683       column += len;
684     }
685 }
686
687 static void
688 do_print  (const void *nodep, VISIT value, int level)
689 {
690   if (value == leaf || value == postorder)
691     {
692       const char *s = *(const char **) nodep;
693
694       puts (s);
695     }
696 }
697
698 static void
699 internal_function
700 add_known_names (struct gconv_module *node)
701 {
702   if (node->left != NULL)
703     add_known_names (node->left);
704   if (node->right != NULL)
705     add_known_names (node->right);
706   do
707     {
708       if (strcmp (node->from_string, "INTERNAL"))
709         tsearch (node->from_string, &printlist,
710                  (__compar_fn_t) strverscmp);
711       if (strcmp (node->to_string, "INTERNAL") != 0)
712         tsearch (node->to_string, &printlist, (__compar_fn_t) strverscmp);
713
714       node = node->same;
715     }
716   while (node != NULL);
717 }
718
719
720 static void
721 insert_cache (void)
722 {
723   const struct gconvcache_header *header;
724   const char *strtab;
725   const struct hash_entry *hashtab;
726   size_t cnt;
727
728   header = (const struct gconvcache_header *) __gconv_get_cache ();
729   strtab = (char *) header + header->string_offset;
730   hashtab = (struct hash_entry *) ((char *) header + header->hash_offset);
731
732   for (cnt = 0; cnt < header->hash_size; ++cnt)
733     if (hashtab[cnt].string_offset != 0)
734       {
735         const char *str = strtab + hashtab[cnt].string_offset;
736
737         if (strcmp (str, "INTERNAL") != 0)
738           tsearch (str, &printlist, (__compar_fn_t) strverscmp);
739       }
740 }
741
742
743 static void
744 internal_function
745 print_known_names (void)
746 {
747   iconv_t h;
748   void *cache;
749
750   /* We must initialize the internal databases first.  */
751   h = iconv_open ("L1", "L1");
752   iconv_close (h);
753
754   /* See whether we have a cache.  */
755   cache = __gconv_get_cache ();
756   if (cache != NULL)
757     /* Yep, use only this information.  */
758     insert_cache ();
759   else
760     {
761       struct gconv_module *modules;
762
763       /* No, then use the information read from the gconv-modules file.
764          First add the aliases.  */
765       twalk (__gconv_get_alias_db (), insert_print_list);
766
767       /* Add the from- and to-names from the known modules.  */
768       modules = __gconv_get_modules_db ();
769       if (modules != NULL)
770         add_known_names (modules);
771     }
772
773   fputs (_("\
774 The following list contain all the coded character sets known.  This does\n\
775 not necessarily mean that all combinations of these names can be used for\n\
776 the FROM and TO command line parameters.  One coded character set can be\n\
777 listed with several different names (aliases).\n\n  "), stdout);
778
779   /* Now print the collected names.  */
780   column = 2;
781   if (isatty (fileno (stdout)))
782     {
783       twalk (printlist, do_print_human);
784
785       if (column != 0)
786         puts ("");
787     }
788   else
789     twalk (printlist, do_print);
790 }