Improved unicode fileio support.
[reactos.git] / reactos / lib / msvcrt / stdio / vfscanf.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19 //#include <stdarg.h>
20 #include <msvcrt/stdarg.h> // robd
21 #include <msvcrt/crttypes.h> // robd
22
23 #include <msvcrt/errno.h>
24 #include <limits.h>
25 #include <msvcrt/ctype.h>
26 #include <msvcrt/stdio.h>
27 #include <msvcrt/stdlib.h>
28 #include <msvcrt/string.h>
29 #include <msvcrt/wchar.h>
30 #include <msvcrt/malloc.h>
31 #include <msvcrt/mbstring.h>
32 #include <msvcrt/internal/file.h>
33 #include <msvcrt/internal/stdio.h>
34
35 /* The internal entry points for `strtoX' take an extra flag argument
36 saying whether or not to parse locale-dependent number grouping. */
37
38 double __strtod_internal (const char *__nptr,char **__endptr, int __group);
39 float __strtof_internal (const char *__nptr, char **__endptr,int __group);
40 long double __strtold_internal (const char *__nptr,char **__endptr, int __group);
41 long int __strtol_internal (const char *__nptr, char **__endptr, int __base, int __group);
42 unsigned long int __strtoul_internal (const char *__nptr, char **__endptr, int __base, int __group);
43
44
45 #include <msvcrt/crttypes.h> // robd
46 //#ifdef __GNUC__
47 //#define HAVE_LONGLONG
48 //#define LONGLONG LONGLONG
49 //#else
50 //#define LONGLONG long
51 //#endif
52
53 /* Those are flags in the conversion format. */
54 # define LONG 0x001 /* l: long or double */
55 # define LONGDBL 0x002 /* L: LONGLONG or long double */
56 # define SHORT 0x004 /* h: short */
57 # define SUPPRESS 0x008 /* *: suppress assignment */
58 # define POINTER 0x010 /* weird %p pointer (`fake hex') */
59 # define NOSKIP 0x020 /* do not skip blanks */
60 # define WIDTH 0x040 /* width was given */
61 # define GROUP 0x080 /* ': group numbers */
62 # define MALLOC 0x100 /* a: malloc strings */
63
64 # define TYPEMOD (LONG|LONGDBL|SHORT)
65
66
67 # define ungetc(c, s) ((void) (c != EOF && --read_in), ungetc (c, s))
68 # define inchar() ((c = getc (s)), (void) (c != EOF && ++read_in), c)
69 # define encode_error() do { \
70 funlockfile (s); \
71 __set_errno (EILSEQ); \
72 return done; \
73 } while (0)
74 # define conv_error() do { \
75 funlockfile (s); \
76 return done; \
77 } while (0)
78 # define input_error() do { \
79 funlockfile (s); \
80 return done ? 0 : EOF; \
81 } while (0)
82 # define memory_error() do { \
83 funlockfile (s); \
84 __set_errno (ENOMEM); \
85 return EOF; \
86 } while (0)
87 # define ARGCHECK(s, format) \
88 do \
89 { \
90 /* Check file argument for consistence. */ \
91 if (!__validfp (s) || !s->__mode.__read) \
92 { \
93 __set_errno (EBADF); \
94 return EOF; \
95 } \
96 else if (format == NULL) \
97 { \
98 __set_errno (EINVAL); \
99 return EOF; \
100 } \
101 } while (0)
102
103 # define flockfile(S) /* nothing */
104 # define funlockfile(S) /* nothing */
105
106 char *wp = NULL; /* Workspace. */
107 size_t wpmax = 0; /* Maximal size of workspace. */
108 size_t wpsize = 0; /* Currently used bytes in workspace. */
109
110
111 void ADDW(int Ch) \
112 {
113 if (wpsize == wpmax)
114 {
115 char *old = wp;
116 wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax;
117 wp = (char *) malloc (wpmax);
118 if (old != NULL) {
119 memcpy (wp, old, wpsize);
120 free(old);
121 }
122 }
123 wp[wpsize++] = (Ch);
124 }
125
126
127 int __vfscanf (FILE *s, const char *format, va_list argptr)
128 {
129 va_list arg;
130 register const char *f = format;
131 register unsigned char fc; /* Current character of the format. */
132 register size_t done = 0; /* Assignments done. */
133 register size_t read_in = 0; /* Chars read in. */
134 register int c = 0; /* Last char read. */
135 register int width; /* Maximum field width. */
136 register int flags; /* Modifiers for current format element. */
137
138 /* Status for reading F-P nums. */
139 char got_dot, got_e, negative;
140 /* If a [...] is a [^...]. */
141 char not_in;
142 /* Base for integral numbers. */
143 int base;
144 /* Signedness for integral numbers. */
145 int number_signed;
146 /* Decimal point character. */
147 wchar_t decimal = '.';
148 /* The thousands character of the current locale. */
149 wchar_t thousands = ',';
150 /* Integral holding variables. */
151 union
152 {
153 LONGLONG q;
154 ULONGLONG uq;
155 long int l;
156 unsigned long int ul;
157 } num;
158 /* Character-buffer pointer. */
159 char *str = NULL;
160 wchar_t *wstr = NULL;
161 char **strptr = NULL;
162 size_t strsize = 0;
163 /* We must not react on white spaces immediately because they can
164 possibly be matched even if in the input stream no character is
165 available anymore. */
166 int skip_space = 0;
167 /* Workspace. */
168 char *tw; /* Temporary pointer. */
169
170 #ifdef __va_copy
171 __va_copy (arg, argptr);
172 #else
173 arg = (va_list) argptr;
174 #endif
175
176
177
178 /* Run through the format string. */
179 while (*f != '\0')
180 {
181 unsigned int argpos;
182 /* Extract the next argument, which is of type TYPE.
183 For a %N$... spec, this is the Nth argument from the beginning;
184 otherwise it is the next argument after the state now in ARG. */
185 #define ARG(type) va_arg(argptr,type)
186
187 if (!isascii (*f))
188 {
189 /* Non-ASCII, may be a multibyte. */
190 // int len = mblen (f, strlen (f));
191 int len =1;
192 if (len > 0)
193 {
194 do
195 {
196 c = inchar ();
197 if (c == EOF)
198 input_error ();
199 else if (c != *f++)
200 {
201 ungetc (c, s);
202 conv_error ();
203 }
204 }
205 while (--len > 0);
206 continue;
207 }
208 }
209
210 fc = *f++;
211 if (fc != '%')
212 {
213 /* Remember to skip spaces. */
214 if (isspace (fc))
215 {
216 skip_space = 1;
217 continue;
218 }
219
220 /* Read a character. */
221 c = inchar ();
222
223 /* Characters other than format specs must just match. */
224 if (c == EOF)
225 input_error ();
226
227 /* We saw white space char as the last character in the format
228 string. Now it's time to skip all leading white space. */
229 if (skip_space)
230 {
231 while (isspace (c))
232 if (inchar () == EOF && errno == EINTR)
233 conv_error ();
234 skip_space = 0;
235 }
236
237 if (c != fc)
238 {
239 ungetc (c, s);
240 conv_error ();
241 }
242
243 continue;
244 }
245
246 /* This is the start of the conversion string. */
247 flags = 0;
248
249 /* Initialize state of modifiers. */
250 argpos = 0;
251
252 /* Prepare temporary buffer. */
253 wpsize = 0;
254
255 /* Check for a positional parameter specification. */
256 if (isdigit (*f))
257 {
258 argpos = *f++ - '0';
259 while (isdigit (*f))
260 argpos = argpos * 10 + (*f++ - '0');
261 if (*f == '$')
262 ++f;
263 else
264 {
265 /* Oops; that was actually the field width. */
266 width = argpos;
267 flags |= WIDTH;
268 argpos = 0;
269 goto got_width;
270 }
271 }
272
273 /* Check for the assignment-suppressing and the number grouping flag. */
274 while (*f == '*' || *f == '\'')
275 switch (*f++)
276 {
277 case '*':
278 flags |= SUPPRESS;
279 break;
280 case '\'':
281 flags |= GROUP;
282 break;
283 }
284
285 /* We have seen width. */
286 if (isdigit (*f))
287 flags |= WIDTH;
288
289 /* Find the maximum field width. */
290 width = 0;
291 while (isdigit (*f))
292 {
293 width *= 10;
294 width += *f++ - '0';
295 }
296 got_width:
297 if (width == 0)
298 width = -1;
299
300 /* Check for type modifiers. */
301 while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
302 switch (*f++)
303 {
304 case 'h':
305 /* int's are short int's. */
306 if (flags & TYPEMOD)
307 /* Signal illegal format element. */
308 conv_error ();
309 flags |= SHORT;
310 break;
311 case 'l':
312 if (flags & (SHORT|LONGDBL))
313 conv_error ();
314 else if (flags & LONG)
315 {
316 /* A double `l' is equivalent to an `L'. */
317 flags &= ~LONG;
318 flags |= LONGDBL;
319 }
320 else
321 /* int's are long int's. */
322 flags |= LONG;
323 break;
324 case 'q':
325 case 'L':
326 /* double's are long double's, and int's are LONGLONG int's. */
327 if (flags & TYPEMOD)
328 /* Signal illegal format element. */
329 conv_error ();
330 flags |= LONGDBL;
331 break;
332 case 'a':
333 if (flags & TYPEMOD)
334 /* Signal illegal format element. */
335 conv_error ();
336 /* String conversions (%s, %[) take a `char **'
337 arg and fill it in with a malloc'd pointer. */
338 flags |= MALLOC;
339 break;
340 }
341
342 /* End of the format string? */
343 if (*f == '\0')
344 conv_error ();
345
346 /* We must take care for EINTR errors. */
347 if (c == EOF && errno == EINTR)
348 input_error ();
349
350 /* Find the conversion specifier. */
351 fc = *f++;
352 if (skip_space || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
353 {
354 /* Eat whitespace. */
355 do
356 if (inchar () == EOF && errno == EINTR)
357 input_error ();
358 while (isspace (c));
359 ungetc (c, s);
360 skip_space = 0;
361 }
362
363 switch (fc)
364 {
365 case '%': /* Must match a literal '%'. */
366 c = inchar ();
367 if (c != fc)
368 {
369 ungetc (c, s);
370 conv_error ();
371 }
372 break;
373
374 case 'n': /* Answer number of assignments done. */
375 /* Corrigendum 1 to ISO C 1990 describes the allowed flags
376 with the 'n' conversion specifier. */
377 if (!(flags & SUPPRESS))
378 {
379 /* Don't count the read-ahead. */
380 if (flags & LONGDBL)
381 *ARG (long int *) = read_in;
382 else if (flags & LONG)
383 *ARG (long int *) = read_in;
384 else if (flags & SHORT)
385 *ARG (short int *) = read_in;
386 else
387 *ARG (int *) = read_in;
388
389 #ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1
390 /* We have a severe problem here. The ISO C standard
391 contradicts itself in explaining the effect of the %n
392 format in `scanf'. While in ISO C:1990 and the ISO C
393 Amendement 1:1995 the result is described as
394
395 Execution of a %n directive does not effect the
396 assignment count returned at the completion of
397 execution of the f(w)scanf function.
398
399 in ISO C Corrigendum 1:1994 the following was added:
400
401 Subclause 7.9.6.2
402 Add the following fourth example:
403 In:
404 #include <stdio.h>
405 int d1, d2, n1, n2, i;
406 i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
407 the value 123 is assigned to d1 and the value3 to n1.
408 Because %n can never get an input failure the value
409 of 3 is also assigned to n2. The value of d2 is not
410 affected. The value 3 is assigned to i.
411
412 We go for now with the historically correct code fro ISO C,
413 i.e., we don't count the %n assignments. When it ever
414 should proof to be wrong just remove the #ifdef above. */
415 ++done;
416 #endif
417 }
418 break;
419
420 case 'c': /* Match characters. */
421 if ((flags & LONG) == 0)
422 {
423 if (!(flags & SUPPRESS))
424 {
425 str = ARG (char *);
426 if (str == NULL)
427 conv_error ();
428 }
429
430 c = inchar ();
431 if (c == EOF)
432 input_error ();
433
434 if (width == -1)
435 width = 1;
436
437 if (!(flags & SUPPRESS))
438 {
439 do
440 *str++ = c;
441 while (--width > 0 && inchar () != EOF);
442 }
443 else
444 while (--width > 0 && inchar () != EOF);
445
446 if (width > 0)
447 /* I.e., EOF was read. */
448 --read_in;
449
450 if (!(flags & SUPPRESS))
451 ++done;
452
453 break;
454 }
455 /* FALLTHROUGH */
456 case 'C':
457 /* Get UTF-8 encoded wide character. Here we assume (as in
458 other parts of the libc) that we only have to handle
459 UTF-8. */
460 {
461 wint_t val;
462 size_t cnt = 0;
463 int first = 1;
464
465 if (!(flags & SUPPRESS))
466 {
467 wstr = ARG (wchar_t *);
468 if (str == NULL)
469 conv_error ();
470 }
471
472 do
473 {
474 #define NEXT_WIDE_CHAR(First) \
475 c = inchar (); \
476 if (c == EOF) { \
477 /* EOF is only an error for the first character. */ \
478 if (First) { \
479 input_error (); \
480 } \
481 else \
482 { \
483 --read_in; \
484 break; \
485 } \
486 } \
487 val = c; \
488 if (val >= 0x80) \
489 { \
490 if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
491 encode_error (); \
492 if ((c & 0xe0) == 0xc0) \
493 { \
494 /* We expect two bytes. */ \
495 cnt = 1; \
496 val &= 0x1f; \
497 } \
498 else if ((c & 0xf0) == 0xe0) \
499 { \
500 /* We expect three bytes. */ \
501 cnt = 2; \
502 val &= 0x0f; \
503 } \
504 else if ((c & 0xf8) == 0xf0) \
505 { \
506 /* We expect four bytes. */ \
507 cnt = 3; \
508 val &= 0x07; \
509 } \
510 else if ((c & 0xfc) == 0xf8) \
511 { \
512 /* We expect five bytes. */ \
513 cnt = 4; \
514 val &= 0x03; \
515 } \
516 else \
517 { \
518 /* We expect six bytes. */ \
519 cnt = 5; \
520 val &= 0x01; \
521 } \
522 \
523 do \
524 { \
525 c = inchar (); \
526 if (c == EOF \
527 || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
528 encode_error (); \
529 val <<= 6; \
530 val |= c & 0x3f; \
531 } \
532 while (--cnt > 0); \
533 } \
534 \
535 if (!(flags & SUPPRESS)) \
536 *wstr++ = val; \
537 first = 0
538
539 NEXT_WIDE_CHAR (first);
540 }
541 while (--width > 0);
542
543 if (width > 0)
544 /* I.e., EOF was read. */
545 --read_in;
546
547 if (!(flags & SUPPRESS))
548 ++done;
549 }
550 break;
551
552 case 's': /* Read a string. */
553 if (flags & LONG)
554 /* We have to process a wide character string. */
555 goto wide_char_string;
556
557 #define STRING_ARG(Str, Type) \
558 if (!(flags & SUPPRESS)) \
559 { \
560 if (flags & MALLOC) \
561 { \
562 /* The string is to be stored in a malloc'd buffer. */ \
563 strptr = ARG (char **); \
564 if (strptr == NULL) \
565 conv_error (); \
566 /* Allocate an initial buffer. */ \
567 strsize = 100; \
568 *strptr = malloc (strsize * sizeof (Type)); \
569 Str = (Type *) *strptr; \
570 } \
571 else \
572 Str = ARG (Type *); \
573 if (Str == NULL) \
574 conv_error (); \
575 }
576 STRING_ARG (str, char);
577
578 c = inchar ();
579 if (c == EOF)
580 input_error ();
581
582 do
583 {
584 if (isspace (c))
585 {
586 ungetc (c, s);
587 break;
588 }
589 #define STRING_ADD_CHAR(Str, c, Type) \
590 if (!(flags & SUPPRESS)) \
591 { \
592 *Str++ = c; \
593 if ((flags & MALLOC) && (char *) Str == *strptr + strsize) \
594 { \
595 /* Enlarge the buffer. */ \
596 Str = realloc (*strptr, strsize * 2 * sizeof (Type)); \
597 if (Str == NULL) \
598 { \
599 /* Can't allocate that much. Last-ditch effort. */\
600 Str = realloc (*strptr, \
601 (strsize + 1) * sizeof (Type)); \
602 if (Str == NULL) \
603 { \
604 /* We lose. Oh well. \
605 Terminate the string and stop converting, \
606 so at least we don't skip any input. */ \
607 ((Type *) (*strptr))[strsize] = '\0'; \
608 ++done; \
609 conv_error (); \
610 } \
611 else \
612 { \
613 *strptr = (char *) Str; \
614 Str = ((Type *) *strptr) + strsize; \
615 ++strsize; \
616 } \
617 } \
618 else \
619 { \
620 *strptr = (char *) Str; \
621 Str = ((Type *) *strptr) + strsize; \
622 strsize *= 2; \
623 } \
624 } \
625 }
626 STRING_ADD_CHAR (str, c, char);
627 } while ((width <= 0 || --width > 0) && inchar () != EOF);
628
629 if (!(flags & SUPPRESS))
630 {
631 *str = '\0';
632 ++done;
633 }
634 break;
635
636 case 'S':
637 /* Wide character string. */
638 wide_char_string:
639 {
640 wint_t val;
641 int first = 1;
642 STRING_ARG (wstr, wchar_t);
643
644 do
645 {
646 size_t cnt = 0;
647 NEXT_WIDE_CHAR (first);
648
649 if (iswspace (val))
650 {
651 /* XXX We would have to push back the whole wide char
652 with possibly many bytes. But since scanf does
653 not make a difference for white space characters
654 we can simply push back a simple <SP> which is
655 guaranteed to be in the [:space:] class. */
656 ungetc (' ', s);
657 break;
658 }
659
660 STRING_ADD_CHAR (wstr, val, wchar_t);
661 first = 0;
662 }
663 while (width <= 0 || --width > 0);
664
665 if (!(flags & SUPPRESS))
666 {
667 *wstr = L'\0';
668 ++done;
669 }
670 }
671 break;
672
673 case 'x': /* Hexadecimal integer. */
674 case 'X': /* Ditto. */
675 base = 16;
676 number_signed = 0;
677 goto number;
678
679 case 'o': /* Octal integer. */
680 base = 8;
681 number_signed = 0;
682 goto number;
683
684 case 'u': /* Unsigned decimal integer. */
685 base = 10;
686 number_signed = 0;
687 goto number;
688
689 case 'd': /* Signed decimal integer. */
690 base = 10;
691 number_signed = 1;
692 goto number;
693
694 case 'i': /* Generic number. */
695 base = 0;
696 number_signed = 1;
697
698 number:
699 c = inchar ();
700 if (c == EOF)
701 input_error ();
702
703 /* Check for a sign. */
704 if (c == '-' || c == '+')
705 {
706 ADDW (c);
707 if (width > 0)
708 --width;
709 c = inchar ();
710 }
711
712 /* Look for a leading indication of base. */
713 if (width != 0 && c == '0')
714 {
715 if (width > 0)
716 --width;
717
718 ADDW (c);
719 c = inchar ();
720
721 if (width != 0 && tolower (c) == 'x')
722 {
723 if (base == 0)
724 base = 16;
725 if (base == 16)
726 {
727 if (width > 0)
728 --width;
729 c = inchar ();
730 }
731 }
732 else if (base == 0)
733 base = 8;
734 }
735
736 if (base == 0)
737 base = 10;
738
739 /* Read the number into workspace. */
740 while (c != EOF && width != 0)
741 {
742 if (base == 16 ? !isxdigit (c) :
743 ((!isdigit (c) || c - '0' >= base) &&
744 !((flags & GROUP) && base == 10 && c == thousands)))
745 break;
746 ADDW (c);
747 if (width > 0)
748 --width;
749
750 c = inchar ();
751 }
752
753 /* The just read character is not part of the number anymore. */
754 ungetc (c, s);
755
756 if (wpsize == 0 ||
757 (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
758 /* There was no number. */
759 conv_error ();
760
761 /* Convert the number. */
762 ADDW ('\0');
763 if (flags & LONGDBL)
764 {
765 // if (number_signed)
766 // num.q = __strtoq_internal (wp, &tw, base, flags & GROUP);
767 // else
768 // num.uq = __strtouq_internal (wp, &tw, base, flags & GROUP);
769 }
770 else
771 {
772 if (number_signed)
773 num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
774 else
775 num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
776 }
777 if (wp == tw)
778 conv_error ();
779
780 if (!(flags & SUPPRESS))
781 {
782 if (! number_signed)
783 {
784 if (flags & LONGDBL) {
785 *ARG (ULONGLONG*) = num.uq;
786 }
787 else if (flags & LONG)
788 *ARG (unsigned long int*) = num.ul;
789 else if (flags & SHORT)
790 *ARG (unsigned short int*) = (unsigned short int) num.ul;
791 else
792 *ARG (unsigned int*) = (unsigned int) num.ul;
793 }
794 else
795 {
796 if (flags & LONGDBL) {
797 *ARG (LONGLONG*) = num.q;
798 }
799 else if (flags & LONG)
800 *ARG (long int *) = num.l;
801 else if (flags & SHORT)
802 *ARG (short int *) = (short int) num.l;
803 else
804 *ARG (int *) = (int) num.l;
805 }
806 ++done;
807 }
808 break;
809
810 case 'e': /* Floating-point numbers. */
811 case 'E':
812 case 'f':
813 case 'g':
814 case 'G':
815 c = inchar ();
816 if (c == EOF)
817 input_error ();
818
819 /* Check for a sign. */
820 if (c == '-' || c == '+')
821 {
822 negative = c == '-';
823 if (inchar () == EOF)
824 /* EOF is only an input error before we read any chars. */
825 conv_error ();
826 if (width > 0)
827 --width;
828 }
829 else
830 negative = 0;
831
832 got_dot = got_e = 0;
833 do
834 {
835 if (isdigit (c))
836 ADDW (c);
837 else if (got_e && wp[wpsize - 1] == 'e'
838 && (c == '-' || c == '+'))
839 ADDW (c);
840 else if (wpsize > 0 && !got_e && tolower (c) == 'e')
841 {
842 ADDW ('e');
843 got_e = got_dot = 1;
844 }
845 else if (c == decimal && !got_dot)
846 {
847 ADDW (c);
848 got_dot = 1;
849 }
850 else if ((flags & GROUP) && c == thousands && !got_dot)
851 ADDW (c);
852 else
853 {
854 /* The last read character is not part of the number
855 anymore. */
856 ungetc (c, s);
857 break;
858 }
859 if (width > 0)
860 --width;
861 }
862 while (width != 0 && inchar () != EOF);
863
864 if (wpsize == 0)
865 conv_error ();
866
867 /* Convert the number. */
868 ADDW ('\0');
869 if (flags & LONGDBL)
870 {
871 long double d = __strtold_internal (wp, &tw, flags & GROUP);
872 if (!(flags & SUPPRESS) && tw != wp)
873 *ARG (long double *) = negative ? -d : d;
874 }
875 else if (flags & LONG)
876 {
877 double d = __strtod_internal (wp, &tw, flags & GROUP);
878 if (!(flags & SUPPRESS) && tw != wp)
879 *ARG (double *) = negative ? -d : d;
880 }
881 else
882 {
883 float d = __strtof_internal (wp, &tw, flags & GROUP);
884 if (!(flags & SUPPRESS) && tw != wp)
885 *ARG (float *) = negative ? -d : d;
886 }
887
888 if (tw == wp)
889 conv_error ();
890
891 if (!(flags & SUPPRESS))
892 ++done;
893 break;
894
895 case '[': /* Character class. */
896 if (flags & LONG)
897 {
898 STRING_ARG (wstr, wchar_t);
899 c = '\0'; /* This is to keep gcc quiet. */
900 }
901 else
902 {
903 STRING_ARG (str, char);
904
905 c = inchar ();
906 if (c == EOF)
907 input_error ();
908 }
909
910 if (*f == '^')
911 {
912 ++f;
913 not_in = 1;
914 }
915 else
916 not_in = 0;
917
918 /* Fill WP with byte flags indexed by character.
919 We will use this flag map for matching input characters. */
920 if (wpmax < UCHAR_MAX)
921 {
922 wpmax = UCHAR_MAX;
923 wp = (char *) alloca (wpmax);
924 }
925 memset (wp, 0, UCHAR_MAX);
926
927 fc = *f;
928 if (fc == ']' || fc == '-')
929 {
930 /* If ] or - appears before any char in the set, it is not
931 the terminator or separator, but the first char in the
932 set. */
933 wp[fc] = 1;
934 ++f;
935 }
936
937 while ((fc = *f++) != '\0' && fc != ']')
938 {
939 if (fc == '-' && *f != '\0' && *f != ']' &&
940 (unsigned char) f[-2] <= (unsigned char) *f)
941 {
942 /* Add all characters from the one before the '-'
943 up to (but not including) the next format char. */
944 for (fc = f[-2]; fc < *f; ++fc)
945 wp[fc] = 1;
946 }
947 else
948 /* Add the character to the flag map. */
949 wp[fc] = 1;
950 }
951 if (fc == '\0')
952 {
953 if (!(flags & LONG))
954 ungetc (c, s);
955 conv_error();
956 }
957
958 if (flags & LONG)
959 {
960 wint_t val;
961 int first = 1;
962
963 do
964 {
965 size_t cnt = 0;
966 NEXT_WIDE_CHAR (first);
967 if (val > 255 || wp[val] == not_in)
968 {
969 /* XXX We have a problem here. We read a wide
970 character and this possibly took several
971 bytes. But we can only push back one single
972 character. To be sure we don't create wrong
973 input we push it back only in case it is
974 representable within one byte. */
975 if (val < 0x80)
976 ungetc (val, s);
977 break;
978 }
979 STRING_ADD_CHAR (wstr, val, wchar_t);
980 if (width > 0)
981 --width;
982 first = 0;
983 }
984 while (width != 0);
985
986 if (first)
987 conv_error ();
988
989 if (!(flags & SUPPRESS))
990 {
991 *wstr = L'\0';
992 ++done;
993 }
994 }
995 else
996 {
997 num.ul = read_in - 1; /* -1 because we already read one char. */
998 do
999 {
1000 if (wp[c] == not_in)
1001 {
1002 ungetc (c, s);
1003 break;
1004 }
1005 STRING_ADD_CHAR (str, c, char);
1006 if (width > 0)
1007 --width;
1008 }
1009 while (width != 0 && inchar () != EOF);
1010
1011 if (read_in == num.ul)
1012 conv_error ();
1013
1014 if (!(flags & SUPPRESS))
1015 {
1016 *str = '\0';
1017 ++done;
1018 }
1019 }
1020 break;
1021
1022 case 'p': /* Generic pointer. */
1023 base = 16;
1024 /* A PTR must be the same size as a `long int'. */
1025 flags &= ~(SHORT|LONGDBL);
1026 flags |= LONG;
1027 number_signed = 0;
1028 goto number;
1029 }
1030 }
1031
1032 /* The last thing we saw int the format string was a white space.
1033 Consume the last white spaces. */
1034 if (skip_space)
1035 {
1036 do
1037 c = inchar ();
1038 while (isspace (c));
1039 ungetc (c, s);
1040 }
1041
1042
1043 return done;
1044 }
1045
1046
1047
1048 int
1049 xfscanf(FILE *f, const char *fmt, ...)
1050 {
1051 int r;
1052 va_list a=0;
1053 va_start(a, fmt);
1054 r = __vfscanf(f, fmt, a);
1055 va_end(a);
1056 return r;
1057 }
1058
1059
1060 double __strtod_internal (const char *__nptr,char **__endptr, int __group)
1061 {
1062 return strtod(__nptr,__endptr);
1063 }
1064 float __strtof_internal (const char *__nptr, char **__endptr,int __group)
1065 {
1066 return (float)strtod(__nptr,__endptr);
1067 }
1068 static double powten[] =
1069 {
1070 1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
1071 #ifdef __GNUC__
1072 1e512L, 1e512L*1e512L, 1e2048L, 1e4096L
1073 #else
1074 1e256L, 1e256L, 1e256L, 1e256L
1075 #endif
1076 };
1077
1078 long double __strtold_internal (const char *s,char **sret, int __group)
1079 {
1080
1081 long double r; /* result */
1082 int e, ne; /* exponent */
1083 int sign; /* +- 1.0 */
1084 int esign;
1085 int flags=0;
1086 int l2powm1;
1087
1088 r = 0.0L;
1089 sign = 1;
1090 e = ne = 0;
1091 esign = 1;
1092
1093 while(*s && isspace(*s))
1094 s++;
1095
1096 if (*s == '+')
1097 s++;
1098 else if (*s == '-')
1099 {
1100 sign = -1;
1101 s++;
1102 }
1103
1104 while ((*s >= '0') && (*s <= '9'))
1105 {
1106 flags |= 1;
1107 r *= 10.0L;
1108 r += *s - '0';
1109 s++;
1110 }
1111
1112 if (*s == '.')
1113 {
1114 s++;
1115 while ((*s >= '0') && (*s <= '9'))
1116 {
1117 flags |= 2;
1118 r *= 10.0L;
1119 r += *s - '0';
1120 s++;
1121 ne++;
1122 }
1123 }
1124 if (flags == 0)
1125 {
1126 if (sret)
1127 *sret = (char *)s;
1128 return 0.0L;
1129 }
1130
1131 if ((*s == 'e') || (*s == 'E'))
1132 {
1133 s++;
1134 if (*s == '+')
1135 s++;
1136 else if (*s == '-')
1137 {
1138 s++;
1139 esign = -1;
1140 }
1141 while ((*s >= '0') && (*s <= '9'))
1142 {
1143 e *= 10;
1144 e += *s - '0';
1145 s++;
1146 }
1147 }
1148 if (esign < 0)
1149 {
1150 esign = -esign;
1151 e = -e;
1152 }
1153 e = e - ne;
1154 if (e < -4096)
1155 {
1156 /* possibly subnormal number, 10^e would overflow */
1157 r *= 1.0e-2048L;
1158 e += 2048;
1159 }
1160 if (e < 0)
1161 {
1162 e = -e;
1163 esign = -esign;
1164 }
1165 if (e >= 8192)
1166 e = 8191;
1167 if (e)
1168 {
1169 double d = 1.0L;
1170 l2powm1 = 0;
1171 while (e)
1172 {
1173 if (e & 1)
1174 d *= powten[l2powm1];
1175 e >>= 1;
1176 l2powm1++;
1177 }
1178 if (esign > 0)
1179 r *= d;
1180 else
1181 r /= d;
1182 }
1183 if (sret)
1184 *sret = (char *)s;
1185 return r * sign;
1186
1187 return 0;
1188 }
1189 long int __strtol_internal (const char *__nptr, char **__endptr, int __base, int __group)
1190 {
1191 return strtol(__nptr,__endptr, __base);
1192 }
1193 unsigned long int __strtoul_internal (const char *__nptr, char **__endptr, int __base, int __group)
1194 {
1195 return strtoul(__nptr,__endptr, __base);
1196 }
1197
1198
1199
1200
1201
1202
1203
1204
1205