More portable CRTDLL_iswctype.
[wine] / dlls / crtdll / wcstring.c
1 /*
2  * CRTDLL wide-char functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  *
6  * TODO:
7  *   These functions are really necessary only if sizeof(WCHAR) != sizeof(wchar_t),
8  *   otherwise we could use the libc functions directly.
9  */
10
11 #include "config.h"
12
13 #include <ctype.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #ifdef HAVE_WCTYPE_H
17 #include <wctype.h>
18 #endif
19
20 #include "windef.h"
21 #include "crtdll.h"
22 #include "debugtools.h"
23
24 DEFAULT_DEBUG_CHANNEL(crtdll);
25
26 /*********************************************************************
27  *           CRTDLL__wcsdup    (CRTDLL.320)
28  */
29 LPWSTR __cdecl CRTDLL__wcsdup( LPCWSTR str )
30 {
31     LPWSTR ret = NULL;
32     if (str)
33     {
34         int size = (CRTDLL_wcslen(str) + 1) * sizeof(WCHAR);
35         ret = CRTDLL_malloc( size );
36         if (ret) memcpy( ret, str, size );
37     }
38     return ret;
39 }
40
41
42 /*********************************************************************
43  *           CRTDLL__wcsicmp    (CRTDLL.321)
44  */
45 INT __cdecl CRTDLL__wcsicmp( LPCWSTR str1, LPCWSTR str2 )
46 {
47     while (*str1 && (CRTDLL_towupper(*str1) == CRTDLL_towupper(*str2)))
48     {
49         str1++;
50         str2++;
51     }
52     return CRTDLL_towupper(*str1) - CRTDLL_towupper(*str2);
53 }
54
55
56 /*********************************************************************
57  *           CRTDLL__wcsicoll    (CRTDLL.322)
58  */
59 INT __cdecl CRTDLL__wcsicoll( LPCWSTR str1, LPCWSTR str2 )
60 {
61     /* FIXME: handle collates */
62     return CRTDLL__wcsicmp( str1, str2 );
63 }
64
65
66 /*********************************************************************
67  *           CRTDLL__wcslwr    (CRTDLL.323)
68  */
69 LPWSTR __cdecl CRTDLL__wcslwr( LPWSTR str )
70 {
71     LPWSTR ret = str;
72     for ( ; *str; str++) *str = CRTDLL_towlower(*str);
73     return ret;
74 }
75
76
77 /*********************************************************************
78  *           CRTDLL__wcsnicmp    (CRTDLL.324)
79  */
80 INT __cdecl CRTDLL__wcsnicmp( LPCWSTR str1, LPCWSTR str2, INT n )
81 {
82     if (!n) return 0;
83     while ((--n > 0) && *str1 && (CRTDLL_towupper(*str1) == CRTDLL_towupper(*str2)))
84     {
85         str1++;
86         str2++;
87     }
88     return CRTDLL_towupper(*str1) - CRTDLL_towupper(*str2);
89 }
90
91
92 /*********************************************************************
93  *           CRTDLL__wcsnset    (CRTDLL.325)
94  */
95 LPWSTR __cdecl CRTDLL__wcsnset( LPWSTR str, WCHAR c, INT n )
96 {
97     LPWSTR ret = str;
98     while ((n-- > 0) && *str) *str++ = c;
99     return ret;
100 }
101
102
103 /*********************************************************************
104  *           CRTDLL__wcsrev    (CRTDLL.326)
105  */
106 LPWSTR __cdecl CRTDLL__wcsrev( LPWSTR str )
107 {
108     LPWSTR ret = str;
109     LPWSTR end = str + CRTDLL_wcslen(str) - 1;
110     while (end > str)
111     {
112         WCHAR t = *end;
113         *end--  = *str;
114         *str++  = t;
115     }
116     return ret;
117 }
118
119
120 /*********************************************************************
121  *           CRTDLL__wcsset    (CRTDLL.327)
122  */
123 LPWSTR __cdecl CRTDLL__wcsset( LPWSTR str, WCHAR c )
124 {
125     LPWSTR ret = str;
126     while (*str) *str++ = c;
127     return ret;
128 }
129
130
131 /*********************************************************************
132  *           CRTDLL__wcsupr    (CRTDLL.328)
133  */
134 LPWSTR __cdecl CRTDLL__wcsupr( LPWSTR str )
135 {
136     LPWSTR ret = str;
137     for ( ; *str; str++) *str = CRTDLL_towupper(*str);
138     return ret;
139 }
140
141
142 /*********************************************************************
143  *           CRTDLL_towlower    (CRTDLL.493)
144  */
145 WCHAR __cdecl CRTDLL_towlower( WCHAR ch )
146 {
147 #ifdef HAVE_WCTYPE_H
148     ch = (WCHAR)towlower( (wchar_t)ch );
149 #else
150     if (!HIBYTE(ch)) ch = (WCHAR)tolower( LOBYTE(ch) );  /* FIXME */
151 #endif
152     return ch;
153 }
154
155
156 /*********************************************************************
157  *           CRTDLL_towupper    (CRTDLL.494)
158  */
159 WCHAR __cdecl CRTDLL_towupper( WCHAR ch )
160 {
161 #ifdef HAVE_WCTYPE_H
162     ch = (WCHAR)towupper( (wchar_t)ch );
163 #else
164     if (!HIBYTE(ch)) ch = (WCHAR)toupper( LOBYTE(ch) );  /* FIXME */
165 #endif
166     return ch;
167 }
168
169
170 /***********************************************************************
171  *           CRTDLL_wcscat    (CRTDLL.503)
172  */
173 LPWSTR __cdecl CRTDLL_wcscat( LPWSTR dst, LPCWSTR src )
174 {
175     LPWSTR p = dst;
176     while (*p) p++;
177     while ((*p++ = *src++));
178     return dst;
179 }
180
181
182 /*********************************************************************
183  *           CRTDLL_wcschr    (CRTDLL.504)
184  */
185 LPWSTR __cdecl CRTDLL_wcschr( LPCWSTR str, WCHAR ch )
186 {
187     while (*str)
188     {
189         if (*str == ch) return (LPWSTR)str;
190         str++;
191     }
192     return NULL;
193 }
194
195
196 /*********************************************************************
197  *           CRTDLL_wcscmp    (CRTDLL.505)
198  */
199 INT __cdecl CRTDLL_wcscmp( LPCWSTR str1, LPCWSTR str2 )
200 {
201     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
202     return (INT)(*str1 - *str2);
203 }
204
205
206 /*********************************************************************
207  *           CRTDLL_wcscoll    (CRTDLL.506)
208  */
209 DWORD __cdecl CRTDLL_wcscoll( LPCWSTR str1, LPCWSTR str2 )
210 {
211     /* FIXME: handle collates */
212     return CRTDLL_wcscmp( str1, str2 );
213 }
214
215
216 /***********************************************************************
217  *           CRTDLL_wcscpy    (CRTDLL.507)
218  */
219 LPWSTR __cdecl CRTDLL_wcscpy( LPWSTR dst, LPCWSTR src )
220 {
221     LPWSTR p = dst;
222     while ((*p++ = *src++));
223     return dst;
224 }
225
226
227 /*********************************************************************
228  *           CRTDLL_wcscspn    (CRTDLL.508)
229  */
230 INT __cdecl CRTDLL_wcscspn( LPCWSTR str, LPCWSTR reject )
231 {
232     LPCWSTR start = str;
233     while (*str)
234     {
235         LPCWSTR p = reject;
236         while (*p && (*p != *str)) p++;
237         if (*p) break;
238         str++;
239     }
240     return str - start;
241 }
242
243
244 /***********************************************************************
245  *           CRTDLL_wcslen    (CRTDLL.510)
246  */
247 INT __cdecl CRTDLL_wcslen( LPCWSTR str )
248 {
249     LPCWSTR s = str;
250     while (*s) s++;
251     return s - str;
252 }
253
254
255 /*********************************************************************
256  *           CRTDLL_wcsncat    (CRTDLL.511)
257  */
258 LPWSTR __cdecl CRTDLL_wcsncat( LPWSTR s1, LPCWSTR s2, INT n )
259 {
260     LPWSTR ret = s1;
261     while (*s1) s1++;
262     while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
263     *s1 = 0;
264     return ret;
265 }
266
267
268 /*********************************************************************
269  *           CRTDLL_wcsncmp    (CRTDLL.512)
270  */
271 INT __cdecl CRTDLL_wcsncmp( LPCWSTR str1, LPCWSTR str2, INT n )
272 {
273     if (!n) return 0;
274     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
275     return (INT)(*str1 - *str2);
276 }
277
278
279 /*********************************************************************
280  *           CRTDLL_wcsncpy    (CRTDLL.513)
281  */
282 LPWSTR __cdecl CRTDLL_wcsncpy( LPWSTR s1, LPCWSTR s2, INT n )
283 {
284     LPWSTR ret = s1;
285     while (n-- > 0) if (!(*s1++ = *s2++)) break;
286     while (n-- > 0) *s1++ = 0;
287     return ret;
288 }
289
290
291 /*********************************************************************
292  *           CRTDLL_wcspbrk    (CRTDLL.514)
293  */
294 LPWSTR __cdecl CRTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept )
295 {
296     LPCWSTR p;
297     while (*str)
298     {
299         for (p = accept; *p; p++) if (*p == *str) return (LPWSTR)str;
300         str++;
301     }
302     return NULL;
303 }
304
305
306 /*********************************************************************
307  *           CRTDLL_wcsrchr    (CRTDLL.515)
308  */
309 LPWSTR __cdecl CRTDLL_wcsrchr( LPWSTR str, WCHAR ch )
310 {
311     LPWSTR last = NULL;
312     while (*str)
313     {
314         if (*str == ch) last = str;
315         str++;
316     }
317     return last;
318 }
319
320
321 /*********************************************************************
322  *           CRTDLL_wcsspn    (CRTDLL.516)
323  */
324 INT __cdecl CRTDLL_wcsspn( LPCWSTR str, LPCWSTR accept )
325 {
326     LPCWSTR start = str;
327     while (*str)
328     {
329         LPCWSTR p = accept;
330         while (*p && (*p != *str)) p++;
331         if (!*p) break;
332         str++;
333     }
334     return str - start;
335 }
336
337
338 /*********************************************************************
339  *           CRTDLL_wcsstr    (CRTDLL.517)
340  */
341 LPWSTR __cdecl CRTDLL_wcsstr( LPCWSTR str, LPCWSTR sub )
342 {
343     while (*str)
344     {
345         LPCWSTR p1 = str, p2 = sub;
346         while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
347         if (!*p2) return (LPWSTR)str;
348         str++;
349     }
350     return NULL;
351 }
352
353
354 /*********************************************************************
355  *           CRTDLL_wcstok    (CRTDLL.519)
356  */
357 LPWSTR __cdecl CRTDLL_wcstok( LPWSTR str, LPCWSTR delim )
358 {
359     static LPWSTR next = NULL;
360     LPWSTR ret;
361
362     if (!str)
363         if (!(str = next)) return NULL;
364
365     while (*str && CRTDLL_wcschr( delim, *str )) str++;
366     if (!*str) return NULL;
367     ret = str++;
368     while (*str && !CRTDLL_wcschr( delim, *str )) str++;
369     if (*str) *str++ = 0;
370     next = str;
371     return ret;
372 }
373
374
375 /*********************************************************************
376  *           CRTDLL_wcstombs    (CRTDLL.521)
377  *
378  * FIXME: the reason I do not use wcstombs is that it seems to fail
379  *        for any latin-1 valid character. Not good.
380  */
381 INT __cdecl CRTDLL_wcstombs( LPSTR dst, LPCWSTR src, INT n )
382 {
383     int copied=0;
384     while ((n>0) && *src) {
385         int ret;
386         /* FIXME: could potentially overflow if we ever have MB of 2 bytes*/
387         ret = wctomb(dst,(wchar_t)*src);
388         if (ret<0) {
389             /* FIXME: sadly, some versions of glibc do not like latin characters
390              * as UNICODE chars for some reason (like german umlauts). Just
391              * copy those anyway. MM 991106
392              */
393             *dst=*src;
394             ret = 1;
395         }
396         dst     += ret;
397         n       -= ret;
398         copied  += ret;
399         src++;
400     }
401     return copied;
402 }
403
404 /*********************************************************************
405  *           CRTDLL_wctomb    (CRTDLL.524)
406  */
407 INT __cdecl CRTDLL_wctomb( LPSTR dst, WCHAR ch )
408 {
409     return wctomb( dst, (wchar_t)ch );
410 }
411
412 /*********************************************************************
413  *           CRTDLL_iswalnum    (CRTDLL.405)
414  */
415 int CRTDLL_iswalnum( WCHAR wc )
416 {
417 #ifdef HAVE_WCTYPE_H
418 #undef iswalnum
419     return iswalnum(wc);
420 #else
421     return isalnum( LOBYTE(wc) );  /* FIXME */
422 #endif
423 }
424
425 /*********************************************************************
426  *           CRTDLL_iswalpha    (CRTDLL.406)
427  */
428 int CRTDLL_iswalpha( WCHAR wc )
429 {
430 #ifdef HAVE_WCTYPE_H
431 #undef iswalpha
432     return iswalpha(wc);
433 #else
434     return isalpha( LOBYTE(wc) );  /* FIXME */
435 #endif
436 }
437
438 /*********************************************************************
439  *           CRTDLL_iswcntrl    (CRTDLL.408)
440  */
441 int CRTDLL_iswcntrl( WCHAR wc )
442 {
443 #ifdef HAVE_WCTYPE_H
444 #undef iswcntrl
445     return iswcntrl(wc);
446 #else
447     return iscntrl( LOBYTE(wc) );  /* FIXME */
448 #endif
449 }
450
451 /*********************************************************************
452  *           CRTDLL_iswdigit    (CRTDLL.410)
453  */
454 int CRTDLL_iswdigit( WCHAR wc )
455 {
456 #ifdef HAVE_WCTYPE_H
457 #undef iswdigit
458     return iswdigit(wc);
459 #else
460     return isdigit( LOBYTE(wc) );  /* FIXME */
461 #endif
462 }
463
464 /*********************************************************************
465  *           CRTDLL_iswgraph    (CRTDLL.411)
466  */
467 int CRTDLL_iswgraph( WCHAR wc )
468 {
469 #ifdef HAVE_WCTYPE_H
470 #undef iswgraph
471     return iswgraph(wc);
472 #else
473     return isgraph( LOBYTE(wc) );  /* FIXME */
474 #endif
475 }
476
477 /*********************************************************************
478  *           CRTDLL_iswlower    (CRTDLL.412)
479  */
480 int CRTDLL_iswlower( WCHAR wc )
481 {
482 #ifdef HAVE_WCTYPE_H
483 #undef iswlower
484     return iswlower(wc);
485 #else
486     return islower( LOBYTE(wc) );  /* FIXME */
487 #endif
488 }
489
490 /*********************************************************************
491  *           CRTDLL_iswprint    (CRTDLL.413)
492  */
493 int CRTDLL_iswprint( WCHAR wc )
494 {
495 #ifdef HAVE_WCTYPE_H
496 #undef iswprint
497     return iswprint(wc);
498 #else
499     return isprint( LOBYTE(wc) );  /* FIXME */
500 #endif
501 }
502
503 /*********************************************************************
504  *           CRTDLL_iswpunct    (CRTDLL.414)
505  */
506 int CRTDLL_iswpunct( WCHAR wc )
507 {
508 #ifdef HAVE_WCTYPE_H
509 #undef iswpunct
510     return iswpunct(wc);
511 #else
512     return ispunct( LOBYTE(wc) );  /* FIXME */
513 #endif
514 }
515
516 /*********************************************************************
517  *           CRTDLL_iswspace    (CRTDLL.415)
518  */
519 int CRTDLL_iswspace( WCHAR wc )
520 {
521 #ifdef HAVE_WCTYPE_H
522 #undef iswspace
523     return iswspace(wc);
524 #else
525     return isspace( LOBYTE(wc) );  /* FIXME */
526 #endif
527 }
528
529 /*********************************************************************
530  *           CRTDLL_iswupper    (CRTDLL.416)
531  */
532 int CRTDLL_iswupper( WCHAR wc )
533 {
534 #ifdef HAVE_WCTYPE_H
535 #undef iswupper
536     return iswupper(wc);
537 #else
538     return isupper( LOBYTE(wc) );  /* FIXME */
539 #endif
540 }
541
542 /*********************************************************************
543  *           CRTDLL_iswxdigit    (CRTDLL.417)
544  */
545 int CRTDLL_iswxdigit( WCHAR wc )
546 {
547 #ifdef HAVE_WCTYPE_H
548 #undef iswxdigit
549     return iswxdigit(wc);
550 #else
551     return isxdigit( LOBYTE(wc) );  /* FIXME */
552 #endif
553 }
554
555 /*********************************************************************
556  *           CRTDLL_iswctype    (CRTDLL.409)
557  */
558 int CRTDLL_iswctype( WCHAR wc, WCHAR wct )
559 {
560     int res = 0;
561
562     if (wct & 0x0001) res |= CRTDLL_iswupper(wc);
563     if (wct & 0x0002) res |= CRTDLL_iswlower(wc);
564     if (wct & 0x0004) res |= CRTDLL_iswdigit(wc);
565     if (wct & 0x0008) res |= CRTDLL_iswspace(wc);
566     if (wct & 0x0010) res |= CRTDLL_iswpunct(wc);
567     if (wct & 0x0020) res |= CRTDLL_iswcntrl(wc);
568     if (wct & 0x0080) res |= CRTDLL_iswxdigit(wc);
569     if (wct & 0x0100) res |= CRTDLL_iswalpha(wc);
570     if (wct & 0x0040)
571         FIXME(": iswctype(%04hx,_BLANK|...) requested\n",wc);
572     if (wct & 0x8000)
573         FIXME(": iswctype(%04hx,_LEADBYTE|...) requested\n",wc);
574     return res;
575 }