Blame iconv/iconv_charmap.c

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