ddraw/tests: Rewrite LimitTest().
[wine.git] / dlls / ntdll / string.c
blobc349add54363e5f2abc5bd188cd34dccea8e079f
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 * strpbrk (NTDLL.@)
169 char * __cdecl NTDLL_strpbrk( const char *str, const char *accept )
171 return strpbrk( str, accept );
175 /*********************************************************************
176 * strrchr (NTDLL.@)
178 char * __cdecl NTDLL_strrchr( const char *str, int c )
180 return strrchr( str, c );
184 /*********************************************************************
185 * strspn (NTDLL.@)
187 size_t __cdecl NTDLL_strspn( const char *str, const char *accept )
189 return strspn( str, accept );
193 /*********************************************************************
194 * strstr (NTDLL.@)
196 char * __cdecl NTDLL_strstr( const char *haystack, const char *needle )
198 return strstr( haystack, needle );
202 /*********************************************************************
203 * _memccpy (NTDLL.@)
205 void * __cdecl _memccpy( void *dst, const void *src, int c, size_t n )
207 return memccpy( dst, src, c, n );
211 /*********************************************************************
212 * _memicmp (NTDLL.@)
214 * Compare two blocks of memory as strings, ignoring case.
216 * PARAMS
217 * s1 [I] First string to compare to s2
218 * s2 [I] Second string to compare to s1
219 * len [I] Number of bytes to compare
221 * RETURNS
222 * An integer less than, equal to, or greater than zero indicating that
223 * s1 is less than, equal to or greater than s2 respectively.
225 * NOTES
226 * Any Nul characters in s1 or s2 are ignored. This function always
227 * compares up to len bytes or the first place where s1 and s2 differ.
229 INT __cdecl _memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
231 int ret = 0;
232 while (len--)
234 if ((ret = tolower(*s1) - tolower(*s2))) break;
235 s1++;
236 s2++;
238 return ret;
242 /*********************************************************************
243 * _stricmp (NTDLL.@)
244 * _strcmpi (NTDLL.@)
246 int __cdecl _stricmp( LPCSTR str1, LPCSTR str2 )
248 return strcasecmp( str1, str2 );
252 /*********************************************************************
253 * _strnicmp (NTDLL.@)
255 int __cdecl _strnicmp( LPCSTR str1, LPCSTR str2, size_t n )
257 return strncasecmp( str1, str2, n );
261 /*********************************************************************
262 * _strupr (NTDLL.@)
264 * Convert a string to upper case.
266 * PARAMS
267 * str [I/O] String to convert
269 * RETURNS
270 * str. There is no error return, if str is NULL or invalid, this
271 * function will crash.
273 LPSTR __cdecl _strupr( LPSTR str )
275 LPSTR ret = str;
276 for ( ; *str; str++) *str = toupper(*str);
277 return ret;
281 /*********************************************************************
282 * _strlwr (NTDLL.@)
284 * Convert a string to lowercase
286 * PARAMS
287 * str [I/O] String to convert
289 * RETURNS
290 * str. There is no error return, if str is NULL or invalid, this
291 * function will crash.
293 LPSTR __cdecl _strlwr( LPSTR str )
295 LPSTR ret = str;
296 for ( ; *str; str++) *str = tolower(*str);
297 return ret;
301 /*********************************************************************
302 * tolower (NTDLL.@)
304 int __cdecl NTDLL_tolower( int c )
306 return tolower( c );
310 /*********************************************************************
311 * toupper (NTDLL.@)
313 int __cdecl NTDLL_toupper( int c )
315 return toupper( c );
319 /*********************************************************************
320 * isalnum (NTDLL.@)
322 int __cdecl NTDLL_isalnum( int c )
324 return isalnum( c );
328 /*********************************************************************
329 * isalpha (NTDLL.@)
331 int __cdecl NTDLL_isalpha( int c )
333 return isalpha( c );
337 /*********************************************************************
338 * iscntrl (NTDLL.@)
340 int __cdecl NTDLL_iscntrl( int c )
342 return iscntrl( c );
346 /*********************************************************************
347 * isdigit (NTDLL.@)
349 int __cdecl NTDLL_isdigit( int c )
351 return isdigit( c );
355 /*********************************************************************
356 * isgraph (NTDLL.@)
358 int __cdecl NTDLL_isgraph( int c )
360 return isgraph( c );
364 /*********************************************************************
365 * islower (NTDLL.@)
367 int __cdecl NTDLL_islower( int c )
369 return islower( c );
373 /*********************************************************************
374 * isprint (NTDLL.@)
376 int __cdecl NTDLL_isprint( int c )
378 return isprint( c );
382 /*********************************************************************
383 * ispunct (NTDLL.@)
385 int __cdecl NTDLL_ispunct( int c )
387 return ispunct( c );
391 /*********************************************************************
392 * isspace (NTDLL.@)
394 int __cdecl NTDLL_isspace( int c )
396 return isspace( c );
400 /*********************************************************************
401 * isupper (NTDLL.@)
403 int __cdecl NTDLL_isupper( int c )
405 return isupper( c );
409 /*********************************************************************
410 * isxdigit (NTDLL.@)
412 int __cdecl NTDLL_isxdigit( int c )
414 return isxdigit( c );
418 /*********************************************************************
419 * __isascii (NTDLL.@)
421 int CDECL NTDLL___isascii(int c)
423 return (unsigned)c < 0x80;
427 /*********************************************************************
428 * __toascii (NTDLL.@)
430 int CDECL NTDLL___toascii(int c)
432 return (unsigned)c & 0x7f;
436 /*********************************************************************
437 * __iscsym (NTDLL.@)
439 int CDECL NTDLL___iscsym(int c)
441 return (c < 127 && (isalnum(c) || c == '_'));
445 /*********************************************************************
446 * __iscsymf (NTDLL.@)
448 int CDECL NTDLL___iscsymf(int c)
450 return (c < 127 && (isalpha(c) || c == '_'));
454 /*********************************************************************
455 * _toupper (NTDLL.@)
457 int CDECL NTDLL__toupper(int c)
459 return c - 0x20; /* sic */
463 /*********************************************************************
464 * _tolower (NTDLL.@)
466 int CDECL NTDLL__tolower(int c)
468 return c + 0x20; /* sic */
472 /*********************************************************************
473 * strtol (NTDLL.@)
475 LONG __cdecl NTDLL_strtol( const char *nptr, char **endptr, int base )
477 return strtol( nptr, endptr, base );
481 /*********************************************************************
482 * strtoul (NTDLL.@)
484 ULONG __cdecl NTDLL_strtoul( const char *nptr, char **endptr, int base )
486 return strtoul( nptr, endptr, base );
490 /*********************************************************************
491 * _ultoa (NTDLL.@)
493 * Convert an unsigned long integer to a string.
495 * RETURNS
496 * str.
498 * NOTES
499 * - Converts value to a Nul terminated string which is copied to str.
500 * - The maximum length of the copied str is 33 bytes.
501 * - Does not check if radix is in the range of 2 to 36.
502 * - If str is NULL it crashes, as the native function does.
504 char * __cdecl _ultoa(
505 ULONG value, /* [I] Value to be converted */
506 char *str, /* [O] Destination for the converted value */
507 int radix) /* [I] Number base for conversion */
509 char buffer[33];
510 char *pos;
511 int digit;
513 pos = &buffer[32];
514 *pos = '\0';
516 do {
517 digit = value % radix;
518 value = value / radix;
519 if (digit < 10) {
520 *--pos = '0' + digit;
521 } else {
522 *--pos = 'a' + digit - 10;
523 } /* if */
524 } while (value != 0L);
526 memcpy(str, pos, &buffer[32] - pos + 1);
527 return str;
531 /*********************************************************************
532 * _ltoa (NTDLL.@)
534 * Convert a long integer to a string.
536 * RETURNS
537 * str.
539 * NOTES
540 * - Converts value to a Nul terminated string which is copied to str.
541 * - The maximum length of the copied str is 33 bytes. If radix
542 * is 10 and value is negative, the value is converted with sign.
543 * - Does not check if radix is in the range of 2 to 36.
544 * - If str is NULL it crashes, as the native function does.
546 char * __cdecl _ltoa(
547 LONG value, /* [I] Value to be converted */
548 char *str, /* [O] Destination for the converted value */
549 int radix) /* [I] Number base for conversion */
551 ULONG val;
552 int negative;
553 char buffer[33];
554 char *pos;
555 int digit;
557 if (value < 0 && radix == 10) {
558 negative = 1;
559 val = -value;
560 } else {
561 negative = 0;
562 val = value;
563 } /* if */
565 pos = &buffer[32];
566 *pos = '\0';
568 do {
569 digit = val % radix;
570 val = val / radix;
571 if (digit < 10) {
572 *--pos = '0' + digit;
573 } else {
574 *--pos = 'a' + digit - 10;
575 } /* if */
576 } while (val != 0L);
578 if (negative) {
579 *--pos = '-';
580 } /* if */
582 memcpy(str, pos, &buffer[32] - pos + 1);
583 return str;
587 /*********************************************************************
588 * _itoa (NTDLL.@)
590 * Converts an integer to a string.
592 * RETURNS
593 * str.
595 * NOTES
596 * - Converts value to a '\0' terminated string which is copied to str.
597 * - The maximum length of the copied str is 33 bytes. If radix
598 * is 10 and value is negative, the value is converted with sign.
599 * - Does not check if radix is in the range of 2 to 36.
600 * - If str is NULL it crashes, as the native function does.
602 char * __cdecl _itoa(
603 int value, /* [I] Value to be converted */
604 char *str, /* [O] Destination for the converted value */
605 int radix) /* [I] Number base for conversion */
607 return _ltoa(value, str, radix);
611 /*********************************************************************
612 * _ui64toa (NTDLL.@)
614 * Converts a large unsigned integer to a string.
616 * RETURNS
617 * str.
619 * NOTES
620 * - Converts value to a '\0' terminated string which is copied to str.
621 * - The maximum length of the copied str is 65 bytes.
622 * - Does not check if radix is in the range of 2 to 36.
623 * - If str is NULL it crashes, as the native function does.
625 char * __cdecl _ui64toa(
626 ULONGLONG value, /* [I] Value to be converted */
627 char *str, /* [O] Destination for the converted value */
628 int radix) /* [I] Number base for conversion */
630 char buffer[65];
631 char *pos;
632 int digit;
634 pos = &buffer[64];
635 *pos = '\0';
637 do {
638 digit = value % radix;
639 value = value / radix;
640 if (digit < 10) {
641 *--pos = '0' + digit;
642 } else {
643 *--pos = 'a' + digit - 10;
644 } /* if */
645 } while (value != 0L);
647 memcpy(str, pos, &buffer[64] - pos + 1);
648 return str;
652 /*********************************************************************
653 * _i64toa (NTDLL.@)
655 * Converts a large integer to a string.
657 * RETURNS
658 * str.
660 * NOTES
661 * - Converts value to a Nul terminated string which is copied to str.
662 * - The maximum length of the copied str is 65 bytes. If radix
663 * is 10 and value is negative, the value is converted with sign.
664 * - Does not check if radix is in the range of 2 to 36.
665 * - If str is NULL it crashes, as the native function does.
667 * DIFFERENCES
668 * - The native DLL converts negative values (for base 10) wrong:
669 *| -1 is converted to -18446744073709551615
670 *| -2 is converted to -18446744073709551614
671 *| -9223372036854775807 is converted to -9223372036854775809
672 *| -9223372036854775808 is converted to -9223372036854775808
673 * The native msvcrt _i64toa function and our ntdll _i64toa function
674 * do not have this bug.
676 char * __cdecl _i64toa(
677 LONGLONG value, /* [I] Value to be converted */
678 char *str, /* [O] Destination for the converted value */
679 int radix) /* [I] Number base for conversion */
681 ULONGLONG val;
682 int negative;
683 char buffer[65];
684 char *pos;
685 int digit;
687 if (value < 0 && radix == 10) {
688 negative = 1;
689 val = -value;
690 } else {
691 negative = 0;
692 val = value;
693 } /* if */
695 pos = &buffer[64];
696 *pos = '\0';
698 do {
699 digit = val % radix;
700 val = val / radix;
701 if (digit < 10) {
702 *--pos = '0' + digit;
703 } else {
704 *--pos = 'a' + digit - 10;
705 } /* if */
706 } while (val != 0L);
708 if (negative) {
709 *--pos = '-';
710 } /* if */
712 memcpy(str, pos, &buffer[64] - pos + 1);
713 return str;
717 /*********************************************************************
718 * _atoi64 (NTDLL.@)
720 * Convert a string to a large integer.
722 * PARAMS
723 * str [I] String to be converted
725 * RETURNS
726 * Success: The integer value represented by str.
727 * Failure: 0. Note that this cannot be distinguished from a successful
728 * return, if the string contains "0".
730 * NOTES
731 * - Accepts: {whitespace} [+|-] {digits}
732 * - No check is made for value overflow, only the lower 64 bits are assigned.
733 * - If str is NULL it crashes, as the native function does.
735 LONGLONG __cdecl _atoi64( const char *str )
737 ULONGLONG RunningTotal = 0;
738 BOOL bMinus = FALSE;
740 while (*str == ' ' || (*str >= '\011' && *str <= '\015')) {
741 str++;
742 } /* while */
744 if (*str == '+') {
745 str++;
746 } else if (*str == '-') {
747 bMinus = TRUE;
748 str++;
749 } /* if */
751 while (*str >= '0' && *str <= '9') {
752 RunningTotal = RunningTotal * 10 + *str - '0';
753 str++;
754 } /* while */
756 return bMinus ? -RunningTotal : RunningTotal;
760 /*********************************************************************
761 * atoi (NTDLL.@)
763 int __cdecl NTDLL_atoi( const char *nptr )
765 return _atoi64( nptr );
769 /*********************************************************************
770 * atol (NTDLL.@)
772 LONG __cdecl NTDLL_atol( const char *nptr )
774 return _atoi64( nptr );
778 /* helper function for *scanf. Returns the value of character c in the
779 * given base, or -1 if the given character is not a digit of the base.
781 static int char2digit( char c, int base )
783 if ((c >= '0' && c <= '9') && (c <= '0'+base-1)) return (c-'0');
784 if (base <= 10) return -1;
785 if ((c >= 'A') && (c <= 'Z') && (c <= 'A'+base-11)) return (c-'A'+10);
786 if ((c >= 'a') && (c <= 'z') && (c <= 'a'+base-11)) return (c-'a'+10);
787 return -1;
791 static int NTDLL_vsscanf( const char *str, const char *format, __ms_va_list ap)
793 int rd = 0, consumed = 0;
794 int nch;
795 if (!*format) return 0;
797 nch = (consumed++, *str++);
798 if (nch == '\0')
799 return EOF;
801 while (*format)
803 if (isspace( *format ))
805 /* skip whitespace */
806 while ((nch != '\0') && isspace( nch ))
807 nch = (consumed++, *str++);
809 else if (*format == '%')
811 int st = 0;
812 BOOLEAN suppress = 0;
813 int width = 0;
814 int base;
815 int h_prefix = 0;
816 BOOLEAN l_prefix = FALSE;
817 BOOLEAN L_prefix = FALSE;
818 BOOLEAN w_prefix = FALSE;
819 BOOLEAN I64_prefix = FALSE;
820 BOOLEAN prefix_finished = FALSE;
821 format++;
822 /* a leading asterisk means 'suppress assignment of this field' */
823 if (*format == '*')
825 format++;
826 suppress = TRUE;
828 /* look for width specification */
829 while (isdigit( *format ))
831 width *= 10;
832 width += *format++ - '0';
834 if (width == 0) width = -1; /* no width spec seen */
835 /* read prefix (if any) */
836 while (!prefix_finished)
838 switch (*format)
840 case 'h': h_prefix++; break;
841 case 'l':
842 if (*(format+1) == 'l')
844 I64_prefix = TRUE;
845 format++;
847 l_prefix = TRUE;
848 break;
849 case 'w': w_prefix = TRUE; break;
850 case 'L': L_prefix = TRUE; break;
851 case 'I':
852 if (*(format + 1) == '6' &&
853 *(format + 2) == '4')
855 I64_prefix = TRUE;
856 format += 2;
858 break;
859 default:
860 prefix_finished = TRUE;
862 if (!prefix_finished) format++;
864 /* read type */
865 switch (*format)
867 case 'p':
868 case 'P': /* pointer. */
869 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = TRUE;
870 /* fall through */
871 case 'x':
872 case 'X': /* hexadecimal integer. */
873 base = 16;
874 goto number;
875 case 'o': /* octal integer */
876 base = 8;
877 goto number;
878 case 'u': /* unsigned decimal integer */
879 base = 10;
880 goto number;
881 case 'd': /* signed decimal integer */
882 base = 10;
883 goto number;
884 case 'i': /* generic integer */
885 base = 0;
886 number:
888 /* read an integer */
889 ULONGLONG cur = 0;
890 BOOLEAN negative = FALSE;
891 BOOLEAN seendigit = FALSE;
892 /* skip initial whitespace */
893 while ((nch != '\0') && isspace( nch ))
894 nch = (consumed++, *str++);
895 /* get sign */
896 if (nch == '-' || nch == '+')
898 negative = (nch == '-');
899 nch = (consumed++, *str++);
900 if (width > 0) width--;
902 /* look for leading indication of base */
903 if (width != 0 && nch == '0' && *format != 'p' && *format != 'P')
905 nch = (consumed++, *str++);
906 if (width > 0) width--;
907 seendigit = TRUE;
908 if (width != 0 && (nch == 'x' || nch == 'X'))
910 if (base == 0)
911 base = 16;
912 if (base == 16)
914 nch = (consumed++, *str++);
915 if (width > 0) width--;
916 seendigit = FALSE;
918 } else if (base == 0)
919 base = 8;
921 /* format %i without indication of base */
922 if (base == 0)
923 base = 10;
924 /* throw away leading zeros */
925 while (width != 0 && nch == '0')
927 nch = (consumed++, *str++);
928 if (width > 0) width--;
929 seendigit = TRUE;
931 if (width != 0 && char2digit( nch, base ) != -1)
933 cur = char2digit( nch, base );
934 nch = (consumed++, *str++);
935 if (width > 0) width--;
936 seendigit = TRUE;
938 /* read until no more digits */
939 while (width != 0 && nch != '\0' && char2digit( nch, base ) != -1)
941 cur = cur*base + char2digit( nch, base );
942 nch = (consumed++, *str++);
943 if (width > 0) width--;
944 seendigit = TRUE;
946 /* okay, done! */
947 if (!seendigit) break; /* not a valid number */
948 st = 1;
949 if (!suppress)
951 #define _SET_NUMBER_( type ) *va_arg( ap, type* ) = negative ? -cur : cur
952 if (I64_prefix) _SET_NUMBER_( LONGLONG );
953 else if (l_prefix) _SET_NUMBER_( LONG );
954 else if (h_prefix == 1) _SET_NUMBER_( short int );
955 else _SET_NUMBER_( int );
958 break;
959 case 'e':
960 case 'E':
961 case 'f':
962 case 'g':
963 case 'G':
964 { /* read a float */
965 long double cur = 1, expcnt = 10;
966 ULONGLONG d, hlp;
967 int exp = 0;
968 BOOLEAN negative = FALSE;
969 /*unsigned fpcontrol;*/
970 BOOLEAN negexp;
972 /* skip initial whitespace */
973 while (nch != '\0' && isspace( nch ))
974 nch = (consumed++, *str++);
976 /* get sign */
977 if (nch == '-' || nch == '+')
979 negative = (nch == '-');
980 if (width > 0) width--;
981 if (width == 0) break;
982 nch = (consumed++, *str++);
985 /* get first digit */
986 if ('.' != nch)
988 if (!isdigit( nch )) break;
989 d = nch - '0';
990 nch = (consumed++, *str++);
991 if (width > 0) width--;
992 /* read until no more digits */
993 while (width != 0 && nch != '\0' && isdigit( nch ))
995 hlp = d * 10 + nch - '0';
996 nch = (consumed++, *str++);
997 if (width > 0) width--;
998 if(d > (ULONGLONG)-1/10 || hlp < d)
1000 exp++;
1001 break;
1003 else
1004 d = hlp;
1006 while (width != 0 && nch != '\0' && isdigit( nch ))
1008 exp++;
1009 nch = (consumed++, *str++);
1010 if (width > 0) width--;
1013 else
1014 d = 0; /* Fix: .8 -> 0.8 */
1016 /* handle decimals */
1017 if (width != 0 && nch == '.')
1019 nch = (consumed++, *str++);
1020 if (width > 0) width--;
1022 while (width != 0 && nch != '\0' && isdigit( nch ))
1024 hlp = d * 10 + nch - '0';
1025 nch = (consumed++, *str++);
1026 if (width > 0) width--;
1027 if(d > (ULONGLONG)-1/10 || hlp < d)
1028 break;
1030 d = hlp;
1031 exp--;
1033 while (width != 0 && nch != '\0' && isdigit( nch ))
1035 nch = (consumed++, *str++);
1036 if (width > 0) width--;
1040 /* handle exponent */
1041 if (width != 0 && (nch == 'e' || nch == 'E'))
1043 int sign = 1, e = 0;
1045 nch = (consumed++, *str++);
1046 if (width > 0) width--;
1047 if (width != 0 && (nch == '+' || nch == '-'))
1049 if(nch == '-')
1050 sign = -1;
1051 nch = (consumed++, *str++);
1052 if (width > 0) width--;
1055 /* exponent digits */
1056 while (width != 0 && nch != '\0' && isdigit( nch ))
1058 if (e > INT_MAX/10 || (e = e * 10 + nch - '0') < 0)
1059 e = INT_MAX;
1060 nch = (consumed++, *str++);
1061 if (width > 0) width--;
1063 e *= sign;
1065 if(exp < 0 && e < 0 && e+exp > 0) exp = INT_MIN;
1066 else if(exp > 0 && e > 0 && e+exp < 0) exp = INT_MAX;
1067 else exp += e;
1070 /*fpcontrol = _control87(0, 0);
1071 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
1072 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);*/
1074 negexp = (exp < 0);
1075 if (negexp)
1076 exp = -exp;
1077 /* update 'cur' with this exponent. */
1078 while (exp)
1080 if(exp & 1)
1081 cur *= expcnt;
1082 exp /= 2;
1083 expcnt = expcnt*expcnt;
1085 cur = (negexp ? d/cur : d*cur);
1087 /*_control87(fpcontrol, 0xffffffff);*/
1089 st = 1;
1090 if (!suppress)
1092 if (L_prefix || l_prefix) _SET_NUMBER_( double );
1093 else _SET_NUMBER_( float );
1096 break;
1097 /* According to msdn,
1098 * 's' reads a character string in a call to fscanf
1099 * and 'S' a wide character string and vice versa in a
1100 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
1101 * this behaviour. 'h' forces reading char * but 'l' and 'w'
1102 * force reading WCHAR. */
1103 case 's':
1104 if (w_prefix || l_prefix) goto widecharstring;
1105 else if (h_prefix) goto charstring;
1106 else goto charstring;
1107 case 'S':
1108 if (w_prefix || l_prefix) goto widecharstring;
1109 else if (h_prefix) goto charstring;
1110 else goto widecharstring;
1111 charstring:
1112 { /* read a word into a char */
1113 char *sptr = suppress ? NULL : va_arg( ap, char * );
1114 char *sptr_beg = sptr;
1115 unsigned size = UINT_MAX;
1116 /* skip initial whitespace */
1117 while (nch != '\0' && isspace( nch ))
1118 nch = (consumed++, *str++);
1119 /* read until whitespace */
1120 while (width != 0 && nch != '\0' && !isspace( nch ))
1122 if (!suppress)
1124 *sptr++ = nch;
1125 if(size > 1) size--;
1126 else
1128 *sptr_beg = 0;
1129 return rd;
1132 st++;
1133 nch = (consumed++, *str++);
1134 if (width > 0) width--;
1136 /* terminate */
1137 if (st && !suppress) *sptr = 0;
1139 break;
1140 widecharstring:
1141 { /* read a word into a WCHAR * */
1142 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1143 WCHAR *sptr_beg = sptr;
1144 unsigned size = UINT_MAX;
1145 /* skip initial whitespace */
1146 while (nch != '\0' && isspace( nch ))
1147 nch = (consumed++, *str++);
1148 /* read until whitespace */
1149 while (width != 0 && nch != '\0' && !isspace( nch ))
1151 if (!suppress)
1153 *sptr++ = nch;
1154 if (size > 1) size--;
1155 else
1157 *sptr_beg = 0;
1158 return rd;
1161 st++;
1162 nch = (consumed++, *str++);
1163 if (width > 0) width--;
1165 /* terminate */
1166 if (st && !suppress) *sptr = 0;
1168 break;
1169 /* 'c' and 'C work analogously to 's' and 'S' as described
1170 * above */
1171 case 'c':
1172 if (w_prefix || l_prefix) goto widecharacter;
1173 else if (h_prefix) goto character;
1174 else goto character;
1175 case 'C':
1176 if (w_prefix || l_prefix) goto widecharacter;
1177 else if (h_prefix) goto character;
1178 else goto widecharacter;
1179 character:
1180 { /* read single character into char */
1181 char *sptr = suppress ? NULL : va_arg( ap, char * );
1182 char *sptr_beg = sptr;
1183 unsigned size = UINT_MAX;
1184 if (width == -1) width = 1;
1185 while (width && nch != '\0')
1187 if (!suppress)
1189 *sptr++ = nch;
1190 if(size) size--;
1191 else
1193 *sptr_beg = 0;
1194 return rd;
1197 st++;
1198 width--;
1199 nch = (consumed++, *str++);
1202 break;
1203 widecharacter:
1204 { /* read single character into a WCHAR */
1205 WCHAR *sptr = suppress ? NULL : va_arg( ap, WCHAR * );
1206 WCHAR *sptr_beg = sptr;
1207 unsigned size = UINT_MAX;
1208 if (width == -1) width = 1;
1209 while (width && nch != '\0')
1211 if (!suppress)
1213 *sptr++ = nch;
1214 if (size) size--;
1215 else
1217 *sptr_beg = 0;
1218 return rd;
1221 st++;
1222 width--;
1223 nch = (consumed++, *str++);
1226 break;
1227 case 'n':
1229 if (!suppress)
1231 int *n = va_arg( ap, int * );
1232 *n = consumed - 1;
1234 /* This is an odd one: according to the standard,
1235 * "Execution of a %n directive does not increment the
1236 * assignment count returned at the completion of
1237 * execution" even if it wasn't suppressed with the
1238 * '*' flag. The Corrigendum to the standard seems
1239 * to contradict this (comment out the assignment to
1240 * suppress below if you want to implement these
1241 * alternate semantics) but the windows program I'm
1242 * looking at expects the behavior I've coded here
1243 * (which happens to be what glibc does as well).
1245 suppress = TRUE;
1246 st = 1;
1248 break;
1249 case '[':
1251 char *sptr = suppress ? NULL : va_arg( ap, char * );
1252 char *sptr_beg = sptr;
1253 RTL_BITMAP bitMask;
1254 ULONG Mask[8] = { 0 };
1255 BOOLEAN invert = FALSE; /* Set if we are NOT to find the chars */
1256 unsigned size = UINT_MAX;
1258 RtlInitializeBitMap( &bitMask, Mask, sizeof(Mask) * 8 );
1260 /* Read the format */
1261 format++;
1262 if (*format == '^')
1264 invert = TRUE;
1265 format++;
1267 if (*format == ']')
1269 RtlSetBits( &bitMask, ']', 1 );
1270 format++;
1272 while (*format && (*format != ']'))
1274 /* According to msdn:
1275 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
1276 if ((*format == '-') && (*(format + 1) != ']'))
1278 if ((*(format - 1)) < *(format + 1))
1279 RtlSetBits( &bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1) );
1280 else
1281 RtlSetBits( &bitMask, *(format + 1) , *(format - 1) - *(format + 1) );
1282 format++;
1284 else
1285 RtlSetBits( &bitMask, *format, 1 );
1286 format++;
1288 /* read until char is not suitable */
1289 while (width != 0 && nch != '\0')
1291 if (!invert)
1293 if(RtlAreBitsSet( &bitMask, nch, 1 ))
1295 if (!suppress) *sptr++ = nch;
1297 else
1298 break;
1300 else
1302 if (RtlAreBitsClear( &bitMask, nch, 1 ))
1304 if (!suppress) *sptr++ = nch;
1306 else
1307 break;
1309 st++;
1310 nch = (consumed++, *str++);
1311 if (width > 0) width--;
1312 if(size > 1) size--;
1313 else
1315 if (!suppress) *sptr_beg = 0;
1316 return rd;
1319 /* terminate */
1320 if (!suppress) *sptr = 0;
1322 break;
1323 default:
1324 /* From spec: "if a percent sign is followed by a character
1325 * that has no meaning as a format-control character, that
1326 * character and the following characters are treated as
1327 * an ordinary sequence of characters, that is, a sequence
1328 * of characters that must match the input. For example,
1329 * to specify that a percent-sign character is to be input,
1330 * use %%." */
1331 while (nch != '\0' && isspace( nch ))
1332 nch = (consumed++, *str++);
1333 if (nch == *format)
1335 suppress = TRUE; /* whoops no field to be read */
1336 st = 1; /* but we got what we expected */
1337 nch = (consumed++, *str++);
1339 break;
1341 if (st && !suppress) rd++;
1342 else if (!st) break;
1344 /* A non-white-space character causes scanf to read, but not store,
1345 * a matching non-white-space character. */
1346 else
1348 if (nch == *format)
1349 nch = (consumed++, *str++);
1350 else break;
1352 format++;
1354 if (nch != '\0')
1356 consumed--, str--;
1359 return rd;
1363 /*********************************************************************
1364 * sscanf (NTDLL.@)
1366 int WINAPIV NTDLL_sscanf( const char *str, const char *format, ... )
1368 int ret;
1369 __ms_va_list valist;
1370 __ms_va_start( valist, format );
1371 ret = NTDLL_vsscanf( str, format, valist );
1372 __ms_va_end( valist );
1373 return ret;
1377 /*********************************************************************
1378 * _splitpath (NTDLL.@)
1380 * Split a path into its component pieces.
1382 * PARAMS
1383 * inpath [I] Path to split
1384 * drv [O] Destination for drive component (e.g. "A:"). Must be at least 3 characters.
1385 * dir [O] Destination for directory component. Should be at least MAX_PATH characters.
1386 * fname [O] Destination for File name component. Should be at least MAX_PATH characters.
1387 * ext [O] Destination for file extension component. Should be at least MAX_PATH characters.
1389 * RETURNS
1390 * Nothing.
1392 void __cdecl _splitpath(const char* inpath, char * drv, char * dir,
1393 char* fname, char * ext )
1395 const char *p, *end;
1397 if (inpath[0] && inpath[1] == ':')
1399 if (drv)
1401 drv[0] = inpath[0];
1402 drv[1] = inpath[1];
1403 drv[2] = 0;
1405 inpath += 2;
1407 else if (drv) drv[0] = 0;
1409 /* look for end of directory part */
1410 end = NULL;
1411 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1413 if (end) /* got a directory */
1415 if (dir)
1417 memcpy( dir, inpath, end - inpath );
1418 dir[end - inpath] = 0;
1420 inpath = end;
1422 else if (dir) dir[0] = 0;
1424 /* look for extension: what's after the last dot */
1425 end = NULL;
1426 for (p = inpath; *p; p++) if (*p == '.') end = p;
1428 if (!end) end = p; /* there's no extension */
1430 if (fname)
1432 memcpy( fname, inpath, end - inpath );
1433 fname[end - inpath] = 0;
1435 if (ext) strcpy( ext, end );