Updated changelog
[ncmpc-debian.git] / src / util / LocaleString.cxx
1 /*
2  * Copyright 2018 Max Kellermann <max.kellermann@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
20  * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "LocaleString.hxx"
31
32 #include <cwchar>
33
34 #include <string.h>
35
36 bool
37 IsIncompleteCharMB(const char *s, size_t n) noexcept
38 {
39         auto mb = std::mbstate_t();
40         const std::size_t length = std::mbrlen(s, n, &mb);
41         return length == std::size_t(-2);
42 }
43
44 std::size_t
45 StringLengthMB(const char *s, size_t byte_length) noexcept
46 {
47         const char *const end = s + byte_length;
48         auto state = std::mbstate_t();
49
50         size_t length = 0;
51         while (s < end) {
52                 wchar_t w;
53                 std::size_t n = std::mbrtowc(&w, s, end - s, &state);
54                 if (n == std::size_t(-2))
55                         break;
56
57                 if (n == std::size_t(-1) || n == 0) {
58                         ++s;
59                 } else {
60                         s += n;
61                         ++length;
62                 }
63         }
64
65         return length;
66
67 }
68
69 std::size_t
70 CharSizeMB(const char *s, size_t n) noexcept
71 {
72         auto mb = std::mbstate_t();
73         const std::size_t length = std::mbrlen(s, n, &mb);
74         if (length == std::size_t(-2))
75                 return n;
76
77         if (length == std::size_t(-1))
78                 return 1;
79
80         return length;
81 }
82
83 const char *
84 PrevCharMB(const char *start, const char *reference) noexcept
85 {
86         const char *p = reference;
87
88         while (p > start) {
89                 --p;
90
91                 auto mb = std::mbstate_t();
92                 const std::size_t length = std::mbrlen(p, reference - p, &mb);
93                 if (length != std::size_t(-1))
94                         break;
95         }
96
97         return p;
98 }
99
100 const char *
101 AtCharMB(const char *s, size_t length, size_t i) noexcept
102 {
103         const char *const end = s + length;
104         auto state = std::mbstate_t();
105
106         while (i > 0) {
107                 wchar_t w;
108                 std::size_t n = std::mbrtowc(&w, s, end - s, &state);
109
110                 if (n == std::size_t(-2)) {
111                         s += strlen(s);
112                         break;
113                 }
114
115                 --i;
116
117                 if (n == std::size_t(-1) || n == 0)
118                         ++s;
119                 else
120                         s += n;
121         }
122
123         return s;
124 }
125
126 size_t
127 StringWidthMB(const char *s, size_t length) noexcept
128 {
129         const char *const end = s + length;
130         auto state = std::mbstate_t();
131
132         size_t width = 0;
133         while (s < end) {
134                 wchar_t w;
135                 std::size_t n = std::mbrtowc(&w, s, end - s, &state);
136                 if (n == std::size_t(-2))
137                         break;
138
139                 if (n == std::size_t(-1) || n == 0) {
140                         ++s;
141                 } else {
142                         s += n;
143                         int cw = wcwidth(w);
144                         if (cw > 0)
145                                 width += cw;
146                 }
147         }
148
149         return width;
150 }
151
152 size_t
153 StringWidthMB(const char *s) noexcept
154 {
155         return StringWidthMB(s, strlen(s));
156 }
157
158 const char *
159 AtWidthMB(const char *s, size_t length, size_t width) noexcept
160 {
161         const char *const end = s + length;
162         auto state = std::mbstate_t();
163
164         while (width > 0 && s < end) {
165                 wchar_t w;
166                 std::size_t n = std::mbrtowc(&w, s, end - s, &state);
167                 if (n == std::size_t(-2))
168                         break;
169
170                 if (n == std::size_t(-1) || n == 0) {
171                         --width;
172                         ++s;
173                 } else {
174                         int cw = wcwidth(w);
175                         if (cw > 0) {
176                                 if (size_t(cw) > width)
177                                         break;
178                                 width -= cw;
179                         }
180
181                         s += n;
182                 }
183         }
184
185         return s;
186 }