master
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#include "mingw_sformat.h"
61
62/* Helper flags for conversion. */
63#define IS_C 0x0001
64#define IS_S 0x0002
65#define IS_L 0x0004
66#define IS_LL 0x0008
67#define IS_SIGNED_NUM 0x0010
68#define IS_POINTER 0x0020
69#define IS_HEX_FLOAT 0x0040
70#define IS_SUPPRESSED 0x0080
71#define USE_GROUP 0x0100
72#define USE_GNU_ALLOC 0x0200
73#define USE_POSIX_ALLOC 0x0400
74
75#define IS_ALLOC_USED (USE_GNU_ALLOC | USE_POSIX_ALLOC)
76
77static void *
78get_va_nth (va_list argp, unsigned int n)
79{
80 va_list ap;
81 if (!n) abort ();
82 va_copy (ap, argp);
83 while (--n > 0)
84 (void) va_arg(ap, void *);
85 return va_arg (ap, void *);
86}
87
88static void
89optimize_alloc (char **p, char *end, size_t alloc_sz)
90{
91 size_t need_sz;
92 char *h;
93
94 if (!p || !*p)
95 return;
96
97 need_sz = end - *p;
98 if (need_sz == alloc_sz)
99 return;
100
101 if ((h = (char *) realloc (*p, need_sz)) != NULL)
102 *p = h;
103}
104
105static void
106back_ch (int c, _IFP *s, size_t *rin, int not_eof)
107{
108 if (!not_eof && c == EOF)
109 return;
110 if (s->is_string == 0)
111 {
112 FILE *fp = s->fp;
113 ungetc (c, fp);
114 rin[0] -= 1;
115 return;
116 }
117 rin[0] -= 1;
118 s->bch[s->back_top] = c;
119 s->back_top += 1;
120}
121
122static int
123in_ch (_IFP *s, size_t *rin)
124{
125 int r;
126 if (s->back_top)
127 {
128 s->back_top -= 1;
129 r = s->bch[s->back_top];
130 rin[0] += 1;
131 }
132 else if (s->seen_eof)
133 {
134 return EOF;
135 }
136 else if (s->is_string)
137 {
138 const char *ps = s->str;
139 r = ((int) *ps) & 0xff;
140 ps++;
141 if (r != 0)
142 {
143 rin[0] += 1;
144 s->str = ps;
145 return r;
146 }
147 s->seen_eof = 1;
148 return EOF;
149 }
150 else
151 {
152 FILE *fp = (FILE *) s->fp;
153 r = getc (fp);
154 if (r != EOF)
155 rin[0] += 1;
156 else s->seen_eof = 1;
157 }
158 return r;
159}
160
161static int
162match_string (_IFP *s, size_t *rin, int *c, const char *str)
163{
164 int ch = *c;
165
166 if (*str == 0)
167 return 1;
168
169 if (*str != (char) tolower (ch))
170 return 0;
171 ++str;
172 while (*str != 0)
173 {
174 if ((ch = in_ch (s, rin)) == EOF)
175 {
176 c[0] = ch;
177 return 0;
178 }
179
180 if (*str != (char) tolower (ch))
181 {
182 c[0] = ch;
183 return 0;
184 }
185 ++str;
186 }
187 c[0] = ch;
188 return 1;
189}
190
191struct gcollect
192{
193 size_t count;
194 struct gcollect *next;
195 char **ptrs[32];
196};
197
198static void
199release_ptrs (struct gcollect **pt, char **wbuf)
200{
201 struct gcollect *pf;
202 size_t cnt;
203
204 if (wbuf)
205 {
206 free (*wbuf);
207 *wbuf = NULL;
208 }
209 if (!pt || (pf = *pt) == NULL)
210 return;
211 while (pf != NULL)
212 {
213 struct gcollect *pf_sv = pf;
214 for (cnt = 0; cnt < pf->count; ++cnt)
215 {
216 free (*pf->ptrs[cnt]);
217 *pf->ptrs[cnt] = NULL;
218 }
219 pf = pf->next;
220 free (pf_sv);
221 }
222 *pt = NULL;
223}
224
225static int
226cleanup_return (int rval, struct gcollect **pfree, char **strp, char **wbuf)
227{
228 if (rval == EOF)
229 release_ptrs (pfree, wbuf);
230 else
231 {
232 if (pfree)
233 {
234 struct gcollect *pf = *pfree, *pf_sv;
235 while (pf != NULL)
236 {
237 pf_sv = pf;
238 pf = pf->next;
239 free (pf_sv);
240 }
241 *pfree = NULL;
242 }
243 if (strp != NULL)
244 {
245 free (*strp);
246 *strp = NULL;
247 }
248 if (wbuf)
249 {
250 free (*wbuf);
251 *wbuf = NULL;
252 }
253 }
254 return rval;
255}
256
257static struct gcollect *
258resize_gcollect (struct gcollect *pf)
259{
260 struct gcollect *np;
261 if (pf && pf->count < 32)
262 return pf;
263 np = malloc (sizeof (struct gcollect));
264 np->count = 0;
265 np->next = pf;
266 return np;
267}
268
269static char *
270resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, char *old)
271{
272 char *wbuf;
273 size_t nsz;
274 if (*wbuf_max_sz != wpsz)
275 return old;
276 nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
277 if (!old)
278 wbuf = (char *) malloc (nsz);
279 else
280 wbuf = (char *) realloc (old, nsz);
281 if (!wbuf)
282 {
283 if (old)
284 free (old);
285 }
286 else
287 *wbuf_max_sz = nsz;
288 return wbuf;
289}
290
291int
292__cdecl
293__mingw_sformat (_IFP *s, const char *format, va_list argp)
294{
295 const char *f = format;
296 struct gcollect *gcollect = NULL;
297 size_t read_in = 0, wbuf_max_sz = 0, cnt;
298 ssize_t str_sz = 0;
299 char *str = NULL, **pstr = NULL, *wbuf = NULL;
300 wchar_t *wstr = NULL;
301 int rval = 0, c = 0, ignore_ws = 0;
302 va_list arg;
303 unsigned char fc;
304 unsigned int npos;
305 int width, flags, base = 0, errno_sv;
306 size_t wbuf_cur_sz, read_in_sv, new_sz, n;
307 char seen_dot, seen_exp, is_neg, not_in;
308 char *tmp_wbuf_ptr, buf[MB_LEN_MAX];
309 const char *lc_decimal_point, *lc_thousands_sep;
310 mbstate_t state = {0}, cstate;
311 union {
312 unsigned long long ull;
313 unsigned long ul;
314 long long ll;
315 long l;
316 } cv_val;
317
318 arg = argp;
319
320 if (!s || s->fp == NULL || !format)
321 {
322 errno = EINVAL;
323 return EOF;
324 }
325
326 lc_decimal_point = localeconv()->decimal_point;
327 lc_thousands_sep = localeconv()->thousands_sep;
328 if (lc_thousands_sep != NULL && *lc_thousands_sep == 0)
329 lc_thousands_sep = NULL;
330
331 while (*f != 0)
332 {
333 if (!isascii ((unsigned char) *f))
334 {
335 int len;
336
337 if ((len = mbrlen (f, strlen (f), &state)) > 0)
338 {
339 do
340 {
341 if ((c = in_ch (s, &read_in)) == EOF || c != (unsigned char) *f++)
342 {
343 back_ch (c, s, &read_in, 1);
344 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
345 }
346 }
347 while (--len > 0);
348
349 continue;
350 }
351 }
352
353 fc = *f++;
354 if (fc != '%')
355 {
356 if (isspace (fc))
357 ignore_ws = 1;
358 else
359 {
360 if ((c = in_ch (s, &read_in)) == EOF)
361 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
362
363 if (ignore_ws)
364 {
365 ignore_ws = 0;
366 if (isspace (c))
367 {
368 do
369 {
370 if ((c = in_ch (s, &read_in)) == EOF)
371 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
372 }
373 while (isspace (c));
374 }
375 }
376
377 if (c != fc)
378 {
379 back_ch (c, s, &read_in, 0);
380 return cleanup_return (rval, &gcollect, pstr, &wbuf);
381 }
382 }
383
384 continue;
385 }
386
387 width = flags = 0;
388 npos = 0;
389 wbuf_cur_sz = 0;
390
391 if (isdigit ((unsigned char) *f))
392 {
393 const char *svf = f;
394 npos = (unsigned char) *f++ - '0';
395 while (isdigit ((unsigned char) *f))
396 npos = npos * 10 + ((unsigned char) *f++ - '0');
397 if (*f != '$')
398 {
399 npos = 0;
400 f = svf;
401 }
402 else
403 f++;
404 }
405
406 do
407 {
408 if (*f == '*')
409 flags |= IS_SUPPRESSED;
410 else if (*f == '\'')
411 {
412 if (lc_thousands_sep)
413 flags |= USE_GROUP;
414 }
415 else if (*f == 'I')
416 {
417 /* we don't support locale's digits (i18N), but ignore it for now silently. */
418 ;
419#ifdef _WIN32
420 if (f[1] == '6' && f[2] == '4')
421 {
422 flags |= IS_LL | IS_L;
423 f += 2;
424 }
425 else if (f[1] == '3' && f[2] == '2')
426 {
427 flags |= IS_L;
428 f += 2;
429 }
430 else
431 {
432#ifdef _WIN64
433 flags |= IS_LL | IS_L;
434#else
435 flags |= IS_L;
436#endif
437 }
438#endif
439 }
440 else
441 break;
442 ++f;
443 }
444 while (1);
445
446 while (isdigit ((unsigned char) *f))
447 width = width * 10 + ((unsigned char) *f++ - '0');
448
449 if (!width)
450 width = -1;
451
452 switch (*f)
453 {
454 case 'h':
455 ++f;
456 flags |= (*f == 'h' ? IS_C : IS_S);
457 if (*f == 'h')
458 ++f;
459 break;
460 case 'l':
461 ++f;
462 flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
463 if (*f == 'l')
464 ++f;
465 break;
466 case 'q': case 'L':
467 ++f;
468 flags |= IS_LL | IS_L;
469 break;
470 case 'a':
471 if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
472 break;
473 ++f;
474 flags |= USE_GNU_ALLOC;
475 break;
476 case 'm':
477 flags |= USE_POSIX_ALLOC;
478 ++f;
479 if (*f == 'l')
480 {
481 flags |= IS_L;
482 f++;
483 }
484 break;
485 case 'z':
486#ifdef _WIN64
487 flags |= IS_LL | IS_L;
488#else
489 flags |= IS_L;
490#endif
491 ++f;
492 break;
493 case 'j':
494 if (sizeof (uintmax_t) > sizeof (unsigned long))
495 flags |= IS_LL;
496 else if (sizeof (uintmax_t) > sizeof (unsigned int))
497 flags |= IS_L;
498 ++f;
499 break;
500 case 't':
501#ifdef _WIN64
502 flags |= IS_LL;
503#else
504 flags |= IS_L;
505#endif
506 ++f;
507 break;
508 case 0:
509 return cleanup_return (rval, &gcollect, pstr, &wbuf);
510 default:
511 break;
512 }
513
514 if (*f == 0)
515 return cleanup_return (rval, &gcollect, pstr, &wbuf);
516
517 fc = *f++;
518 if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
519 {
520 errno_sv = errno;
521 errno = 0;
522 do
523 {
524 if ((c == EOF || (c = in_ch (s, &read_in)) == EOF)
525 && errno == EINTR)
526 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
527 }
528 while (isspace (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)) == EOF)
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
591 str_sz = (width > 1024 ? 1024 : width);
592 if ((str = *pstr = (char *) malloc (str_sz)) == NULL)
593 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
594
595 gcollect = resize_gcollect (gcollect);
596 gcollect->ptrs[gcollect->count++] = pstr;
597 }
598 else
599 {
600 if (npos != 0)
601 str = (char *) get_va_nth (argp, npos);
602 else
603 str = va_arg (arg, char *);
604 if (!str)
605 return cleanup_return (rval, &gcollect, pstr, &wbuf);
606 }
607 }
608
609 if ((c = in_ch (s, &read_in)) == EOF)
610 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
611
612 if ((flags & IS_SUPPRESSED) == 0)
613 {
614 do
615 {
616 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
617 {
618 new_sz = str_sz + (str_sz >= width ? width - 1 : str_sz);
619 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
620 && new_sz > (size_t) (str_sz + 1))
621 new_sz = str_sz + 1;
622 if (!str)
623 {
624 release_ptrs (&gcollect, &wbuf);
625 return EOF;
626 }
627 *pstr = str;
628 str += str_sz;
629 str_sz = new_sz;
630 }
631 *str++ = c;
632 }
633 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
634 }
635 else
636 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
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 gcollect = resize_gcollect (gcollect);
667 gcollect->ptrs[gcollect->count++] = pstr;
668 }
669 else
670 {
671 if (npos != 0)
672 wstr = (wchar_t *) get_va_nth (argp, npos);
673 else
674 wstr = va_arg (arg, wchar_t *);
675 if (!wstr)
676 return cleanup_return (rval, &gcollect, pstr, &wbuf);
677 }
678 }
679
680 if ((c = in_ch (s, &read_in)) == EOF)
681 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
682
683 cstate = (mbstate_t){0};
684
685 do
686 {
687 buf[0] = c;
688
689 if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
690 && wstr == ((wchar_t *) *pstr + str_sz))
691 {
692 new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
693
694 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
695 && new_sz > (size_t) (str_sz + 1))
696 new_sz = str_sz + 1;
697 if (!wstr)
698 {
699 release_ptrs (&gcollect, &wbuf);
700 return EOF;
701 }
702 *pstr = (char *) wstr;
703 wstr += str_sz;
704 str_sz = new_sz;
705 }
706
707 while (1)
708 {
709 n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
710
711 if (n == (size_t) -2)
712 {
713 if ((c = in_ch (s, &read_in)) == EOF)
714 {
715 errno = EILSEQ;
716 return cleanup_return (rval, &gcollect, pstr, &wbuf);
717 }
718
719 buf[0] = c;
720 continue;
721 }
722
723 if (n != 1)
724 {
725 errno = EILSEQ;
726 return cleanup_return (rval, &gcollect, pstr, &wbuf);
727 }
728 break;
729 }
730
731 ++wstr;
732 }
733 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
734
735 if ((flags & IS_SUPPRESSED) == 0)
736 {
737 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
738 pstr = NULL;
739 ++rval;
740 }
741 break;
742
743 case 's':
744 if ((flags & IS_SUPPRESSED) == 0)
745 {
746 if ((flags & IS_ALLOC_USED) != 0)
747 {
748 if (npos != 0)
749 pstr = (char **) get_va_nth (argp, npos);
750 else
751 pstr = va_arg (arg, char **);
752
753 if (!pstr)
754 return cleanup_return (rval, &gcollect, pstr, &wbuf);
755
756 str_sz = 100;
757 if ((str = *pstr = (char *) malloc (100)) == NULL)
758 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
759 gcollect = resize_gcollect (gcollect);
760 gcollect->ptrs[gcollect->count++] = pstr;
761 }
762 else
763 {
764 if (npos != 0)
765 str = (char *) get_va_nth (argp, npos);
766 else
767 str = va_arg (arg, char *);
768 if (!str)
769 return cleanup_return (rval, &gcollect, pstr, &wbuf);
770 }
771 }
772
773 if ((c = in_ch (s, &read_in)) == EOF)
774 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
775
776 do
777 {
778 if (isspace (c))
779 {
780 back_ch (c, s, &read_in, 1);
781 break;
782 }
783
784 if ((flags & IS_SUPPRESSED) == 0)
785 {
786 *str++ = c;
787 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
788 {
789 new_sz = str_sz * 2;
790
791 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
792 && new_sz > (size_t) (str_sz + 1))
793 new_sz = str_sz + 1;
794 if (!str)
795 {
796 if ((flags & USE_POSIX_ALLOC) == 0)
797 {
798 (*pstr)[str_sz - 1] = 0;
799 pstr = NULL;
800 ++rval;
801 }
802 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
803 }
804 *pstr = str;
805 str += str_sz;
806 str_sz = new_sz;
807 }
808 }
809 }
810 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
811
812 if ((flags & IS_SUPPRESSED) == 0)
813 {
814 *str++ = 0;
815 optimize_alloc (pstr, str, str_sz);
816 pstr = NULL;
817 ++rval;
818 }
819 break;
820
821 case 'S':
822 if ((flags & IS_SUPPRESSED) == 0)
823 {
824 if ((flags & IS_ALLOC_USED) != 0)
825 {
826 if (npos != 0)
827 pstr = (char **) get_va_nth (argp, npos);
828 else
829 pstr = va_arg (arg, char **);
830
831 if (!pstr)
832 return cleanup_return (rval, &gcollect, pstr, &wbuf);
833
834 str_sz = 100;
835 *pstr = (char *) malloc (100 * sizeof (wchar_t));
836 if ((wstr = (wchar_t *) *pstr) == NULL)
837 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
838 gcollect = resize_gcollect (gcollect);
839 gcollect->ptrs[gcollect->count++] = pstr;
840 }
841 else
842 {
843 if (npos != 0)
844 wstr = (wchar_t *) get_va_nth (argp, npos);
845 else
846 wstr = va_arg (arg, wchar_t *);
847 if (!wstr)
848 return cleanup_return (rval, &gcollect, pstr, &wbuf);
849 }
850 }
851
852 if ((c = in_ch (s, &read_in)) == EOF)
853 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
854
855 cstate = (mbstate_t){0};
856
857 do
858 {
859 if (isspace (c))
860 {
861 back_ch (c, s, &read_in, 1);
862 break;
863 }
864
865 buf[0] = c;
866
867 while (1)
868 {
869 n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
870
871 if (n == (size_t) -2)
872 {
873 if ((c = in_ch (s, &read_in)) == EOF)
874 {
875 errno = EILSEQ;
876 return cleanup_return (rval, &gcollect, pstr, &wbuf);
877 }
878
879 buf[0] = c;
880 continue;
881 }
882
883 if (n != 1)
884 {
885 errno = EILSEQ;
886 return cleanup_return (rval, &gcollect, pstr, &wbuf);
887 }
888
889 ++wstr;
890 break;
891 }
892
893 if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
894 && wstr == ((wchar_t *) *pstr + str_sz))
895 {
896 new_sz = str_sz * 2;
897 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
898 && new_sz > (size_t) (str_sz + 1))
899 new_sz = str_sz + 1;
900 if (!wstr)
901 {
902 if ((flags & USE_POSIX_ALLOC) == 0)
903 {
904 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
905 pstr = NULL;
906 ++rval;
907 }
908 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
909 }
910 *pstr = (char *) wstr;
911 wstr += str_sz;
912 str_sz = new_sz;
913 }
914 }
915 while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
916
917 if ((flags & IS_SUPPRESSED) == 0)
918 {
919 *wstr++ = 0;
920 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
921 pstr = NULL;
922 ++rval;
923 }
924 break;
925
926 case 'd': case 'i':
927 case 'o': case 'p':
928 case 'u':
929 case 'x': case 'X':
930 switch (fc)
931 {
932 case 'd':
933 flags |= IS_SIGNED_NUM;
934 base = 10;
935 break;
936 case 'i':
937 flags |= IS_SIGNED_NUM;
938 base = 0;
939 break;
940 case 'o':
941 base = 8;
942 break;
943 case 'p':
944 base = 16;
945 flags &= ~(IS_S | IS_LL | IS_L);
946 #ifdef _WIN64
947 flags |= IS_LL;
948 #endif
949 flags |= IS_L | IS_POINTER;
950 break;
951 case 'u':
952 base = 10;
953 break;
954 case 'x': case 'X':
955 base = 16;
956 break;
957 }
958
959 if ((c = in_ch (s, &read_in)) == EOF)
960 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
961 if (c == '+' || c == '-')
962 {
963 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
964 wbuf[wbuf_cur_sz++] = c;
965 if (width > 0)
966 --width;
967 c = in_ch (s, &read_in);
968 }
969 if (width != 0 && c == '0')
970 {
971 if (width > 0)
972 --width;
973
974 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
975 wbuf[wbuf_cur_sz++] = c;
976 c = in_ch (s, &read_in);
977
978 if (width != 0 && tolower (c) == 'x')
979 {
980 if (!base)
981 base = 16;
982 if (base == 16)
983 {
984 if (width > 0)
985 --width;
986 c = in_ch (s, &read_in);
987 }
988 }
989 else if (!base)
990 base = 8;
991 }
992
993 if (!base)
994 base = 10;
995
996 while (c != EOF && width != 0)
997 {
998 if (base == 16)
999 {
1000 if (!isxdigit (c))
1001 break;
1002 }
1003 else if (!isdigit (c) || (int) (c - '0') >= base)
1004 {
1005 const char *p = lc_thousands_sep;
1006 int remain;
1007
1008 if (base != 10 || (flags & USE_GROUP) == 0)
1009 break;
1010 remain = width > 0 ? width : INT_MAX;
1011 while ((unsigned char) *p == c && remain >= 0)
1012 {
1013 /* As our conversion routines aren't supporting thousands
1014 separators, we are filtering them here. */
1015
1016 ++p;
1017 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1018 break;
1019 --remain;
1020 }
1021
1022 if (*p != 0)
1023 {
1024 if (p > lc_thousands_sep)
1025 {
1026 back_ch (c, s, &read_in, 0);
1027 while (--p > lc_thousands_sep)
1028 back_ch ((unsigned char) *p, s, &read_in, 1);
1029 c = (unsigned char) *p;
1030 }
1031 break;
1032 }
1033
1034 if (width > 0)
1035 width = remain;
1036 --wbuf_cur_sz;
1037 }
1038 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1039 wbuf[wbuf_cur_sz++] = c;
1040 if (width > 0)
1041 --width;
1042
1043 c = in_ch (s, &read_in);
1044 }
1045
1046 if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
1047 {
1048 if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
1049 && match_string (s, &read_in, &c, "(nil)"))
1050 {
1051 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1052 wbuf[wbuf_cur_sz++] = '0';
1053 }
1054 else
1055 {
1056 back_ch (c, s, &read_in, 0);
1057 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1058 }
1059 }
1060 else
1061 back_ch (c, s, &read_in, 0);
1062
1063 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1064 wbuf[wbuf_cur_sz++] = 0;
1065
1066 if ((flags & IS_LL))
1067 {
1068 if (flags & IS_SIGNED_NUM)
1069 cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1070 else
1071 cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base);
1072 }
1073 else
1074 {
1075 if (flags & IS_SIGNED_NUM)
1076 cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1077 else
1078 cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base);
1079 }
1080 if (wbuf == tmp_wbuf_ptr)
1081 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1082
1083 if ((flags & IS_SUPPRESSED) == 0)
1084 {
1085 if ((flags & IS_SIGNED_NUM) != 0)
1086 {
1087 if ((flags & IS_LL) != 0)
1088 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
1089 else if ((flags & IS_L) != 0)
1090 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
1091 else if ((flags & IS_S) != 0)
1092 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
1093 else if ((flags & IS_C) != 0)
1094 *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
1095 else
1096 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
1097 }
1098 else
1099 {
1100 if ((flags & IS_LL) != 0)
1101 *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
1102 else if ((flags & IS_L) != 0)
1103 *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
1104 else if ((flags & IS_S) != 0)
1105 *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
1106 = (unsigned short) cv_val.ul;
1107 else if ((flags & IS_C) != 0)
1108 *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
1109 else
1110 *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
1111 }
1112 ++rval;
1113 }
1114 break;
1115
1116 case 'e': case 'E':
1117 case 'f': case 'F':
1118 case 'g': case 'G':
1119 case 'a': case 'A':
1120 if (width > 0)
1121 --width;
1122 if ((c = in_ch (s, &read_in)) == EOF)
1123 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1124
1125 seen_dot = seen_exp = 0;
1126 is_neg = (c == '-' ? 1 : 0);
1127
1128 if (c == '-' || c == '+')
1129 {
1130 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1131 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1132 if (width > 0)
1133 --width;
1134 }
1135
1136 if (tolower (c) == 'n')
1137 {
1138 const char *match_txt = "nan";
1139
1140 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1141 wbuf[wbuf_cur_sz++] = c;
1142
1143 ++match_txt;
1144 do
1145 {
1146 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1147 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1148
1149 if (width > 0)
1150 --width;
1151
1152 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1153 wbuf[wbuf_cur_sz++] = c;
1154 ++match_txt;
1155 }
1156 while (*match_txt != 0);
1157 }
1158 else if (tolower (c) == 'i')
1159 {
1160 const char *match_txt = "inf";
1161
1162 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1163 wbuf[wbuf_cur_sz++] = c;
1164
1165 ++match_txt;
1166 do
1167 {
1168 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1169 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1170 if (width > 0)
1171 --width;
1172
1173 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1174 wbuf[wbuf_cur_sz++] = c;
1175 ++match_txt;
1176 }
1177 while (*match_txt != 0);
1178
1179 if (width != 0 && (c = in_ch (s, &read_in)) != EOF && tolower (c) == 'i')
1180 {
1181 match_txt = "inity";
1182
1183 if (width > 0)
1184 --width;
1185
1186 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1187 wbuf[wbuf_cur_sz++] = c;
1188 ++match_txt;
1189
1190 do
1191 {
1192 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1193 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1194 if (width > 0)
1195 --width;
1196
1197 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1198 wbuf[wbuf_cur_sz++] = c;
1199 ++match_txt;
1200 }
1201 while (*match_txt != 0);
1202 }
1203 else if (width != 0 && c != EOF)
1204 back_ch (c, s, &read_in, 0);
1205 }
1206 else
1207 {
1208 not_in = 'e';
1209 if (width != 0 && c == '0')
1210 {
1211 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1212 wbuf[wbuf_cur_sz++] = c;
1213
1214 c = in_ch (s, &read_in);
1215 if (width > 0)
1216 --width;
1217 if (width != 0 && tolower (c) == 'x')
1218 {
1219 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1220 wbuf[wbuf_cur_sz++] = c;
1221
1222 flags |= IS_HEX_FLOAT;
1223 not_in = 'p';
1224
1225 flags &= ~USE_GROUP;
1226 c = in_ch (s, &read_in);
1227 if (width > 0)
1228 --width;
1229 }
1230 }
1231
1232 while (1)
1233 {
1234 if (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c))
1235 || (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in && (c == '-' || c == '+')))
1236 {
1237 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1238 wbuf[wbuf_cur_sz++] = c;
1239 }
1240 else if (wbuf_cur_sz > 0 && !seen_exp && (char) tolower (c) == not_in)
1241 {
1242 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1243 wbuf[wbuf_cur_sz++] = not_in;
1244 seen_exp = seen_dot = 1;
1245 }
1246 else
1247 {
1248 const char *p = lc_decimal_point;
1249 int remain = width > 0 ? width : INT_MAX;
1250
1251 if (! seen_dot)
1252 {
1253 while ((unsigned char) *p == c && remain >= 0)
1254 {
1255 ++p;
1256 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1257 break;
1258 --remain;
1259 }
1260 }
1261
1262 if (*p == 0)
1263 {
1264 for (p = lc_decimal_point; *p != 0; ++p)
1265 {
1266 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1267 wbuf[wbuf_cur_sz++] = (unsigned char) *p;
1268 }
1269 if (width > 0)
1270 width = remain;
1271 seen_dot = 1;
1272 }
1273 else
1274 {
1275 const char *pp = lc_thousands_sep;
1276
1277 if (!seen_dot && (flags & USE_GROUP) != 0)
1278 {
1279 while ((pp - lc_thousands_sep) < (p - lc_decimal_point)
1280 && *pp == lc_decimal_point[(pp - lc_thousands_sep)])
1281 ++pp;
1282 if ((pp - lc_thousands_sep) == (p - lc_decimal_point))
1283 {
1284 while ((unsigned char) *pp == c && remain >= 0)
1285 {
1286 ++pp;
1287 if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1288 break;
1289 --remain;
1290 }
1291 }
1292 }
1293
1294 if (pp != NULL && *pp == 0)
1295 {
1296 /* As our conversion routines aren't supporting thousands
1297 separators, we are filtering them here. */
1298 if (width > 0)
1299 width = remain;
1300 }
1301 else
1302 {
1303 back_ch (c, s, &read_in, 0);
1304 break;
1305 }
1306 }
1307 }
1308
1309 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1310 break;
1311
1312 if (width > 0)
1313 --width;
1314 }
1315
1316 if (!wbuf_cur_sz || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
1317 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1318 }
1319
1320 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1321 wbuf[wbuf_cur_sz++] = 0;
1322
1323 if ((flags & IS_LL) != 0)
1324 {
1325 long double ld;
1326 ld = __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1327 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1328 *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -ld : ld;
1329 }
1330 else if ((flags & IS_L) != 0)
1331 {
1332 double d;
1333 d = (double) __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1334 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1335 *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
1336 }
1337 else
1338 {
1339 float d = __mingw_strtof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1340 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1341 *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
1342 }
1343
1344 if (wbuf == tmp_wbuf_ptr)
1345 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1346
1347 if ((flags & IS_SUPPRESSED) == 0)
1348 ++rval;
1349 break;
1350
1351 case '[':
1352 if ((flags & IS_L) != 0)
1353 {
1354 if ((flags & IS_SUPPRESSED) == 0)
1355 {
1356 if ((flags & IS_ALLOC_USED) != 0)
1357 {
1358 if (npos != 0)
1359 pstr = (char **) get_va_nth (argp, npos);
1360 else
1361 pstr = va_arg (arg, char **);
1362
1363 if (!pstr)
1364 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1365
1366 str_sz = 100;
1367 *pstr = (char *) malloc (100 * sizeof (wchar_t));
1368
1369 if ((wstr = (wchar_t *) *pstr) == NULL)
1370 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1371 gcollect = resize_gcollect (gcollect);
1372 gcollect->ptrs[gcollect->count++] = pstr;
1373 }
1374 else
1375 {
1376 if (npos != 0)
1377 wstr = (wchar_t *) get_va_nth (argp, npos);
1378 else
1379 wstr = va_arg (arg, wchar_t *);
1380 if (!wstr)
1381 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1382 }
1383 }
1384 }
1385 else if ((flags & IS_SUPPRESSED) == 0)
1386 {
1387 if ((flags & IS_ALLOC_USED) != 0)
1388 {
1389 if (npos != 0)
1390 pstr = (char **) get_va_nth (argp, npos);
1391 else
1392 pstr = va_arg (arg, char **);
1393
1394 if (!pstr)
1395 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1396
1397 str_sz = 100;
1398 if ((str = *pstr = (char *) malloc (100)) == NULL)
1399 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1400
1401 gcollect = resize_gcollect (gcollect);
1402 gcollect->ptrs[gcollect->count++] = pstr;
1403 }
1404 else
1405 {
1406 if (npos != 0)
1407 str = (char *) get_va_nth (argp, npos);
1408 else
1409 str = va_arg (arg, char *);
1410 if (!str)
1411 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1412 }
1413 }
1414
1415 not_in = (*f == '^' ? 1 : 0);
1416 if (*f == '^')
1417 f++;
1418
1419 if (width < 0)
1420 width = INT_MAX;
1421
1422 if (wbuf_max_sz < 256)
1423 {
1424 wbuf_max_sz = 256;
1425 if (wbuf)
1426 free (wbuf);
1427 wbuf = (char *) malloc (wbuf_max_sz);
1428 }
1429 memset (wbuf, 0, 256);
1430
1431 fc = *f;
1432 if (fc == ']' || fc == '-')
1433 {
1434 wbuf[fc] = 1;
1435 ++f;
1436 }
1437
1438 while ((fc = *f++) != 0 && fc != ']')
1439 {
1440 if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f)
1441 {
1442 for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
1443 wbuf[fc] = 1;
1444 }
1445 else
1446 wbuf[fc] = 1;
1447 }
1448
1449 if (!fc)
1450 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1451
1452 if ((flags & IS_L) != 0)
1453 {
1454 read_in_sv = read_in;
1455 cnt = 0;
1456
1457 if ((c = in_ch (s, &read_in)) == EOF)
1458 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1459
1460 cstate = (mbstate_t){0};
1461
1462 do
1463 {
1464 if (wbuf[c] == not_in)
1465 {
1466 back_ch (c, s, &read_in, 1);
1467 break;
1468 }
1469
1470 if ((flags & IS_SUPPRESSED) == 0)
1471 {
1472 buf[0] = c;
1473 n = mbrtowc (wstr, buf, 1, &cstate);
1474
1475 if (n == (size_t) -2)
1476 {
1477 ++cnt;
1478 continue;
1479 }
1480 cnt = 0;
1481
1482 ++wstr;
1483 if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
1484 {
1485 new_sz = str_sz * 2;
1486 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
1487 && new_sz > (size_t) (str_sz + 1))
1488 new_sz = str_sz + 1;
1489 if (!wstr)
1490 {
1491 if ((flags & USE_POSIX_ALLOC) == 0)
1492 {
1493 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
1494 pstr = NULL;
1495 ++rval;
1496 }
1497 else
1498 rval = EOF;
1499 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1500 }
1501 *pstr = (char *) wstr;
1502 wstr += str_sz;
1503 str_sz = new_sz;
1504 }
1505 }
1506
1507 if (--width <= 0)
1508 break;
1509 }
1510 while ((c = in_ch (s, &read_in)) != EOF);
1511
1512 if (cnt != 0)
1513 {
1514 errno = EILSEQ;
1515 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1516 }
1517
1518 if (read_in_sv == read_in)
1519 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1520
1521
1522 if ((flags & IS_SUPPRESSED) == 0)
1523 {
1524 *wstr++ = 0;
1525 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
1526 pstr = NULL;
1527 ++rval;
1528 }
1529 }
1530 else
1531 {
1532 read_in_sv = read_in;
1533
1534 if ((c = in_ch (s, &read_in)) == EOF)
1535 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1536
1537 do
1538 {
1539 if (wbuf[c] == not_in)
1540 {
1541 back_ch (c, s, &read_in, 1);
1542 break;
1543 }
1544
1545 if ((flags & IS_SUPPRESSED) == 0)
1546 {
1547 *str++ = c;
1548 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
1549 {
1550 new_sz = str_sz * 2;
1551
1552 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
1553 && new_sz > (size_t) (str_sz + 1))
1554 new_sz = str_sz + 1;
1555 if (!str)
1556 {
1557 if ((flags & USE_POSIX_ALLOC) == 0)
1558 {
1559 (*pstr)[str_sz - 1] = 0;
1560 pstr = NULL;
1561 ++rval;
1562 }
1563 else
1564 rval = EOF;
1565 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1566 }
1567 *pstr = str;
1568 str += str_sz;
1569 str_sz = new_sz;
1570 }
1571 }
1572 }
1573 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
1574
1575 if (read_in_sv == read_in)
1576 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1577
1578 if ((flags & IS_SUPPRESSED) == 0)
1579 {
1580 *str++ = 0;
1581 optimize_alloc (pstr, str, str_sz);
1582 pstr = NULL;
1583 ++rval;
1584 }
1585 }
1586 break;
1587
1588 default:
1589 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1590 }
1591 }
1592
1593 if (ignore_ws)
1594 {
1595 while (isspace ((c = in_ch (s, &read_in))));
1596 back_ch (c, s, &read_in, 0);
1597 }
1598
1599 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1600}