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