12940b44dSPeter Avalos /////////////////////////////////////////////////////////////////////////////// 22940b44dSPeter Avalos // 3*e151908bSDaniel Fojt /// \file tuklib_mbstr_width.c 42940b44dSPeter Avalos /// \brief Calculate width of a multibyte string 52940b44dSPeter Avalos // 62940b44dSPeter Avalos // Author: Lasse Collin 72940b44dSPeter Avalos // 82940b44dSPeter Avalos // This file has been put into the public domain. 92940b44dSPeter Avalos // You can do whatever you want with this file. 102940b44dSPeter Avalos // 112940b44dSPeter Avalos /////////////////////////////////////////////////////////////////////////////// 122940b44dSPeter Avalos 132940b44dSPeter Avalos #include "tuklib_mbstr.h" 14*e151908bSDaniel Fojt #include <string.h> 152940b44dSPeter Avalos 162940b44dSPeter Avalos #if defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) 172940b44dSPeter Avalos # include <wchar.h> 182940b44dSPeter Avalos #endif 192940b44dSPeter Avalos 202940b44dSPeter Avalos 212940b44dSPeter Avalos extern size_t tuklib_mbstr_width(const char * str,size_t * bytes)222940b44dSPeter Avalostuklib_mbstr_width(const char *str, size_t *bytes) 232940b44dSPeter Avalos { 242940b44dSPeter Avalos const size_t len = strlen(str); 252940b44dSPeter Avalos if (bytes != NULL) 262940b44dSPeter Avalos *bytes = len; 272940b44dSPeter Avalos 282940b44dSPeter Avalos #if !(defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)) 292940b44dSPeter Avalos // In single-byte mode, the width of the string is the same 302940b44dSPeter Avalos // as its length. 312940b44dSPeter Avalos return len; 322940b44dSPeter Avalos 332940b44dSPeter Avalos #else 342940b44dSPeter Avalos mbstate_t state; 352940b44dSPeter Avalos memset(&state, 0, sizeof(state)); 362940b44dSPeter Avalos 372940b44dSPeter Avalos size_t width = 0; 382940b44dSPeter Avalos size_t i = 0; 392940b44dSPeter Avalos 402940b44dSPeter Avalos // Convert one multibyte character at a time to wchar_t 412940b44dSPeter Avalos // and get its width using wcwidth(). 422940b44dSPeter Avalos while (i < len) { 432940b44dSPeter Avalos wchar_t wc; 442940b44dSPeter Avalos const size_t ret = mbrtowc(&wc, str + i, len - i, &state); 452940b44dSPeter Avalos if (ret < 1 || ret > len) 462940b44dSPeter Avalos return (size_t)-1; 472940b44dSPeter Avalos 482940b44dSPeter Avalos i += ret; 492940b44dSPeter Avalos 502940b44dSPeter Avalos const int wc_width = wcwidth(wc); 512940b44dSPeter Avalos if (wc_width < 0) 522940b44dSPeter Avalos return (size_t)-1; 532940b44dSPeter Avalos 54*e151908bSDaniel Fojt width += (size_t)wc_width; 552940b44dSPeter Avalos } 562940b44dSPeter Avalos 572940b44dSPeter Avalos // Require that the string ends in the initial shift state. 582940b44dSPeter Avalos // This way the caller can be combine the string with other 592940b44dSPeter Avalos // strings without needing to worry about the shift states. 602940b44dSPeter Avalos if (!mbsinit(&state)) 612940b44dSPeter Avalos return (size_t)-1; 622940b44dSPeter Avalos 632940b44dSPeter Avalos return width; 642940b44dSPeter Avalos #endif 652940b44dSPeter Avalos } 66