diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-09-18 19:57:24 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-09-18 19:57:24 +0000 |
commit | 7913ba4d91b848ec4e5698c59d43198a3ef9215d (patch) | |
tree | afc73f6e0376ae6d07526c5efa9e941641ce1f6d /stdio-common/vfscanf.c | |
parent | cedf9b89dd3b436ff7fad4c75d3f288ee4cd4ecd (diff) | |
download | glibc-7913ba4d91b848ec4e5698c59d43198a3ef9215d.tar glibc-7913ba4d91b848ec4e5698c59d43198a3ef9215d.tar.gz glibc-7913ba4d91b848ec4e5698c59d43198a3ef9215d.tar.bz2 glibc-7913ba4d91b848ec4e5698c59d43198a3ef9215d.zip |
Updated to fedora-glibc-20070918T1931cvs/fedora-glibc-2_6_90-14
Diffstat (limited to 'stdio-common/vfscanf.c')
-rw-r--r-- | stdio-common/vfscanf.c | 350 |
1 files changed, 302 insertions, 48 deletions
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 9e6daced5d..e4728d00c9 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -60,12 +60,13 @@ #define NOSKIP 0x0020 /* do not skip blanks */ #define NUMBER_SIGNED 0x0040 /* signed integer */ #define GROUP 0x0080 /* ': group numbers */ -#define MALLOC 0x0100 /* a: malloc strings */ +#define GNU_MALLOC 0x0100 /* a: malloc strings */ #define CHAR 0x0200 /* hh: char */ #define I18N 0x0400 /* I: use locale's digits */ #define HEXA_FLOAT 0x0800 /* hexadecimal float */ #define READ_POINTER 0x1000 /* this is a pointer value */ - +#define POSIX_MALLOC 0x2000 /* m: malloc strings */ +#define MALLOC (GNU_MALLOC | POSIX_MALLOC) #include <locale/localeinfo.h> #include <libioP.h> @@ -146,6 +147,21 @@ if (done == 0) done = EOF; \ goto errout; \ } while (0) +#define add_ptr_to_free(ptr) \ + do \ + { \ + if (ptrs_to_free == NULL \ + || ptrs_to_free->count == (sizeof (ptrs_to_free->ptrs) \ + / sizeof (ptrs_to_free->ptrs[0]))) \ + { \ + struct ptrs_to_free *new_ptrs = alloca (sizeof (*ptrs_to_free)); \ + new_ptrs->count = 0; \ + new_ptrs->next = ptrs_to_free; \ + ptrs_to_free = new_ptrs; \ + } \ + ptrs_to_free->ptrs[ptrs_to_free->count++] = (ptr); \ + } \ + while (0) #define ARGCHECK(s, format) \ do \ { \ @@ -169,6 +185,12 @@ _IO_funlockfile (S); \ __libc_cleanup_region_end (0) +struct ptrs_to_free +{ + size_t count; + struct ptrs_to_free *next; + char **ptrs[32]; +}; /* Read formatted input from S according to the format string FORMAT, using the argument list in ARG. @@ -218,6 +240,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, #else const char *thousands; #endif + struct ptrs_to_free *ptrs_to_free = NULL; /* State for the conversions. */ mbstate_t state; /* Integral holding variables. */ @@ -491,9 +514,24 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, --f; break; } + /* In __isoc99_*scanf %as, %aS and %a[ extension is not + supported at all. */ + if (s->_flags2 & _IO_FLAGS2_SCANF_STD) + { + --f; + break; + } /* String conversions (%s, %[) take a `char **' arg and fill it in with a malloc'd pointer. */ - flags |= MALLOC; + flags |= GNU_MALLOC; + break; + case L_('m'): + flags |= POSIX_MALLOC; + if (*f == L_('l')) + { + ++f; + flags |= LONG; + } break; case L_('z'): if (need_longlong && sizeof (size_t) > sizeof (unsigned long int)) @@ -609,20 +647,46 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, case L_('c'): /* Match characters. */ if ((flags & LONG) == 0) { - if (!(flags & SUPPRESS)) - { - str = ARG (char *); - if (str == NULL) - conv_error (); - } + if (width == -1) + width = 1; + +#define STRING_ARG(Str, Type, Width) \ + do if (!(flags & SUPPRESS)) \ + { \ + if (flags & MALLOC) \ + { \ + /* The string is to be stored in a malloc'd buffer. */ \ + /* For %mS using char ** is actually wrong, but \ + shouldn't make a difference on any arch glibc \ + supports and would unnecessarily complicate \ + things. */ \ + strptr = ARG (char **); \ + if (strptr == NULL) \ + conv_error (); \ + /* Allocate an initial buffer. */ \ + strsize = Width; \ + *strptr = (char *) malloc (strsize * sizeof (Type)); \ + Str = (Type *) *strptr; \ + if (Str != NULL) \ + add_ptr_to_free (strptr); \ + else if (flags & POSIX_MALLOC) \ + goto reteof; \ + } \ + else \ + Str = ARG (Type *); \ + if (Str == NULL) \ + conv_error (); \ + } while (0) +#ifdef COMPILE_WSCANF + STRING_ARG (str, char, 100); +#else + STRING_ARG (str, char, (width > 1024 ? 1024 : width)); +#endif c = inchar (); if (__builtin_expect (c == EOF, 0)) input_error (); - if (width == -1) - width = 1; - #ifdef COMPILE_WSCANF /* We have to convert the wide character(s) into multibyte characters and store the result. */ @@ -632,6 +696,38 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { size_t n; + if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC) + && str + MB_CUR_MAX >= *strptr + strsize) + { + /* We have to enlarge the buffer if the `m' flag + was given. */ + size_t strleng = str - *strptr; + char *newstr; + + newstr = (char *) realloc (*strptr, strsize * 2); + if (newstr == NULL) + { + /* Can't allocate that much. Last-ditch effort. */ + newstr = (char *) realloc (*strptr, + strleng + MB_CUR_MAX); + if (newstr == NULL) + /* c can't have `a' flag, only `m'. */ + goto reteof; + else + { + *strptr = newstr; + str = newstr + strleng; + strsize = strleng + MB_CUR_MAX; + } + } + else + { + *strptr = newstr; + str = newstr + strleng; + strsize *= 2; + } + } + n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state); if (__builtin_expect (n == (size_t) -1, 0)) /* No valid wide character. */ @@ -646,7 +742,40 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (!(flags & SUPPRESS)) { do - *str++ = c; + { + if ((flags & MALLOC) + && (char *) str == *strptr + strsize) + { + /* Enlarge the buffer. */ + size_t newsize + = strsize + + (strsize >= width ? width - 1 : strsize); + + str = (char *) realloc (*strptr, newsize); + if (str == NULL) + { + /* Can't allocate that much. Last-ditch + effort. */ + str = (char *) realloc (*strptr, strsize + 1); + if (str == NULL) + /* c can't have `a' flag, only `m'. */ + goto reteof; + else + { + *strptr = (char *) str; + str += strsize; + ++strsize; + } + } + else + { + *strptr = (char *) str; + str += strsize; + strsize = newsize; + } + } + *str++ = c; + } while (--width > 0 && inchar () != EOF); } else @@ -654,18 +783,25 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, #endif if (!(flags & SUPPRESS)) - ++done; + { + if ((flags & MALLOC) && str - *strptr != strsize) + { + char *cp = (char *) realloc (*strptr, str - *strptr); + if (cp != NULL) + *strptr = cp; + } + strptr = NULL; + ++done; + } break; } /* FALLTHROUGH */ case L_('C'): - if (!(flags & SUPPRESS)) - { - wstr = ARG (wchar_t *); - if (wstr == NULL) - conv_error (); - } + if (width == -1) + width = 1; + + STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width)); c = inchar (); if (__builtin_expect (c == EOF, 0)) @@ -676,7 +812,40 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (!(flags & SUPPRESS)) { do - *wstr++ = c; + { + if ((flags & MALLOC) + && wstr == (wchar_t *) *strptr + strsize) + { + size_t newsize + = strsize + (strsize > width ? width - 1 : strsize); + /* Enlarge the buffer. */ + wstr = (wchar_t *) realloc (*strptr, + newsize * sizeof (wchar_t)); + if (wstr == NULL) + { + /* Can't allocate that much. Last-ditch effort. */ + wstr = (wchar_t *) realloc (*strptr, + (strsize + 1) + * sizeof (wchar_t)); + if (wstr == NULL) + /* C or lc can't have `a' flag, only `m' flag. */ + goto reteof; + else + { + *strptr = (char *) wstr; + wstr += strsize; + ++strsize; + } + } + else + { + *strptr = (char *) wstr; + wstr += strsize; + strsize = newsize; + } + } + *wstr++ = c; + } while (--width > 0 && inchar () != EOF); } else @@ -695,6 +864,38 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* This is what we present the mbrtowc function first. */ buf[0] = c; + if (!(flags & SUPPRESS) && (flags & MALLOC) + && wstr == (wchar_t *) *strptr + strsize) + { + size_t newsize + = strsize + (strsize > width ? width - 1 : strsize); + /* Enlarge the buffer. */ + wstr = (wchar_t *) realloc (*strptr, + newsize * sizeof (wchar_t)); + if (wstr == NULL) + { + /* Can't allocate that much. Last-ditch effort. */ + wstr = (wchar_t *) realloc (*strptr, + ((strsize + 1) + * sizeof (wchar_t))); + if (wstr == NULL) + /* C or lc can't have `a' flag, only `m' flag. */ + goto reteof; + else + { + *strptr = (char *) wstr; + wstr += strsize; + ++strsize; + } + } + else + { + *strptr = (char *) wstr; + wstr += strsize; + strsize = newsize; + } + } + while (1) { size_t n; @@ -728,33 +929,27 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, #endif if (!(flags & SUPPRESS)) - ++done; + { + if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize) + { + wchar_t *cp = (wchar_t *) realloc (*strptr, + ((wstr + - (wchar_t *) *strptr) + * sizeof (wchar_t))); + if (cp != NULL) + *strptr = (char *) cp; + } + strptr = NULL; + + ++done; + } break; case L_('s'): /* Read a string. */ if (!(flags & LONG)) { -#define STRING_ARG(Str, Type) \ - do if (!(flags & SUPPRESS)) \ - { \ - if (flags & MALLOC) \ - { \ - /* The string is to be stored in a malloc'd buffer. */ \ - strptr = ARG (char **); \ - if (strptr == NULL) \ - conv_error (); \ - /* Allocate an initial buffer. */ \ - strsize = 100; \ - *strptr = (char *) malloc (strsize * sizeof (Type)); \ - Str = (Type *) *strptr; \ - } \ - else \ - Str = ARG (Type *); \ - if (Str == NULL) \ - conv_error (); \ - } while (0) - STRING_ARG (str, char); + STRING_ARG (str, char, 100); c = inchar (); if (__builtin_expect (c == EOF, 0)) @@ -782,8 +977,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (!(flags & SUPPRESS) && (flags & MALLOC) && str + MB_CUR_MAX >= *strptr + strsize) { - /* We have to enlarge the buffer if the `a' flag - was given. */ + /* We have to enlarge the buffer if the `a' or `m' + flag was given. */ size_t strleng = str - *strptr; char *newstr; @@ -796,10 +991,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, strleng + MB_CUR_MAX); if (newstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -843,10 +1041,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, str = (char *) realloc (*strptr, strsize + 1); if (str == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strsize - 1] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -886,10 +1087,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, newstr = (char *) realloc (*strptr, strleng + n + 1); if (newstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -911,6 +1115,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (cp != NULL) *strptr = cp; } + strptr = NULL; ++done; } @@ -925,7 +1130,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, #endif /* Wide character string. */ - STRING_ARG (wstr, wchar_t); + STRING_ARG (wstr, wchar_t, 100); c = inchar (); if (__builtin_expect (c == EOF, 0)) @@ -958,16 +1163,19 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (wstr == NULL) { /* Can't allocate that much. Last-ditch - effort. */ + effort. */ wstr = (wchar_t *) realloc (*strptr, (strsize + 1) * sizeof (wchar_t)); if (wstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; + strptr = NULL; ++done; conv_error (); } @@ -1033,10 +1241,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, * sizeof (wchar_t))); if (wstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; + strptr = NULL; ++done; conv_error (); } @@ -1072,6 +1283,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (cp != NULL) *strptr = (char *) cp; } + strptr = NULL; ++done; } @@ -2069,9 +2281,9 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, case L_('['): /* Character class. */ if (flags & LONG) - STRING_ARG (wstr, wchar_t); + STRING_ARG (wstr, wchar_t, 100); else - STRING_ARG (str, char); + STRING_ARG (str, char, 100); if (*f == L_('^')) { @@ -2219,10 +2431,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, * sizeof (wchar_t)); if (wstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; + strptr = NULL; ++done; conv_error (); } @@ -2298,10 +2513,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, * sizeof (wchar_t))); if (wstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; + strptr = NULL; ++done; conv_error (); } @@ -2349,6 +2567,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (cp != NULL) *strptr = (char *) cp; } + strptr = NULL; ++done; } @@ -2435,10 +2654,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, strleng + MB_CUR_MAX); if (newstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -2497,10 +2719,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, newsize = strsize + 1; goto allocagain; } + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strsize - 1] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -2537,10 +2762,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, newstr = (char *) realloc (*strptr, strleng + n + 1); if (newstr == NULL) { + if (flags & POSIX_MALLOC) + goto reteof; /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; + strptr = NULL; ++done; conv_error (); } @@ -2562,6 +2790,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (cp != NULL) *strptr = cp; } + strptr = NULL; ++done; } @@ -2600,6 +2829,31 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (errp != NULL) *errp |= errval; + if (done == EOF) + { + reteof: + if (__builtin_expect (ptrs_to_free != NULL, 0)) + { + struct ptrs_to_free *p = ptrs_to_free; + while (p != NULL) + { + for (size_t cnt = 0; cnt < p->count; ++cnt) + { + free (*p->ptrs[cnt]); + *p->ptrs[cnt] = NULL; + } + p = p->next; + free (ptrs_to_free); + ptrs_to_free = p; + } + } + return EOF; + } + else if (__builtin_expect (strptr != NULL, 0)) + { + free (*strptr); + *strptr = NULL; + } return done; } |