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 } 66