* elf/elf.h (R_SPARC_GLOB_JMP): New macro.
[platform/upstream/glibc.git] / iconv / iconv_charmap.c
1 /* Convert using charmaps and possibly iconv().
2    Copyright (C) 2001, 2005, 2006, 2008 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published
8    by the Free Software Foundation; version 2 of the License, or
9    (at your option) any later version.
10
11    This program 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
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <error.h>
23 #include <fcntl.h>
24 #include <iconv.h>
25 #include <libintl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30 #include <sys/stat.h>
31
32 #include "iconv_prog.h"
33
34
35 /* Prototypes for a few program-wide used functions.  */
36 extern void *xmalloc (size_t __n);
37 extern void *xcalloc (size_t __n, size_t __s);
38
39
40 struct convtable
41 {
42   int term[256 / 8];
43   union
44   {
45     struct convtable *sub;
46     struct charseq *out;
47   } val[256];
48 };
49
50
51 static inline struct convtable *
52 allocate_table (void)
53 {
54   return (struct convtable *) xcalloc (1, sizeof (struct convtable));
55 }
56
57
58 static inline int
59 is_term (struct convtable *tbl, unsigned int idx)
60 {
61   return tbl->term[idx / 8] & (1 << (idx % 8));
62 }
63
64
65 static inline void
66 clear_term (struct convtable *tbl, unsigned int idx)
67 {
68   tbl->term[idx / 8] &= ~(1 << (idx % 8));
69 }
70
71
72 static inline void
73 set_term (struct convtable *tbl, unsigned int idx)
74 {
75   tbl->term[idx / 8] |= 1 << (idx % 8);
76 }
77
78
79 /* Generate the conversion table.  */
80 static struct convtable *use_from_charmap (struct charmap_t *from_charmap,
81                                            const char *to_code);
82 static struct convtable *use_to_charmap (const char *from_code,
83                                          struct charmap_t *to_charmap);
84 static struct convtable *use_both_charmaps (struct charmap_t *from_charmap,
85                                             struct charmap_t *to_charmap);
86
87 /* Prototypes for the functions doing the actual work.  */
88 static int process_block (struct convtable *tbl, char *addr, size_t len,
89                           FILE *output);
90 static int process_fd (struct convtable *tbl, int fd, FILE *output);
91 static int process_file (struct convtable *tbl, FILE *input, FILE *output);
92
93
94 int
95 charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
96                     const char *to_code, struct charmap_t *to_charmap,
97                     int argc, int remaining, char *argv[],
98                     const char *output_file)
99 {
100   struct convtable *cvtbl;
101   int status = EXIT_SUCCESS;
102
103   /* We have three different cases to handle:
104
105      - both, from_charmap and to_charmap, are available.  This means we
106        can assume that the symbolic names match and use them to create
107        the mapping.
108
109      - only from_charmap is available.  In this case we can only hope that
110        the symbolic names used are of the <Uxxxx> form in which case we
111        can use a UCS4->"to_code" iconv() conversion for the second step.
112
113      - only to_charmap is available.  This is similar, only that we would
114        use iconv() for the "to_code"->UCS4 conversion.
115
116        We first create a table which maps input bytes into output bytes.
117        Once this is done we can handle all three of the cases above
118        equally.  */
119   if (from_charmap != NULL)
120     {
121       if (to_charmap == NULL)
122         cvtbl = use_from_charmap (from_charmap, to_code);
123       else
124         cvtbl = use_both_charmaps (from_charmap, to_charmap);
125     }
126   else
127     {
128       assert (to_charmap != NULL);
129       cvtbl = use_to_charmap (from_code, to_charmap);
130     }
131
132   /* If we couldn't generate a table stop now.  */
133   if (cvtbl == NULL)
134     return EXIT_FAILURE;
135
136   /* Determine output file.  */
137   FILE *output;
138   if (output_file != NULL && strcmp (output_file, "-") != 0)
139     {
140       output = fopen (output_file, "w");
141       if (output == NULL)
142         error (EXIT_FAILURE, errno, _("cannot open output file"));
143     }
144   else
145     output = stdout;
146
147   /* We can now start the conversion.  */
148   if (remaining == argc)
149     {
150       if (process_file (cvtbl, stdin, output) != 0)
151         status = EXIT_FAILURE;
152     }
153   else
154     do
155       {
156         struct stat st;
157         char *addr;
158         int fd;
159
160         if (verbose)
161           printf ("%s:\n", argv[remaining]);
162         if (strcmp (argv[remaining], "-") == 0)
163           fd = 0;
164         else
165           {
166             fd = open (argv[remaining], O_RDONLY);
167
168             if (fd == -1)
169               {
170                 error (0, errno, _("cannot open input file `%s'"),
171                        argv[remaining]);
172                 status = EXIT_FAILURE;
173                 continue;
174               }
175           }
176
177 #ifdef _POSIX_MAPPED_FILES
178         /* We have possibilities for reading the input file.  First try
179            to mmap() it since this will provide the fastest solution.  */
180         if (fstat (fd, &st) == 0
181             && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
182                               fd, 0)) != MAP_FAILED))
183           {
184             /* Yes, we can use mmap().  The descriptor is not needed
185                anymore.  */
186             if (close (fd) != 0)
187               error (EXIT_FAILURE, errno,
188                      _("error while closing input `%s'"), argv[remaining]);
189
190             if (process_block (cvtbl, addr, st.st_size, output) < 0)
191               {
192                 /* Something went wrong.  */
193                 status = EXIT_FAILURE;
194
195                 /* We don't need the input data anymore.  */
196                 munmap ((void *) addr, st.st_size);
197
198                 /* We cannot go on with producing output since it might
199                    lead to problem because the last output might leave
200                    the output stream in an undefined state.  */
201                 break;
202               }
203
204             /* We don't need the input data anymore.  */
205             munmap ((void *) addr, st.st_size);
206           }
207         else
208 #endif  /* _POSIX_MAPPED_FILES */
209           {
210             /* Read the file in pieces.  */
211             if (process_fd (cvtbl, fd, output) != 0)
212               {
213                 /* Something went wrong.  */
214                 status = EXIT_FAILURE;
215
216                 /* We don't need the input file anymore.  */
217                 close (fd);
218
219                 /* We cannot go on with producing output since it might
220                    lead to problem because the last output might leave
221                    the output stream in an undefined state.  */
222                 break;
223               }
224
225             /* Now close the file.  */
226             close (fd);
227           }
228       }
229     while (++remaining < argc);
230
231   /* All done.  */
232   return status;
233 }
234
235
236 static void
237 add_bytes (struct convtable *tbl, struct charseq *in, struct charseq *out)
238 {
239   int n = 0;
240   unsigned int byte;
241
242   assert (in->nbytes > 0);
243
244   byte = ((unsigned char *) in->bytes)[n];
245   while (n + 1 < in->nbytes)
246     {
247       if (is_term (tbl, byte) || tbl->val[byte].sub == NULL)
248         {
249           /* Note that we simply ignore a definition for a byte sequence
250              which is also the prefix for a longer one.  */
251           clear_term (tbl, byte);
252           tbl->val[byte].sub =
253             (struct convtable *) xcalloc (1, sizeof (struct convtable));
254         }
255
256       tbl = tbl->val[byte].sub;
257
258       byte = ((unsigned char *) in->bytes)[++n];
259     }
260
261   /* Only add the new sequence if there is none yet and the byte sequence
262      is not part of an even longer one.  */
263   if (! is_term (tbl, byte) && tbl->val[byte].sub == NULL)
264     {
265       set_term (tbl, byte);
266       tbl->val[byte].out = out;
267     }
268 }
269
270
271 static struct convtable *
272 use_from_charmap (struct charmap_t *from_charmap, const char *to_code)
273 {
274   /* We iterate over all entries in the from_charmap and for those which
275      have a known UCS4 representation we use an iconv() call to determine
276      the mapping to the to_code charset.  */
277   struct convtable *rettbl;
278   iconv_t cd;
279   void *ptr = NULL;
280   const void *key;
281   size_t keylen;
282   void *data;
283
284   cd = iconv_open (to_code, "WCHAR_T");
285   if (cd == (iconv_t) -1)
286     /* We cannot do anything.  */
287     return NULL;
288
289   rettbl = allocate_table ();
290
291   while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
292          >= 0)
293     {
294       struct charseq *in = (struct charseq *) data;
295
296       if (in->ucs4 != UNINITIALIZED_CHAR_VALUE)
297         {
298           /* There is a chance.  Try the iconv module.  */
299           wchar_t inbuf[1] = { in->ucs4 };
300           unsigned char outbuf[64];
301           char *inptr = (char *) inbuf;
302           size_t inlen = sizeof (inbuf);
303           char *outptr = (char *) outbuf;
304           size_t outlen = sizeof (outbuf);
305
306           (void) iconv (cd, &inptr, &inlen, &outptr, &outlen);
307
308           if (outptr != (char *) outbuf)
309             {
310               /* We got some output.  Good, use it.  */
311               struct charseq *newp;
312
313               outlen = sizeof (outbuf) - outlen;
314               assert ((char *) outbuf + outlen == outptr);
315
316               newp = (struct charseq *) xmalloc (sizeof (struct charseq)
317                                                  + outlen);
318               newp->name = in->name;
319               newp->ucs4 = in->ucs4;
320               newp->nbytes = outlen;
321               memcpy (newp->bytes, outbuf, outlen);
322
323               add_bytes (rettbl, in, newp);
324             }
325
326           /* Clear any possible state left behind.  */
327           (void) iconv (cd, NULL, NULL, NULL, NULL);
328         }
329     }
330
331   iconv_close (cd);
332
333   return rettbl;
334 }
335
336
337 static struct convtable *
338 use_to_charmap (const char *from_code, struct charmap_t *to_charmap)
339 {
340   /* We iterate over all entries in the to_charmap and for those which
341      have a known UCS4 representation we use an iconv() call to determine
342      the mapping to the from_code charset.  */
343   struct convtable *rettbl;
344   iconv_t cd;
345   void *ptr = NULL;
346   const void *key;
347   size_t keylen;
348   void *data;
349
350   /* Note that the conversion we use here is the reverse direction.  Without
351      exhaustive search we cannot figure out which input yields the UCS4
352      character we are looking for.  Therefore we determine it the other
353      way round.  */
354   cd = iconv_open (from_code, "WCHAR_T");
355   if (cd == (iconv_t) -1)
356     /* We cannot do anything.  */
357     return NULL;
358
359   rettbl = allocate_table ();
360
361   while (iterate_table (&to_charmap->char_table, &ptr, &key, &keylen, &data)
362          >= 0)
363     {
364       struct charseq *out = (struct charseq *) data;
365
366       if (out->ucs4 != UNINITIALIZED_CHAR_VALUE)
367         {
368           /* There is a chance.  Try the iconv module.  */
369           wchar_t inbuf[1] = { out->ucs4 };
370           unsigned char outbuf[64];
371           char *inptr = (char *) inbuf;
372           size_t inlen = sizeof (inbuf);
373           char *outptr = (char *) outbuf;
374           size_t outlen = sizeof (outbuf);
375
376           (void) iconv (cd, &inptr, &inlen, &outptr, &outlen);
377
378           if (outptr != (char *) outbuf)
379             {
380               /* We got some output.  Good, use it.  */
381               union
382               {
383                 struct charseq seq;
384                 struct
385                 {
386                   const char *name;
387                   uint32_t ucs4;
388                   int nbytes;
389                   unsigned char bytes[outlen];
390                 } mem;
391               } new;
392
393               outlen = sizeof (outbuf) - outlen;
394               assert ((char *) outbuf + outlen == outptr);
395
396               new.mem.name = out->name;
397               new.mem.ucs4 = out->ucs4;
398               new.mem.nbytes = outlen;
399               memcpy (new.mem.bytes, outbuf, outlen);
400
401               add_bytes (rettbl, &new.seq, out);
402             }
403
404           /* Clear any possible state left behind.  */
405           (void) iconv (cd, NULL, NULL, NULL, NULL);
406         }
407     }
408
409   iconv_close (cd);
410
411   return rettbl;
412 }
413
414
415 static struct convtable *
416 use_both_charmaps (struct charmap_t *from_charmap,
417                    struct charmap_t *to_charmap)
418 {
419   /* In this case we iterate over all the entries in the from_charmap,
420      determine the internal name, and find an appropriate entry in the
421      to_charmap (if it exists).  */
422   struct convtable *rettbl = allocate_table ();
423   void *ptr = NULL;
424   const void *key;
425   size_t keylen;
426   void *data;
427
428   while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
429          >= 0)
430     {
431       struct charseq *in = (struct charseq *) data;
432       struct charseq *out = charmap_find_value (to_charmap, key, keylen);
433
434       if (out != NULL)
435         add_bytes (rettbl, in, out);
436     }
437
438   return rettbl;
439 }
440
441
442 static int
443 process_block (struct convtable *tbl, char *addr, size_t len, FILE *output)
444 {
445   size_t n = 0;
446
447   while (n < len)
448     {
449       struct convtable *cur = tbl;
450       unsigned char *curp = (unsigned char *) addr;
451       unsigned int byte = *curp;
452       int cnt;
453       struct charseq *out;
454
455       while (! is_term (cur, byte))
456         if (cur->val[byte].sub == NULL)
457           {
458             /* This is a invalid sequence.  Skip the first byte if we are
459                ignoring errors.  Otherwise punt.  */
460             if (! omit_invalid)
461               {
462                 error (0, 0, _("illegal input sequence at position %Zd"), n);
463                 return -1;
464               }
465
466             n -= curp - (unsigned char *) addr;
467
468             byte = *(curp = (unsigned char *) ++addr);
469             if (++n >= len)
470               /* All converted.  */
471               return 0;
472
473             cur = tbl;
474           }
475         else
476           {
477             cur = cur->val[byte].sub;
478
479             if (++n >= len)
480               {
481                 error (0, 0, _("\
482 incomplete character or shift sequence at end of buffer"));
483                 return -1;
484               }
485
486             byte = *++curp;
487           }
488
489       /* We found a final byte.  Write the output bytes.  */
490       out = cur->val[byte].out;
491       for (cnt = 0; cnt < out->nbytes; ++cnt)
492         fputc_unlocked (out->bytes[cnt], output);
493
494       addr = (char *) curp + 1;
495       ++n;
496     }
497
498   return 0;
499 }
500
501
502 static int
503 process_fd (struct convtable *tbl, int fd, FILE *output)
504 {
505   /* We have a problem with reading from a descriptor since we must not
506      provide the iconv() function an incomplete character or shift
507      sequence at the end of the buffer.  Since we have to deal with
508      arbitrary encodings we must read the whole text in a buffer and
509      process it in one step.  */
510   static char *inbuf = NULL;
511   static size_t maxlen = 0;
512   char *inptr = inbuf;
513   size_t actlen = 0;
514
515   while (actlen < maxlen)
516     {
517       ssize_t n = read (fd, inptr, maxlen - actlen);
518
519       if (n == 0)
520         /* No more text to read.  */
521         break;
522
523       if (n == -1)
524         {
525           /* Error while reading.  */
526           error (0, errno, _("error while reading the input"));
527           return -1;
528         }
529
530       inptr += n;
531       actlen += n;
532     }
533
534   if (actlen == maxlen)
535     while (1)
536       {
537         ssize_t n;
538         char *new_inbuf;
539
540         /* Increase the buffer.  */
541         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
542         if (new_inbuf == NULL)
543           {
544             error (0, errno, _("unable to allocate buffer for input"));
545             return -1;
546           }
547         inbuf = new_inbuf;
548         maxlen += 32768;
549         inptr = inbuf + actlen;
550
551         do
552           {
553             n = read (fd, inptr, maxlen - actlen);
554
555             if (n == 0)
556               /* No more text to read.  */
557               break;
558
559             if (n == -1)
560               {
561                 /* Error while reading.  */
562                 error (0, errno, _("error while reading the input"));
563                 return -1;
564               }
565
566             inptr += n;
567             actlen += n;
568           }
569         while (actlen < maxlen);
570
571         if (n == 0)
572           /* Break again so we leave both loops.  */
573           break;
574       }
575
576   /* Now we have all the input in the buffer.  Process it in one run.  */
577   return process_block (tbl, inbuf, actlen, output);
578 }
579
580
581 static int
582 process_file (struct convtable *tbl, FILE *input, FILE *output)
583 {
584   /* This should be safe since we use this function only for `stdin' and
585      we haven't read anything so far.  */
586   return process_fd (tbl, fileno (input), output);
587 }