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