| /* |
| This Software is provided under the Zope Public License (ZPL) Version 2.1. |
| |
| Copyright (c) 2011 by the mingw-w64 project |
| |
| See the AUTHORS file for the list of contributors to the mingw-w64 project. |
| |
| This license has been certified as open source. It has also been designated |
| as GPL compatible by the Free Software Foundation (FSF). |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are met: |
| |
| 1. Redistributions in source code must retain the accompanying copyright |
| notice, this list of conditions, and the following disclaimer. |
| 2. Redistributions in binary form must reproduce the accompanying |
| copyright notice, this list of conditions, and the following disclaimer |
| in the documentation and/or other materials provided with the |
| distribution. |
| 3. Names of the copyright holders must not be used to endorse or promote |
| products derived from this software without prior written permission |
| from the copyright holders. |
| 4. The right to distribute this software or to use it for any purpose does |
| not give you the right to use Servicemarks (sm) or Trademarks (tm) of |
| the copyright holders. Use of them is covered by separate agreement |
| with the copyright holders. |
| 5. If any files are modified, you must cause the modified files to carry |
| prominent notices stating that you changed the files and the date of |
| any change. |
| |
| Disclaimer |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED |
| OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, |
| OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <limits.h> |
| #include <stddef.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <wchar.h> |
| #include <ctype.h> |
| #include <wctype.h> |
| #include <locale.h> |
| #include <errno.h> |
| |
| #ifndef CP_UTF8 |
| #define CP_UTF8 65001 |
| #endif |
| |
| #ifndef MB_ERR_INVALID_CHARS |
| #define MB_ERR_INVALID_CHARS 0x00000008 |
| #endif |
| |
| /* Helper flags for conversion. */ |
| #define IS_C 0x0001 |
| #define IS_S 0x0002 |
| #define IS_L 0x0004 |
| #define IS_LL 0x0008 |
| #define IS_SIGNED_NUM 0x0010 |
| #define IS_POINTER 0x0020 |
| #define IS_HEX_FLOAT 0x0040 |
| #define IS_SUPPRESSED 0x0080 |
| #define USE_GROUP 0x0100 |
| #define USE_GNU_ALLOC 0x0200 |
| #define USE_POSIX_ALLOC 0x0400 |
| |
| #define IS_ALLOC_USED (USE_GNU_ALLOC | USE_POSIX_ALLOC) |
| |
| /* internal stream structure with back-buffer. */ |
| typedef struct _IFP |
| { |
| __extension__ union { |
| void *fp; |
| const wchar_t *str; |
| }; |
| int bch[1024]; |
| int is_string : 1; |
| int back_top; |
| int seen_eof : 1; |
| } _IFP; |
| |
| static void * |
| get_va_nth (va_list argp, unsigned int n) |
| { |
| va_list ap; |
| if (!n) |
| abort (); |
| va_copy (ap, argp); |
| while (--n > 0) |
| (void) va_arg(ap, void *); |
| return va_arg (ap, void *); |
| } |
| |
| static void |
| optimize_alloc (int do_realloc, char **p, size_t sz, size_t need_sz, size_t typ_sz) |
| { |
| char *h; |
| |
| if (!do_realloc || sz == need_sz || !p || *p == NULL) |
| return; |
| if ((h = (char *) realloc (*p, need_sz * typ_sz)) != NULL) |
| *p = h; |
| } |
| |
| static void |
| back_ch (int c, _IFP *s, size_t *rin, int not_eof) |
| { |
| if (!not_eof && c == WEOF) |
| return; |
| if (s->is_string == 0) |
| { |
| FILE *fp = s->fp; |
| ungetwc (c, fp); |
| rin[0] -= 1; |
| return; |
| } |
| rin[0] -= 1; |
| s->bch[s->back_top] = c; |
| s->back_top += 1; |
| } |
| |
| static int |
| in_ch (_IFP *s, size_t *rin) |
| { |
| int r; |
| if (s->back_top) |
| { |
| s->back_top -= 1; |
| r = s->bch[s->back_top]; |
| rin[0] += 1; |
| } |
| else if (s->seen_eof) |
| { |
| return WEOF; |
| } |
| else if (s->is_string) |
| { |
| const wchar_t *ps = s->str; |
| r = ((int) *ps) & 0xffff; |
| ps++; |
| if (r != 0) |
| { |
| rin[0] += 1; |
| s->str = ps; |
| return r; |
| } |
| s->seen_eof = 1; |
| return WEOF; |
| } |
| else |
| { |
| FILE *fp = (FILE *) s->fp; |
| r = getwc (fp); |
| if (r != WEOF) |
| rin[0] += 1; |
| else s->seen_eof = 1; |
| } |
| return r; |
| } |
| |
| static int |
| match_string (_IFP *s, size_t *rin, wint_t *c, const wchar_t *str) |
| { |
| int ch = *c; |
| |
| if (*str == 0) |
| return 1; |
| |
| if (*str != (wchar_t) towlower (ch)) |
| return 0; |
| ++str; |
| while (*str != 0) |
| { |
| if ((ch = in_ch (s, rin)) == WEOF) |
| { |
| c[0] = ch; |
| return 0; |
| } |
| |
| if (*str != (wchar_t) towlower (ch)) |
| { |
| c[0] = ch; |
| return 0; |
| } |
| ++str; |
| } |
| c[0] = ch; |
| return 1; |
| } |
| |
| struct gcollect |
| { |
| size_t count; |
| struct gcollect *next; |
| char **ptrs[32]; |
| }; |
| |
| static void |
| release_ptrs (struct gcollect **pt, wchar_t **wbuf) |
| { |
| struct gcollect *pf; |
| size_t cnt; |
| |
| if (wbuf) |
| { |
| free (*wbuf); |
| *wbuf = NULL; |
| } |
| if (!pt || (pf = *pt) == NULL) |
| return; |
| while (pf != NULL) |
| { |
| struct gcollect *pf_sv = pf; |
| for (cnt = 0; cnt < pf->count; ++cnt) |
| { |
| free (*pf->ptrs[cnt]); |
| *pf->ptrs[cnt] = NULL; |
| } |
| pf = pf->next; |
| free (pf_sv); |
| } |
| *pt = NULL; |
| } |
| |
| static int |
| cleanup_return (int rval, struct gcollect **pfree, char **strp, wchar_t **wbuf) |
| { |
| if (rval == WEOF) |
| release_ptrs (pfree, wbuf); |
| else |
| { |
| if (pfree) |
| { |
| struct gcollect *pf = *pfree, *pf_sv; |
| while (pf != NULL) |
| { |
| pf_sv = pf; |
| pf = pf->next; |
| free (pf_sv); |
| } |
| *pfree = NULL; |
| } |
| if (strp != NULL) |
| { |
| free (*strp); |
| *strp = NULL; |
| } |
| if (wbuf) |
| { |
| free (*wbuf); |
| *wbuf = NULL; |
| } |
| } |
| return rval; |
| } |
| |
| static struct gcollect * |
| resize_gcollect (struct gcollect *pf) |
| { |
| struct gcollect *np; |
| if (pf && pf->count < 32) |
| return pf; |
| np = malloc (sizeof (struct gcollect)); |
| np->count = 0; |
| np->next = pf; |
| return np; |
| } |
| |
| static wchar_t * |
| resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, wchar_t *old) |
| { |
| wchar_t *wbuf; |
| size_t nsz; |
| if (*wbuf_max_sz != wpsz) |
| return old; |
| nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0])); |
| if (!old) |
| wbuf = (wchar_t *) malloc (nsz * sizeof (wchar_t)); |
| else |
| wbuf = (wchar_t *) realloc (old, nsz * sizeof (wchar_t)); |
| if (!wbuf) |
| { |
| if (old) |
| free (old); |
| } |
| else |
| *wbuf_max_sz = nsz; |
| return wbuf; |
| } |
| |
| static int |
| __mingw_swformat (_IFP *s, const wchar_t *format, va_list argp) |
| { |
| const wchar_t *f = format; |
| struct gcollect *gcollect = NULL; |
| size_t read_in = 0, wbuf_max_sz = 0; |
| ssize_t str_sz = 0; |
| char *str = NULL, **pstr = NULL;; |
| wchar_t *wstr = NULL, *wbuf = NULL; |
| wint_t c = 0, rval = 0; |
| int ignore_ws = 0; |
| va_list arg; |
| size_t wbuf_cur_sz, str_len, read_in_sv, new_sz, n; |
| unsigned int fc, npos; |
| int width, flags, base = 0, errno_sv, clen; |
| char seen_dot, seen_exp, is_neg, *nstr, buf[MB_LEN_MAX]; |
| wchar_t wc, not_in, *tmp_wbuf_ptr, *temp_wbuf_end, *wbuf_iter; |
| wint_t lc_decimal_point, lc_thousands_sep; |
| mbstate_t state; |
| union { |
| unsigned long long ull; |
| unsigned long ul; |
| long long ll; |
| long l; |
| } cv_val; |
| |
| arg = argp; |
| |
| if (!s || s->fp == NULL || !format) |
| { |
| errno = EINVAL; |
| return WEOF; |
| } |
| |
| memset (&state, 0, sizeof(state)); |
| clen = mbrtowc( &wc, localeconv()->decimal_point, 16, &state); |
| lc_decimal_point = (clen > 0 ? wc : '.'); |
| memset( &state, 0, sizeof( state ) ); |
| clen = mbrtowc( &wc, localeconv()->thousands_sep, 16, &state); |
| lc_thousands_sep = (clen > 0 ? wc : 0); |
| |
| while (*f != 0) |
| { |
| fc = *f++; |
| if (fc != '%') |
| { |
| if (iswspace (fc)) |
| ignore_ws = 1; |
| else |
| { |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| if (ignore_ws) |
| { |
| ignore_ws = 0; |
| if (iswspace (c)) |
| { |
| do |
| { |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| while (iswspace (c)); |
| } |
| } |
| |
| if (c != fc) |
| { |
| back_ch (c, s, &read_in, 0); |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| continue; |
| } |
| |
| width = flags = 0; |
| npos = 0; |
| wbuf_cur_sz = 0; |
| |
| if (iswdigit ((unsigned int) *f)) |
| { |
| const wchar_t *svf = f; |
| npos = (unsigned int) *f++ - '0'; |
| while (iswdigit ((unsigned int) *f)) |
| npos = npos * 10 + ((unsigned int) *f++ - '0'); |
| if (*f != '$') |
| { |
| npos = 0; |
| f = svf; |
| } |
| else |
| f++; |
| } |
| |
| do |
| { |
| if (*f == '*') |
| flags |= IS_SUPPRESSED; |
| else if (*f == '\'') |
| { |
| if (lc_thousands_sep) |
| flags |= USE_GROUP; |
| } |
| else if (*f == 'I') |
| { |
| /* we don't support locale's digits (i18N), but ignore it for now silently. */ |
| ; |
| #ifdef _WIN32 |
| if (f[1] == '6' && f[2] == '4') |
| { |
| flags |= IS_LL | IS_L; |
| f += 2; |
| } |
| else if (f[1] == '3' && f[2] == '2') |
| { |
| flags |= IS_L; |
| f += 2; |
| } |
| else |
| { |
| #ifdef _WIN64 |
| flags |= IS_LL | IS_L; |
| #else |
| flags |= IS_L; |
| #endif |
| } |
| #endif |
| } |
| else |
| break; |
| ++f; |
| } |
| while (1); |
| |
| while (iswdigit ((unsigned char) *f)) |
| width = width * 10 + ((unsigned char) *f++ - '0'); |
| |
| if (!width) |
| width = -1; |
| |
| switch (*f) |
| { |
| case 'h': |
| ++f; |
| flags |= (*f == 'h' ? IS_C : IS_S); |
| if (*f == 'h') |
| ++f; |
| break; |
| case 'l': |
| ++f; |
| flags |= (*f == 'l' ? IS_LL : 0) | IS_L; |
| if (*f == 'l') |
| ++f; |
| break; |
| case 'q': case 'L': |
| ++f; |
| flags |= IS_LL | IS_L; |
| break; |
| case 'a': |
| if (f[1] != 's' && f[1] != 'S' && f[1] != '[') |
| break; |
| ++f; |
| flags |= USE_GNU_ALLOC; |
| break; |
| case 'm': |
| flags |= USE_POSIX_ALLOC; |
| ++f; |
| if (*f == 'l') |
| { |
| flags |= IS_L; |
| ++f; |
| } |
| break; |
| case 'z': |
| #ifdef _WIN64 |
| flags |= IS_LL | IS_L; |
| #else |
| flags |= IS_L; |
| #endif |
| ++f; |
| break; |
| case 'j': |
| if (sizeof (uintmax_t) > sizeof (unsigned long)) |
| flags |= IS_LL; |
| else if (sizeof (uintmax_t) > sizeof (unsigned int)) |
| flags |= IS_L; |
| ++f; |
| break; |
| case 't': |
| #ifdef _WIN64 |
| flags |= IS_LL; |
| #else |
| flags |= IS_L; |
| #endif |
| ++f; |
| break; |
| case 0: |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| default: |
| break; |
| } |
| |
| if (*f == 0) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| |
| fc = *f++; |
| if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n')) |
| { |
| errno_sv = errno; |
| errno = 0; |
| do |
| { |
| if ((c == WEOF || (c = in_ch (s, &read_in)) == WEOF) && errno == EINTR) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| while (iswspace (c)); |
| |
| ignore_ws = 0; |
| errno = errno_sv; |
| back_ch (c, s, &read_in, 0); |
| } |
| |
| switch (fc) |
| { |
| case 'c': |
| if ((flags & IS_L) != 0) |
| fc = 'C'; |
| break; |
| case 's': |
| if ((flags & IS_L) != 0) |
| fc = 'S'; |
| break; |
| } |
| |
| switch (fc) |
| { |
| case '%': |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| if (c != fc) |
| { |
| back_ch (c, s, &read_in, 1); |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| break; |
| |
| case 'n': |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_LL) != 0) |
| *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in; |
| else if ((flags & IS_L) != 0) |
| *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in; |
| else if ((flags & IS_S) != 0) |
| *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in; |
| else if ((flags & IS_C) != 0) |
| *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in; |
| else |
| *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in; |
| } |
| break; |
| |
| case 'c': |
| if (width == -1) |
| width = 1; |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = 100; |
| if ((str = *pstr = (char *) malloc (100)) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| else |
| { |
| if (npos != 0) |
| str = (char *) get_va_nth (argp, npos); |
| else |
| str = va_arg (arg, char *); |
| if (!str) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| memset (&state, 0, sizeof (state)); |
| |
| do |
| { |
| if ((flags & IS_SUPPRESSED) == 0 && (flags & USE_POSIX_ALLOC) != 0 |
| && (str + MB_CUR_MAX) >= (*pstr + str_sz)) |
| { |
| new_sz = str_sz * 2; |
| str_len = (str - *pstr); |
| while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL |
| && new_sz > (str_len + MB_CUR_MAX)) |
| new_sz = str_len + MB_CUR_MAX; |
| if (!nstr) |
| { |
| release_ptrs (&gcollect, &wbuf); |
| return WEOF; |
| } |
| *pstr = nstr; |
| str = nstr + str_len; |
| str_sz = new_sz; |
| } |
| |
| n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state); |
| if (n == (size_t) -1LL) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| str += n; |
| } |
| while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (str - *pstr), sizeof (char)); |
| pstr = NULL; |
| ++rval; |
| } |
| |
| break; |
| |
| case 'C': |
| if (width == -1) |
| width = 1; |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = (width > 1024 ? 1024 : width); |
| *pstr = (char *) malloc (str_sz * sizeof (wchar_t)); |
| if ((wstr = (wchar_t *) *pstr) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| if ((wstr = (wchar_t *) *pstr) != NULL) |
| { |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| } |
| else |
| { |
| if (npos != 0) |
| wstr = (wchar_t *) get_va_nth (argp, npos); |
| else |
| wstr = va_arg (arg, wchar_t *); |
| if (!wstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| do |
| { |
| if ((flags & IS_ALLOC_USED) != 0 |
| && wstr == ((wchar_t *) *pstr + str_sz)) |
| { |
| new_sz = str_sz + (str_sz > width ? width - 1 : str_sz); |
| while ((wstr = (wchar_t *) realloc (*pstr, |
| new_sz * sizeof (wchar_t))) == NULL |
| && new_sz > (size_t) (str_sz + 1)) |
| new_sz = str_sz + 1; |
| if (!wstr) |
| { |
| release_ptrs (&gcollect, &wbuf); |
| return WEOF; |
| } |
| *pstr = (char *) wstr; |
| wstr += str_sz; |
| str_sz = new_sz; |
| } |
| *wstr++ = c; |
| } |
| while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF); |
| } |
| else |
| { |
| while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF); |
| } |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (wstr - (wchar_t *) *pstr), sizeof (wchar_t)); |
| pstr = NULL; |
| ++rval; |
| } |
| break; |
| |
| case 's': |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = 100; |
| if ((str = *pstr = (char *) malloc (100)) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| else |
| { |
| if (npos != 0) |
| str = (char *) get_va_nth (argp, npos); |
| else |
| str = va_arg (arg, char *); |
| if (!str) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| memset (&state, 0, sizeof (state)); |
| |
| do |
| { |
| if (iswspace (c)) |
| { |
| back_ch (c, s, &read_in, 1); |
| break; |
| } |
| |
| { |
| if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0 |
| && (str + MB_CUR_MAX) >= (*pstr + str_sz)) |
| { |
| new_sz = str_sz * 2; |
| str_len = (str - *pstr); |
| |
| while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL |
| && new_sz > (str_len + MB_CUR_MAX)) |
| new_sz = str_len + MB_CUR_MAX; |
| if (!nstr) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| (*pstr)[str_len] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = nstr; |
| str = nstr + str_len; |
| str_sz = new_sz; |
| } |
| |
| n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, |
| &state); |
| if (n == (size_t) -1LL) |
| { |
| errno = EILSEQ; |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| |
| str += n; |
| } |
| } |
| while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| n = wcrtomb (buf, 0, &state); |
| if (n > 0 && (flags & IS_ALLOC_USED) != 0 |
| && (str + n) >= (*pstr + str_sz)) |
| { |
| str_len = (str - *pstr); |
| |
| if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| (*pstr)[str_len] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = nstr; |
| str = nstr + str_len; |
| str_sz = str_len + n + 1; |
| } |
| |
| if (n) |
| { |
| memcpy (str, buf, n); |
| str += n; |
| } |
| *str++ = 0; |
| |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (str - *pstr), sizeof (char)); |
| pstr = NULL; |
| ++rval; |
| } |
| break; |
| |
| case 'S': |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = 100; |
| *pstr = (char *) malloc (100 * sizeof (wchar_t)); |
| if ((wstr = (wchar_t *) *pstr) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| else |
| { |
| if (npos != 0) |
| wstr = (wchar_t *) get_va_nth (argp, npos); |
| else |
| wstr = va_arg (arg, wchar_t *); |
| if (!wstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| do |
| { |
| if (iswspace (c)) |
| { |
| back_ch (c, s, &read_in, 1); |
| break; |
| } |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| *wstr++ = c; |
| if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz)) |
| { |
| new_sz = str_sz * 2; |
| |
| while ((wstr = (wchar_t *) realloc (*pstr, |
| new_sz * sizeof (wchar_t))) == NULL |
| && new_sz > (size_t) (str_sz + 1)) |
| new_sz = str_sz + 1; |
| if (!wstr) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| ((wchar_t *) (*pstr))[str_sz - 1] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = (char *) wstr; |
| wstr += str_sz; |
| str_sz = new_sz; |
| } |
| } |
| } |
| while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != WEOF); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| *wstr++ = 0; |
| |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (wstr - (wchar_t *) *pstr), sizeof (wchar_t)); |
| pstr = NULL; |
| ++rval; |
| } |
| break; |
| |
| case 'd': case 'i': |
| case 'o': case 'p': |
| case 'u': |
| case 'x': case 'X': |
| switch (fc) |
| { |
| case 'd': |
| flags |= IS_SIGNED_NUM; |
| base = 10; |
| break; |
| case 'i': |
| flags |= IS_SIGNED_NUM; |
| base = 0; |
| break; |
| case 'o': |
| base = 8; |
| break; |
| case 'p': |
| base = 16; |
| flags &= ~(IS_S | IS_LL | IS_L); |
| #ifdef _WIN64 |
| flags |= IS_LL; |
| #endif |
| flags |= IS_L | IS_POINTER; |
| break; |
| case 'u': |
| base = 10; |
| break; |
| case 'x': case 'X': |
| base = 16; |
| break; |
| } |
| |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| if (c == '+' || c == '-') |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| if (width > 0) |
| --width; |
| c = in_ch (s, &read_in); |
| } |
| |
| if (width != 0 && c == '0') |
| { |
| if (width > 0) |
| --width; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| c = in_ch (s, &read_in); |
| |
| if (width != 0 && towlower (c) == 'x') |
| { |
| if (!base) |
| base = 16; |
| if (base == 16) |
| { |
| if (width > 0) |
| --width; |
| c = in_ch (s, &read_in); |
| } |
| } |
| else if (!base) |
| base = 8; |
| } |
| |
| if (!base) |
| base = 10; |
| |
| while (c != WEOF && width != 0) |
| { |
| if (base == 16) |
| { |
| if (!iswxdigit (c)) |
| break; |
| } |
| else if (!iswdigit (c) || (int) (c - '0') >= base) |
| { |
| if (base != 10 || (flags & USE_GROUP) == 0 || c != lc_thousands_sep) |
| break; |
| } |
| if (c != lc_thousands_sep) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| } |
| |
| if (width > 0) |
| --width; |
| |
| c = in_ch (s, &read_in); |
| } |
| |
| if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-'))) |
| { |
| if (!wbuf_cur_sz && (flags & IS_POINTER) != 0 |
| && match_string (s, &read_in, &c, L"(nil)")) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = '0'; |
| } |
| else |
| { |
| back_ch (c, s, &read_in, 0); |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| else |
| back_ch (c, s, &read_in, 0); |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = 0; |
| |
| if ((flags & IS_LL) != 0) |
| { |
| if ((flags & IS_SIGNED_NUM) != 0) |
| cv_val.ll = wcstoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); |
| else |
| cv_val.ull = wcstoull (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); |
| } |
| else |
| { |
| if ((flags & IS_SIGNED_NUM) != 0) |
| cv_val.l = wcstol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); |
| else |
| cv_val.ul = wcstoul (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); |
| } |
| if (wbuf == tmp_wbuf_ptr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_SIGNED_NUM) != 0) |
| { |
| if ((flags & IS_LL) != 0) |
| *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll; |
| else if ((flags & IS_L) != 0) |
| *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l; |
| else if ((flags & IS_S) != 0) |
| *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l; |
| else if ((flags & IS_C) != 0) |
| *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul; |
| else |
| *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l; |
| } |
| else |
| { |
| if ((flags & IS_LL) != 0) |
| *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull; |
| else if ((flags & IS_L) != 0) |
| *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul; |
| else if ((flags & IS_S) != 0) |
| *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *)) |
| = (unsigned short) cv_val.ul; |
| else if ((flags & IS_C) != 0) |
| *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul; |
| else |
| *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul; |
| } |
| ++rval; |
| } |
| break; |
| |
| case 'e': case 'E': |
| case 'f': case 'F': |
| case 'g': case 'G': |
| case 'a': case 'A': |
| if (width > 0) |
| --width; |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| seen_dot = seen_exp = 0; |
| is_neg = (c == '-' ? 1 : 0); |
| |
| if (c == '-' || c == '+') |
| { |
| if (width == 0 || (c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| if (width > 0) |
| --width; |
| } |
| |
| if (towlower (c) == 'n') |
| { |
| const wchar_t *match_txt = L"nan"; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| ++match_txt; |
| do |
| { |
| if (width == 0 || (c = in_ch (s, &read_in)) == WEOF |
| || towlower (c) != match_txt[0]) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| if (width > 0) |
| --width; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| ++match_txt; |
| } |
| while (*match_txt != 0); |
| } |
| else if (towlower (c) == 'i') |
| { |
| const wchar_t *match_txt = L"inf"; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| ++match_txt; |
| do |
| { |
| if (width == 0 || (c = in_ch (s, &read_in)) == WEOF |
| || towlower (c) != match_txt[0]) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| if (width > 0) |
| --width; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| ++match_txt; |
| } |
| while (*match_txt != 0); |
| |
| if (width != 0 && (c = in_ch (s, &read_in)) != WEOF && towlower (c) == 'i') |
| { |
| match_txt = L"inity"; |
| if (width > 0) |
| --width; |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| ++match_txt; |
| do |
| { |
| if (width == 0 || (c = in_ch (s, &read_in)) == WEOF |
| || towlower (c) != match_txt[0]) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| if (width > 0) |
| --width; |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| ++match_txt; |
| } |
| while (*match_txt != 0); |
| } |
| else if (width != 0 && c != WEOF) |
| back_ch (c, s, &read_in, 0); |
| } |
| else |
| { |
| not_in = 'e'; |
| if (width != 0 && c == '0') |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| c = in_ch (s, &read_in); |
| if (width > 0) |
| --width; |
| if (width != 0 && towlower (c) == 'x') |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| flags |= IS_HEX_FLOAT; |
| not_in = 'p'; |
| |
| flags &= ~USE_GROUP; |
| c = in_ch (s, &read_in); |
| if (width > 0) |
| --width; |
| } |
| } |
| |
| while (1) |
| { |
| if (iswdigit (c)) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| } |
| else if (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && iswxdigit (c)) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| } |
| else if (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in |
| && (c == '-' || c == '+')) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| } |
| else if (wbuf_cur_sz > 0 && !seen_exp |
| && (wchar_t) towlower (c) == not_in) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = not_in; |
| |
| seen_exp = seen_dot = 1; |
| } |
| else |
| { |
| if (!seen_dot && c == lc_decimal_point) |
| { |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = c; |
| |
| seen_dot = 1; |
| } |
| else if ((flags & USE_GROUP) != 0 && !seen_dot && c == lc_thousands_sep) |
| { |
| /* As our conversion routines aren't supporting thousands |
| separators, we are filtering them here. */ |
| } |
| else |
| { |
| back_ch (c, s, &read_in, 0); |
| break; |
| } |
| } |
| |
| if (width == 0 || (c = in_ch (s, &read_in)) == WEOF) |
| break; |
| |
| if (width > 0) |
| --width; |
| } |
| |
| if (wbuf_cur_sz == 0 || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2)) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); |
| wbuf[wbuf_cur_sz++] = 0; |
| |
| if ((flags & IS_LL) != 0) |
| { |
| long double d = __mingw_wcstold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/); |
| if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf) |
| *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -d : d; |
| } |
| else if ((flags & IS_L) != 0) |
| { |
| double d = __mingw_wcstod (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/); |
| if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf) |
| *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d; |
| } |
| else |
| { |
| float d = __mingw_wcstof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/); |
| if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf) |
| *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d; |
| } |
| |
| if (wbuf == tmp_wbuf_ptr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| ++rval; |
| break; |
| |
| case '[': |
| if ((flags & IS_L) != 0) |
| { |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = 100; |
| *pstr = (char *) malloc (100 * sizeof (wchar_t)); |
| if ((wstr = (wchar_t *) *pstr) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| else |
| { |
| if (npos != 0) |
| wstr = (wchar_t *) get_va_nth (argp, npos); |
| else |
| wstr = va_arg (arg, wchar_t *); |
| if (!wstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| } |
| else if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0) |
| { |
| if (npos != 0) |
| pstr = (char **) get_va_nth (argp, npos); |
| else |
| pstr = va_arg (arg, char **); |
| |
| if (!pstr) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| str_sz = 100; |
| if ((str = *pstr = (char *) malloc (100)) == NULL) |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| gcollect = resize_gcollect (gcollect); |
| gcollect->ptrs[gcollect->count++] = pstr; |
| } |
| else |
| { |
| if (npos != 0) |
| str = (char *) get_va_nth (argp, npos); |
| else |
| str = va_arg (arg, char *); |
| if (!str) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| not_in = (*f == '^' ? 1 : 0); |
| if (*f == '^') |
| f++; |
| |
| if (width < 0) |
| width = INT_MAX; |
| |
| tmp_wbuf_ptr = (wchar_t *) f; |
| |
| if (*f == L']') |
| ++f; |
| |
| while ((fc = *f++) != 0 && fc != L']'); |
| |
| if (fc == 0) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| temp_wbuf_end = (wchar_t *) f - 1; |
| |
| if ((flags & IS_L) != 0) |
| { |
| read_in_sv = read_in; |
| |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| do |
| { |
| int ended = 0; |
| for (wbuf_iter = tmp_wbuf_ptr; wbuf_iter < temp_wbuf_end;) |
| { |
| if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0 |
| && (wbuf_iter + 1) != temp_wbuf_end |
| && wbuf_iter != tmp_wbuf_ptr |
| && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1]) |
| { |
| for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc); |
| |
| if (wc <= wbuf_iter[1] && !not_in) |
| break; |
| if (wc <= wbuf_iter[1] && not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| ended = 1; |
| break; |
| } |
| |
| wbuf_iter += 2; |
| } |
| else |
| { |
| if ((wint_t) *wbuf_iter == c && !not_in) |
| break; |
| if ((wint_t) *wbuf_iter == c && not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| ended = 1; |
| break; |
| } |
| |
| ++wbuf_iter; |
| } |
| } |
| if (ended) |
| break; |
| |
| if (wbuf_iter == temp_wbuf_end && !not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| break; |
| } |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| *wstr++ = c; |
| |
| if ((flags & IS_ALLOC_USED) != 0 |
| && wstr == ((wchar_t *) *pstr + str_sz)) |
| { |
| new_sz = str_sz * 2; |
| while ((wstr = (wchar_t *) realloc (*pstr, |
| new_sz * sizeof (wchar_t))) == NULL |
| && new_sz > (size_t) (str_sz + 1)) |
| new_sz = str_sz + 1; |
| if (!wstr) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| ((wchar_t *) (*pstr))[str_sz - 1] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = (char *) wstr; |
| wstr += str_sz; |
| str_sz = new_sz; |
| } |
| } |
| } |
| while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF); |
| |
| if (read_in_sv == read_in) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| *wstr++ = 0; |
| |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (wstr - (wchar_t *) *pstr), sizeof (wchar_t)); |
| pstr = NULL; |
| ++rval; |
| } |
| } |
| else |
| { |
| read_in_sv = read_in; |
| |
| if ((c = in_ch (s, &read_in)) == WEOF) |
| return cleanup_return ((!rval ? WEOF : rval), &gcollect, pstr, &wbuf); |
| |
| memset (&state, 0, sizeof (state)); |
| |
| do |
| { |
| int ended = 0; |
| wbuf_iter = tmp_wbuf_ptr; |
| while (wbuf_iter < temp_wbuf_end) |
| { |
| if (wbuf_iter[0] == '-' && wbuf_iter[1] != 0 |
| && (wbuf_iter + 1) != temp_wbuf_end |
| && wbuf_iter != tmp_wbuf_ptr |
| && (unsigned int) wbuf_iter[-1] <= (unsigned int) wbuf_iter[1]) |
| { |
| for (wc = wbuf_iter[-1] + 1; wc <= wbuf_iter[1] && (wint_t) wc != c; ++wc); |
| |
| if (wc <= wbuf_iter[1] && !not_in) |
| break; |
| if (wc <= wbuf_iter[1] && not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| ended = 1; |
| break; |
| } |
| |
| wbuf_iter += 2; |
| } |
| else |
| { |
| if ((wint_t) *wbuf_iter == c && !not_in) |
| break; |
| if ((wint_t) *wbuf_iter == c && not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| ended = 1; |
| break; |
| } |
| |
| ++wbuf_iter; |
| } |
| } |
| |
| if (ended) |
| break; |
| if (wbuf_iter == temp_wbuf_end && !not_in) |
| { |
| back_ch (c, s, &read_in, 0); |
| break; |
| } |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| if ((flags & IS_ALLOC_USED) != 0 |
| && (str + MB_CUR_MAX) >= (*pstr + str_sz)) |
| { |
| new_sz = str_sz * 2; |
| str_len = (str - *pstr); |
| |
| while ((nstr = (char *) realloc (*pstr, new_sz)) == NULL |
| && new_sz > (str_len + MB_CUR_MAX)) |
| new_sz = str_len + MB_CUR_MAX; |
| if (!nstr) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| ((*pstr))[str_len] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = nstr; |
| str = nstr + str_len; |
| str_sz = new_sz; |
| } |
| } |
| |
| n = wcrtomb ((flags & IS_SUPPRESSED) == 0 ? str : NULL, c, &state); |
| if (n == (size_t) -1LL) |
| { |
| errno = EILSEQ; |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| |
| str += n; |
| } |
| while (--width > 0 && (c = in_ch (s, &read_in)) != WEOF); |
| |
| if (read_in_sv == read_in) |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| |
| if ((flags & IS_SUPPRESSED) == 0) |
| { |
| n = wcrtomb (buf, 0, &state); |
| if (n > 0 && (flags & IS_ALLOC_USED) != 0 |
| && (str + n) >= (*pstr + str_sz)) |
| { |
| str_len = (str - *pstr); |
| |
| if ((nstr = (char *) realloc (*pstr, str_len + n + 1)) == NULL) |
| { |
| if ((flags & USE_POSIX_ALLOC) == 0) |
| { |
| (*pstr)[str_len] = 0; |
| pstr = NULL; |
| ++rval; |
| } |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? WEOF : rval), &gcollect, pstr, &wbuf); |
| } |
| *pstr = nstr; |
| str = nstr + str_len; |
| str_sz = str_len + n + 1; |
| } |
| |
| if (n) |
| { |
| memcpy (str, buf, n); |
| str += n; |
| } |
| *str++ = 0; |
| |
| optimize_alloc ((flags & IS_ALLOC_USED) != 0, pstr, str_sz, (str - *pstr), sizeof (char)); |
| pstr = NULL; |
| ++rval; |
| } |
| } |
| break; |
| |
| default: |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| } |
| |
| if (ignore_ws) |
| { |
| while (iswspace ((c = in_ch (s, &read_in)))); |
| back_ch (c, s, &read_in, 0); |
| } |
| |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); |
| } |
| |
| int |
| __mingw_vfwscanf (FILE *s, const wchar_t *format, va_list argp) |
| { |
| _IFP ifp; |
| memset (&ifp, 0, sizeof (_IFP)); |
| ifp.fp = s; |
| return __mingw_swformat (&ifp, format, argp); |
| } |
| |
| int |
| __mingw_vswscanf (const wchar_t *s, const wchar_t *format, va_list argp) |
| { |
| _IFP ifp; |
| memset (&ifp, 0, sizeof (_IFP)); |
| ifp.str = s; |
| ifp.is_string = 1; |
| return __mingw_swformat (&ifp, format, argp); |
| } |
| |