| 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 | |