Blame readline/mbutil.c

Packit Service 706eca
/* mbutil.c -- readline multibyte character utility functions */
Packit Service 706eca
Packit Service 706eca
/* Copyright (C) 2001-2009 Free Software Foundation, Inc.
Packit Service 706eca
Packit Service 706eca
   This file is part of the GNU Readline Library (Readline), a library
Packit Service 706eca
   for reading lines of text with interactive input and history editing.      
Packit Service 706eca
Packit Service 706eca
   Readline is free software: you can redistribute it and/or modify
Packit Service 706eca
   it under the terms of the GNU General Public License as published by
Packit Service 706eca
   the Free Software Foundation, either version 3 of the License, or
Packit Service 706eca
   (at your option) any later version.
Packit Service 706eca
Packit Service 706eca
   Readline is distributed in the hope that it will be useful,
Packit Service 706eca
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 706eca
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 706eca
   GNU General Public License for more details.
Packit Service 706eca
Packit Service 706eca
   You should have received a copy of the GNU General Public License
Packit Service 706eca
   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 706eca
*/
Packit Service 706eca
Packit Service 706eca
#define READLINE_LIBRARY
Packit Service 706eca
Packit Service 706eca
#if defined (HAVE_CONFIG_H)
Packit Service 706eca
#  include <config.h>
Packit Service 706eca
#endif
Packit Service 706eca
Packit Service 706eca
#include <sys/types.h>
Packit Service 706eca
#include <fcntl.h>
Packit Service 706eca
#include "posixjmp.h"
Packit Service 706eca
Packit Service 706eca
#if defined (HAVE_UNISTD_H)
Packit Service 706eca
#  include <unistd.h>	   /* for _POSIX_VERSION */
Packit Service 706eca
#endif /* HAVE_UNISTD_H */
Packit Service 706eca
Packit Service 706eca
#if defined (HAVE_STDLIB_H)
Packit Service 706eca
#  include <stdlib.h>
Packit Service 706eca
#else
Packit Service 706eca
#  include "ansi_stdlib.h"
Packit Service 706eca
#endif /* HAVE_STDLIB_H */
Packit Service 706eca
Packit Service 706eca
#include <stdio.h>
Packit Service 706eca
#include <ctype.h>
Packit Service 706eca
Packit Service 706eca
/* System-specific feature definitions and include files. */
Packit Service 706eca
#include "rldefs.h"
Packit Service 706eca
#include "rlmbutil.h"
Packit Service 706eca
Packit Service 706eca
#if defined (TIOCSTAT_IN_SYS_IOCTL)
Packit Service 706eca
#  include <sys/ioctl.h>
Packit Service 706eca
#endif /* TIOCSTAT_IN_SYS_IOCTL */
Packit Service 706eca
Packit Service 706eca
/* Some standard library routines. */
Packit Service 706eca
#include "readline.h"
Packit Service 706eca
Packit Service 706eca
#include "rlprivate.h"
Packit Service 706eca
#include "xmalloc.h"
Packit Service 706eca
Packit Service 706eca
/* Declared here so it can be shared between the readline and history
Packit Service 706eca
   libraries. */
Packit Service 706eca
#if defined (HANDLE_MULTIBYTE)
Packit Service 706eca
int rl_byte_oriented = 0;
Packit Service 706eca
#else
Packit Service 706eca
int rl_byte_oriented = 1;
Packit Service 706eca
#endif
Packit Service 706eca
Packit Service 706eca
/* **************************************************************** */
Packit Service 706eca
/*								    */
Packit Service 706eca
/*		Multibyte Character Utility Functions		    */
Packit Service 706eca
/*								    */
Packit Service 706eca
/* **************************************************************** */
Packit Service 706eca
Packit Service 706eca
#if defined(HANDLE_MULTIBYTE)
Packit Service 706eca
Packit Service 706eca
static int
Packit Service 706eca
_rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int seed, count, find_non_zero;
Packit Service 706eca
{
Packit Service 706eca
  size_t tmp, len;
Packit Service 706eca
  mbstate_t ps;
Packit Service 706eca
  int point;
Packit Service 706eca
  wchar_t wc;
Packit Service 706eca
Packit Service 706eca
  tmp = 0;
Packit Service 706eca
Packit Service 706eca
  memset(&ps, 0, sizeof (mbstate_t));
Packit Service 706eca
  if (seed < 0)
Packit Service 706eca
    seed = 0;
Packit Service 706eca
  if (count <= 0)
Packit Service 706eca
    return seed;
Packit Service 706eca
Packit Service 706eca
  point = seed + _rl_adjust_point (string, seed, &ps);
Packit Service 706eca
  /* if this is true, means that seed was not pointing to a byte indicating
Packit Service 706eca
     the beginning of a multibyte character.  Correct the point and consume
Packit Service 706eca
     one char. */
Packit Service 706eca
  if (seed < point)
Packit Service 706eca
    count--;
Packit Service 706eca
Packit Service 706eca
  while (count > 0)  
Packit Service 706eca
    {
Packit Service 706eca
      len = strlen (string + point);
Packit Service 706eca
      if (len == 0)
Packit Service 706eca
	break;
Packit Service 706eca
      tmp = mbrtowc (&wc, string+point, len, &ps);
Packit Service 706eca
      if (MB_INVALIDCH ((size_t)tmp))
Packit Service 706eca
	{
Packit Service 706eca
	  /* invalid bytes. assume a byte represents a character */
Packit Service 706eca
	  point++;
Packit Service 706eca
	  count--;
Packit Service 706eca
	  /* reset states. */
Packit Service 706eca
	  memset(&ps, 0, sizeof(mbstate_t));
Packit Service 706eca
	}
Packit Service 706eca
      else if (MB_NULLWCH (tmp))
Packit Service 706eca
	break;			/* found wide '\0' */
Packit Service 706eca
      else
Packit Service 706eca
	{
Packit Service 706eca
	  /* valid bytes */
Packit Service 706eca
	  point += tmp;
Packit Service 706eca
	  if (find_non_zero)
Packit Service 706eca
	    {
Packit Service 706eca
	      if (wcwidth (wc) == 0)
Packit Service 706eca
		continue;
Packit Service 706eca
	      else
Packit Service 706eca
		count--;
Packit Service 706eca
	    }
Packit Service 706eca
	  else
Packit Service 706eca
	    count--;
Packit Service 706eca
	}
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  if (find_non_zero)
Packit Service 706eca
    {
Packit Service 706eca
      tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
Packit Service 706eca
      while (MB_NULLWCH (tmp) == 0 && MB_INVALIDCH (tmp) == 0 && wcwidth (wc) == 0)
Packit Service 706eca
	{
Packit Service 706eca
	  point += tmp;
Packit Service 706eca
	  tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
Packit Service 706eca
	}
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return point;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static int
Packit Service 706eca
_rl_find_prev_mbchar_internal (string, seed, find_non_zero)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int seed, find_non_zero;
Packit Service 706eca
{
Packit Service 706eca
  mbstate_t ps;
Packit Service 706eca
  int prev, non_zero_prev, point, length;
Packit Service 706eca
  size_t tmp;
Packit Service 706eca
  wchar_t wc;
Packit Service 706eca
Packit Service 706eca
  memset(&ps, 0, sizeof(mbstate_t));
Packit Service 706eca
  length = strlen(string);
Packit Service 706eca
  
Packit Service 706eca
  if (seed < 0)
Packit Service 706eca
    return 0;
Packit Service 706eca
  else if (length < seed)
Packit Service 706eca
    return length;
Packit Service 706eca
Packit Service 706eca
  prev = non_zero_prev = point = 0;
Packit Service 706eca
  while (point < seed)
Packit Service 706eca
    {
Packit Service 706eca
      tmp = mbrtowc (&wc, string + point, length - point, &ps);
Packit Service 706eca
      if (MB_INVALIDCH ((size_t)tmp))
Packit Service 706eca
	{
Packit Service 706eca
	  /* in this case, bytes are invalid or shorted to compose
Packit Service 706eca
	     multibyte char, so assume that the first byte represents
Packit Service 706eca
	     a single character anyway. */
Packit Service 706eca
	  tmp = 1;
Packit Service 706eca
	  /* clear the state of the byte sequence, because
Packit Service 706eca
	     in this case effect of mbstate is undefined  */
Packit Service 706eca
	  memset(&ps, 0, sizeof (mbstate_t));
Packit Service 706eca
Packit Service 706eca
	  /* Since we're assuming that this byte represents a single
Packit Service 706eca
	     non-zero-width character, don't forget about it. */
Packit Service 706eca
	  prev = point;
Packit Service 706eca
	}
Packit Service 706eca
      else if (MB_NULLWCH (tmp))
Packit Service 706eca
	break;			/* Found '\0' char.  Can this happen? */
Packit Service 706eca
      else
Packit Service 706eca
	{
Packit Service 706eca
	  if (find_non_zero)
Packit Service 706eca
	    {
Packit Service 706eca
	      if (wcwidth (wc) != 0)
Packit Service 706eca
		prev = point;
Packit Service 706eca
	    }
Packit Service 706eca
	  else
Packit Service 706eca
	    prev = point;  
Packit Service 706eca
	}
Packit Service 706eca
Packit Service 706eca
      point += tmp;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return prev;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
/* return the number of bytes parsed from the multibyte sequence starting
Packit Service 706eca
   at src, if a non-L'\0' wide character was recognized. It returns 0, 
Packit Service 706eca
   if a L'\0' wide character was recognized. It  returns (size_t)(-1), 
Packit Service 706eca
   if an invalid multibyte sequence was encountered. It returns (size_t)(-2) 
Packit Service 706eca
   if it couldn't parse a complete  multibyte character.  */
Packit Service 706eca
int
Packit Service 706eca
_rl_get_char_len (src, ps)
Packit Service 706eca
     char *src;
Packit Service 706eca
     mbstate_t *ps;
Packit Service 706eca
{
Packit Service 706eca
  size_t tmp;
Packit Service 706eca
Packit Service 706eca
  tmp = mbrlen((const char *)src, (size_t)strlen (src), ps);
Packit Service 706eca
  if (tmp == (size_t)(-2))
Packit Service 706eca
    {
Packit Service 706eca
      /* shorted to compose multibyte char */
Packit Service 706eca
      if (ps)
Packit Service 706eca
	memset (ps, 0, sizeof(mbstate_t));
Packit Service 706eca
      return -2;
Packit Service 706eca
    }
Packit Service 706eca
  else if (tmp == (size_t)(-1))
Packit Service 706eca
    {
Packit Service 706eca
      /* invalid to compose multibyte char */
Packit Service 706eca
      /* initialize the conversion state */
Packit Service 706eca
      if (ps)
Packit Service 706eca
	memset (ps, 0, sizeof(mbstate_t));
Packit Service 706eca
      return -1;
Packit Service 706eca
    }
Packit Service 706eca
  else if (tmp == (size_t)0)
Packit Service 706eca
    return 0;
Packit Service 706eca
  else
Packit Service 706eca
    return (int)tmp;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
/* compare the specified two characters. If the characters matched,
Packit Service 706eca
   return 1. Otherwise return 0. */
Packit Service 706eca
int
Packit Service 706eca
_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
Packit Service 706eca
     char *buf1;
Packit Service 706eca
     int pos1;
Packit Service 706eca
     mbstate_t *ps1;
Packit Service 706eca
     char *buf2;
Packit Service 706eca
     int pos2;
Packit Service 706eca
     mbstate_t *ps2;
Packit Service 706eca
{
Packit Service 706eca
  int i, w1, w2;
Packit Service 706eca
Packit Service 706eca
  if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 || 
Packit Service 706eca
	(w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 ||
Packit Service 706eca
	(w1 != w2) ||
Packit Service 706eca
	(buf1[pos1] != buf2[pos2]))
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  for (i = 1; i < w1; i++)
Packit Service 706eca
    if (buf1[pos1+i] != buf2[pos2+i])
Packit Service 706eca
      return 0;
Packit Service 706eca
Packit Service 706eca
  return 1;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
/* adjust pointed byte and find mbstate of the point of string.
Packit Service 706eca
   adjusted point will be point <= adjusted_point, and returns
Packit Service 706eca
   differences of the byte(adjusted_point - point).
Packit Service 706eca
   if point is invalied (point < 0 || more than string length),
Packit Service 706eca
   it returns -1 */
Packit Service 706eca
int
Packit Service 706eca
_rl_adjust_point(string, point, ps)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int point;
Packit Service 706eca
     mbstate_t *ps;
Packit Service 706eca
{
Packit Service 706eca
  size_t tmp = 0;
Packit Service 706eca
  int length;
Packit Service 706eca
  int pos = 0;
Packit Service 706eca
Packit Service 706eca
  length = strlen(string);
Packit Service 706eca
  if (point < 0)
Packit Service 706eca
    return -1;
Packit Service 706eca
  if (length < point)
Packit Service 706eca
    return -1;
Packit Service 706eca
  
Packit Service 706eca
  while (pos < point)
Packit Service 706eca
    {
Packit Service 706eca
      tmp = mbrlen (string + pos, length - pos, ps);
Packit Service 706eca
      if (MB_INVALIDCH ((size_t)tmp))
Packit Service 706eca
	{
Packit Service 706eca
	  /* in this case, bytes are invalid or shorted to compose
Packit Service 706eca
	     multibyte char, so assume that the first byte represents
Packit Service 706eca
	     a single character anyway. */
Packit Service 706eca
	  pos++;
Packit Service 706eca
	  /* clear the state of the byte sequence, because
Packit Service 706eca
	     in this case effect of mbstate is undefined  */
Packit Service 706eca
	  if (ps)
Packit Service 706eca
	    memset (ps, 0, sizeof (mbstate_t));
Packit Service 706eca
	}
Packit Service 706eca
      else if (MB_NULLWCH (tmp))
Packit Service 706eca
	pos++;
Packit Service 706eca
      else
Packit Service 706eca
	pos += tmp;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return (pos - point);
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
int
Packit Service 706eca
_rl_is_mbchar_matched (string, seed, end, mbchar, length)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int seed, end;
Packit Service 706eca
     char *mbchar;
Packit Service 706eca
     int length;
Packit Service 706eca
{
Packit Service 706eca
  int i;
Packit Service 706eca
Packit Service 706eca
  if ((end - seed) < length)
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  for (i = 0; i < length; i++)
Packit Service 706eca
    if (string[seed + i] != mbchar[i])
Packit Service 706eca
      return 0;
Packit Service 706eca
  return 1;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
wchar_t
Packit Service 706eca
_rl_char_value (buf, ind)
Packit Service 706eca
     char *buf;
Packit Service 706eca
     int ind;
Packit Service 706eca
{
Packit Service 706eca
  size_t tmp;
Packit Service 706eca
  wchar_t wc;
Packit Service 706eca
  mbstate_t ps;
Packit Service 706eca
  int l;
Packit Service 706eca
Packit Service 706eca
  if (MB_LEN_MAX == 1 || rl_byte_oriented)
Packit Service 706eca
    return ((wchar_t) buf[ind]);
Packit Service 706eca
  l = strlen (buf);
Packit Service 706eca
  if (ind >= l - 1)
Packit Service 706eca
    return ((wchar_t) buf[ind]);
Packit Service 706eca
  memset (&ps, 0, sizeof (mbstate_t));
Packit Service 706eca
  tmp = mbrtowc (&wc, buf + ind, l - ind, &ps);
Packit Service 706eca
  if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp))  
Packit Service 706eca
    return ((wchar_t) buf[ind]);
Packit Service 706eca
  return wc;
Packit Service 706eca
}
Packit Service 706eca
#endif /* HANDLE_MULTIBYTE */
Packit Service 706eca
Packit Service 706eca
/* Find next `count' characters started byte point of the specified seed.
Packit Service 706eca
   If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte
Packit Service 706eca
   characters. */
Packit Service 706eca
#undef _rl_find_next_mbchar
Packit Service 706eca
int
Packit Service 706eca
_rl_find_next_mbchar (string, seed, count, flags)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int seed, count, flags;
Packit Service 706eca
{
Packit Service 706eca
#if defined (HANDLE_MULTIBYTE)
Packit Service 706eca
  return _rl_find_next_mbchar_internal (string, seed, count, flags);
Packit Service 706eca
#else
Packit Service 706eca
  return (seed + count);
Packit Service 706eca
#endif
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
/* Find previous character started byte point of the specified seed.
Packit Service 706eca
   Returned point will be point <= seed.  If flags is MB_FIND_NONZERO,
Packit Service 706eca
   we look for non-zero-width multibyte characters. */
Packit Service 706eca
#undef _rl_find_prev_mbchar
Packit Service 706eca
int
Packit Service 706eca
_rl_find_prev_mbchar (string, seed, flags)
Packit Service 706eca
     char *string;
Packit Service 706eca
     int seed, flags;
Packit Service 706eca
{
Packit Service 706eca
#if defined (HANDLE_MULTIBYTE)
Packit Service 706eca
  return _rl_find_prev_mbchar_internal (string, seed, flags);
Packit Service 706eca
#else
Packit Service 706eca
  return ((seed == 0) ? seed : seed - 1);
Packit Service 706eca
#endif
Packit Service 706eca
}