summaryrefslogtreecommitdiff
path: root/src/pal/src/cruntime/string.cpp
blob: abe6d136f0d81b52e0f77c3f9b3201568e8bc014 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// 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 <string.h>
#include <ctype.h>
#include <pthread.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>


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