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 string.cpp
12
13Abstract:
14
15 Implementation of the string functions in the C runtime library that are Windows specific.
16
17
18
19--*/
20
21#include "pal/palinternal.h"
22#include "pal/dbgmsg.h"
23#include "pal/cruntime.h"
24
25#include <string.h>
26#include <ctype.h>
27#include <pthread.h>
28#include <errno.h>
29#include <limits.h>
30#include <unistd.h>
31
32
33SET_DEFAULT_DEBUG_CHANNEL(CRT);
34
35/*++
36Function:
37 _strnicmp
38
39compare at most count characters from two strings, ignoring case
40
41The strnicmp() function compares, with case insensitivity, at most count
42characters from s1 to s2. All uppercase characters from s1 and s2 are
43mapped to lowercase for the purposes of doing the comparison.
44
45Returns:
46
47Value Meaning
48
49< 0 s1 is less than s2
500 s1 is equal to s2
51> 0 s1 is greater than s2
52
53--*/
54int
55__cdecl
56_strnicmp( const char *s1, const char *s2, size_t count )
57{
58 int ret;
59
60 PERF_ENTRY(_strnicmp);
61 ENTRY("_strnicmp (s1=%p (%s), s2=%p (%s), count=%d)\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL", count);
62
63 ret = strncasecmp(s1, s2, count );
64
65 LOGEXIT("_strnicmp returning int %d\n", ret);
66 PERF_EXIT(_strnicmp);
67 return ret;
68}
69
70/*++
71Function:
72 _stricmp
73
74compare two strings, ignoring case
75
76The stricmp() function compares, with case insensitivity, the string
77pointed to by s1 to the string pointed to by s2. All uppercase
78characters from s1 and s2 are mapped to lowercase for the purposes of
79doing the comparison.
80
81Returns:
82
83Value Meaning
84
85< 0 s1 is less than s2
860 s1 is equal to s2
87> 0 s1 is greater than s2
88
89--*/
90int
91__cdecl
92_stricmp(
93 const char *s1,
94 const char *s2)
95{
96 int ret;
97
98 PERF_ENTRY(_stricmp);
99 ENTRY("_stricmp (s1=%p (%s), s2=%p (%s))\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL");
100
101 ret = strcasecmp(s1, s2);
102
103 LOGEXIT("_stricmp returning int %d\n", ret);
104 PERF_EXIT(_stricmp);
105 return ret;
106}
107
108
109/*++
110Function:
111 _strlwr
112
113Convert a string to lowercase.
114
115
116This function returns a pointer to the converted string. Because the
117modification is done in place, the pointer returned is the same as the
118pointer passed as the input argument. No return value is reserved to
119indicate an error.
120
121Parameter
122
123string Null-terminated string to convert to lowercase
124
125Remarks
126
127The _strlwr function converts any uppercase letters in string to
128lowercase as determined by the LC_CTYPE category setting of the
129current locale. Other characters are not affected. For more
130information on LC_CTYPE, see setlocale.
131
132--*/
133char *
134__cdecl
135_strlwr(
136 char *str)
137{
138 char *orig = str;
139
140 PERF_ENTRY(_strlwr);
141 ENTRY("_strlwr (str=%p (%s))\n", str?str:"NULL", str?str:"NULL");
142
143 while (*str)
144 {
145 *str = tolower(*str);
146 str++;
147 }
148
149 LOGEXIT("_strlwr returning char* %p (%s)\n", orig?orig:"NULL", orig?orig:"NULL");
150 PERF_EXIT(_strlwr);
151 return orig;
152}
153
154/*++
155Function:
156 PAL_strtoul
157
158Convert string to an unsigned long-integer value.
159
160Return Value
161
162strtoul returns the converted value, if any, or ULONG_MAX on
163overflow. It returns 0 if no conversion can be performed. errno is
164set to ERANGE if overflow or underflow occurs.
165
166Parameters
167
168szNumber Null-terminated string to convert to a ULONG
169pszEnd Pointer to character that stops scan
170nBase Number base to use
171
172Remarks
173
174strtoul stops reading the string szNumber at the first character it cannot
175recognize as part of a number. This may be the terminating null
176character, or it may be the first numeric character greater than or
177equal to base. The LC_NUMERIC category setting of the current locale
178determines recognition of the radix character in szNumber; for more
179information, see setlocale. If pszEnd is not NULL, a pointer to the
180character that stopped the scan is stored at the location pointed to
181by pszEnd. If no conversion can be performed (no valid digits were
182found or an invalid base was specified), the value of szNumber is stored
183at the location pointed to by pszEnd.
184
185Notes :
186 MSDN states that only space and tab are accepted as leading whitespace, but
187 tests indicate that other whitespace characters (newline, carriage return,
188 etc) are also accepted. This matches the behavior on Unix systems.
189
190 For strtoul, we need to check if the value to be returned
191 is outside the 32 bit range. If so, the returned value needs to be set
192 as appropriate, according to the MSDN pages and in all instances errno
193 must be set to ERANGE (The one exception is converting a string
194 representing a negative value to unsigned long).
195 Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
196 Windows behavior, we must return long's in the 32 bit range.
197 --*/
198
199/* The use of ULONG is by design, to ensure that a 32 bit value is always
200returned from this function. If "unsigned long" is used instead of ULONG,
201then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus
202breaking Windows behavior. */
203ULONG
204__cdecl
205PAL_strtoul(const char *szNumber, char **pszEnd, int nBase)
206{
207 unsigned long ulResult;
208
209 PERF_ENTRY(strtoul);
210 ENTRY("strtoul (szNumber=%p (%s), pszEnd=%p, nBase=%d)\n",
211 szNumber?szNumber:"NULL",
212 szNumber?szNumber:"NULL",
213 pszEnd,
214 nBase);
215
216 ulResult = strtoul(szNumber, pszEnd, nBase);
217
218#ifdef BIT64
219 if (ulResult > _UI32_MAX)
220 {
221 char ch = *szNumber;
222 while (isspace(ch))
223 {
224 ch = *szNumber++;
225 }
226 /* If the string represents a positive number that is greater than
227 _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno
228 to match Windows behavior. */
229 if (ch != '-')
230 {
231 ulResult = _UI32_MAX;
232 errno = ERANGE;
233 }
234 }
235#endif
236
237 LOGEXIT("strtoul returning unsigned long %lu\n", ulResult);
238 PERF_EXIT(wcstoul);
239
240 /* When returning unsigned long res from this function, it will be
241 implicitly cast to ULONG. This handles situations where a string that
242 represents a negative number is passed in to strtoul. The Windows
243 behavior is analogous to taking the binary equivalent of the negative
244 value and treating it as a positive number. Returning a ULONG from
245 this function, as opposed to native unsigned long, allows us to match
246 this behavior. The explicit cast to ULONG below is used to silence any
247 potential warnings due to the implicit casting. */
248 return (ULONG)ulResult;
249
250}
251
252
253/*++
254Function:
255 PAL_atol
256
257Convert string to a long value.
258
259Return Value
260
261atol returns the converted value, if any. In the case of overflow,
262the return value is undefined.
263
264Parameters
265
266szNumber Null-terminated string to convert to a LONG
267--*/
268
269/* The use of LONG is by design, to ensure that a 32 bit value is always
270returned from this function. If "long" is used instead of LONG, then a 64 bit
271value could be returned on 64 bit platforms like HP-UX, thus breaking
272Windows behavior. */
273LONG
274__cdecl
275PAL_atol(const char *szNumber)
276{
277 long lResult;
278
279 PERF_ENTRY(atol);
280 ENTRY("atol (szNumber=%p (%s))\n",
281 szNumber, szNumber?szNumber:"NULL"
282 );
283
284 lResult = atol(szNumber);
285
286 LOGEXIT("atol returning long %ld\n", (LONG)lResult);
287 PERF_EXIT(atol);
288 /* This explicit cast to LONG is used to silence any potential warnings
289 due to implicitly casting the native long lResult to LONG when returning. */
290 return (LONG)lResult;
291
292}
293
294