function old new delta read_line_input 4886 5003 +117 in_uint16_table - 97 +97 in_interval_table - 78 +78 static.rtl_b - 68 +68 unicode_isrtl - 55 +55 isrtl_str - 51 +51 static.rtl_p - 42 +42 unicode_conv_to_printable2 633 477 -156 ------------------------------------------------------------------------------ (add/remove: 6/0 grow/shrink: 1/1 up/down: 508/-156) Total: 352 bytes Signed-off-by: Tomas Heinrich <heinrich.tomas@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
		
			
				
	
	
		
			561 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			561 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* vi: set sw=4 ts=4: */
 | 
						|
/*
 | 
						|
 * Unicode support routines.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2009 Denys Vlasenko
 | 
						|
 *
 | 
						|
 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
 | 
						|
 */
 | 
						|
#include "libbb.h"
 | 
						|
#include "unicode.h"
 | 
						|
 | 
						|
/* If it's not #defined as a constant in unicode.h... */
 | 
						|
#ifndef unicode_status
 | 
						|
uint8_t unicode_status;
 | 
						|
#endif
 | 
						|
 | 
						|
/* This file is compiled only if FEATURE_ASSUME_UNICODE is on.
 | 
						|
 * We check other options and decide whether to use libc support
 | 
						|
 * via locale, or use our own logic:
 | 
						|
 */
 | 
						|
 | 
						|
#if ENABLE_LOCALE_SUPPORT
 | 
						|
 | 
						|
/* Unicode support using libc locale support. */
 | 
						|
 | 
						|
void FAST_FUNC init_unicode(void)
 | 
						|
{
 | 
						|
	/* In unicode, this is a one character string */
 | 
						|
	static const char unicode_0x394[] = { 0xce, 0x94, 0 };
 | 
						|
 | 
						|
	if (unicode_status != UNICODE_UNKNOWN)
 | 
						|
		return;
 | 
						|
 | 
						|
	unicode_status = unicode_strlen(unicode_0x394) == 1 ? UNICODE_ON : UNICODE_OFF;
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
/* Homegrown Unicode support. It knows only C and Unicode locales. */
 | 
						|
 | 
						|
# if ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
 | 
						|
void FAST_FUNC init_unicode(void)
 | 
						|
{
 | 
						|
	char *lang;
 | 
						|
 | 
						|
	if (unicode_status != UNICODE_UNKNOWN)
 | 
						|
		return;
 | 
						|
 | 
						|
	unicode_status = UNICODE_OFF;
 | 
						|
	lang = getenv("LANG");
 | 
						|
	if (!lang || !(strstr(lang, ".utf") || strstr(lang, ".UTF")))
 | 
						|
		return;
 | 
						|
	unicode_status = UNICODE_ON;
 | 
						|
}
 | 
						|
# endif
 | 
						|
 | 
						|
static size_t wcrtomb_internal(char *s, wchar_t wc)
 | 
						|
{
 | 
						|
	int n, i;
 | 
						|
	uint32_t v = wc;
 | 
						|
 | 
						|
	if (v <= 0x7f) {
 | 
						|
		*s = v;
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* RFC 3629 says that Unicode ends at 10FFFF,
 | 
						|
	 * but we cover entire 32 bits */
 | 
						|
 | 
						|
	/* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 80-7FF -> 110yyyxx 10xxxxxx */
 | 
						|
 | 
						|
	/* How many bytes do we need? */
 | 
						|
	n = 2;
 | 
						|
	/* (0x80000000+ would result in n = 7, limiting n to 6) */
 | 
						|
	while (v >= 0x800 && n < 6) {
 | 
						|
		v >>= 5;
 | 
						|
		n++;
 | 
						|
	}
 | 
						|
	/* Fill bytes n-1..1 */
 | 
						|
	i = n;
 | 
						|
	while (--i) {
 | 
						|
		s[i] = (wc & 0x3f) | 0x80;
 | 
						|
		wc >>= 6;
 | 
						|
	}
 | 
						|
	/* Fill byte 0 */
 | 
						|
	s[0] = wc | (uint8_t)(0x3f00 >> n);
 | 
						|
	return n;
 | 
						|
}
 | 
						|
size_t FAST_FUNC wcrtomb(char *s, wchar_t wc, mbstate_t *ps UNUSED_PARAM)
 | 
						|
{
 | 
						|
	if (unicode_status != UNICODE_ON) {
 | 
						|
		*s = wc;
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	return wcrtomb_internal(s, wc);
 | 
						|
}
 | 
						|
size_t FAST_FUNC wcstombs(char *dest, const wchar_t *src, size_t n)
 | 
						|
{
 | 
						|
	size_t org_n = n;
 | 
						|
 | 
						|
	if (unicode_status != UNICODE_ON) {
 | 
						|
		while (n) {
 | 
						|
			wchar_t c = *src++;
 | 
						|
			*dest++ = c;
 | 
						|
			if (c == 0)
 | 
						|
				break;
 | 
						|
			n--;
 | 
						|
		}
 | 
						|
		return org_n - n;
 | 
						|
	}
 | 
						|
 | 
						|
	while (n >= MB_CUR_MAX) {
 | 
						|
		wchar_t wc = *src++;
 | 
						|
		size_t len = wcrtomb_internal(dest, wc);
 | 
						|
 | 
						|
		if (wc == L'\0')
 | 
						|
			return org_n - n;
 | 
						|
		dest += len;
 | 
						|
		n -= len;
 | 
						|
	}
 | 
						|
	while (n) {
 | 
						|
		char tbuf[MB_CUR_MAX];
 | 
						|
		wchar_t wc = *src++;
 | 
						|
		size_t len = wcrtomb_internal(tbuf, wc);
 | 
						|
 | 
						|
		if (len > n)
 | 
						|
			len = n;
 | 
						|
		memcpy(dest, tbuf, len);
 | 
						|
		if (wc == L'\0')
 | 
						|
			return org_n - n;
 | 
						|
		dest += len;
 | 
						|
		n -= len;
 | 
						|
	}
 | 
						|
	return org_n - n;
 | 
						|
}
 | 
						|
 | 
						|
#define ERROR_WCHAR (~(wchar_t)0)
 | 
						|
 | 
						|
static const char *mbstowc_internal(wchar_t *res, const char *src)
 | 
						|
{
 | 
						|
	int bytes;
 | 
						|
	unsigned c = (unsigned char) *src++;
 | 
						|
 | 
						|
	if (c <= 0x7f) {
 | 
						|
		*res = c;
 | 
						|
		return src;
 | 
						|
	}
 | 
						|
 | 
						|
	/* 80-7FF -> 110yyyxx 10xxxxxx */
 | 
						|
	/* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	/* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
 | 
						|
	bytes = 0;
 | 
						|
	do {
 | 
						|
		c <<= 1;
 | 
						|
		bytes++;
 | 
						|
	} while ((c & 0x80) && bytes < 6);
 | 
						|
	if (bytes == 1) {
 | 
						|
		/* A bare "continuation" byte. Say, 80 */
 | 
						|
		*res = ERROR_WCHAR;
 | 
						|
		return src;
 | 
						|
	}
 | 
						|
	c = (uint8_t)(c) >> bytes;
 | 
						|
 | 
						|
	while (--bytes) {
 | 
						|
		unsigned ch = (unsigned char) *src;
 | 
						|
		if ((ch & 0xc0) != 0x80) {
 | 
						|
			/* Missing "continuation" byte. Example: e0 80 */
 | 
						|
			*res = ERROR_WCHAR;
 | 
						|
			return src;
 | 
						|
		}
 | 
						|
		c = (c << 6) + (ch & 0x3f);
 | 
						|
		src++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* TODO */
 | 
						|
	/* Need to check that c isn't produced by overlong encoding */
 | 
						|
	/* Example: 11000000 10000000 converts to NUL */
 | 
						|
	/* 11110000 10000000 10000100 10000000 converts to 0x100 */
 | 
						|
	/* correct encoding: 11000100 10000000 */
 | 
						|
	if (c <= 0x7f) { /* crude check */
 | 
						|
		*res = ERROR_WCHAR;
 | 
						|
		return src;
 | 
						|
	}
 | 
						|
 | 
						|
	*res = c;
 | 
						|
	return src;
 | 
						|
}
 | 
						|
size_t FAST_FUNC mbstowcs(wchar_t *dest, const char *src, size_t n)
 | 
						|
{
 | 
						|
	size_t org_n = n;
 | 
						|
 | 
						|
	if (unicode_status != UNICODE_ON) {
 | 
						|
		while (n) {
 | 
						|
			unsigned char c = *src++;
 | 
						|
 | 
						|
			if (dest)
 | 
						|
				*dest++ = c;
 | 
						|
			if (c == 0)
 | 
						|
				break;
 | 
						|
			n--;
 | 
						|
		}
 | 
						|
		return org_n - n;
 | 
						|
	}
 | 
						|
 | 
						|
	while (n) {
 | 
						|
		wchar_t wc;
 | 
						|
		src = mbstowc_internal(&wc, src);
 | 
						|
		if (wc == ERROR_WCHAR) /* error */
 | 
						|
			return (size_t) -1L;
 | 
						|
		if (dest)
 | 
						|
			*dest++ = wc;
 | 
						|
		if (wc == 0) /* end-of-string */
 | 
						|
			break;
 | 
						|
		n--;
 | 
						|
	}
 | 
						|
 | 
						|
	return org_n - n;
 | 
						|
}
 | 
						|
 | 
						|
int FAST_FUNC iswspace(wint_t wc)
 | 
						|
{
 | 
						|
	return (unsigned)wc <= 0x7f && isspace(wc);
 | 
						|
}
 | 
						|
 | 
						|
int FAST_FUNC iswalnum(wint_t wc)
 | 
						|
{
 | 
						|
	return (unsigned)wc <= 0x7f && isalnum(wc);
 | 
						|
}
 | 
						|
 | 
						|
int FAST_FUNC iswpunct(wint_t wc)
 | 
						|
{
 | 
						|
	return (unsigned)wc <= 0x7f && ispunct(wc);
 | 
						|
}
 | 
						|
 | 
						|
#include "unicode_wcwidth.c"
 | 
						|
 | 
						|
# if ENABLE_UNICODE_BIDI_SUPPORT
 | 
						|
int FAST_FUNC unicode_isrtl(wint_t wc)
 | 
						|
{
 | 
						|
	/* ranges taken from
 | 
						|
	 * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt
 | 
						|
	 * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter
 | 
						|
	 */
 | 
						|
	static const struct interval rtl_b[] = {
 | 
						|
#  define BIG_(a,b) { a, b },
 | 
						|
#  define PAIR(a,b)
 | 
						|
		PAIR(0x0590, 0x0590)
 | 
						|
		PAIR(0x05BE, 0x05BE)
 | 
						|
		PAIR(0x05C0, 0x05C0)
 | 
						|
		PAIR(0x05C3, 0x05C3)
 | 
						|
		PAIR(0x05C6, 0x05C6)
 | 
						|
		BIG_(0x05C8, 0x05FF)
 | 
						|
		PAIR(0x0604, 0x0605)
 | 
						|
		PAIR(0x0608, 0x0608)
 | 
						|
		PAIR(0x060B, 0x060B)
 | 
						|
		PAIR(0x060D, 0x060D)
 | 
						|
		BIG_(0x061B, 0x064A)
 | 
						|
		PAIR(0x065F, 0x065F)
 | 
						|
		PAIR(0x066D, 0x066F)
 | 
						|
		BIG_(0x0671, 0x06D5)
 | 
						|
		PAIR(0x06E5, 0x06E6)
 | 
						|
		PAIR(0x06EE, 0x06EF)
 | 
						|
		BIG_(0x06FA, 0x070E)
 | 
						|
		PAIR(0x0710, 0x0710)
 | 
						|
		BIG_(0x0712, 0x072F)
 | 
						|
		BIG_(0x074B, 0x07A5)
 | 
						|
		BIG_(0x07B1, 0x07EA)
 | 
						|
		PAIR(0x07F4, 0x07F5)
 | 
						|
		BIG_(0x07FA, 0x0815)
 | 
						|
		PAIR(0x081A, 0x081A)
 | 
						|
		PAIR(0x0824, 0x0824)
 | 
						|
		PAIR(0x0828, 0x0828)
 | 
						|
		BIG_(0x082E, 0x08FF)
 | 
						|
		PAIR(0x200F, 0x200F)
 | 
						|
		PAIR(0x202B, 0x202B)
 | 
						|
		PAIR(0x202E, 0x202E)
 | 
						|
		BIG_(0xFB1D, 0xFB1D)
 | 
						|
		BIG_(0xFB1F, 0xFB28)
 | 
						|
		BIG_(0xFB2A, 0xFD3D)
 | 
						|
		BIG_(0xFD40, 0xFDCF)
 | 
						|
		BIG_(0xFDC8, 0xFDCF)
 | 
						|
		BIG_(0xFDF0, 0xFDFC)
 | 
						|
		BIG_(0xFDFE, 0xFDFF)
 | 
						|
		BIG_(0xFE70, 0xFEFE)
 | 
						|
		/* Probably not necessary
 | 
						|
		{0x10800, 0x1091E},
 | 
						|
		{0x10920, 0x10A00},
 | 
						|
		{0x10A04, 0x10A04},
 | 
						|
		{0x10A07, 0x10A0B},
 | 
						|
		{0x10A10, 0x10A37},
 | 
						|
		{0x10A3B, 0x10A3E},
 | 
						|
		{0x10A40, 0x10A7F},
 | 
						|
		{0x10B36, 0x10B38},
 | 
						|
		{0x10B40, 0x10E5F},
 | 
						|
		{0x10E7F, 0x10FFF},
 | 
						|
		{0x1E800, 0x1EFFF}
 | 
						|
		*/
 | 
						|
#  undef BIG_
 | 
						|
#  undef PAIR
 | 
						|
	};
 | 
						|
 | 
						|
	static const uint16_t rtl_p[] = {
 | 
						|
#  define BIG_(a,b)
 | 
						|
#  define PAIR(a,b) (a << 2) | (b-a),
 | 
						|
		/* Exact copy-n-paste of the above: */
 | 
						|
		PAIR(0x0590, 0x0590)
 | 
						|
		PAIR(0x05BE, 0x05BE)
 | 
						|
		PAIR(0x05C0, 0x05C0)
 | 
						|
		PAIR(0x05C3, 0x05C3)
 | 
						|
		PAIR(0x05C6, 0x05C6)
 | 
						|
		BIG_(0x05C8, 0x05FF)
 | 
						|
		PAIR(0x0604, 0x0605)
 | 
						|
		PAIR(0x0608, 0x0608)
 | 
						|
		PAIR(0x060B, 0x060B)
 | 
						|
		PAIR(0x060D, 0x060D)
 | 
						|
		BIG_(0x061B, 0x064A)
 | 
						|
		PAIR(0x065F, 0x065F)
 | 
						|
		PAIR(0x066D, 0x066F)
 | 
						|
		BIG_(0x0671, 0x06D5)
 | 
						|
		PAIR(0x06E5, 0x06E6)
 | 
						|
		PAIR(0x06EE, 0x06EF)
 | 
						|
		BIG_(0x06FA, 0x070E)
 | 
						|
		PAIR(0x0710, 0x0710)
 | 
						|
		BIG_(0x0712, 0x072F)
 | 
						|
		BIG_(0x074B, 0x07A5)
 | 
						|
		BIG_(0x07B1, 0x07EA)
 | 
						|
		PAIR(0x07F4, 0x07F5)
 | 
						|
		BIG_(0x07FA, 0x0815)
 | 
						|
		PAIR(0x081A, 0x081A)
 | 
						|
		PAIR(0x0824, 0x0824)
 | 
						|
		PAIR(0x0828, 0x0828)
 | 
						|
		BIG_(0x082E, 0x08FF)
 | 
						|
		PAIR(0x200F, 0x200F)
 | 
						|
		PAIR(0x202B, 0x202B)
 | 
						|
		PAIR(0x202E, 0x202E)
 | 
						|
		BIG_(0xFB1D, 0xFB1D)
 | 
						|
		BIG_(0xFB1F, 0xFB28)
 | 
						|
		BIG_(0xFB2A, 0xFD3D)
 | 
						|
		BIG_(0xFD40, 0xFDCF)
 | 
						|
		BIG_(0xFDC8, 0xFDCF)
 | 
						|
		BIG_(0xFDF0, 0xFDFC)
 | 
						|
		BIG_(0xFDFE, 0xFDFF)
 | 
						|
		BIG_(0xFE70, 0xFEFE)
 | 
						|
		/* Probably not necessary
 | 
						|
		{0x10800, 0x1091E},
 | 
						|
		{0x10920, 0x10A00},
 | 
						|
		{0x10A04, 0x10A04},
 | 
						|
		{0x10A07, 0x10A0B},
 | 
						|
		{0x10A10, 0x10A37},
 | 
						|
		{0x10A3B, 0x10A3E},
 | 
						|
		{0x10A40, 0x10A7F},
 | 
						|
		{0x10B36, 0x10B38},
 | 
						|
		{0x10B40, 0x10E5F},
 | 
						|
		{0x10E7F, 0x10FFF},
 | 
						|
		{0x1E800, 0x1EFFF}
 | 
						|
		*/
 | 
						|
#  undef BIG_
 | 
						|
#  undef PAIR
 | 
						|
	};
 | 
						|
 | 
						|
	if (in_interval_table(wc, rtl_b, ARRAY_SIZE(rtl_b) - 1))
 | 
						|
		return 1;
 | 
						|
	if (in_uint16_table(wc, rtl_p, ARRAY_SIZE(rtl_p) - 1))
 | 
						|
		return 1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
# endif /* UNICODE_BIDI_SUPPORT */
 | 
						|
 | 
						|
#endif /* Homegrown Unicode support */
 | 
						|
 | 
						|
 | 
						|
/* The rest is mostly same for libc and for "homegrown" support */
 | 
						|
 | 
						|
size_t FAST_FUNC unicode_strlen(const char *string)
 | 
						|
{
 | 
						|
	size_t width = mbstowcs(NULL, string, INT_MAX);
 | 
						|
	if (width == (size_t)-1L)
 | 
						|
		return strlen(string);
 | 
						|
	return width;
 | 
						|
}
 | 
						|
 | 
						|
static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
 | 
						|
{
 | 
						|
	char *dst;
 | 
						|
	unsigned dst_len;
 | 
						|
	unsigned uni_count;
 | 
						|
	unsigned uni_width;
 | 
						|
 | 
						|
	if (unicode_status != UNICODE_ON) {
 | 
						|
		char *d;
 | 
						|
		if (flags & UNI_FLAG_PAD) {
 | 
						|
			d = dst = xmalloc(width + 1);
 | 
						|
			while ((int)--width >= 0) {
 | 
						|
				unsigned char c = *src;
 | 
						|
				if (c == '\0') {
 | 
						|
					do
 | 
						|
						*d++ = ' ';
 | 
						|
					while ((int)--width >= 0);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				*d++ = (c >= ' ' && c < 0x7f) ? c : '?';
 | 
						|
				src++;
 | 
						|
			}
 | 
						|
			*d = '\0';
 | 
						|
		} else {
 | 
						|
			d = dst = xstrndup(src, width);
 | 
						|
			while (*d) {
 | 
						|
				unsigned char c = *d;
 | 
						|
				if (c < ' ' || c >= 0x7f)
 | 
						|
					*d = '?';
 | 
						|
				d++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (stats)
 | 
						|
			stats->byte_count = stats->unicode_count = (d - dst);
 | 
						|
		return dst;
 | 
						|
	}
 | 
						|
 | 
						|
	dst = NULL;
 | 
						|
	uni_count = uni_width = 0;
 | 
						|
	dst_len = 0;
 | 
						|
	while (1) {
 | 
						|
		int w;
 | 
						|
		wchar_t wc;
 | 
						|
 | 
						|
#if ENABLE_LOCALE_SUPPORT
 | 
						|
		{
 | 
						|
			mbstate_t mbst = { 0 };
 | 
						|
			ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
 | 
						|
			/* If invalid sequence is seen: -1 is returned,
 | 
						|
			 * src points to the invalid sequence, errno = EILSEQ.
 | 
						|
			 * Else number of wchars (excluding terminating L'\0')
 | 
						|
			 * written to dest is returned.
 | 
						|
			 * If len (here: 1) non-L'\0' wchars stored at dest,
 | 
						|
			 * src points to the next char to be converted.
 | 
						|
			 * If string is completely converted: src = NULL.
 | 
						|
			 */
 | 
						|
			if (rc == 0) /* end-of-string */
 | 
						|
				break;
 | 
						|
			if (rc < 0) { /* error */
 | 
						|
				src++;
 | 
						|
				goto subst;
 | 
						|
			}
 | 
						|
			if (!iswprint(wc))
 | 
						|
				goto subst;
 | 
						|
		}
 | 
						|
#else
 | 
						|
		src = mbstowc_internal(&wc, src);
 | 
						|
		/* src is advanced to next mb char
 | 
						|
		 * wc == ERROR_WCHAR: invalid sequence is seen
 | 
						|
		 * else: wc is set
 | 
						|
		 */
 | 
						|
		if (wc == ERROR_WCHAR) /* error */
 | 
						|
			goto subst;
 | 
						|
		if (wc == 0) /* end-of-string */
 | 
						|
			break;
 | 
						|
#endif
 | 
						|
		if (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
 | 
						|
			goto subst;
 | 
						|
		w = wcwidth(wc);
 | 
						|
		if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) /* non-printable wchar */
 | 
						|
		 || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
 | 
						|
		 || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
 | 
						|
		) {
 | 
						|
 subst:
 | 
						|
			wc = CONFIG_SUBST_WCHAR;
 | 
						|
			w = 1;
 | 
						|
		}
 | 
						|
		width -= w;
 | 
						|
		/* Note: if width == 0, we still may add more chars,
 | 
						|
		 * they may be zero-width or combining ones */
 | 
						|
		if ((int)width < 0) {
 | 
						|
			/* can't add this wc, string would become longer than width */
 | 
						|
			width += w;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		uni_count++;
 | 
						|
		uni_width += w;
 | 
						|
		dst = xrealloc(dst, dst_len + MB_CUR_MAX);
 | 
						|
#if ENABLE_LOCALE_SUPPORT
 | 
						|
		{
 | 
						|
			mbstate_t mbst = { 0 };
 | 
						|
			dst_len += wcrtomb(&dst[dst_len], wc, &mbst);
 | 
						|
		}
 | 
						|
#else
 | 
						|
		dst_len += wcrtomb_internal(&dst[dst_len], wc);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	/* Pad to remaining width */
 | 
						|
	if (flags & UNI_FLAG_PAD) {
 | 
						|
		dst = xrealloc(dst, dst_len + width + 1);
 | 
						|
		uni_count += width;
 | 
						|
		uni_width += width;
 | 
						|
		while ((int)--width >= 0) {
 | 
						|
			dst[dst_len++] = ' ';
 | 
						|
		}
 | 
						|
	}
 | 
						|
	dst[dst_len] = '\0';
 | 
						|
	if (stats) {
 | 
						|
		stats->byte_count = dst_len;
 | 
						|
		stats->unicode_count = uni_count;
 | 
						|
		stats->unicode_width = uni_width;
 | 
						|
	}
 | 
						|
 | 
						|
	return dst;
 | 
						|
}
 | 
						|
char* FAST_FUNC unicode_conv_to_printable(uni_stat_t *stats, const char *src)
 | 
						|
{
 | 
						|
	return unicode_conv_to_printable2(stats, src, INT_MAX, 0);
 | 
						|
}
 | 
						|
char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth)
 | 
						|
{
 | 
						|
	return unicode_conv_to_printable2(stats, src, maxwidth, 0);
 | 
						|
}
 | 
						|
char* FAST_FUNC unicode_conv_to_printable_fixedwidth(uni_stat_t *stats, const char *src, unsigned width)
 | 
						|
{
 | 
						|
	return unicode_conv_to_printable2(stats, src, width, UNI_FLAG_PAD);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef UNUSED
 | 
						|
unsigned FAST_FUNC unicode_padding_to_width(unsigned width, const char *src)
 | 
						|
{
 | 
						|
	if (unicode_status != UNICODE_ON) {
 | 
						|
		return width - strnlen(src, width);
 | 
						|
	}
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		int w;
 | 
						|
		wchar_t wc;
 | 
						|
 | 
						|
#if ENABLE_LOCALE_SUPPORT
 | 
						|
		{
 | 
						|
			mbstate_t mbst = { 0 };
 | 
						|
			ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
 | 
						|
			if (rc <= 0) /* error, or end-of-string */
 | 
						|
				return width;
 | 
						|
		}
 | 
						|
#else
 | 
						|
		src = mbstowc_internal(&wc, src);
 | 
						|
		if (wc == ERROR_WCHAR || wc == 0) /* error, or end-of-string */
 | 
						|
			return width;
 | 
						|
#endif
 | 
						|
		w = wcwidth(wc);
 | 
						|
		if (w < 0) /* non-printable wchar */
 | 
						|
			return width;
 | 
						|
		width -= w;
 | 
						|
		if ((int)width <= 0) /* string is longer than width */
 | 
						|
			return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 |