Blame iconv/iconv_charmap.c

Packit Service 82fcde
/* Convert using charmaps and possibly iconv().
Packit Service 82fcde
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
Packit Service 82fcde
Packit Service 82fcde
   This program is free software; you can redistribute it and/or modify
Packit Service 82fcde
   it under the terms of the GNU General Public License as published
Packit Service 82fcde
   by the Free Software Foundation; version 2 of the License, or
Packit Service 82fcde
   (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   This program is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 82fcde
   GNU General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU General Public License
Packit Service 82fcde
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <iconv.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <sys/mman.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
Packit Service 82fcde
#include "iconv_prog.h"
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Prototypes for a few program-wide used functions.  */
Packit Service 82fcde
#include <programs/xmalloc.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
struct convtable
Packit Service 82fcde
{
Packit Service 82fcde
  int term[256 / 8];
Packit Service 82fcde
  union
Packit Service 82fcde
  {
Packit Service 82fcde
    struct convtable *sub;
Packit Service 82fcde
    struct charseq *out;
Packit Service 82fcde
  } val[256];
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline struct convtable *
Packit Service 82fcde
allocate_table (void)
Packit Service 82fcde
{
Packit Service 82fcde
  return (struct convtable *) xcalloc (1, sizeof (struct convtable));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline int
Packit Service 82fcde
is_term (struct convtable *tbl, unsigned int idx)
Packit Service 82fcde
{
Packit Service 82fcde
  return tbl->term[idx / 8] & (1 << (idx % 8));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline void
Packit Service 82fcde
clear_term (struct convtable *tbl, unsigned int idx)
Packit Service 82fcde
{
Packit Service 82fcde
  tbl->term[idx / 8] &= ~(1 << (idx % 8));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline void
Packit Service 82fcde
set_term (struct convtable *tbl, unsigned int idx)
Packit Service 82fcde
{
Packit Service 82fcde
  tbl->term[idx / 8] |= 1 << (idx % 8);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Generate the conversion table.  */
Packit Service 82fcde
static struct convtable *use_from_charmap (struct charmap_t *from_charmap,
Packit Service 82fcde
					   const char *to_code);
Packit Service 82fcde
static struct convtable *use_to_charmap (const char *from_code,
Packit Service 82fcde
					 struct charmap_t *to_charmap);
Packit Service 82fcde
static struct convtable *use_both_charmaps (struct charmap_t *from_charmap,
Packit Service 82fcde
					    struct charmap_t *to_charmap);
Packit Service 82fcde
Packit Service 82fcde
/* Prototypes for the functions doing the actual work.  */
Packit Service 82fcde
static int process_block (struct convtable *tbl, char *addr, size_t len,
Packit Service 82fcde
			  FILE *output);
Packit Service 82fcde
static int process_fd (struct convtable *tbl, int fd, FILE *output);
Packit Service 82fcde
static int process_file (struct convtable *tbl, FILE *input, FILE *output);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
Packit Service 82fcde
		    const char *to_code, struct charmap_t *to_charmap,
Packit Service 82fcde
		    int argc, int remaining, char *argv[],
Packit Service 82fcde
		    const char *output_file)
Packit Service 82fcde
{
Packit Service 82fcde
  struct convtable *cvtbl;
Packit Service 82fcde
  int status = EXIT_SUCCESS;
Packit Service 82fcde
Packit Service 82fcde
  /* We have three different cases to handle:
Packit Service 82fcde
Packit Service 82fcde
     - both, from_charmap and to_charmap, are available.  This means we
Packit Service 82fcde
       can assume that the symbolic names match and use them to create
Packit Service 82fcde
       the mapping.
Packit Service 82fcde
Packit Service 82fcde
     - only from_charmap is available.  In this case we can only hope that
Packit Service 82fcde
       the symbolic names used are of the <Uxxxx> form in which case we
Packit Service 82fcde
       can use a UCS4->"to_code" iconv() conversion for the second step.
Packit Service 82fcde
Packit Service 82fcde
     - only to_charmap is available.  This is similar, only that we would
Packit Service 82fcde
       use iconv() for the "to_code"->UCS4 conversion.
Packit Service 82fcde
Packit Service 82fcde
       We first create a table which maps input bytes into output bytes.
Packit Service 82fcde
       Once this is done we can handle all three of the cases above
Packit Service 82fcde
       equally.  */
Packit Service 82fcde
  if (from_charmap != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (to_charmap == NULL)
Packit Service 82fcde
	cvtbl = use_from_charmap (from_charmap, to_code);
Packit Service 82fcde
      else
Packit Service 82fcde
	cvtbl = use_both_charmaps (from_charmap, to_charmap);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      assert (to_charmap != NULL);
Packit Service 82fcde
      cvtbl = use_to_charmap (from_code, to_charmap);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* If we couldn't generate a table stop now.  */
Packit Service 82fcde
  if (cvtbl == NULL)
Packit Service 82fcde
    return EXIT_FAILURE;
Packit Service 82fcde
Packit Service 82fcde
  /* Determine output file.  */
Packit Service 82fcde
  FILE *output;
Packit Service 82fcde
  if (output_file != NULL && strcmp (output_file, "-") != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      output = fopen (output_file, "w");
Packit Service 82fcde
      if (output == NULL)
Packit Service 82fcde
	error (EXIT_FAILURE, errno, _("cannot open output file"));
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    output = stdout;
Packit Service 82fcde
Packit Service 82fcde
  /* We can now start the conversion.  */
Packit Service 82fcde
  if (remaining == argc)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (process_file (cvtbl, stdin, output) != 0)
Packit Service 82fcde
	status = EXIT_FAILURE;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    do
Packit Service 82fcde
      {
Packit Service 82fcde
	int fd;
Packit Service 82fcde
Packit Service 82fcde
	if (verbose)
Packit Service 82fcde
	  printf ("%s:\n", argv[remaining]);
Packit Service 82fcde
	if (strcmp (argv[remaining], "-") == 0)
Packit Service 82fcde
	  fd = 0;
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    fd = open (argv[remaining], O_RDONLY);
Packit Service 82fcde
Packit Service 82fcde
	    if (fd == -1)
Packit Service 82fcde
	      {
Packit Service 82fcde
		error (0, errno, _("cannot open input file `%s'"),
Packit Service 82fcde
		       argv[remaining]);
Packit Service 82fcde
		status = EXIT_FAILURE;
Packit Service 82fcde
		continue;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
#ifdef _POSIX_MAPPED_FILES
Packit Service 82fcde
	struct stat64 st;
Packit Service 82fcde
	char *addr;
Packit Service 82fcde
	/* We have possibilities for reading the input file.  First try
Packit Service 82fcde
	   to mmap() it since this will provide the fastest solution.  */
Packit Service 82fcde
	if (fstat64 (fd, &st) == 0
Packit Service 82fcde
	    && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
Packit Service 82fcde
			      fd, 0)) != MAP_FAILED))
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* Yes, we can use mmap().  The descriptor is not needed
Packit Service 82fcde
	       anymore.  */
Packit Service 82fcde
	    if (close (fd) != 0)
Packit Service 82fcde
	      error (EXIT_FAILURE, errno,
Packit Service 82fcde
		     _("error while closing input `%s'"), argv[remaining]);
Packit Service 82fcde
Packit Service 82fcde
	    if (process_block (cvtbl, addr, st.st_size, output) < 0)
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Something went wrong.  */
Packit Service 82fcde
		status = EXIT_FAILURE;
Packit Service 82fcde
Packit Service 82fcde
		/* We don't need the input data anymore.  */
Packit Service 82fcde
		munmap ((void *) addr, st.st_size);
Packit Service 82fcde
Packit Service 82fcde
		/* We cannot go on with producing output since it might
Packit Service 82fcde
		   lead to problem because the last output might leave
Packit Service 82fcde
		   the output stream in an undefined state.  */
Packit Service 82fcde
		break;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    /* We don't need the input data anymore.  */
Packit Service 82fcde
	    munmap ((void *) addr, st.st_size);
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
#endif	/* _POSIX_MAPPED_FILES */
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* Read the file in pieces.  */
Packit Service 82fcde
	    if (process_fd (cvtbl, fd, output) != 0)
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Something went wrong.  */
Packit Service 82fcde
		status = EXIT_FAILURE;
Packit Service 82fcde
Packit Service 82fcde
		/* We don't need the input file anymore.  */
Packit Service 82fcde
		close (fd);
Packit Service 82fcde
Packit Service 82fcde
		/* We cannot go on with producing output since it might
Packit Service 82fcde
		   lead to problem because the last output might leave
Packit Service 82fcde
		   the output stream in an undefined state.  */
Packit Service 82fcde
		break;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    /* Now close the file.  */
Packit Service 82fcde
	    close (fd);
Packit Service 82fcde
	  }
Packit Service 82fcde
      }
Packit Service 82fcde
    while (++remaining < argc);
Packit Service 82fcde
Packit Service 82fcde
  /* All done.  */
Packit Service 82fcde
  return status;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Add the IN->OUT mapping to TBL.  OUT is potentially stored in the table.
Packit Service 82fcde
   IN is used only here, so it need not be kept live afterwards.  */
Packit Service 82fcde
static void
Packit Service 82fcde
add_bytes (struct convtable *tbl, const struct charseq *in, struct charseq *out)
Packit Service 82fcde
{
Packit Service 82fcde
  int n = 0;
Packit Service 82fcde
  unsigned int byte;
Packit Service 82fcde
Packit Service 82fcde
  assert (in->nbytes > 0);
Packit Service 82fcde
Packit Service 82fcde
  byte = ((unsigned char *) in->bytes)[n];
Packit Service 82fcde
  while (n + 1 < in->nbytes)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (is_term (tbl, byte) || tbl->val[byte].sub == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Note that we simply ignore a definition for a byte sequence
Packit Service 82fcde
	     which is also the prefix for a longer one.  */
Packit Service 82fcde
	  clear_term (tbl, byte);
Packit Service 82fcde
	  tbl->val[byte].sub =
Packit Service 82fcde
	    (struct convtable *) xcalloc (1, sizeof (struct convtable));
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      tbl = tbl->val[byte].sub;
Packit Service 82fcde
Packit Service 82fcde
      byte = ((unsigned char *) in->bytes)[++n];
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Only add the new sequence if there is none yet and the byte sequence
Packit Service 82fcde
     is not part of an even longer one.  */
Packit Service 82fcde
  if (! is_term (tbl, byte) && tbl->val[byte].sub == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      set_term (tbl, byte);
Packit Service 82fcde
      tbl->val[byte].out = out;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Try to convert SEQ from WCHAR_T format using CD.
Packit Service 82fcde
   Returns a malloc'd struct or NULL.  */
Packit Service 82fcde
static struct charseq *
Packit Service 82fcde
convert_charseq (iconv_t cd, const struct charseq *seq)
Packit Service 82fcde
{
Packit Service 82fcde
  struct charseq *result = NULL;
Packit Service 82fcde
Packit Service 82fcde
  if (seq->ucs4 != UNINITIALIZED_CHAR_VALUE)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* There is a chance.  Try the iconv module.  */
Packit Service 82fcde
      wchar_t inbuf[1] = { seq->ucs4 };
Packit Service 82fcde
      unsigned char outbuf[64];
Packit Service 82fcde
      char *inptr = (char *) inbuf;
Packit Service 82fcde
      size_t inlen = sizeof (inbuf);
Packit Service 82fcde
      char *outptr = (char *) outbuf;
Packit Service 82fcde
      size_t outlen = sizeof (outbuf);
Packit Service 82fcde
Packit Service 82fcde
      (void) iconv (cd, &inptr, &inlen, &outptr, &outlen);
Packit Service 82fcde
Packit Service 82fcde
      if (outptr != (char *) outbuf)
Packit Service 82fcde
        {
Packit Service 82fcde
          /* We got some output.  Good, use it.  */
Packit Service 82fcde
          outlen = sizeof (outbuf) - outlen;
Packit Service 82fcde
          assert ((char *) outbuf + outlen == outptr);
Packit Service 82fcde
Packit Service 82fcde
          result = xmalloc (sizeof (struct charseq) + outlen);
Packit Service 82fcde
          result->name = seq->name;
Packit Service 82fcde
          result->ucs4 = seq->ucs4;
Packit Service 82fcde
          result->nbytes = outlen;
Packit Service 82fcde
          memcpy (result->bytes, outbuf, outlen);
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      /* Clear any possible state left behind.  */
Packit Service 82fcde
      (void) iconv (cd, NULL, NULL, NULL, NULL);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static struct convtable *
Packit Service 82fcde
use_from_charmap (struct charmap_t *from_charmap, const char *to_code)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We iterate over all entries in the from_charmap and for those which
Packit Service 82fcde
     have a known UCS4 representation we use an iconv() call to determine
Packit Service 82fcde
     the mapping to the to_code charset.  */
Packit Service 82fcde
  struct convtable *rettbl;
Packit Service 82fcde
  iconv_t cd;
Packit Service 82fcde
  void *ptr = NULL;
Packit Service 82fcde
  const void *key;
Packit Service 82fcde
  size_t keylen;
Packit Service 82fcde
  void *data;
Packit Service 82fcde
Packit Service 82fcde
  cd = iconv_open (to_code, "WCHAR_T");
Packit Service 82fcde
  if (cd == (iconv_t) -1)
Packit Service 82fcde
    /* We cannot do anything.  */
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  rettbl = allocate_table ();
Packit Service 82fcde
Packit Service 82fcde
  while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
Packit Service 82fcde
	 >= 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct charseq *in = data;
Packit Service 82fcde
      struct charseq *newp = convert_charseq (cd, in);
Packit Service 82fcde
      if (newp != NULL)
Packit Service 82fcde
        add_bytes (rettbl, in, newp);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  iconv_close (cd);
Packit Service 82fcde
Packit Service 82fcde
  return rettbl;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static struct convtable *
Packit Service 82fcde
use_to_charmap (const char *from_code, struct charmap_t *to_charmap)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We iterate over all entries in the to_charmap and for those which
Packit Service 82fcde
     have a known UCS4 representation we use an iconv() call to determine
Packit Service 82fcde
     the mapping to the from_code charset.  */
Packit Service 82fcde
  struct convtable *rettbl;
Packit Service 82fcde
  iconv_t cd;
Packit Service 82fcde
  void *ptr = NULL;
Packit Service 82fcde
  const void *key;
Packit Service 82fcde
  size_t keylen;
Packit Service 82fcde
  void *data;
Packit Service 82fcde
Packit Service 82fcde
  /* Note that the conversion we use here is the reverse direction.  Without
Packit Service 82fcde
     exhaustive search we cannot figure out which input yields the UCS4
Packit Service 82fcde
     character we are looking for.  Therefore we determine it the other
Packit Service 82fcde
     way round.  */
Packit Service 82fcde
  cd = iconv_open (from_code, "WCHAR_T");
Packit Service 82fcde
  if (cd == (iconv_t) -1)
Packit Service 82fcde
    /* We cannot do anything.  */
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  rettbl = allocate_table ();
Packit Service 82fcde
Packit Service 82fcde
  while (iterate_table (&to_charmap->char_table, &ptr, &key, &keylen, &data)
Packit Service 82fcde
	 >= 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct charseq *out = data;
Packit Service 82fcde
      struct charseq *newp = convert_charseq (cd, out);
Packit Service 82fcde
      if (newp != NULL)
Packit Service 82fcde
        {
Packit Service 82fcde
          add_bytes (rettbl, newp, out);
Packit Service 82fcde
          free (newp);
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  iconv_close (cd);
Packit Service 82fcde
Packit Service 82fcde
  return rettbl;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static struct convtable *
Packit Service 82fcde
use_both_charmaps (struct charmap_t *from_charmap,
Packit Service 82fcde
		   struct charmap_t *to_charmap)
Packit Service 82fcde
{
Packit Service 82fcde
  /* In this case we iterate over all the entries in the from_charmap,
Packit Service 82fcde
     determine the internal name, and find an appropriate entry in the
Packit Service 82fcde
     to_charmap (if it exists).  */
Packit Service 82fcde
  struct convtable *rettbl = allocate_table ();
Packit Service 82fcde
  void *ptr = NULL;
Packit Service 82fcde
  const void *key;
Packit Service 82fcde
  size_t keylen;
Packit Service 82fcde
  void *data;
Packit Service 82fcde
Packit Service 82fcde
  while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
Packit Service 82fcde
	 >= 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct charseq *in = (struct charseq *) data;
Packit Service 82fcde
      struct charseq *out = charmap_find_value (to_charmap, key, keylen);
Packit Service 82fcde
Packit Service 82fcde
      if (out != NULL)
Packit Service 82fcde
	add_bytes (rettbl, in, out);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return rettbl;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
process_block (struct convtable *tbl, char *addr, size_t len, FILE *output)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t n = 0;
Packit Service 82fcde
Packit Service 82fcde
  while (n < len)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct convtable *cur = tbl;
Packit Service 82fcde
      unsigned char *curp = (unsigned char *) addr;
Packit Service 82fcde
      unsigned int byte = *curp;
Packit Service 82fcde
      int cnt;
Packit Service 82fcde
      struct charseq *out;
Packit Service 82fcde
Packit Service 82fcde
      while (! is_term (cur, byte))
Packit Service 82fcde
	if (cur->val[byte].sub == NULL)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* This is an invalid sequence.  Skip the first byte if we are
Packit Service 82fcde
	       ignoring errors.  Otherwise punt.  */
Packit Service 82fcde
	    if (! omit_invalid)
Packit Service 82fcde
	      {
Packit Service 82fcde
		error (0, 0, _("illegal input sequence at position %Zd"), n);
Packit Service 82fcde
		return -1;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    n -= curp - (unsigned char *) addr;
Packit Service 82fcde
Packit Service 82fcde
	    byte = *(curp = (unsigned char *) ++addr);
Packit Service 82fcde
	    if (++n >= len)
Packit Service 82fcde
	      /* All converted.  */
Packit Service 82fcde
	      return 0;
Packit Service 82fcde
Packit Service 82fcde
	    cur = tbl;
Packit Service 82fcde
	  }
Packit Service 82fcde
	else
Packit Service 82fcde
	  {
Packit Service 82fcde
	    cur = cur->val[byte].sub;
Packit Service 82fcde
Packit Service 82fcde
	    if (++n >= len)
Packit Service 82fcde
	      {
Packit Service 82fcde
		error (0, 0, _("\
Packit Service 82fcde
incomplete character or shift sequence at end of buffer"));
Packit Service 82fcde
		return -1;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    byte = *++curp;
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
      /* We found a final byte.  Write the output bytes.  */
Packit Service 82fcde
      out = cur->val[byte].out;
Packit Service 82fcde
      for (cnt = 0; cnt < out->nbytes; ++cnt)
Packit Service 82fcde
	fputc_unlocked (out->bytes[cnt], output);
Packit Service 82fcde
Packit Service 82fcde
      addr = (char *) curp + 1;
Packit Service 82fcde
      ++n;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
process_fd (struct convtable *tbl, int fd, FILE *output)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We have a problem with reading from a descriptor since we must not
Packit Service 82fcde
     provide the iconv() function an incomplete character or shift
Packit Service 82fcde
     sequence at the end of the buffer.  Since we have to deal with
Packit Service 82fcde
     arbitrary encodings we must read the whole text in a buffer and
Packit Service 82fcde
     process it in one step.  */
Packit Service 82fcde
  static char *inbuf = NULL;
Packit Service 82fcde
  static size_t maxlen = 0;
Packit Service 82fcde
  char *inptr = inbuf;
Packit Service 82fcde
  size_t actlen = 0;
Packit Service 82fcde
Packit Service 82fcde
  while (actlen < maxlen)
Packit Service 82fcde
    {
Packit Service 82fcde
      ssize_t n = read (fd, inptr, maxlen - actlen);
Packit Service 82fcde
Packit Service 82fcde
      if (n == 0)
Packit Service 82fcde
	/* No more text to read.  */
Packit Service 82fcde
	break;
Packit Service 82fcde
Packit Service 82fcde
      if (n == -1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Error while reading.  */
Packit Service 82fcde
	  error (0, errno, _("error while reading the input"));
Packit Service 82fcde
	  return -1;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      inptr += n;
Packit Service 82fcde
      actlen += n;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (actlen == maxlen)
Packit Service 82fcde
    while (1)
Packit Service 82fcde
      {
Packit Service 82fcde
	ssize_t n;
Packit Service 82fcde
	char *new_inbuf;
Packit Service 82fcde
Packit Service 82fcde
	/* Increase the buffer.  */
Packit Service 82fcde
	new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
Packit Service 82fcde
	if (new_inbuf == NULL)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    error (0, errno, _("unable to allocate buffer for input"));
Packit Service 82fcde
	    return -1;
Packit Service 82fcde
	  }
Packit Service 82fcde
	inbuf = new_inbuf;
Packit Service 82fcde
	maxlen += 32768;
Packit Service 82fcde
	inptr = inbuf + actlen;
Packit Service 82fcde
Packit Service 82fcde
	do
Packit Service 82fcde
	  {
Packit Service 82fcde
	    n = read (fd, inptr, maxlen - actlen);
Packit Service 82fcde
Packit Service 82fcde
	    if (n == 0)
Packit Service 82fcde
	      /* No more text to read.  */
Packit Service 82fcde
	      break;
Packit Service 82fcde
Packit Service 82fcde
	    if (n == -1)
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Error while reading.  */
Packit Service 82fcde
		error (0, errno, _("error while reading the input"));
Packit Service 82fcde
		return -1;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    inptr += n;
Packit Service 82fcde
	    actlen += n;
Packit Service 82fcde
	  }
Packit Service 82fcde
	while (actlen < maxlen);
Packit Service 82fcde
Packit Service 82fcde
	if (n == 0)
Packit Service 82fcde
	  /* Break again so we leave both loops.  */
Packit Service 82fcde
	  break;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  /* Now we have all the input in the buffer.  Process it in one run.  */
Packit Service 82fcde
  return process_block (tbl, inbuf, actlen, output);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
process_file (struct convtable *tbl, FILE *input, FILE *output)
Packit Service 82fcde
{
Packit Service 82fcde
  /* This should be safe since we use this function only for `stdin' and
Packit Service 82fcde
     we haven't read anything so far.  */
Packit Service 82fcde
  return process_fd (tbl, fileno (input), output);
Packit Service 82fcde
}