• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  This Software is provided under the Zope Public License (ZPL) Version 2.1.
3 
4  Copyright (c) 2011 by the mingw-w64 project
5 
6  See the AUTHORS file for the list of contributors to the mingw-w64 project.
7 
8  This license has been certified as open source. It has also been designated
9  as GPL compatible by the Free Software Foundation (FSF).
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are met:
13 
14    1. Redistributions in source code must retain the accompanying copyright
15       notice, this list of conditions, and the following disclaimer.
16    2. Redistributions in binary form must reproduce the accompanying
17       copyright notice, this list of conditions, and the following disclaimer
18       in the documentation and/or other materials provided with the
19       distribution.
20    3. Names of the copyright holders must not be used to endorse or promote
21       products derived from this software without prior written permission
22       from the copyright holders.
23    4. The right to distribute this software or to use it for any purpose does
24       not give you the right to use Servicemarks (sm) or Trademarks (tm) of
25       the copyright holders.  Use of them is covered by separate agreement
26       with the copyright holders.
27    5. If any files are modified, you must cause the modified files to carry
28       prominent notices stating that you changed the files and the date of
29       any change.
30 
31  Disclaimer
32 
33  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
34  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
36  EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
37  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
39  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
42  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 */
44 
45 #define __LARGE_MBSTATE_T
46 
47 #include <limits.h>
48 #include <stddef.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <wchar.h>
55 #include <ctype.h>
56 #include <wctype.h>
57 #include <locale.h>
58 #include <errno.h>
59 
60 #ifndef CP_UTF8
61 #define CP_UTF8 65001
62 #endif
63 
64 #ifndef MB_ERR_INVALID_CHARS
65 #define MB_ERR_INVALID_CHARS 0x00000008
66 #endif
67 
68 /* Helper flags for conversion.  */
69 #define IS_C		0x0001
70 #define IS_S		0x0002
71 #define IS_L		0x0004
72 #define IS_LL		0x0008
73 #define IS_SIGNED_NUM	0x0010
74 #define IS_POINTER	0x0020
75 #define IS_HEX_FLOAT	0x0040
76 #define IS_SUPPRESSED	0x0080
77 #define USE_GROUP	0x0100
78 #define USE_GNU_ALLOC	0x0200
79 #define USE_POSIX_ALLOC	0x0400
80 
81 #define IS_ALLOC_USED	(USE_GNU_ALLOC | USE_POSIX_ALLOC)
82 
83 /* internal stream structure with back-buffer.  */
84 typedef struct _IFP
85 {
86   __extension__ union {
87     void *fp;
88     const wchar_t *str;
89   };
90   int bch[1024];
91   int is_string : 1;
92   int back_top;
93   int seen_eof : 1;
94 } _IFP;
95 
96 static void *
get_va_nth(va_list argp,unsigned int n)97 get_va_nth (va_list argp, unsigned int n)
98 {
99   va_list ap;
100   if (!n)
101     abort ();
102   va_copy (ap, argp);
103   while (--n > 0)
104     (void) va_arg(ap, void *);
105   return va_arg (ap, void *);
106 }
107 
108 static void
optimize_alloc(char ** p,char * end,size_t alloc_sz)109 optimize_alloc (char **p, char *end, size_t alloc_sz)
110 {
111   size_t need_sz;
112   char *h;
113 
114   if (!p || !*p)
115     return;
116 
117   need_sz = end - *p;
118   if (need_sz == alloc_sz)
119     return;
120 
121   if ((h = (char *) realloc (*p, need_sz)) != NULL)
122     *p = h;
123 }
124 
125 static void
back_ch(int c,_IFP * s,size_t * rin,int not_eof)126 back_ch (int c, _IFP *s, size_t *rin, int not_eof)
127 {
128   if (!not_eof && c == WEOF)
129     return;
130   if (s->is_string == 0)
131     {
132       FILE *fp = s->fp;
133       ungetwc (c, fp);
134       rin[0] -= 1;
135       return;
136     }
137   rin[0] -= 1;
138   s->bch[s->back_top] = c;
139   s->back_top += 1;
140 }
141 
142 static int
in_ch(_IFP * s,size_t * rin)143 in_ch (_IFP *s, size_t *rin)
144 {
145   int r;
146   if (s->back_top)
147   {
148     s->back_top -= 1;
149     r = s->bch[s->back_top];
150     rin[0] += 1;
151   }
152   else if (s->seen_eof)
153   {
154     return WEOF;
155   }
156   else if (s->is_string)
157   {
158     const wchar_t *ps = s->str;
159     r = ((int) *ps) & 0xffff;
160     ps++;
161     if (r != 0)
162     {
163       rin[0] += 1;
164       s->str = ps;
165       return r;
166     }
167     s->seen_eof = 1;
168     return WEOF;
169   }
170   else
171   {
172     FILE *fp = (FILE *) s->fp;
173     r = getwc (fp);
174     if (r != WEOF)
175       rin[0] += 1;
176     else s->seen_eof = 1;
177   }
178   return r;
179 }
180 
181 static int
match_string(_IFP * s,size_t * rin,wint_t * c,const wchar_t * str)182 match_string (_IFP *s, size_t *rin, wint_t *c, const wchar_t *str)
183 {
184   int ch = *c;
185 
186   if (*str == 0)
187     return 1;
188 
189   if (*str != (wchar_t) towlower (ch))
190     return 0;
191   ++str;
192   while (*str != 0)
193   {
194     if ((ch = in_ch (s, rin)) == WEOF)
195     {
196       c[0] = ch;
197       return 0;
198     }
199 
200     if (*str != (wchar_t) towlower (ch))
201     {
202       c[0] = ch;
203       return 0;
204     }
205     ++str;
206   }
207   c[0] = ch;
208   return 1;
209 }
210 
211 struct gcollect
212 {
213   size_t count;
214   struct gcollect *next;
215   char **ptrs[32];
216 };
217 
218 static void
release_ptrs(struct gcollect ** pt,wchar_t ** wbuf)219 release_ptrs (struct gcollect **pt, wchar_t **wbuf)
220 {
221   struct gcollect *pf;
222   size_t cnt;
223 
224   if (wbuf)
225     {
226       free (*wbuf);
227       *wbuf = NULL;
228     }
229   if (!pt || (pf = *pt) == NULL)
230     return;
231   while (pf != NULL)
232     {
233       struct gcollect *pf_sv = pf;
234       for (cnt = 0; cnt < pf->count; ++cnt)
235 	{
236 	  free (*pf->ptrs[cnt]);
237 	  *pf->ptrs[cnt] = NULL;
238 	}
239       pf = pf->next;
240       free (pf_sv);
241     }
242   *pt = NULL;
243 }
244 
245 static int
cleanup_return(int rval,struct gcollect ** pfree,char ** strp,wchar_t ** wbuf)246 cleanup_return (int rval, struct gcollect **pfree, char **strp, wchar_t **wbuf)
247 {
248   if (rval == EOF)
249       release_ptrs (pfree, wbuf);
250   else
251     {
252       if (pfree)
253         {
254           struct gcollect *pf = *pfree, *pf_sv;
255           while (pf != NULL)
256             {
257               pf_sv = pf;
258               pf = pf->next;
259               free (pf_sv);
260             }
261           *pfree = NULL;
262         }
263       if (strp != NULL)
264 	{
265 	  free (*strp);
266 	  *strp = NULL;
267 	}
268       if (wbuf)
269 	{
270 	  free (*wbuf);
271 	  *wbuf = NULL;
272 	}
273     }
274   return rval;
275 }
276 
277 static struct gcollect *
resize_gcollect(struct gcollect * pf)278 resize_gcollect (struct gcollect *pf)
279 {
280   struct gcollect *np;
281   if (pf && pf->count < 32)
282     return pf;
283   np = malloc (sizeof (struct gcollect));
284   np->count = 0;
285   np->next = pf;
286   return np;
287 }
288 
289 static wchar_t *
resize_wbuf(size_t wpsz,size_t * wbuf_max_sz,wchar_t * old)290 resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, wchar_t *old)
291 {
292   wchar_t *wbuf;
293   size_t nsz;
294   if (*wbuf_max_sz != wpsz)
295     return old;
296   nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
297   if (!old)
298     wbuf = (wchar_t *) malloc (nsz * sizeof (wchar_t));
299   else
300     wbuf = (wchar_t *) realloc (old, nsz * sizeof (wchar_t));
301   if (!wbuf)
302   {
303     if (old)
304       free (old);
305   }
306   else
307     *wbuf_max_sz = nsz;
308   return wbuf;
309 }
310 
311 static int
__mingw_swformat(_IFP * s,const wchar_t * format,va_list argp)312 __mingw_swformat (_IFP *s, const wchar_t *format, va_list argp)
313 {
314   const wchar_t *f = format;
315   struct gcollect *gcollect = NULL;
316   size_t read_in = 0, wbuf_max_sz = 0;
317   ssize_t str_sz = 0;
318   char *str = NULL, **pstr = NULL;;
319   wchar_t *wstr = NULL, *wbuf = NULL;
320   wint_t c = 0, rval = 0;
321   int ignore_ws = 0;
322   va_list arg;
323   size_t wbuf_cur_sz, str_len, read_in_sv, new_sz, n;
324   unsigned int fc, npos;
325   int width, flags, base = 0, errno_sv, clen;
326   char seen_dot, seen_exp, is_neg, *nstr, buf[MB_LEN_MAX];
327   wchar_t wc, not_in, *tmp_wbuf_ptr, *temp_wbuf_end, *wbuf_iter;
328   wint_t lc_decimal_point, lc_thousands_sep;
329   mbstate_t state;
330   union {
331     unsigned long long ull;
332     unsigned long ul;
333     long long ll;
334     long l;
335   } cv_val;
336 
337   arg = argp;
338 
339   if (!s || s->fp == NULL || !format)
340     {
341       errno = EINVAL;
342       return EOF;
343     }
344 
345   memset (&state, 0, sizeof(state));
346   clen = mbrtowc( &wc, localeconv()->decimal_point, 16, &state);
347   lc_decimal_point = (clen > 0 ? wc : '.');
348   memset( &state, 0, sizeof( state ) );
349   clen = mbrtowc( &wc, localeconv()->thousands_sep, 16, &state);
350   lc_thousands_sep = (clen > 0 ? wc : 0);
351 
352   while (*f != 0)
353     {
354       fc = *f++;
355       if (fc != '%')
356         {
357           if (iswspace (fc))
358 	    ignore_ws = 1;
359 	  else
360 	    {
361 	      if ((c = in_ch (s, &read_in)) == WEOF)
362 		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
363 
364 	      if (ignore_ws)
365 		{
366 		  ignore_ws = 0;
367 		  if (iswspace (c))
368 		    {
369 		      do
370 			{
371 			  if ((c = in_ch (s, &read_in)) == WEOF)
372 			    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
373 			}
374 		      while (iswspace (c));
375 		    }
376 		}
377 
378 	      if (c != fc)
379 		{
380 		  back_ch (c, s, &read_in, 0);
381 		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
382 		}
383 	    }
384 
385 	  continue;
386 	}
387 
388       width = flags = 0;
389       npos = 0;
390       wbuf_cur_sz = 0;
391 
392       if (iswdigit ((unsigned int) *f))
393 	{
394 	  const wchar_t *svf = f;
395 	  npos = (unsigned int) *f++ - '0';
396 	  while (iswdigit ((unsigned int) *f))
397 	    npos = npos * 10 + ((unsigned int) *f++ - '0');
398 	  if (*f != '$')
399 	    {
400 	      npos = 0;
401 	      f = svf;
402 	    }
403 	  else
404 	    f++;
405 	}
406 
407       do
408 	{
409 	  if (*f == '*')
410 	    flags |= IS_SUPPRESSED;
411 	  else if (*f == '\'')
412 	    {
413 	      if (lc_thousands_sep)
414 		flags |= USE_GROUP;
415 	    }
416 	  else if (*f == 'I')
417 	    {
418 	      /* we don't support locale's digits (i18N), but ignore it for now silently.  */
419 	      ;
420 #ifdef _WIN32
421               if (f[1] == '6' && f[2] == '4')
422                 {
423 		  flags |= IS_LL | IS_L;
424 		  f += 2;
425 		}
426 	      else if (f[1] == '3' && f[2] == '2')
427 		{
428 		  flags |= IS_L;
429 		  f += 2;
430 		}
431 	      else
432 	        {
433 #ifdef _WIN64
434 		  flags |= IS_LL | IS_L;
435 #else
436 		  flags |= IS_L;
437 #endif
438 		}
439 #endif
440 	    }
441 	  else
442 	    break;
443 	  ++f;
444         }
445       while (1);
446 
447       while (iswdigit ((unsigned char) *f))
448 	width = width * 10 + ((unsigned char) *f++ - '0');
449 
450       if (!width)
451 	width = -1;
452 
453       switch (*f)
454 	{
455 	case 'h':
456 	  ++f;
457 	  flags |= (*f == 'h' ? IS_C : IS_S);
458 	  if (*f == 'h')
459 	    ++f;
460 	  break;
461 	case 'l':
462 	  ++f;
463 	  flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
464 	  if (*f == 'l')
465 	    ++f;
466 	  break;
467 	case 'q': case 'L':
468 	  ++f;
469 	  flags |= IS_LL | IS_L;
470 	  break;
471 	case 'a':
472 	  if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
473 	    break;
474 	  ++f;
475 	  flags |= USE_GNU_ALLOC;
476 	  break;
477 	case 'm':
478 	  flags |= USE_POSIX_ALLOC;
479 	  ++f;
480 	  if (*f == 'l')
481 	    {
482 	      flags |= IS_L;
483 	      ++f;
484 	    }
485 	  break;
486 	case 'z':
487 #ifdef _WIN64
488 	  flags |= IS_LL | IS_L;
489 #else
490 	  flags |= IS_L;
491 #endif
492 	  ++f;
493 	  break;
494 	case 'j':
495 	  if (sizeof (uintmax_t) > sizeof (unsigned long))
496 	    flags |= IS_LL;
497 	  else if (sizeof (uintmax_t) > sizeof (unsigned int))
498 	    flags |= IS_L;
499 	  ++f;
500 	  break;
501 	case 't':
502 #ifdef _WIN64
503 	  flags |= IS_LL;
504 #else
505 	  flags |= IS_L;
506 #endif
507 	  ++f;
508 	  break;
509 	case 0:
510 	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
511 	default:
512 	  break;
513 	}
514 
515       if (*f == 0)
516 	return cleanup_return (rval, &gcollect, pstr, &wbuf);
517 
518       fc = *f++;
519       if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
520 	{
521 	  errno_sv = errno;
522 	  errno = 0;
523 	  do
524 	    {
525 	      if ((c == WEOF || (c = in_ch (s, &read_in)) == WEOF) && errno == EINTR)
526 		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
527 	    }
528 	  while (iswspace (c));
529 
530 	  ignore_ws = 0;
531 	  errno = errno_sv;
532 	  back_ch (c, s, &read_in, 0);
533 	}
534 
535       switch (fc)
536         {
537         case 'c':
538           if ((flags & IS_L) != 0)
539             fc = 'C';
540           break;
541         case 's':
542           if ((flags & IS_L) != 0)
543             fc = 'S';
544           break;
545         }
546 
547       switch (fc)
548 	{
549 	case '%':
550 	  if ((c = in_ch (s, &read_in)) == WEOF)
551 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
552 	  if (c != fc)
553 	    {
554 	      back_ch (c, s, &read_in, 1);
555 	      return cleanup_return (rval, &gcollect, pstr, &wbuf);
556 	    }
557 	  break;
558 
559 	case 'n':
560 	  if ((flags & IS_SUPPRESSED) == 0)
561 	    {
562 	      if ((flags & IS_LL) != 0)
563 		*(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
564 	      else if ((flags & IS_L) != 0)
565 		*(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
566 	      else if ((flags & IS_S) != 0)
567 		*(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
568 	      else if ((flags & IS_C) != 0)
569 	        *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
570 	      else
571 		*(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
572 	    }
573 	  break;
574 
575 	case 'c':
576 	  if (width == -1)
577 	    width = 1;
578 
579 	  if ((flags & IS_SUPPRESSED) == 0)
580 	    {
581 	      if ((flags & IS_ALLOC_USED) != 0)
582 		{
583 		   if (npos != 0)
584 		     pstr = (char **) get_va_nth (argp, npos);
585 		   else
586 		     pstr = va_arg (arg, char **);
587 
588 		  if (!pstr)
589 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
590 		  str_sz = 100;
591 		  if ((str = *pstr = (char *) malloc (100)) == NULL)
592 		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
593 		  gcollect = resize_gcollect (gcollect);
594 		  gcollect->ptrs[gcollect->count++] = pstr;
595 		}
596 	      else
597 		{
598 		  if (npos != 0)
599 		     str = (char *) get_va_nth (argp, npos);
600 		  else
601 		    str = va_arg (arg, char *);
602 		  if (!str)
603 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
604 		}
605 	    }
606 	  if ((c = in_ch (s, &read_in)) == WEOF)
607 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
608 
609 	  memset (&state, 0, sizeof (state));
610 
611 	  do
612 	    {
613 	      if ((flags & IS_SUPPRESSED) == 0 && (flags & USE_POSIX_ALLOC) != 0
614 		  && (str + MB_CUR_MAX) >= (*pstr + str_sz))
615 		{
616 		  new_sz = str_sz * 2;
617 		  str_len = (str - *pstr);
618 		  while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
619 			 && new_sz > (str_len + MB_CUR_MAX))
620 		    new_sz = str_len + MB_CUR_MAX;
621 		  if (!nstr)
622 		    {
623 		      release_ptrs (&gcollect, &wbuf);
624 		      return EOF;
625 		    }
626 		  *pstr = nstr;
627 		  str = nstr + str_len;
628 		  str_sz = new_sz;
629 		}
630 
631 	      n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
632 	      if (n == (size_t) -1LL)
633 		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
634 	      str += n;
635 	    }
636 	  while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
637 
638 	  if ((flags & IS_SUPPRESSED) == 0)
639 	    {
640 	      optimize_alloc (pstr, str, str_sz);
641 	      pstr = NULL;
642 	      ++rval;
643 	    }
644 
645 	  break;
646 
647 	case 'C':
648 	  if (width == -1)
649 	    width = 1;
650 
651 	  if ((flags & IS_SUPPRESSED) == 0)
652 	    {
653 	      if ((flags & IS_ALLOC_USED) != 0)
654 		{
655 		 if (npos != 0)
656 		   pstr = (char **) get_va_nth (argp, npos);
657 		 else
658 		   pstr = va_arg (arg, char **);
659 
660 		  if (!pstr)
661 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
662 		  str_sz = (width > 1024 ? 1024 : width);
663 		  *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
664 		  if ((wstr = (wchar_t *) *pstr) == NULL)
665 		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
666 
667 		  if ((wstr = (wchar_t *) *pstr) != NULL)
668 		    {
669 		      gcollect = resize_gcollect (gcollect);
670 		      gcollect->ptrs[gcollect->count++] = pstr;
671 		    }
672 		}
673 	      else
674 		{
675 		  if (npos != 0)
676 		    wstr = (wchar_t *) get_va_nth (argp, npos);
677 		  else
678 		    wstr = va_arg (arg, wchar_t *);
679 		  if (!wstr)
680 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
681 		}
682 	    }
683 
684 	  if ((c = in_ch (s, &read_in)) == WEOF)
685 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
686 
687 	  if ((flags & IS_SUPPRESSED) == 0)
688 	    {
689 	      do
690 		{
691 		  if ((flags & IS_ALLOC_USED) != 0
692 		      && wstr == ((wchar_t *) *pstr + str_sz))
693 		    {
694 		      new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
695 		      while ((wstr = (wchar_t *) realloc (*pstr,
696 						  new_sz * sizeof (wchar_t))) == NULL
697 			     && new_sz > (size_t) (str_sz + 1))
698 			new_sz = str_sz + 1;
699 		      if (!wstr)
700 			{
701 			  release_ptrs (&gcollect, &wbuf);
702 			  return EOF;
703 			}
704 		      *pstr = (char *) wstr;
705 		      wstr += str_sz;
706 		      str_sz = new_sz;
707 		    }
708 		  *wstr++ = c;
709 		}
710 	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
711 	    }
712 	  else
713 	    {
714 	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
715 	    }
716 
717 	  if ((flags & IS_SUPPRESSED) == 0)
718 	    {
719 	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
720 	      pstr = NULL;
721 	      ++rval;
722 	    }
723 	  break;
724 
725 	case 's':
726 	  if ((flags & IS_SUPPRESSED) == 0)
727 	    {
728 	      if ((flags & IS_ALLOC_USED) != 0)
729 		{
730 		 if (npos != 0)
731 		   pstr = (char **) get_va_nth (argp, npos);
732 		 else
733 		   pstr = va_arg (arg, char **);
734 
735 		  if (!pstr)
736 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
737 		  str_sz = 100;
738 		  if ((str = *pstr = (char *) malloc (100)) == NULL)
739 		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
740 		  gcollect = resize_gcollect (gcollect);
741 		  gcollect->ptrs[gcollect->count++] = pstr;
742 		}
743 	      else
744 		{
745 		  if (npos != 0)
746 		    str = (char *) get_va_nth (argp, npos);
747 		  else
748 		    str = va_arg (arg, char *);
749 		  if (!str)
750 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
751 		}
752 	    }
753 
754 	  if ((c = in_ch (s, &read_in)) == WEOF)
755 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
756 
757 	  memset (&state, 0, sizeof (state));
758 
759 	  do
760 	    {
761 	      if (iswspace (c))
762 		{
763 		  back_ch (c, s, &read_in, 1);
764 		  break;
765 		}
766 
767 	      {
768 		if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
769 		    && (str + MB_CUR_MAX) >= (*pstr + str_sz))
770 		  {
771 		    new_sz = str_sz * 2;
772 		    str_len = (str - *pstr);
773 
774 		    while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
775 			   && new_sz > (str_len + MB_CUR_MAX))
776 		      new_sz = str_len + MB_CUR_MAX;
777 		    if (!nstr)
778 		      {
779 			if ((flags & USE_POSIX_ALLOC) == 0)
780 			  {
781 			    (*pstr)[str_len] = 0;
782 			    pstr = NULL;
783 			    ++rval;
784 			  }
785 			return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
786 		      }
787 		    *pstr = nstr;
788 		    str = nstr + str_len;
789 		    str_sz = new_sz;
790 		  }
791 
792 		n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c,
793 			       &state);
794 		if (n == (size_t) -1LL)
795 		{
796 		  errno = EILSEQ;
797 		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
798 		}
799 
800 		str += n;
801 	      }
802 	    }
803 	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
804 
805 	  if ((flags & IS_SUPPRESSED) == 0)
806 	    {
807 	      n = wcrtomb (buf, 0, &state);
808 	      if (n > 0 && (flags & IS_ALLOC_USED) != 0
809 		  && (str + n) >= (*pstr + str_sz))
810 		{
811 		  str_len = (str - *pstr);
812 
813 		  if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
814 		    {
815 		      if ((flags & USE_POSIX_ALLOC) == 0)
816 			{
817 			  (*pstr)[str_len] = 0;
818 			  pstr = NULL;
819 			  ++rval;
820 			}
821 		      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
822 		    }
823 		  *pstr = nstr;
824 		  str = nstr + str_len;
825 		  str_sz = str_len + n + 1;
826 		}
827 
828 	      if (n)
829 	      {
830 		memcpy (str, buf, n);
831 		str += n;
832 	      }
833 	      *str++ = 0;
834 
835 	      optimize_alloc (pstr, str, str_sz);
836 	      pstr = NULL;
837 	      ++rval;
838 	    }
839 	  break;
840 
841 	case 'S':
842 	  if ((flags & IS_SUPPRESSED) == 0)
843 	    {
844 	      if ((flags & IS_ALLOC_USED) != 0)
845 		{
846 		 if (npos != 0)
847 		   pstr = (char **) get_va_nth (argp, npos);
848 		 else
849 		   pstr = va_arg (arg, char **);
850 
851 		  if (!pstr)
852 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
853 		  str_sz = 100;
854 		  *pstr = (char *) malloc (100 * sizeof (wchar_t));
855 		  if ((wstr = (wchar_t *) *pstr) == NULL)
856 		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
857 		  gcollect = resize_gcollect (gcollect);
858 		  gcollect->ptrs[gcollect->count++] = pstr;
859 		}
860 	      else
861 		{
862 		  if (npos != 0)
863 		    wstr = (wchar_t *) get_va_nth (argp, npos);
864 		  else
865 		    wstr = va_arg (arg, wchar_t *);
866 		  if (!wstr)
867 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
868 		}
869 	    }
870 	  if ((c = in_ch (s, &read_in)) == WEOF)
871 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
872 
873 	  do
874 	    {
875 	      if (iswspace (c))
876 		{
877 		  back_ch (c, s, &read_in, 1);
878 		  break;
879 		}
880 
881 	      if ((flags & IS_SUPPRESSED) == 0)
882 		{
883 		  *wstr++ = c;
884 		  if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
885 		    {
886 		      new_sz = str_sz * 2;
887 
888 		      while ((wstr = (wchar_t *) realloc (*pstr,
889 						  new_sz * sizeof (wchar_t))) == NULL
890 			      && new_sz > (size_t) (str_sz + 1))
891 			new_sz = str_sz + 1;
892 		      if (!wstr)
893 			{
894 			  if ((flags & USE_POSIX_ALLOC) == 0)
895 			    {
896 			      ((wchar_t *) (*pstr))[str_sz - 1] = 0;
897 			      pstr = NULL;
898 			      ++rval;
899 			    }
900 			  return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
901 			}
902 		      *pstr = (char *) wstr;
903 		      wstr += str_sz;
904 		      str_sz = new_sz;
905 		    }
906 		}
907 	    }
908 	  while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF);
909 
910 	  if ((flags & IS_SUPPRESSED) == 0)
911 	    {
912 	      *wstr++ = 0;
913 
914 	      optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
915 	      pstr = NULL;
916 	      ++rval;
917 	    }
918 	  break;
919 
920 	case 'd': case 'i':
921 	case 'o': case 'p':
922 	case 'u':
923 	case 'x': case 'X':
924 	  switch (fc)
925 	    {
926 	    case 'd':
927 	      flags |= IS_SIGNED_NUM;
928 	      base = 10;
929 	      break;
930 	    case 'i':
931 	      flags |= IS_SIGNED_NUM;
932 	      base = 0;
933 	      break;
934 	    case 'o':
935 	      base = 8;
936 	      break;
937 	    case 'p':
938 	      base = 16;
939 	      flags &= ~(IS_S | IS_LL | IS_L);
940     #ifdef _WIN64
941 	      flags |= IS_LL;
942     #endif
943 	      flags |= IS_L | IS_POINTER;
944 	      break;
945 	    case 'u':
946 	      base = 10;
947 	      break;
948 	    case 'x': case 'X':
949 	      base = 16;
950 	      break;
951 	    }
952 
953 	  if ((c = in_ch (s, &read_in)) == WEOF)
954 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
955 
956 	  if (c == '+' || c == '-')
957 	    {
958 	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
959 	      wbuf[wbuf_cur_sz++] = c;
960 
961 	      if (width > 0)
962 		--width;
963 	      c = in_ch (s, &read_in);
964 	    }
965 
966 	  if (width != 0 && c == '0')
967 	    {
968 	      if (width > 0)
969 		--width;
970 
971 	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
972 	      wbuf[wbuf_cur_sz++] = c;
973 
974 	      c = in_ch (s, &read_in);
975 
976 	      if (width != 0 && towlower (c) == 'x')
977 		{
978 		  if (!base)
979 		    base = 16;
980 		  if (base == 16)
981 		    {
982 		      if (width > 0)
983 			--width;
984 		      c = in_ch (s, &read_in);
985 		    }
986 		}
987 	      else if (!base)
988 		base = 8;
989 	    }
990 
991 	  if (!base)
992 	    base = 10;
993 
994 	  while (c != WEOF && width != 0)
995 	    {
996 	      if (base == 16)
997 		{
998 		  if (!iswxdigit (c))
999 		    break;
1000 		}
1001 	      else if (!iswdigit (c) || (int) (c - '0') >= base)
1002 		{
1003 		  if (base != 10 || (flags & USE_GROUP) == 0 || c != lc_thousands_sep)
1004 		    break;
1005 		}
1006 	      if (c != lc_thousands_sep)
1007 	        {
1008 	          wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1009 	          wbuf[wbuf_cur_sz++] = c;
1010 		}
1011 
1012 	      if (width > 0)
1013 		--width;
1014 
1015 	      c = in_ch (s, &read_in);
1016 	    }
1017 
1018 	  if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
1019 	    {
1020 	      if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
1021 		  && match_string (s, &read_in, &c, L"(nil)"))
1022 		{
1023 		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1024 		  wbuf[wbuf_cur_sz++] = '0';
1025 		}
1026 	      else
1027 		{
1028 		  back_ch (c, s, &read_in, 0);
1029 		  return cleanup_return (rval, &gcollect, pstr, &wbuf);
1030 		}
1031 	    }
1032 	  else
1033 	    back_ch (c, s, &read_in, 0);
1034 
1035 	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1036 	  wbuf[wbuf_cur_sz++] = 0;
1037 
1038 	  if ((flags & IS_LL) != 0)
1039 	    {
1040 	      if ((flags & IS_SIGNED_NUM) != 0)
1041 		cv_val.ll = wcstoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1042 	      else
1043 		cv_val.ull = wcstoull (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1044 	    }
1045 	  else
1046 	    {
1047 	      if ((flags & IS_SIGNED_NUM) != 0)
1048 		cv_val.l = wcstol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1049 	      else
1050 		cv_val.ul = wcstoul (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1051 	    }
1052 	  if (wbuf == tmp_wbuf_ptr)
1053 	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1054 
1055 	  if ((flags & IS_SUPPRESSED) == 0)
1056 	    {
1057 	      if ((flags & IS_SIGNED_NUM) != 0)
1058 		{
1059 		  if ((flags & IS_LL) != 0)
1060 		    *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
1061 		  else if ((flags & IS_L) != 0)
1062 		    *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
1063 		  else if ((flags & IS_S) != 0)
1064 		    *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
1065 		  else if ((flags & IS_C) != 0)
1066 		    *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
1067 		  else
1068 		    *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
1069 		}
1070 	      else
1071 		{
1072 		  if ((flags & IS_LL) != 0)
1073 		    *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
1074 		  else if ((flags & IS_L) != 0)
1075 		    *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
1076 		  else if ((flags & IS_S) != 0)
1077 		    *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
1078 		      = (unsigned short) cv_val.ul;
1079 		  else if ((flags & IS_C) != 0)
1080 		    *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
1081 		  else
1082 		    *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
1083 		}
1084 	      ++rval;
1085 	    }
1086 	  break;
1087 
1088 	case 'e': case 'E':
1089 	case 'f': case 'F':
1090 	case 'g': case 'G':
1091 	case 'a': case 'A':
1092 	  if (width > 0)
1093 	    --width;
1094 	  if ((c = in_ch (s, &read_in)) == WEOF)
1095 	    return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1096 
1097 	  seen_dot = seen_exp = 0;
1098 	  is_neg = (c == '-' ? 1 : 0);
1099 
1100 	  if (c == '-' || c == '+')
1101 	    {
1102 	      if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
1103 		return cleanup_return (rval, &gcollect, pstr, &wbuf);
1104 	      if (width > 0)
1105 		--width;
1106 	    }
1107 
1108 	  if (towlower (c) == 'n')
1109 	    {
1110 	      const wchar_t *match_txt = L"nan";
1111 
1112 	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1113 	      wbuf[wbuf_cur_sz++] = c;
1114 
1115 	      ++match_txt;
1116 	      do
1117 		{
1118 		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1119 		      || towlower (c) != match_txt[0])
1120 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1121 		  if (width > 0)
1122 		    --width;
1123 
1124 		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1125 		  wbuf[wbuf_cur_sz++] = c;
1126 		  ++match_txt;
1127 		}
1128 	      while (*match_txt != 0);
1129 	    }
1130 	  else if (towlower (c) == 'i')
1131 	    {
1132 	      const wchar_t *match_txt = L"inf";
1133 
1134 	      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1135 	      wbuf[wbuf_cur_sz++] = c;
1136 
1137 	      ++match_txt;
1138 	      do
1139 		{
1140 		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1141 		      || towlower (c) != match_txt[0])
1142 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1143 		  if (width > 0)
1144 		    --width;
1145 
1146 		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1147 		  wbuf[wbuf_cur_sz++] = c;
1148 		  ++match_txt;
1149 		}
1150 	      while (*match_txt != 0);
1151 
1152 	      if (width != 0 && (c = in_ch (s, &read_in)) != WEOF && towlower (c) == 'i')
1153 		{
1154 		  match_txt = L"inity";
1155 		  if (width > 0)
1156 		    --width;
1157 
1158 		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1159 		  wbuf[wbuf_cur_sz++] = c;
1160 
1161 		  ++match_txt;
1162 		  do
1163 		    {
1164 		      if (width == 0 || (c = in_ch (s, &read_in)) == WEOF
1165 			  || towlower (c) != match_txt[0])
1166 			return cleanup_return (rval, &gcollect, pstr, &wbuf);
1167 		      if (width > 0)
1168 			--width;
1169 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1170 		      wbuf[wbuf_cur_sz++] = c;
1171 		      ++match_txt;
1172 		    }
1173 		  while (*match_txt != 0);
1174 		}
1175 	      else if (width != 0 && c != WEOF)
1176 	        back_ch (c, s, &read_in, 0);
1177 	    }
1178 	  else
1179 	    {
1180 	      not_in = 'e';
1181 	      if (width != 0 && c == '0')
1182 		{
1183 		  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1184 		  wbuf[wbuf_cur_sz++] = c;
1185 
1186 		  c = in_ch (s, &read_in);
1187 		  if (width > 0)
1188 		    --width;
1189 		  if (width != 0 && towlower (c) == 'x')
1190 		    {
1191 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1192 		      wbuf[wbuf_cur_sz++] = c;
1193 		      flags |= IS_HEX_FLOAT;
1194 		      not_in = 'p';
1195 
1196 		      flags &= ~USE_GROUP;
1197 		      c = in_ch (s, &read_in);
1198 		      if (width > 0)
1199 			--width;
1200 		    }
1201 		}
1202 
1203 	      while (1)
1204 		{
1205 		  if (iswdigit (c))
1206 		    {
1207 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1208 		      wbuf[wbuf_cur_sz++] = c;
1209 		    }
1210 		  else if (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && iswxdigit (c))
1211 		    {
1212 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1213 		      wbuf[wbuf_cur_sz++] = c;
1214 		    }
1215 		  else if (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in
1216 			   && (c == '-' || c == '+'))
1217 		    {
1218 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1219 		      wbuf[wbuf_cur_sz++] = c;
1220 		    }
1221 		  else if (wbuf_cur_sz > 0 && !seen_exp
1222 			   && (wchar_t) towlower (c) == not_in)
1223 		    {
1224 		      wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1225 		      wbuf[wbuf_cur_sz++] = not_in;
1226 
1227 		      seen_exp = seen_dot = 1;
1228 		    }
1229 		  else
1230 		    {
1231 		      if (!seen_dot && c == lc_decimal_point)
1232 			{
1233 			  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1234 			  wbuf[wbuf_cur_sz++] = c;
1235 
1236 			  seen_dot = 1;
1237 			}
1238 		      else if ((flags & USE_GROUP) != 0 && !seen_dot && c == lc_thousands_sep)
1239 			{
1240 			  /* As our conversion routines aren't supporting thousands
1241 			     separators, we are filtering them here.  */
1242 			}
1243 		      else
1244 			{
1245 			  back_ch (c, s, &read_in, 0);
1246 			  break;
1247 			}
1248 		    }
1249 
1250 		  if (width == 0 || (c = in_ch (s, &read_in)) == WEOF)
1251 		    break;
1252 
1253 		  if (width > 0)
1254 		    --width;
1255 		}
1256 
1257 	      if (wbuf_cur_sz == 0 || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
1258 		return cleanup_return (rval, &gcollect, pstr, &wbuf);
1259 	    }
1260 
1261 	  wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1262 	  wbuf[wbuf_cur_sz++] = 0;
1263 
1264 	  if ((flags & IS_LL) != 0)
1265 	    {
1266 	      long double d = __mingw_wcstold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1267 	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1268 		*(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -d : d;
1269 	    }
1270 	  else if ((flags & IS_L) != 0)
1271 	    {
1272 	      double d = __mingw_wcstod (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1273 	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1274 		*(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
1275 	    }
1276 	  else
1277 	    {
1278 	      float d = __mingw_wcstof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1279 	      if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1280 		*(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
1281 	    }
1282 
1283 	  if (wbuf == tmp_wbuf_ptr)
1284 	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1285 
1286 	  if ((flags & IS_SUPPRESSED) == 0)
1287 	    ++rval;
1288 	  break;
1289 
1290 	case '[':
1291 	  if ((flags & IS_L) != 0)
1292 	    {
1293 	      if ((flags & IS_SUPPRESSED) == 0)
1294 		{
1295 		  if ((flags & IS_ALLOC_USED) != 0)
1296 		    {
1297 		     if (npos != 0)
1298 		       pstr = (char **) get_va_nth (argp, npos);
1299 		     else
1300 		       pstr = va_arg (arg, char **);
1301 
1302 		      if (!pstr)
1303 			return cleanup_return (rval, &gcollect, pstr, &wbuf);
1304 		      str_sz = 100;
1305 		      *pstr = (char *) malloc (100 * sizeof (wchar_t));
1306 		      if ((wstr = (wchar_t *) *pstr) == NULL)
1307 			return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1308 
1309 		      gcollect = resize_gcollect (gcollect);
1310 		      gcollect->ptrs[gcollect->count++] = pstr;
1311 		    }
1312 		  else
1313 		    {
1314 		      if (npos != 0)
1315 			wstr = (wchar_t *) get_va_nth (argp, npos);
1316 		      else
1317 			wstr = va_arg (arg, wchar_t *);
1318 		      if (!wstr)
1319 			return cleanup_return (rval, &gcollect, pstr, &wbuf);
1320 		    }
1321 		}
1322 
1323 	    }
1324 	  else if ((flags & IS_SUPPRESSED) == 0)
1325 	    {
1326 	      if ((flags & IS_ALLOC_USED) != 0)
1327 		{
1328 		 if (npos != 0)
1329 		   pstr = (char **) get_va_nth (argp, npos);
1330 		 else
1331 		   pstr = va_arg (arg, char **);
1332 
1333 		  if (!pstr)
1334 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1335 		  str_sz = 100;
1336 		  if ((str = *pstr = (char *) malloc (100)) == NULL)
1337 		    return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1338 		  gcollect = resize_gcollect (gcollect);
1339 		  gcollect->ptrs[gcollect->count++] = pstr;
1340 		}
1341 	      else
1342 		{
1343 		  if (npos != 0)
1344 		    str = (char *) get_va_nth (argp, npos);
1345 		  else
1346 		    str = va_arg (arg, char *);
1347 		  if (!str)
1348 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1349 		}
1350 	    }
1351 
1352 	  not_in = (*f == '^' ? 1 : 0);
1353 	  if (*f == '^')
1354 	    f++;
1355 
1356 	  if (width < 0)
1357 	    width = INT_MAX;
1358 
1359 	  tmp_wbuf_ptr = (wchar_t *) f;
1360 
1361 	  if (*f == L']')
1362 	    ++f;
1363 
1364 	  while ((fc = *f++) != 0 && fc != L']');
1365 
1366 	  if (fc == 0)
1367 	    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1368 	  temp_wbuf_end = (wchar_t *) f - 1;
1369 
1370 	  if ((flags & IS_L) != 0)
1371 	    {
1372 	      read_in_sv = read_in;
1373 
1374 	      if ((c = in_ch (s, &read_in)) == WEOF)
1375 		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1376 
1377 	      do
1378 		{
1379 		  int ended = 0;
1380 		  for (wbuf_iter = tmp_wbuf_ptr; wbuf_iter < temp_wbuf_end;)
1381 		    {
1382 		      if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
1383 			  && (wbuf_iter + 1) != temp_wbuf_end
1384 			  && wbuf_iter != tmp_wbuf_ptr
1385 			  && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
1386 			{
1387 			  for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
1388 
1389 			  if (wc <= wbuf_iter[1] && !not_in)
1390 			    break;
1391 			  if (wc <= wbuf_iter[1] && not_in)
1392 			    {
1393 			      back_ch (c, s, &read_in, 0);
1394 			      ended = 1;
1395 			      break;
1396 			    }
1397 
1398 			  wbuf_iter += 2;
1399 			}
1400 		      else
1401 			{
1402 			  if ((wint_t) *wbuf_iter == c && !not_in)
1403 			    break;
1404 			  if ((wint_t) *wbuf_iter == c && not_in)
1405 			    {
1406 			      back_ch (c, s, &read_in, 0);
1407 			      ended = 1;
1408 			      break;
1409 			    }
1410 
1411 			  ++wbuf_iter;
1412 			}
1413 		    }
1414 		  if (ended)
1415 		    break;
1416 
1417 		  if (wbuf_iter == temp_wbuf_end && !not_in)
1418 		    {
1419 		      back_ch (c, s, &read_in, 0);
1420 		      break;
1421 		    }
1422 
1423 		  if ((flags & IS_SUPPRESSED) == 0)
1424 		    {
1425 		      *wstr++ = c;
1426 
1427 		      if ((flags & IS_ALLOC_USED) != 0
1428 			  && wstr == ((wchar_t *) *pstr + str_sz))
1429 			{
1430 			  new_sz = str_sz * 2;
1431 			  while ((wstr = (wchar_t *) realloc (*pstr,
1432 						      new_sz * sizeof (wchar_t))) == NULL
1433 				 && new_sz > (size_t) (str_sz + 1))
1434 			    new_sz = str_sz + 1;
1435 			  if (!wstr)
1436 			    {
1437 			      if ((flags & USE_POSIX_ALLOC) == 0)
1438 				{
1439 				  ((wchar_t *) (*pstr))[str_sz - 1] = 0;
1440 				  pstr = NULL;
1441 				  ++rval;
1442 				}
1443 			      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1444 			    }
1445 			  *pstr = (char *) wstr;
1446 			  wstr += str_sz;
1447 			  str_sz = new_sz;
1448 			}
1449 		    }
1450 		}
1451 	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
1452 
1453 	      if (read_in_sv == read_in)
1454 		return cleanup_return (rval, &gcollect, pstr, &wbuf);
1455 
1456 	      if ((flags & IS_SUPPRESSED) == 0)
1457 		{
1458 		  *wstr++ = 0;
1459 
1460 		  optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
1461 		  pstr = NULL;
1462 		  ++rval;
1463 		}
1464 	    }
1465 	  else
1466 	    {
1467 	      read_in_sv = read_in;
1468 
1469 	      if ((c = in_ch (s, &read_in)) == WEOF)
1470 		return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1471 
1472 	      memset (&state, 0, sizeof (state));
1473 
1474 	      do
1475 		{
1476 		  int ended = 0;
1477 		  wbuf_iter = tmp_wbuf_ptr;
1478 		  while (wbuf_iter < temp_wbuf_end)
1479 		    {
1480 		      if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0
1481 			  && (wbuf_iter + 1) != temp_wbuf_end
1482 			  && wbuf_iter != tmp_wbuf_ptr
1483 			  && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1])
1484 			{
1485 			  for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc);
1486 
1487 			  if (wc <= wbuf_iter[1] && !not_in)
1488 			    break;
1489 			  if (wc <= wbuf_iter[1] && not_in)
1490 			    {
1491 			      back_ch (c, s, &read_in, 0);
1492 			      ended = 1;
1493 			      break;
1494 			    }
1495 
1496 			  wbuf_iter += 2;
1497 			}
1498 		      else
1499 			{
1500 			  if ((wint_t) *wbuf_iter == c && !not_in)
1501 			    break;
1502 			  if ((wint_t) *wbuf_iter == c && not_in)
1503 			    {
1504 			      back_ch (c, s, &read_in, 0);
1505 			      ended = 1;
1506 			      break;
1507 			    }
1508 
1509 			  ++wbuf_iter;
1510 			}
1511 		    }
1512 
1513 		  if (ended)
1514 		    break;
1515 		  if (wbuf_iter == temp_wbuf_end && !not_in)
1516 		    {
1517 		      back_ch (c, s, &read_in, 0);
1518 		      break;
1519 		    }
1520 
1521 		  if ((flags & IS_SUPPRESSED) == 0)
1522 		    {
1523 		      if ((flags & IS_ALLOC_USED) != 0
1524 			  && (str + MB_CUR_MAX) >= (*pstr + str_sz))
1525 			{
1526 			  new_sz = str_sz * 2;
1527 			  str_len = (str - *pstr);
1528 
1529 			  while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL
1530 			  	 && new_sz > (str_len + MB_CUR_MAX))
1531 			    new_sz = str_len + MB_CUR_MAX;
1532 			  if (!nstr)
1533 			    {
1534 			      if ((flags & USE_POSIX_ALLOC) == 0)
1535 				{
1536 				  ((*pstr))[str_len] = 0;
1537 				  pstr = NULL;
1538 				  ++rval;
1539 				}
1540 			      return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1541 			    }
1542 			  *pstr = nstr;
1543 			  str = nstr + str_len;
1544 			  str_sz = new_sz;
1545 			}
1546 		    }
1547 
1548 		  n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state);
1549 		  if (n == (size_t) -1LL)
1550 		  {
1551 		    errno = EILSEQ;
1552 		    return cleanup_return (rval, &gcollect, pstr, &wbuf);
1553 		  }
1554 
1555 		  str += n;
1556 		}
1557 	      while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF);
1558 
1559 	      if (read_in_sv == read_in)
1560 		return cleanup_return (rval, &gcollect, pstr, &wbuf);
1561 
1562 	      if ((flags & IS_SUPPRESSED) == 0)
1563 		{
1564 		  n = wcrtomb (buf, 0, &state);
1565 		  if (n > 0 && (flags & IS_ALLOC_USED) != 0
1566 		      && (str + n) >= (*pstr + str_sz))
1567 		    {
1568 		      str_len = (str - *pstr);
1569 
1570 		      if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL)
1571 			{
1572 			  if ((flags & USE_POSIX_ALLOC) == 0)
1573 			    {
1574 			      (*pstr)[str_len] = 0;
1575 			      pstr = NULL;
1576 			      ++rval;
1577 			    }
1578 			  return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1579 			}
1580 		      *pstr = nstr;
1581 		      str = nstr + str_len;
1582 		      str_sz = str_len + n + 1;
1583 		    }
1584 
1585 		  if (n)
1586 		  {
1587 		    memcpy (str, buf, n);
1588 		    str += n;
1589 		  }
1590 		  *str++ = 0;
1591 
1592 		  optimize_alloc (pstr, str, str_sz);
1593 		  pstr = NULL;
1594 		  ++rval;
1595 		}
1596 	    }
1597 	  break;
1598 
1599 	default:
1600 	  return cleanup_return (rval, &gcollect, pstr, &wbuf);
1601 	}
1602     }
1603 
1604   if (ignore_ws)
1605     {
1606       while (iswspace ((c = in_ch (s, &read_in))));
1607       back_ch (c, s, &read_in, 0);
1608     }
1609 
1610   return cleanup_return (rval, &gcollect, pstr, &wbuf);
1611 }
1612 
1613 int
__mingw_vfwscanf(FILE * s,const wchar_t * format,va_list argp)1614 __mingw_vfwscanf (FILE *s, const wchar_t *format, va_list argp)
1615 {
1616   _IFP ifp;
1617   memset (&ifp, 0, sizeof (_IFP));
1618   ifp.fp = s;
1619   return __mingw_swformat (&ifp, format, argp);
1620 }
1621 
1622 int
__mingw_vswscanf(const wchar_t * s,const wchar_t * format,va_list argp)1623 __mingw_vswscanf (const wchar_t *s, const wchar_t *format, va_list argp)
1624 {
1625   _IFP ifp;
1626   memset (&ifp, 0, sizeof (_IFP));
1627   ifp.str = s;
1628   ifp.is_string = 1;
1629   return __mingw_swformat (&ifp, format, argp);
1630 }
1631 
1632