regarding bug 756 (corrected patch)
Daniel Gudbjartsson
dfg at decode.is
Wed Aug 7 17:57:57 CDT 2002
Very sorry about that. Attached is the corrected patch.
Daniel
"Dimitrie O. Paun" wrote:
>
> > From: Daniel Gudbjartsson <dfg at decode.is>
>
> > 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');
>
> First off, I can't parse the above. It's A && B && C + base -1. What is that?!?
>
> If you intend to clean it up, make it more readable:
> + if (('0' <= c) && (c <= min('0'+base-1, '9')) return c-')';
>
> 'cause that's what you want to say: if c is a valid digit (but no more then '9') in the given base, right?
>
> --
> Dimi.
--
Daniel Fannar Gudbjartsson
Decode Genetics
Sturlugata 8
101 Reykjavik
Iceland
dfg at decode.is
Tel: +354 570 1964
Fax: +354 570 1903
-------------- next part --------------
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 22:52:18 -0000
@@ -207,251 +207,10 @@
/*********************************************************************
* _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 22:52:19 -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 22:52:19 -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 22:52:19 -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