1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 wchar.c
12
13Abstract:
14
15 Implementation of wide char string functions.
16
17
18
19--*/
20
21
22#include "pal/palinternal.h"
23#include "pal/cruntime.h"
24#include "pal/dbgmsg.h"
25#include "pal/unicode_data.h"
26
27#include "pal/thread.hpp"
28#include "pal/threadsusp.hpp"
29
30
31#if HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#if HAVE_COREFOUNDATION
36#define CF_EXCLUDE_CSTD_HEADERS
37#include <CoreFoundation/CoreFoundation.h>
38#include <wctype.h>
39#else
40#include <wctype.h>
41#endif
42
43#include <errno.h>
44#include <algorithm>
45
46SET_DEFAULT_DEBUG_CHANNEL(CRT);
47
48
49/*--
50Function:
51 wtolower (internal)
52
5316-bit wide character version of the ANSI tolower() function.
54
55 --*/
56static
57wchar_16
58wtolower(wchar_16 c)
59{
60 /* Note: Surrogate pairs unicode character are not supported */
61
62#if HAVE_TOWLOWER
63
64 wchar_t w;
65 w = (wchar_t) c;
66 w = towlower(w);
67 return (wchar_16) w;
68
69#else
70
71 return PAL_towlower(c);
72
73#endif
74
75}
76
77/*--
78Function:
79 _wtoi
80
81See MSDN doc
82--*/
83int
84__cdecl
85_wtoi(
86 const wchar_16 *string)
87{
88 int len;
89 int ret;
90 char *tempStr;
91
92 PERF_ENTRY(_wtoi);
93 ENTRY("_wtoi (string=%p)\n", string);
94
95 len = WideCharToMultiByte(CP_ACP, 0, string, -1, 0, 0, 0, 0);
96 if (!len)
97 {
98 ASSERT("WideCharToMultiByte failed. Error is %d\n",
99 GetLastError());
100 return -1;
101 }
102 tempStr = (char *) PAL_malloc(len);
103 if (!tempStr)
104 {
105 ERROR("PAL_malloc failed\n");
106 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
107 return -1;
108 }
109 len = WideCharToMultiByte(CP_ACP, 0, string, -1, tempStr, len, 0, 0);
110 if (!len)
111 {
112 ASSERT("WideCharToMultiByte failed. Error is %d\n",
113 GetLastError());
114 PAL_free(tempStr);
115 return -1;
116 }
117 ret = atoi(tempStr);
118
119 PAL_free(tempStr);
120 LOGEXIT("_wtoi returns int %d\n", ret);
121 PERF_EXIT(_wtoi);
122 return ret;
123}
124
125
126/*--
127Function:
128 PAL_iswspace
129
130See MSDN doc
131--*/
132int
133__cdecl
134PAL_iswspace(wchar_16 c)
135{
136 int ret;
137
138 PERF_ENTRY(iswspace);
139 ENTRY("PAL_iswspace (c=%C)\n", c);
140
141 ret = iswspace(c);
142
143 LOGEXIT("PAL_iswspace returns int %d\n", ret);
144 PERF_EXIT(iswspace);
145 return ret;
146}
147
148/*++
149Function:
150 _wcsnicmp
151
152Compare characters of two strings without regard to case
153
154Return Value
155
156The return value indicates the relationship between the substrings as follows.
157
158Return Value
159
160Description
161
162< 0 string1 substring less than string2 substring
163 0 string1 substring identical to string2 substring
164> 0 string1 substring greater than string2 substring
165
166Parameters
167
168string1, string2 Null-terminated strings to compare
169count Number of characters to compare
170
171Remarks
172
173The _strnicmp function lexicographically compares, at most, the first
174count characters of string1 and string2. The comparison is performed
175without regard to case; _strnicmp is a case-insensitive version of
176strncmp. The comparison ends if a terminating null character is
177reached in either string before count characters are compared. If the
178strings are equal when a terminating null character is reached in
179either string before count characters are compared, the shorter string
180is lesser.
181
182--*/
183int
184__cdecl
185_wcsnicmp(
186 const wchar_16 *string1,
187 const wchar_16 *string2,
188 size_t count)
189{
190 size_t i;
191 int diff = 0;
192
193 PERF_ENTRY(_wcsnicmp);
194 ENTRY("_wcsnicmp (string1=%p (%S), string2=%p (%S), count=%lu)\n",
195 string1?string1:W16_NULLSTRING,
196 string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING,
197 (unsigned long) count);
198
199 for (i = 0; i < count; i++)
200 {
201 diff = wtolower(string1[i]) - wtolower(string2[i]);
202 if (diff != 0 || 0 == string1[i] || 0 == string2[i])
203 {
204 break;
205 }
206 }
207 LOGEXIT("_wcsnicmp returning int %d\n", diff);
208 PERF_EXIT(_wcsnicmp);
209 return diff;
210}
211
212/*++
213Function:
214 _wcsicmp
215
216Compare characters of two strings without regard to case
217
218Return Value
219
220The return value indicates the relationship between the substrings as follows.
221
222Return Value
223
224Description
225
226< 0 string1 substring less than string2 substring
227 0 string1 substring identical to string2 substring
228> 0 string1 substring greater than string2 substring
229
230Parameters
231
232string1, string2 Null-terminated strings to compare
233
234--*/
235int
236__cdecl
237_wcsicmp(
238 const wchar_16 *string1,
239 const wchar_16 *string2)
240{
241 int ret;
242
243 PERF_ENTRY(_wcsicmp);
244 ENTRY("_wcsicmp (string1=%p (%S), string2=%p (%S))\n",
245 string1?string1:W16_NULLSTRING,
246 string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING);
247
248 ret = _wcsnicmp(string1, string2, 0x7fffffff);
249
250 LOGEXIT("_wcsnicmp returns int %d\n", ret);
251 PERF_EXIT(_wcsicmp);
252 return ret;
253}
254
255
256/*++
257Function:
258 _wcslwr
259
260Convert a string to lowercase.
261
262Return Value
263
264Returns a pointer to the converted string. Because the modification is
265done in place, the pointer returned is the same as the pointer passed
266as the input argument. No return value is reserved to indicate an
267error.
268
269Parameter
270
271string Null-terminated string to convert to lowercase
272
273Remarks
274
275--*/
276wchar_16 *
277__cdecl
278_wcslwr(
279 wchar_16 *string)
280{
281 int i;
282
283 PERF_ENTRY(_wcslwr);
284 ENTRY("_wcslwr (string=%p (%S))\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
285
286 for (i=0 ; string[i] != 0; i++)
287 {
288 string[i] = wtolower(string[i]);
289 }
290
291 LOGEXIT("_wcslwr returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
292 PERF_EXIT(_wcslwr);
293 return string;
294}
295
296
297/*++
298Function:
299 PAL_wcstol
300
301Convert string to a long-integer value.
302
303Return Value
304
305wcstol returns the value represented in the string nptr, except when
306the representation would cause an overflow, in which case it returns
307LONG_MAX or LONG_MIN. strtol returns 0 if no conversion can be
308performed. errno is set to ERANGE if overflow or underflow occurs.
309
310Parameters
311
312nptr Null-terminated string to convert
313endptr Pointer to character that stops scan
314base Number base to use
315
316Remarks
317
318The wcstol function converts nptr to a long. It stops reading the
319string nptr at the first character it cannot recognize as part of a
320number. This may be the terminating null character, or it may be the
321first numeric character greater than or equal to base.
322
323Notes :
324 MSDN states that only space and tab are accepted as leading whitespace, but
325 tests indicate that other whitespace characters (newline, carriage return,
326 etc) are also accepted. This matches the behavior on Unix systems.
327
328 For wcstol and wcstoul, we need to check if the value to be returned
329 is outside the 32 bit range. If so, the returned value needs to be set
330 as appropriate, according to the MSDN pages for wcstol and wcstoul,
331 and in all instances errno must be set to ERANGE (The one exception
332 is converting a string representing a negative value to unsigned long).
333 Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
334 Windows behavior, we must return long's in the 32 bit range.
335--*/
336
337/* The use of LONG is by design, to ensure that a 32 bit value is always
338returned from this function. If "long" is used instead of LONG, then a 64 bit
339value could be returned on 64 bit platforms like HP-UX, thus breaking
340Windows behavior. */
341LONG
342__cdecl
343PAL_wcstol(
344 const wchar_16 *nptr,
345 wchar_16 **endptr,
346 int base)
347{
348 char *s_nptr = 0;
349 char *s_endptr = 0;
350 long res;
351 int size;
352 DWORD dwLastError = 0;
353
354 PERF_ENTRY(wcstol);
355 ENTRY("wcstol (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
356 endptr, base);
357
358 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
359 if (!size)
360 {
361 dwLastError = GetLastError();
362 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
363 SetLastError(ERROR_INVALID_PARAMETER);
364 res = 0;
365 goto PAL_wcstolExit;
366 }
367 s_nptr = (char *)PAL_malloc(size);
368 if (!s_nptr)
369 {
370 ERROR("PAL_malloc failed\n");
371 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
372 res = 0;
373 goto PAL_wcstolExit;
374 }
375 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
376 if( size==0 )
377 {
378 dwLastError = GetLastError();
379 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
380 SetLastError(ERROR_INVALID_PARAMETER);
381 res = 0;
382 goto PAL_wcstolExit;
383 }
384
385 res = strtol(s_nptr, &s_endptr, base);
386
387#ifdef BIT64
388 if (res > _I32_MAX)
389 {
390 res = _I32_MAX;
391 errno = ERANGE;
392 }
393 else if (res < _I32_MIN)
394 {
395 res = _I32_MIN;
396 errno = ERANGE;
397 }
398#endif
399
400 /* only ASCII characters will be accepted by strtol, and those always get
401 mapped to single-byte characters, so the first rejected character will
402 have the same index in the multibyte and widechar strings */
403 if( endptr )
404 {
405 size = s_endptr - s_nptr;
406 *endptr = (wchar_16 *)&nptr[size];
407 }
408
409PAL_wcstolExit:
410 PAL_free(s_nptr);
411 LOGEXIT("wcstol returning long %ld\n", res);
412 PERF_EXIT(wcstol);
413 /* This explicit cast to LONG is used to silence any potential warnings
414 due to implicitly casting the native long res to LONG when returning. */
415 return (LONG)res;
416}
417
418
419/*++
420Function:
421 PAL_wcstoul
422
423Convert string to an unsigned long-integer value.
424
425Return Value
426
427wcstoul returns the converted value, if any, or ULONG_MAX on
428overflow. It returns 0 if no conversion can be performed. errno is
429set to ERANGE if overflow or underflow occurs.
430
431Parameters
432
433nptr Null-terminated string to convert
434endptr Pointer to character that stops scan
435base Number base to use
436
437Remarks
438
439wcstoul stops reading the string nptr at the first character it cannot
440recognize as part of a number. This may be the terminating null
441character, or it may be the first numeric character greater than or
442equal to base. The LC_NUMERIC category setting of the current locale
443determines recognition of the radix character in nptr; for more
444information, see setlocale. If endptr is not NULL, a pointer to the
445character that stopped the scan is stored at the location pointed to
446by endptr. If no conversion can be performed (no valid digits were
447found or an invalid base was specified), the value of nptr is stored
448at the location pointed to by endptr.
449
450Notes :
451 MSDN states that only space and tab are accepted as leading whitespace, but
452 tests indicate that other whitespace characters (newline, carriage return,
453 etc) are also accepted. This matches the behavior on Unix systems.
454
455 For wcstol and wcstoul, we need to check if the value to be returned
456 is outside the 32 bit range. If so, the returned value needs to be set
457 as appropriate, according to the MSDN pages for wcstol and wcstoul,
458 and in all instances errno must be set to ERANGE (The one exception
459 is converting a string representing a negative value to unsigned long).
460 Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
461 Windows behavior, we must return long's in the 32 bit range.
462--*/
463
464/* The use of ULONG is by design, to ensure that a 32 bit value is always
465returned from this function. If "unsigned long" is used instead of ULONG,
466then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus
467breaking Windows behavior .*/
468ULONG
469__cdecl
470PAL_wcstoul(
471 const wchar_16 *nptr,
472 wchar_16 **endptr,
473 int base)
474{
475 char *s_nptr = 0;
476 char *s_endptr = 0;
477 unsigned long res;
478 int size;
479 DWORD dwLastError = 0;
480
481 PERF_ENTRY(wcstoul);
482 ENTRY("wcstoul (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
483 endptr, base);
484
485 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
486 if (!size)
487 {
488 dwLastError = GetLastError();
489 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
490 SetLastError(ERROR_INVALID_PARAMETER);
491 res = 0;
492 goto PAL_wcstoulExit;
493 }
494 s_nptr = (char *)PAL_malloc(size);
495 if (!s_nptr)
496 {
497 ERROR("PAL_malloc failed\n");
498 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
499 res = 0;
500 goto PAL_wcstoulExit;
501 }
502 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
503 if (!size)
504 {
505 dwLastError = GetLastError();
506 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
507 SetLastError(ERROR_INVALID_PARAMETER);
508 res = 0;
509 goto PAL_wcstoulExit;
510 }
511
512 res = strtoul(s_nptr, &s_endptr, base);
513
514#ifdef BIT64
515 if (res > _UI32_MAX)
516 {
517 wchar_16 wc = *nptr;
518 while (PAL_iswspace(wc))
519 {
520 wc = *nptr++;
521 }
522 /* If the string represents a positive number that is greater than
523 _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno
524 to match Windows behavior. */
525 if (wc != '-')
526 {
527 res = _UI32_MAX;
528 errno = ERANGE;
529 }
530 }
531#endif
532
533 /* only ASCII characters will be accepted by strtol, and those always get
534 mapped to single-byte characters, so the first rejected character will
535 have the same index in the multibyte and widechar strings */
536 if( endptr )
537 {
538 size = s_endptr - s_nptr;
539 *endptr = (wchar_16 *)&nptr[size];
540 }
541
542PAL_wcstoulExit:
543 PAL_free(s_nptr);
544 LOGEXIT("wcstoul returning unsigned long %lu\n", res);
545 PERF_EXIT(wcstoul);
546
547 /* When returning unsigned long res from this function, it will be
548 implicitly cast to ULONG. This handles situations where a string that
549 represents a negative number is passed in to wcstoul. The Windows
550 behavior is analogous to taking the binary equivalent of the negative
551 value and treating it as a positive number. Returning a ULONG from
552 this function, as opposed to native unsigned long, allows us to match
553 this behavior. The explicit case to ULONG below is used to silence any
554 potential warnings due to the implicit casting. */
555 return (ULONG)res;
556}
557
558ULONGLONG
559__cdecl
560PAL__wcstoui64(
561 const wchar_16 *nptr,
562 wchar_16 **endptr,
563 int base)
564{
565 char *s_nptr = 0;
566 char *s_endptr = 0;
567 unsigned long long res;
568 int size;
569 DWORD dwLastError = 0;
570
571 PERF_ENTRY(wcstoul);
572 ENTRY("_wcstoui64 (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
573 endptr, base);
574
575 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
576 if (!size)
577 {
578 dwLastError = GetLastError();
579 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
580 SetLastError(ERROR_INVALID_PARAMETER);
581 res = 0;
582 goto PAL__wcstoui64Exit;
583 }
584 s_nptr = (char *)PAL_malloc(size);
585 if (!s_nptr)
586 {
587 ERROR("PAL_malloc failed\n");
588 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
589 res = 0;
590 goto PAL__wcstoui64Exit;
591 }
592 size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
593 if (!size)
594 {
595 dwLastError = GetLastError();
596 ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
597 SetLastError(ERROR_INVALID_PARAMETER);
598 res = 0;
599 goto PAL__wcstoui64Exit;
600 }
601
602 res = strtoull(s_nptr, &s_endptr, base);
603
604 /* only ASCII characters will be accepted by strtoull, and those always get
605 mapped to single-byte characters, so the first rejected character will
606 have the same index in the multibyte and widechar strings */
607 if( endptr )
608 {
609 size = s_endptr - s_nptr;
610 *endptr = (wchar_16 *)&nptr[size];
611 }
612
613PAL__wcstoui64Exit:
614 PAL_free(s_nptr);
615 LOGEXIT("_wcstoui64 returning unsigned long long %llu\n", res);
616 PERF_EXIT(_wcstoui64);
617
618 return res;
619}
620
621/*++
622Function:
623 PAL_towlower
624
625See MSDN
626
627--*/
628wchar_16
629__cdecl
630PAL_towlower( wchar_16 c )
631{
632#if HAVE_COREFOUNDATION
633 PERF_ENTRY(towlower);
634 ENTRY("towlower (c=%d)\n", c);
635 if (!PAL_iswlower(c))
636 {
637 CFMutableStringRef cfString = CFStringCreateMutable(
638 kCFAllocatorDefault, 1);
639 if (cfString != NULL)
640 {
641 CFStringAppendCharacters(cfString, (const UniChar*)&c, 1);
642 CFStringLowercase(cfString, NULL);
643 c = CFStringGetCharacterAtIndex(cfString, 0);
644 CFRelease(cfString);
645 }
646 }
647 LOGEXIT("towlower returns int %d\n", c );
648 PERF_EXIT(towlower);
649 return c;
650#else /* HAVE_COREFOUNDATION */
651 UnicodeDataRec dataRec;
652
653 PERF_ENTRY(towlower);
654 ENTRY("towlower (c=%d)\n", c);
655
656 if (!GetUnicodeData(c, &dataRec))
657 {
658 TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
659 LOGEXIT("towlower returns int %d\n", c );
660 PERF_EXIT(towlower);
661 return c;
662 }
663
664 if ( (dataRec.C1_TYPE_FLAGS & C1_LOWER) || (dataRec.nOpposingCase == 0 ))
665 {
666 LOGEXIT("towlower returns int %d\n", c );
667 PERF_EXIT(towlower);
668 return c;
669 }
670 else
671 {
672 LOGEXIT("towlower returns int %d\n", dataRec.nOpposingCase );
673 PERF_EXIT(towlower);
674 return dataRec.nOpposingCase;
675 }
676#endif /* HAVE_COREFOUNDATION */
677}
678
679
680/*++
681Function:
682 PAL_towupper
683
684See MSDN
685
686--*/
687wchar_16
688__cdecl
689PAL_towupper( wchar_16 c )
690{
691#if HAVE_COREFOUNDATION
692 PERF_ENTRY(towupper);
693 ENTRY("towupper (c=%d)\n", c);
694 if (!PAL_iswupper(c))
695 {
696 CFMutableStringRef cfString = CFStringCreateMutable(
697 kCFAllocatorDefault, 1);
698 if (cfString != NULL)
699 {
700 CFStringAppendCharacters(cfString, (const UniChar*)&c, 1);
701 CFStringUppercase(cfString, NULL);
702 c = CFStringGetCharacterAtIndex(cfString, 0);
703 CFRelease(cfString);
704 }
705 }
706 LOGEXIT("towupper returns int %d\n", c );
707 PERF_EXIT(towupper);
708 return c;
709#else /* HAVE_COREFOUNDATION */
710 UnicodeDataRec dataRec;
711
712 PERF_ENTRY(towupper);
713 ENTRY("towupper (c=%d)\n", c);
714
715 if (!GetUnicodeData(c, &dataRec))
716 {
717 TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
718 LOGEXIT("towupper returns int %d\n", c );
719 PERF_EXIT(towupper);
720 return c;
721 }
722
723 if ( (dataRec.C1_TYPE_FLAGS & C1_UPPER) || (dataRec.nOpposingCase == 0 ))
724 {
725 LOGEXIT("towupper returns int %d\n", c );
726 PERF_EXIT(towupper);
727 return c;
728 }
729 else
730 {
731 LOGEXIT("towupper returns int %d\n", dataRec.nOpposingCase );
732 PERF_EXIT(towupper);
733 return dataRec.nOpposingCase;
734 }
735#endif /* HAVE_COREFOUNDATION */
736}
737
738/*++
739Function:
740 PAL_iswupper
741
742See MSDN
743
744--*/
745int
746__cdecl
747PAL_iswupper( wchar_16 c )
748{
749 BOOL bRetVal = FALSE;
750#if HAVE_COREFOUNDATION
751 static CFCharacterSetRef sUppercaseSet;
752
753 if (sUppercaseSet == NULL)
754 {
755 sUppercaseSet = CFCharacterSetGetPredefined(
756 kCFCharacterSetUppercaseLetter);
757 }
758 PERF_ENTRY(iswupper);
759 ENTRY( "iswupper (c=%d)\n", c );
760 bRetVal = CFCharacterSetIsCharacterMember(sUppercaseSet, c);
761#else /* HAVE_COREFOUNDATION */
762 UnicodeDataRec dataRec;
763
764 PERF_ENTRY(iswupper);
765 ENTRY( "iswupper (c=%d)\n", c );
766
767 if (!GetUnicodeData(c, &dataRec))
768 {
769 TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
770 goto exit;
771 }
772
773 if (dataRec.C1_TYPE_FLAGS & C1_UPPER)
774 {
775 bRetVal = TRUE;
776 }
777exit:
778#endif /* HAVE_COREFOUNDATION */
779 LOGEXIT( "iswupper returns %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
780 PERF_EXIT(iswupper);
781 return bRetVal;
782}
783
784/*++
785Function:
786 PAL_iswlower
787
788See MSDN
789
790--*/
791int
792__cdecl
793PAL_iswlower( wchar_16 c )
794{
795 BOOL bRetVal = FALSE;
796#if HAVE_COREFOUNDATION
797 static CFCharacterSetRef sLowercaseSet;
798
799 if (sLowercaseSet == NULL)
800 {
801 sLowercaseSet = CFCharacterSetGetPredefined(
802 kCFCharacterSetLowercaseLetter);
803 }
804 PERF_ENTRY(iswlower);
805 ENTRY("PAL_iswlower (c=%d)\n", c);
806 bRetVal = CFCharacterSetIsCharacterMember(sLowercaseSet, c);
807#else /* HAVE_COREFOUNDATION */
808 UnicodeDataRec dataRec;
809
810 PERF_ENTRY(iswlower);
811 ENTRY("PAL_iswlower (c=%d)\n", c);
812
813 if (!GetUnicodeData(c, &dataRec))
814 {
815 TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
816 goto exit;
817 }
818
819 if (dataRec.C1_TYPE_FLAGS & C1_LOWER)
820 {
821 bRetVal = TRUE;
822 }
823exit:
824#endif /* HAVE_COREFOUNDATION */
825 LOGEXIT("PAL_iswlower returns %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE");
826 PERF_EXIT(iswlower);
827 return bRetVal;
828}
829
830/*++
831Function:
832 PAL_iswalpha
833
834See MSDN
835
836--*/
837int
838__cdecl
839PAL_iswalpha( wchar_16 c )
840{
841 PERF_ENTRY(iswalpha);
842 ENTRY( "PAL_iswalpha (c=%d)\n", c);
843
844 if ( PAL_iswupper( c ) || PAL_iswlower( c ) )
845 {
846 LOGEXIT( "PAL_iswalpha returns 1.\n" );
847 PERF_EXIT(iswalpha);
848 return 1;
849 }
850
851 LOGEXIT( "PAL_iswalpha returns 0.\n" );
852 PERF_EXIT(iswalpha);
853 return 0;
854}
855
856
857/*++
858Function:
859 PAL_wcscat
860
861See MSDN or the man page for mcscat.
862
863--*/
864wchar_16 *
865__cdecl
866PAL_wcscat(
867 wchar_16 *strDestination,
868 const wchar_16 *strSource)
869{
870 wchar_16 *ret;
871 PERF_ENTRY(wcscat);
872 ENTRY("wcscat (strDestination=%p (%S), strSource=%p (%S))\n",
873 strDestination?strDestination:W16_NULLSTRING,
874 strDestination?strDestination:W16_NULLSTRING, strSource?strSource:W16_NULLSTRING, strSource?strSource:W16_NULLSTRING);
875
876 ret = PAL_wcsncat( strDestination, strSource, PAL_wcslen( strSource ) );
877
878 LOGEXIT("wcscat returnng wchar_t %p (%S)\n", ret, ret);
879 PERF_EXIT(wcscat);
880 return ret;
881}
882
883
884/*++
885Function:
886 PAL_wcscpy
887
888See MSDN or the man page for mcscpy.
889
890--*/
891wchar_16 *
892__cdecl
893PAL_wcscpy(
894 wchar_16 *strDestination,
895 const wchar_16 *strSource)
896{
897 wchar_16 *start = strDestination;
898
899 PERF_ENTRY(wcscpy);
900 ENTRY("wcscpy (strDestination=%p, strSource=%p (%S))\n",
901 strDestination, strSource ? strSource:W16_NULLSTRING, strSource ? strSource:W16_NULLSTRING);
902
903 if (strDestination == NULL)
904 {
905 ERROR("invalid strDestination argument\n");
906 LOGEXIT("wcscpy returning wchar_t NULL\n");
907 PERF_EXIT(wcscpy);
908 return NULL;
909 }
910
911 if (strSource == NULL)
912 {
913 ERROR("invalid strSource argument\n");
914 LOGEXIT("wcscpy returning wchar_t NULL\n");
915 PERF_EXIT(wcscpy);
916 return NULL;
917 }
918
919 /* copy source string to destination string */
920 while(*strSource)
921 {
922 *strDestination++ = *strSource++;
923 }
924
925 /* add terminating null */
926 *strDestination = '\0';
927
928 LOGEXIT("wcscpy returning wchar_t %p (%S)\n", start, start);
929 PERF_EXIT(wcscpy);
930 return start;
931}
932
933
934/*++
935Function:
936 PAL_wcslen
937
938See MSDN or the man page for wcslen.
939
940--*/
941size_t
942__cdecl
943PAL_wcslen(
944 const wchar_16 *string)
945{
946 size_t nChar = 0;
947
948 PERF_ENTRY(wcslen);
949 ENTRY("wcslen (string=%p (%S))\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
950
951 if ( !string )
952 {
953 LOGEXIT("wcslen returning size_t %u\n", 0);
954 PERF_EXIT(wcslen);
955 return 0;
956 }
957 while (*string++)
958 {
959 nChar++;
960 }
961
962 LOGEXIT("wcslen returning size_t %u\n", nChar);
963 PERF_EXIT(wcslen);
964 return nChar;
965}
966
967
968/*++
969Function:
970 PAL_wcsncmp
971
972See MSDN or the man page for wcsncmp.
973--*/
974int
975__cdecl
976PAL_wcsncmp(
977 const wchar_16 *string1,
978 const wchar_16 *string2,
979 size_t count)
980{
981 size_t i;
982 int diff = 0;
983
984 PERF_ENTRY(wcsncmp);
985 ENTRY("wcsncmp (string1=%p (%S), string2=%p (%S) count=%lu)\n",
986 string1?string1:W16_NULLSTRING,
987 string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING,
988 (unsigned long) count);
989
990 for (i = 0; i < count; i++)
991 {
992 diff = string1[i] - string2[i];
993 if (diff != 0)
994 {
995 break;
996 }
997
998 /* stop if we reach the end of the string */
999 if(string1[i]==0)
1000 {
1001 break;
1002 }
1003 }
1004 LOGEXIT("wcsncmp returning int %d\n", diff);
1005 PERF_EXIT(wcsncmp);
1006 return diff;
1007}
1008
1009/*++
1010Function:
1011 PAL_wcscmp
1012
1013See MSDN or the man page for wcscmp.
1014--*/
1015int
1016__cdecl
1017PAL_wcscmp(
1018 const wchar_16 *string1,
1019 const wchar_16 *string2)
1020{
1021 int ret;
1022
1023 PERF_ENTRY(wcscmp);
1024 ENTRY("wcscmp (string1=%p (%S), string2=%p (%S))\n",
1025 string1?string1:W16_NULLSTRING,
1026 string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING);
1027
1028 ret = PAL_wcsncmp(string1, string2, 0x7fffffff);
1029
1030 LOGEXIT("wcscmp returns int %d\n", ret);
1031 PERF_EXIT(wcscmp);
1032 return ret;
1033}
1034
1035/*++
1036Function:
1037 PAL_wcschr
1038
1039See MSDN or man page for wcschr.
1040
1041--*/
1042wchar_16 _WConst_return *
1043__cdecl
1044PAL_wcschr(
1045 const wchar_16 * string,
1046 wchar_16 c)
1047{
1048 PERF_ENTRY(wcschr);
1049 ENTRY("wcschr (string=%p (%S), c=%C)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING, c);
1050
1051 while (*string)
1052 {
1053 if (*string == c)
1054 {
1055 LOGEXIT("wcschr returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
1056 PERF_EXIT(wcschr);
1057 return (wchar_16 *) string;
1058 }
1059 string++;
1060 }
1061
1062 // Check if the comparand was \000
1063 if (*string == c)
1064 return (wchar_16 *) string;
1065
1066 LOGEXIT("wcschr returning wchar_t NULL\n");
1067 PERF_EXIT(wcschr);
1068 return NULL;
1069}
1070
1071
1072/*++
1073Function:
1074 PAL_wcsrchr
1075
1076See MSDN or man page for wcsrchr.
1077
1078--*/
1079wchar_16 _WConst_return *
1080__cdecl
1081PAL_wcsrchr(
1082 const wchar_16 * string,
1083 wchar_16 c)
1084{
1085 wchar_16 *last = NULL;
1086
1087 PERF_ENTRY(wcsrchr);
1088 ENTRY("wcsrchr (string=%p (%S), c=%C)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING, c);
1089
1090 while (*string)
1091 {
1092 if (*string == c)
1093 {
1094 last = (wchar_16 *) string;
1095 }
1096 string++;
1097 }
1098
1099 LOGEXIT("wcsrchr returning wchar_t %p (%S)\n", last?last:W16_NULLSTRING, last?last:W16_NULLSTRING);
1100 PERF_EXIT(wcsrchr);
1101 return (wchar_16 *)last;
1102}
1103
1104
1105/*++
1106Function:
1107 PAL_wcsspn
1108
1109See MSDN or man page for wcspbrk.
1110--*/
1111size_t
1112__cdecl
1113PAL_wcsspn (const wchar_16 *string, const wchar_16 *stringCharSet)
1114{
1115 ASSERT(0);
1116 return 0;
1117}
1118
1119
1120/*++
1121Function:
1122 PAL_wcspbrk
1123
1124See MSDN or man page for wcspbrk.
1125--*/
1126const wchar_16 *
1127__cdecl
1128PAL_wcspbrk(
1129 const wchar_16 *string,
1130 const wchar_16 *strCharSet)
1131{
1132 PERF_ENTRY(wcspbrk);
1133 ENTRY("wcspbrk (string=%p (%S), strCharSet=%p (%S))\n",
1134 string?string:W16_NULLSTRING,
1135 string?string:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING);
1136
1137 while (*string)
1138 {
1139 if (PAL_wcschr(strCharSet, *string) != NULL)
1140 {
1141 LOGEXIT("wcspbrk returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
1142 PERF_EXIT(wcspbrk);
1143 return (wchar_16 *) string;
1144 }
1145
1146 string++;
1147 }
1148
1149 LOGEXIT("wcspbrk returning wchar_t NULL\n");
1150 PERF_EXIT(wcspbrk);
1151 return NULL;
1152}
1153
1154
1155/*++
1156Function:
1157 PAL_wcsstr
1158
1159See MSDN or man page for wcsstr.
1160--*/
1161const wchar_16 *
1162__cdecl
1163PAL_wcsstr(
1164 const wchar_16 *string,
1165 const wchar_16 *strCharSet)
1166{
1167 wchar_16 *ret = NULL;
1168 int i;
1169
1170 PERF_ENTRY(wcsstr);
1171 ENTRY("wcsstr (string=%p (%S), strCharSet=%p (%S))\n",
1172 string?string:W16_NULLSTRING,
1173 string?string:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING);
1174
1175 if (string == NULL)
1176 {
1177 ret = NULL;
1178 goto leave;
1179 }
1180
1181 if (strCharSet == NULL)
1182 {
1183 ret = NULL;
1184 goto leave;
1185 }
1186
1187 if (*strCharSet == 0)
1188 {
1189 ret = (wchar_16 *)string;
1190 goto leave;
1191 }
1192
1193 while (*string != 0)
1194 {
1195 i = 0;
1196 while (1)
1197 {
1198 if (*(strCharSet + i) == 0)
1199 {
1200 ret = (wchar_16 *) string;
1201 goto leave;
1202 }
1203 else if (*(string + i) == 0)
1204 {
1205 ret = NULL;
1206 goto leave;
1207 }
1208 else if (*(string + i) != *(strCharSet + i))
1209 {
1210 break;
1211 }
1212
1213 i++;
1214 }
1215 string++;
1216 }
1217
1218 leave:
1219 LOGEXIT("wcsstr returning wchar_t %p (%S)\n", ret?ret:W16_NULLSTRING, ret?ret:W16_NULLSTRING);
1220 PERF_EXIT(wcsstr);
1221 return ret;
1222}
1223
1224/*++
1225Function :
1226
1227 PAL_wcsncpy
1228
1229see msdn doc.
1230--*/
1231wchar_16 *
1232__cdecl
1233PAL_wcsncpy( wchar_16 * strDest, const wchar_16 *strSource, size_t count )
1234{
1235 UINT length = sizeof( wchar_16 ) * count;
1236 PERF_ENTRY(wcsncpy);
1237 ENTRY("wcsncpy( strDest:%p, strSource:%p (%S), count:%lu)\n",
1238 strDest, strSource, strSource, (unsigned long) count);
1239
1240 memset( strDest, 0, length );
1241 length = std::min( count, PAL_wcslen( strSource ) ) * sizeof( wchar_16 );
1242 memcpy( strDest, strSource, length );
1243
1244 LOGEXIT("wcsncpy returning (wchar_16*): %p\n", strDest);
1245 PERF_EXIT(wcsncpy);
1246 return strDest;
1247}
1248
1249/*++
1250Function :
1251
1252 wcsncat
1253
1254see msdn doc.
1255--*/
1256wchar_16 *
1257__cdecl
1258PAL_wcsncat( wchar_16 * strDest, const wchar_16 *strSource, size_t count )
1259{
1260 wchar_16 *start = strDest;
1261 UINT LoopCount = 0;
1262 UINT StrSourceLength = 0;
1263
1264 PERF_ENTRY(wcsncat);
1265 ENTRY( "wcsncat (strDestination=%p (%S), strSource=%p (%S), count=%lu )\n",
1266 strDest ? strDest : W16_NULLSTRING,
1267 strDest ? strDest : W16_NULLSTRING,
1268 strSource ? strSource : W16_NULLSTRING,
1269 strSource ? strSource : W16_NULLSTRING, (unsigned long) count);
1270
1271 if ( strDest == NULL )
1272 {
1273 ERROR("invalid strDest argument\n");
1274 LOGEXIT("wcsncat returning wchar_t NULL\n");
1275 PERF_EXIT(wcsncat);
1276 return NULL;
1277 }
1278
1279 if ( strSource == NULL )
1280 {
1281 ERROR("invalid strSource argument\n");
1282 LOGEXIT("wcsncat returning wchar_t NULL\n");
1283 PERF_EXIT(wcsncat);
1284 return NULL;
1285 }
1286
1287 /* find end of source string */
1288 while ( *strDest )
1289 {
1290 strDest++;
1291 }
1292
1293 StrSourceLength = PAL_wcslen( strSource );
1294 if ( StrSourceLength < count )
1295 {
1296 count = StrSourceLength;
1297 }
1298
1299 /* concatenate new string */
1300 while( *strSource && LoopCount < count )
1301 {
1302 *strDest++ = *strSource++;
1303 LoopCount++;
1304 }
1305
1306 /* add terminating null */
1307 *strDest = '\0';
1308
1309 LOGEXIT("wcsncat returning wchar_t %p (%S)\n", start, start);
1310 PERF_EXIT(wcsncat);
1311 return start;
1312}
1313
1314static BOOL MISC_CRT_WCSTOD_IsValidCharacter( WCHAR c )
1315{
1316 if ( c == '+' || c == '-' || c == '.' || ( c >= '0' && c <= '9' ) ||
1317 c == 'e' || c == 'E' || c == 'd' || c == 'D' )
1318 {
1319 return TRUE;
1320 }
1321 return FALSE;
1322}
1323
1324/*++
1325Function :
1326
1327 wcstod
1328
1329 There is a slight difference between the Windows version of wcstod
1330 and the BSD versio of wcstod.
1331
1332 Under Windows the string " -1b " returns -1.000000 stop char = 'b'
1333 Under BSD the same string returns 0.000000 stop ' '
1334
1335see msdn doc.
1336--*/
1337double
1338__cdecl
1339PAL_wcstod( const wchar_16 * nptr, wchar_16 **endptr )
1340{
1341 double RetVal = 0.0;
1342 LPSTR lpStringRep = NULL;
1343 LPWSTR lpStartOfExpression = (LPWSTR)nptr;
1344 LPWSTR lpEndOfExpression = NULL;
1345 UINT Length = 0;
1346
1347 PERF_ENTRY(wcstod);
1348 ENTRY( "wcstod( %p (%S), %p (%S) )\n", nptr, nptr, endptr , endptr );
1349
1350 if ( !nptr )
1351 {
1352 ERROR( "nptr is invalid.\n" );
1353 LOGEXIT( "wcstod returning 0.0\n" );
1354 PERF_EXIT(wcstod);
1355 return 0.0;
1356 }
1357
1358 /* Eat white space. */
1359 while ( PAL_iswspace( *lpStartOfExpression ) )
1360 {
1361 lpStartOfExpression++;
1362 }
1363
1364 /* Get the end of the expression. */
1365 lpEndOfExpression = lpStartOfExpression;
1366 while ( *lpEndOfExpression )
1367 {
1368 if ( !MISC_CRT_WCSTOD_IsValidCharacter( *lpEndOfExpression ) )
1369 {
1370 break;
1371 }
1372 lpEndOfExpression++;
1373 }
1374
1375 if ( lpEndOfExpression != lpStartOfExpression )
1376 {
1377 Length = lpEndOfExpression - lpStartOfExpression;
1378 lpStringRep = (LPSTR)PAL_malloc( Length + 1);
1379
1380 if ( lpStringRep )
1381 {
1382 if ( WideCharToMultiByte( CP_ACP, 0, lpStartOfExpression, Length,
1383 lpStringRep, Length + 1 ,
1384 NULL, 0 ) != 0 )
1385 {
1386 LPSTR ScanStop = NULL;
1387 lpStringRep[Length]= 0;
1388 RetVal = strtod( lpStringRep, &ScanStop );
1389
1390 /* See if strtod failed. */
1391 if ( RetVal == 0.0 && ScanStop == lpStringRep )
1392 {
1393 ASSERT( "An error occurred in the conversion.\n" );
1394 lpEndOfExpression = (LPWSTR)nptr;
1395 }
1396 }
1397 else
1398 {
1399 ASSERT( "Wide char to multibyte conversion failed.\n" );
1400 lpEndOfExpression = (LPWSTR)nptr;
1401 }
1402 }
1403 else
1404 {
1405 ERROR( "Not enough memory.\n" );
1406 lpEndOfExpression = (LPWSTR)nptr;
1407 }
1408 }
1409 else
1410 {
1411 ERROR( "Malformed expression.\n" );
1412 lpEndOfExpression = (LPWSTR)nptr;
1413 }
1414
1415 /* Set the stop scan character. */
1416 if ( endptr != NULL )
1417 {
1418 *endptr = lpEndOfExpression;
1419 }
1420
1421 PAL_free( lpStringRep );
1422 LOGEXIT( "wcstod returning %f.\n", RetVal );
1423 PERF_EXIT(wcstod);
1424 return RetVal;
1425}
1426
1427/*++
1428Function:
1429
1430 iswdigit
1431
1432See MSDN for more details.
1433--*/
1434int
1435__cdecl
1436PAL_iswdigit( wchar_16 c )
1437{
1438 UINT nRetVal = 0;
1439#if HAVE_COREFOUNDATION
1440 static CFCharacterSetRef sDigitSet;
1441
1442 if (sDigitSet == NULL)
1443 {
1444 sDigitSet = CFCharacterSetGetPredefined(
1445 kCFCharacterSetDecimalDigit);
1446 }
1447 PERF_ENTRY(iswdigit);
1448 ENTRY("PAL_iswdigit (c=%d)\n", c);
1449 nRetVal = CFCharacterSetIsCharacterMember(sDigitSet, c);
1450#else /* HAVE_COREFOUNDATION */
1451 UnicodeDataRec dataRec;
1452
1453 PERF_ENTRY(iswdigit);
1454 ENTRY("PAL_iswdigit (c=%d)\n", c);
1455
1456 if (GetUnicodeData(c, &dataRec))
1457 {
1458 if (dataRec.C1_TYPE_FLAGS & C1_DIGIT)
1459 {
1460 nRetVal = 1;
1461 }
1462 else
1463 {
1464 nRetVal = 0;
1465 }
1466 }
1467 else
1468 {
1469 TRACE( "No corresonding unicode record for character %d.\n", c );
1470 }
1471#endif /* HAVE_COREFOUNDATION */
1472 LOGEXIT("PAL_iswdigit returning %d\n", nRetVal);
1473 PERF_EXIT(iswdigit);
1474 return nRetVal;
1475}
1476
1477/*++
1478Function:
1479
1480 iswxdigit
1481
1482See MSDN for more details.
1483
1484Notes :
1485the information in UnicodeData doesn't help us, it doesn't have enough
1486granularity. Results in windows show that only ASCII and "Fullwidth" (>0xFF10)
1487numbers and letters are considered as "hex"; other "numbers"
1488(nGeneralCategory==8) aren't.
1489--*/
1490int
1491__cdecl
1492PAL_iswxdigit( wchar_16 c )
1493{
1494 UINT nRetVal = 0;
1495
1496 PERF_ENTRY(iswxdigit);
1497 ENTRY("PAL_iswxdigit( c=%d )\n", c);
1498
1499 /* ASCII characters */
1500 if((c>= 'A' && c<='F') || /* uppercase hex letters */
1501 (c>= 'a' && c<='f') || /* lowercase hex letters */
1502 (c>= '0' && c<='9')) /* digits */
1503 {
1504 nRetVal = 1;
1505 }
1506 else
1507 /* "fullwidth" characters, whatever that is */
1508 if((c>= 0xFF10 && c<=0xFF19) || /* digits */
1509 (c>= 0xFF21 && c<=0xFF26) || /* uppercase hex letters */
1510 (c>= 0xFF41 && c<=0xFF46)) /* lowercase hex letters */
1511 {
1512 nRetVal = 1;
1513 }
1514 else
1515 {
1516 nRetVal = 0;
1517 }
1518 LOGEXIT("PAL_iswxdigit returning %d\n", nRetVal);
1519 PERF_EXIT(iswxdigit);
1520 return nRetVal;
1521}
1522
1523
1524/*++
1525Function:
1526
1527 iswprint
1528
1529See MSDN for more details.
1530--*/
1531int
1532__cdecl
1533PAL_iswprint( wchar_16 c )
1534{
1535 int ret;
1536
1537
1538 PERF_ENTRY(iswprint);
1539 ENTRY("PAL_iswprint (%#X)\n", c);
1540
1541 ret = iswprint(c);
1542
1543 LOGEXIT("PAL_iswprint returns %d\n", ret);
1544 PERF_EXIT(iswprint);
1545 return (ret);
1546}
1547
1548
1549/*++
1550Function:
1551 PAL_wcscspn
1552
1553Finds the number of consecutive characters from the start of the string
1554that are not in the set.
1555
1556Return value:
1557
1558The number of characters from the start of the string that are not in
1559the set.
1560
1561Parameters:
1562string String
1563strCharSet Set of delimiter characters
1564
1565--*/
1566size_t
1567__cdecl
1568PAL_wcscspn(const wchar_16 *string, const wchar_16 *strCharSet)
1569{
1570 const wchar_16 *temp;
1571 size_t count = 0;
1572
1573 PERF_ENTRY(wcscspn);
1574
1575 while(*string != 0)
1576 {
1577 for(temp = strCharSet; *temp != 0; temp++)
1578 {
1579 if (*string == *temp)
1580 {
1581 PERF_EXIT(wcscspn);
1582 return count;
1583 }
1584 }
1585 count++;
1586 string++;
1587 }
1588 PERF_EXIT(wcscspn);
1589 return count;
1590}
1591
1592#if HAVE_COREFOUNDATION
1593/*--
1594Function:
1595 PAL_iswblank
1596
1597Returns TRUE if c is a Win32 "blank" character.
1598--*/
1599int
1600__cdecl
1601PAL_iswblank(wchar_16 c)
1602{
1603 int ret;
1604 static CFCharacterSetRef sSpaceAndNewlineSet;
1605
1606 if (sSpaceAndNewlineSet == NULL)
1607 {
1608 sSpaceAndNewlineSet = CFCharacterSetGetPredefined(
1609 kCFCharacterSetWhitespaceAndNewline);
1610 }
1611 switch (c)
1612 {
1613 case 0x0085:
1614 case 0x1680:
1615 case 0x202f:
1616 case 0xfeff:
1617 // These are blank characters on Windows, but are not part
1618 // of the SpaceAndNewline character set in Core Foundation.
1619 ret = TRUE;
1620 break;
1621 case 0x2028:
1622 case 0x2029:
1623 // These are not blank characters on Windows, but are part
1624 // of the SpaceAndNewline character set in Core Foundation.
1625 ret = FALSE;
1626 break;
1627 default:
1628 ret = CFCharacterSetIsCharacterMember(sSpaceAndNewlineSet, c);
1629 break;
1630 }
1631 return ret;
1632}
1633
1634/*--
1635Function:
1636 PAL_iswcntrl
1637
1638Returns TRUE if c is a control character.
1639--*/
1640int
1641__cdecl
1642PAL_iswcntrl(wchar_16 c)
1643{
1644 int ret;
1645 static CFCharacterSetRef sControlSet;
1646
1647 if (sControlSet == NULL)
1648 {
1649 sControlSet = CFCharacterSetGetPredefined(kCFCharacterSetControl);
1650 }
1651 ret = CFCharacterSetIsCharacterMember(sControlSet, c);
1652 return ret;
1653}
1654
1655/*--
1656Function:
1657 PAL_iswpunct
1658
1659Returns TRUE if c is a punctuation character.
1660--*/
1661int
1662__cdecl
1663PAL_iswpunct(wchar_16 c)
1664{
1665 int ret;
1666 static CFCharacterSetRef sPunctuationSet = NULL;
1667 static CFCharacterSetRef sSymbolSet = NULL;
1668
1669 if (sPunctuationSet == NULL)
1670 {
1671 sPunctuationSet = CFCharacterSetGetPredefined(kCFCharacterSetPunctuation);
1672 }
1673 if (sSymbolSet == NULL)
1674 {
1675 sSymbolSet = CFCharacterSetGetPredefined(kCFCharacterSetSymbol);
1676 }
1677 ret = CFCharacterSetIsCharacterMember(sPunctuationSet, c) ||
1678 CFCharacterSetIsCharacterMember(sSymbolSet, c);
1679 return ret;
1680}
1681#endif // HAVE_COREFOUNDATION
1682