comctl32: A couple fixes for tab icon offsets.
[wine] / dlls / ntdll / string.c
1 /*
2  * NTDLL string functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  * Copyright 2000 Jon Griffiths
6  * Copyright 2003 Thomas Mertes
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <ctype.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include "windef.h"
31 #include "winternl.h"
32
33
34 /*********************************************************************
35  *                  _memicmp   (NTDLL.@)
36  *
37  * Compare two blocks of memory as strings, ignoring case.
38  *
39  * PARAMS
40  *  s1  [I] First string to compare to s2
41  *  s2  [I] Second string to compare to s1
42  *  len [I] Number of bytes to compare
43  *
44  * RETURNS
45  *  An integer less than, equal to, or greater than zero indicating that
46  *  s1 is less than, equal to or greater than s2 respectively.
47  *
48  * NOTES
49  *  Any Nul characters in s1 or s2 are ignored. This function always
50  *  compares up to len bytes or the first place where s1 and s2 differ.
51  */
52 INT __cdecl NTDLL__memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
53 {
54     int ret = 0;
55     while (len--)
56     {
57         if ((ret = tolower(*s1) - tolower(*s2))) break;
58         s1++;
59         s2++;
60     }
61     return ret;
62 }
63
64
65 /*********************************************************************
66  *                  memcpy   (NTDLL.@)
67  *
68  * NOTES
69  *  Behaves like memmove.
70  */
71 void * __cdecl NTDLL_memcpy( void *dst, const void *src, size_t n )
72 {
73     return memmove( dst, src, n );
74 }
75
76
77 /*********************************************************************
78  *                  _strupr   (NTDLL.@)
79  *
80  * Convert a string to upper case.
81  *
82  * PARAMS
83  *  str [I/O] String to convert
84  *
85  * RETURNS
86  *  str. There is no error return, if str is NULL or invalid, this
87  *  function will crash.
88  */
89 LPSTR __cdecl _strupr( LPSTR str )
90 {
91     LPSTR ret = str;
92     for ( ; *str; str++) *str = toupper(*str);
93     return ret;
94 }
95
96
97 /*********************************************************************
98  *                  _strlwr   (NTDLL.@)
99  *
100  * Convert a string to lowercase
101  *
102  * PARAMS
103  *  str [I/O] String to convert
104  *
105  * RETURNS
106  *  str. There is no error return, if str is NULL or invalid, this
107  *  function will crash.
108  */
109 LPSTR __cdecl _strlwr( LPSTR str )
110 {
111     LPSTR ret = str;
112     for ( ; *str; str++) *str = tolower(*str);
113     return ret;
114 }
115
116
117 /*********************************************************************
118  *      _ultoa   (NTDLL.@)
119  *
120  * Convert an unsigned long integer to a string.
121  *
122  * RETURNS
123  *  str.
124  *
125  * NOTES
126  *  - Converts value to a Nul terminated string which is copied to str.
127  *  - The maximum length of the copied str is 33 bytes.
128  *  - Does not check if radix is in the range of 2 to 36.
129  *  - If str is NULL it crashes, as the native function does.
130  */
131 char * __cdecl _ultoa(
132     unsigned long value, /* [I] Value to be converted */
133     char *str,           /* [O] Destination for the converted value */
134     int radix)           /* [I] Number base for conversion */
135 {
136     char buffer[33];
137     char *pos;
138     int digit;
139
140     pos = &buffer[32];
141     *pos = '\0';
142
143     do {
144         digit = value % radix;
145         value = value / radix;
146         if (digit < 10) {
147             *--pos = '0' + digit;
148         } else {
149             *--pos = 'a' + digit - 10;
150         } /* if */
151     } while (value != 0L);
152
153     memcpy(str, pos, &buffer[32] - pos + 1);
154     return str;
155 }
156
157
158 /*********************************************************************
159  *      _ltoa   (NTDLL.@)
160  *
161  * Convert a long integer to a string.
162  *
163  * RETURNS
164  *  str.
165  *
166  * NOTES
167  *  - Converts value to a Nul terminated string which is copied to str.
168  *  - The maximum length of the copied str is 33 bytes. If radix
169  *  is 10 and value is negative, the value is converted with sign.
170  *  - Does not check if radix is in the range of 2 to 36.
171  *  - If str is NULL it crashes, as the native function does.
172  */
173 char * __cdecl _ltoa(
174     long value, /* [I] Value to be converted */
175     char *str,  /* [O] Destination for the converted value */
176     int radix)  /* [I] Number base for conversion */
177 {
178     unsigned long val;
179     int negative;
180     char buffer[33];
181     char *pos;
182     int digit;
183
184     if (value < 0 && radix == 10) {
185         negative = 1;
186         val = -value;
187     } else {
188         negative = 0;
189         val = value;
190     } /* if */
191
192     pos = &buffer[32];
193     *pos = '\0';
194
195     do {
196         digit = val % radix;
197         val = val / radix;
198         if (digit < 10) {
199             *--pos = '0' + digit;
200         } else {
201             *--pos = 'a' + digit - 10;
202         } /* if */
203     } while (val != 0L);
204
205     if (negative) {
206         *--pos = '-';
207     } /* if */
208
209     memcpy(str, pos, &buffer[32] - pos + 1);
210     return str;
211 }
212
213
214 /*********************************************************************
215  *      _itoa    (NTDLL.@)
216  *
217  * Converts an integer to a string.
218  *
219  * RETURNS
220  *  str.
221  *
222  * NOTES
223  *  - Converts value to a '\0' terminated string which is copied to str.
224  *  - The maximum length of the copied str is 33 bytes. If radix
225  *  is 10 and value is negative, the value is converted with sign.
226  *  - Does not check if radix is in the range of 2 to 36.
227  *  - If str is NULL it crashes, as the native function does.
228  */
229 char * __cdecl _itoa(
230     int value, /* [I] Value to be converted */
231     char *str, /* [O] Destination for the converted value */
232     int radix) /* [I] Number base for conversion */
233 {
234     return _ltoa(value, str, radix);
235 }
236
237
238 /*********************************************************************
239  *      _ui64toa   (NTDLL.@)
240  *
241  * Converts a large unsigned integer to a string.
242  *
243  * RETURNS
244  *  str.
245  *
246  * NOTES
247  *  - Converts value to a '\0' terminated string which is copied to str.
248  *  - The maximum length of the copied str is 65 bytes.
249  *  - Does not check if radix is in the range of 2 to 36.
250  *  - If str is NULL it crashes, as the native function does.
251  */
252 char * __cdecl _ui64toa(
253     ULONGLONG value, /* [I] Value to be converted */
254     char *str,       /* [O] Destination for the converted value */
255     int radix)       /* [I] Number base for conversion */
256 {
257     char buffer[65];
258     char *pos;
259     int digit;
260
261     pos = &buffer[64];
262     *pos = '\0';
263
264     do {
265         digit = value % radix;
266         value = value / radix;
267         if (digit < 10) {
268             *--pos = '0' + digit;
269         } else {
270             *--pos = 'a' + digit - 10;
271         } /* if */
272     } while (value != 0L);
273
274     memcpy(str, pos, &buffer[64] - pos + 1);
275     return str;
276 }
277
278
279 /*********************************************************************
280  *      _i64toa   (NTDLL.@)
281  *
282  * Converts a large integer to a string.
283  *
284  * RETURNS
285  *  str.
286  *
287  * NOTES
288  *  - Converts value to a Nul terminated string which is copied to str.
289  *  - The maximum length of the copied str is 65 bytes. If radix
290  *  is 10 and value is negative, the value is converted with sign.
291  *  - Does not check if radix is in the range of 2 to 36.
292  *  - If str is NULL it crashes, as the native function does.
293  *
294  * DIFFERENCES
295  * - The native DLL converts negative values (for base 10) wrong:
296  *|                     -1 is converted to -18446744073709551615
297  *|                     -2 is converted to -18446744073709551614
298  *|   -9223372036854775807 is converted to  -9223372036854775809
299  *|   -9223372036854775808 is converted to  -9223372036854775808
300  *   The native msvcrt _i64toa function and our ntdll _i64toa function
301  *   do not have this bug.
302  */
303 char * __cdecl _i64toa(
304     LONGLONG value, /* [I] Value to be converted */
305     char *str,      /* [O] Destination for the converted value */
306     int radix)      /* [I] Number base for conversion */
307 {
308     ULONGLONG val;
309     int negative;
310     char buffer[65];
311     char *pos;
312     int digit;
313
314     if (value < 0 && radix == 10) {
315         negative = 1;
316         val = -value;
317     } else {
318         negative = 0;
319         val = value;
320     } /* if */
321
322     pos = &buffer[64];
323     *pos = '\0';
324
325     do {
326         digit = val % radix;
327         val = val / radix;
328         if (digit < 10) {
329             *--pos = '0' + digit;
330         } else {
331             *--pos = 'a' + digit - 10;
332         } /* if */
333     } while (val != 0L);
334
335     if (negative) {
336         *--pos = '-';
337     } /* if */
338
339     memcpy(str, pos, &buffer[64] - pos + 1);
340     return str;
341 }
342
343
344 /*********************************************************************
345  *      _atoi64   (NTDLL.@)
346  *
347  * Convert a string to a large integer.
348  *
349  * PARAMS
350  *  str [I] String to be converted
351  *
352  * RETURNS
353  *  Success: The integer value represented by str.
354  *  Failure: 0. Note that this cannot be distinguished from a successful
355  *           return, if the string contains "0".
356  *
357  * NOTES
358  *  - Accepts: {whitespace} [+|-] {digits}
359  *  - No check is made for value overflow, only the lower 64 bits are assigned.
360  *  - If str is NULL it crashes, as the native function does.
361  */
362 LONGLONG __cdecl _atoi64( char *str )
363 {
364     ULONGLONG RunningTotal = 0;
365     char bMinus = 0;
366
367     while (*str == ' ' || (*str >= '\011' && *str <= '\015')) {
368         str++;
369     } /* while */
370
371     if (*str == '+') {
372         str++;
373     } else if (*str == '-') {
374         bMinus = 1;
375         str++;
376     } /* if */
377
378     while (*str >= '0' && *str <= '9') {
379         RunningTotal = RunningTotal * 10 + *str - '0';
380         str++;
381     } /* while */
382
383     return bMinus ? -RunningTotal : RunningTotal;
384 }
385
386
387 /*********************************************************************
388  *              _splitpath (NTDLL.@)
389  *
390  * Split a path into its component pieces.
391  *
392  * PARAMS
393  *  inpath [I] Path to split
394  *  drv    [O] Destination for drive component (e.g. "A:"). Must be at least 3 characters.
395  *  dir    [O] Destination for directory component. Should be at least MAX_PATH characters.
396  *  fname  [O] Destination for File name component. Should be at least MAX_PATH characters.
397  *  ext    [O] Destination for file extension component. Should be at least MAX_PATH characters.
398  *
399  * RETURNS
400  *  Nothing.
401  */
402 void __cdecl _splitpath(const char* inpath, char * drv, char * dir,
403                         char* fname, char * ext )
404 {
405     const char *p, *end;
406
407     if (inpath[0] && inpath[1] == ':')
408     {
409         if (drv)
410         {
411             drv[0] = inpath[0];
412             drv[1] = inpath[1];
413             drv[2] = 0;
414         }
415         inpath += 2;
416     }
417     else if (drv) drv[0] = 0;
418
419     /* look for end of directory part */
420     end = NULL;
421     for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
422
423     if (end)  /* got a directory */
424     {
425         if (dir)
426         {
427             memcpy( dir, inpath, end - inpath );
428             dir[end - inpath] = 0;
429         }
430         inpath = end;
431     }
432     else if (dir) dir[0] = 0;
433
434     /* look for extension: what's after the last dot */
435     end = NULL;
436     for (p = inpath; *p; p++) if (*p == '.') end = p;
437
438     if (!end) end = p; /* there's no extension */
439
440     if (fname)
441     {
442         memcpy( fname, inpath, end - inpath );
443         fname[end - inpath] = 0;
444     }
445     if (ext) strcpy( ext, end );
446 }