user32: Hook drawing menu buttons.
[wine.git] / dlls / ntdll / string.c
bloba48496b65c640ad1c21f77cf0e353e00d6289ae3
1 /*
2 * NTDLL string functions
4 * Copyright 2000 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
6 * Copyright 2003 Thomas Mertes
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <limits.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdint.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winternl.h"
35 #include "ntdll_misc.h"
38 /* same as wctypes except for TAB, which doesn't have C1_BLANK for some reason... */
39 static const unsigned short ctypes[257] =
41 /* -1 */
42 0x0000,
43 /* 00 */
44 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
45 0x0020, 0x0028, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
46 /* 10 */
47 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
48 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
49 /* 20 */
50 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
51 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
52 /* 30 */
53 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
54 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
55 /* 40 */
56 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
57 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
58 /* 50 */
59 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
60 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
61 /* 60 */
62 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
63 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
64 /* 70 */
65 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
66 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020
70 /*********************************************************************
71 * memchr (NTDLL.@)
73 void * __cdecl memchr( const void *ptr, int c, size_t n )
75 const unsigned char *p = ptr;
77 for (p = ptr; n; n--, p++) if (*p == (unsigned char)c) return (void *)(ULONG_PTR)p;
78 return NULL;
82 /*********************************************************************
83 * memcmp (NTDLL.@)
85 int __cdecl memcmp( const void *ptr1, const void *ptr2, size_t n )
87 const unsigned char *p1, *p2;
89 for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
91 if (*p1 < *p2) return -1;
92 if (*p1 > *p2) return 1;
94 return 0;
98 /*********************************************************************
99 * memcpy (NTDLL.@)
101 * NOTES
102 * Behaves like memmove.
104 void * __cdecl memcpy( void *dst, const void *src, size_t n )
106 volatile unsigned char *d = dst; /* avoid gcc optimizations */
107 const unsigned char *s = src;
109 if ((size_t)dst - (size_t)src >= n)
111 while (n--) *d++ = *s++;
113 else
115 d += n - 1;
116 s += n - 1;
117 while (n--) *d-- = *s--;
119 return dst;
123 /*********************************************************************
124 * memmove (NTDLL.@)
126 void * __cdecl memmove( void *dst, const void *src, size_t n )
128 volatile unsigned char *d = dst; /* avoid gcc optimizations */
129 const unsigned char *s = src;
131 if ((size_t)dst - (size_t)src >= n)
133 while (n--) *d++ = *s++;
135 else
137 d += n - 1;
138 s += n - 1;
139 while (n--) *d-- = *s--;
141 return dst;
145 /*********************************************************************
146 * memcpy_s (MSVCRT.@)
148 errno_t __cdecl memcpy_s( void *dst, size_t len, const void *src, size_t count )
150 if (!count) return 0;
151 if (!dst) return EINVAL;
152 if (!src)
154 memset( dst, 0, len );
155 return EINVAL;
157 if (count > len)
159 memset( dst, 0, len );
160 return ERANGE;
162 memmove( dst, src, count );
163 return 0;
167 /*********************************************************************
168 * memmove_s (MSVCRT.@)
170 errno_t __cdecl memmove_s( void *dst, size_t len, const void *src, size_t count )
172 if (!count) return 0;
173 if (!dst) return EINVAL;
174 if (!src) return EINVAL;
175 if (count > len) return ERANGE;
176 memmove( dst, src, count );
177 return 0;
181 static inline void memset_aligned_32( unsigned char *d, uint64_t v, size_t n )
183 unsigned char *end = d + n;
184 while (d < end)
186 *(uint64_t *)(d + 0) = v;
187 *(uint64_t *)(d + 8) = v;
188 *(uint64_t *)(d + 16) = v;
189 *(uint64_t *)(d + 24) = v;
190 d += 32;
194 /*********************************************************************
195 * memset (NTDLL.@)
197 void *__cdecl memset( void *dst, int c, size_t n )
199 typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64;
200 typedef uint32_t DECLSPEC_ALIGN(1) unaligned_ui32;
201 typedef uint16_t DECLSPEC_ALIGN(1) unaligned_ui16;
203 uint64_t v = 0x101010101010101ull * (unsigned char)c;
204 unsigned char *d = (unsigned char *)dst;
205 size_t a = 0x20 - ((uintptr_t)d & 0x1f);
207 if (n >= 16)
209 *(unaligned_ui64 *)(d + 0) = v;
210 *(unaligned_ui64 *)(d + 8) = v;
211 *(unaligned_ui64 *)(d + n - 16) = v;
212 *(unaligned_ui64 *)(d + n - 8) = v;
213 if (n <= 32) return dst;
214 *(unaligned_ui64 *)(d + 16) = v;
215 *(unaligned_ui64 *)(d + 24) = v;
216 *(unaligned_ui64 *)(d + n - 32) = v;
217 *(unaligned_ui64 *)(d + n - 24) = v;
218 if (n <= 64) return dst;
220 n = (n - a) & ~0x1f;
221 memset_aligned_32( d + a, v, n );
222 return dst;
224 if (n >= 8)
226 *(unaligned_ui64 *)d = v;
227 *(unaligned_ui64 *)(d + n - 8) = v;
228 return dst;
230 if (n >= 4)
232 *(unaligned_ui32 *)d = v;
233 *(unaligned_ui32 *)(d + n - 4) = v;
234 return dst;
236 if (n >= 2)
238 *(unaligned_ui16 *)d = v;
239 *(unaligned_ui16 *)(d + n - 2) = v;
240 return dst;
242 if (n >= 1)
244 *(uint8_t *)d = v;
245 return dst;
247 return dst;
251 /*********************************************************************
252 * strcat (NTDLL.@)
254 char * __cdecl strcat( char *dst, const char *src )
256 char *d = dst;
257 while (*d) d++;
258 while ((*d++ = *src++));
259 return dst;
263 /*********************************************************************
264 * strcat_s (NTDLL.@)
266 errno_t __cdecl strcat_s( char *dst, size_t len, const char *src )
268 size_t i, j;
270 if (!dst || !len) return EINVAL;
271 if (!src)
273 *dst = 0;
274 return EINVAL;
276 for (i = 0; i < len; i++) if (!dst[i]) break;
277 for (j = 0; (j + i) < len; j++) if (!(dst[j + i] = src[j])) return 0;
278 *dst = 0;
279 return ERANGE;
283 /*********************************************************************
284 * strchr (NTDLL.@)
286 char * __cdecl strchr( const char *str, int c )
288 do { if (*str == (char)c) return (char *)(ULONG_PTR)str; } while (*str++);
289 return NULL;
293 /*********************************************************************
294 * strcmp (NTDLL.@)
296 int __cdecl strcmp( const char *str1, const char *str2 )
298 while (*str1 && *str1 == *str2) { str1++; str2++; }
299 if ((unsigned char)*str1 > (unsigned char)*str2) return 1;
300 if ((unsigned char)*str1 < (unsigned char)*str2) return -1;
301 return 0;
305 /*********************************************************************
306 * strcpy (NTDLL.@)
308 char * __cdecl strcpy( char *dst, const char *src )
310 char *d = dst;
311 while ((*d++ = *src++));
312 return dst;
316 /*********************************************************************
317 * strcpy_s (NTDLL.@)
319 errno_t __cdecl strcpy_s( char *dst, size_t len, const char *src )
321 size_t i;
323 if (!dst || !len) return EINVAL;
324 if (!src)
326 *dst = 0;
327 return EINVAL;
330 for (i = 0; i < len; i++) if (!(dst[i] = src[i])) return 0;
331 *dst = 0;
332 return ERANGE;
336 /*********************************************************************
337 * strcspn (NTDLL.@)
339 size_t __cdecl strcspn( const char *str, const char *reject )
341 const char *ptr;
342 for (ptr = str; *ptr; ptr++) if (strchr( reject, *ptr )) break;
343 return ptr - str;
347 /*********************************************************************
348 * strlen (NTDLL.@)
350 size_t __cdecl strlen( const char *str )
352 const char *s = str;
353 while (*s) s++;
354 return s - str;
358 /*********************************************************************
359 * strncat (NTDLL.@)
361 char * __cdecl strncat( char *dst, const char *src, size_t len )
363 char *d = dst;
364 while (*d) d++;
365 for ( ; len && *src; d++, src++, len--) *d = *src;
366 *d = 0;
367 return dst;
371 /*********************************************************************
372 * strncat_s (NTDLL.@)
374 errno_t __cdecl strncat_s( char *dst, size_t len, const char *src, size_t count )
376 size_t i, j;
378 if (!dst || !len) return EINVAL;
379 if (!count) return 0;
380 if (!src)
382 *dst = 0;
383 return EINVAL;
386 for (i = 0; i < len; i++) if (!dst[i]) break;
388 if (i == len)
390 *dst = 0;
391 return EINVAL;
394 for (j = 0; (j + i) < len; j++)
396 if (count == _TRUNCATE && j + i == len - 1)
398 dst[j + i] = 0;
399 return STRUNCATE;
401 if (j == count || !(dst[j + i] = src[j]))
403 dst[j + i] = 0;
404 return 0;
407 *dst = 0;
408 return ERANGE;
412 /*********************************************************************
413 * strncmp (NTDLL.@)
415 int __cdecl strncmp( const char *str1, const char *str2, size_t len )
417 if (!len) return 0;
418 while (--len && *str1 && *str1 == *str2) { str1++; str2++; }
419 return (unsigned char)*str1 - (unsigned char)*str2;
423 /*********************************************************************
424 * strncpy (NTDLL.@)
426 #undef strncpy
427 char * __cdecl strncpy( char *dst, const char *src, size_t len )
429 char *d;
430 for (d = dst; len && *src; d++, src++, len--) *d = *src;
431 while (len--) *d++ = 0;
432 return dst;
436 /*********************************************************************
437 * strncpy_s (NTDLL.@)
439 errno_t __cdecl strncpy_s( char *dst, size_t len, const char *src, size_t count )
441 size_t i, end;
443 if (!count)
445 if (dst && len) *dst = 0;
446 return 0;
448 if (!dst || !len) return EINVAL;
449 if (!src)
451 *dst = 0;
452 return EINVAL;
455 if (count != _TRUNCATE && count < len)
456 end = count;
457 else
458 end = len - 1;
460 for (i = 0; i < end; i++)
461 if (!(dst[i] = src[i])) return 0;
463 if (count == _TRUNCATE)
465 dst[i] = 0;
466 return STRUNCATE;
468 if (end == count)
470 dst[i] = 0;
471 return 0;
473 dst[0] = 0;
474 return ERANGE;
478 /*********************************************************************
479 * strnlen (NTDLL.@)
481 size_t __cdecl strnlen( const char *str, size_t len )
483 const char *s;
484 for (s = str; len && *s; s++, len--) ;
485 return s - str;
489 /*********************************************************************
490 * strpbrk (NTDLL.@)
492 char * __cdecl strpbrk( const char *str, const char *accept )
494 for ( ; *str; str++) if (strchr( accept, *str )) return (char *)(ULONG_PTR)str;
495 return NULL;
499 /*********************************************************************
500 * strrchr (NTDLL.@)
502 char * __cdecl strrchr( const char *str, int c )
504 char *ret = NULL;
505 do { if (*str == (char)c) ret = (char *)(ULONG_PTR)str; } while (*str++);
506 return ret;
510 /*********************************************************************
511 * strspn (NTDLL.@)
513 size_t __cdecl strspn( const char *str, const char *accept )
515 const char *ptr;
516 for (ptr = str; *ptr; ptr++) if (!strchr( accept, *ptr )) break;
517 return ptr - str;
521 /*********************************************************************
522 * strstr (NTDLL.@)
524 char * __cdecl strstr( const char *str, const char *sub )
526 while (*str)
528 const char *p1 = str, *p2 = sub;
529 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
530 if (!*p2) return (char *)str;
531 str++;
533 return NULL;
537 /*********************************************************************
538 * _memccpy (NTDLL.@)
540 void * __cdecl _memccpy( void *dst, const void *src, int c, size_t n )
542 unsigned char *d = dst;
543 const unsigned char *s = src;
544 while (n--) if ((*d++ = *s++) == (unsigned char)c) return d;
545 return NULL;
549 /*********************************************************************
550 * tolower (NTDLL.@)
552 int __cdecl tolower( int c )
554 return (char)c >= 'A' && (char)c <= 'Z' ? c - 'A' + 'a' : c;
558 /*********************************************************************
559 * _memicmp (NTDLL.@)
561 * Compare two blocks of memory as strings, ignoring case.
563 * PARAMS
564 * s1 [I] First string to compare to s2
565 * s2 [I] Second string to compare to s1
566 * len [I] Number of bytes to compare
568 * RETURNS
569 * An integer less than, equal to, or greater than zero indicating that
570 * s1 is less than, equal to or greater than s2 respectively.
572 * NOTES
573 * Any Nul characters in s1 or s2 are ignored. This function always
574 * compares up to len bytes or the first place where s1 and s2 differ.
576 int __cdecl _memicmp( const void *str1, const void *str2, size_t len )
578 const unsigned char *s1 = str1, *s2 = str2;
579 int ret = 0;
580 while (len--)
582 if ((ret = tolower(*s1) - tolower(*s2))) break;
583 s1++;
584 s2++;
586 return ret;
590 /*********************************************************************
591 * _strnicmp (NTDLL.@)
593 int __cdecl _strnicmp( LPCSTR str1, LPCSTR str2, size_t n )
595 int l1, l2;
597 while (n--)
599 l1 = (unsigned char)tolower(*str1);
600 l2 = (unsigned char)tolower(*str2);
601 if (l1 != l2)
603 if (sizeof(void *) > sizeof(int)) return l1 - l2;
604 return l1 - l2 > 0 ? 1 : -1;
606 if (!l1) return 0;
607 str1++;
608 str2++;
610 return 0;
614 /*********************************************************************
615 * _stricmp (NTDLL.@)
616 * _strcmpi (NTDLL.@)
618 int __cdecl _stricmp( LPCSTR str1, LPCSTR str2 )
620 return _strnicmp( str1, str2, -1 );
624 /*********************************************************************
625 * _strupr (NTDLL.@)
627 * Convert a string to upper case.
629 * PARAMS
630 * str [I/O] String to convert
632 * RETURNS
633 * str. There is no error return, if str is NULL or invalid, this
634 * function will crash.
636 LPSTR __cdecl _strupr( LPSTR str )
638 LPSTR ret = str;
639 for ( ; *str; str++) if (*str >= 'a' && *str <= 'z') *str += 'A' + 'a';
640 return ret;
644 /*********************************************************************
645 * _strupr_s (NTDLL.@)
647 errno_t __cdecl _strupr_s( char *str, size_t len )
649 if (!str) return EINVAL;
651 if (strnlen( str, len ) == len)
653 *str = 0;
654 return EINVAL;
657 _strupr( str );
658 return 0;
662 /*********************************************************************
663 * _strlwr (NTDLL.@)
665 * Convert a string to lowercase
667 * PARAMS
668 * str [I/O] String to convert
670 * RETURNS
671 * str. There is no error return, if str is NULL or invalid, this
672 * function will crash.
674 LPSTR __cdecl _strlwr( LPSTR str )
676 LPSTR ret = str;
677 for ( ; *str; str++) if (*str >= 'A' && *str <= 'Z') *str += 'a' - 'A';
678 return ret;
682 /*********************************************************************
683 * _strlwr_s (NTDLL.@)
685 errno_t __cdecl _strlwr_s( char *str, size_t len )
687 if (!str) return EINVAL;
689 if (strnlen( str, len ) == len)
691 *str = 0;
692 return EINVAL;
694 _strlwr( str );
695 return 0;
699 /*********************************************************************
700 * toupper (NTDLL.@)
702 int __cdecl toupper( int c )
704 char str[4], *p = str;
705 WCHAR wc;
706 DWORD len;
708 memcpy( str, &c, sizeof(c) );
709 wc = RtlAnsiCharToUnicodeChar( &p );
710 if (RtlUpcaseUnicodeToMultiByteN( str, 2, &len, &wc, sizeof(wc) )) return c;
711 if (len == 2) return ((unsigned char)str[0] << 8) + (unsigned char)str[1];
712 return (unsigned char)str[0];
716 /*********************************************************************
717 * isalnum (NTDLL.@)
719 int __cdecl isalnum( int c )
721 return ctypes[c + 1] & (C1_LOWER | C1_UPPER | C1_DIGIT);
725 /*********************************************************************
726 * isalpha (NTDLL.@)
728 int __cdecl isalpha( int c )
730 return ctypes[c + 1] & (C1_LOWER | C1_UPPER);
734 /*********************************************************************
735 * iscntrl (NTDLL.@)
737 int __cdecl iscntrl( int c )
739 return ctypes[c + 1] & C1_CNTRL;
743 /*********************************************************************
744 * isdigit (NTDLL.@)
746 int __cdecl isdigit( int c )
748 return ctypes[c + 1] & C1_DIGIT;
752 /*********************************************************************
753 * isgraph (NTDLL.@)
755 int __cdecl isgraph( int c )
757 return ctypes[c + 1] & (C1_LOWER | C1_UPPER | C1_DIGIT | C1_PUNCT);
761 /*********************************************************************
762 * islower (NTDLL.@)
764 int __cdecl islower( int c )
766 return ctypes[c + 1] & C1_LOWER;
770 /*********************************************************************
771 * isprint (NTDLL.@)
773 int __cdecl isprint( int c )
775 return ctypes[c + 1] & (C1_LOWER | C1_UPPER | C1_DIGIT | C1_PUNCT | C1_BLANK);
779 /*********************************************************************
780 * ispunct (NTDLL.@)
782 int __cdecl ispunct( int c )
784 return ctypes[c + 1] & C1_PUNCT;
788 /*********************************************************************
789 * isspace (NTDLL.@)
791 int __cdecl isspace( int c )
793 return ctypes[c + 1] & C1_SPACE;
797 /*********************************************************************
798 * isupper (NTDLL.@)
800 int __cdecl isupper( int c )
802 return ctypes[c + 1] & C1_UPPER;
806 /*********************************************************************
807 * isxdigit (NTDLL.@)
809 int __cdecl isxdigit( int c )
811 return ctypes[c + 1] & C1_XDIGIT;
815 /*********************************************************************
816 * __isascii (NTDLL.@)
818 int CDECL __isascii(int c)
820 return (unsigned)c < 0x80;
824 /*********************************************************************
825 * __toascii (NTDLL.@)
827 int CDECL __toascii(int c)
829 return (unsigned)c & 0x7f;
833 /*********************************************************************
834 * __iscsym (NTDLL.@)
836 int CDECL __iscsym(int c)
838 return (c < 127 && (isalnum(c) || c == '_'));
842 /*********************************************************************
843 * __iscsymf (NTDLL.@)
845 int CDECL __iscsymf(int c)
847 return (c < 127 && (isalpha(c) || c == '_'));
851 /*********************************************************************
852 * _toupper (NTDLL.@)
854 int CDECL _toupper(int c)
856 return c - 0x20; /* sic */
860 /*********************************************************************
861 * _tolower (NTDLL.@)
863 int CDECL _tolower(int c)
865 return c + 0x20; /* sic */
869 /*********************************************************************
870 * strtok_s (NTDLL.@)
872 char * __cdecl strtok_s( char *str, const char *delim, char **ctx )
874 char *next;
876 if (!delim || !ctx) return NULL;
877 if (!str)
879 str = *ctx;
880 if (!str) return NULL;
882 while (*str && strchr( delim, *str )) str++;
883 if (!*str)
885 *ctx = str;
886 return NULL;
888 next = str + 1;
889 while (*next && !strchr( delim, *next )) next++;
890 if (*next) *next++ = 0;
891 *ctx = next;
892 return str;
896 static int char_to_int( char c )
898 if ('0' <= c && c <= '9') return c - '0';
899 if ('A' <= c && c <= 'Z') return c - 'A' + 10;
900 if ('a' <= c && c <= 'z') return c - 'a' + 10;
901 return -1;
904 /*********************************************************************
905 * strtol (NTDLL.@)
907 __msvcrt_long __cdecl strtol( const char *s, char **end, int base )
909 BOOL negative = FALSE, empty = TRUE;
910 LONG ret = 0;
912 if (base < 0 || base == 1 || base > 36) return 0;
913 if (end) *end = (char *)s;
914 while (isspace(*s)) s++;
916 if (*s == '-')
918 negative = TRUE;
919 s++;
921 else if (*s == '+') s++;
923 if ((base == 0 || base == 16) && !char_to_int( *s ) && (s[1] == 'x' || s[1] == 'X'))
925 base = 16;
926 s += 2;
928 if (base == 0) base = char_to_int( *s ) ? 10 : 8;
930 while (*s)
932 int v = char_to_int( *s );
933 if (v < 0 || v >= base) break;
934 if (negative) v = -v;
935 s++;
936 empty = FALSE;
938 if (!negative && (ret > MAXLONG / base || ret * base > MAXLONG - v))
939 ret = MAXLONG;
940 else if (negative && (ret < (LONG)MINLONG / base || ret * base < (LONG)(MINLONG - v)))
941 ret = MINLONG;
942 else
943 ret = ret * base + v;
946 if (end && !empty) *end = (char *)s;
947 return ret;
951 /*********************************************************************
952 * strtoul (NTDLL.@)
954 __msvcrt_ulong __cdecl strtoul( const char *s, char **end, int base )
956 BOOL negative = FALSE, empty = TRUE;
957 ULONG ret = 0;
959 if (base < 0 || base == 1 || base > 36) return 0;
960 if (end) *end = (char *)s;
961 while (isspace(*s)) s++;
963 if (*s == '-')
965 negative = TRUE;
966 s++;
968 else if (*s == '+') s++;
970 if ((base == 0 || base == 16) && !char_to_int( *s ) && (s[1] == 'x' || s[1] == 'X'))
972 base = 16;
973 s += 2;
975 if (base == 0) base = char_to_int( *s ) ? 10 : 8;
977 while (*s)
979 int v = char_to_int( *s );
980 if (v < 0 || v >= base) break;
981 s++;
982 empty = FALSE;
984 if (ret > MAXDWORD / base || ret * base > MAXDWORD - v)
985 ret = MAXDWORD;
986 else
987 ret = ret * base + v;
990 if (end && !empty) *end = (char *)s;
991 return negative ? -ret : ret;
995 /*********************************************************************
996 * _ultoa (NTDLL.@)
998 * Convert an unsigned long integer to a string.
1000 * RETURNS
1001 * str.
1003 * NOTES
1004 * - Converts value to a Nul terminated string which is copied to str.
1005 * - The maximum length of the copied str is 33 bytes.
1006 * - Does not check if radix is in the range of 2 to 36.
1007 * - If str is NULL it crashes, as the native function does.
1009 char * __cdecl _ultoa( __msvcrt_ulong value, char *str, int radix )
1011 char buffer[33];
1012 char *pos;
1013 int digit;
1015 pos = &buffer[32];
1016 *pos = '\0';
1018 do {
1019 digit = value % radix;
1020 value = value / radix;
1021 if (digit < 10) {
1022 *--pos = '0' + digit;
1023 } else {
1024 *--pos = 'a' + digit - 10;
1025 } /* if */
1026 } while (value != 0L);
1028 memcpy(str, pos, &buffer[32] - pos + 1);
1029 return str;
1033 /*********************************************************************
1034 * _ltoa (NTDLL.@)
1036 * Convert a long integer to a string.
1038 * RETURNS
1039 * str.
1041 * NOTES
1042 * - Converts value to a Nul terminated string which is copied to str.
1043 * - The maximum length of the copied str is 33 bytes. If radix
1044 * is 10 and value is negative, the value is converted with sign.
1045 * - Does not check if radix is in the range of 2 to 36.
1046 * - If str is NULL it crashes, as the native function does.
1048 char * __cdecl _ltoa( __msvcrt_long value, char *str, int radix )
1050 ULONG val;
1051 int negative;
1052 char buffer[33];
1053 char *pos;
1054 int digit;
1056 if (value < 0 && radix == 10) {
1057 negative = 1;
1058 val = -value;
1059 } else {
1060 negative = 0;
1061 val = value;
1062 } /* if */
1064 pos = &buffer[32];
1065 *pos = '\0';
1067 do {
1068 digit = val % radix;
1069 val = val / radix;
1070 if (digit < 10) {
1071 *--pos = '0' + digit;
1072 } else {
1073 *--pos = 'a' + digit - 10;
1074 } /* if */
1075 } while (val != 0L);
1077 if (negative) {
1078 *--pos = '-';
1079 } /* if */
1081 memcpy(str, pos, &buffer[32] - pos + 1);
1082 return str;
1086 /*********************************************************************
1087 * _itoa (NTDLL.@)
1089 * Converts an integer to a string.
1091 * RETURNS
1092 * str.
1094 * NOTES
1095 * - Converts value to a '\0' terminated string which is copied to str.
1096 * - The maximum length of the copied str is 33 bytes. If radix
1097 * is 10 and value is negative, the value is converted with sign.
1098 * - Does not check if radix is in the range of 2 to 36.
1099 * - If str is NULL it crashes, as the native function does.
1101 char * __cdecl _itoa(
1102 int value, /* [I] Value to be converted */
1103 char *str, /* [O] Destination for the converted value */
1104 int radix) /* [I] Number base for conversion */
1106 return _ltoa(value, str, radix);
1110 /*********************************************************************
1111 * _ui64toa (NTDLL.@)
1113 * Converts a large unsigned integer to a string.
1115 * RETURNS
1116 * str.
1118 * NOTES
1119 * - Converts value to a '\0' terminated string which is copied to str.
1120 * - The maximum length of the copied str is 65 bytes.
1121 * - Does not check if radix is in the range of 2 to 36.
1122 * - If str is NULL it crashes, as the native function does.
1124 char * __cdecl _ui64toa(
1125 ULONGLONG value, /* [I] Value to be converted */
1126 char *str, /* [O] Destination for the converted value */
1127 int radix) /* [I] Number base for conversion */
1129 char buffer[65];
1130 char *pos;
1131 int digit;
1133 pos = &buffer[64];
1134 *pos = '\0';
1136 do {
1137 digit = value % radix;
1138 value = value / radix;
1139 if (digit < 10) {
1140 *--pos = '0' + digit;
1141 } else {
1142 *--pos = 'a' + digit - 10;
1143 } /* if */
1144 } while (value != 0L);
1146 memcpy(str, pos, &buffer[64] - pos + 1);
1147 return str;
1151 /*********************************************************************
1152 * _i64toa (NTDLL.@)
1154 * Converts a large integer to a string.
1156 * RETURNS
1157 * str.
1159 * NOTES
1160 * - Converts value to a Nul terminated string which is copied to str.
1161 * - The maximum length of the copied str is 65 bytes. If radix
1162 * is 10 and value is negative, the value is converted with sign.
1163 * - Does not check if radix is in the range of 2 to 36.
1164 * - If str is NULL it crashes, as the native function does.
1166 * DIFFERENCES
1167 * - The native DLL converts negative values (for base 10) wrong:
1168 *| -1 is converted to -18446744073709551615
1169 *| -2 is converted to -18446744073709551614
1170 *| -9223372036854775807 is converted to -9223372036854775809
1171 *| -9223372036854775808 is converted to -9223372036854775808
1172 * The native msvcrt _i64toa function and our ntdll _i64toa function
1173 * do not have this bug.
1175 char * __cdecl _i64toa(
1176 LONGLONG value, /* [I] Value to be converted */
1177 char *str, /* [O] Destination for the converted value */
1178 int radix) /* [I] Number base for conversion */
1180 ULONGLONG val;
1181 int negative;
1182 char buffer[65];
1183 char *pos;
1184 int digit;
1186 if (value < 0 && radix == 10) {
1187 negative = 1;
1188 val = -value;
1189 } else {
1190 negative = 0;
1191 val = value;
1192 } /* if */
1194 pos = &buffer[64];
1195 *pos = '\0';
1197 do {
1198 digit = val % radix;
1199 val = val / radix;
1200 if (digit < 10) {
1201 *--pos = '0' + digit;
1202 } else {
1203 *--pos = 'a' + digit - 10;
1204 } /* if */
1205 } while (val != 0L);
1207 if (negative) {
1208 *--pos = '-';
1209 } /* if */
1211 memcpy(str, pos, &buffer[64] - pos + 1);
1212 return str;
1216 /*********************************************************************
1217 * _ui64toa_s (NTDLL.@)
1219 errno_t __cdecl _ui64toa_s( unsigned __int64 value, char *str, size_t size, int radix )
1221 char buffer[65], *pos;
1223 if (!str || !size) return EINVAL;
1224 if (radix < 2 || radix > 36)
1226 str[0] = 0;
1227 return EINVAL;
1230 pos = buffer + 64;
1231 *pos = 0;
1233 do {
1234 int digit = value % radix;
1235 value = value / radix;
1236 if (digit < 10)
1237 *--pos = '0' + digit;
1238 else
1239 *--pos = 'a' + digit - 10;
1240 } while (value != 0);
1242 if (buffer - pos + 65 > size)
1244 str[0] = 0;
1245 return ERANGE;
1247 memcpy( str, pos, buffer - pos + 65 );
1248 return 0;
1252 /*********************************************************************
1253 * _ultoa_s (NTDLL.@)
1255 errno_t __cdecl _ultoa_s( __msvcrt_ulong value, char *str, size_t size, int radix )
1257 return _ui64toa_s( value, str, size, radix );
1261 /*********************************************************************
1262 * _i64toa_s (NTDLL.@)
1264 errno_t __cdecl _i64toa_s( __int64 value, char *str, size_t size, int radix )
1266 unsigned __int64 val;
1267 BOOL is_negative;
1268 char buffer[65], *pos;
1270 if (!str || !size) return EINVAL;
1271 if (radix < 2 || radix > 36)
1273 str[0] = 0;
1274 return EINVAL;
1277 if (value < 0 && radix == 10)
1279 is_negative = TRUE;
1280 val = -value;
1282 else
1284 is_negative = FALSE;
1285 val = value;
1288 pos = buffer + 64;
1289 *pos = 0;
1293 unsigned int digit = val % radix;
1294 val /= radix;
1296 if (digit < 10)
1297 *--pos = '0' + digit;
1298 else
1299 *--pos = 'a' + digit - 10;
1301 while (val != 0);
1303 if (is_negative) *--pos = '-';
1305 if (buffer - pos + 65 > size)
1307 str[0] = 0;
1308 return ERANGE;
1310 memcpy( str, pos, buffer - pos + 65 );
1311 return 0;
1315 /*********************************************************************
1316 * _ltoa_s (NTDLL.@)
1318 errno_t __cdecl _ltoa_s( __msvcrt_long value, char *str, size_t size, int radix )
1320 if (value < 0 && radix == 10) return _i64toa_s( value, str, size, radix );
1321 return _ui64toa_s( (__msvcrt_ulong)value, str, size, radix );
1325 /*********************************************************************
1326 * _itoa_s (NTDLL.@)
1328 errno_t __cdecl _itoa_s( int value, char *str, size_t size, int radix )
1330 if (value < 0 && radix == 10) return _i64toa_s( value, str, size, radix );
1331 return _ui64toa_s( (unsigned int)value, str, size, radix );
1335 /*********************************************************************
1336 * _atoi64 (NTDLL.@)
1338 * Convert a string to a large integer.
1340 * PARAMS
1341 * str [I] String to be converted
1343 * RETURNS
1344 * Success: The integer value represented by str.
1345 * Failure: 0. Note that this cannot be distinguished from a successful
1346 * return, if the string contains "0".
1348 * NOTES
1349 * - Accepts: {whitespace} [+|-] {digits}
1350 * - No check is made for value overflow, only the lower 64 bits are assigned.
1351 * - If str is NULL it crashes, as the native function does.
1353 LONGLONG __cdecl _atoi64( const char *str )
1355 ULONGLONG RunningTotal = 0;
1356 BOOL bMinus = FALSE;
1358 while (*str == ' ' || (*str >= '\011' && *str <= '\015')) {
1359 str++;
1360 } /* while */
1362 if (*str == '+') {
1363 str++;
1364 } else if (*str == '-') {
1365 bMinus = TRUE;
1366 str++;
1367 } /* if */
1369 while (*str >= '0' && *str <= '9') {
1370 RunningTotal = RunningTotal * 10 + *str - '0';
1371 str++;
1372 } /* while */
1374 return bMinus ? -RunningTotal : RunningTotal;
1378 /*********************************************************************
1379 * atoi (NTDLL.@)
1381 int __cdecl atoi( const char *nptr )
1383 return _atoi64( nptr );
1387 /*********************************************************************
1388 * atol (NTDLL.@)
1390 __msvcrt_long __cdecl atol( const char *nptr )
1392 return _atoi64( nptr );
1396 /* helper function for *scanf. Returns the value of character c in the
1397 * given base, or -1 if the given character is not a digit of the base.
1399 static int char2digit( char c, int base )
1401 if ((c >= '0' && c <= '9') && (c <= '0'+base-1)) return (c-'0');
1402 if (base <= 10) return -1;
1403 if ((c >= 'A') && (c <= 'Z') && (c <= 'A'+base-11)) return (c-'A'+10);
1404 if ((c >= 'a') && (c <= 'z') && (c <= 'a'+base-11)) return (c-'a'+10);
1405 return -1;
1409 static int vsscanf( const char *str, const char *format, va_list ap)
1411 int rd = 0, consumed = 0;
1412 int nch;
1413 if (!*format) return 0;
1415 nch = (consumed++, *str++);
1416 if (nch == '\0')
1417 return EOF;
1419 while (*format)
1421 if (isspace( *format ))
1423 /* skip whitespace */
1424 while ((nch != '\0') && isspace( nch ))
1425 nch = (consumed++, *str++);
1427 else if (*format == '%')
1429 int st = 0;
1430 BOOLEAN suppress = 0;
1431 int width = 0;
1432 int base;
1433 int h_prefix = 0;
1434 BOOLEAN l_prefix = FALSE;
1435 BOOLEAN w_prefix = FALSE;
1436 BOOLEAN I64_prefix = FALSE;
1437 BOOLEAN prefix_finished = FALSE;
1438 format++;
1439 /* a leading asterisk means 'suppress assignment of this field' */
1440 if (*format == '*')
1442 format++;
1443 suppress = TRUE;
1445 /* look for width specification */
1446 while (isdigit( *format ))
1448 width *= 10;
1449 width += *format++ - '0';
1451 if (width == 0) width = -1; /* no width spec seen */
1452 /* read prefix (if any) */
1453 while (!prefix_finished)
1455 switch (*format)
1457 case 'h': h_prefix++; break;
1458 case 'l':
1459 if (*(format+1) == 'l')
1461 I64_prefix = TRUE;
1462 format++;
1464 l_prefix = TRUE;
1465 break;
1466 case 'w': w_prefix = TRUE; break;
1467 case 'I':
1468 if (*(format + 1) == '6' &&
1469 *(format + 2) == '4')
1471 I64_prefix = TRUE;
1472 format += 2;
1474 break;
1475 default:
1476 prefix_finished = TRUE;
1478 if (!prefix_finished) format++;
1480 /* read type */
1481 switch (*format)
1483 case 'p':
1484 case 'P': /* pointer. */
1485 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = TRUE;
1486 /* fall through */
1487 case 'x':
1488 case 'X': /* hexadecimal integer. */
1489 base = 16;
1490 goto number;
1491 case 'o': /* octal integer */
1492 base = 8;
1493 goto number;
1494 case 'u': /* unsigned decimal integer */
1495 base = 10;
1496 goto number;
1497 case 'd': /* signed decimal integer */
1498 base = 10;
1499 goto number;
1500 case 'i': /* generic integer */
1501 base = 0;
1502 number:
1504 /* read an integer */
1505 ULONGLONG cur = 0;
1506 BOOLEAN negative = FALSE;
1507 BOOLEAN seendigit = FALSE;
1508 /* skip initial whitespace */
1509 while ((nch != '\0') && isspace( nch ))
1510 nch = (consumed++, *str++);
1511 /* get sign */
1512 if (nch == '-' || nch == '+')
1514 negative = (nch == '-');
1515 nch = (consumed++, *str++);
1516 if (width > 0) width--;
1518 /* look for leading indication of base */
1519 if (width != 0 && nch == '0' && *format != 'p' && *format != 'P')
1521 nch = (consumed++, *str++);
1522 if (width > 0) width--;
1523 seendigit = TRUE;
1524 if (width != 0 && (nch == 'x' || nch == 'X'))
1526 if (base == 0)
1527 base = 16;
1528 if (base == 16)
1530 nch = (consumed++, *str++);
1531 if (width > 0) width--;
1532 seendigit = FALSE;
1534 } else if (base == 0)
1535 base = 8;
1537 /* format %i without indication of base */
1538 if (base == 0)
1539 base = 10;
1540 /* throw away leading zeros */
1541 while (width != 0 && nch == '0')
1543 nch = (consumed++, *str++);
1544 if (width > 0) width--;
1545 seendigit = TRUE;
1547 if (width != 0 && char2digit( nch, base ) != -1)
1549 cur = char2digit( nch, base );
1550 nch = (consumed++, *str++);
1551 if (width > 0) width--;
1552 seendigit = TRUE;
1554 /* read until no more digits */
1555 while (width != 0 && nch != '\0' && char2digit( nch, base ) != -1)
1557 cur = cur*base + char2digit( nch, base );
1558 nch = (consumed++, *str++);
1559 if (width > 0) width--;
1560 seendigit = TRUE;
1562 /* okay, done! */
1563 if (!seendigit) break; /* not a valid number */
1564 st = 1;
1565 if (!suppress)
1567 #define _SET_NUMBER_( type ) *va_arg( ap, type* ) = negative ? -cur : cur
1568 if (I64_prefix) _SET_NUMBER_( LONGLONG );
1569 else if (l_prefix) _SET_NUMBER_( LONG );
1570 else if (h_prefix == 1) _SET_NUMBER_( short int );
1571 else _SET_NUMBER_( int );
1574 break;
1575 /* According to msdn,
1576 * 's' reads a character string in a call to fscanf
1577 * and 'S' a wide character string and vice versa in a
1578 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
1579 * this behaviour. 'h' forces reading char * but 'l' and 'w'
1580 * force reading WCHAR. */
1581 case 's':
1582 if (w_prefix || l_prefix) goto widecharstring;
1583 else if (h_prefix) goto charstring;
1584 else goto charstring;
1585 case 'S':
1586 if (w_prefix || l_prefix) goto widecharstring;
1587 else if (h_prefix) goto charstring;
1588 else goto widecharstring;
1589 charstring:
1590 { /* read a word into a char */
1591 char *sptr = suppress ? NULL : va_arg( ap, char * );
1592 char *sptr_beg = sptr;
1593 unsigned size = UINT_MAX;
1594 /* skip initial whitespace */
1595 while (nch != '\0' && isspace( nch ))
1596 nch = (consumed++, *str++);
1597 /* read until whitespace */
1598 while (width != 0 && nch != '\0' && !isspace( nch ))
1600 if (!suppress)
1602 *sptr++ = nch;
1603 if(size > 1) size--;
1604 else
1606 *sptr_beg = 0;
1607 return rd;
1610 st++;
1611 nch = (consumed++, *str++);
1612 if (width > 0) width--;
1614 /* terminate */
1615 if (st && !suppress) *sptr = 0;
1617 break;
1618 widecharstring:
1619 { /* read a word into a WCHAR * */
1620 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1621 WCHAR *sptr_beg = sptr;
1622 unsigned size = UINT_MAX;
1623 /* skip initial whitespace */
1624 while (nch != '\0' && isspace( nch ))
1625 nch = (consumed++, *str++);
1626 /* read until whitespace */
1627 while (width != 0 && nch != '\0' && !isspace( nch ))
1629 if (!suppress)
1631 *sptr++ = nch;
1632 if (size > 1) size--;
1633 else
1635 *sptr_beg = 0;
1636 return rd;
1639 st++;
1640 nch = (consumed++, *str++);
1641 if (width > 0) width--;
1643 /* terminate */
1644 if (st && !suppress) *sptr = 0;
1646 break;
1647 /* 'c' and 'C work analogously to 's' and 'S' as described
1648 * above */
1649 case 'c':
1650 if (w_prefix || l_prefix) goto widecharacter;
1651 else if (h_prefix) goto character;
1652 else goto character;
1653 case 'C':
1654 if (w_prefix || l_prefix) goto widecharacter;
1655 else if (h_prefix) goto character;
1656 else goto widecharacter;
1657 character:
1658 { /* read single character into char */
1659 char *sptr = suppress ? NULL : va_arg( ap, char * );
1660 char *sptr_beg = sptr;
1661 unsigned size = UINT_MAX;
1662 if (width == -1) width = 1;
1663 while (width && nch != '\0')
1665 if (!suppress)
1667 *sptr++ = nch;
1668 if(size) size--;
1669 else
1671 *sptr_beg = 0;
1672 return rd;
1675 st++;
1676 width--;
1677 nch = (consumed++, *str++);
1680 break;
1681 widecharacter:
1682 { /* read single character into a WCHAR */
1683 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1684 WCHAR *sptr_beg = sptr;
1685 unsigned size = UINT_MAX;
1686 if (width == -1) width = 1;
1687 while (width && nch != '\0')
1689 if (!suppress)
1691 *sptr++ = nch;
1692 if (size) size--;
1693 else
1695 *sptr_beg = 0;
1696 return rd;
1699 st++;
1700 width--;
1701 nch = (consumed++, *str++);
1704 break;
1705 case 'n':
1707 if (!suppress)
1709 int *n = va_arg( ap, int * );
1710 *n = consumed - 1;
1712 /* This is an odd one: according to the standard,
1713 * "Execution of a %n directive does not increment the
1714 * assignment count returned at the completion of
1715 * execution" even if it wasn't suppressed with the
1716 * '*' flag. The Corrigendum to the standard seems
1717 * to contradict this (comment out the assignment to
1718 * suppress below if you want to implement these
1719 * alternate semantics) but the windows program I'm
1720 * looking at expects the behavior I've coded here
1721 * (which happens to be what glibc does as well).
1723 suppress = TRUE;
1724 st = 1;
1726 break;
1727 case '[':
1729 char *sptr = suppress ? NULL : va_arg( ap, char * );
1730 char *sptr_beg = sptr;
1731 RTL_BITMAP bitMask;
1732 ULONG Mask[8] = { 0 };
1733 BOOLEAN invert = FALSE; /* Set if we are NOT to find the chars */
1734 unsigned size = UINT_MAX;
1736 RtlInitializeBitMap( &bitMask, Mask, sizeof(Mask) * 8 );
1738 /* Read the format */
1739 format++;
1740 if (*format == '^')
1742 invert = TRUE;
1743 format++;
1745 if (*format == ']')
1747 RtlSetBits( &bitMask, ']', 1 );
1748 format++;
1750 while (*format && (*format != ']'))
1752 /* According to msdn:
1753 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
1754 if ((*format == '-') && (*(format + 1) != ']'))
1756 if ((*(format - 1)) < *(format + 1))
1757 RtlSetBits( &bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1) );
1758 else
1759 RtlSetBits( &bitMask, *(format + 1) , *(format - 1) - *(format + 1) );
1760 format++;
1762 else
1763 RtlSetBits( &bitMask, *format, 1 );
1764 format++;
1766 /* read until char is not suitable */
1767 while (width != 0 && nch != '\0')
1769 if (!invert)
1771 if(RtlAreBitsSet( &bitMask, nch, 1 ))
1773 if (!suppress) *sptr++ = nch;
1775 else
1776 break;
1778 else
1780 if (RtlAreBitsClear( &bitMask, nch, 1 ))
1782 if (!suppress) *sptr++ = nch;
1784 else
1785 break;
1787 st++;
1788 nch = (consumed++, *str++);
1789 if (width > 0) width--;
1790 if(size > 1) size--;
1791 else
1793 if (!suppress) *sptr_beg = 0;
1794 return rd;
1797 /* terminate */
1798 if (!suppress) *sptr = 0;
1800 break;
1801 default:
1802 /* From spec: "if a percent sign is followed by a character
1803 * that has no meaning as a format-control character, that
1804 * character and the following characters are treated as
1805 * an ordinary sequence of characters, that is, a sequence
1806 * of characters that must match the input. For example,
1807 * to specify that a percent-sign character is to be input,
1808 * use %%." */
1809 while (nch != '\0' && isspace( nch ))
1810 nch = (consumed++, *str++);
1811 if (nch == *format)
1813 suppress = TRUE; /* whoops no field to be read */
1814 st = 1; /* but we got what we expected */
1815 nch = (consumed++, *str++);
1817 break;
1819 if (st && !suppress) rd++;
1820 else if (!st) break;
1822 /* A non-white-space character causes scanf to read, but not store,
1823 * a matching non-white-space character. */
1824 else
1826 if (nch == *format)
1827 nch = (consumed++, *str++);
1828 else break;
1830 format++;
1832 if (nch != '\0')
1834 consumed--, str--;
1837 return rd;
1841 /*********************************************************************
1842 * sscanf (NTDLL.@)
1844 int WINAPIV sscanf( const char *str, const char *format, ... )
1846 int ret;
1847 va_list valist;
1848 va_start( valist, format );
1849 ret = vsscanf( str, format, valist );
1850 va_end( valist );
1851 return ret;
1855 /******************************************************************
1856 * _splitpath_s (NTDLL.@)
1858 errno_t __cdecl _splitpath_s( const char *inpath, char *drive, size_t sz_drive,
1859 char *dir, size_t sz_dir, char *fname, size_t sz_fname,
1860 char *ext, size_t sz_ext )
1862 const char *p, *end;
1864 if (!inpath || (!drive && sz_drive) ||
1865 (drive && !sz_drive) ||
1866 (!dir && sz_dir) ||
1867 (dir && !sz_dir) ||
1868 (!fname && sz_fname) ||
1869 (fname && !sz_fname) ||
1870 (!ext && sz_ext) ||
1871 (ext && !sz_ext))
1872 return EINVAL;
1874 if (inpath[0] && inpath[1] == ':')
1876 if (drive)
1878 if (sz_drive <= 2) goto error;
1879 drive[0] = inpath[0];
1880 drive[1] = inpath[1];
1881 drive[2] = 0;
1883 inpath += 2;
1885 else if (drive) drive[0] = '\0';
1887 /* look for end of directory part */
1888 end = NULL;
1889 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1891 if (end) /* got a directory */
1893 if (dir)
1895 if (sz_dir <= end - inpath) goto error;
1896 memcpy( dir, inpath, end - inpath );
1897 dir[end - inpath] = 0;
1899 inpath = end;
1901 else if (dir) dir[0] = 0;
1903 /* look for extension: what's after the last dot */
1904 end = NULL;
1905 for (p = inpath; *p; p++) if (*p == '.') end = p;
1907 if (!end) end = p; /* there's no extension */
1909 if (fname)
1911 if (sz_fname <= end - inpath) goto error;
1912 memcpy( fname, inpath, end - inpath );
1913 fname[end - inpath] = 0;
1915 if (ext)
1917 if (sz_ext <= strlen(end)) goto error;
1918 strcpy( ext, end );
1920 return 0;
1922 error:
1923 if (drive) drive[0] = 0;
1924 if (dir) dir[0] = 0;
1925 if (fname) fname[0]= 0;
1926 if (ext) ext[0]= 0;
1927 return ERANGE;
1931 /*********************************************************************
1932 * _splitpath (NTDLL.@)
1934 * Split a path into its component pieces.
1936 * PARAMS
1937 * inpath [I] Path to split
1938 * drv [O] Destination for drive component (e.g. "A:"). Must be at least 3 characters.
1939 * dir [O] Destination for directory component. Should be at least MAX_PATH characters.
1940 * fname [O] Destination for File name component. Should be at least MAX_PATH characters.
1941 * ext [O] Destination for file extension component. Should be at least MAX_PATH characters.
1943 * RETURNS
1944 * Nothing.
1946 void __cdecl _splitpath(const char* inpath, char * drv, char * dir,
1947 char* fname, char * ext )
1949 _splitpath_s( inpath, drv, drv ? _MAX_DRIVE : 0, dir, dir ? _MAX_DIR : 0,
1950 fname, fname ? _MAX_FNAME : 0, ext, ext ? _MAX_EXT : 0 );
1954 /*********************************************************************
1955 * _makepath_s (NTDLL.@)
1957 errno_t __cdecl _makepath_s( char *path, size_t size, const char *drive,
1958 const char *directory, const char *filename,
1959 const char *extension )
1961 char *p = path;
1963 if (!path || !size) return EINVAL;
1965 if (drive && drive[0])
1967 if (size <= 2) goto range;
1968 *p++ = drive[0];
1969 *p++ = ':';
1970 size -= 2;
1973 if (directory && directory[0])
1975 unsigned int len = strlen(directory);
1976 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1977 unsigned int copylen = min(size - 1, len);
1979 if (size < 2) goto range;
1980 memmove(p, directory, copylen);
1981 if (size <= len) goto range;
1982 p += copylen;
1983 size -= copylen;
1984 if (needs_separator)
1986 if (size < 2) goto range;
1987 *p++ = '\\';
1988 size -= 1;
1992 if (filename && filename[0])
1994 unsigned int len = strlen(filename);
1995 unsigned int copylen = min(size - 1, len);
1997 if (size < 2) goto range;
1998 memmove(p, filename, copylen);
1999 if (size <= len) goto range;
2000 p += len;
2001 size -= len;
2004 if (extension && extension[0])
2006 unsigned int len = strlen(extension);
2007 unsigned int needs_period = extension[0] != '.';
2008 unsigned int copylen;
2010 if (size < 2) goto range;
2011 if (needs_period)
2013 *p++ = '.';
2014 size -= 1;
2016 copylen = min(size - 1, len);
2017 memcpy(p, extension, copylen);
2018 if (size <= len) goto range;
2019 p += copylen;
2022 *p = 0;
2023 return 0;
2025 range:
2026 path[0] = 0;
2027 return ERANGE;