]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/xz/src/common/tuklib_mbstr_width.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / contrib / xz / 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 }