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