From 77a58cad3fa0a286bd2581187a2463a762d711ba Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 5 Dec 1995 03:35:55 +0000 Subject: Tue Dec 5 02:27:32 1995 Ulrich Drepper * libio/Makefile [routines]: Remove iofscanf, add iopopen, pclose. * libio/iofscanf.c: Remove file. * libio/iogetdelim.c (_IO_getdelim): Correct stupid bug at string termination. * libio/iopopen.c: New file from GNU libio. * libio/memstream.c: Fixed bug in fclose handling. Instead of providing a close callback we need a finish callback. * libio/pclose.c: New file. Derived from popen.c in GNU libio. * posix/gnu/types.h: Fixed typo. * stdio-common/errnobug.c: fputs returns EOF in error case. Do not test for != 0. * stdio-common/printf-parse.h (parse_one_spec): Do not force padding with ' ' if precision is given. Fix by HJ Lu. * stdio-common/printf_fp.c: Fix comment. * stdio-common/tfformat.c, stdio-common/tiformat.c, stdio-common/tstdiomisc.c: New files from GNU libio test suite. * stdio-common/tstgetln.c: Provide ssize_t type when testing libio. * stdio-common/vfprintf.c (outchar): Use PUTC instead of putc. (vfprintf): Cleasr args_type array before using it. When printing 0 as an integer with precision 0 nothing must be written for the number. Based on patch by HJ Lu. * stdio-common/vfscanf.c: Remove fixed input buffer. Now we have a dynamically extended buffer. * stdlib/strtod.c: Merge with version in Linux libc. This fixes some bugs with handling of very small numbers and has different solution for formaer patches. * sysdeps/i386/i586/add_n.S, sysdeps/i386/i586/sub_n.S: Rename macros r1 and r2 to t1, and t2 resp. This is necessary because glibc headers also define r1. Tue Dec 5 02:27:32 1995 Ulrich Drepper * libio/Makefile [routines]: Remove iofscanf, add iopopen, pclose. * libio/iofscanf.c: Remove file. * libio/iogetdelim.c (_IO_getdelim): Correct stupid bug at string termination. * libio/iopopen.c: New file from GNU libio. * libio/memstream.c: Fixed bug in fclose handling. Instead of providing a close callback we need a finish callback. * libio/pclose.c: New file. Derived from popen.c in GNU libio. * posix/gnu/types.h: Fixed typo. * stdio-common/errnobug.c: fputs returns EOF in error case. Do not test for != 0. * stdio-common/printf-parse.h (parse_one_spec): Do not force padding with ' ' if precision is given. Fix by HJ Lu. * stdio-common/printf_fp.c: Fix comment. * stdio-common/tfformat.c, stdio-common/tiformat.c, stdio-common/tstdiomisc.c: New files from GNU libio test suite. * stdio-common/tstgetln.c: Provide ssize_t type when testing libio. * stdio-common/vfprintf.c (outchar): Use PUTC instead of putc. (vfprintf): Cleasr args_type array before using it. When printing 0 as an integer with precision 0 nothing must be written for the number. Based on patch by HJ Lu. * stdio-common/vfscanf.c: Remove fixed input buffer. Now we have a dynamically extended buffer. * stdlib/strtod.c: Merge with version in Linux libc. This fixes some bugs with handling of very small numbers and has different solution for formaer patches. * sysdeps/i386/i586/add_n.S, sysdeps/i386/i586/sub_n.S: Rename macros r1 and r2 to t1, and t2 resp. This is necessary because glibc headers also define r1. --- stdio-common/Makefile | 3 +- stdio-common/errnobug.c | 4 +- stdio-common/printf-parse.h | 8 +--- stdio-common/printf_fp.c | 2 +- stdio-common/tstgetln.c | 6 ++- stdio-common/vfprintf.c | 51 +++++++++++++++++------- stdio-common/vfscanf.c | 94 +++++++++++++++++++++++++++------------------ 7 files changed, 106 insertions(+), 62 deletions(-) (limited to 'stdio-common') diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 3afb555458..8ae8b48e1d 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -39,7 +39,8 @@ distribute := _itoa.h printf-parse.h tests := tst-printf tstscanf test_rdwr test-popen tstgetln test-fseek \ temptest tst-fileno test-fwrite \ xbug errnobug \ - bug1 bug2 bug3 bug4 bug5 bug6 bug7 + bug1 bug2 bug3 bug4 bug5 bug6 bug7 \ + tfformat tiformat tstdiomisc include ../Rules diff --git a/stdio-common/errnobug.c b/stdio-common/errnobug.c index cf17be30a2..d1122e4e9b 100644 --- a/stdio-common/errnobug.c +++ b/stdio-common/errnobug.c @@ -1,5 +1,5 @@ /* Regression test for reported old bug that errno is clobbered - by the first successful output to a stream on an unseekable object. + by the first successful output to a stream on an unseekable object. Copyright (C) 1995 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -43,7 +43,7 @@ main (void) } errno = 0; - if (fputs ("fnord", f)) + if (fputs ("fnord", f) == EOF) { perror ("fputs"); return 1; diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h index 0f6e9e287b..9abbdba187 100644 --- a/stdio-common/printf-parse.h +++ b/stdio-common/printf-parse.h @@ -32,7 +32,7 @@ Cambridge, MA 02139, USA. */ struct printf_spec { - /* Information parsed from the format spec. */ + /* Information parsed from the format spec. */ struct printf_info info; /* Pointers into the format string for the end of this format @@ -260,10 +260,6 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, else /* "%.?" is treated like "%.0?". */ spec->info.prec = 0; - - /* If there was a precision specified, ignore the 0 flag and always - pad with spaces. */ - spec->info.pad = ' '; } /* Check for type modifiers. */ @@ -364,7 +360,7 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, break; } - if (spec->data_arg == -1 && spec->ndata_args > 0) + if (spec->data_arg == -1 && spec->ndata_args > 0) { /* There are args consumed, but no positional spec. Use the next sequential arg position. */ diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c index 31c009e891..44f501f206 100644 --- a/stdio-common/printf_fp.c +++ b/stdio-common/printf_fp.c @@ -345,7 +345,7 @@ __printf_fp (fp, info, args) scalesize = 0; if (exponent > 2) { - /* |FP| >= 1.0. */ + /* |FP| >= 8.0. */ int scaleexpo = 0; int explog = LDBL_MAX_10_EXP_LOG; int exp10 = 0; diff --git a/stdio-common/tstgetln.c b/stdio-common/tstgetln.c index ea8ea817da..a35be272e9 100644 --- a/stdio-common/tstgetln.c +++ b/stdio-common/tstgetln.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1995 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -19,6 +19,10 @@ Cambridge, MA 02139, USA. */ #include #include +#ifdef USE_IN_LIBIO +# define ssize_t _IO_ssize_t +#endif + int DEFUN_VOID(main) { diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index c73661973a..08a488ce81 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -96,7 +96,7 @@ ssize_t __printf_pad __P ((FILE *, char pad, size_t n)); do \ { \ register const int outc = (x); \ - if (putc (outc, s) == EOF) \ + if (PUTC (outc, s) == EOF) \ return -1; \ else \ ++done; \ @@ -230,11 +230,12 @@ vfprintf (s, format, ap) /* Allocate memory for the argument descriptions. */ args_type = alloca (nargs * sizeof (int)); + memset (args_type, 0, nargs * sizeof (int)); args_value = alloca (nargs * sizeof (union printf_arg)); - /* XXX Could do sanity check here: - Initialize args_type elts to zero. - If any is still zero after this loop, format is invalid. */ + /* XXX Could do sanity check here: If any element in ARGS_TYPE is + still zero after this loop, format is invalid. For now we simply + use 0 as the value. */ /* Fill in the types of all the arguments. */ for (cnt = 0; cnt < nspecs; ++cnt) @@ -287,6 +288,8 @@ vfprintf (s, format, ap) default: if ((args_type[cnt] & PA_FLAG_PTR) != 0) args_value[cnt].pa_pointer = va_arg (ap, void *); + else + args_value[cnt].pa_long_double = 0.0; break; } @@ -420,15 +423,27 @@ vfprintf (s, format, ap) char *const workend = &work[sizeof(work) - 1]; register char *w; - /* Supply a default precision if none was given. */ if (specs[cnt].info.prec == -1) - specs[cnt].info.prec = 1; - - /* Put the number in WORK. */ - w = _itoa (num, workend + 1, base, specs[cnt].info.spec == 'X'); - w -= 1; - if (specs[cnt].info.group && grouping) - w = group_number (w, workend, grouping, thousands_sep); + /* Supply a default precision if none was given. */ + specs[cnt].info.prec = 1; + else + /* We have to take care for the '0' flag. If a + precision is given it must be ignored. */ + specs[cnt].info.pad = ' '; + + /* If the precision is 0 and the number is 0 nothing has + to be written for the number. */ + if (specs[cnt].info.prec == 0 && num == 0) + w = workend; + else + { + /* Put the number in WORK. */ + w = _itoa (num, workend + 1, base, + specs[cnt].info.spec == 'X'); + w -= 1; + if (specs[cnt].info.group && grouping) + w = group_number (w, workend, grouping, thousands_sep); + } specs[cnt].info.width -= workend - w; specs[cnt].info.prec -= workend - w; @@ -618,8 +633,18 @@ vfprintf (s, format, ap) } #ifdef USE_IN_LIBIO -#undef vfprintf +# undef vfprintf +# ifdef strong_alias +/* This is for glibc. */ strong_alias (_IO_vfprintf, vfprintf) +# else +# if defined __ELF__ || defined __GNU_LIBRARY__ +# include +# ifdef weak_alias +weak_alias (_IO_vfprintf, vfprintf); +# endif +# endif +# endif #endif diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index b0e48df4f8..76c9936abe 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -132,6 +132,8 @@ __vfscanf (FILE *s, const char *format, va_list argptr) int base; /* Signedness for integral numbers. */ int number_signed; + /* Decimal point character. */ + wchar_t decimal; /* Integral holding variables. */ union { @@ -144,9 +146,24 @@ __vfscanf (FILE *s, const char *format, va_list argptr) register char *str, **strptr; size_t strsize; /* Workspace. */ - char work[200]; - char *w; /* Pointer into WORK. */ - wchar_t decimal; /* Decimal point character. */ + char *tw; /* Temporary pointer. */ + char *wp = NULL; /* Workspace. */ + size_t wpsize = 0; /* Currently used bytes in workspace. */ + size_t wpmax = 0; /* Maximal size of workspace. */ +#define ADDW(Ch) \ + do \ + { \ + if (wpsize == wpmax) \ + { \ + char *old = wp; \ + wpmax = 200 > 2 * wpmax ? 200 : 2 * wpmax; \ + wp = (char *) alloca (wpmax); \ + if (wpsize > 0) \ + memcpy (wp, old, wpsize); \ + } \ + wp[wpsize++] = (Ch); \ + } \ + while (0) ARGCHECK (s, format); @@ -338,7 +355,6 @@ __vfscanf (FILE *s, const char *format, va_list argptr) conv_error (); /* Find the conversion specifier. */ - w = work; fc = *f++; if (fc != '[' && fc != 'c' && fc != 'n') /* Eat whitespace. */ @@ -490,7 +506,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) /* Check for a sign. */ if (c == '-' || c == '+') { - *w++ = c; + ADDW (c); if (width > 0) --width; (void) inchar (); @@ -501,7 +517,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) { if (width > 0) --width; - *w++ = '0'; + ADDW ('0'); (void) inchar (); @@ -523,40 +539,40 @@ __vfscanf (FILE *s, const char *format, va_list argptr) if (base == 0) base = 10; - /* Read the number into WORK. */ + /* Read the number into workspace. */ do { if (base == 16 ? !isxdigit (c) : (!isdigit (c) || c - '0' >= base)) break; - *w++ = c; + ADDW (c); if (width > 0) --width; } while (inchar () != EOF && width != 0); - if (w == work || - (w - work == 1 && (work[0] == '+' || work[0] == '-'))) + if (wpsize == 0 || + (wpsize == 1 && (wp[0] == '+' || wp[0] == '-'))) /* There was no number. */ conv_error (); /* Convert the number. */ - *w = '\0'; + ADDW ('\0'); if (is_longlong) { if (number_signed) - num.q = __strtoq_internal (work, &w, base, group_flag); + num.q = __strtoq_internal (wp, &tw, base, group_flag); else - num.uq = __strtouq_internal (work, &w, base, group_flag); + num.uq = __strtouq_internal (wp, &tw, base, group_flag); } else { if (number_signed) - num.l = __strtol_internal (work, &w, base, group_flag); + num.l = __strtol_internal (wp, &tw, base, group_flag); else - num.ul = __strtoul_internal (work, &w, base, group_flag); + num.ul = __strtoul_internal (wp, &tw, base, group_flag); } - if (w == work) + if (wp == tw) conv_error (); if (do_assign) @@ -599,7 +615,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) /* Check for a sign. */ if (c == '-' || c == '+') { - *w++ = c; + ADDW (c); if (inchar () == EOF) /* EOF is only an input error before we read any chars. */ conv_error (); @@ -611,17 +627,18 @@ __vfscanf (FILE *s, const char *format, va_list argptr) do { if (isdigit (c)) - *w++ = c; - else if (got_e && w[-1] == 'e' && (c == '-' || c == '+')) - *w++ = c; + ADDW (c); + else if (got_e && wp[wpsize - 1] == 'e' + && (c == '-' || c == '+')) + ADDW (c); else if (!got_e && tolower (c) == 'e') { - *w++ = 'e'; + ADDW ('e'); got_e = got_dot = 1; } else if (c == decimal && !got_dot) { - *w++ = c; + ADDW (c); got_dot = 1; } else @@ -630,33 +647,34 @@ __vfscanf (FILE *s, const char *format, va_list argptr) --width; } while (inchar () != EOF && width != 0); - if (w == work) + if (wpsize == 0) conv_error(); - if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e') + if (wp[wpsize - 1] == '-' || wp[wpsize - 1] == '+' + || wp[wpsize - 1] == 'e') conv_error (); /* Convert the number. */ - *w = '\0'; + ADDW ('\0'); if (is_long_double) { - long double d = __strtold_internal (work, &w, group_flag); - if (do_assign && w != work) + long double d = __strtold_internal (wp, &tw, group_flag); + if (do_assign && tw != wp) *ARG (long double *) = d; } else if (is_long) { - double d = __strtod_internal (work, &w, group_flag); - if (do_assign && w != work) + double d = __strtod_internal (wp, &tw, group_flag); + if (do_assign && tw != wp) *ARG (double *) = d; } else { - float d = __strtof_internal (work, &w, group_flag); - if (do_assign && w != work) + float d = __strtof_internal (wp, &tw, group_flag); + if (do_assign && tw != wp) *ARG (float *) = d; } - if (w == work) + if (tw == wp) conv_error (); if (do_assign) @@ -680,23 +698,23 @@ __vfscanf (FILE *s, const char *format, va_list argptr) while ((fc = *f++) != '\0' && fc != ']') { if (fc == '-' && *f != '\0' && *f != ']' && - w > work && w[-1] <= *f) + wpsize > 0 && wp[wpsize - 1] <= *f) /* Add all characters from the one before the '-' up to (but not including) the next format char. */ - for (fc = w[-1] + 1; fc < *f; ++fc) - *w++ = fc; + for (fc = wp[wpsize - 1] + 1; fc < *f; ++fc) + ADDW (fc); else /* Add the character to the list. */ - *w++ = fc; + ADDW (fc); } if (fc == '\0') conv_error(); - *w = '\0'; + ADDW ('\0'); num.ul = read_in; do { - if ((strchr (work, c) == NULL) != not_in) + if ((strchr (wp, c) == NULL) != not_in) break; STRING_ADD_CHAR (c); if (width > 0) -- cgit 1.4.1