A couple of optimizations and bug fixes.
[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
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <string.h>
28
29 #include "ntstatus.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winternl.h"
34
35
36 /*********************************************************************
37  *                  _memicmp   (NTDLL.@)
38  */
39 INT __cdecl NTDLL__memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
40 {
41     int ret = 0;
42     while (len--)
43     {
44         if ((ret = tolower(*s1) - tolower(*s2))) break;
45         s1++;
46         s2++;
47     }
48     return ret;
49 }
50
51
52 /*********************************************************************
53  *                  _strupr   (NTDLL.@)
54  */
55 LPSTR __cdecl _strupr( LPSTR str )
56 {
57     LPSTR ret = str;
58     for ( ; *str; str++) *str = toupper(*str);
59     return ret;
60 }
61
62
63 /*********************************************************************
64  *                  _strlwr   (NTDLL.@)
65  *
66  * convert a string in place to lowercase
67  */
68 LPSTR __cdecl _strlwr( LPSTR str )
69 {
70     LPSTR ret = str;
71     for ( ; *str; str++) *str = tolower(*str);
72     return ret;
73 }
74
75
76 /*********************************************************************
77  *      _ultoa   (NTDLL.@)
78  *
79  * Converts an unsigned long integer to a string.
80  *
81  * RETURNS
82  *  Always returns str.
83  *
84  * NOTES
85  *  Converts value to a '\0' terminated string which is copied to str.
86  *  The maximum length of the copied str is 33 bytes.
87  *  Does not check if radix is in the range of 2 to 36.
88  *  If str is NULL it crashes, as the native function does.
89  */
90 char * __cdecl _ultoa(
91     unsigned long value, /* [I] Value to be converted */
92     char *str,           /* [O] Destination for the converted value */
93     int radix)           /* [I] Number base for conversion */
94 {
95     char buffer[33];
96     char *pos;
97     int digit;
98
99     pos = &buffer[32];
100     *pos = '\0';
101
102     do {
103         digit = value % radix;
104         value = value / radix;
105         if (digit < 10) {
106             *--pos = '0' + digit;
107         } else {
108             *--pos = 'a' + digit - 10;
109         } /* if */
110     } while (value != 0L);
111
112     memcpy(str, pos, &buffer[32] - pos + 1);
113     return str;
114 }
115
116
117 /*********************************************************************
118  *      _ltoa   (NTDLL.@)
119  *
120  * Converts a long integer to a string.
121  *
122  * RETURNS
123  *  Always returns str.
124  *
125  * NOTES
126  *  Converts value to a '\0' terminated string which is copied to str.
127  *  The maximum length of the copied str is 33 bytes. If radix
128  *  is 10 and value is negative, the value is converted with sign.
129  *  Does not check if radix is in the range of 2 to 36.
130  *  If str is NULL it crashes, as the native function does.
131  */
132 char * __cdecl _ltoa(
133     long value, /* [I] Value to be converted */
134     char *str,  /* [O] Destination for the converted value */
135     int radix)  /* [I] Number base for conversion */
136 {
137     unsigned long val;
138     int negative;
139     char buffer[33];
140     char *pos;
141     int digit;
142
143     if (value < 0 && radix == 10) {
144         negative = 1;
145         val = -value;
146     } else {
147         negative = 0;
148         val = value;
149     } /* if */
150
151     pos = &buffer[32];
152     *pos = '\0';
153
154     do {
155         digit = val % radix;
156         val = val / radix;
157         if (digit < 10) {
158             *--pos = '0' + digit;
159         } else {
160             *--pos = 'a' + digit - 10;
161         } /* if */
162     } while (val != 0L);
163
164     if (negative) {
165         *--pos = '-';
166     } /* if */
167
168     memcpy(str, pos, &buffer[32] - pos + 1);
169     return str;
170 }
171
172
173 /*********************************************************************
174  *      _itoa    (NTDLL.@)
175  *
176  * Converts an integer to a string.
177  *
178  * RETURNS
179  *  Always returns str.
180  *
181  * NOTES
182  *  Converts value to a '\0' terminated string which is copied to str.
183  *  The maximum length of the copied str is 33 bytes. If radix
184  *  is 10 and value is negative, the value is converted with sign.
185  *  Does not check if radix is in the range of 2 to 36.
186  *  If str is NULL it crashes, as the native function does.
187  */
188 char * __cdecl _itoa(
189     int value, /* [I] Value to be converted */
190     char *str, /* [O] Destination for the converted value */
191     int radix) /* [I] Number base for conversion */
192 {
193     return _ltoa(value, str, radix);
194 }
195
196
197 /*********************************************************************
198  *      _ui64toa   (NTDLL.@)
199  *
200  * Converts a large unsigned integer to a string.
201  *
202  * RETURNS
203  *  Always returns str.
204  *
205  * NOTES
206  *  Converts value to a '\0' terminated string which is copied to str.
207  *  The maximum length of the copied str is 65 bytes.
208  *  Does not check if radix is in the range of 2 to 36.
209  *  If str is NULL it crashes, as the native function does.
210  */
211 char * __cdecl _ui64toa(
212     ULONGLONG value, /* [I] Value to be converted */
213     char *str,       /* [O] Destination for the converted value */
214     int radix)       /* [I] Number base for conversion */
215 {
216     char buffer[65];
217     char *pos;
218     int digit;
219
220     pos = &buffer[64];
221     *pos = '\0';
222
223     do {
224         digit = value % radix;
225         value = value / radix;
226         if (digit < 10) {
227             *--pos = '0' + digit;
228         } else {
229             *--pos = 'a' + digit - 10;
230         } /* if */
231     } while (value != 0L);
232
233     memcpy(str, pos, &buffer[64] - pos + 1);
234     return str;
235 }
236
237
238 /*********************************************************************
239  *      _i64toa   (NTDLL.@)
240  *
241  * Converts a large integer to a string.
242  *
243  * RETURNS
244  *  Always returns 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. If radix
249  *  is 10 and value is negative, the value is converted with sign.
250  *  Does not check if radix is in the range of 2 to 36.
251  *  If str is NULL it crashes, as the native function does.
252  *
253  * DIFFERENCES
254  * - The native DLL converts negative values (for base 10) wrong:
255  *                     -1 is converted to -18446744073709551615
256  *                     -2 is converted to -18446744073709551614
257  *   -9223372036854775807 is converted to  -9223372036854775809
258  *   -9223372036854775808 is converted to  -9223372036854775808
259  *   The native msvcrt _i64toa function and our ntdll _i64toa function
260  *   do not have this bug.
261  */
262 char * __cdecl _i64toa(
263     LONGLONG value, /* [I] Value to be converted */
264     char *str,      /* [O] Destination for the converted value */
265     int radix)      /* [I] Number base for conversion */
266 {
267     ULONGLONG val;
268     int negative;
269     char buffer[65];
270     char *pos;
271     int digit;
272
273     if (value < 0 && radix == 10) {
274         negative = 1;
275         val = -value;
276     } else {
277         negative = 0;
278         val = value;
279     } /* if */
280
281     pos = &buffer[64];
282     *pos = '\0';
283
284     do {
285         digit = val % radix;
286         val = val / radix;
287         if (digit < 10) {
288             *--pos = '0' + digit;
289         } else {
290             *--pos = 'a' + digit - 10;
291         } /* if */
292     } while (val != 0L);
293
294     if (negative) {
295         *--pos = '-';
296     } /* if */
297
298     memcpy(str, pos, &buffer[64] - pos + 1);
299     return str;
300 }
301
302
303 /*********************************************************************
304  *      _atoi64   (NTDLL.@)
305  *
306  * Converts a string to a large integer.
307  *
308  * PARAMS
309  *  str [I] Wstring to be converted
310  *
311  * RETURNS
312  *  On success it returns the integer value otherwise it returns 0.
313  *
314  * NOTES
315  *  Accepts: {whitespace} [+|-] {digits}
316  *  No check is made for value overflow, only the lower 64 bits are assigned.
317  *  If str is NULL it crashes, as the native function does.
318  */
319 LONGLONG __cdecl _atoi64( char *str )
320 {
321     ULONGLONG RunningTotal = 0;
322     char bMinus = 0;
323
324     while (*str == ' ' || (*str >= '\011' && *str <= '\015')) {
325         str++;
326     } /* while */
327
328     if (*str == '+') {
329         str++;
330     } else if (*str == '-') {
331         bMinus = 1;
332         str++;
333     } /* if */
334
335     while (*str >= '0' && *str <= '9') {
336         RunningTotal = RunningTotal * 10 + *str - '0';
337         str++;
338     } /* while */
339
340     return bMinus ? -RunningTotal : RunningTotal;
341 }
342
343
344 /*********************************************************************
345  *              _splitpath (NTDLL.@)
346  */
347 void __cdecl _splitpath(const char* inpath, char * drv, char * dir,
348                         char* fname, char * ext )
349 {
350     const char *p, *end;
351
352     if (inpath[0] && inpath[1] == ':')
353     {
354         if (drv)
355         {
356             drv[0] = inpath[0];
357             drv[1] = inpath[1];
358             drv[2] = 0;
359         }
360         inpath += 2;
361     }
362     else if (drv) drv[0] = 0;
363
364     /* look for end of directory part */
365     end = NULL;
366     for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
367
368     if (end)  /* got a directory */
369     {
370         if (dir)
371         {
372             memcpy( dir, inpath, end - inpath );
373             dir[end - inpath] = 0;
374         }
375         inpath = end;
376     }
377     else if (dir) dir[0] = 0;
378
379     /* look for extension: what's after the last dot */
380     end = NULL;
381     for (p = inpath; *p; p++) if (*p == '.') end = p;
382
383     if (!end) end = p; /* there's no extension */
384
385     if (fname)
386     {
387         memcpy( fname, inpath, end - inpath );
388         fname[end - inpath] = 0;
389     }
390     if (ext) strcpy( ext, end );
391 }