version 1.1.1.1, 2014/07/30 08:16:45
|
version 1.1.1.2, 2021/03/17 01:01:01
|
Line 1
|
Line 1
|
/* mbutil.c -- readline multibyte character utility functions */ |
/* mbutil.c -- readline multibyte character utility functions */ |
|
|
/* Copyright (C) 2001-2009 Free Software Foundation, Inc. | /* Copyright (C) 2001-2020 Free Software Foundation, Inc. |
|
|
This file is part of the GNU Readline Library (Readline), a library |
This file is part of the GNU Readline Library (Readline), a library |
for reading lines of text with interactive input and history editing. |
for reading lines of text with interactive input and history editing. |
Line 75 int _rl_utf8locale = 0;
|
Line 75 int _rl_utf8locale = 0;
|
|
|
#if defined(HANDLE_MULTIBYTE) |
#if defined(HANDLE_MULTIBYTE) |
|
|
|
/* **************************************************************** */ |
|
/* */ |
|
/* UTF-8 specific Character Utility Functions */ |
|
/* */ |
|
/* **************************************************************** */ |
|
|
|
/* Return the length in bytes of the possibly-multibyte character beginning |
|
at S. Encoding is UTF-8. */ |
static int |
static int |
_rl_find_next_mbchar_internal (string, seed, count, find_non_zero) | _rl_utf8_mblen (const char *s, size_t n) |
char *string; | |
int seed, count, find_non_zero; | |
{ |
{ |
|
unsigned char c, c1, c2, c3; |
|
|
|
if (s == 0) |
|
return (0); /* no shift states */ |
|
if (n <= 0) |
|
return (-1); |
|
|
|
c = (unsigned char)*s; |
|
if (c < 0x80) |
|
return (c != 0); |
|
if (c >= 0xc2) |
|
{ |
|
c1 = (unsigned char)s[1]; |
|
if (c < 0xe0) |
|
{ |
|
if (n == 1) |
|
return -2; |
|
if (n >= 2 && (c1 ^ 0x80) < 0x40) |
|
return 2; |
|
} |
|
else if (c < 0xf0) |
|
{ |
|
if (n == 1) |
|
return -2; |
|
if ((c1 ^ 0x80) < 0x40 |
|
&& (c >= 0xe1 || c1 >= 0xa0) |
|
&& (c != 0xed || c1 < 0xa0)) |
|
{ |
|
if (n == 2) |
|
return -2; |
|
c2 = (unsigned char)s[2]; |
|
if ((c2 ^ 0x80) < 0x40) |
|
return 3; |
|
} |
|
} |
|
else if (c < 0xf4) |
|
{ |
|
if (n == 1) |
|
return -2; |
|
if (((c1 ^ 0x80) < 0x40) |
|
&& (c >= 0xf1 || c1 >= 0x90) |
|
&& (c < 0xf4 || (c == 0xf4 && c1 < 0x90))) |
|
{ |
|
if (n == 2) |
|
return -2; |
|
c2 = (unsigned char)s[2]; |
|
if ((c2 ^ 0x80) < 0x40) |
|
{ |
|
if (n == 3) |
|
return -2; |
|
c3 = (unsigned char)s[3]; |
|
if ((c3 ^ 0x80) < 0x40) |
|
return 4; |
|
} |
|
} |
|
} |
|
} |
|
/* invalid or incomplete multibyte character */ |
|
return -1; |
|
} |
|
|
|
static int |
|
_rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_zero) |
|
{ |
size_t tmp, len; |
size_t tmp, len; |
mbstate_t ps; |
mbstate_t ps; |
int point; |
int point; |
Line 94 _rl_find_next_mbchar_internal (string, seed, count, fi
|
Line 164 _rl_find_next_mbchar_internal (string, seed, count, fi
|
return seed; |
return seed; |
|
|
point = seed + _rl_adjust_point (string, seed, &ps); |
point = seed + _rl_adjust_point (string, seed, &ps); |
|
/* if _rl_adjust_point returns -1, the character or string is invalid. |
|
treat as a byte. */ |
|
if (point == seed - 1) /* invalid */ |
|
return seed + 1; |
|
|
/* if this is true, means that seed was not pointing to a byte indicating |
/* if this is true, means that seed was not pointing to a byte indicating |
the beginning of a multibyte character. Correct the point and consume |
the beginning of a multibyte character. Correct the point and consume |
one char. */ |
one char. */ |
Line 105 _rl_find_next_mbchar_internal (string, seed, count, fi
|
Line 180 _rl_find_next_mbchar_internal (string, seed, count, fi
|
len = strlen (string + point); |
len = strlen (string + point); |
if (len == 0) |
if (len == 0) |
break; |
break; |
tmp = mbrtowc (&wc, string+point, len, &ps); | if (_rl_utf8locale && UTF8_SINGLEBYTE(string[point])) |
| { |
| tmp = 1; |
| wc = (wchar_t) string[point]; |
| memset(&ps, 0, sizeof(mbstate_t)); |
| } |
| else |
| tmp = mbrtowc (&wc, string+point, len, &ps); |
if (MB_INVALIDCH ((size_t)tmp)) |
if (MB_INVALIDCH ((size_t)tmp)) |
{ |
{ |
/* invalid bytes. assume a byte represents a character */ |
/* invalid bytes. assume a byte represents a character */ |
Line 145 _rl_find_next_mbchar_internal (string, seed, count, fi
|
Line 227 _rl_find_next_mbchar_internal (string, seed, count, fi
|
return point; |
return point; |
} |
} |
|
|
|
static inline int |
|
_rl_test_nonzero (char *string, int ind, int len) |
|
{ |
|
size_t tmp; |
|
wchar_t wc; |
|
mbstate_t ps; |
|
|
|
memset (&ps, 0, sizeof (mbstate_t)); |
|
tmp = mbrtowc (&wc, string + ind, len - ind, &ps); |
|
/* treat invalid multibyte sequences as non-zero-width */ |
|
return (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp) || WCWIDTH (wc) > 0); |
|
} |
|
|
|
/* experimental -- needs to handle zero-width characters better */ |
static int |
static int |
_rl_find_prev_mbchar_internal (string, seed, find_non_zero) | _rl_find_prev_utf8char (char *string, int seed, int find_non_zero) |
char *string; | |
int seed, find_non_zero; | |
{ |
{ |
|
char *s; |
|
unsigned char b; |
|
int save, prev; |
|
size_t len; |
|
|
|
if (find_non_zero) |
|
len = RL_STRLEN (string); |
|
|
|
prev = seed - 1; |
|
while (prev >= 0) |
|
{ |
|
b = (unsigned char)string[prev]; |
|
if (UTF8_SINGLEBYTE (b)) |
|
return (prev); |
|
|
|
save = prev; |
|
|
|
/* Move back until we're not in the middle of a multibyte char */ |
|
if (UTF8_MBCHAR (b)) |
|
{ |
|
while (prev > 0 && (b = (unsigned char)string[--prev]) && UTF8_MBCHAR (b)) |
|
; |
|
} |
|
|
|
if (UTF8_MBFIRSTCHAR (b)) |
|
{ |
|
if (find_non_zero) |
|
{ |
|
if (_rl_test_nonzero (string, prev, len)) |
|
return (prev); |
|
else /* valid but WCWIDTH (wc) == 0 */ |
|
prev = prev - 1; |
|
} |
|
else |
|
return (prev); |
|
} |
|
else |
|
return (save); /* invalid utf-8 multibyte sequence */ |
|
} |
|
|
|
return ((prev < 0) ? 0 : prev); |
|
} |
|
|
|
/*static*/ int |
|
_rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero) |
|
{ |
mbstate_t ps; |
mbstate_t ps; |
int prev, non_zero_prev, point, length; |
int prev, non_zero_prev, point, length; |
size_t tmp; |
size_t tmp; |
wchar_t wc; |
wchar_t wc; |
|
|
|
if (_rl_utf8locale) |
|
return (_rl_find_prev_utf8char (string, seed, find_non_zero)); |
|
|
memset(&ps, 0, sizeof(mbstate_t)); |
memset(&ps, 0, sizeof(mbstate_t)); |
length = strlen(string); |
length = strlen(string); |
|
|
Line 166 _rl_find_prev_mbchar_internal (string, seed, find_non_
|
Line 309 _rl_find_prev_mbchar_internal (string, seed, find_non_
|
prev = non_zero_prev = point = 0; |
prev = non_zero_prev = point = 0; |
while (point < seed) |
while (point < seed) |
{ |
{ |
tmp = mbrtowc (&wc, string + point, length - point, &ps); | if (_rl_utf8locale && UTF8_SINGLEBYTE(string[point])) |
| { |
| tmp = 1; |
| wc = (wchar_t) string[point]; |
| memset(&ps, 0, sizeof(mbstate_t)); |
| } |
| else |
| tmp = mbrtowc (&wc, string + point, length - point, &ps); |
if (MB_INVALIDCH ((size_t)tmp)) |
if (MB_INVALIDCH ((size_t)tmp)) |
{ |
{ |
/* in this case, bytes are invalid or shorted to compose | /* in this case, bytes are invalid or too short to compose |
multibyte char, so assume that the first byte represents |
multibyte char, so assume that the first byte represents |
a single character anyway. */ |
a single character anyway. */ |
tmp = 1; |
tmp = 1; |
Line 206 _rl_find_prev_mbchar_internal (string, seed, find_non_
|
Line 356 _rl_find_prev_mbchar_internal (string, seed, find_non_
|
if an invalid multibyte sequence was encountered. It returns (size_t)(-2) |
if an invalid multibyte sequence was encountered. It returns (size_t)(-2) |
if it couldn't parse a complete multibyte character. */ |
if it couldn't parse a complete multibyte character. */ |
int |
int |
_rl_get_char_len (src, ps) | _rl_get_char_len (char *src, mbstate_t *ps) |
char *src; | |
mbstate_t *ps; | |
{ |
{ |
size_t tmp; | size_t tmp, l; |
| int mb_cur_max; |
|
|
tmp = mbrlen((const char *)src, (size_t)strlen (src), ps); | /* Look at no more than MB_CUR_MAX characters */ |
| l = (size_t)strlen (src); |
| if (_rl_utf8locale && l > 0 && UTF8_SINGLEBYTE(*src)) |
| tmp = (*src != 0) ? 1 : 0; |
| else |
| { |
| mb_cur_max = MB_CUR_MAX; |
| tmp = mbrlen((const char *)src, (l < mb_cur_max) ? l : mb_cur_max, ps); |
| } |
if (tmp == (size_t)(-2)) |
if (tmp == (size_t)(-2)) |
{ |
{ |
/* shorted to compose multibyte char */ | /* too short to compose multibyte char */ |
if (ps) |
if (ps) |
memset (ps, 0, sizeof(mbstate_t)); |
memset (ps, 0, sizeof(mbstate_t)); |
return -2; |
return -2; |
Line 237 _rl_get_char_len (src, ps)
|
Line 394 _rl_get_char_len (src, ps)
|
/* compare the specified two characters. If the characters matched, |
/* compare the specified two characters. If the characters matched, |
return 1. Otherwise return 0. */ |
return 1. Otherwise return 0. */ |
int |
int |
_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) | _rl_compare_chars (char *buf1, int pos1, mbstate_t *ps1, char *buf2, int pos2, mbstate_t *ps2) |
char *buf1; | |
int pos1; | |
mbstate_t *ps1; | |
char *buf2; | |
int pos2; | |
mbstate_t *ps2; | |
{ |
{ |
int i, w1, w2; |
int i, w1, w2; |
|
|
Line 263 _rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
|
Line 414 _rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
|
/* adjust pointed byte and find mbstate of the point of string. |
/* adjust pointed byte and find mbstate of the point of string. |
adjusted point will be point <= adjusted_point, and returns |
adjusted point will be point <= adjusted_point, and returns |
differences of the byte(adjusted_point - point). |
differences of the byte(adjusted_point - point). |
if point is invalied (point < 0 || more than string length), | if point is invalid (point < 0 || more than string length), |
it returns -1 */ |
it returns -1 */ |
int |
int |
_rl_adjust_point (string, point, ps) | _rl_adjust_point (char *string, int point, mbstate_t *ps) |
char *string; | |
int point; | |
mbstate_t *ps; | |
{ |
{ |
size_t tmp = 0; | size_t tmp; |
int length; | int length, pos; |
int pos = 0; | |
|
|
|
tmp = 0; |
|
pos = 0; |
length = strlen(string); |
length = strlen(string); |
if (point < 0) |
if (point < 0) |
return -1; |
return -1; |
Line 283 _rl_adjust_point (string, point, ps)
|
Line 432 _rl_adjust_point (string, point, ps)
|
|
|
while (pos < point) |
while (pos < point) |
{ |
{ |
tmp = mbrlen (string + pos, length - pos, ps); | if (_rl_utf8locale && UTF8_SINGLEBYTE(string[pos])) |
| tmp = 1; |
| else |
| tmp = mbrlen (string + pos, length - pos, ps); |
if (MB_INVALIDCH ((size_t)tmp)) |
if (MB_INVALIDCH ((size_t)tmp)) |
{ |
{ |
/* in this case, bytes are invalid or shorted to compose | /* in this case, bytes are invalid or too short to compose |
multibyte char, so assume that the first byte represents |
multibyte char, so assume that the first byte represents |
a single character anyway. */ |
a single character anyway. */ |
pos++; |
pos++; |
Line 305 _rl_adjust_point (string, point, ps)
|
Line 457 _rl_adjust_point (string, point, ps)
|
} |
} |
|
|
int |
int |
_rl_is_mbchar_matched (string, seed, end, mbchar, length) | _rl_is_mbchar_matched (char *string, int seed, int end, char *mbchar, int length) |
char *string; | |
int seed, end; | |
char *mbchar; | |
int length; | |
{ |
{ |
int i; |
int i; |
|
|
Line 323 _rl_is_mbchar_matched (string, seed, end, mbchar, leng
|
Line 471 _rl_is_mbchar_matched (string, seed, end, mbchar, leng
|
} |
} |
|
|
wchar_t |
wchar_t |
_rl_char_value (buf, ind) | _rl_char_value (char *buf, int ind) |
char *buf; | |
int ind; | |
{ |
{ |
size_t tmp; |
size_t tmp; |
wchar_t wc; |
wchar_t wc; |
Line 334 _rl_char_value (buf, ind)
|
Line 480 _rl_char_value (buf, ind)
|
|
|
if (MB_LEN_MAX == 1 || rl_byte_oriented) |
if (MB_LEN_MAX == 1 || rl_byte_oriented) |
return ((wchar_t) buf[ind]); |
return ((wchar_t) buf[ind]); |
|
if (_rl_utf8locale && UTF8_SINGLEBYTE(buf[ind])) |
|
return ((wchar_t) buf[ind]); |
l = strlen (buf); |
l = strlen (buf); |
if (ind >= l - 1) |
if (ind >= l - 1) |
return ((wchar_t) buf[ind]); |
return ((wchar_t) buf[ind]); |
|
if (l < ind) /* Sanity check */ |
|
l = strlen (buf+ind); |
memset (&ps, 0, sizeof (mbstate_t)); |
memset (&ps, 0, sizeof (mbstate_t)); |
tmp = mbrtowc (&wc, buf + ind, l - ind, &ps); |
tmp = mbrtowc (&wc, buf + ind, l - ind, &ps); |
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp)) |
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp)) |
Line 350 _rl_char_value (buf, ind)
|
Line 500 _rl_char_value (buf, ind)
|
characters. */ |
characters. */ |
#undef _rl_find_next_mbchar |
#undef _rl_find_next_mbchar |
int |
int |
_rl_find_next_mbchar (string, seed, count, flags) | _rl_find_next_mbchar (char *string, int seed, int count, int flags) |
char *string; | |
int seed, count, flags; | |
{ |
{ |
#if defined (HANDLE_MULTIBYTE) |
#if defined (HANDLE_MULTIBYTE) |
return _rl_find_next_mbchar_internal (string, seed, count, flags); |
return _rl_find_next_mbchar_internal (string, seed, count, flags); |
Line 366 _rl_find_next_mbchar (string, seed, count, flags)
|
Line 514 _rl_find_next_mbchar (string, seed, count, flags)
|
we look for non-zero-width multibyte characters. */ |
we look for non-zero-width multibyte characters. */ |
#undef _rl_find_prev_mbchar |
#undef _rl_find_prev_mbchar |
int |
int |
_rl_find_prev_mbchar (string, seed, flags) | _rl_find_prev_mbchar (char *string, int seed, int flags) |
char *string; | |
int seed, flags; | |
{ |
{ |
#if defined (HANDLE_MULTIBYTE) |
#if defined (HANDLE_MULTIBYTE) |
return _rl_find_prev_mbchar_internal (string, seed, flags); |
return _rl_find_prev_mbchar_internal (string, seed, flags); |