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 | |
9 | Module Name: |
10 | |
11 | string.cpp |
12 | |
13 | Abstract: |
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 | |
33 | SET_DEFAULT_DEBUG_CHANNEL(CRT); |
34 | |
35 | /*++ |
36 | Function: |
37 | _strnicmp |
38 | |
39 | compare at most count characters from two strings, ignoring case |
40 | |
41 | The strnicmp() function compares, with case insensitivity, at most count |
42 | characters from s1 to s2. All uppercase characters from s1 and s2 are |
43 | mapped to lowercase for the purposes of doing the comparison. |
44 | |
45 | Returns: |
46 | |
47 | Value Meaning |
48 | |
49 | < 0 s1 is less than s2 |
50 | 0 s1 is equal to s2 |
51 | > 0 s1 is greater than s2 |
52 | |
53 | --*/ |
54 | int |
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 | /*++ |
71 | Function: |
72 | _stricmp |
73 | |
74 | compare two strings, ignoring case |
75 | |
76 | The stricmp() function compares, with case insensitivity, the string |
77 | pointed to by s1 to the string pointed to by s2. All uppercase |
78 | characters from s1 and s2 are mapped to lowercase for the purposes of |
79 | doing the comparison. |
80 | |
81 | Returns: |
82 | |
83 | Value Meaning |
84 | |
85 | < 0 s1 is less than s2 |
86 | 0 s1 is equal to s2 |
87 | > 0 s1 is greater than s2 |
88 | |
89 | --*/ |
90 | int |
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 | /*++ |
110 | Function: |
111 | _strlwr |
112 | |
113 | Convert a string to lowercase. |
114 | |
115 | |
116 | This function returns a pointer to the converted string. Because the |
117 | modification is done in place, the pointer returned is the same as the |
118 | pointer passed as the input argument. No return value is reserved to |
119 | indicate an error. |
120 | |
121 | Parameter |
122 | |
123 | string Null-terminated string to convert to lowercase |
124 | |
125 | Remarks |
126 | |
127 | The _strlwr function converts any uppercase letters in string to |
128 | lowercase as determined by the LC_CTYPE category setting of the |
129 | current locale. Other characters are not affected. For more |
130 | information on LC_CTYPE, see setlocale. |
131 | |
132 | --*/ |
133 | char * |
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 | /*++ |
155 | Function: |
156 | PAL_strtoul |
157 | |
158 | Convert string to an unsigned long-integer value. |
159 | |
160 | Return Value |
161 | |
162 | strtoul returns the converted value, if any, or ULONG_MAX on |
163 | overflow. It returns 0 if no conversion can be performed. errno is |
164 | set to ERANGE if overflow or underflow occurs. |
165 | |
166 | Parameters |
167 | |
168 | szNumber Null-terminated string to convert to a ULONG |
169 | pszEnd Pointer to character that stops scan |
170 | nBase Number base to use |
171 | |
172 | Remarks |
173 | |
174 | strtoul stops reading the string szNumber at the first character it cannot |
175 | recognize as part of a number. This may be the terminating null |
176 | character, or it may be the first numeric character greater than or |
177 | equal to base. The LC_NUMERIC category setting of the current locale |
178 | determines recognition of the radix character in szNumber; for more |
179 | information, see setlocale. If pszEnd is not NULL, a pointer to the |
180 | character that stopped the scan is stored at the location pointed to |
181 | by pszEnd. If no conversion can be performed (no valid digits were |
182 | found or an invalid base was specified), the value of szNumber is stored |
183 | at the location pointed to by pszEnd. |
184 | |
185 | Notes : |
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 |
200 | returned from this function. If "unsigned long" is used instead of ULONG, |
201 | then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus |
202 | breaking Windows behavior. */ |
203 | ULONG |
204 | __cdecl |
205 | PAL_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 | /*++ |
254 | Function: |
255 | PAL_atol |
256 | |
257 | Convert string to a long value. |
258 | |
259 | Return Value |
260 | |
261 | atol returns the converted value, if any. In the case of overflow, |
262 | the return value is undefined. |
263 | |
264 | Parameters |
265 | |
266 | szNumber 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 |
270 | returned from this function. If "long" is used instead of LONG, then a 64 bit |
271 | value could be returned on 64 bit platforms like HP-UX, thus breaking |
272 | Windows behavior. */ |
273 | LONG |
274 | __cdecl |
275 | PAL_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 | |