Moved a few more functions to the dlls/kernel directory.
[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   /* Modified PD code from 'snippets' collection. */
351   char ch, *ptr, *p;
352   char pathbuff[MAX_PATH], *path=pathbuff;
353
354   strcpy(pathbuff, inpath);
355
356   /* convert slashes to backslashes for searching */
357   for (ptr = (char*)path; *ptr; ++ptr)
358     if ('/' == *ptr)
359       *ptr = '\\';
360
361   /* look for drive spec */
362   if ('\0' != (ptr = strchr(path, ':')))
363   {
364     ++ptr;
365     if (drv)
366     {
367       strncpy(drv, path, ptr - path);
368       drv[ptr - path] = '\0';
369     }
370     path = ptr;
371   }
372   else if (drv)
373     *drv = '\0';
374
375   /* find rightmost backslash or leftmost colon */
376   if (NULL == (ptr = strrchr(path, '\\')))
377     ptr = (strchr(path, ':'));
378
379   if (!ptr)
380   {
381     ptr = (char *)path; /* no path */
382     if (dir)
383       *dir = '\0';
384   }
385   else
386   {
387     ++ptr; /* skip the delimiter */
388     if (dir)
389     {
390       ch = *ptr;
391       *ptr = '\0';
392       strcpy(dir, path);
393       *ptr = ch;
394     }
395   }
396
397   if (NULL == (p = strrchr(ptr, '.')))
398   {
399     if (fname)
400       strcpy(fname, ptr);
401     if (ext)
402       *ext = '\0';
403   }
404   else
405   {
406     *p = '\0';
407     if (fname)
408       strcpy(fname, ptr);
409     *p = '.';
410     if (ext)
411       strcpy(ext, p);
412   }
413
414   /* Fix pathological case - Win returns ':' as part of the
415    * directory when no drive letter is given.
416    */
417   if (drv && drv[0] == ':')
418   {
419     *drv = '\0';
420     if (dir)
421     {
422       pathbuff[0] = ':';
423       pathbuff[1] = '\0';
424       strcat(pathbuff,dir);
425       strcpy(dir,pathbuff);
426     }
427   }
428 }