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 case 'b': case 'B':
931 switch (fc)
932 {
933 case 'd':
934 flags |= IS_SIGNED_NUM;
935 base = 10;
936 break;
937 case 'i':
938 flags |= IS_SIGNED_NUM;
939 base = 0;
940 break;
941 case 'o':
942 base = 8;
943 break;
944 case 'p':
945 base = 16;
946 flags &= ~(IS_S | IS_LL | IS_L);
947 #ifdef _WIN64
948 flags |= IS_LL;
949 #endif
950 flags |= IS_L | IS_POINTER;
951 break;
952 case 'u':
953 base = 10;
954 break;
955 case 'x': case 'X':
956 base = 16;
957 break;
958 case 'b': case 'B':
959 base = 2;
960 break;
961 }
962
963 if ((c = in_ch (s, &read_in)) == EOF)
964 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
965 if (c == '+' || c == '-')
966 {
967 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
968 wbuf[wbuf_cur_sz++] = c;
969 if (width > 0)
970 --width;
971 c = in_ch (s, &read_in);
972 }
973 if (width != 0 && c == '0')
974 {
975 if (width > 0)
976 --width;
977
978 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
979 wbuf[wbuf_cur_sz++] = c;
980 c = in_ch (s, &read_in);
981
982 if (width != 0 && tolower (c) == 'x')
983 {
984 if (!base)
985 base = 16;
986 if (base == 16)
987 {
988 if (width > 0)
989 --width;
990 c = in_ch (s, &read_in);
991 }
992 }
993 else if (!base)
994 base = 8;
995 }
996
997 if (!base)
998 base = 10;
999
1000 while (c != EOF && width != 0)
1001 {
1002 if (base == 16)
1003 {
1004 if (!isxdigit (c))
1005 break;
1006 }
1007 else if (!isdigit (c) || (int) (c - '0') >= base)
1008 {
1009 const char *p = lc_thousands_sep;
1010 int remain;
1011
1012 if (base != 10 || (flags & USE_GROUP) == 0)
1013 break;
1014 remain = width > 0 ? width : INT_MAX;
1015 while ((unsigned char) *p == c && remain >= 0)
1016 {
1017 /* As our conversion routines aren't supporting thousands
1018 separators, we are filtering them here. */
1019
1020 ++p;
1021 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1022 break;
1023 --remain;
1024 }
1025
1026 if (*p != 0)
1027 {
1028 if (p > lc_thousands_sep)
1029 {
1030 back_ch (c, s, &read_in, 0);
1031 while (--p > lc_thousands_sep)
1032 back_ch ((unsigned char) *p, s, &read_in, 1);
1033 c = (unsigned char) *p;
1034 }
1035 break;
1036 }
1037
1038 if (width > 0)
1039 width = remain;
1040 --wbuf_cur_sz;
1041 }
1042 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1043 wbuf[wbuf_cur_sz++] = c;
1044 if (width > 0)
1045 --width;
1046
1047 c = in_ch (s, &read_in);
1048 }
1049
1050 if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
1051 {
1052 if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
1053 && match_string (s, &read_in, &c, "(nil)"))
1054 {
1055 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1056 wbuf[wbuf_cur_sz++] = '0';
1057 }
1058 else
1059 {
1060 back_ch (c, s, &read_in, 0);
1061 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1062 }
1063 }
1064 else
1065 back_ch (c, s, &read_in, 0);
1066
1067 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1068 wbuf[wbuf_cur_sz++] = 0;
1069
1070 if ((flags & IS_LL))
1071 {
1072 if (flags & IS_SIGNED_NUM)
1073 cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1074 else
1075 cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base);
1076 }
1077 else
1078 {
1079 if (flags & IS_SIGNED_NUM)
1080 cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
1081 else
1082 cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base);
1083 }
1084 if (wbuf == tmp_wbuf_ptr)
1085 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1086
1087 if ((flags & IS_SUPPRESSED) == 0)
1088 {
1089 if ((flags & IS_SIGNED_NUM) != 0)
1090 {
1091 if ((flags & IS_LL) != 0)
1092 *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
1093 else if ((flags & IS_L) != 0)
1094 *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
1095 else if ((flags & IS_S) != 0)
1096 *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
1097 else if ((flags & IS_C) != 0)
1098 *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
1099 else
1100 *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
1101 }
1102 else
1103 {
1104 if ((flags & IS_LL) != 0)
1105 *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
1106 else if ((flags & IS_L) != 0)
1107 *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
1108 else if ((flags & IS_S) != 0)
1109 *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
1110 = (unsigned short) cv_val.ul;
1111 else if ((flags & IS_C) != 0)
1112 *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
1113 else
1114 *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
1115 }
1116 ++rval;
1117 }
1118 break;
1119
1120 case 'e': case 'E':
1121 case 'f': case 'F':
1122 case 'g': case 'G':
1123 case 'a': case 'A':
1124 if (width > 0)
1125 --width;
1126 if ((c = in_ch (s, &read_in)) == EOF)
1127 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1128
1129 seen_dot = seen_exp = 0;
1130 is_neg = (c == '-' ? 1 : 0);
1131
1132 if (c == '-' || c == '+')
1133 {
1134 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1135 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1136 if (width > 0)
1137 --width;
1138 }
1139
1140 if (tolower (c) == 'n')
1141 {
1142 const char *match_txt = "nan";
1143
1144 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1145 wbuf[wbuf_cur_sz++] = c;
1146
1147 ++match_txt;
1148 do
1149 {
1150 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1151 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1152
1153 if (width > 0)
1154 --width;
1155
1156 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1157 wbuf[wbuf_cur_sz++] = c;
1158 ++match_txt;
1159 }
1160 while (*match_txt != 0);
1161 }
1162 else if (tolower (c) == 'i')
1163 {
1164 const char *match_txt = "inf";
1165
1166 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1167 wbuf[wbuf_cur_sz++] = c;
1168
1169 ++match_txt;
1170 do
1171 {
1172 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1173 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1174 if (width > 0)
1175 --width;
1176
1177 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1178 wbuf[wbuf_cur_sz++] = c;
1179 ++match_txt;
1180 }
1181 while (*match_txt != 0);
1182
1183 if (width != 0 && (c = in_ch (s, &read_in)) != EOF && tolower (c) == 'i')
1184 {
1185 match_txt = "inity";
1186
1187 if (width > 0)
1188 --width;
1189
1190 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1191 wbuf[wbuf_cur_sz++] = c;
1192 ++match_txt;
1193
1194 do
1195 {
1196 if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
1197 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1198 if (width > 0)
1199 --width;
1200
1201 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1202 wbuf[wbuf_cur_sz++] = c;
1203 ++match_txt;
1204 }
1205 while (*match_txt != 0);
1206 }
1207 else if (width != 0 && c != EOF)
1208 back_ch (c, s, &read_in, 0);
1209 }
1210 else
1211 {
1212 not_in = 'e';
1213 if (width != 0 && c == '0')
1214 {
1215 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1216 wbuf[wbuf_cur_sz++] = c;
1217
1218 c = in_ch (s, &read_in);
1219 if (width > 0)
1220 --width;
1221 if (width != 0 && tolower (c) == 'x')
1222 {
1223 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1224 wbuf[wbuf_cur_sz++] = c;
1225
1226 flags |= IS_HEX_FLOAT;
1227 not_in = 'p';
1228
1229 flags &= ~USE_GROUP;
1230 c = in_ch (s, &read_in);
1231 if (width > 0)
1232 --width;
1233 }
1234 }
1235
1236 while (1)
1237 {
1238 if (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c))
1239 || (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in && (c == '-' || c == '+')))
1240 {
1241 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1242 wbuf[wbuf_cur_sz++] = c;
1243 }
1244 else if (wbuf_cur_sz > 0 && !seen_exp && (char) tolower (c) == not_in)
1245 {
1246 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1247 wbuf[wbuf_cur_sz++] = not_in;
1248 seen_exp = seen_dot = 1;
1249 }
1250 else
1251 {
1252 const char *p = lc_decimal_point;
1253 int remain = width > 0 ? width : INT_MAX;
1254
1255 if (! seen_dot)
1256 {
1257 while ((unsigned char) *p == c && remain >= 0)
1258 {
1259 ++p;
1260 if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1261 break;
1262 --remain;
1263 }
1264 }
1265
1266 if (*p == 0)
1267 {
1268 for (p = lc_decimal_point; *p != 0; ++p)
1269 {
1270 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1271 wbuf[wbuf_cur_sz++] = (unsigned char) *p;
1272 }
1273 if (width > 0)
1274 width = remain;
1275 seen_dot = 1;
1276 }
1277 else
1278 {
1279 const char *pp = lc_thousands_sep;
1280
1281 if (!seen_dot && (flags & USE_GROUP) != 0)
1282 {
1283 while ((pp - lc_thousands_sep) < (p - lc_decimal_point)
1284 && *pp == lc_decimal_point[(pp - lc_thousands_sep)])
1285 ++pp;
1286 if ((pp - lc_thousands_sep) == (p - lc_decimal_point))
1287 {
1288 while ((unsigned char) *pp == c && remain >= 0)
1289 {
1290 ++pp;
1291 if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
1292 break;
1293 --remain;
1294 }
1295 }
1296 }
1297
1298 if (pp != NULL && *pp == 0)
1299 {
1300 /* As our conversion routines aren't supporting thousands
1301 separators, we are filtering them here. */
1302 if (width > 0)
1303 width = remain;
1304 }
1305 else
1306 {
1307 back_ch (c, s, &read_in, 0);
1308 break;
1309 }
1310 }
1311 }
1312
1313 if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
1314 break;
1315
1316 if (width > 0)
1317 --width;
1318 }
1319
1320 if (!wbuf_cur_sz || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
1321 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1322 }
1323
1324 wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
1325 wbuf[wbuf_cur_sz++] = 0;
1326
1327 if ((flags & IS_LL) != 0)
1328 {
1329 long double ld;
1330 ld = __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1331 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1332 *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -ld : ld;
1333 }
1334 else if ((flags & IS_L) != 0)
1335 {
1336 double d;
1337 d = (double) __mingw_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1338 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1339 *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
1340 }
1341 else
1342 {
1343 float d = __mingw_strtof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
1344 if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
1345 *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
1346 }
1347
1348 if (wbuf == tmp_wbuf_ptr)
1349 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1350
1351 if ((flags & IS_SUPPRESSED) == 0)
1352 ++rval;
1353 break;
1354
1355 case '[':
1356 if ((flags & IS_L) != 0)
1357 {
1358 if ((flags & IS_SUPPRESSED) == 0)
1359 {
1360 if ((flags & IS_ALLOC_USED) != 0)
1361 {
1362 if (npos != 0)
1363 pstr = (char **) get_va_nth (argp, npos);
1364 else
1365 pstr = va_arg (arg, char **);
1366
1367 if (!pstr)
1368 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1369
1370 str_sz = 100;
1371 *pstr = (char *) malloc (100 * sizeof (wchar_t));
1372
1373 if ((wstr = (wchar_t *) *pstr) == NULL)
1374 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1375 gcollect = resize_gcollect (gcollect);
1376 gcollect->ptrs[gcollect->count++] = pstr;
1377 }
1378 else
1379 {
1380 if (npos != 0)
1381 wstr = (wchar_t *) get_va_nth (argp, npos);
1382 else
1383 wstr = va_arg (arg, wchar_t *);
1384 if (!wstr)
1385 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1386 }
1387 }
1388 }
1389 else if ((flags & IS_SUPPRESSED) == 0)
1390 {
1391 if ((flags & IS_ALLOC_USED) != 0)
1392 {
1393 if (npos != 0)
1394 pstr = (char **) get_va_nth (argp, npos);
1395 else
1396 pstr = va_arg (arg, char **);
1397
1398 if (!pstr)
1399 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1400
1401 str_sz = 100;
1402 if ((str = *pstr = (char *) malloc (100)) == NULL)
1403 return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
1404
1405 gcollect = resize_gcollect (gcollect);
1406 gcollect->ptrs[gcollect->count++] = pstr;
1407 }
1408 else
1409 {
1410 if (npos != 0)
1411 str = (char *) get_va_nth (argp, npos);
1412 else
1413 str = va_arg (arg, char *);
1414 if (!str)
1415 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1416 }
1417 }
1418
1419 not_in = (*f == '^' ? 1 : 0);
1420 if (*f == '^')
1421 f++;
1422
1423 if (width < 0)
1424 width = INT_MAX;
1425
1426 if (wbuf_max_sz < 256)
1427 {
1428 wbuf_max_sz = 256;
1429 if (wbuf)
1430 free (wbuf);
1431 wbuf = (char *) malloc (wbuf_max_sz);
1432 }
1433 memset (wbuf, 0, 256);
1434
1435 fc = *f;
1436 if (fc == ']' || fc == '-')
1437 {
1438 wbuf[fc] = 1;
1439 ++f;
1440 }
1441
1442 while ((fc = *f++) != 0 && fc != ']')
1443 {
1444 if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f)
1445 {
1446 for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
1447 wbuf[fc] = 1;
1448 }
1449 else
1450 wbuf[fc] = 1;
1451 }
1452
1453 if (!fc)
1454 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1455
1456 if ((flags & IS_L) != 0)
1457 {
1458 read_in_sv = read_in;
1459 cnt = 0;
1460
1461 if ((c = in_ch (s, &read_in)) == EOF)
1462 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1463
1464 cstate = (mbstate_t){0};
1465
1466 do
1467 {
1468 if (wbuf[c] == not_in)
1469 {
1470 back_ch (c, s, &read_in, 1);
1471 break;
1472 }
1473
1474 if ((flags & IS_SUPPRESSED) == 0)
1475 {
1476 buf[0] = c;
1477 n = mbrtowc (wstr, buf, 1, &cstate);
1478
1479 if (n == (size_t) -2)
1480 {
1481 ++cnt;
1482 continue;
1483 }
1484 cnt = 0;
1485
1486 ++wstr;
1487 if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
1488 {
1489 new_sz = str_sz * 2;
1490 while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
1491 && new_sz > (size_t) (str_sz + 1))
1492 new_sz = str_sz + 1;
1493 if (!wstr)
1494 {
1495 if ((flags & USE_POSIX_ALLOC) == 0)
1496 {
1497 ((wchar_t *) (*pstr))[str_sz - 1] = 0;
1498 pstr = NULL;
1499 ++rval;
1500 }
1501 else
1502 rval = EOF;
1503 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1504 }
1505 *pstr = (char *) wstr;
1506 wstr += str_sz;
1507 str_sz = new_sz;
1508 }
1509 }
1510
1511 if (--width <= 0)
1512 break;
1513 }
1514 while ((c = in_ch (s, &read_in)) != EOF);
1515
1516 if (cnt != 0)
1517 {
1518 errno = EILSEQ;
1519 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1520 }
1521
1522 if (read_in_sv == read_in)
1523 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1524
1525
1526 if ((flags & IS_SUPPRESSED) == 0)
1527 {
1528 *wstr++ = 0;
1529 optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
1530 pstr = NULL;
1531 ++rval;
1532 }
1533 }
1534 else
1535 {
1536 read_in_sv = read_in;
1537
1538 if ((c = in_ch (s, &read_in)) == EOF)
1539 return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
1540
1541 do
1542 {
1543 if (wbuf[c] == not_in)
1544 {
1545 back_ch (c, s, &read_in, 1);
1546 break;
1547 }
1548
1549 if ((flags & IS_SUPPRESSED) == 0)
1550 {
1551 *str++ = c;
1552 if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
1553 {
1554 new_sz = str_sz * 2;
1555
1556 while ((str = (char *) realloc (*pstr, new_sz)) == NULL
1557 && new_sz > (size_t) (str_sz + 1))
1558 new_sz = str_sz + 1;
1559 if (!str)
1560 {
1561 if ((flags & USE_POSIX_ALLOC) == 0)
1562 {
1563 (*pstr)[str_sz - 1] = 0;
1564 pstr = NULL;
1565 ++rval;
1566 }
1567 else
1568 rval = EOF;
1569 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1570 }
1571 *pstr = str;
1572 str += str_sz;
1573 str_sz = new_sz;
1574 }
1575 }
1576 }
1577 while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
1578
1579 if (read_in_sv == read_in)
1580 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1581
1582 if ((flags & IS_SUPPRESSED) == 0)
1583 {
1584 *str++ = 0;
1585 optimize_alloc (pstr, str, str_sz);
1586 pstr = NULL;
1587 ++rval;
1588 }
1589 }
1590 break;
1591
1592 default:
1593 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1594 }
1595 }
1596
1597 if (ignore_ws)
1598 {
1599 while (isspace ((c = in_ch (s, &read_in))));
1600 back_ch (c, s, &read_in, 0);
1601 }
1602
1603 return cleanup_return (rval, &gcollect, pstr, &wbuf);
1604}