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