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
33 #include "ntdll_misc.h"
36 /* same as wctypes except for TAB, which doesn't have C1_BLANK for some reason... */
37 static const unsigned short ctypes
[257] =
42 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
43 0x0020, 0x0028, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
45 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
46 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
48 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
49 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
51 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
52 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
54 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
55 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
57 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
58 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
60 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
61 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
63 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
64 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020
68 /*********************************************************************
71 void * __cdecl
memchr( const void *ptr
, int c
, size_t n
)
73 const unsigned char *p
= ptr
;
75 for (p
= ptr
; n
; n
--, p
++) if (*p
== c
) return (void *)(ULONG_PTR
)p
;
80 /*********************************************************************
83 int __cdecl
memcmp( const void *ptr1
, const void *ptr2
, size_t n
)
85 const unsigned char *p1
, *p2
;
87 for (p1
= ptr1
, p2
= ptr2
; n
; n
--, p1
++, p2
++)
89 if (*p1
< *p2
) return -1;
90 if (*p1
> *p2
) return 1;
96 /*********************************************************************
100 * Behaves like memmove.
102 void * __cdecl
memcpy( void *dst
, const void *src
, size_t n
)
104 volatile unsigned char *d
= dst
; /* avoid gcc optimizations */
105 const unsigned char *s
= src
;
107 if ((size_t)dst
- (size_t)src
>= n
)
109 while (n
--) *d
++ = *s
++;
115 while (n
--) *d
-- = *s
--;
121 /*********************************************************************
124 void * __cdecl
memmove( void *dst
, const void *src
, size_t n
)
126 volatile unsigned char *d
= dst
; /* avoid gcc optimizations */
127 const unsigned char *s
= src
;
129 if ((size_t)dst
- (size_t)src
>= n
)
131 while (n
--) *d
++ = *s
++;
137 while (n
--) *d
-- = *s
--;
143 /*********************************************************************
146 void * __cdecl
memset( void *dst
, int c
, size_t n
)
148 volatile unsigned char *d
= dst
; /* avoid gcc optimizations */
149 while (n
--) *d
++ = c
;
154 /*********************************************************************
157 char * __cdecl
strcat( char *dst
, const char *src
)
161 while ((*d
++ = *src
++));
166 /*********************************************************************
169 char * __cdecl
strchr( const char *str
, int c
)
171 do { if (*str
== (char)c
) return (char *)(ULONG_PTR
)str
; } while (*str
++);
176 /*********************************************************************
179 int __cdecl
strcmp( const char *str1
, const char *str2
)
181 while (*str1
&& *str1
== *str2
) { str1
++; str2
++; }
182 if ((unsigned char)*str1
> (unsigned char)*str2
) return 1;
183 if ((unsigned char)*str1
< (unsigned char)*str2
) return -1;
188 /*********************************************************************
191 char * __cdecl
strcpy( char *dst
, const char *src
)
194 while ((*d
++ = *src
++));
199 /*********************************************************************
202 size_t __cdecl
strcspn( const char *str
, const char *reject
)
205 for (ptr
= str
; *ptr
; ptr
++) if (strchr( reject
, *ptr
)) break;
210 /*********************************************************************
213 size_t __cdecl
strlen( const char *str
)
221 /*********************************************************************
224 char * __cdecl
strncat( char *dst
, const char *src
, size_t len
)
228 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
234 /*********************************************************************
237 int __cdecl
strncmp( const char *str1
, const char *str2
, size_t len
)
240 while (--len
&& *str1
&& *str1
== *str2
) { str1
++; str2
++; }
241 return (unsigned char)*str1
- (unsigned char)*str2
;
245 /*********************************************************************
249 char * __cdecl
strncpy( char *dst
, const char *src
, size_t len
)
252 for (d
= dst
; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
253 while (len
--) *d
++ = 0;
258 /*********************************************************************
261 size_t __cdecl
strnlen( const char *str
, size_t len
)
264 for (s
= str
; len
&& *s
; s
++, len
--) ;
269 /*********************************************************************
272 char * __cdecl
strpbrk( const char *str
, const char *accept
)
274 for ( ; *str
; str
++) if (strchr( accept
, *str
)) return (char *)(ULONG_PTR
)str
;
279 /*********************************************************************
282 char * __cdecl
strrchr( const char *str
, int c
)
285 do { if (*str
== (char)c
) ret
= (char *)(ULONG_PTR
)str
; } while (*str
++);
290 /*********************************************************************
293 size_t __cdecl
strspn( const char *str
, const char *accept
)
296 for (ptr
= str
; *ptr
; ptr
++) if (!strchr( accept
, *ptr
)) break;
301 /*********************************************************************
304 char * __cdecl
strstr( const char *str
, const char *sub
)
308 const char *p1
= str
, *p2
= sub
;
309 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
310 if (!*p2
) return (char *)str
;
317 /*********************************************************************
320 void * __cdecl
_memccpy( void *dst
, const void *src
, int c
, size_t n
)
322 unsigned char *d
= dst
;
323 const unsigned char *s
= src
;
324 while (n
--) if ((*d
++ = *s
++) == (unsigned char)c
) return d
;
329 /*********************************************************************
332 int __cdecl
tolower( int c
)
334 return (char)c
>= 'A' && (char)c
<= 'Z' ? c
- 'A' + 'a' : c
;
338 /*********************************************************************
341 * Compare two blocks of memory as strings, ignoring case.
344 * s1 [I] First string to compare to s2
345 * s2 [I] Second string to compare to s1
346 * len [I] Number of bytes to compare
349 * An integer less than, equal to, or greater than zero indicating that
350 * s1 is less than, equal to or greater than s2 respectively.
353 * Any Nul characters in s1 or s2 are ignored. This function always
354 * compares up to len bytes or the first place where s1 and s2 differ.
356 int __cdecl
_memicmp( const void *str1
, const void *str2
, size_t len
)
358 const unsigned char *s1
= str1
, *s2
= str2
;
362 if ((ret
= tolower(*s1
) - tolower(*s2
))) break;
370 /*********************************************************************
371 * _strnicmp (NTDLL.@)
373 int __cdecl
_strnicmp( LPCSTR str1
, LPCSTR str2
, size_t n
)
379 l1
= (unsigned char)tolower(*str1
);
380 l2
= (unsigned char)tolower(*str2
);
383 if (sizeof(void *) > sizeof(int)) return l1
- l2
;
384 return l1
- l2
> 0 ? 1 : -1;
394 /*********************************************************************
398 int __cdecl
_stricmp( LPCSTR str1
, LPCSTR str2
)
400 return _strnicmp( str1
, str2
, -1 );
404 /*********************************************************************
407 * Convert a string to upper case.
410 * str [I/O] String to convert
413 * str. There is no error return, if str is NULL or invalid, this
414 * function will crash.
416 LPSTR __cdecl
_strupr( LPSTR str
)
419 for ( ; *str
; str
++) *str
= RtlUpperChar(*str
);
424 /*********************************************************************
427 * Convert a string to lowercase
430 * str [I/O] String to convert
433 * str. There is no error return, if str is NULL or invalid, this
434 * function will crash.
436 LPSTR __cdecl
_strlwr( LPSTR str
)
439 for ( ; *str
; str
++) *str
= tolower(*str
);
444 /*********************************************************************
447 int __cdecl
toupper( int c
)
449 char str
[2], *p
= str
;
455 wc
= RtlAnsiCharToUnicodeChar( &p
);
456 wc
= RtlUpcaseUnicodeChar( wc
);
457 RtlUnicodeToMultiByteN( str
, sizeof(str
), &len
, &wc
, sizeof(wc
) );
458 if (len
== 2) return ((unsigned char)str
[0] << 8) + (unsigned char)str
[1];
459 return (unsigned char)str
[0];
463 /*********************************************************************
466 int __cdecl
isalnum( int c
)
468 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
);
472 /*********************************************************************
475 int __cdecl
isalpha( int c
)
477 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
);
481 /*********************************************************************
484 int __cdecl
iscntrl( int c
)
486 return ctypes
[c
+ 1] & C1_CNTRL
;
490 /*********************************************************************
493 int __cdecl
isdigit( int c
)
495 return ctypes
[c
+ 1] & C1_DIGIT
;
499 /*********************************************************************
502 int __cdecl
isgraph( int c
)
504 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
| C1_PUNCT
);
508 /*********************************************************************
511 int __cdecl
islower( int c
)
513 return ctypes
[c
+ 1] & C1_LOWER
;
517 /*********************************************************************
520 int __cdecl
isprint( int c
)
522 return ctypes
[c
+ 1] & (C1_LOWER
| C1_UPPER
| C1_DIGIT
| C1_PUNCT
| C1_BLANK
);
526 /*********************************************************************
529 int __cdecl
ispunct( int c
)
531 return ctypes
[c
+ 1] & C1_PUNCT
;
535 /*********************************************************************
538 int __cdecl
isspace( int c
)
540 return ctypes
[c
+ 1] & C1_SPACE
;
544 /*********************************************************************
547 int __cdecl
isupper( int c
)
549 return ctypes
[c
+ 1] & C1_UPPER
;
553 /*********************************************************************
556 int __cdecl
isxdigit( int c
)
558 return ctypes
[c
+ 1] & C1_XDIGIT
;
562 /*********************************************************************
563 * __isascii (NTDLL.@)
565 int CDECL
__isascii(int c
)
567 return (unsigned)c
< 0x80;
571 /*********************************************************************
572 * __toascii (NTDLL.@)
574 int CDECL
__toascii(int c
)
576 return (unsigned)c
& 0x7f;
580 /*********************************************************************
583 int CDECL
__iscsym(int c
)
585 return (c
< 127 && (isalnum(c
) || c
== '_'));
589 /*********************************************************************
590 * __iscsymf (NTDLL.@)
592 int CDECL
__iscsymf(int c
)
594 return (c
< 127 && (isalpha(c
) || c
== '_'));
598 /*********************************************************************
601 int CDECL
_toupper(int c
)
603 return c
- 0x20; /* sic */
607 /*********************************************************************
610 int CDECL
_tolower(int c
)
612 return c
+ 0x20; /* sic */
616 static int char_to_int( char c
)
618 if ('0' <= c
&& c
<= '9') return c
- '0';
619 if ('A' <= c
&& c
<= 'Z') return c
- 'A' + 10;
620 if ('a' <= c
&& c
<= 'z') return c
- 'a' + 10;
624 /*********************************************************************
627 __msvcrt_long __cdecl
strtol( const char *s
, char **end
, int base
)
629 BOOL negative
= FALSE
, empty
= TRUE
;
632 if (base
< 0 || base
== 1 || base
> 36) return 0;
633 if (end
) *end
= (char *)s
;
634 while (isspace(*s
)) s
++;
641 else if (*s
== '+') s
++;
643 if ((base
== 0 || base
== 16) && !char_to_int( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
648 if (base
== 0) base
= char_to_int( *s
) ? 10 : 8;
652 int v
= char_to_int( *s
);
653 if (v
< 0 || v
>= base
) break;
654 if (negative
) v
= -v
;
658 if (!negative
&& (ret
> MAXLONG
/ base
|| ret
* base
> MAXLONG
- v
))
660 else if (negative
&& (ret
< (LONG
)MINLONG
/ base
|| ret
* base
< (LONG
)(MINLONG
- v
)))
663 ret
= ret
* base
+ v
;
666 if (end
&& !empty
) *end
= (char *)s
;
671 /*********************************************************************
674 __msvcrt_ulong __cdecl
strtoul( const char *s
, char **end
, int base
)
676 BOOL negative
= FALSE
, empty
= TRUE
;
679 if (base
< 0 || base
== 1 || base
> 36) return 0;
680 if (end
) *end
= (char *)s
;
681 while (isspace(*s
)) s
++;
688 else if (*s
== '+') s
++;
690 if ((base
== 0 || base
== 16) && !char_to_int( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
695 if (base
== 0) base
= char_to_int( *s
) ? 10 : 8;
699 int v
= char_to_int( *s
);
700 if (v
< 0 || v
>= base
) break;
704 if (ret
> MAXDWORD
/ base
|| ret
* base
> MAXDWORD
- v
)
707 ret
= ret
* base
+ v
;
710 if (end
&& !empty
) *end
= (char *)s
;
711 return negative
? -ret
: ret
;
715 /*********************************************************************
718 * Convert an unsigned long integer to a string.
724 * - Converts value to a Nul terminated string which is copied to str.
725 * - The maximum length of the copied str is 33 bytes.
726 * - Does not check if radix is in the range of 2 to 36.
727 * - If str is NULL it crashes, as the native function does.
729 char * __cdecl
_ultoa( __msvcrt_ulong value
, char *str
, int radix
)
739 digit
= value
% radix
;
740 value
= value
/ radix
;
742 *--pos
= '0' + digit
;
744 *--pos
= 'a' + digit
- 10;
746 } while (value
!= 0L);
748 memcpy(str
, pos
, &buffer
[32] - pos
+ 1);
753 /*********************************************************************
756 * Convert a long integer to a string.
762 * - Converts value to a Nul terminated string which is copied to str.
763 * - The maximum length of the copied str is 33 bytes. If radix
764 * is 10 and value is negative, the value is converted with sign.
765 * - Does not check if radix is in the range of 2 to 36.
766 * - If str is NULL it crashes, as the native function does.
768 char * __cdecl
_ltoa( __msvcrt_long value
, char *str
, int radix
)
776 if (value
< 0 && radix
== 10) {
791 *--pos
= '0' + digit
;
793 *--pos
= 'a' + digit
- 10;
801 memcpy(str
, pos
, &buffer
[32] - pos
+ 1);
806 /*********************************************************************
809 * Converts an integer to a string.
815 * - Converts value to a '\0' terminated string which is copied to str.
816 * - The maximum length of the copied str is 33 bytes. If radix
817 * is 10 and value is negative, the value is converted with sign.
818 * - Does not check if radix is in the range of 2 to 36.
819 * - If str is NULL it crashes, as the native function does.
821 char * __cdecl
_itoa(
822 int value
, /* [I] Value to be converted */
823 char *str
, /* [O] Destination for the converted value */
824 int radix
) /* [I] Number base for conversion */
826 return _ltoa(value
, str
, radix
);
830 /*********************************************************************
833 * Converts a large unsigned integer to a string.
839 * - Converts value to a '\0' terminated string which is copied to str.
840 * - The maximum length of the copied str is 65 bytes.
841 * - Does not check if radix is in the range of 2 to 36.
842 * - If str is NULL it crashes, as the native function does.
844 char * __cdecl
_ui64toa(
845 ULONGLONG value
, /* [I] Value to be converted */
846 char *str
, /* [O] Destination for the converted value */
847 int radix
) /* [I] Number base for conversion */
857 digit
= value
% radix
;
858 value
= value
/ radix
;
860 *--pos
= '0' + digit
;
862 *--pos
= 'a' + digit
- 10;
864 } while (value
!= 0L);
866 memcpy(str
, pos
, &buffer
[64] - pos
+ 1);
871 /*********************************************************************
874 * Converts a large integer to a string.
880 * - Converts value to a Nul terminated string which is copied to str.
881 * - The maximum length of the copied str is 65 bytes. If radix
882 * is 10 and value is negative, the value is converted with sign.
883 * - Does not check if radix is in the range of 2 to 36.
884 * - If str is NULL it crashes, as the native function does.
887 * - The native DLL converts negative values (for base 10) wrong:
888 *| -1 is converted to -18446744073709551615
889 *| -2 is converted to -18446744073709551614
890 *| -9223372036854775807 is converted to -9223372036854775809
891 *| -9223372036854775808 is converted to -9223372036854775808
892 * The native msvcrt _i64toa function and our ntdll _i64toa function
893 * do not have this bug.
895 char * __cdecl
_i64toa(
896 LONGLONG value
, /* [I] Value to be converted */
897 char *str
, /* [O] Destination for the converted value */
898 int radix
) /* [I] Number base for conversion */
906 if (value
< 0 && radix
== 10) {
921 *--pos
= '0' + digit
;
923 *--pos
= 'a' + digit
- 10;
931 memcpy(str
, pos
, &buffer
[64] - pos
+ 1);
936 /*********************************************************************
939 * Convert a string to a large integer.
942 * str [I] String to be converted
945 * Success: The integer value represented by str.
946 * Failure: 0. Note that this cannot be distinguished from a successful
947 * return, if the string contains "0".
950 * - Accepts: {whitespace} [+|-] {digits}
951 * - No check is made for value overflow, only the lower 64 bits are assigned.
952 * - If str is NULL it crashes, as the native function does.
954 LONGLONG __cdecl
_atoi64( const char *str
)
956 ULONGLONG RunningTotal
= 0;
959 while (*str
== ' ' || (*str
>= '\011' && *str
<= '\015')) {
965 } else if (*str
== '-') {
970 while (*str
>= '0' && *str
<= '9') {
971 RunningTotal
= RunningTotal
* 10 + *str
- '0';
975 return bMinus
? -RunningTotal
: RunningTotal
;
979 /*********************************************************************
982 int __cdecl
atoi( const char *nptr
)
984 return _atoi64( nptr
);
988 /*********************************************************************
991 __msvcrt_long __cdecl
atol( const char *nptr
)
993 return _atoi64( nptr
);
997 /* helper function for *scanf. Returns the value of character c in the
998 * given base, or -1 if the given character is not a digit of the base.
1000 static int char2digit( char c
, int base
)
1002 if ((c
>= '0' && c
<= '9') && (c
<= '0'+base
-1)) return (c
-'0');
1003 if (base
<= 10) return -1;
1004 if ((c
>= 'A') && (c
<= 'Z') && (c
<= 'A'+base
-11)) return (c
-'A'+10);
1005 if ((c
>= 'a') && (c
<= 'z') && (c
<= 'a'+base
-11)) return (c
-'a'+10);
1010 static int vsscanf( const char *str
, const char *format
, __ms_va_list ap
)
1012 int rd
= 0, consumed
= 0;
1014 if (!*format
) return 0;
1016 nch
= (consumed
++, *str
++);
1022 if (isspace( *format
))
1024 /* skip whitespace */
1025 while ((nch
!= '\0') && isspace( nch
))
1026 nch
= (consumed
++, *str
++);
1028 else if (*format
== '%')
1031 BOOLEAN suppress
= 0;
1035 BOOLEAN l_prefix
= FALSE
;
1036 BOOLEAN w_prefix
= FALSE
;
1037 BOOLEAN I64_prefix
= FALSE
;
1038 BOOLEAN prefix_finished
= FALSE
;
1040 /* a leading asterisk means 'suppress assignment of this field' */
1046 /* look for width specification */
1047 while (isdigit( *format
))
1050 width
+= *format
++ - '0';
1052 if (width
== 0) width
= -1; /* no width spec seen */
1053 /* read prefix (if any) */
1054 while (!prefix_finished
)
1058 case 'h': h_prefix
++; break;
1060 if (*(format
+1) == 'l')
1067 case 'w': w_prefix
= TRUE
; break;
1069 if (*(format
+ 1) == '6' &&
1070 *(format
+ 2) == '4')
1077 prefix_finished
= TRUE
;
1079 if (!prefix_finished
) format
++;
1085 case 'P': /* pointer. */
1086 if (sizeof(void *) == sizeof(LONGLONG
)) I64_prefix
= TRUE
;
1089 case 'X': /* hexadecimal integer. */
1092 case 'o': /* octal integer */
1095 case 'u': /* unsigned decimal integer */
1098 case 'd': /* signed decimal integer */
1101 case 'i': /* generic integer */
1105 /* read an integer */
1107 BOOLEAN negative
= FALSE
;
1108 BOOLEAN seendigit
= FALSE
;
1109 /* skip initial whitespace */
1110 while ((nch
!= '\0') && isspace( nch
))
1111 nch
= (consumed
++, *str
++);
1113 if (nch
== '-' || nch
== '+')
1115 negative
= (nch
== '-');
1116 nch
= (consumed
++, *str
++);
1117 if (width
> 0) width
--;
1119 /* look for leading indication of base */
1120 if (width
!= 0 && nch
== '0' && *format
!= 'p' && *format
!= 'P')
1122 nch
= (consumed
++, *str
++);
1123 if (width
> 0) width
--;
1125 if (width
!= 0 && (nch
== 'x' || nch
== 'X'))
1131 nch
= (consumed
++, *str
++);
1132 if (width
> 0) width
--;
1135 } else if (base
== 0)
1138 /* format %i without indication of base */
1141 /* throw away leading zeros */
1142 while (width
!= 0 && nch
== '0')
1144 nch
= (consumed
++, *str
++);
1145 if (width
> 0) width
--;
1148 if (width
!= 0 && char2digit( nch
, base
) != -1)
1150 cur
= char2digit( nch
, base
);
1151 nch
= (consumed
++, *str
++);
1152 if (width
> 0) width
--;
1155 /* read until no more digits */
1156 while (width
!= 0 && nch
!= '\0' && char2digit( nch
, base
) != -1)
1158 cur
= cur
*base
+ char2digit( nch
, base
);
1159 nch
= (consumed
++, *str
++);
1160 if (width
> 0) width
--;
1164 if (!seendigit
) break; /* not a valid number */
1168 #define _SET_NUMBER_( type ) *va_arg( ap, type* ) = negative ? -cur : cur
1169 if (I64_prefix
) _SET_NUMBER_( LONGLONG
);
1170 else if (l_prefix
) _SET_NUMBER_( LONG
);
1171 else if (h_prefix
== 1) _SET_NUMBER_( short int );
1172 else _SET_NUMBER_( int );
1176 /* According to msdn,
1177 * 's' reads a character string in a call to fscanf
1178 * and 'S' a wide character string and vice versa in a
1179 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
1180 * this behaviour. 'h' forces reading char * but 'l' and 'w'
1181 * force reading WCHAR. */
1183 if (w_prefix
|| l_prefix
) goto widecharstring
;
1184 else if (h_prefix
) goto charstring
;
1185 else goto charstring
;
1187 if (w_prefix
|| l_prefix
) goto widecharstring
;
1188 else if (h_prefix
) goto charstring
;
1189 else goto widecharstring
;
1191 { /* read a word into a char */
1192 char *sptr
= suppress
? NULL
: va_arg( ap
, char * );
1193 char *sptr_beg
= sptr
;
1194 unsigned size
= UINT_MAX
;
1195 /* skip initial whitespace */
1196 while (nch
!= '\0' && isspace( nch
))
1197 nch
= (consumed
++, *str
++);
1198 /* read until whitespace */
1199 while (width
!= 0 && nch
!= '\0' && !isspace( nch
))
1204 if(size
> 1) size
--;
1212 nch
= (consumed
++, *str
++);
1213 if (width
> 0) width
--;
1216 if (st
&& !suppress
) *sptr
= 0;
1220 { /* read a word into a WCHAR * */
1221 WCHAR
*sptr
= suppress
? NULL
: va_arg( ap
, WCHAR
* );
1222 WCHAR
*sptr_beg
= sptr
;
1223 unsigned size
= UINT_MAX
;
1224 /* skip initial whitespace */
1225 while (nch
!= '\0' && isspace( nch
))
1226 nch
= (consumed
++, *str
++);
1227 /* read until whitespace */
1228 while (width
!= 0 && nch
!= '\0' && !isspace( nch
))
1233 if (size
> 1) size
--;
1241 nch
= (consumed
++, *str
++);
1242 if (width
> 0) width
--;
1245 if (st
&& !suppress
) *sptr
= 0;
1248 /* 'c' and 'C work analogously to 's' and 'S' as described
1251 if (w_prefix
|| l_prefix
) goto widecharacter
;
1252 else if (h_prefix
) goto character
;
1253 else goto character
;
1255 if (w_prefix
|| l_prefix
) goto widecharacter
;
1256 else if (h_prefix
) goto character
;
1257 else goto widecharacter
;
1259 { /* read single character into char */
1260 char *sptr
= suppress
? NULL
: va_arg( ap
, char * );
1261 char *sptr_beg
= sptr
;
1262 unsigned size
= UINT_MAX
;
1263 if (width
== -1) width
= 1;
1264 while (width
&& nch
!= '\0')
1278 nch
= (consumed
++, *str
++);
1283 { /* read single character into a WCHAR */
1284 WCHAR
*sptr
= suppress
? NULL
: va_arg( ap
, WCHAR
* );
1285 WCHAR
*sptr_beg
= sptr
;
1286 unsigned size
= UINT_MAX
;
1287 if (width
== -1) width
= 1;
1288 while (width
&& nch
!= '\0')
1302 nch
= (consumed
++, *str
++);
1310 int *n
= va_arg( ap
, int * );
1313 /* This is an odd one: according to the standard,
1314 * "Execution of a %n directive does not increment the
1315 * assignment count returned at the completion of
1316 * execution" even if it wasn't suppressed with the
1317 * '*' flag. The Corrigendum to the standard seems
1318 * to contradict this (comment out the assignment to
1319 * suppress below if you want to implement these
1320 * alternate semantics) but the windows program I'm
1321 * looking at expects the behavior I've coded here
1322 * (which happens to be what glibc does as well).
1330 char *sptr
= suppress
? NULL
: va_arg( ap
, char * );
1331 char *sptr_beg
= sptr
;
1333 ULONG Mask
[8] = { 0 };
1334 BOOLEAN invert
= FALSE
; /* Set if we are NOT to find the chars */
1335 unsigned size
= UINT_MAX
;
1337 RtlInitializeBitMap( &bitMask
, Mask
, sizeof(Mask
) * 8 );
1339 /* Read the format */
1348 RtlSetBits( &bitMask
, ']', 1 );
1351 while (*format
&& (*format
!= ']'))
1353 /* According to msdn:
1354 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
1355 if ((*format
== '-') && (*(format
+ 1) != ']'))
1357 if ((*(format
- 1)) < *(format
+ 1))
1358 RtlSetBits( &bitMask
, *(format
- 1) +1 , *(format
+ 1) - *(format
- 1) );
1360 RtlSetBits( &bitMask
, *(format
+ 1) , *(format
- 1) - *(format
+ 1) );
1364 RtlSetBits( &bitMask
, *format
, 1 );
1367 /* read until char is not suitable */
1368 while (width
!= 0 && nch
!= '\0')
1372 if(RtlAreBitsSet( &bitMask
, nch
, 1 ))
1374 if (!suppress
) *sptr
++ = nch
;
1381 if (RtlAreBitsClear( &bitMask
, nch
, 1 ))
1383 if (!suppress
) *sptr
++ = nch
;
1389 nch
= (consumed
++, *str
++);
1390 if (width
> 0) width
--;
1391 if(size
> 1) size
--;
1394 if (!suppress
) *sptr_beg
= 0;
1399 if (!suppress
) *sptr
= 0;
1403 /* From spec: "if a percent sign is followed by a character
1404 * that has no meaning as a format-control character, that
1405 * character and the following characters are treated as
1406 * an ordinary sequence of characters, that is, a sequence
1407 * of characters that must match the input. For example,
1408 * to specify that a percent-sign character is to be input,
1410 while (nch
!= '\0' && isspace( nch
))
1411 nch
= (consumed
++, *str
++);
1414 suppress
= TRUE
; /* whoops no field to be read */
1415 st
= 1; /* but we got what we expected */
1416 nch
= (consumed
++, *str
++);
1420 if (st
&& !suppress
) rd
++;
1421 else if (!st
) break;
1423 /* A non-white-space character causes scanf to read, but not store,
1424 * a matching non-white-space character. */
1428 nch
= (consumed
++, *str
++);
1442 /*********************************************************************
1445 int WINAPIV
sscanf( const char *str
, const char *format
, ... )
1448 __ms_va_list valist
;
1449 __ms_va_start( valist
, format
);
1450 ret
= vsscanf( str
, format
, valist
);
1451 __ms_va_end( valist
);
1456 /*********************************************************************
1457 * _splitpath (NTDLL.@)
1459 * Split a path into its component pieces.
1462 * inpath [I] Path to split
1463 * drv [O] Destination for drive component (e.g. "A:"). Must be at least 3 characters.
1464 * dir [O] Destination for directory component. Should be at least MAX_PATH characters.
1465 * fname [O] Destination for File name component. Should be at least MAX_PATH characters.
1466 * ext [O] Destination for file extension component. Should be at least MAX_PATH characters.
1471 void __cdecl
_splitpath(const char* inpath
, char * drv
, char * dir
,
1472 char* fname
, char * ext
)
1474 const char *p
, *end
;
1476 if (inpath
[0] && inpath
[1] == ':')
1486 else if (drv
) drv
[0] = 0;
1488 /* look for end of directory part */
1490 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1492 if (end
) /* got a directory */
1496 memcpy( dir
, inpath
, end
- inpath
);
1497 dir
[end
- inpath
] = 0;
1501 else if (dir
) dir
[0] = 0;
1503 /* look for extension: what's after the last dot */
1505 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1507 if (!end
) end
= p
; /* there's no extension */
1511 memcpy( fname
, inpath
, end
- inpath
);
1512 fname
[end
- inpath
] = 0;
1514 if (ext
) strcpy( ext
, end
);