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