[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [MiNT] Gcc 3.3.6 v 4.0.1
Done, thanks Vincent !
Alan.
On Fri, 2009-03-06 at 01:01 +0100, Vincent Rivière wrote:
> So here is my patch for the file obstream.c in the MiNTLib. The previous
> code was totally broken. Hopefully that file is independant to the remaining
> of the MiNTLib. So this patch is not going to break anything. I added a
> testcase, called test-obstack, which checks for common scenarios. Everything
> seems to be OK now.
>
> This patch fixes the t-printf testcase in the GMP library. Remember, it was
> the main goal. Now all the GMP test cases passes ! It uses very intensive
> mathematical functions, so our platform is pretty reliable :-)
>
> Note that the test-printf testcase in the MiNTLib currently fails, it is
> absolutely not related to this patch.
>
> Some background information:
>
> Obstacks are memory pools. They are part of glibc.
> http://www.gnu.org/software/libc/manual/html_node/Obstacks.html
>
> The function obstack_printf() is similar to fprintf, except it prints into
> an obstack growing object.
> http://www.gnu.org/software/libc/manual/html_node/Dynamic-Output.html
>
> The function open_obstack_stream() allows to write to an obstack growing
> object through a FILE interface (fwrite, fprintf...)
> http://www.gnu.org/software/libc/manual/html_node/Obstack-Streams.html
> This function is still documented, but I have not been able to find it,
> either in the glibc sources neither in my Linux boxes.
>
> Please apply and commit this patch !
>
> plain text document attachment (obstream.patch)
> diff -aurN mintlib-CVS-20090305/stdio/Makefile mintlib-CVS-20090305-obstream/stdio/Makefile
> --- mintlib-CVS-20090305/stdio/Makefile 2009-03-05 22:50:13.890500000 +0100
> +++ mintlib-CVS-20090305-obstream/stdio/Makefile 2009-03-01 23:23:04.000000000 +0100
> @@ -31,7 +31,7 @@
>
> TESTS = bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 \
> doprnt errnobug ferror fformat fileno fseek fwrite getln glue iformat \
> -llformat popen printf printfsz rdwr scanf scanf1 scanf2 \
> +llformat obstream popen printf printfsz rdwr scanf scanf1 scanf2 \
> scanf3 scanf4 scanf5 scanf6 scanf7 scanf8 scanf9 scanf10 scanf11 scanf12 \
> stdiomisc temp tmpfile tmpnam ungetc wc-printf xbug
>
> diff -aurN mintlib-CVS-20090305/stdio/obstream.c mintlib-CVS-20090305-obstream/stdio/obstream.c
> --- mintlib-CVS-20090305/stdio/obstream.c 2009-03-05 22:50:13.890500000 +0100
> +++ mintlib-CVS-20090305-obstream/stdio/obstream.c 2009-03-05 22:31:14.000000000 +0100
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1992, 1996, 1997 Free Software Foundation, Inc.
> +/* Copyright (C) 1992, 1996, 1997, 2009 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
> @@ -20,60 +20,64 @@
> #include <obstack.h>
> #include <stdarg.h>
> #include <string.h>
> +#include <stdlib.h>
>
> /* Output-room function for obstack streams. */
>
> static void
> grow (FILE *stream, int c)
> {
> - struct obstack *const obstack = (struct obstack *) stream->__cookie;
> + struct obstack *obstack = (struct obstack *) stream->__cookie;
> + int size_written = (int)(stream->__target + stream->__bufp - stream->__buffer);
>
> - /* Move the end of the object back to include only the portion
> - of the buffer which the user has already written into. */
> - obstack_blank_fast (obstack, - (stream->__put_limit - stream->__bufp));
> -
> - if ((size_t) stream->__target > obstack_object_size (obstack))
> - {
> - /* Our target (where the buffer maps to) is always zero except when
> - the user just did a SEEK_END fseek. If he sought within the
> - buffer, we need do nothing and will zero the target below. If he
> - sought past the end of the object, grow and zero-fill the object
> - up to the target address. */
> -
> - obstack_blank (obstack,
> - stream->__target - obstack_object_size (obstack));
> - /* fseek has just flushed us, so the put limit points
> - to the end of the written data. */
> - bzero (stream->__put_limit,
> - stream->__target - stream->__bufsize);
> + /* Check if the buffer has been flushed by fseek(). */
> + if (stream->__target != -1 && stream->__target > 0)
> + {
> + /* Restore the stream pointers to match the object. */
> + stream->__buffer = obstack_base (obstack);
> + stream->__bufsize = obstack_object_size (obstack);
> + stream->__bufp = stream->__buffer + stream->__target;
> + stream->__get_limit = stream->__bufp;
> + stream->__put_limit = stream->__buffer + stream->__bufsize;
> + stream->__target = 0;
> }
>
> - if (c != EOF)
> - obstack_1grow (obstack, (unsigned char) c);
> -
> /* The stream buffer always maps exactly to the object on the top
> of the obstack. The start of the buffer is the start of the object.
> The put limit points just past the end of the object. On fflush, the
> obstack is sync'd so the end of the object points just past the last
> character written to the stream. */
> -
> - stream->__target = stream->__offset = 0;
> - stream->__buffer = obstack_base (obstack);
> - stream->__bufsize = obstack_room (obstack);
> - stream->__bufp = obstack_next_free (obstack);
> - stream->__get_limit = stream->__bufp;
> -
> if (c == EOF)
> - /* This is fflush. Make the stream buffer, the object,
> - and the characters actually written all match. */
> - stream->__put_limit = stream->__get_limit;
> - else
> {
> - /* Extend the buffer (and the object) to include
> - the rest of the obstack chunk (which is uninitialized).
> - Data past bufp is undefined. */
> + /* This is fflush. The object must be shrinked to keep only the portion
> + of the buffer which the user has already written into. */
> + obstack_blank_fast (obstack, -(obstack_object_size (obstack) - size_written));
> +
> + /* Adjust the stream pointers. */
> + stream->__bufsize = obstack_object_size (obstack);
> stream->__put_limit = stream->__buffer + stream->__bufsize;
> - obstack_blank_fast (obstack, stream->__put_limit - stream->__bufp);
> + }
> + else if (size_written == obstack_object_size (obstack))
> + {
> + /* The buffer is full. Appending a byte to the object
> + may cause the allocation of a new chunk. */
> + obstack_1grow (obstack, (unsigned char) c);
> + ++size_written;
> +
> + /* Increase the object size to the size of the new chunk. */
> + obstack_blank_fast (obstack, obstack_room (obstack));
> +
> + /* Relocate the stream pointers. */
> + stream->__buffer = obstack_base (obstack);
> + stream->__bufsize = obstack_object_size (obstack);
> + stream->__bufp = stream->__buffer + size_written;
> + stream->__get_limit = stream->__bufp;
> + stream->__put_limit = stream->__buffer + stream->__bufsize;
> + }
> + else
> + {
> + /* The user called fseek() backwards, so there is room in the buffer. */
> + *stream->__bufp++ = (unsigned char)c;
> }
> }
>
> @@ -83,56 +87,51 @@
> static int
> seek (void *cookie, fpos_t *pos, int whence)
> {
> + struct obstack *obstack = (struct obstack *) cookie;
> + fpos_t current_offset = obstack_object_size (obstack); /* Stream has just been flushed. */
> + fpos_t target_offset;
> + ptrdiff_t delta;
> +
> switch (whence)
> {
> case SEEK_SET:
> + target_offset = *pos;
> + break;
> +
> case SEEK_CUR:
> - return 0;
> + target_offset = current_offset + *pos;
> + break;
>
> case SEEK_END:
> - /* Return the position relative to the end of the object.
> - fseek has just flushed us, so the obstack is consistent. */
> - *pos += obstack_object_size ((struct obstack *) cookie);
> - return 0;
> + target_offset = current_offset - *pos;
> + break;
>
> default:
> __libc_fatal ("obstream::seek called with bogus WHENCE\n");
> return -1;
> }
> -}
> -
> -/* Input room function for obstack streams.
> - Only what has been written to the stream can be read back. */
> -
> -static int
> -input (FILE *stream)
> -{
> - /* Re-sync with the obstack, growing the object if necessary. */
> - grow (stream, EOF);
>
> - if (stream->__bufp < stream->__get_limit)
> - return (unsigned char) *stream->__bufp++;
> + /* Resize the buffer. */
> + delta = target_offset - current_offset;
> + if (delta > 0)
> + {
> + obstack_blank (obstack, delta);
> + bzero (obstack_base (obstack) + current_offset, delta);
> + }
>
> - stream->__eof = 1;
> - return EOF;
> + return 0;
> }
> -
> +
> /* Initialize STREAM to talk to OBSTACK. */
>
> static void
> init_obstream (FILE *stream, struct obstack *obstack)
> {
> - (void) obstack;
> + int initial_object_size;
>
> + stream->__cookie = obstack;
> stream->__magic = _IOMAGIC;
> stream->__mode.__write = 1;
> - stream->__mode.__read = 1;
> -
> - /* Input can read only what has been written. */
> - stream->__room_funcs.__input = input;
> -
> - /* Do nothing for close. */
> - stream->__io_funcs.__close = NULL;
>
> /* When the buffer is full, grow the obstack. */
> stream->__room_funcs.__output = grow;
> @@ -141,20 +140,26 @@
> stream->__io_funcs.__seek = seek;
> stream->__target = stream->__offset = 0;
>
> + /* Increase the size of the current object to the size of the chunk. */
> + initial_object_size = obstack_object_size (obstack);
> + obstack_blank_fast (obstack, obstack_room (obstack));
> +
> + /* The initial buffer is the current growing object. */
> + stream->__buffer = obstack_base (obstack);
> + stream->__bufsize = obstack_object_size (obstack);
> + stream->__bufp = stream->__buffer + initial_object_size;
> + stream->__get_limit = stream->__bufp;
> + stream->__put_limit = stream->__buffer + stream->__bufsize;
> stream->__seen = 1;
>
> /* Don't deallocate that buffer! */
> stream->__userbuf = 1;
> -
> - /* We don't have to initialize the buffer.
> - The first read attempt will call grow, which will do all the work. */
> }
>
> FILE *
> -open_obstack_stream (obstack)
> - struct obstack *obstack;
> +open_obstack_stream (struct obstack *obstack)
> {
> - register FILE *stream;
> + FILE *stream;
>
> stream = __newstream ();
> if (stream == NULL)
> @@ -165,15 +170,18 @@
> }
>
> int
> -obstack_vprintf (obstack, format, args)
> - struct obstack *obstack;
> - const char *format;
> - va_list args;
> +obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
> {
> + int result;
> FILE f;
> bzero (&f, sizeof (f));
> init_obstream (&f, obstack);
> - return vfprintf (&f, format, args);
> + result = vfprintf (&f, format, args);
> +
> + if (result >= 0)
> + fflush(&f);
> +
> + return result;
> }
>
> int
> diff -aurN mintlib-CVS-20090305/stdio/test-obstream.c mintlib-CVS-20090305-obstream/stdio/test-obstream.c
> --- mintlib-CVS-20090305/stdio/test-obstream.c 1970-01-01 01:00:00.000000000 +0100
> +++ mintlib-CVS-20090305-obstream/stdio/test-obstream.c 2009-03-05 22:26:00.000000000 +0100
> @@ -0,0 +1,359 @@
> +/* Copyright (C) 2009 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
> + modify it under the terms of the GNU Library General Public License as
> + published by the Free Software Foundation; either version 2 of the
> + License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Library General Public License for more details.
> +
> + You should have received a copy of the GNU Library General Public
> + License along with the GNU C Library; see the file COPYING.LIB. If not,
> + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
> + Boston, MA 02111-1307, USA. */
> +
> +#include <stdio.h>
> +#include <obstack.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdarg.h>
> +
> +#define obstack_chunk_alloc malloc
> +#define obstack_chunk_free free
> +
> +static void
> +check_obstack_printf_int(void)
> +{
> + const char *fmt, *want;
> + struct obstack ob;
> + int got_len, want_len, ob_len;
> + char *got;
> +
> + obstack_init (&ob);
> +
> + fmt = "%d";
> + want = "567";
> + want_len = strlen (want);
> + got_len = obstack_printf (&ob, fmt, 567);
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> +
> + if (got_len != want_len
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_obstack_printf_int: obstack_printf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + obstack_free (&ob, NULL);
> +}
> +
> +static void
> +check_obstack_printf_typical(void)
> +{
> + const char *fmt, *want;
> + struct obstack ob;
> + int got_len, want_len;
> + char *got;
> +
> + obstack_init (&ob);
> +
> + fmt = "Found %d occurences.";
> + want = "Found 23 occurences.";
> + want_len = strlen (want);
> + obstack_printf (&ob, fmt, 23);
> + obstack_1grow(&ob, '\0');
> + got = (char*)obstack_finish (&ob);
> + got_len = strlen(got);
> +
> + if (got_len != want_len
> + || strcmp(got, want) != 0)
> + {
> + printf ("check_obstack_printf_typical: obstack_printf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + exit (1);
> + }
> +
> + obstack_free (&ob, NULL);
> +}
> +
> +static void
> +check_obstack_printf_two_times(void)
> +{
> + const char *fmt, *want;
> + struct obstack ob;
> + int got_len, want_len, ob_len;
> + char *got;
> +
> + obstack_init (&ob);
> +
> + /* First write */
> + fmt = "%d";
> + want = "123";
> + want_len = strlen (want);
> + got_len = obstack_printf (&ob, fmt, 123);
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> +
> + if (got_len != want_len
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_obstack_printf_two_times: first obstack_printf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + /* Second write */
> + fmt = "%d";
> + want = "1234567";
> + want_len = strlen (want);
> + got_len = obstack_printf (&ob, fmt, 4567);
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> +
> + if (got_len != 4
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_obstack_printf_two_times: second obstack_printf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + obstack_free (&ob, NULL);
> +}
> +
> +static void
> +check_obstack_vprintf(const char* want, const char* fmt, ...)
> +{
> + va_list ap;
> + struct obstack ob;
> + int got_len, want_len, ob_len;
> + char *got;
> +
> + obstack_init (&ob);
> +
> + va_start (ap, fmt);
> + want_len = strlen (want);
> + got_len = obstack_vprintf (&ob, fmt, ap);
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> +
> + if (got_len != want_len
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_obstack_vprintf: obstack_printf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + obstack_free (&ob, NULL);
> +}
> +
> +static void
> +check_open_obstack_stream(void)
> +{
> + struct obstack ob;
> + const char* fmt;
> + int got_len, want_len, ob_len, got2_len, want2_len, err;
> + const char *want, *got, *want2;
> + FILE* f;
> +
> + obstack_init (&ob);
> +
> + f = open_obstack_stream(&ob);
> + if (f == NULL)
> + {
> + printf("check_open_obstack_stream: open_obstack_stream returned NULL\n");
> + exit (1);
> + }
> +
> + /* Test fprintf */
> + fmt = "one %d";
> + want = "one 2";
> + want_len = strlen (want);
> + got_len = fprintf(f, fmt, 2);
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> + if (got_len != want_len
> + || ob_len < want_len /* Will be equal after flush. */
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_open_obstack_stream: fprintf wrong\n");
> + printf (" fmt |%s|\n", fmt);
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", got_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" got_len %d\n", got_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + /* Test fwrite */
> + want = "one 2 three\nfour";
> + want_len = strlen (want);
> + want2 = " three\nfour";
> + want2_len = strlen (want2);
> + got2_len = fwrite(want2, 1, want2_len, f);
> + if (got2_len != want2_len)
> + {
> + printf("check_open_obstack_stream: fwrite failed.\n");
> + exit (1);
> + }
> +
> + /* Test fflush */
> + err = fflush(f);
> + if (err != 0)
> + {
> + printf("check_open_obstack_stream: fflush failed.\n");
> + exit (1);
> + }
> +
> + /* Check fwrite + fflush */
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> + if (got2_len != want2_len
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_open_obstack_stream: fwrite wrong\n");
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", ob_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" ob_len %d\n", ob_len);
> + printf (" want2_len %d\n", want2_len);
> + printf (" got2_len %d\n", got2_len);
> + exit (1);
> + }
> +
> + /* Test fseek SEEK_SET */
> + err = fseek(f, 25, SEEK_SET);
> + if (err != 0)
> + {
> + printf("check_open_obstack_stream: fseek SEEK_SET failed.\n");
> + exit (1);
> + }
> +
> + want = "one 2 three\nfour\0\0\0\0\0\0\0\0\0";
> + want_len = 25;
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> + if (ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_open_obstack_stream: fseek SEEK_SET wrong\n");
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", ob_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + /* Test fseek SEEK_CUR backwards. */
> + err = fseek(f, -11, SEEK_CUR);
> + if (err != 0)
> + {
> + printf("check_open_obstack_stream: fseek SEEK_CUR failed.\n");
> + exit (1);
> + }
> +
> + /* Seeking backwards should not change the object contents. */
> + want = "one 2 three\nfour\0\0\0\0\0\0\0\0\0";
> + want_len = 25;
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> + if (ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_open_obstack_stream: fseek SEEK_CUR wrong\n");
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", ob_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" ob_len %d\n", ob_len);
> + exit (1);
> + }
> +
> + /* Test fwrite2 */
> + want = "one 2 three\nfoObar five six seven";
> + want_len = strlen (want);
> + want2 = "Obar five six seven";
> + want2_len = strlen (want2);
> + got2_len = fwrite(want2, 1, want2_len, f);
> + if (got2_len != want2_len)
> + {
> + printf("check_open_obstack_stream: fwrite2 failed.\n");
> + exit (1);
> + }
> +
> + /* Test fclose */
> + err = fclose(f);
> + if (err != 0)
> + {
> + printf("check_open_obstack_stream: fclose failed.\n");
> + exit (1);
> + }
> +
> + /* Check fwrite + fclose */
> + got = obstack_base (&ob);
> + ob_len = obstack_object_size (&ob);
> + if (got2_len != want2_len
> + || ob_len != want_len
> + || memcmp (got, want, want_len) != 0)
> + {
> + printf ("check_open_obstack_stream: fwrite2 wrong\n");
> + printf (" want |%s|\n", want);
> + printf (" got |%.*s|\n", ob_len, got);
> + printf (" want_len %d\n", want_len);
> + printf (" ob_len %d\n", ob_len);
> + printf (" want2_len %d\n", want2_len);
> + printf (" got2_len %d\n", got2_len);
> + exit (1);
> + }
> +
> + obstack_free (&ob, NULL);
> +}
> +
> +int
> +main (int argc, char *argv[])
> +{
> + check_obstack_printf_int();
> + check_obstack_printf_typical();
> + check_obstack_printf_two_times();
> + check_obstack_vprintf("one and 2 then 3.4", "%s and %d then %.1f", "one", 2, 3.4);
> + check_obstack_vprintf("one\ntwo\nthree", "one\n%s", "two\nthree");
> + check_open_obstack_stream();
> +
> + return 0;
> +}