regarding bug 756

Daniel Gudbjartsson dfg at decode.is
Wed Aug 7 14:32:43 CDT 2002


Hello,

This patch implements fwscanf, swscanf and wscanf, as well as
implementing sscanf the "Microsoft" way. It also combines the
implementations of _cscanf and fscanf and implements most of the
remaining (documented) behaviour of all the scanf's. The only documented
feature that is not yet implemented is the I64 prefix.

I have tested most of the new features but not all. I am at least
convinced that this implementation is in no way less correct than the
old one :)

License: LGPL
Changelog:
	Combined the implementation of all the scanf's in a single place
(scanf.c)
	Added implementations of fwscanf, swscanf, wscanf and sscanf.
	Corrected the declaration of swscanf.
        Added implementation of the l, h, L and w prefixes.
	Added implementation of the c, C, s, S and n types.

Just for the record I plan on spending some time cleaning up some of the
basic functions in the run-time library, so if you like or dislike what
I have done please let me know.

Respectfully,
Daniel
-- 

Daniel Fannar Gudbjartsson
Decode Genetics
Sturlugata 8
101 Reykjavik
Iceland

dfg at decode.is
Tel: +354 570 1964
Fax: +354 570 1903
-------------- next part --------------
? .emacs
? main.cpp
? output.txt
? patch
? dlls/msvcrt/questions
? dlls/msvcrt/scanf.c
? documentation/wine-devel
? documentation/wine-devel.pdf
? documentation/wine-devel.ps
? documentation/wine-pkg
? documentation/wine-pkg.pdf
? documentation/wine-pkg.ps
? documentation/wine-set-html.tgz
? documentation/wine-user
? documentation/winedoc-html.tgz
? documentation/winedoc-pdf.tgz
? documentation/winedoc-ps.tgz
? documentation/winedoc-sgml.tgz
? documentation/winehq-shtml.tgz
? documentation/winelib-user
? documentation/winelib-user.pdf
? documentation/winelib-user.ps
? documentation/www.winehq.com
? programs/winver
Index: dlls/msvcrt/console.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/console.c,v
retrieving revision 1.8
diff -u -r1.8 console.c
--- dlls/msvcrt/console.c	9 Mar 2002 23:39:08 -0000	1.8
+++ dlls/msvcrt/console.c	7 Aug 2002 19:29:56 -0000
@@ -197,261 +197,20 @@
  * given base, or -1 if the given character is not a digit of the base.
  */
 static int char2digit(char c, int base) {
-    if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0');
+    if ((c>='0') && (c<='9') && (c<='0')+base-1) return (c-'0');
     if (base<=10) return -1;
-    if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10);
-    if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10);
+    if ((c>='A') && (c<='Z') && (c<='A')+base-11) return (c-'A')+10;
+    if ((c>='a') && (c<='z') && (c<='a')+base-11) return (c-'a')+10;
     return -1;
 }
 
 /*********************************************************************
  *		_cscanf (MSVCRT.@)
  */
-int _cscanf(const char* format, ...)
-{
-    /* NOTE: If you extend this function, extend MSVCRT_fscanf in file.c too */
-    int rd = 0;
-    int nch;
-    va_list ap;
-    if (!*format) return 0;
-    WARN("\"%s\": semi-stub\n", format);
-    va_start(ap, format);
-  LOCK_CONSOLE;
-    nch = _getch();
-    while (*format) {
-	/* a whitespace character in the format string causes scanf to read,
-	 * but not store, all consecutive white-space characters in the input
-	 * up to the next non-white-space character.  One white space character
-	 * in the input matches any number (including zero) and combination of
-	 * white-space characters in the input. */
-	if (isspace(*format)) {
-            /* skip whitespace */
-            while ((nch!=MSVCRT_EOF) && isspace(nch))
-                nch = _getch();
-        }
-	/* a format specification causes scanf to read and convert characters
-	 * in the input into values of a specified type.  The value is assigned
-	 * to an argument in the argument list.  Format specifications have
-	 * the form %[*][width][{h | l | I64 | L}]type */
-	/* FIXME: unimplemented: h/l/I64/L modifiers and some type specs. */
-        else if (*format == '%') {
-            int st = 0; int suppress = 0; int width = 0;
-	    int base, number_signed;
-            format++;
-	    /* look for leading asterisk, which means 'suppress assignment of
-	     * this field'. */
-	    if (*format=='*') {
-		format++;
-		suppress=1;
-	    }
-	    /* look for width specification */
-	    while (isdigit(*format)) {
-		width*=10;
-		width+=*format++ - '0';
-	    }
-	    if (width==0) width=-1; /* no width spec seen */
-            switch(*format) {
-	    case '%': /* read a percent symbol */
-		if (nch!='%') break;
-		nch = _getch();
-		break;
-	    case 'x':
-	    case 'X': /* hexadecimal integer. */
-		base = 16; number_signed = 0;
-		goto number;
-	    case 'o': /* octal integer */
-		base = 8; number_signed = 0;
-		goto number;
-	    case 'u': /* unsigned decimal integer */
-		base = 10; number_signed = 0;
-		goto number;
-	    case 'd': /* signed decimal integer */
-		base = 10; number_signed = 1;
-		goto number;
-	    case 'i': /* generic integer */
-		base = 0; number_signed = 1;
-	    number: {
-		    /* read an integer */
-                    int*val = suppress ? NULL : va_arg(ap, int*);
-                    int cur = 0; int negative = 0; int seendigit=0;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = _getch();
-                    /* get sign */
-                    if (number_signed && (nch == '-' || nch == '+')) {
-			negative = (nch=='-');
-                        nch = _getch();
-			if (width>0) width--;
-                    }
-		    /* look for leading indication of base */
-		    if (width!=0 && nch == '0') {
-                        nch = _getch();
-			if (width>0) width--;
-			seendigit=1;
-			if (width!=0 && (nch=='x' || nch=='X')) {
-			    if (base==0)
-				base=16;
-			    if (base==16) {
-				nch = _getch();
-				if (width>0) width--;
-				seendigit=0;
-			    }
-			} else if (base==0)
-			    base = 8;
-		    }
-		    if (base==0)
-			base=10;
-		    /* throw away leading zeros */
-		    while (width!=0 && nch=='0') {
-                        nch = _getch();
-			if (width>0) width--;
-			seendigit=1;
-		    }
-		    /* get first digit.  Keep working copy negative, as the
-		     * range of negative numbers in two's complement notation
-		     * is one larger than the range of positive numbers. */
-		    if (width!=0 && char2digit(nch, base)!=-1) {
-			cur = -char2digit(nch, base);
-			nch = _getch();
-			if (width>0) width--;
-			seendigit=1;
-		    }
-                    /* read until no more digits */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                        cur = cur*base + char2digit(nch, base);
-                        nch = _getch();
-			if (width>0) width--;
-			seendigit=1;
-                    }
-		    /* negate parsed number if non-negative */
-		    if (!negative) cur=-cur;
-		    /* okay, done! */
-		    if (!seendigit) break; /* not a valid number */
-                    st = 1;
-                    if (!suppress) *val = cur;
-                }
-                break;
-	    case 'e':
-	    case 'E':
-	    case 'f':
-	    case 'g':
-            case 'G': { /* read a float */
-                    float*val = suppress ? NULL : va_arg(ap, float*);
-                    float cur = 0;
-		    int negative = 0;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = _getch();
-		    /* get sign. */
-                    if (nch == '-' || nch == '+') {
-			negative = (nch=='-');
-			if (width>0) width--;
-			if (width==0) break;
-                        nch = _getch();
-                    }
-		    /* get first digit. */
-		    if (!isdigit(nch)) break;
-		    cur = (nch - '0') * (negative ? -1 : 1);
-                    nch = _getch();
-		    if (width>0) width--;
-                    /* read until no more digits */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                        cur = cur*10 + (nch - '0');
-                        nch = _getch();
-			if (width>0) width--;
-                    }
-		    /* handle decimals */
-                    if (width!=0 && nch == '.') {
-                        float dec = 1;
-                        nch = _getch();
-			if (width>0) width--;
-                        while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                            dec /= 10;
-                            cur += dec * (nch - '0');
-                            nch = _getch();
-			    if (width>0) width--;
-                        }
-                    }
-		    /* handle exponent */
-		    if (width!=0 && (nch == 'e' || nch == 'E')) {
-			int exponent = 0, negexp = 0;
-			float expcnt;
-                        nch = _getch();
-			if (width>0) width--;
-			/* possible sign on the exponent */
-			if (width!=0 && (nch=='+' || nch=='-')) {
-			    negexp = (nch=='-');
-                            nch = _getch();
-			    if (width>0) width--;
-			}
-			/* exponent digits */
-			while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-			    exponent *= 10;
-			    exponent += (nch - '0');
-                            nch = _getch();
-			    if (width>0) width--;
-                        }
-			/* update 'cur' with this exponent. */
-			expcnt =  negexp ? .1 : 10;
-			while (exponent!=0) {
-			    if (exponent&1)
-				cur*=expcnt;
-			    exponent/=2;
-			    expcnt=expcnt*expcnt;
-			}
-		    }
-                    st = 1;
-                    if (!suppress) *val = cur;
-                }
-                break;
-            case 's': { /* read a word */
-                    char*str = suppress ? NULL : va_arg(ap, char*);
-                    char*sptr = str;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = _getch();
-                    /* read until whitespace */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && !isspace(nch)) {
-                        if (!suppress) *sptr++ = nch;
-			st++;
-                        nch = _getch();
-			if (width>0) width--;
-                    }
-                    /* terminate */
-                    if (!suppress) *sptr = 0;
-                    TRACE("read word: %s\n", str);
-                }
-                break;
-            default: FIXME("unhandled: %%%c\n", *format);
-		/* From spec: "if a percent sign is followed by a character
-		 * that has no meaning as a format-control character, that
-		 * character and the following characters are treated as
-		 * an ordinary sequence of characters, that is, a sequence
-		 * of characters that must match the input.  For example,
-		 * to specify that a percent-sign character is to be input,
-		 * use %%."
-		 * LEAVING AS-IS because we catch bugs better that way. */
-            }
-            if (st && !suppress) rd++;
-            else break;
-        }
-	/* a non-white-space character causes scanf to read, but not store,
-	 * a matching non-white-space character. */
-        else {
-            /* check for character match */
-            if (nch == *format)
-               nch = _getch();
-            else break;
-        }
-        format++;
-    }
-    if (nch != MSVCRT_EOF)
-      _ungetch(nch);
-    UNLOCK_CONSOLE;
-    va_end(ap);
-    TRACE("returning %d\n", rd);
-    return rd;
-}
+#undef WIDE_SCANF
+#define CONSOLE 1
+#undef STRING
+#include "scanf.c"
 
 /*********************************************************************
  *		_kbhit (MSVCRT.@)
Index: dlls/msvcrt/file.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/file.c,v
retrieving revision 1.33
diff -u -r1.33 file.c
--- dlls/msvcrt/file.c	31 Jul 2002 20:04:57 -0000	1.33
+++ dlls/msvcrt/file.c	7 Aug 2002 19:29:56 -0000
@@ -1860,7 +1860,7 @@
   return _lseek(file->_file,*pos,SEEK_SET);
 }
 
-/* helper function for fscanf.  Returns the value of character c in the
+/* helper function for *scanf.  Returns the value of character c in the
  * given base, or -1 if the given character is not a digit of the base.
  */
 static int char2digit(char c, int base) {
@@ -1871,257 +1871,48 @@
     return -1;
 }
 
+/* helper function for *wscanf.  Returns the value of character c in the
+ * given base, or -1 if the given character is not a digit of the base.
+ */
+static int wchar2digit(WCHAR c, int base) {
+    if ((c>=L'0') && (c<=L'9') && (c<=L'0'+base-1)) return (c-L'0');
+    if (base<=10) return -1;
+    if ((c>=L'A') && (c<=L'Z') && (c<=L'A'+base-11)) return (c-L'A')+10;
+    if ((c>=L'a') && (c<=L'z') && (c<=L'a'+base-11)) return (c-L'a')+10;
+    return -1;
+}
+
 /*********************************************************************
  *		fscanf (MSVCRT.@)
- * Implemented based on
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp
- * Extended by C. Scott Ananian <cananian at alumni.princeton.edu> to handle
- * more types of format spec.
- */
-int MSVCRT_fscanf(MSVCRT_FILE* file, const char *format, ...)
-{
-    /* NOTE: If you extend this function, extend MSVCRT__cscanf in console.c too */
-    int rd = 0;
-    int nch;
-    va_list ap;
-    if (!*format) return 0;
-    WARN("%p (\"%s\"): semi-stub\n", file, format);
-    nch = MSVCRT_fgetc(file);
-    va_start(ap, format);
-    while (*format) {
-	/* a whitespace character in the format string causes scanf to read,
-	 * but not store, all consecutive white-space characters in the input
-	 * up to the next non-white-space character.  One white space character
-	 * in the input matches any number (including zero) and combination of
-	 * white-space characters in the input. */
-	if (isspace(*format)) {
-            /* skip whitespace */
-            while ((nch!=MSVCRT_EOF) && isspace(nch))
-                nch = MSVCRT_fgetc(file);
-        }
-	/* a format specification causes scanf to read and convert characters
-	 * in the input into values of a specified type.  The value is assigned
-	 * to an argument in the argument list.  Format specifications have
-	 * the form %[*][width][{h | l | I64 | L}]type */
-	/* FIXME: unimplemented: h/l/I64/L modifiers and some type specs. */
-        else if (*format == '%') {
-            int st = 0; int suppress = 0; int width = 0;
-	    int base, number_signed;
-            format++;
-	    /* look for leading asterisk, which means 'suppress assignment of
-	     * this field'. */
-	    if (*format=='*') {
-		format++;
-		suppress=1;
-	    }
-	    /* look for width specification */
-	    while (isdigit(*format)) {
-		width*=10;
-		width+=*format++ - '0';
-	    }
-	    if (width==0) width=-1; /* no width spec seen */
-            switch(*format) {
-	    case '%': /* read a percent symbol */
-		if (nch!='%') break;
-		nch = MSVCRT_fgetc(file);
-		break;
-	    case 'x':
-	    case 'X': /* hexadecimal integer. */
-		base = 16; number_signed = 0;
-		goto number;
-	    case 'o': /* octal integer */
-		base = 8; number_signed = 0;
-		goto number;
-	    case 'u': /* unsigned decimal integer */
-		base = 10; number_signed = 0;
-		goto number;
-	    case 'd': /* signed decimal integer */
-		base = 10; number_signed = 1;
-		goto number;
-	    case 'i': /* generic integer */
-		base = 0; number_signed = 1;
-	    number: {
-		    /* read an integer */
-                    int*val = suppress ? NULL : va_arg(ap, int*);
-                    int cur = 0; int negative = 0; int seendigit=0;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = MSVCRT_fgetc(file);
-                    /* get sign */
-                    if (number_signed && (nch == '-' || nch == '+')) {
-			negative = (nch=='-');
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-                    }
-		    /* look for leading indication of base */
-		    if (width!=0 && nch == '0') {
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-			seendigit=1;
-			if (width!=0 && (nch=='x' || nch=='X')) {
-			    if (base==0)
-				base=16;
-			    if (base==16) {
-				nch = MSVCRT_fgetc(file);
-				if (width>0) width--;
-				seendigit=0;
-			    }
-			} else if (base==0)
-			    base = 8;
-		    }
-		    if (base==0)
-			base=10;
-		    /* throw away leading zeros */
-		    while (width!=0 && nch=='0') {
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-			seendigit=1;
-		    }
-		    /* get first digit.  Keep working copy negative, as the
-		     * range of negative numbers in two's complement notation
-		     * is one larger than the range of positive numbers. */
-		    if (width!=0 && char2digit(nch, base)!=-1) {
-			cur = -char2digit(nch, base);
-			nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-			seendigit=1;
-		    }
-                    /* read until no more digits */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                        cur = cur*base + char2digit(nch, base);
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-			seendigit=1;
-                    }
-		    /* negate parsed number if non-negative */
-		    if (!negative) cur=-cur;
-		    /* okay, done! */
-		    if (!seendigit) break; /* not a valid number */
-                    st = 1;
-                    if (!suppress) *val = cur;
-                }
-                break;
-	    case 'e':
-	    case 'E':
-	    case 'f':
-	    case 'g':
-            case 'G': { /* read a float */
-                    float*val = suppress ? NULL : va_arg(ap, float*);
-                    float cur = 0;
-		    int negative = 0;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = MSVCRT_fgetc(file);
-		    /* get sign. */
-                    if (nch == '-' || nch == '+') {
-			negative = (nch=='-');
-			if (width>0) width--;
-			if (width==0) break;
-                        nch = MSVCRT_fgetc(file);
-                    }
-		    /* get first digit. */
-		    if (!isdigit(nch)) break;
-		    cur = (nch - '0') * (negative ? -1 : 1);
-                    nch = MSVCRT_fgetc(file);
-		    if (width>0) width--;
-                    /* read until no more digits */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                        cur = cur*10 + (nch - '0');
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-                    }
-		    /* handle decimals */
-                    if (width!=0 && nch == '.') {
-                        float dec = 1;
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-                        while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-                            dec /= 10;
-                            cur += dec * (nch - '0');
-                            nch = MSVCRT_fgetc(file);
-			    if (width>0) width--;
-                        }
-                    }
-		    /* handle exponent */
-		    if (width!=0 && (nch == 'e' || nch == 'E')) {
-			int exponent = 0, negexp = 0;
-			float expcnt;
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-			/* possible sign on the exponent */
-			if (width!=0 && (nch=='+' || nch=='-')) {
-			    negexp = (nch=='-');
-                            nch = MSVCRT_fgetc(file);
-			    if (width>0) width--;
-			}
-			/* exponent digits */
-			while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
-			    exponent *= 10;
-			    exponent += (nch - '0');
-                            nch = MSVCRT_fgetc(file);
-			    if (width>0) width--;
-                        }
-			/* update 'cur' with this exponent. */
-			expcnt =  negexp ? .1 : 10;
-			while (exponent!=0) {
-			    if (exponent&1)
-				cur*=expcnt;
-			    exponent/=2;
-			    expcnt=expcnt*expcnt;
-			}
-		    }
-                    st = 1;
-                    if (!suppress) *val = cur;
-                }
-                break;
-            case 's': { /* read a word */
-                    char*str = suppress ? NULL : va_arg(ap, char*);
-                    char*sptr = str;
-                    /* skip initial whitespace */
-                    while ((nch!=MSVCRT_EOF) && isspace(nch))
-                        nch = MSVCRT_fgetc(file);
-                    /* read until whitespace */
-                    while (width!=0 && (nch!=MSVCRT_EOF) && !isspace(nch)) {
-                        if (!suppress) *sptr++ = nch;
-			st++;
-                        nch = MSVCRT_fgetc(file);
-			if (width>0) width--;
-                    }
-                    /* terminate */
-                    if (!suppress) *sptr = 0;
-                    TRACE("read word: %s\n", str);
-                }
-                break;
-            default: FIXME("unhandled: %%%c\n", *format);
-		/* From spec: "if a percent sign is followed by a character
-		 * that has no meaning as a format-control character, that
-		 * character and the following characters are treated as
-		 * an ordinary sequence of characters, that is, a sequence
-		 * of characters that must match the input.  For example,
-		 * to specify that a percent-sign character is to be input,
-		 * use %%."
-		 * LEAVING AS-IS because we catch bugs better that way. */
-            }
-            if (st && !suppress) rd++;
-            else break;
-        }
-	/* a non-white-space character causes scanf to read, but not store,
-	 * a matching non-white-space character. */
-        else {
-            /* check for character match */
-            if (nch == *format)
-               nch = MSVCRT_fgetc(file);
-            else break;
-        }
-        format++;
-    }
-    if (nch!=MSVCRT_EOF) {
-        FIXME("need ungetch\n");
-    }
-    va_end(ap);
-    TRACE("returning %d\n", rd);
-    return rd;
-}
+ */
+#undef WIDE_SCANF
+#undef CONSOLE
+#undef STRING
+#include "scanf.c"
+
+/*********************************************************************
+ *		fwscanf (MSVCRT.@)
+ */
+#define WIDE_SCANF 1
+#undef CONSOLE
+#undef STRING
+#include "scanf.c"
+
+/*********************************************************************
+ *		sscanf (MSVCRT.@)
+ */
+#undef WIDE_SCANF
+#undef CONSOLE
+#define STRING 1
+#include "scanf.c"
+
+/*********************************************************************
+ *		swscanf (MSVCRT.@)
+ */
+#define WIDE_SCANF 1
+#undef CONSOLE
+#define STRING 1
+#include "scanf.c"
 
 /*********************************************************************
  *		fseek (MSVCRT.@)
@@ -2349,6 +2140,20 @@
 }
 
 /*********************************************************************
+ *		wscanf (MSVCRT.@)
+ */
+int MSVCRT_wscanf(const WCHAR *format, ...)
+{
+  va_list valist;
+  int res;
+
+  va_start(valist, format);
+  res = MSVCRT_fwscanf(MSVCRT_stdin, format, valist);
+  va_end(valist);
+  return res;
+}
+
+/*********************************************************************
  *		rename (MSVCRT.@)
  */
 int MSVCRT_rename(const char *oldpath,const char *newpath)
@@ -2589,3 +2394,4 @@
     va_end(valist);
     return res;
 }
+
Index: dlls/msvcrt/msvcrt.spec
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/msvcrt.spec,v
retrieving revision 1.47
diff -u -r1.47 msvcrt.spec
--- dlls/msvcrt/msvcrt.spec	31 Jul 2002 20:04:57 -0000	1.47
+++ dlls/msvcrt/msvcrt.spec	7 Aug 2002 19:29:57 -0000
@@ -619,7 +619,7 @@
 @ cdecl ftell(ptr) MSVCRT_ftell
 @ varargs fwprintf(ptr wstr) MSVCRT_fwprintf
 @ cdecl fwrite(ptr long long ptr) MSVCRT_fwrite
-@ stub fwscanf #(ptr wstr) varargs
+@ varargs fwscanf(ptr wstr) MSVCRT_fwscanf
 @ cdecl getc(ptr) MSVCRT_getc
 @ cdecl getchar() MSVCRT_getchar
 @ cdecl getenv(str) MSVCRT_getenv
@@ -697,7 +697,7 @@
 @ varargs sprintf(ptr str) sprintf
 @ forward -noimport sqrt ntdll.sqrt
 @ cdecl srand(long) srand
-@ varargs sscanf(str str) sscanf
+@ varargs sscanf(str str) MSVCRT_sscanf
 @ cdecl strcat(str str) strcat
 @ cdecl strchr(str long) strchr
 @ cdecl strcmp(str str) strcmp
@@ -762,6 +762,6 @@
 @ stub wcsxfrm #(wstr wstr long)
 @ cdecl wctomb(ptr long) MSVCRT_wctomb
 @ varargs wprintf(wstr) MSVCRT_wprintf
-@ stub wscanf #(wstr) varargs
+@ varargs wscanf(wstr) MSVCRT_wscanf
 @ stub _Gettnames
 @ stub __lc_collate_cp
Index: include/msvcrt/stdio.h
===================================================================
RCS file: /home/wine/wine/include/msvcrt/stdio.h,v
retrieving revision 1.6
diff -u -r1.6 stdio.h
--- include/msvcrt/stdio.h	31 May 2002 23:06:50 -0000	1.6
+++ include/msvcrt/stdio.h	7 Aug 2002 19:29:58 -0000
@@ -206,7 +206,7 @@
 MSVCRT(wint_t) MSVCRT(putwchar)(MSVCRT(wint_t));
 int         MSVCRT(putws)(const WCHAR*);
 int         MSVCRT(swprintf)(WCHAR*,const WCHAR*,...);
-int         MSVCRT(swscanf)(WCHAR*,const WCHAR*,...);
+int         MSVCRT(swscanf)(const WCHAR*,const WCHAR*,...);
 MSVCRT(wint_t) MSVCRT(ungetwc)(MSVCRT(wint_t),MSVCRT(FILE)*);
 int         MSVCRT(vfwprintf)(MSVCRT(FILE)*,const WCHAR*,va_list);
 int         MSVCRT(vswprintf)(WCHAR*,const WCHAR*,va_list);
--- /dev/null	Thu Aug 30 20:30:55 2001
+++ dlls/msvcrt/scanf.c	Wed Aug  7 19:29:45 2002
@@ -0,0 +1,472 @@
+/*
+ * general implementation of scanf used by scanf, sscanf, fscanf,
+ * _cscanf, wscanf, swscanf and fwscanf
+ *
+ * Copyright 1996,1998 Marcus Meissner
+ * Copyright 1996 Jukka Iivonen
+ * Copyright 1997,2000 Uwe Bonnes
+ * Copyright 2000 Jon Griffiths
+ * Copyright 2002 Daniel Gudbjartsson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef WIDE_SCANF
+#define _L_(x) L##x
+#define _CHAR_ WCHAR
+#define _EOF_ MSVCRT_WEOF
+#define _ISSPACE_(c) MSVCRT_iswspace(c)
+#define _ISDIGIT_(c) MSVCRT_iswdigit(c)
+#define _CONVERT_(c) c /*** FIXME ***/
+#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base))
+#else /* WIDE_SCANF */
+#define _L_(x) x
+#define _CHAR_ char
+#define _EOF_ MSVCRT_EOF
+#define _ISSPACE_(c) isspace(c)
+#define _ISDIGIT_(c) isdigit(c)
+#define _CONVERT_(c) c /*** FIXME ***/
+#define _CHAR2DIGIT_(c, base) char2digit((c), (base))
+#endif /* WIDE_SCANF */
+
+#ifdef CONSOLE
+#define _GETC_(file) _getch()
+#define _UNGETC_(nch, file) _ungetch(nch)
+#define _FUNCTION_ _cscanf(const _CHAR_ *format, ...)
+#else
+#ifdef STRING
+#define _GETC_(file) *file++
+#define _UNGETC_(nch, file) file--
+#ifdef WIDE_SCANF
+#define _FUNCTION_ MSVCRT_swscanf(const WCHAR *file, const WCHAR *format, ...)
+#else /* WIDE_SCANF */
+#define _FUNCTION_ MSVCRT_sscanf(const char *file, const char *format, ...)
+#endif /* WIDE_SCANF */
+#else /* STRING */
+#ifdef WIDE_SCANF
+#define _GETC_(file) MSVCRT_fgetwc(file)
+#define _UNGETC_(nch, file) MSVCRT_ungetwc(nch, file)
+#define _FUNCTION_ MSVCRT_fwscanf(MSVCRT_FILE* file, const WCHAR *format, ...)
+#else /* WIDE_SCANF */
+#define _GETC_(file) MSVCRT_fgetc(file)
+#define _UNGETC_(nch, file) MSVCRT_ungetc(nch, file)
+#define _FUNCTION_ MSVCRT_fscanf(MSVCRT_FILE* file, const char *format, ...)
+#endif /* WIDE_SCANF */
+#endif /* STRING */
+#endif /* CONSOLE */
+
+/*********************************************************************
+ * Implemented based on
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp
+ * Extended by C. Scott Ananian <cananian at alumni.princeton.edu> to handle
+ * more types of format spec.
+ */
+int _FUNCTION_ {
+    int rd = 0;
+    int nch;
+    va_list ap;
+    if (!*format) return 0;
+#ifndef WIDE_SCANF
+#ifdef CONSOLE
+    WARN("(\"%s\"): semi-stub\n", format);
+#else /* CONSOLE */
+#ifdef STRING
+    WARN("%s (\"%s\"): semi-stub\n", file, format);
+#else /* STRING */
+    WARN("%p (\"%s\"): semi-stub\n", file, format);
+#endif /* STRING */
+#endif /* CONSOLE */
+#endif /* WIDE_SCANF */
+    nch = _GETC_(file);
+    va_start(ap, format);
+    while (*format) {
+	/* a whitespace character in the format string causes scanf to read,
+	 * but not store, all consecutive white-space characters in the input
+	 * up to the next non-white-space character.  One white space character
+	 * in the input matches any number (including zero) and combination of
+	 * white-space characters in the input. */
+	if (_ISSPACE_(*format)) {
+            /* skip whitespace */
+            while ((nch!=_EOF_) && _ISSPACE_(nch))
+                nch = _GETC_(file);
+        }
+	/* a format specification causes scanf to read and convert characters
+	 * in the input into values of a specified type.  The value is assigned
+	 * to an argument in the argument list.  Format specifications have
+	 * the form %[*][width][{h | l | I64 | L}]type */
+        else if (*format == _L_('%')) {
+            int st = 0; int suppress = 0; int width = 0;
+	    int base, number_signed;
+	    int h_prefix = 0;
+	    int l_prefix = 0;
+	    int L_prefix = 0;
+	    int w_prefix = 0;
+	    /* int I64_prefix = 0; */
+            format++;
+	    /* look for leading asterisk, which means 'suppress assignment of
+	     * this field'. */
+	    if (*format==_L_('*')) {
+		format++;
+		suppress=1;
+	    }
+	    /* look for width specification */
+	    while (_ISDIGIT_(*format)) {
+		width*=10;
+		width+=*format++ - _L_('0');
+	    }
+	    if (width==0) width=-1; /* no width spec seen */
+	    /* read prefix (if any) */
+	    int prefix_finished = 0;
+	    while (!prefix_finished) {
+		switch(*format) {
+		case _L_('h'): h_prefix = 1; break;
+		case _L_('l'): l_prefix = 1; break;
+		case _L_('w'): w_prefix = 1; break;
+		case _L_('L'): L_prefix = 1; break;
+		case _L_('I'):
+		    if (*(format + 1) == _L_('6') &&
+			*(format + 2) == _L_('4')) {
+			/* I64_prefix = 1; */
+			format += 2;
+			FIXME("I64 prefix currently not implemented in fscanf/fwscanf");
+		    }
+		    break;
+		default:
+		    prefix_finished = 1;
+		}
+		if (!prefix_finished) format++;
+	    }
+	    /* read type */
+            switch(*format) {
+	    case _L_('%'): { /* read a percent symbol */
+		    while ((nch!=_EOF_) && _ISSPACE_(nch))
+			nch = _GETC_(file);
+		    if (nch==_L_('%')) {
+			suppress = 1; /* whoops no field to be read */
+			st = 1; /* but we got what we expected */
+			nch = _GETC_(file);
+		    }
+	        }
+		break;
+	    case _L_('x'):
+	    case _L_('X'): /* hexadecimal integer. */
+		base = 16; number_signed = 0;
+		goto number;
+	    case _L_('o'): /* octal integer */
+		base = 8; number_signed = 0;
+		goto number;
+	    case _L_('u'): /* unsigned decimal integer */
+		base = 10; number_signed = 0;
+		goto number;
+	    case _L_('d'): /* signed decimal integer */
+		base = 10; number_signed = 1;
+		goto number;
+	    case _L_('i'): /* generic integer */
+		base = 0; number_signed = 1;
+	    number: {
+		    /* read an integer */
+                    long unsigned int cur = 0;
+		    int negative = 0;
+		    int seendigit=0;
+                    /* skip initial whitespace */
+                    while ((nch!=_EOF_) && _ISSPACE_(nch))
+                        nch = _GETC_(file);
+                    /* get sign */
+                    if (number_signed && (nch == _L_('-') ||
+					  nch == _L_('+'))) {
+			negative = (nch==_L_('-'));
+                        nch = _GETC_(file);
+			if (width>0) width--;
+                    }
+		    /* look for leading indication of base */
+		    if (width!=0 && nch == _L_('0')) {
+                        nch = _GETC_(file);
+			if (width>0) width--;
+			seendigit=1;
+			if (width!=0 && (nch==_L_('x') || nch==_L_('X'))) {
+			    if (base==0)
+				base=16;
+			    if (base==16) {
+				nch = _GETC_(file);
+				if (width>0) width--;
+				seendigit=0;
+			    }
+			} else if (base==0)
+			    base = 8;
+		    }
+		    /* throw away leading zeros */
+		    while (width!=0 && nch==_L_('0')) {
+                        nch = _GETC_(file);
+			if (width>0) width--;
+			seendigit=1;
+		    }
+		    if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) {
+			cur = _CHAR2DIGIT_(nch, base);
+			nch = _GETC_(file);
+			if (width>0) width--;
+			seendigit=1;
+		    }
+                    /* read until no more digits */
+                    while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
+                        cur = cur*base + _CHAR2DIGIT_(nch, base);
+                        nch = _GETC_(file);
+			if (width>0) width--;
+			seendigit=1;
+                    }
+		    /* okay, done! */
+		    if (!seendigit) break; /* not a valid number */
+                    st = 1;
+                    if (!suppress) {
+#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur
+			if (number_signed) {
+			    if (l_prefix) _SET_NUMBER_(long int);
+			    else if (h_prefix) _SET_NUMBER_(short int);
+			    else _SET_NUMBER_(int);
+			} else {
+			    if (negative) {
+				WARN("Dropping sign in reading a negative number into an unsigned value");
+				negative = 0;
+			    }
+			    if (l_prefix) _SET_NUMBER_(unsigned long int);
+			    else if (h_prefix)
+				_SET_NUMBER_(unsigned short int);
+			    else _SET_NUMBER_(unsigned int);
+			}
+		    }
+                }
+                break;
+	    case _L_('e'):
+	    case _L_('E'):
+	    case _L_('f'):
+	    case _L_('g'):
+            case _L_('G'): { /* read a float */
+                    long double cur = 0;
+		    int negative = 0;
+                    /* skip initial whitespace */
+                    while ((nch!=_EOF_) && _ISSPACE_(nch))
+                        nch = _GETC_(file);
+		    /* get sign. */
+                    if (nch == _L_('-') || nch == _L_('+')) {
+			negative = (nch==_L_('-'));
+			if (width>0) width--;
+			if (width==0) break;
+                        nch = _GETC_(file);
+                    }
+		    /* get first digit. */
+		    if (!_ISDIGIT_(nch)) break;
+		    cur = (nch - _L_('0')) * (negative ? -1 : 1);
+                    nch = _GETC_(file);
+		    if (width>0) width--;
+                    /* read until no more digits */
+                    while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
+                        cur = cur*10 + (nch - _L_('0'));
+                        nch = _GETC_(file);
+			if (width>0) width--;
+                    }
+		    /* handle decimals */
+                    if (width!=0 && nch == _L_('.')) {
+                        float dec = 1;
+                        nch = _GETC_(file);
+			if (width>0) width--;
+                        while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
+                            dec /= 10;
+                            cur += dec * (nch - _L_('0'));
+                            nch = _GETC_(file);
+			    if (width>0) width--;
+                        }
+                    }
+		    /* handle exponent */
+		    if (width!=0 && (nch == _L_('e') || nch == _L_('E'))) {
+			int exponent = 0, negexp = 0;
+			float expcnt;
+                        nch = _GETC_(file);
+			if (width>0) width--;
+			/* possible sign on the exponent */
+			if (width!=0 && (nch==_L_('+') || nch==_L_('-'))) {
+			    negexp = (nch==_L_('-'));
+                            nch = _GETC_(file);
+			    if (width>0) width--;
+			}
+			/* exponent digits */
+			while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
+			    exponent *= 10;
+			    exponent += (nch - _L_('0'));
+                            nch = _GETC_(file);
+			    if (width>0) width--;
+                        }
+			/* update 'cur' with this exponent. */
+			expcnt =  negexp ? .1 : 10;
+			while (exponent!=0) {
+			    if (exponent&1)
+				cur*=expcnt;
+			    exponent/=2;
+			    expcnt=expcnt*expcnt;
+			}
+		    }
+                    st = 1;
+                    if (!suppress) {
+			if (L_prefix) _SET_NUMBER_(long double);
+			else if (l_prefix) _SET_NUMBER_(double);
+			else _SET_NUMBER_(float);
+		    }
+                }
+                break;
+		/* According to
+		 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf_type_field_characters.asp
+		 * 's' reads a character string in a call to fscanf
+		 * and 'S' a wide character string and vice versa in a
+		 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
+		 * this behaviour. 'h' forces reading char * but 'l' and 'w'
+		 * force reading WCHAR. */
+	    case _L_('s'):
+		    if (w_prefix || l_prefix) goto widecharstring;
+		    else if (h_prefix) goto charstring;
+#ifdef WIDE_SCANF
+		    else goto widecharstring;
+#else /* WIDE_SCANF */
+		    else goto charstring;
+#endif /* WIDE_SCANF */
+	    case _L_('S'):
+		    if (w_prefix || l_prefix) goto widecharstring;
+		    else if (h_prefix) goto charstring;
+#ifdef WIDE_SCANF
+		    else goto charstring;
+#else /* WIDE_SCANF */
+		    else goto widecharstring;
+#endif /* WIDE_SCANF */
+	    charstring: { /* read a word into a char */
+		    char*str = suppress ? NULL : va_arg(ap, char*);
+                    char*sptr = str;
+                    /* skip initial whitespace */
+                    while ((nch!=_EOF_) && _ISSPACE_(nch))
+                        nch = _GETC_(file);
+                    /* read until whitespace */
+                    while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
+#ifdef WIDE_SCANF
+                        if (!suppress) *sptr++ = _CONVERT_(nch);
+#else /* WIDE_SCANF */
+                        if (!suppress) *sptr++ = nch;
+#endif /* WIDE_SCANF */
+			st++;
+                        nch = _GETC_(file);
+			if (width>0) width--;
+                    }
+                    /* terminate */
+                    if (!suppress) *sptr = 0;
+                }
+                break;
+	    widecharstring: { /* read a word into a WCHAR * */
+		    WCHAR*str =
+			suppress ? NULL : va_arg(ap, WCHAR*);
+                    WCHAR*sptr = str;
+                    /* skip initial whitespace */
+                    while ((nch!=_EOF_) && _ISSPACE_(nch))
+                        nch = _GETC_(file);
+                    /* read until whitespace */
+                    while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
+#ifdef WIDE_SCANF
+                        if (!suppress) *sptr++ = nch;
+#else /* WIDE_SCANF */
+                        if (!suppress) *sptr++ = _CONVERT_(nch);
+#endif /* WIDE_SCANF */
+			st++;
+                        nch = _GETC_(file);
+			if (width>0) width--;
+                    }
+                    /* terminate */
+                    if (!suppress) *sptr = 0;
+                }
+                break;
+            /* 'c' and 'C work analogously to 's' and 'S' as described
+	     * above */
+	    case _L_('c'):
+		    if (w_prefix || l_prefix) goto widecharacter;
+		    else if (h_prefix) goto character;
+#ifdef WIDE_SCANF
+		    else goto widecharacter;
+#else /* WIDE_SCANF */
+		    else goto character;
+#endif /* WIDE_SCANF */
+	    case _L_('C'):
+		    if (w_prefix || l_prefix) goto widecharacter;
+		    else if (h_prefix) goto character;
+#ifdef WIDE_SCANF
+		    else goto character;
+#else /* WIDE_SCANF */
+		    else goto widecharacter;
+#endif /* WIDE_SCANF */
+	  character: { /* read single character into char */
+		    if (!suppress) {
+			char*c = va_arg(ap, char*);
+#ifdef WIDE_SCANF
+			*c = _CONVERT_(nch);
+#else /* WIDE_SCANF */
+			*c = nch;
+#endif /* WIDE_SCANF */
+			st = 1;
+		    }
+ 		    nch = _GETC_(file);
+	        }
+		break;
+	  widecharacter: {
+		    if (!suppress) { /* read single character into WCHAR */
+			WCHAR*c = va_arg(ap, WCHAR*);
+#ifdef WIDE_SCANF
+			*c = nch;
+#else /* WIDE_SCANF */
+			*c = _CONVERT_(nch);
+#endif /* WIDE_SCANF */
+			st = 1;
+		    }
+		    nch = _GETC_(file);
+	        }
+		break;
+	    case _L_('n'): {
+ 		    if (!suppress) {
+			int*n = va_arg(ap, int*);
+			*n = rd;
+		    }
+	        }
+		break;
+            default: FIXME("unhandled: %%%c\n", *format);
+		/* From spec: "if a percent sign is followed by a character
+		 * that has no meaning as a format-control character, that
+		 * character and the following characters are treated as
+		 * an ordinary sequence of characters, that is, a sequence
+		 * of characters that must match the input.  For example,
+		 * to specify that a percent-sign character is to be input,
+		 * use %%."
+		 * LEAVING AS-IS because we catch bugs better that way. */
+            }
+            if (st && !suppress) rd++;
+            else if (!st) break;
+        }
+	/* a non-white-space character causes scanf to read, but not store,
+	 * a matching non-white-space character. */
+        else {
+            /* check for character match */
+            if (nch == *format) {
+		nch = _GETC_(file);
+            } else break;
+        }
+        format++;
+    }
+    if (nch!=_EOF_) {
+	_UNGETC_(nch, file);
+    }
+    va_end(ap);
+    TRACE("returning %d\n", rd);
+    return rd;
+}


More information about the wine-patches mailing list