(process_block): Don't print message about invliad input if the -c option is used.
[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,1999,2000,2001,2002,2003 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;
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                 if (process_block (cd, addr, st.st_size, output) < 0)
317                   {
318                     /* Something went wrong.  */
319                     status = EXIT_FAILURE;
320
321                     /* We don't need the input data anymore.  */
322                     munmap ((void *) addr, st.st_size);
323
324                     /* We cannot go on with producing output since it might
325                        lead to problem because the last output might leave
326                        the output stream in an undefined state.  */
327                     break;
328                   }
329
330                 /* We don't need the input data anymore.  */
331                 munmap ((void *) addr, st.st_size);
332               }
333             else
334 #endif  /* _POSIX_MAPPED_FILES */
335               {
336                 /* Read the file in pieces.  */
337                 if (process_fd (cd, fd, output) != 0)
338                   {
339                     /* Something went wrong.  */
340                     status = EXIT_FAILURE;
341
342                     /* We don't need the input file anymore.  */
343                     close (fd);
344
345                     /* We cannot go on with producing output since it might
346                        lead to problem because the last output might leave
347                        the output stream in an undefined state.  */
348                     break;
349                   }
350
351                 /* Now close the file.  */
352                 close (fd);
353               }
354           }
355         while (++remaining < argc);
356     }
357
358   /* Close the output file now.  */
359   if (fclose (output))
360     error (EXIT_FAILURE, errno, _("error while closing output file"));
361
362   return status;
363 }
364
365
366 /* Handle program arguments.  */
367 static error_t
368 parse_opt (int key, char *arg, struct argp_state *state)
369 {
370   switch (key)
371     {
372     case 'f':
373       from_code = arg;
374       break;
375     case 't':
376       to_code = arg;
377       break;
378     case 'o':
379       output_file = arg;
380       break;
381     case 's':
382       /* Nothing, for now at least.  We are not giving out any information
383          about missing character or so.  */
384       break;
385     case 'c':
386       /* Omit invalid characters from output.  */
387       omit_invalid = 1;
388       break;
389     case OPT_VERBOSE:
390       verbose = 1;
391       break;
392     case OPT_LIST:
393       list = 1;
394       break;
395     default:
396       return ARGP_ERR_UNKNOWN;
397     }
398   return 0;
399 }
400
401
402 static char *
403 more_help (int key, const char *text, void *input)
404 {
405   switch (key)
406     {
407     case ARGP_KEY_HELP_EXTRA:
408       /* We print some extra information.  */
409       return strdup (gettext ("\
410 Report bugs using the `glibcbug' script to <bugs@gnu.org>.\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 "), "2003");
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
442   while (len > 0)
443     {
444       outptr = outbuf;
445       outlen = OUTBUF_SIZE;
446       n = iconv (cd, &addr, &len, &outptr, &outlen);
447
448       if (outptr != outbuf)
449         {
450           /* We have something to write out.  */
451           int errno_save = errno;
452
453           if (fwrite (outbuf, 1, outptr - outbuf, output)
454               < (size_t) (outptr - outbuf)
455               || ferror (output))
456             {
457               /* Error occurred while printing the result.  */
458               error (0, 0, _("\
459 conversion stopped due to problem in writing the output"));
460               return -1;
461             }
462
463           errno = errno_save;
464         }
465
466       if (n != (size_t) -1)
467         {
468           /* All the input test is processed.  For state-dependent
469              character sets we have to flush the state now.  */
470           outptr = outbuf;
471           outlen = OUTBUF_SIZE;
472           (void) iconv (cd, NULL, NULL, &outptr, &outlen);
473
474           if (outptr != outbuf)
475             {
476               /* We have something to write out.  */
477               int errno_save = errno;
478
479               if (fwrite (outbuf, 1, outptr - outbuf, output)
480                   < (size_t) (outptr - outbuf)
481                   || ferror (output))
482                 {
483                   /* Error occurred while printing the result.  */
484                   error (0, 0, _("\
485 conversion stopped due to problem in writing the output"));
486                   return -1;
487                 }
488
489               errno = errno_save;
490             }
491
492           break;
493         }
494
495       if (errno != E2BIG)
496         {
497           /* iconv() ran into a problem.  */
498           switch (errno)
499             {
500             case EILSEQ:
501               if (! omit_invalid)
502                 error (0, 0, _("illegal input sequence at position %ld"),
503                        (long int) (addr - start));
504               break;
505             case EINVAL:
506               error (0, 0, _("\
507 incomplete character or shift sequence at end of buffer"));
508               break;
509             case EBADF:
510               error (0, 0, _("internal error (illegal descriptor)"));
511               break;
512             default:
513               error (0, 0, _("unknown iconv() error %d"), errno);
514               break;
515             }
516
517           return -1;
518         }
519     }
520
521   return 0;
522 }
523
524
525 static int
526 process_fd (iconv_t cd, int fd, FILE *output)
527 {
528   /* we have a problem with reading from a desriptor since we must not
529      provide the iconv() function an incomplete character or shift
530      sequence at the end of the buffer.  Since we have to deal with
531      arbitrary encodings we must read the whole text in a buffer and
532      process it in one step.  */
533   static char *inbuf = NULL;
534   static size_t maxlen = 0;
535   char *inptr = NULL;
536   size_t actlen = 0;
537
538   while (actlen < maxlen)
539     {
540       ssize_t n = read (fd, inptr, maxlen - actlen);
541
542       if (n == 0)
543         /* No more text to read.  */
544         break;
545
546       if (n == -1)
547         {
548           /* Error while reading.  */
549           error (0, errno, _("error while reading the input"));
550           return -1;
551         }
552
553       inptr += n;
554       actlen += n;
555     }
556
557   if (actlen == maxlen)
558     while (1)
559       {
560         ssize_t n;
561         char *new_inbuf;
562
563         /* Increase the buffer.  */
564         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
565         if (new_inbuf == NULL)
566           {
567             error (0, errno, _("unable to allocate buffer for input"));
568             return -1;
569           }
570         inbuf = new_inbuf;
571         maxlen += 32768;
572         inptr = inbuf + actlen;
573
574         do
575           {
576             n = read (fd, inptr, maxlen - actlen);
577
578             if (n == 0)
579               /* No more text to read.  */
580               break;
581
582             if (n == -1)
583               {
584                 /* Error while reading.  */
585                 error (0, errno, _("error while reading the input"));
586                 return -1;
587               }
588
589             inptr += n;
590             actlen += n;
591           }
592         while (actlen < maxlen);
593
594         if (n == 0)
595           /* Break again so we leave both loops.  */
596           break;
597       }
598
599   /* Now we have all the input in the buffer.  Process it in one run.  */
600   return process_block (cd, inbuf, actlen, output);
601 }
602
603
604 static int
605 process_file (iconv_t cd, FILE *input, FILE *output)
606 {
607   /* This should be safe since we use this function only for `stdin' and
608      we haven't read anything so far.  */
609   return process_fd (cd, fileno (input), output);
610 }
611
612
613 /* Print all known character sets/encodings.  */
614 static void *printlist;
615 static size_t column;
616 static int not_first;
617
618 static void
619 insert_print_list (const void *nodep, VISIT value, int level)
620 {
621   if (value == leaf || value == postorder)
622     {
623       const struct gconv_alias *s = *(const struct gconv_alias **) nodep;
624       tsearch (s->fromname, &printlist, (__compar_fn_t) strverscmp);
625     }
626 }
627
628 static void
629 do_print_human  (const void *nodep, VISIT value, int level)
630 {
631   if (value == leaf || value == postorder)
632     {
633       const char *s = *(const char **) nodep;
634       size_t len = strlen (s);
635       size_t cnt;
636
637       while (len > 0 && s[len - 1] == '/')
638         --len;
639
640       for (cnt = 0; cnt < len; ++cnt)
641         if (isalnum (s[cnt]))
642           break;
643       if (cnt == len)
644         return;
645
646       if (not_first)
647         {
648           putchar (',');
649           ++column;
650
651           if (column > 2 && column + len > 77)
652             {
653               fputs ("\n  ", stdout);
654               column = 2;
655             }
656           else
657             {
658               putchar (' ');
659               ++column;
660             }
661         }
662       else
663         not_first = 1;
664
665       fwrite (s, len, 1, stdout);
666       column += len;
667     }
668 }
669
670 static void
671 do_print  (const void *nodep, VISIT value, int level)
672 {
673   if (value == leaf || value == postorder)
674     {
675       const char *s = *(const char **) nodep;
676
677       puts (s);
678     }
679 }
680
681 static void
682 internal_function
683 add_known_names (struct gconv_module *node)
684 {
685   if (node->left != NULL)
686     add_known_names (node->left);
687   if (node->right != NULL)
688     add_known_names (node->right);
689   do
690     {
691       if (strcmp (node->from_string, "INTERNAL"))
692         tsearch (node->from_string, &printlist,
693                  (__compar_fn_t) strverscmp);
694       if (strcmp (node->to_string, "INTERNAL") != 0)
695         tsearch (node->to_string, &printlist, (__compar_fn_t) strverscmp);
696
697       node = node->same;
698     }
699   while (node != NULL);
700 }
701
702
703 static void
704 insert_cache (void)
705 {
706   const struct gconvcache_header *header;
707   const char *strtab;
708   const struct hash_entry *hashtab;
709   size_t cnt;
710
711   header = (const struct gconvcache_header *) __gconv_get_cache ();
712   strtab = (char *) header + header->string_offset;
713   hashtab = (struct hash_entry *) ((char *) header + header->hash_offset);
714
715   for (cnt = 0; cnt < header->hash_size; ++cnt)
716     if (hashtab[cnt].string_offset != 0)
717       {
718         const char *str = strtab + hashtab[cnt].string_offset;
719
720         if (strcmp (str, "INTERNAL") != 0)
721           tsearch (str, &printlist, (__compar_fn_t) strverscmp);
722       }
723 }
724
725
726 static void
727 internal_function
728 print_known_names (void)
729 {
730   iconv_t h;
731   void *cache;
732
733   /* We must initialize the internal databases first.  */
734   h = iconv_open ("L1", "L1");
735   iconv_close (h);
736
737   /* See whether we have a cache.  */
738   cache = __gconv_get_cache ();
739   if (cache != NULL)
740     /* Yep, use only this information.  */
741     insert_cache ();
742   else
743     {
744       struct gconv_module *modules;
745
746       /* No, then use the information read from the gconv-modules file.
747          First add the aliases.  */
748       twalk (__gconv_get_alias_db (), insert_print_list);
749
750       /* Add the from- and to-names from the known modules.  */
751       modules = __gconv_get_modules_db ();
752       if (modules != NULL)
753         add_known_names (modules);
754     }
755
756   fputs (_("\
757 The following list contain all the coded character sets known.  This does\n\
758 not necessarily mean that all combinations of these names can be used for\n\
759 the FROM and TO command line parameters.  One coded character set can be\n\
760 listed with several different names (aliases).\n\n  "), stdout);
761
762   /* Now print the collected names.  */
763   column = 2;
764   if (isatty (fileno (stdout)))
765     {
766       twalk (printlist, do_print_human);
767
768       if (column != 0)
769         puts ("");
770     }
771   else
772     twalk (printlist, do_print);
773 }