[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [MiNT] Gcc 3.3.6 v 4.0.1



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 !

--
Vincent Rivière
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;
+}