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
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] =
44 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
45 0x0020, 0x0028, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
47 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
48 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
50 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
51 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
53 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
54 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
56 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
57 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
59 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
60 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
62 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
63 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
65 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
66 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020
70 /*********************************************************************
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
;
82 /*********************************************************************
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;
98 /*********************************************************************
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
++;
117 while (n
--) *d
-- = *s
--;
123 /*********************************************************************
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
++;
139 while (n
--) *d
-- = *s
--;
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
;
154 memset( dst
, 0, len
);
159 memset( dst
, 0, len
);
162 memmove( dst
, src
, count
);
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
);
181 static inline void memset_aligned_32( unsigned char *d
, uint64_t v
, size_t n
)
183 unsigned char *end
= d
+ n
;
186 *(uint64_t *)(d
+ 0) = v
;
187 *(uint64_t *)(d
+ 8) = v
;
188 *(uint64_t *)(d
+ 16) = v
;
189 *(uint64_t *)(d
+ 24) = v
;
194 /*********************************************************************
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);
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
;
221 memset_aligned_32( d
+ a
, v
, n
);
226 *(unaligned_ui64
*)d
= v
;
227 *(unaligned_ui64
*)(d
+ n
- 8) = v
;
232 *(unaligned_ui32
*)d
= v
;
233 *(unaligned_ui32
*)(d
+ n
- 4) = v
;
238 *(unaligned_ui16
*)d
= v
;
239 *(unaligned_ui16
*)(d
+ n
- 2) = v
;
251 /*********************************************************************
254 char * __cdecl
strcat( char *dst
, const char *src
)
258 while ((*d
++ = *src
++));
263 /*********************************************************************
266 errno_t __cdecl
strcat_s( char *dst
, size_t len
, const char *src
)
270 if (!dst
|| !len
) 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;
283 /*********************************************************************
286 char * __cdecl
strchr( const char *str
, int c
)
288 do { if (*str
== (char)c
) return (char *)(ULONG_PTR
)str
; } while (*str
++);
293 /*********************************************************************
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;
305 /*********************************************************************
308 char * __cdecl
strcpy( char *dst
, const char *src
)
311 while ((*d
++ = *src
++));
316 /*********************************************************************
319 errno_t __cdecl
strcpy_s( char *dst
, size_t len
, const char *src
)
323 if (!dst
|| !len
) return EINVAL
;
330 for (i
= 0; i
< len
; i
++) if (!(dst
[i
] = src
[i
])) return 0;
336 /*********************************************************************
339 size_t __cdecl
strcspn( const char *str
, const char *reject
)
342 for (ptr
= str
; *ptr
; ptr
++) if (strchr( reject
, *ptr
)) break;
347 /*********************************************************************
350 size_t __cdecl
strlen( const char *str
)
358 /*********************************************************************
361 char * __cdecl
strncat( char *dst
, const char *src
, size_t len
)
365 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
371 /*********************************************************************
372 * strncat_s (NTDLL.@)
374 errno_t __cdecl
strncat_s( char *dst
, size_t len
, const char *src
, size_t count
)
378 if (!dst
|| !len
) return EINVAL
;
379 if (!count
) return 0;
386 for (i
= 0; i
< len
; i
++) if (!dst
[i
]) break;
394 for (j
= 0; (j
+ i
) < len
; j
++)
396 if (count
== _TRUNCATE
&& j
+ i
== len
- 1)
401 if (j
== count
|| !(dst
[j
+ i
] = src
[j
]))
412 /*********************************************************************
415 int __cdecl
strncmp( const char *str1
, const char *str2
, size_t len
)
418 while (--len
&& *str1
&& *str1
== *str2
) { str1
++; str2
++; }
419 return (unsigned char)*str1
- (unsigned char)*str2
;
423 /*********************************************************************
427 char * __cdecl
strncpy( char *dst
, const char *src
, size_t len
)
430 for (d
= dst
; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
431 while (len
--) *d
++ = 0;
436 /*********************************************************************
437 * strncpy_s (NTDLL.@)
439 errno_t __cdecl
strncpy_s( char *dst
, size_t len
, const char *src
, size_t count
)
445 if (dst
&& len
) *dst
= 0;
448 if (!dst
|| !len
) return EINVAL
;
455 if (count
!= _TRUNCATE
&& count
< len
)
460 for (i
= 0; i
< end
; i
++)
461 if (!(dst
[i
] = src
[i
])) return 0;
463 if (count
== _TRUNCATE
)
478 /*********************************************************************
481 size_t __cdecl
strnlen( const char *str
, size_t len
)
484 for (s
= str
; len
&& *s
; s
++, len
--) ;
489 /*********************************************************************
492 char * __cdecl
strpbrk( const char *str
, const char *accept
)
494 for ( ; *str
; str
++) if (strchr( accept
, *str
)) return (char *)(ULONG_PTR
)str
;
499 /*********************************************************************
502 char * __cdecl
strrchr( const char *str
, int c
)
505 do { if (*str
== (char)c
) ret
= (char *)(ULONG_PTR
)str
; } while (*str
++);
510 /*********************************************************************
513 size_t __cdecl
strspn( const char *str
, const char *accept
)
516 for (ptr
= str
; *ptr
; ptr
++) if (!strchr( accept
, *ptr
)) break;
521 /*********************************************************************
524 char * __cdecl
strstr( const char *str
, const char *sub
)
528 const char *p1
= str
, *p2
= sub
;
529 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
530 if (!*p2
) return (char *)str
;
537 /*********************************************************************
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
;
549 /*********************************************************************
552 int __cdecl
tolower( int c
)
554 return (char)c
>= 'A' && (char)c
<= 'Z' ? c
- 'A' + 'a' : c
;
558 /*********************************************************************
561 * Compare two blocks of memory as strings, ignoring case.
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
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.
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
;
582 if ((ret
= tolower(*s1
) - tolower(*s2
))) break;
590 /*********************************************************************
591 * _strnicmp (NTDLL.@)
593 int __cdecl
_strnicmp( LPCSTR str1
, LPCSTR str2
, size_t n
)
599 l1
= (unsigned char)tolower(*str1
);
600 l2
= (unsigned char)tolower(*str2
);
603 if (sizeof(void *) > sizeof(int)) return l1
- l2
;
604 return l1
- l2
> 0 ? 1 : -1;
614 /*********************************************************************
618 int __cdecl
_stricmp( LPCSTR str1
, LPCSTR str2
)
620 return _strnicmp( str1
, str2
, -1 );
624 /*********************************************************************
627 * Convert a string to upper case.
630 * str [I/O] String to convert
633 * str. There is no error return, if str is NULL or invalid, this
634 * function will crash.
636 LPSTR __cdecl
_strupr( LPSTR str
)
639 for ( ; *str
; str
++) if (*str
>= 'a' && *str
<= 'z') *str
+= 'A' + 'a';
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
)
662 /*********************************************************************
665 * Convert a string to lowercase
668 * str [I/O] String to convert
671 * str. There is no error return, if str is NULL or invalid, this
672 * function will crash.
674 LPSTR __cdecl
_strlwr( LPSTR str
)
677 for ( ; *str
; str
++) if (*str
>= 'A' && *str
<= 'Z') *str
+= 'a' - 'A';
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
)
699 /*********************************************************************
702 int __cdecl
toupper( int c
)
704 char str
[4], *p
= str
;
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 /*********************************************************************
719 int __cdecl
isalnum( int c
)
721 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
);
725 /*********************************************************************
728 int __cdecl
isalpha( int c
)
730 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
);
734 /*********************************************************************
737 int __cdecl
iscntrl( int c
)
739 return ctypes
[c
+ 1] & C1_CNTRL
;
743 /*********************************************************************
746 int __cdecl
isdigit( int c
)
748 return ctypes
[c
+ 1] & C1_DIGIT
;
752 /*********************************************************************
755 int __cdecl
isgraph( int c
)
757 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
| C1_PUNCT
);
761 /*********************************************************************
764 int __cdecl
islower( int c
)
766 return ctypes
[c
+ 1] & C1_LOWER
;
770 /*********************************************************************
773 int __cdecl
isprint( int c
)
775 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
| C1_PUNCT
| C1_BLANK
);
779 /*********************************************************************
782 int __cdecl
ispunct( int c
)
784 return ctypes
[c
+ 1] & C1_PUNCT
;
788 /*********************************************************************
791 int __cdecl
isspace( int c
)
793 return ctypes
[c
+ 1] & C1_SPACE
;
797 /*********************************************************************
800 int __cdecl
isupper( int c
)
802 return ctypes
[c
+ 1] & C1_UPPER
;
806 /*********************************************************************
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 /*********************************************************************
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 /*********************************************************************
854 int CDECL
_toupper(int c
)
856 return c
- 0x20; /* sic */
860 /*********************************************************************
863 int CDECL
_tolower(int c
)
865 return c
+ 0x20; /* sic */
869 /*********************************************************************
872 char * __cdecl
strtok_s( char *str
, const char *delim
, char **ctx
)
876 if (!delim
|| !ctx
) return NULL
;
880 if (!str
) return NULL
;
882 while (*str
&& strchr( delim
, *str
)) str
++;
889 while (*next
&& !strchr( delim
, *next
)) next
++;
890 if (*next
) *next
++ = 0;
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;
904 /*********************************************************************
907 __msvcrt_long __cdecl
strtol( const char *s
, char **end
, int base
)
909 BOOL negative
= FALSE
, empty
= TRUE
;
912 if (base
< 0 || base
== 1 || base
> 36) return 0;
913 if (end
) *end
= (char *)s
;
914 while (isspace(*s
)) s
++;
921 else if (*s
== '+') s
++;
923 if ((base
== 0 || base
== 16) && !char_to_int( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
928 if (base
== 0) base
= char_to_int( *s
) ? 10 : 8;
932 int v
= char_to_int( *s
);
933 if (v
< 0 || v
>= base
) break;
934 if (negative
) v
= -v
;
938 if (!negative
&& (ret
> MAXLONG
/ base
|| ret
* base
> MAXLONG
- v
))
940 else if (negative
&& (ret
< (LONG
)MINLONG
/ base
|| ret
* base
< (LONG
)(MINLONG
- v
)))
943 ret
= ret
* base
+ v
;
946 if (end
&& !empty
) *end
= (char *)s
;
951 /*********************************************************************
954 __msvcrt_ulong __cdecl
strtoul( const char *s
, char **end
, int base
)
956 BOOL negative
= FALSE
, empty
= TRUE
;
959 if (base
< 0 || base
== 1 || base
> 36) return 0;
960 if (end
) *end
= (char *)s
;
961 while (isspace(*s
)) s
++;
968 else if (*s
== '+') s
++;
970 if ((base
== 0 || base
== 16) && !char_to_int( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
975 if (base
== 0) base
= char_to_int( *s
) ? 10 : 8;
979 int v
= char_to_int( *s
);
980 if (v
< 0 || v
>= base
) break;
984 if (ret
> MAXDWORD
/ base
|| ret
* base
> MAXDWORD
- v
)
987 ret
= ret
* base
+ v
;
990 if (end
&& !empty
) *end
= (char *)s
;
991 return negative
? -ret
: ret
;
995 /*********************************************************************
998 * Convert an unsigned long integer to a string.
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
)
1019 digit
= value
% radix
;
1020 value
= value
/ radix
;
1022 *--pos
= '0' + digit
;
1024 *--pos
= 'a' + digit
- 10;
1026 } while (value
!= 0L);
1028 memcpy(str
, pos
, &buffer
[32] - pos
+ 1);
1033 /*********************************************************************
1036 * Convert a long integer to a string.
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
)
1056 if (value
< 0 && radix
== 10) {
1068 digit
= val
% radix
;
1071 *--pos
= '0' + digit
;
1073 *--pos
= 'a' + digit
- 10;
1075 } while (val
!= 0L);
1081 memcpy(str
, pos
, &buffer
[32] - pos
+ 1);
1086 /*********************************************************************
1089 * Converts an integer to a string.
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.
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 */
1137 digit
= value
% radix
;
1138 value
= value
/ radix
;
1140 *--pos
= '0' + digit
;
1142 *--pos
= 'a' + digit
- 10;
1144 } while (value
!= 0L);
1146 memcpy(str
, pos
, &buffer
[64] - pos
+ 1);
1151 /*********************************************************************
1154 * Converts a large integer to a string.
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.
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 */
1186 if (value
< 0 && radix
== 10) {
1198 digit
= val
% radix
;
1201 *--pos
= '0' + digit
;
1203 *--pos
= 'a' + digit
- 10;
1205 } while (val
!= 0L);
1211 memcpy(str
, pos
, &buffer
[64] - pos
+ 1);
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)
1234 int digit
= value
% radix
;
1235 value
= value
/ radix
;
1237 *--pos
= '0' + digit
;
1239 *--pos
= 'a' + digit
- 10;
1240 } while (value
!= 0);
1242 if (buffer
- pos
+ 65 > size
)
1247 memcpy( str
, pos
, buffer
- pos
+ 65 );
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
;
1268 char buffer
[65], *pos
;
1270 if (!str
|| !size
) return EINVAL
;
1271 if (radix
< 2 || radix
> 36)
1277 if (value
< 0 && radix
== 10)
1284 is_negative
= FALSE
;
1293 unsigned int digit
= val
% radix
;
1297 *--pos
= '0' + digit
;
1299 *--pos
= 'a' + digit
- 10;
1303 if (is_negative
) *--pos
= '-';
1305 if (buffer
- pos
+ 65 > size
)
1310 memcpy( str
, pos
, buffer
- pos
+ 65 );
1315 /*********************************************************************
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 /*********************************************************************
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 /*********************************************************************
1338 * Convert a string to a large integer.
1341 * str [I] String to be converted
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".
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')) {
1364 } else if (*str
== '-') {
1369 while (*str
>= '0' && *str
<= '9') {
1370 RunningTotal
= RunningTotal
* 10 + *str
- '0';
1374 return bMinus
? -RunningTotal
: RunningTotal
;
1378 /*********************************************************************
1381 int __cdecl
atoi( const char *nptr
)
1383 return _atoi64( nptr
);
1387 /*********************************************************************
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);
1409 static int vsscanf( const char *str
, const char *format
, va_list ap
)
1411 int rd
= 0, consumed
= 0;
1413 if (!*format
) return 0;
1415 nch
= (consumed
++, *str
++);
1421 if (isspace( *format
))
1423 /* skip whitespace */
1424 while ((nch
!= '\0') && isspace( nch
))
1425 nch
= (consumed
++, *str
++);
1427 else if (*format
== '%')
1430 BOOLEAN suppress
= 0;
1434 BOOLEAN l_prefix
= FALSE
;
1435 BOOLEAN w_prefix
= FALSE
;
1436 BOOLEAN I64_prefix
= FALSE
;
1437 BOOLEAN prefix_finished
= FALSE
;
1439 /* a leading asterisk means 'suppress assignment of this field' */
1445 /* look for width specification */
1446 while (isdigit( *format
))
1449 width
+= *format
++ - '0';
1451 if (width
== 0) width
= -1; /* no width spec seen */
1452 /* read prefix (if any) */
1453 while (!prefix_finished
)
1457 case 'h': h_prefix
++; break;
1459 if (*(format
+1) == 'l')
1466 case 'w': w_prefix
= TRUE
; break;
1468 if (*(format
+ 1) == '6' &&
1469 *(format
+ 2) == '4')
1476 prefix_finished
= TRUE
;
1478 if (!prefix_finished
) format
++;
1484 case 'P': /* pointer. */
1485 if (sizeof(void *) == sizeof(LONGLONG
)) I64_prefix
= TRUE
;
1488 case 'X': /* hexadecimal integer. */
1491 case 'o': /* octal integer */
1494 case 'u': /* unsigned decimal integer */
1497 case 'd': /* signed decimal integer */
1500 case 'i': /* generic integer */
1504 /* read an integer */
1506 BOOLEAN negative
= FALSE
;
1507 BOOLEAN seendigit
= FALSE
;
1508 /* skip initial whitespace */
1509 while ((nch
!= '\0') && isspace( nch
))
1510 nch
= (consumed
++, *str
++);
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
--;
1524 if (width
!= 0 && (nch
== 'x' || nch
== 'X'))
1530 nch
= (consumed
++, *str
++);
1531 if (width
> 0) width
--;
1534 } else if (base
== 0)
1537 /* format %i without indication of base */
1540 /* throw away leading zeros */
1541 while (width
!= 0 && nch
== '0')
1543 nch
= (consumed
++, *str
++);
1544 if (width
> 0) width
--;
1547 if (width
!= 0 && char2digit( nch
, base
) != -1)
1549 cur
= char2digit( nch
, base
);
1550 nch
= (consumed
++, *str
++);
1551 if (width
> 0) width
--;
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
--;
1563 if (!seendigit
) break; /* not a valid number */
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 );
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. */
1582 if (w_prefix
|| l_prefix
) goto widecharstring
;
1583 else if (h_prefix
) goto charstring
;
1584 else goto charstring
;
1586 if (w_prefix
|| l_prefix
) goto widecharstring
;
1587 else if (h_prefix
) goto charstring
;
1588 else goto widecharstring
;
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
))
1603 if(size
> 1) size
--;
1611 nch
= (consumed
++, *str
++);
1612 if (width
> 0) width
--;
1615 if (st
&& !suppress
) *sptr
= 0;
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
))
1632 if (size
> 1) size
--;
1640 nch
= (consumed
++, *str
++);
1641 if (width
> 0) width
--;
1644 if (st
&& !suppress
) *sptr
= 0;
1647 /* 'c' and 'C work analogously to 's' and 'S' as described
1650 if (w_prefix
|| l_prefix
) goto widecharacter
;
1651 else if (h_prefix
) goto character
;
1652 else goto character
;
1654 if (w_prefix
|| l_prefix
) goto widecharacter
;
1655 else if (h_prefix
) goto character
;
1656 else goto widecharacter
;
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')
1677 nch
= (consumed
++, *str
++);
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')
1701 nch
= (consumed
++, *str
++);
1709 int *n
= va_arg( ap
, int * );
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).
1729 char *sptr
= suppress
? NULL
: va_arg( ap
, char * );
1730 char *sptr_beg
= sptr
;
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 */
1747 RtlSetBits( &bitMask
, ']', 1 );
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) );
1759 RtlSetBits( &bitMask
, *(format
+ 1) , *(format
- 1) - *(format
+ 1) );
1763 RtlSetBits( &bitMask
, *format
, 1 );
1766 /* read until char is not suitable */
1767 while (width
!= 0 && nch
!= '\0')
1771 if(RtlAreBitsSet( &bitMask
, nch
, 1 ))
1773 if (!suppress
) *sptr
++ = nch
;
1780 if (RtlAreBitsClear( &bitMask
, nch
, 1 ))
1782 if (!suppress
) *sptr
++ = nch
;
1788 nch
= (consumed
++, *str
++);
1789 if (width
> 0) width
--;
1790 if(size
> 1) size
--;
1793 if (!suppress
) *sptr_beg
= 0;
1798 if (!suppress
) *sptr
= 0;
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,
1809 while (nch
!= '\0' && isspace( nch
))
1810 nch
= (consumed
++, *str
++);
1813 suppress
= TRUE
; /* whoops no field to be read */
1814 st
= 1; /* but we got what we expected */
1815 nch
= (consumed
++, *str
++);
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. */
1827 nch
= (consumed
++, *str
++);
1841 /*********************************************************************
1844 int WINAPIV
sscanf( const char *str
, const char *format
, ... )
1848 va_start( valist
, format
);
1849 ret
= vsscanf( str
, format
, valist
);
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
) ||
1868 (!fname
&& sz_fname
) ||
1869 (fname
&& !sz_fname
) ||
1874 if (inpath
[0] && inpath
[1] == ':')
1878 if (sz_drive
<= 2) goto error
;
1879 drive
[0] = inpath
[0];
1880 drive
[1] = inpath
[1];
1885 else if (drive
) drive
[0] = '\0';
1887 /* look for end of directory part */
1889 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1891 if (end
) /* got a directory */
1895 if (sz_dir
<= end
- inpath
) goto error
;
1896 memcpy( dir
, inpath
, end
- inpath
);
1897 dir
[end
- inpath
] = 0;
1901 else if (dir
) dir
[0] = 0;
1903 /* look for extension: what's after the last dot */
1905 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1907 if (!end
) end
= p
; /* there's no extension */
1911 if (sz_fname
<= end
- inpath
) goto error
;
1912 memcpy( fname
, inpath
, end
- inpath
);
1913 fname
[end
- inpath
] = 0;
1917 if (sz_ext
<= strlen(end
)) goto error
;
1923 if (drive
) drive
[0] = 0;
1924 if (dir
) dir
[0] = 0;
1925 if (fname
) fname
[0]= 0;
1931 /*********************************************************************
1932 * _splitpath (NTDLL.@)
1934 * Split a path into its component pieces.
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.
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
)
1963 if (!path
|| !size
) return EINVAL
;
1965 if (drive
&& drive
[0])
1967 if (size
<= 2) goto range
;
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
;
1984 if (needs_separator
)
1986 if (size
< 2) goto range
;
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
;
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
;
2016 copylen
= min(size
- 1, len
);
2017 memcpy(p
, extension
, copylen
);
2018 if (size
<= len
) goto range
;