1 #include <string.h>
2 #include <wchar.h>
3 #include <wctype.h>
4 #include <assert.h>
5 
6 // Returns 1 if 'wc' is in the 'delim' string, 0 otherwise.
_wc_indelim(wchar_t wc,const wchar_t * delim)7 static int _wc_indelim(wchar_t wc, const wchar_t* delim) {
8     while (*delim) {
9         if (wc == *delim)
10             return 1;
11         delim++;
12     }
13     return 0;
14 }
15 
wcpcpy(wchar_t * to,const wchar_t * from)16 wchar_t *wcpcpy(wchar_t *to, const wchar_t *from) {
17     size_t n = 0;
18     for (;;) {
19         wchar_t wc = from[n];
20         to[n] = wc;
21         if (wc == L'\0')
22             break;
23         n++;
24     }
25     return to + n;
26 }
27 
wcpncpy(wchar_t * dst,const wchar_t * src,size_t n)28 wchar_t *wcpncpy(wchar_t *dst, const wchar_t *src, size_t n) {
29     size_t i;
30     for (i = 0; i < n; ++i) {
31         wchar_t wc = src[i];
32         dst[i] = wc;
33         if (wc == L'\0')
34             break;
35     }
36     while (i < n) {
37         dst[i] = L'\0';
38         ++i;
39     }
40     return &dst[n-1];
41 }
42 
wcscasecmp(const wchar_t * s1,const wchar_t * s2)43 int wcscasecmp(const wchar_t *s1, const wchar_t *s2) {
44     size_t n = 0;
45     for (;;) {
46         wchar_t wc1 = towlower(s1[n]);
47         wchar_t wc2 = towlower(s2[n]);
48         if (wc1 != wc2)
49             return (wc1 > wc2) ? +1 : -1;
50         if (wc1 == L'\0')
51             return 0;
52         n++;
53     }
54 }
55 
wcscat(wchar_t * s1,const wchar_t * s2)56 wchar_t *wcscat(wchar_t *s1, const wchar_t *s2) {
57     size_t n = 0;
58     while (s1[n] != L'\0')
59         n++;
60 
61     size_t i = 0;
62     for (;;) {
63         wchar_t wc = s2[i];
64         s1[n+i] = wc;
65         if (wc == L'\0')
66             break;
67         i++;
68     }
69     return s1;
70 }
71 
wcslcat(wchar_t * dst,const wchar_t * src,size_t siz)72 size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t siz) {
73     // Sanity check simplifies code below
74     if (siz == 0)
75         return 0;
76 
77     // Skip dst characters.
78     size_t n = 0;
79     while (n < siz && dst[n] != L'\0')
80       n++;
81 
82     if (n == siz)
83       return n + wcslen(src);
84 
85     // Copy as much source characters as they fit into siz-1 bytes.
86     size_t i;
87     for (i = 0; n+i+1 < siz && src[i] != L'\0'; ++i)
88         dst[n+i] = src[i];
89 
90     // Always zero terminate destination
91     dst[n+i] = L'\0';
92 
93     // Skip remaining source characters
94     while (src[i] != L'\0')
95         i++;
96 
97     return n+i;
98 }
99 
wcslcpy(wchar_t * dst,const wchar_t * src,size_t siz)100 size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz) {
101     size_t i;
102 
103     // Copy all non-zero bytes that fit into siz-1 destination bytes
104     for (i = 0; i + 1 < siz && src[i] != L'\0'; ++i)
105         dst[i] = src[i];
106 
107     // Always zero-terminate destination buffer
108     dst[i] = L'\0';
109 
110     // Skip other source characters.
111     while (src[i] != L'\0')
112         ++i;
113 
114     return i;
115 }
116 
wcslen(const wchar_t * s)117 size_t wcslen(const wchar_t *s) {
118     size_t n = 0;
119     for (;;) {
120         wchar_t wc = s[n];
121         if (wc == L'\0')
122             return n;
123         n++;
124     }
125 }
126 
wcsncasecmp(const wchar_t * s1,const wchar_t * s2,size_t n)127 int wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
128     size_t i;
129     for (i = 0; i < n; ++i) {
130         wchar_t wc1 = towlower(s1[i]);
131         wchar_t wc2 = towlower(s2[i]);
132         if (wc1 != wc2)
133             return (wc1 > wc2) ? +1 : -1;
134     }
135     return 0;
136 }
137 
wcsncat(wchar_t * s1,const wchar_t * s2,size_t n)138 wchar_t *wcsncat(wchar_t *s1, const wchar_t *s2, size_t n) {
139     size_t start = 0;
140     while (s1[start] != L'\0')
141         start++;
142 
143     // Append s2.
144     size_t i;
145     for (i = 0; i < n; ++i) {
146         wchar_t wc = s2[i];
147         s1[start + i] = wc;
148         if (wc == L'\0')
149             break;
150     }
151     return (wchar_t*)s1;
152 }
153 
wcsncmp(const wchar_t * s1,const wchar_t * s2,size_t n)154 int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
155     size_t i;
156     for (i = 0; i < n; ++i) {
157         wchar_t wc = s1[i];
158         if (wc != s2[i])
159             return (wc > s2[i]) ? +1 : -1;
160         if (wc == L'\0')
161             break;
162     }
163     return 0;
164 }
165 
wcsncpy(wchar_t * dst,const wchar_t * src,size_t n)166 wchar_t *wcsncpy(wchar_t *dst, const wchar_t *src, size_t n) {
167     // Copy initial characters.
168     size_t i;
169     for (i = 0; i < n; ++i) {
170         wchar_t wc = src[i];
171         if (wc == L'\0')
172             break;
173         dst[i] = wc;
174     }
175     // zero-pad the remainder.
176     for ( ; i < n; ++i)
177         dst[i] = L'\0';
178 
179     return dst;
180 }
181 
wcsnlen(const wchar_t * s,size_t maxlen)182 size_t wcsnlen(const wchar_t *s, size_t maxlen) {
183     size_t n;
184     for (n = 0; n < maxlen; ++n) {
185         if (s[n] == L'\0')
186             break;
187     }
188     return n;
189 }
190 
wcspbrk(const wchar_t * s,const wchar_t * set)191 wchar_t *wcspbrk(const wchar_t *s, const wchar_t *set) {
192     size_t n = 0;
193     for (;;) {
194         wchar_t wc = s[n];
195         if (!wc)
196             return NULL;
197         if (_wc_indelim(wc, set))
198             return (wchar_t*)&s[n];
199         n++;
200     }
201 }
202 
wcschr(const wchar_t * s,wchar_t c)203 wchar_t *wcschr(const wchar_t *s, wchar_t c) {
204   size_t n = 0;
205   for (;;) {
206     wchar_t wc = s[n];
207     if (wc == c)
208       return (wchar_t*)s + n;
209     if (wc == L'\0')
210       return NULL;
211     n++;
212   }
213 }
214 
wcsrchr(const wchar_t * s,wchar_t c)215 wchar_t *wcsrchr(const wchar_t *s, wchar_t c) {
216     size_t n = 0;
217     wchar_t* last = NULL;
218     for (;;) {
219         wchar_t wc = s[n];
220         if (wc == c)
221             last = (wchar_t*)s + n;
222         if (wc == L'\0')
223             break;
224         n++;
225     }
226     return last;
227 }
228 
wcsspn(const wchar_t * s,const wchar_t * set)229 size_t wcsspn(const wchar_t *s, const wchar_t *set) {
230     size_t n = 0;
231     for (;;) {
232         wchar_t wc = s[n];
233         if (wc == L'\0')
234             break;
235         if (!_wc_indelim(wc, set))
236             break;
237         ++n;
238     }
239     return n;
240 }
241 
wcsstr(const wchar_t * s,const wchar_t * find)242 wchar_t *wcsstr(const wchar_t *s, const wchar_t *find) {
243     wchar_t find_c;
244 
245     // Always find the empty string
246     find_c = *find++;
247     if (!find_c)
248         return (wchar_t*)s;
249 
250     size_t find_len = wcslen(find);
251 
252     for (;;) {
253         wchar_t* p = wcschr(s, find_c);
254         if (p == NULL)
255             return NULL;
256 
257         if (!wmemcmp(p, find, find_len))
258             return p;
259 
260         s = p + 1;
261     }
262     return NULL;
263 }
264 
wcstok(wchar_t * s,const wchar_t * delim,wchar_t ** last)265 wchar_t *wcstok(wchar_t *s, const wchar_t *delim, wchar_t **last) {
266     if (s == NULL) {
267         s = *last;
268         if (s == NULL)
269             return NULL;
270     }
271 
272     // Skip leading delimiters first.
273     size_t i = 0;
274     wchar_t wc;
275     for (;;) {
276         wc = s[i];
277         if (wc && _wc_indelim(wc, delim)) {
278             i++;
279             continue;
280         }
281         break;
282     }
283 
284     if (!wc) {
285         // Nothing left.
286         *last = NULL;
287         return NULL;
288     }
289 
290     size_t tok_start = i;
291 
292     // Skip non delimiters now.
293     for (;;) {
294         wc = s[i];
295         if (wc && !_wc_indelim(wc, delim)) {
296             i++;
297             continue;
298         }
299         break;
300     }
301 
302     if (!wc) {
303         *last = NULL;
304     } else {
305         s[i] = L'\0';
306         *last = &s[i+1];
307     }
308     return &s[tok_start];
309 }
310 
wmemchr(const wchar_t * s,wchar_t c,size_t n)311 wchar_t * wmemchr(const wchar_t *s, wchar_t c, size_t n) {
312     size_t i;
313     for (i = 0; i < n; ++i) {
314         if (s[i] == c)
315             return (wchar_t*)&s[i];
316     }
317     return NULL;
318 }
319 
wmemcmp(const wchar_t * s1,const wchar_t * s2,size_t n)320 int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n) {
321     size_t i;
322     for (i = 0; i < n; ++i) {
323         if (s1[i] == s2[i])
324             continue;
325         if (s1[i] > s2[i])
326             return 1;
327         else
328             return -1;
329     }
330     return 0;
331 }
332 
wmemcpy(wchar_t * d,const wchar_t * s,size_t n)333 wchar_t * wmemcpy(wchar_t *d, const wchar_t *s, size_t n) {
334     return (wchar_t *)memcpy((char*)d,
335                              (const char*)s,
336                              n * sizeof(wchar_t));
337 }
338 
wmemmove(wchar_t * d,const wchar_t * s,size_t n)339 wchar_t* wmemmove(wchar_t* d, const wchar_t* s, size_t n) {
340     return (wchar_t* )memmove((char*)d,
341                               (const char*)s,
342                               n * sizeof(wchar_t));
343 }
344 
wmemset(wchar_t * s,wchar_t c,size_t n)345 wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n) {
346     size_t i;
347     for (i = 0; i < n; ++i)
348         s[i] = c;
349     return s;
350 }
351