(root)/
xz-5.4.5/
src/
common/
tuklib_mbstr_width.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       tuklib_mbstr_width.c
       4  /// \brief      Calculate width of a multibyte string
       5  //
       6  //  Author:     Lasse Collin
       7  //
       8  //  This file has been put into the public domain.
       9  //  You can do whatever you want with this file.
      10  //
      11  ///////////////////////////////////////////////////////////////////////////////
      12  
      13  #include "tuklib_mbstr.h"
      14  #include <string.h>
      15  
      16  #if defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
      17  #	include <wchar.h>
      18  #endif
      19  
      20  
      21  extern size_t
      22  tuklib_mbstr_width(const char *str, size_t *bytes)
      23  {
      24  	const size_t len = strlen(str);
      25  	if (bytes != NULL)
      26  		*bytes = len;
      27  
      28  #if !(defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH))
      29  	// In single-byte mode, the width of the string is the same
      30  	// as its length.
      31  	return len;
      32  
      33  #else
      34  	mbstate_t state;
      35  	memset(&state, 0, sizeof(state));
      36  
      37  	size_t width = 0;
      38  	size_t i = 0;
      39  
      40  	// Convert one multibyte character at a time to wchar_t
      41  	// and get its width using wcwidth().
      42  	while (i < len) {
      43  		wchar_t wc;
      44  		const size_t ret = mbrtowc(&wc, str + i, len - i, &state);
      45  		if (ret < 1 || ret > len)
      46  			return (size_t)-1;
      47  
      48  		i += ret;
      49  
      50  		const int wc_width = wcwidth(wc);
      51  		if (wc_width < 0)
      52  			return (size_t)-1;
      53  
      54  		width += (size_t)wc_width;
      55  	}
      56  
      57  	// Require that the string ends in the initial shift state.
      58  	// This way the caller can be combine the string with other
      59  	// strings without needing to worry about the shift states.
      60  	if (!mbsinit(&state))
      61  		return (size_t)-1;
      62  
      63  	return width;
      64  #endif
      65  }