| /* | |
| 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. | |
| */ | |
| #define __LARGE_MBSTATE_T | |
| #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> | |
| #include "mingw_sformat.h" | |
| /* 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) | |
| 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 (char **p, char *end, size_t alloc_sz) | |
| { | |
| size_t need_sz; | |
| char *h; | |
| if (!p || !*p) | |
| return; | |
| need_sz = end - *p; | |
| if (need_sz == alloc_sz) | |
| return; | |
| if ((h = (char *) realloc (*p, need_sz)) != NULL) | |
| *p = h; | |
| } | |
| static void | |
| back_ch (int c, _IFP *s, size_t *rin, int not_eof) | |
| { | |
| if (!not_eof && c == EOF) | |
| return; | |
| if (s->is_string == 0) | |
| { | |
| FILE *fp = s->fp; | |
| ungetc (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 EOF; | |
| } | |
| else if (s->is_string) | |
| { | |
| const char *ps = s->str; | |
| r = ((int) *ps) & 0xff; | |
| ps++; | |
| if (r != 0) | |
| { | |
| rin[0] += 1; | |
| s->str = ps; | |
| return r; | |
| } | |
| s->seen_eof = 1; | |
| return EOF; | |
| } | |
| else | |
| { | |
| FILE *fp = (FILE *) s->fp; | |
| r = getc (fp); | |
| if (r != EOF) | |
| rin[0] += 1; | |
| else s->seen_eof = 1; | |
| } | |
| return r; | |
| } | |
| static int | |
| match_string (_IFP *s, size_t *rin, int *c, const char *str) | |
| { | |
| int ch = *c; | |
| if (*str == 0) | |
| return 1; | |
| if (*str != (char) tolower (ch)) | |
| return 0; | |
| ++str; | |
| while (*str != 0) | |
| { | |
| if ((ch = in_ch (s, rin)) == EOF) | |
| { | |
| c[0] = ch; | |
| return 0; | |
| } | |
| if (*str != (char) tolower (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, char **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, char **wbuf) | |
| { | |
| if (rval == EOF) | |
| 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 char * | |
| resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, char *old) | |
| { | |
| char *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 = (char *) malloc (nsz); | |
| else | |
| wbuf = (char *) realloc (old, nsz); | |
| if (!wbuf) | |
| { | |
| if (old) | |
| free (old); | |
| } | |
| else | |
| *wbuf_max_sz = nsz; | |
| return wbuf; | |
| } | |
| int | |
| __cdecl | |
| __mingw_sformat (_IFP *s, const char *format, va_list argp) | |
| { | |
| const char *f = format; | |
| struct gcollect *gcollect = NULL; | |
| size_t read_in = 0, wbuf_max_sz = 0, cnt; | |
| ssize_t str_sz = 0; | |
| char *str = NULL, **pstr = NULL, *wbuf = NULL; | |
| wchar_t *wstr = NULL; | |
| int rval = 0, c = 0, ignore_ws = 0; | |
| va_list arg; | |
| unsigned char fc; | |
| unsigned int npos; | |
| int width, flags, base = 0, errno_sv; | |
| size_t wbuf_cur_sz, read_in_sv, new_sz, n; | |
| char seen_dot, seen_exp, is_neg, not_in; | |
| char *tmp_wbuf_ptr, buf[MB_LEN_MAX]; | |
| const char *lc_decimal_point, *lc_thousands_sep; | |
| mbstate_t state = {0}, cstate; | |
| 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 EOF; | |
| } | |
| lc_decimal_point = localeconv()->decimal_point; | |
| lc_thousands_sep = localeconv()->thousands_sep; | |
| if (lc_thousands_sep != NULL && *lc_thousands_sep == 0) | |
| lc_thousands_sep = NULL; | |
| while (*f != 0) | |
| { | |
| if (!isascii ((unsigned char) *f)) | |
| { | |
| int len; | |
| if ((len = mbrlen (f, strlen (f), &state)) > 0) | |
| { | |
| do | |
| { | |
| if ((c = in_ch (s, &read_in)) == EOF || c != (unsigned char) *f++) | |
| { | |
| back_ch (c, s, &read_in, 1); | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| } | |
| } | |
| while (--len > 0); | |
| continue; | |
| } | |
| } | |
| fc = *f++; | |
| if (fc != '%') | |
| { | |
| if (isspace (fc)) | |
| ignore_ws = 1; | |
| else | |
| { | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| if (ignore_ws) | |
| { | |
| ignore_ws = 0; | |
| if (isspace (c)) | |
| { | |
| do | |
| { | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| } | |
| while (isspace (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 (isdigit ((unsigned char) *f)) | |
| { | |
| const char *svf = f; | |
| npos = (unsigned char) *f++ - '0'; | |
| while (isdigit ((unsigned char) *f)) | |
| npos = npos * 10 + ((unsigned char) *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 (isdigit ((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 == EOF || (c = in_ch (s, &read_in)) == EOF) | |
| && errno == EINTR) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| } | |
| while (isspace (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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : 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 = (width > 1024 ? 1024 : width); | |
| if ((str = *pstr = (char *) malloc (str_sz)) == NULL) | |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : 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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| do | |
| { | |
| if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz)) | |
| { | |
| new_sz = str_sz + (str_sz >= width ? width - 1 : str_sz); | |
| while ((str = (char *) realloc (*pstr, new_sz)) == NULL | |
| && new_sz > (size_t) (str_sz + 1)) | |
| new_sz = str_sz + 1; | |
| if (!str) | |
| { | |
| release_ptrs (&gcollect, &wbuf); | |
| return EOF; | |
| } | |
| *pstr = str; | |
| str += str_sz; | |
| str_sz = new_sz; | |
| } | |
| *str++ = c; | |
| } | |
| while (--width > 0 && (c = in_ch (s, &read_in)) != EOF); | |
| } | |
| else | |
| while (--width > 0 && (c = in_ch (s, &read_in)) != EOF); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| optimize_alloc (pstr, str, str_sz); | |
| 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 ? EOF : 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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| cstate = (mbstate_t){0}; | |
| do | |
| { | |
| buf[0] = c; | |
| if ((flags & IS_SUPPRESSED) == 0 && (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 EOF; | |
| } | |
| *pstr = (char *) wstr; | |
| wstr += str_sz; | |
| str_sz = new_sz; | |
| } | |
| while (1) | |
| { | |
| n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate); | |
| if (n == (size_t) -2) | |
| { | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| { | |
| errno = EILSEQ; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| buf[0] = c; | |
| continue; | |
| } | |
| if (n != 1) | |
| { | |
| errno = EILSEQ; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| break; | |
| } | |
| ++wstr; | |
| } | |
| while (--width > 0 && (c = in_ch (s, &read_in)) != EOF); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| optimize_alloc (pstr, (char *) wstr, str_sz * 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 ? EOF : 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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| do | |
| { | |
| if (isspace (c)) | |
| { | |
| back_ch (c, s, &read_in, 1); | |
| break; | |
| } | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *str++ = c; | |
| if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz)) | |
| { | |
| new_sz = str_sz * 2; | |
| while ((str = (char *) realloc (*pstr, new_sz)) == NULL | |
| && new_sz > (size_t) (str_sz + 1)) | |
| new_sz = str_sz + 1; | |
| if (!str) | |
| { | |
| if ((flags & USE_POSIX_ALLOC) == 0) | |
| { | |
| (*pstr)[str_sz - 1] = 0; | |
| pstr = NULL; | |
| ++rval; | |
| } | |
| return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf); | |
| } | |
| *pstr = str; | |
| str += str_sz; | |
| str_sz = new_sz; | |
| } | |
| } | |
| } | |
| while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *str++ = 0; | |
| optimize_alloc (pstr, str, str_sz); | |
| 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 ? EOF : 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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| cstate = (mbstate_t){0}; | |
| do | |
| { | |
| if (isspace (c)) | |
| { | |
| back_ch (c, s, &read_in, 1); | |
| break; | |
| } | |
| buf[0] = c; | |
| while (1) | |
| { | |
| n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate); | |
| if (n == (size_t) -2) | |
| { | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| { | |
| errno = EILSEQ; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| buf[0] = c; | |
| continue; | |
| } | |
| if (n != 1) | |
| { | |
| errno = EILSEQ; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| ++wstr; | |
| break; | |
| } | |
| if ((flags & IS_SUPPRESSED) == 0 && (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 ? EOF : 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)) != EOF); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *wstr++ = 0; | |
| optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t)); | |
| pstr = NULL; | |
| ++rval; | |
| } | |
| break; | |
| case 'd': case 'i': | |
| case 'o': case 'p': | |
| case 'u': | |
| case 'x': case 'X': | |
| case 'b': case 'B': | |
| 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; | |
| case 'b': case 'B': | |
| base = 2; | |
| break; | |
| } | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| return cleanup_return ((!rval ? EOF : 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 && tolower (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 != EOF && width != 0) | |
| { | |
| if (base == 16) | |
| { | |
| if (!isxdigit (c)) | |
| break; | |
| } | |
| else if (!isdigit (c) || (int) (c - '0') >= base) | |
| { | |
| const char *p = lc_thousands_sep; | |
| int remain; | |
| if (base != 10 || (flags & USE_GROUP) == 0) | |
| break; | |
| remain = width > 0 ? width : INT_MAX; | |
| while ((unsigned char) *p == c && remain >= 0) | |
| { | |
| /* As our conversion routines aren't supporting thousands | |
| separators, we are filtering them here. */ | |
| ++p; | |
| if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF) | |
| break; | |
| --remain; | |
| } | |
| if (*p != 0) | |
| { | |
| if (p > lc_thousands_sep) | |
| { | |
| back_ch (c, s, &read_in, 0); | |
| while (--p > lc_thousands_sep) | |
| back_ch ((unsigned char) *p, s, &read_in, 1); | |
| c = (unsigned char) *p; | |
| } | |
| break; | |
| } | |
| if (width > 0) | |
| width = remain; | |
| --wbuf_cur_sz; | |
| } | |
| 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, "(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)) | |
| { | |
| if (flags & IS_SIGNED_NUM) | |
| cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); | |
| else | |
| cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base); | |
| } | |
| else | |
| { | |
| if (flags & IS_SIGNED_NUM) | |
| cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/); | |
| else | |
| cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base); | |
| } | |
| 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)) == EOF) | |
| return cleanup_return ((!rval ? EOF : 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)) == EOF) | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| if (width > 0) | |
| --width; | |
| } | |
| if (tolower (c) == 'n') | |
| { | |
| const char *match_txt = "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)) == EOF || tolower (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 (tolower (c) == 'i') | |
| { | |
| const char *match_txt = "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)) == EOF || tolower (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)) != EOF && tolower (c) == 'i') | |
| { | |
| match_txt = "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)) == EOF || tolower (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 != EOF) | |
| 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 && tolower (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 (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c)) | |
| || (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 && (char) tolower (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 | |
| { | |
| const char *p = lc_decimal_point; | |
| int remain = width > 0 ? width : INT_MAX; | |
| if (! seen_dot) | |
| { | |
| while ((unsigned char) *p == c && remain >= 0) | |
| { | |
| ++p; | |
| if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF) | |
| break; | |
| --remain; | |
| } | |
| } | |
| if (*p == 0) | |
| { | |
| for (p = lc_decimal_point; *p != 0; ++p) | |
| { | |
| wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf); | |
| wbuf[wbuf_cur_sz++] = (unsigned char) *p; | |
| } | |
| if (width > 0) | |
| width = remain; | |
| seen_dot = 1; | |
| } | |
| else | |
| { | |
| const char *pp = lc_thousands_sep; | |
| if (!seen_dot && (flags & USE_GROUP) != 0) | |
| { | |
| while ((pp - lc_thousands_sep) < (p - lc_decimal_point) | |
| && *pp == lc_decimal_point[(pp - lc_thousands_sep)]) | |
| ++pp; | |
| if ((pp - lc_thousands_sep) == (p - lc_decimal_point)) | |
| { | |
| while ((unsigned char) *pp == c && remain >= 0) | |
| { | |
| ++pp; | |
| if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF) | |
| break; | |
| --remain; | |
| } | |
| } | |
| } | |
| if (pp != NULL && *pp == 0) | |
| { | |
| /* As our conversion routines aren't supporting thousands | |
| separators, we are filtering them here. */ | |
| if (width > 0) | |
| width = remain; | |
| } | |
| else | |
| { | |
| back_ch (c, s, &read_in, 0); | |
| break; | |
| } | |
| } | |
| } | |
| if (width == 0 || (c = in_ch (s, &read_in)) == EOF) | |
| break; | |
| if (width > 0) | |
| --width; | |
| } | |
| if (!wbuf_cur_sz || ((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 ld; | |
| ld = __mingw_strtold (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 ? -ld : ld; | |
| } | |
| else if ((flags & IS_L) != 0) | |
| { | |
| double d; | |
| d = (double) __mingw_strtold (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_strtof (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 ? EOF : 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 ? EOF : 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; | |
| if (wbuf_max_sz < 256) | |
| { | |
| wbuf_max_sz = 256; | |
| if (wbuf) | |
| free (wbuf); | |
| wbuf = (char *) malloc (wbuf_max_sz); | |
| } | |
| memset (wbuf, 0, 256); | |
| fc = *f; | |
| if (fc == ']' || fc == '-') | |
| { | |
| wbuf[fc] = 1; | |
| ++f; | |
| } | |
| while ((fc = *f++) != 0 && fc != ']') | |
| { | |
| if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f) | |
| { | |
| for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc) | |
| wbuf[fc] = 1; | |
| } | |
| else | |
| wbuf[fc] = 1; | |
| } | |
| if (!fc) | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| if ((flags & IS_L) != 0) | |
| { | |
| read_in_sv = read_in; | |
| cnt = 0; | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| cstate = (mbstate_t){0}; | |
| do | |
| { | |
| if (wbuf[c] == not_in) | |
| { | |
| back_ch (c, s, &read_in, 1); | |
| break; | |
| } | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| buf[0] = c; | |
| n = mbrtowc (wstr, buf, 1, &cstate); | |
| if (n == (size_t) -2) | |
| { | |
| ++cnt; | |
| continue; | |
| } | |
| cnt = 0; | |
| ++wstr; | |
| 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; | |
| } | |
| else | |
| rval = EOF; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| *pstr = (char *) wstr; | |
| wstr += str_sz; | |
| str_sz = new_sz; | |
| } | |
| } | |
| if (--width <= 0) | |
| break; | |
| } | |
| while ((c = in_ch (s, &read_in)) != EOF); | |
| if (cnt != 0) | |
| { | |
| errno = EILSEQ; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| if (read_in_sv == read_in) | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *wstr++ = 0; | |
| optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t)); | |
| pstr = NULL; | |
| ++rval; | |
| } | |
| } | |
| else | |
| { | |
| read_in_sv = read_in; | |
| if ((c = in_ch (s, &read_in)) == EOF) | |
| return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf); | |
| do | |
| { | |
| if (wbuf[c] == not_in) | |
| { | |
| back_ch (c, s, &read_in, 1); | |
| break; | |
| } | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *str++ = c; | |
| if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz)) | |
| { | |
| new_sz = str_sz * 2; | |
| while ((str = (char *) realloc (*pstr, new_sz)) == NULL | |
| && new_sz > (size_t) (str_sz + 1)) | |
| new_sz = str_sz + 1; | |
| if (!str) | |
| { | |
| if ((flags & USE_POSIX_ALLOC) == 0) | |
| { | |
| (*pstr)[str_sz - 1] = 0; | |
| pstr = NULL; | |
| ++rval; | |
| } | |
| else | |
| rval = EOF; | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| *pstr = str; | |
| str += str_sz; | |
| str_sz = new_sz; | |
| } | |
| } | |
| } | |
| while (--width > 0 && (c = in_ch (s, &read_in)) != EOF); | |
| if (read_in_sv == read_in) | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| if ((flags & IS_SUPPRESSED) == 0) | |
| { | |
| *str++ = 0; | |
| optimize_alloc (pstr, str, str_sz); | |
| pstr = NULL; | |
| ++rval; | |
| } | |
| } | |
| break; | |
| default: | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } | |
| } | |
| if (ignore_ws) | |
| { | |
| while (isspace ((c = in_ch (s, &read_in)))); | |
| back_ch (c, s, &read_in, 0); | |
| } | |
| return cleanup_return (rval, &gcollect, pstr, &wbuf); | |
| } |