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