xref: /reactos/sdk/lib/ucrt/string/strxfrm.cpp (revision b09b5584)
1 /***
2 *strxfrm.c - Transform a string using locale information
3 *
4 *       Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *       Transform a string using the locale information as set by
8 *       LC_COLLATE.
9 *
10 *******************************************************************************/
11 #include <corecrt_internal.h>
12 #include <ctype.h>
13 #include <locale.h>
14 #include <string.h>
15 
16 /***
17 *size_t strxfrm() - Transform a string using locale information
18 *
19 *Purpose:
20 *       Transform the string pointed to by _string2 and place the
21 *       resulting string into the array pointed to by _string1.
22 *       No more than _count characters are place into the
23 *       resulting string (including the null).
24 *
25 *       The transformation is such that if strcmp() is applied to
26 *       the two transformed strings, the return value is equal to
27 *       the result of strcoll() applied to the two original strings.
28 *       Thus, the conversion must take the locale LC_COLLATE info
29 *       into account.
30 *       [ANSI]
31 *
32 *       The value of the following expression is the size of the array
33 *       needed to hold the transformation of the source string:
34 *
35 *           1 + strxfrm(nullptr,string,0)
36 *
37 *Entry:
38 *       char *_string1       = result string
39 *       const char *_string2 = source string
40 *       size_t _count        = max chars to move
41 *
42 *       [If _count is 0, _string1 is permitted to be nullptr.]
43 *
44 *Exit:
45 *       Length of the transformed string (not including the terminating
46 *       null).  If the value returned is >= _count, the contents of the
47 *       _string1 array are indeterminate.
48 *
49 *Exceptions:
50 *       Non-standard: if OM/API error, return INT_MAX.
51 *       Input parameters are validated. Refer to the validation section of the function.
52 *
53 *******************************************************************************/
54 
55 extern "C" size_t __cdecl _strxfrm_l (
56         char *_string1,
57         const char *_string2,
58         size_t _count,
59         _locale_t plocinfo
60         )
61 {
62     int dstlen;
63     size_t retval = INT_MAX;   /* NON-ANSI: default if OM or API error */
64     _LocaleUpdate _loc_update(plocinfo);
65 
66     /* validation section */
67     _VALIDATE_RETURN(_count <= INT_MAX, EINVAL, INT_MAX);
68     _VALIDATE_RETURN(_string1 != nullptr || _count == 0, EINVAL, INT_MAX);
69     _VALIDATE_RETURN(_string2 != nullptr, EINVAL, INT_MAX);
70 
71     /* pre-init output in case of error */
72     if(_string1!=nullptr && _count>0)
73     {
74         *_string1='\0';
75     }
76 
77     if ( (_loc_update.GetLocaleT()->locinfo->locale_name[LC_COLLATE] == nullptr) &&
78             (_loc_update.GetLocaleT()->locinfo->lc_collate_cp == CP_ACP) )
79     {
80 _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
81         strncpy(_string1, _string2, _count);
82 _END_SECURE_CRT_DEPRECATION_DISABLE
83         return strlen(_string2);
84     }
85 
86     /* Inquire size of dst string in BYTES */
87     if ( 0 == (dstlen = __acrt_LCMapStringA(
88                     _loc_update.GetLocaleT(),
89                     _loc_update.GetLocaleT()->locinfo->locale_name[LC_COLLATE],
90                     LCMAP_SORTKEY,
91                     _string2,
92                     -1,
93                     nullptr,
94                     0,
95                     _loc_update.GetLocaleT()->locinfo->lc_collate_cp,
96                     TRUE )) )
97     {
98         errno = EILSEQ;
99         return INT_MAX;
100     }
101 
102     retval = (size_t)dstlen;
103 
104     /* if not enough room, return amount needed */
105     if ( retval > _count )
106     {
107         if (_string1 != nullptr && _count > 0)
108         {
109             *_string1 = '\0';
110             errno = ERANGE;
111         }
112         /* the return value is the string length (without the terminating 0) */
113         retval--;
114         return retval;
115     }
116 
117     /* Map src string to dst string */
118     if ( 0 == __acrt_LCMapStringA(
119                 _loc_update.GetLocaleT(),
120                 _loc_update.GetLocaleT()->locinfo->locale_name[LC_COLLATE],
121                 LCMAP_SORTKEY,
122                 _string2,
123                 -1,
124                 _string1,
125                 (int)_count,
126                 _loc_update.GetLocaleT()->locinfo->lc_collate_cp,
127                 TRUE ) )
128     {
129         errno = EILSEQ;
130         return INT_MAX;
131     }
132     /* the return value is the string length (without the terminating 0) */
133     retval--;
134 
135     return retval;
136 }
137 
138 extern "C" size_t __cdecl strxfrm (
139         char *_string1,
140         const char *_string2,
141         size_t _count
142         )
143 {
144 
145     return _strxfrm_l(_string1, _string2, _count, nullptr);
146 
147 }
148