user32: Support forcing the DPI awareness through the image file execution options.
[wine.git] / dlls / ntdll / string.c
blobe0bf5be1640a62f50d0b059c6962b4a90a219539
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 "config.h"
24 #include "wine/port.h"
26 #include <ctype.h>
27 #include <limits.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include "windef.h"
34 #include "winternl.h"
37 /*********************************************************************
38 * memchr (NTDLL.@)
40 void * __cdecl NTDLL_memchr( const void *ptr, int c, size_t n )
42 return memchr( ptr, c, n );
46 /*********************************************************************
47 * memcmp (NTDLL.@)
49 int __cdecl NTDLL_memcmp( const void *ptr1, const void *ptr2, size_t n )
51 return memcmp( ptr1, ptr2, n );
55 /*********************************************************************
56 * memcpy (NTDLL.@)
58 * NOTES
59 * Behaves like memmove.
61 void * __cdecl NTDLL_memcpy( void *dst, const void *src, size_t n )
63 return memmove( dst, src, n );
67 /*********************************************************************
68 * memmove (NTDLL.@)
70 void * __cdecl NTDLL_memmove( void *dst, const void *src, size_t n )
72 return memmove( dst, src, n );
76 /*********************************************************************
77 * memset (NTDLL.@)
79 void * __cdecl NTDLL_memset( void *dst, int c, size_t n )
81 return memset( dst, c, n );
85 /*********************************************************************
86 * strcat (NTDLL.@)
88 char * __cdecl NTDLL_strcat( char *dst, const char *src )
90 return strcat( dst, src );
94 /*********************************************************************
95 * strchr (NTDLL.@)
97 char * __cdecl NTDLL_strchr( const char *str, int c )
99 return strchr( str, c );
103 /*********************************************************************
104 * strcmp (NTDLL.@)
106 int __cdecl NTDLL_strcmp( const char *str1, const char *str2 )
108 return strcmp( str1, str2 );
112 /*********************************************************************
113 * strcpy (NTDLL.@)
115 char * __cdecl NTDLL_strcpy( char *dst, const char *src )
117 return strcpy( dst, src );
121 /*********************************************************************
122 * strcspn (NTDLL.@)
124 size_t __cdecl NTDLL_strcspn( const char *str, const char *reject )
126 return strcspn( str, reject );
130 /*********************************************************************
131 * strlen (NTDLL.@)
133 size_t __cdecl NTDLL_strlen( const char *str )
135 return strlen( str );
139 /*********************************************************************
140 * strncat (NTDLL.@)
142 char * __cdecl NTDLL_strncat( char *dst, const char *src, size_t len )
144 return strncat( dst, src, len );
148 /*********************************************************************
149 * strncmp (NTDLL.@)
151 int __cdecl NTDLL_strncmp( const char *str1, const char *str2, size_t len )
153 return strncmp( str1, str2, len );
157 /*********************************************************************
158 * strncpy (NTDLL.@)
160 char * __cdecl NTDLL_strncpy( char *dst, const char *src, size_t len )
162 return strncpy( dst, src, len );
166 /*********************************************************************
167 * strnlen (NTDLL.@)
169 size_t __cdecl NTDLL_strnlen( const char *str, size_t len )
171 return strnlen( str, len );
175 /*********************************************************************
176 * strpbrk (NTDLL.@)
178 char * __cdecl NTDLL_strpbrk( const char *str, const char *accept )
180 return strpbrk( str, accept );
184 /*********************************************************************
185 * strrchr (NTDLL.@)
187 char * __cdecl NTDLL_strrchr( const char *str, int c )
189 return strrchr( str, c );
193 /*********************************************************************
194 * strspn (NTDLL.@)
196 size_t __cdecl NTDLL_strspn( const char *str, const char *accept )
198 return strspn( str, accept );
202 /*********************************************************************
203 * strstr (NTDLL.@)
205 char * __cdecl NTDLL_strstr( const char *haystack, const char *needle )
207 return strstr( haystack, needle );
211 /*********************************************************************
212 * _memccpy (NTDLL.@)
214 void * __cdecl _memccpy( void *dst, const void *src, int c, size_t n )
216 return memccpy( dst, src, c, n );
220 /*********************************************************************
221 * _memicmp (NTDLL.@)
223 * Compare two blocks of memory as strings, ignoring case.
225 * PARAMS
226 * s1 [I] First string to compare to s2
227 * s2 [I] Second string to compare to s1
228 * len [I] Number of bytes to compare
230 * RETURNS
231 * An integer less than, equal to, or greater than zero indicating that
232 * s1 is less than, equal to or greater than s2 respectively.
234 * NOTES
235 * Any Nul characters in s1 or s2 are ignored. This function always
236 * compares up to len bytes or the first place where s1 and s2 differ.
238 INT __cdecl _memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
240 int ret = 0;
241 while (len--)
243 if ((ret = tolower(*s1) - tolower(*s2))) break;
244 s1++;
245 s2++;
247 return ret;
251 /*********************************************************************
252 * _stricmp (NTDLL.@)
253 * _strcmpi (NTDLL.@)
255 int __cdecl _stricmp( LPCSTR str1, LPCSTR str2 )
257 return strcasecmp( str1, str2 );
261 /*********************************************************************
262 * _strnicmp (NTDLL.@)
264 int __cdecl _strnicmp( LPCSTR str1, LPCSTR str2, size_t n )
266 return strncasecmp( str1, str2, n );
270 /*********************************************************************
271 * _strupr (NTDLL.@)
273 * Convert a string to upper case.
275 * PARAMS
276 * str [I/O] String to convert
278 * RETURNS
279 * str. There is no error return, if str is NULL or invalid, this
280 * function will crash.
282 LPSTR __cdecl _strupr( LPSTR str )
284 LPSTR ret = str;
285 for ( ; *str; str++) *str = toupper(*str);
286 return ret;
290 /*********************************************************************
291 * _strlwr (NTDLL.@)
293 * Convert a string to lowercase
295 * PARAMS
296 * str [I/O] String to convert
298 * RETURNS
299 * str. There is no error return, if str is NULL or invalid, this
300 * function will crash.
302 LPSTR __cdecl _strlwr( LPSTR str )
304 LPSTR ret = str;
305 for ( ; *str; str++) *str = tolower(*str);
306 return ret;
310 /*********************************************************************
311 * tolower (NTDLL.@)
313 int __cdecl NTDLL_tolower( int c )
315 return tolower( c );
319 /*********************************************************************
320 * toupper (NTDLL.@)
322 int __cdecl NTDLL_toupper( int c )
324 return toupper( c );
328 /*********************************************************************
329 * isalnum (NTDLL.@)
331 int __cdecl NTDLL_isalnum( int c )
333 return isalnum( c );
337 /*********************************************************************
338 * isalpha (NTDLL.@)
340 int __cdecl NTDLL_isalpha( int c )
342 return isalpha( c );
346 /*********************************************************************
347 * iscntrl (NTDLL.@)
349 int __cdecl NTDLL_iscntrl( int c )
351 return iscntrl( c );
355 /*********************************************************************
356 * isdigit (NTDLL.@)
358 int __cdecl NTDLL_isdigit( int c )
360 return isdigit( c );
364 /*********************************************************************
365 * isgraph (NTDLL.@)
367 int __cdecl NTDLL_isgraph( int c )
369 return isgraph( c );
373 /*********************************************************************
374 * islower (NTDLL.@)
376 int __cdecl NTDLL_islower( int c )
378 return islower( c );
382 /*********************************************************************
383 * isprint (NTDLL.@)
385 int __cdecl NTDLL_isprint( int c )
387 return isprint( c );
391 /*********************************************************************
392 * ispunct (NTDLL.@)
394 int __cdecl NTDLL_ispunct( int c )
396 return ispunct( c );
400 /*********************************************************************
401 * isspace (NTDLL.@)
403 int __cdecl NTDLL_isspace( int c )
405 return isspace( c );
409 /*********************************************************************
410 * isupper (NTDLL.@)
412 int __cdecl NTDLL_isupper( int c )
414 return isupper( c );
418 /*********************************************************************
419 * isxdigit (NTDLL.@)
421 int __cdecl NTDLL_isxdigit( int c )
423 return isxdigit( c );
427 /*********************************************************************
428 * __isascii (NTDLL.@)
430 int CDECL NTDLL___isascii(int c)
432 return (unsigned)c < 0x80;
436 /*********************************************************************
437 * __toascii (NTDLL.@)
439 int CDECL NTDLL___toascii(int c)
441 return (unsigned)c & 0x7f;
445 /*********************************************************************
446 * __iscsym (NTDLL.@)
448 int CDECL NTDLL___iscsym(int c)
450 return (c < 127 && (isalnum(c) || c == '_'));
454 /*********************************************************************
455 * __iscsymf (NTDLL.@)
457 int CDECL NTDLL___iscsymf(int c)
459 return (c < 127 && (isalpha(c) || c == '_'));
463 /*********************************************************************
464 * _toupper (NTDLL.@)
466 int CDECL NTDLL__toupper(int c)
468 return c - 0x20; /* sic */
472 /*********************************************************************
473 * _tolower (NTDLL.@)
475 int CDECL NTDLL__tolower(int c)
477 return c + 0x20; /* sic */
481 /*********************************************************************
482 * strtol (NTDLL.@)
484 LONG __cdecl NTDLL_strtol( const char *nptr, char **endptr, int base )
486 return strtol( nptr, endptr, base );
490 /*********************************************************************
491 * strtoul (NTDLL.@)
493 ULONG __cdecl NTDLL_strtoul( const char *nptr, char **endptr, int base )
495 return strtoul( nptr, endptr, base );
499 /*********************************************************************
500 * _ultoa (NTDLL.@)
502 * Convert an unsigned long integer to a string.
504 * RETURNS
505 * str.
507 * NOTES
508 * - Converts value to a Nul terminated string which is copied to str.
509 * - The maximum length of the copied str is 33 bytes.
510 * - Does not check if radix is in the range of 2 to 36.
511 * - If str is NULL it crashes, as the native function does.
513 char * __cdecl _ultoa(
514 ULONG value, /* [I] Value to be converted */
515 char *str, /* [O] Destination for the converted value */
516 int radix) /* [I] Number base for conversion */
518 char buffer[33];
519 char *pos;
520 int digit;
522 pos = &buffer[32];
523 *pos = '\0';
525 do {
526 digit = value % radix;
527 value = value / radix;
528 if (digit < 10) {
529 *--pos = '0' + digit;
530 } else {
531 *--pos = 'a' + digit - 10;
532 } /* if */
533 } while (value != 0L);
535 memcpy(str, pos, &buffer[32] - pos + 1);
536 return str;
540 /*********************************************************************
541 * _ltoa (NTDLL.@)
543 * Convert a long integer to a string.
545 * RETURNS
546 * str.
548 * NOTES
549 * - Converts value to a Nul terminated string which is copied to str.
550 * - The maximum length of the copied str is 33 bytes. If radix
551 * is 10 and value is negative, the value is converted with sign.
552 * - Does not check if radix is in the range of 2 to 36.
553 * - If str is NULL it crashes, as the native function does.
555 char * __cdecl _ltoa(
556 LONG value, /* [I] Value to be converted */
557 char *str, /* [O] Destination for the converted value */
558 int radix) /* [I] Number base for conversion */
560 ULONG val;
561 int negative;
562 char buffer[33];
563 char *pos;
564 int digit;
566 if (value < 0 && radix == 10) {
567 negative = 1;
568 val = -value;
569 } else {
570 negative = 0;
571 val = value;
572 } /* if */
574 pos = &buffer[32];
575 *pos = '\0';
577 do {
578 digit = val % radix;
579 val = val / radix;
580 if (digit < 10) {
581 *--pos = '0' + digit;
582 } else {
583 *--pos = 'a' + digit - 10;
584 } /* if */
585 } while (val != 0L);
587 if (negative) {
588 *--pos = '-';
589 } /* if */
591 memcpy(str, pos, &buffer[32] - pos + 1);
592 return str;
596 /*********************************************************************
597 * _itoa (NTDLL.@)
599 * Converts an integer to a string.
601 * RETURNS
602 * str.
604 * NOTES
605 * - Converts value to a '\0' terminated string which is copied to str.
606 * - The maximum length of the copied str is 33 bytes. If radix
607 * is 10 and value is negative, the value is converted with sign.
608 * - Does not check if radix is in the range of 2 to 36.
609 * - If str is NULL it crashes, as the native function does.
611 char * __cdecl _itoa(
612 int value, /* [I] Value to be converted */
613 char *str, /* [O] Destination for the converted value */
614 int radix) /* [I] Number base for conversion */
616 return _ltoa(value, str, radix);
620 /*********************************************************************
621 * _ui64toa (NTDLL.@)
623 * Converts a large unsigned integer to a string.
625 * RETURNS
626 * str.
628 * NOTES
629 * - Converts value to a '\0' terminated string which is copied to str.
630 * - The maximum length of the copied str is 65 bytes.
631 * - Does not check if radix is in the range of 2 to 36.
632 * - If str is NULL it crashes, as the native function does.
634 char * __cdecl _ui64toa(
635 ULONGLONG value, /* [I] Value to be converted */
636 char *str, /* [O] Destination for the converted value */
637 int radix) /* [I] Number base for conversion */
639 char buffer[65];
640 char *pos;
641 int digit;
643 pos = &buffer[64];
644 *pos = '\0';
646 do {
647 digit = value % radix;
648 value = value / radix;
649 if (digit < 10) {
650 *--pos = '0' + digit;
651 } else {
652 *--pos = 'a' + digit - 10;
653 } /* if */
654 } while (value != 0L);
656 memcpy(str, pos, &buffer[64] - pos + 1);
657 return str;
661 /*********************************************************************
662 * _i64toa (NTDLL.@)
664 * Converts a large integer to a string.
666 * RETURNS
667 * str.
669 * NOTES
670 * - Converts value to a Nul terminated string which is copied to str.
671 * - The maximum length of the copied str is 65 bytes. If radix
672 * is 10 and value is negative, the value is converted with sign.
673 * - Does not check if radix is in the range of 2 to 36.
674 * - If str is NULL it crashes, as the native function does.
676 * DIFFERENCES
677 * - The native DLL converts negative values (for base 10) wrong:
678 *| -1 is converted to -18446744073709551615
679 *| -2 is converted to -18446744073709551614
680 *| -9223372036854775807 is converted to -9223372036854775809
681 *| -9223372036854775808 is converted to -9223372036854775808
682 * The native msvcrt _i64toa function and our ntdll _i64toa function
683 * do not have this bug.
685 char * __cdecl _i64toa(
686 LONGLONG value, /* [I] Value to be converted */
687 char *str, /* [O] Destination for the converted value */
688 int radix) /* [I] Number base for conversion */
690 ULONGLONG val;
691 int negative;
692 char buffer[65];
693 char *pos;
694 int digit;
696 if (value < 0 && radix == 10) {
697 negative = 1;
698 val = -value;
699 } else {
700 negative = 0;
701 val = value;
702 } /* if */
704 pos = &buffer[64];
705 *pos = '\0';
707 do {
708 digit = val % radix;
709 val = val / radix;
710 if (digit < 10) {
711 *--pos = '0' + digit;
712 } else {
713 *--pos = 'a' + digit - 10;
714 } /* if */
715 } while (val != 0L);
717 if (negative) {
718 *--pos = '-';
719 } /* if */
721 memcpy(str, pos, &buffer[64] - pos + 1);
722 return str;
726 /*********************************************************************
727 * _atoi64 (NTDLL.@)
729 * Convert a string to a large integer.
731 * PARAMS
732 * str [I] String to be converted
734 * RETURNS
735 * Success: The integer value represented by str.
736 * Failure: 0. Note that this cannot be distinguished from a successful
737 * return, if the string contains "0".
739 * NOTES
740 * - Accepts: {whitespace} [+|-] {digits}
741 * - No check is made for value overflow, only the lower 64 bits are assigned.
742 * - If str is NULL it crashes, as the native function does.
744 LONGLONG __cdecl _atoi64( const char *str )
746 ULONGLONG RunningTotal = 0;
747 BOOL bMinus = FALSE;
749 while (*str == ' ' || (*str >= '\011' && *str <= '\015')) {
750 str++;
751 } /* while */
753 if (*str == '+') {
754 str++;
755 } else if (*str == '-') {
756 bMinus = TRUE;
757 str++;
758 } /* if */
760 while (*str >= '0' && *str <= '9') {
761 RunningTotal = RunningTotal * 10 + *str - '0';
762 str++;
763 } /* while */
765 return bMinus ? -RunningTotal : RunningTotal;
769 /*********************************************************************
770 * atoi (NTDLL.@)
772 int __cdecl NTDLL_atoi( const char *nptr )
774 return _atoi64( nptr );
778 /*********************************************************************
779 * atol (NTDLL.@)
781 LONG __cdecl NTDLL_atol( const char *nptr )
783 return _atoi64( nptr );
787 /* helper function for *scanf. Returns the value of character c in the
788 * given base, or -1 if the given character is not a digit of the base.
790 static int char2digit( char c, int base )
792 if ((c >= '0' && c <= '9') && (c <= '0'+base-1)) return (c-'0');
793 if (base <= 10) return -1;
794 if ((c >= 'A') && (c <= 'Z') && (c <= 'A'+base-11)) return (c-'A'+10);
795 if ((c >= 'a') && (c <= 'z') && (c <= 'a'+base-11)) return (c-'a'+10);
796 return -1;
800 static int NTDLL_vsscanf( const char *str, const char *format, __ms_va_list ap)
802 int rd = 0, consumed = 0;
803 int nch;
804 if (!*format) return 0;
806 nch = (consumed++, *str++);
807 if (nch == '\0')
808 return EOF;
810 while (*format)
812 if (isspace( *format ))
814 /* skip whitespace */
815 while ((nch != '\0') && isspace( nch ))
816 nch = (consumed++, *str++);
818 else if (*format == '%')
820 int st = 0;
821 BOOLEAN suppress = 0;
822 int width = 0;
823 int base;
824 int h_prefix = 0;
825 BOOLEAN l_prefix = FALSE;
826 BOOLEAN L_prefix = FALSE;
827 BOOLEAN w_prefix = FALSE;
828 BOOLEAN I64_prefix = FALSE;
829 BOOLEAN prefix_finished = FALSE;
830 format++;
831 /* a leading asterisk means 'suppress assignment of this field' */
832 if (*format == '*')
834 format++;
835 suppress = TRUE;
837 /* look for width specification */
838 while (isdigit( *format ))
840 width *= 10;
841 width += *format++ - '0';
843 if (width == 0) width = -1; /* no width spec seen */
844 /* read prefix (if any) */
845 while (!prefix_finished)
847 switch (*format)
849 case 'h': h_prefix++; break;
850 case 'l':
851 if (*(format+1) == 'l')
853 I64_prefix = TRUE;
854 format++;
856 l_prefix = TRUE;
857 break;
858 case 'w': w_prefix = TRUE; break;
859 case 'L': L_prefix = TRUE; break;
860 case 'I':
861 if (*(format + 1) == '6' &&
862 *(format + 2) == '4')
864 I64_prefix = TRUE;
865 format += 2;
867 break;
868 default:
869 prefix_finished = TRUE;
871 if (!prefix_finished) format++;
873 /* read type */
874 switch (*format)
876 case 'p':
877 case 'P': /* pointer. */
878 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = TRUE;
879 /* fall through */
880 case 'x':
881 case 'X': /* hexadecimal integer. */
882 base = 16;
883 goto number;
884 case 'o': /* octal integer */
885 base = 8;
886 goto number;
887 case 'u': /* unsigned decimal integer */
888 base = 10;
889 goto number;
890 case 'd': /* signed decimal integer */
891 base = 10;
892 goto number;
893 case 'i': /* generic integer */
894 base = 0;
895 number:
897 /* read an integer */
898 ULONGLONG cur = 0;
899 BOOLEAN negative = FALSE;
900 BOOLEAN seendigit = FALSE;
901 /* skip initial whitespace */
902 while ((nch != '\0') && isspace( nch ))
903 nch = (consumed++, *str++);
904 /* get sign */
905 if (nch == '-' || nch == '+')
907 negative = (nch == '-');
908 nch = (consumed++, *str++);
909 if (width > 0) width--;
911 /* look for leading indication of base */
912 if (width != 0 && nch == '0' && *format != 'p' && *format != 'P')
914 nch = (consumed++, *str++);
915 if (width > 0) width--;
916 seendigit = TRUE;
917 if (width != 0 && (nch == 'x' || nch == 'X'))
919 if (base == 0)
920 base = 16;
921 if (base == 16)
923 nch = (consumed++, *str++);
924 if (width > 0) width--;
925 seendigit = FALSE;
927 } else if (base == 0)
928 base = 8;
930 /* format %i without indication of base */
931 if (base == 0)
932 base = 10;
933 /* throw away leading zeros */
934 while (width != 0 && nch == '0')
936 nch = (consumed++, *str++);
937 if (width > 0) width--;
938 seendigit = TRUE;
940 if (width != 0 && char2digit( nch, base ) != -1)
942 cur = char2digit( nch, base );
943 nch = (consumed++, *str++);
944 if (width > 0) width--;
945 seendigit = TRUE;
947 /* read until no more digits */
948 while (width != 0 && nch != '\0' && char2digit( nch, base ) != -1)
950 cur = cur*base + char2digit( nch, base );
951 nch = (consumed++, *str++);
952 if (width > 0) width--;
953 seendigit = TRUE;
955 /* okay, done! */
956 if (!seendigit) break; /* not a valid number */
957 st = 1;
958 if (!suppress)
960 #define _SET_NUMBER_( type ) *va_arg( ap, type* ) = negative ? -cur : cur
961 if (I64_prefix) _SET_NUMBER_( LONGLONG );
962 else if (l_prefix) _SET_NUMBER_( LONG );
963 else if (h_prefix == 1) _SET_NUMBER_( short int );
964 else _SET_NUMBER_( int );
967 break;
968 case 'e':
969 case 'E':
970 case 'f':
971 case 'g':
972 case 'G':
973 { /* read a float */
974 long double cur = 1, expcnt = 10;
975 ULONGLONG d, hlp;
976 int exp = 0;
977 BOOLEAN negative = FALSE;
978 /*unsigned fpcontrol;*/
979 BOOLEAN negexp;
981 /* skip initial whitespace */
982 while (nch != '\0' && isspace( nch ))
983 nch = (consumed++, *str++);
985 /* get sign */
986 if (nch == '-' || nch == '+')
988 negative = (nch == '-');
989 if (width > 0) width--;
990 if (width == 0) break;
991 nch = (consumed++, *str++);
994 /* get first digit */
995 if ('.' != nch)
997 if (!isdigit( nch )) break;
998 d = nch - '0';
999 nch = (consumed++, *str++);
1000 if (width > 0) width--;
1001 /* read until no more digits */
1002 while (width != 0 && nch != '\0' && isdigit( nch ))
1004 hlp = d * 10 + nch - '0';
1005 nch = (consumed++, *str++);
1006 if (width > 0) width--;
1007 if(d > (ULONGLONG)-1/10 || hlp < d)
1009 exp++;
1010 break;
1012 else
1013 d = hlp;
1015 while (width != 0 && nch != '\0' && isdigit( nch ))
1017 exp++;
1018 nch = (consumed++, *str++);
1019 if (width > 0) width--;
1022 else
1023 d = 0; /* Fix: .8 -> 0.8 */
1025 /* handle decimals */
1026 if (width != 0 && nch == '.')
1028 nch = (consumed++, *str++);
1029 if (width > 0) width--;
1031 while (width != 0 && nch != '\0' && isdigit( nch ))
1033 hlp = d * 10 + nch - '0';
1034 nch = (consumed++, *str++);
1035 if (width > 0) width--;
1036 if(d > (ULONGLONG)-1/10 || hlp < d)
1037 break;
1039 d = hlp;
1040 exp--;
1042 while (width != 0 && nch != '\0' && isdigit( nch ))
1044 nch = (consumed++, *str++);
1045 if (width > 0) width--;
1049 /* handle exponent */
1050 if (width != 0 && (nch == 'e' || nch == 'E'))
1052 int sign = 1, e = 0;
1054 nch = (consumed++, *str++);
1055 if (width > 0) width--;
1056 if (width != 0 && (nch == '+' || nch == '-'))
1058 if(nch == '-')
1059 sign = -1;
1060 nch = (consumed++, *str++);
1061 if (width > 0) width--;
1064 /* exponent digits */
1065 while (width != 0 && nch != '\0' && isdigit( nch ))
1067 if (e > INT_MAX/10 || (e = e * 10 + nch - '0') < 0)
1068 e = INT_MAX;
1069 nch = (consumed++, *str++);
1070 if (width > 0) width--;
1072 e *= sign;
1074 if(exp < 0 && e < 0 && e+exp > 0) exp = INT_MIN;
1075 else if(exp > 0 && e > 0 && e+exp < 0) exp = INT_MAX;
1076 else exp += e;
1079 /*fpcontrol = _control87(0, 0);
1080 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
1081 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);*/
1083 negexp = (exp < 0);
1084 if (negexp)
1085 exp = -exp;
1086 /* update 'cur' with this exponent. */
1087 while (exp)
1089 if(exp & 1)
1090 cur *= expcnt;
1091 exp /= 2;
1092 expcnt = expcnt*expcnt;
1094 cur = (negexp ? d/cur : d*cur);
1096 /*_control87(fpcontrol, 0xffffffff);*/
1098 st = 1;
1099 if (!suppress)
1101 if (L_prefix || l_prefix) _SET_NUMBER_( double );
1102 else _SET_NUMBER_( float );
1105 break;
1106 /* According to msdn,
1107 * 's' reads a character string in a call to fscanf
1108 * and 'S' a wide character string and vice versa in a
1109 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
1110 * this behaviour. 'h' forces reading char * but 'l' and 'w'
1111 * force reading WCHAR. */
1112 case 's':
1113 if (w_prefix || l_prefix) goto widecharstring;
1114 else if (h_prefix) goto charstring;
1115 else goto charstring;
1116 case 'S':
1117 if (w_prefix || l_prefix) goto widecharstring;
1118 else if (h_prefix) goto charstring;
1119 else goto widecharstring;
1120 charstring:
1121 { /* read a word into a char */
1122 char *sptr = suppress ? NULL : va_arg( ap, char * );
1123 char *sptr_beg = sptr;
1124 unsigned size = UINT_MAX;
1125 /* skip initial whitespace */
1126 while (nch != '\0' && isspace( nch ))
1127 nch = (consumed++, *str++);
1128 /* read until whitespace */
1129 while (width != 0 && nch != '\0' && !isspace( nch ))
1131 if (!suppress)
1133 *sptr++ = nch;
1134 if(size > 1) size--;
1135 else
1137 *sptr_beg = 0;
1138 return rd;
1141 st++;
1142 nch = (consumed++, *str++);
1143 if (width > 0) width--;
1145 /* terminate */
1146 if (st && !suppress) *sptr = 0;
1148 break;
1149 widecharstring:
1150 { /* read a word into a WCHAR * */
1151 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1152 WCHAR *sptr_beg = sptr;
1153 unsigned size = UINT_MAX;
1154 /* skip initial whitespace */
1155 while (nch != '\0' && isspace( nch ))
1156 nch = (consumed++, *str++);
1157 /* read until whitespace */
1158 while (width != 0 && nch != '\0' && !isspace( nch ))
1160 if (!suppress)
1162 *sptr++ = nch;
1163 if (size > 1) size--;
1164 else
1166 *sptr_beg = 0;
1167 return rd;
1170 st++;
1171 nch = (consumed++, *str++);
1172 if (width > 0) width--;
1174 /* terminate */
1175 if (st && !suppress) *sptr = 0;
1177 break;
1178 /* 'c' and 'C work analogously to 's' and 'S' as described
1179 * above */
1180 case 'c':
1181 if (w_prefix || l_prefix) goto widecharacter;
1182 else if (h_prefix) goto character;
1183 else goto character;
1184 case 'C':
1185 if (w_prefix || l_prefix) goto widecharacter;
1186 else if (h_prefix) goto character;
1187 else goto widecharacter;
1188 character:
1189 { /* read single character into char */
1190 char *sptr = suppress ? NULL : va_arg( ap, char * );
1191 char *sptr_beg = sptr;
1192 unsigned size = UINT_MAX;
1193 if (width == -1) width = 1;
1194 while (width && nch != '\0')
1196 if (!suppress)
1198 *sptr++ = nch;
1199 if(size) size--;
1200 else
1202 *sptr_beg = 0;
1203 return rd;
1206 st++;
1207 width--;
1208 nch = (consumed++, *str++);
1211 break;
1212 widecharacter:
1213 { /* read single character into a WCHAR */
1214 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1215 WCHAR *sptr_beg = sptr;
1216 unsigned size = UINT_MAX;
1217 if (width == -1) width = 1;
1218 while (width && nch != '\0')
1220 if (!suppress)
1222 *sptr++ = nch;
1223 if (size) size--;
1224 else
1226 *sptr_beg = 0;
1227 return rd;
1230 st++;
1231 width--;
1232 nch = (consumed++, *str++);
1235 break;
1236 case 'n':
1238 if (!suppress)
1240 int *n = va_arg( ap, int * );
1241 *n = consumed - 1;
1243 /* This is an odd one: according to the standard,
1244 * "Execution of a %n directive does not increment the
1245 * assignment count returned at the completion of
1246 * execution" even if it wasn't suppressed with the
1247 * '*' flag. The Corrigendum to the standard seems
1248 * to contradict this (comment out the assignment to
1249 * suppress below if you want to implement these
1250 * alternate semantics) but the windows program I'm
1251 * looking at expects the behavior I've coded here
1252 * (which happens to be what glibc does as well).
1254 suppress = TRUE;
1255 st = 1;
1257 break;
1258 case '[':
1260 char *sptr = suppress ? NULL : va_arg( ap, char * );
1261 char *sptr_beg = sptr;
1262 RTL_BITMAP bitMask;
1263 ULONG Mask[8] = { 0 };
1264 BOOLEAN invert = FALSE; /* Set if we are NOT to find the chars */
1265 unsigned size = UINT_MAX;
1267 RtlInitializeBitMap( &bitMask, Mask, sizeof(Mask) * 8 );
1269 /* Read the format */
1270 format++;
1271 if (*format == '^')
1273 invert = TRUE;
1274 format++;
1276 if (*format == ']')
1278 RtlSetBits( &bitMask, ']', 1 );
1279 format++;
1281 while (*format && (*format != ']'))
1283 /* According to msdn:
1284 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
1285 if ((*format == '-') && (*(format + 1) != ']'))
1287 if ((*(format - 1)) < *(format + 1))
1288 RtlSetBits( &bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1) );
1289 else
1290 RtlSetBits( &bitMask, *(format + 1) , *(format - 1) - *(format + 1) );
1291 format++;
1293 else
1294 RtlSetBits( &bitMask, *format, 1 );
1295 format++;
1297 /* read until char is not suitable */
1298 while (width != 0 && nch != '\0')
1300 if (!invert)
1302 if(RtlAreBitsSet( &bitMask, nch, 1 ))
1304 if (!suppress) *sptr++ = nch;
1306 else
1307 break;
1309 else
1311 if (RtlAreBitsClear( &bitMask, nch, 1 ))
1313 if (!suppress) *sptr++ = nch;
1315 else
1316 break;
1318 st++;
1319 nch = (consumed++, *str++);
1320 if (width > 0) width--;
1321 if(size > 1) size--;
1322 else
1324 if (!suppress) *sptr_beg = 0;
1325 return rd;
1328 /* terminate */
1329 if (!suppress) *sptr = 0;
1331 break;
1332 default:
1333 /* From spec: "if a percent sign is followed by a character
1334 * that has no meaning as a format-control character, that
1335 * character and the following characters are treated as
1336 * an ordinary sequence of characters, that is, a sequence
1337 * of characters that must match the input. For example,
1338 * to specify that a percent-sign character is to be input,
1339 * use %%." */
1340 while (nch != '\0' && isspace( nch ))
1341 nch = (consumed++, *str++);
1342 if (nch == *format)
1344 suppress = TRUE; /* whoops no field to be read */
1345 st = 1; /* but we got what we expected */
1346 nch = (consumed++, *str++);
1348 break;
1350 if (st && !suppress) rd++;
1351 else if (!st) break;
1353 /* A non-white-space character causes scanf to read, but not store,
1354 * a matching non-white-space character. */
1355 else
1357 if (nch == *format)
1358 nch = (consumed++, *str++);
1359 else break;
1361 format++;
1363 if (nch != '\0')
1365 consumed--, str--;
1368 return rd;
1372 /*********************************************************************
1373 * sscanf (NTDLL.@)
1375 int WINAPIV NTDLL_sscanf( const char *str, const char *format, ... )
1377 int ret;
1378 __ms_va_list valist;
1379 __ms_va_start( valist, format );
1380 ret = NTDLL_vsscanf( str, format, valist );
1381 __ms_va_end( valist );
1382 return ret;
1386 /*********************************************************************
1387 * _splitpath (NTDLL.@)
1389 * Split a path into its component pieces.
1391 * PARAMS
1392 * inpath [I] Path to split
1393 * drv [O] Destination for drive component (e.g. "A:"). Must be at least 3 characters.
1394 * dir [O] Destination for directory component. Should be at least MAX_PATH characters.
1395 * fname [O] Destination for File name component. Should be at least MAX_PATH characters.
1396 * ext [O] Destination for file extension component. Should be at least MAX_PATH characters.
1398 * RETURNS
1399 * Nothing.
1401 void __cdecl _splitpath(const char* inpath, char * drv, char * dir,
1402 char* fname, char * ext )
1404 const char *p, *end;
1406 if (inpath[0] && inpath[1] == ':')
1408 if (drv)
1410 drv[0] = inpath[0];
1411 drv[1] = inpath[1];
1412 drv[2] = 0;
1414 inpath += 2;
1416 else if (drv) drv[0] = 0;
1418 /* look for end of directory part */
1419 end = NULL;
1420 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1422 if (end) /* got a directory */
1424 if (dir)
1426 memcpy( dir, inpath, end - inpath );
1427 dir[end - inpath] = 0;
1429 inpath = end;
1431 else if (dir) dir[0] = 0;
1433 /* look for extension: what's after the last dot */
1434 end = NULL;
1435 for (p = inpath; *p; p++) if (*p == '.') end = p;
1437 if (!end) end = p; /* there's no extension */
1439 if (fname)
1441 memcpy( fname, inpath, end - inpath );
1442 fname[end - inpath] = 0;
1444 if (ext) strcpy( ext, end );