// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. /*++ Module Name: string.cpp Abstract: Implementation of the string functions in the C runtime library that are Windows specific. --*/ #include "pal/palinternal.h" #include "pal/dbgmsg.h" #include "pal/cruntime.h" #include #include #include #include #include #include SET_DEFAULT_DEBUG_CHANNEL(CRT); /*++ Function: _strnicmp compare at most count characters from two strings, ignoring case The strnicmp() function compares, with case insensitivity, at most count characters from s1 to s2. All uppercase characters from s1 and s2 are mapped to lowercase for the purposes of doing the comparison. Returns: Value Meaning < 0 s1 is less than s2 0 s1 is equal to s2 > 0 s1 is greater than s2 --*/ int __cdecl _strnicmp( const char *s1, const char *s2, size_t count ) { int ret; PERF_ENTRY(_strnicmp); ENTRY("_strnicmp (s1=%p (%s), s2=%p (%s), count=%d)\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL", count); ret = strncasecmp(s1, s2, count ); LOGEXIT("_strnicmp returning int %d\n", ret); PERF_EXIT(_strnicmp); return ret; } /*++ Function: _stricmp compare two strings, ignoring case The stricmp() function compares, with case insensitivity, the string pointed to by s1 to the string pointed to by s2. All uppercase characters from s1 and s2 are mapped to lowercase for the purposes of doing the comparison. Returns: Value Meaning < 0 s1 is less than s2 0 s1 is equal to s2 > 0 s1 is greater than s2 --*/ int __cdecl _stricmp( const char *s1, const char *s2) { int ret; PERF_ENTRY(_stricmp); ENTRY("_stricmp (s1=%p (%s), s2=%p (%s))\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL"); ret = strcasecmp(s1, s2); LOGEXIT("_stricmp returning int %d\n", ret); PERF_EXIT(_stricmp); return ret; } /*++ Function: _strlwr Convert a string to lowercase. This function returns a pointer to the converted string. Because the modification is done in place, the pointer returned is the same as the pointer passed as the input argument. No return value is reserved to indicate an error. Parameter string Null-terminated string to convert to lowercase Remarks The _strlwr function converts any uppercase letters in string to lowercase as determined by the LC_CTYPE category setting of the current locale. Other characters are not affected. For more information on LC_CTYPE, see setlocale. --*/ char * __cdecl _strlwr( char *str) { char *orig = str; PERF_ENTRY(_strlwr); ENTRY("_strlwr (str=%p (%s))\n", str?str:"NULL", str?str:"NULL"); while (*str) { *str = tolower(*str); str++; } LOGEXIT("_strlwr returning char* %p (%s)\n", orig?orig:"NULL", orig?orig:"NULL"); PERF_EXIT(_strlwr); return orig; } /*++ Function: PAL_strtoul Convert string to an unsigned long-integer value. Return Value strtoul returns the converted value, if any, or ULONG_MAX on overflow. It returns 0 if no conversion can be performed. errno is set to ERANGE if overflow or underflow occurs. Parameters szNumber Null-terminated string to convert to a ULONG pszEnd Pointer to character that stops scan nBase Number base to use Remarks strtoul stops reading the string szNumber at the first character it cannot recognize as part of a number. This may be the terminating null character, or it may be the first numeric character greater than or equal to base. The LC_NUMERIC category setting of the current locale determines recognition of the radix character in szNumber; for more information, see setlocale. If pszEnd is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by pszEnd. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of szNumber is stored at the location pointed to by pszEnd. Notes : MSDN states that only space and tab are accepted as leading whitespace, but tests indicate that other whitespace characters (newline, carriage return, etc) are also accepted. This matches the behavior on Unix systems. For strtoul, we need to check if the value to be returned is outside the 32 bit range. If so, the returned value needs to be set as appropriate, according to the MSDN pages and in all instances errno must be set to ERANGE (The one exception is converting a string representing a negative value to unsigned long). Note that on 64 bit Windows, long's are still 32 bit. Thus, to match Windows behavior, we must return long's in the 32 bit range. --*/ /* The use of ULONG is by design, to ensure that a 32 bit value is always returned from this function. If "unsigned long" is used instead of ULONG, then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus breaking Windows behavior. */ ULONG __cdecl PAL_strtoul(const char *szNumber, char **pszEnd, int nBase) { unsigned long ulResult; PERF_ENTRY(strtoul); ENTRY("strtoul (szNumber=%p (%s), pszEnd=%p, nBase=%d)\n", szNumber?szNumber:"NULL", szNumber?szNumber:"NULL", pszEnd, nBase); ulResult = strtoul(szNumber, pszEnd, nBase); #ifdef BIT64 if (ulResult > _UI32_MAX) { char ch = *szNumber; while (isspace(ch)) { ch = *szNumber++; } /* If the string represents a positive number that is greater than _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno to match Windows behavior. */ if (ch != '-') { ulResult = _UI32_MAX; errno = ERANGE; } } #endif LOGEXIT("strtoul returning unsigned long %lu\n", ulResult); PERF_EXIT(wcstoul); /* When returning unsigned long res from this function, it will be implicitly cast to ULONG. This handles situations where a string that represents a negative number is passed in to strtoul. The Windows behavior is analogous to taking the binary equivalent of the negative value and treating it as a positive number. Returning a ULONG from this function, as opposed to native unsigned long, allows us to match this behavior. The explicit cast to ULONG below is used to silence any potential warnings due to the implicit casting. */ return (ULONG)ulResult; } /*++ Function: PAL_atol Convert string to a long value. Return Value atol returns the converted value, if any. In the case of overflow, the return value is undefined. Parameters szNumber Null-terminated string to convert to a LONG --*/ /* The use of LONG is by design, to ensure that a 32 bit value is always returned from this function. If "long" is used instead of LONG, then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus breaking Windows behavior. */ LONG __cdecl PAL_atol(const char *szNumber) { long lResult; PERF_ENTRY(atol); ENTRY("atol (szNumber=%p (%s))\n", szNumber?szNumber:"NULL" ); lResult = atol(szNumber); LOGEXIT("atol returning long %ld\n", (LONG)lResult); PERF_EXIT(atol); /* This explicit cast to LONG is used to silence any potential warnings due to implicitly casting the native long lResult to LONG when returning. */ return (LONG)lResult; }