import gdb-1999-12-06 snapshot
[deliverable/binutils-gdb.git] / gdb / utils.c
index e657c5a374febb66c47ef346ad951f9388df78a9..cbaf0cc9dfd3e251095130e0f2146e0bde267263 100644 (file)
@@ -98,6 +98,7 @@ static struct cleanup *exec_error_cleanup_chain;
    support async execution.  The finish and until commands use it. So
    does the target extended-remote command. */
 struct continuation *cmd_continuation;
+struct continuation *intermediate_continuation;
 
 /* Nonzero if we have job control. */
 
@@ -211,6 +212,18 @@ make_cleanup_freeargv (arg)
   return make_my_cleanup (&cleanup_chain, do_freeargv, arg);
 }
 
+static void
+do_gdb_file_delete (void *arg)
+{
+  gdb_file_delete (arg);
+}
+
+struct cleanup *
+make_cleanup_gdb_file_delete (struct gdb_file *arg)
+{
+  return make_my_cleanup (&cleanup_chain, do_gdb_file_delete, arg);
+}
+
 struct cleanup *
 make_my_cleanup (pmy_chain, function, arg)
      struct cleanup **pmy_chain;
@@ -394,7 +407,7 @@ null_cleanup (arg)
 }
 
 /* Add a continuation to the continuation list, the gloabl list
-   cmd_continuation. */
+   cmd_continuation. The new continuation will be added at the front.*/
 void
 add_continuation (continuation_hook, arg_list)
      void (*continuation_hook) PARAMS ((struct continuation_arg *));
@@ -410,32 +423,109 @@ add_continuation (continuation_hook, arg_list)
 }
 
 /* Walk down the cmd_continuation list, and execute all the
-   continuations. */
+   continuations. There is a problem though. In some cases new
+   continuations may be added while we are in the middle of this
+   loop. If this happens they will be added in the front, and done
+   before we have a chance of exhausting those that were already
+   there. We need to then save the beginning of the list in a pointer
+   and do the continuations from there on, instead of using the
+   global beginning of list as our iteration pointer.*/
 void
 do_all_continuations ()
+{
+  struct continuation *continuation_ptr;
+  struct continuation *saved_continuation;
+
+  /* Copy the list header into another pointer, and set the global
+     list header to null, so that the global list can change as a side
+     effect of invoking the continuations and the processing of
+     the preexisting continuations will not be affected. */
+  continuation_ptr = cmd_continuation;
+  cmd_continuation = NULL;
+
+  /* Work now on the list we have set aside. */
+  while (continuation_ptr)
+     {
+       (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+       saved_continuation = continuation_ptr;
+       continuation_ptr = continuation_ptr->next;
+       free (saved_continuation);
+     }
+}
+
+/* Walk down the cmd_continuation list, and get rid of all the
+   continuations. */
+void
+discard_all_continuations ()
 {
   struct continuation *continuation_ptr;
 
   while (cmd_continuation)
     {
-      (cmd_continuation->continuation_hook) (cmd_continuation->arg_list);
       continuation_ptr = cmd_continuation;
       cmd_continuation = continuation_ptr->next;
       free (continuation_ptr);
     }
 }
 
+/* Add a continuation to the continuation list, the gloabl list
+   intermediate_continuation. The new continuation will be added at the front.*/
+void
+add_intermediate_continuation (continuation_hook, arg_list)
+     void (*continuation_hook) PARAMS ((struct continuation_arg *));
+     struct continuation_arg *arg_list;
+{
+  struct continuation *continuation_ptr;
+
+  continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation));
+  continuation_ptr->continuation_hook = continuation_hook;
+  continuation_ptr->arg_list = arg_list;
+  continuation_ptr->next = intermediate_continuation;
+  intermediate_continuation = continuation_ptr;
+}
+
+/* Walk down the cmd_continuation list, and execute all the
+   continuations. There is a problem though. In some cases new
+   continuations may be added while we are in the middle of this
+   loop. If this happens they will be added in the front, and done
+   before we have a chance of exhausting those that were already
+   there. We need to then save the beginning of the list in a pointer
+   and do the continuations from there on, instead of using the
+   global beginning of list as our iteration pointer.*/
+void
+do_all_intermediate_continuations ()
+{
+  struct continuation *continuation_ptr;
+  struct continuation *saved_continuation;
+
+  /* Copy the list header into another pointer, and set the global
+     list header to null, so that the global list can change as a side
+     effect of invoking the continuations and the processing of
+     the preexisting continuations will not be affected. */
+  continuation_ptr = intermediate_continuation;
+  intermediate_continuation = NULL;
+
+  /* Work now on the list we have set aside. */
+  while (continuation_ptr)
+     {
+       (continuation_ptr->continuation_hook) (continuation_ptr->arg_list);
+       saved_continuation = continuation_ptr;
+       continuation_ptr = continuation_ptr->next;
+       free (saved_continuation);
+     }
+}
+
 /* Walk down the cmd_continuation list, and get rid of all the
    continuations. */
 void
-discard_all_continuations ()
+discard_all_intermediate_continuations ()
 {
   struct continuation *continuation_ptr;
 
-  while (cmd_continuation)
+  while (intermediate_continuation)
     {
-      continuation_ptr = cmd_continuation;
-      cmd_continuation = continuation_ptr->next;
+      continuation_ptr = intermediate_continuation;
+      intermediate_continuation = continuation_ptr->next;
       free (continuation_ptr);
     }
 }
@@ -510,32 +600,50 @@ error_begin ()
    The first argument STRING is the error message, used as a fprintf string,
    and the remaining args are passed as arguments to it.  */
 
+NORETURN void
+verror (const char *string, va_list args)
+{
+  char *err_string;
+  struct cleanup *err_string_cleanup;
+  /* FIXME: cagney/1999-11-10: All error calls should come here.
+     Unfortunatly some code uses the sequence: error_begin(); print
+     error message; return_to_top_level.  That code should be
+     flushed. */
+  error_begin ();
+  /* NOTE: It's tempting to just do the following...
+       vfprintf_filtered (gdb_stderr, string, args);
+     and then follow with a similar looking statement to cause the message
+     to also go to gdb_lasterr.  But if we do this, we'll be traversing the
+     va_list twice which works on some platforms and fails miserably on
+     others. */
+  /* Save it as the last error */
+  gdb_file_rewind (gdb_lasterr);
+  vfprintf_filtered (gdb_lasterr, string, args);
+  /* Retrieve the last error and print it to gdb_stderr */
+  err_string = error_last_message ();
+  err_string_cleanup = make_cleanup (free, err_string);
+  fputs_filtered (err_string, gdb_stderr);
+  fprintf_filtered (gdb_stderr, "\n");
+  do_cleanups (err_string_cleanup);
+  return_to_top_level (RETURN_ERROR);
+}
+
 NORETURN void
 error (const char *string,...)
 {
   va_list args;
   va_start (args, string);
-  if (error_hook)
-    (*error_hook) ();
-  else
-    {
-      error_begin ();
-      vfprintf_filtered (gdb_stderr, string, args);
-      fprintf_filtered (gdb_stderr, "\n");
-      /* Save it as the last error as well (no newline) */
-      gdb_file_rewind (gdb_lasterr);
-      vfprintf_filtered (gdb_lasterr, string, args);
-      va_end (args);
-      return_to_top_level (RETURN_ERROR);
-    }
+  verror (string, args);
+  va_end (args);
 }
 
-/* Allows the error message to be passed on a stream buffer */
-
 NORETURN void
 error_stream (GDB_FILE *stream)
 {
-  error (gdb_file_get_strbuf (stream));
+  long size;
+  char *msg = gdb_file_xstrdup (stream, &size);
+  make_cleanup (free, msg);
+  error ("%s", msg);
 }
 
 /* Get the last error message issued by gdb */
@@ -543,26 +651,26 @@ error_stream (GDB_FILE *stream)
 char *
 error_last_message (void)
 {
-  return (gdb_file_get_strbuf (gdb_lasterr));
+  long len;
+  return gdb_file_xstrdup (gdb_lasterr, &len);
 }
-
+  
 /* This is to be called by main() at the very beginning */
 
 void
 error_init (void)
 {
-  gdb_lasterr = tui_sfileopen (132);
+  gdb_lasterr = mem_fileopen ();
 }
 
 /* Print a message reporting an internal error. Ask the user if they
    want to continue, dump core, or just exit. */
 
 NORETURN void
-internal_error (char *string, ...)
+internal_verror (const char *fmt, va_list ap)
 {
   static char msg[] = "Internal GDB error: recursive internal error.\n";
   static int dejavu = 0;
-  va_list args;
   int continue_p;
   int dump_core_p;
 
@@ -584,9 +692,7 @@ internal_error (char *string, ...)
 
   /* Try to get the message out */
   fputs_unfiltered ("gdb-internal-error: ", gdb_stderr);
-  va_start (args, string);
-  vfprintf_unfiltered (gdb_stderr, string, args);
-  va_end (args);
+  vfprintf_unfiltered (gdb_stderr, fmt, ap);
   fputs_unfiltered ("\n", gdb_stderr);
 
   /* Default (no case) is to quit GDB.  When in batch mode this
@@ -620,6 +726,15 @@ Create a core file containing the current state of GDB? ");
   return_to_top_level (RETURN_ERROR);
 }
 
+NORETURN void
+internal_error (char *string, ...)
+{
+  va_list ap;
+  va_start (ap, string);
+  internal_verror (string, ap);
+  va_end (ap);
+}
+
 /* The strerror() function can return NULL for errno values that are
    out of range.  Provide a "safe" version that always returns a
    printable string. */
@@ -775,7 +890,7 @@ notice_quit ()
     immediate_quit = 1;
 }
 
-#else /* !defined(__GO32__) && !defined(_MSC_VER) */
+#else /* !defined(_MSC_VER) */
 
 void
 notice_quit ()
@@ -783,7 +898,7 @@ notice_quit ()
   /* Done by signals */
 }
 
-#endif /* !defined(__GO32__) && !defined(_MSC_VER) */
+#endif /* !defined(_MSC_VER) */
 
 /* Control C comes here */
 void
@@ -1643,6 +1758,7 @@ begin_line ()
 /* ``struct gdb_file'' implementation that maps directly onto
    <stdio.h>'s FILE. */
 
+static gdb_file_write_ftype stdio_file_write;
 static gdb_file_fputs_ftype stdio_file_fputs;
 static gdb_file_isatty_ftype stdio_file_isatty;
 static gdb_file_delete_ftype stdio_file_delete;
@@ -1670,6 +1786,7 @@ stdio_file_new (file, close_p)
   stdio->close_p = close_p;
   set_gdb_file_data (gdb_file, stdio, stdio_file_delete);
   set_gdb_file_flush (gdb_file, stdio_file_flush);
+  set_gdb_file_write (gdb_file, stdio_file_write);
   set_gdb_file_fputs (gdb_file, stdio_file_fputs);
   set_gdb_file_isatty (gdb_file, stdio_file_isatty);
   return gdb_file;
@@ -1681,7 +1798,7 @@ stdio_file_delete (file)
 {
   struct stdio_file *stdio = gdb_file_data (file);
   if (stdio->magic != &stdio_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("stdio_file_delete: bad magic number");
   if (stdio->close_p)
     {
       fclose (stdio->file);
@@ -1695,10 +1812,19 @@ stdio_file_flush (file)
 {
   struct stdio_file *stdio = gdb_file_data (file);
   if (stdio->magic != &stdio_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("stdio_file_flush: bad magic number");
   fflush (stdio->file);
 }
 
+static void
+stdio_file_write (struct gdb_file *file, const char *buf, long length_buf)
+{
+  struct stdio_file *stdio = gdb_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    internal_error ("stdio_file_write: bad magic number");
+  fwrite (buf, length_buf, 1, stdio->file);
+}
+
 static void
 stdio_file_fputs (linebuffer, file)
      const char *linebuffer;
@@ -1706,7 +1832,7 @@ stdio_file_fputs (linebuffer, file)
 {
   struct stdio_file *stdio = gdb_file_data (file);
   if (stdio->magic != &stdio_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("stdio_file_fputs: bad magic number");
   fputs (linebuffer, stdio->file);
 }
 
@@ -1716,7 +1842,7 @@ stdio_file_isatty (file)
 {
   struct stdio_file *stdio = gdb_file_data (file);
   if (stdio->magic != &stdio_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("stdio_file_isatty: bad magic number");
   return (isatty (fileno (stdio->file)));
 }
 
@@ -1731,19 +1857,20 @@ stdio_fileopen (file)
 
 
 /* A pure memory based ``struct gdb_file'' that can be used an output
-   collector. It's input is available through gdb_file_put(). */
+   buffer. The buffers accumulated contents are available via
+   gdb_file_put(). */
 
 struct mem_file
   {
     int *magic;
     char *buffer;
     int sizeof_buffer;
-    int strlen_buffer;
+    int length_buffer;
   };
 
-extern gdb_file_fputs_ftype mem_file_fputs;
 static gdb_file_rewind_ftype mem_file_rewind;
 static gdb_file_put_ftype mem_file_put;
+static gdb_file_write_ftype mem_file_write;
 static gdb_file_delete_ftype mem_file_delete;
 static struct gdb_file *mem_file_new PARAMS ((void));
 static int mem_file_magic;
@@ -1754,12 +1881,13 @@ mem_file_new (void)
   struct mem_file *stream = XMALLOC (struct mem_file);
   struct gdb_file *file = gdb_file_new ();
   set_gdb_file_data (file, stream, mem_file_delete);
-  set_gdb_file_fputs (file, mem_file_fputs);
   set_gdb_file_rewind (file, mem_file_rewind);
   set_gdb_file_put (file, mem_file_put);
+  set_gdb_file_write (file, mem_file_write);
   stream->magic = &mem_file_magic;
   stream->buffer = NULL;
   stream->sizeof_buffer = 0;
+  stream->length_buffer = 0;
   return file;
 }
 
@@ -1786,52 +1914,49 @@ mem_file_rewind (struct gdb_file *file)
   struct mem_file *stream = gdb_file_data (file);
   if (stream->magic != &mem_file_magic)
     internal_error ("mem_file_rewind: bad magic number");
-  if (stream->buffer != NULL)
-    {
-      stream->buffer[0] = '\0';
-      stream->strlen_buffer = 0;
-    }
+  stream->length_buffer = 0;
 }
 
 static void
-mem_file_put (struct gdb_file *file, struct gdb_file *dest)
+mem_file_put (struct gdb_file *file,
+             gdb_file_put_method_ftype *write,
+             void *dest)
 {
   struct mem_file *stream = gdb_file_data (file);
   if (stream->magic != &mem_file_magic)
     internal_error ("mem_file_put: bad magic number");
-  if (stream->buffer != NULL)
-    fputs_unfiltered (stream->buffer, dest);
+  if (stream->length_buffer > 0)
+    write (dest, stream->buffer, stream->length_buffer);
 }
 
 void
-mem_file_fputs (const char *linebuffer, struct gdb_file *file)
+mem_file_write (struct gdb_file *file,
+               const char *buffer,
+               long length_buffer)
 {
   struct mem_file *stream = gdb_file_data (file);
   if (stream->magic != &mem_file_magic)
-    internal_error ("mem_file_fputs: bad magic number");
+    internal_error ("mem_file_write: bad magic number");
   if (stream->buffer == NULL)
     {
-      stream->strlen_buffer = strlen (linebuffer);
-      stream->sizeof_buffer = stream->strlen_buffer + 1;
+      stream->length_buffer = length_buffer;
+      stream->sizeof_buffer = length_buffer;
       stream->buffer = xmalloc (stream->sizeof_buffer);
-      strcpy (stream->buffer, linebuffer);
+      memcpy (stream->buffer, buffer, length_buffer);
     }
   else
     {
-      int len = strlen (linebuffer);
-      int new_strlen = stream->strlen_buffer + len;
-      int new_sizeof = new_strlen + 1;
-      if (new_sizeof >= stream->sizeof_buffer)
+      int new_length = stream->length_buffer + length_buffer;
+      if (new_length >= stream->sizeof_buffer)
        {
-         stream->sizeof_buffer = new_sizeof;
+         stream->sizeof_buffer = new_length;
          stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
        }
-      strcpy (stream->buffer + stream->strlen_buffer, linebuffer);
-      stream->strlen_buffer = new_strlen;
+      memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
+      stream->length_buffer = new_length;
     }
 }
 
-
 /* A ``struct gdb_file'' that is compatible with all the legacy
    code. */
 
@@ -1882,7 +2007,7 @@ tui_file_delete (file)
 {
   struct tui_stream *tmpstream = gdb_file_data (file);
   if (tmpstream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_delete: bad magic number");
   if ((tmpstream->ts_streamtype == astring) &&
       (tmpstream->ts_strbuf != NULL))
     {
@@ -1919,7 +2044,7 @@ tui_sfileopen (n)
     }
   else
     /* Do not allocate the buffer now.  The first time something is printed
-       one will be allocated by gdb_file_adjust_strbuf()  */
+       one will be allocated by tui_file_adjust_strbuf()  */
     tmpstream->ts_strbuf = NULL;
   tmpstream->ts_buflen = n;
   return file;
@@ -1931,7 +2056,7 @@ tui_file_isatty (file)
 {
   struct tui_stream *stream = gdb_file_data (file);
   if (stream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_isatty: bad magic number");
   if (stream->ts_streamtype == afile)
     return (isatty (fileno (stream->ts_filestream)));
   else
@@ -1944,22 +2069,20 @@ tui_file_rewind (file)
 {
   struct tui_stream *stream = gdb_file_data (file);
   if (stream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_rewind: bad magic number");
   stream->ts_strbuf[0] = '\0';
 }
 
 static void
-tui_file_put (file, dest)
-     struct gdb_file *file;
-     struct gdb_file *dest;
+tui_file_put (struct gdb_file *file,
+             gdb_file_put_method_ftype *write,
+             void *dest)
 {
   struct tui_stream *stream = gdb_file_data (file);
   if (stream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_put: bad magic number");
   if (stream->ts_streamtype == astring)
-    {
-      fputs_unfiltered (stream->ts_strbuf, dest);
-    }
+    write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
 }
 
 /* All TUI I/O sent to the *_filtered and *_unfiltered functions
@@ -2001,7 +2124,7 @@ tui_file_fputs (linebuffer, file)
 
          if (stream->ts_streamtype == astring)
            {
-             gdb_file_adjust_strbuf (strlen (linebuffer), stream);
+             tui_file_adjust_strbuf (strlen (linebuffer), stream);
              strcat (stream->ts_strbuf, linebuffer);
            }
          else
@@ -2020,7 +2143,7 @@ tui_file_fputs (linebuffer, file)
          /* The normal case - just do a fputs() */
          if (stream->ts_streamtype == astring)
            {
-             gdb_file_adjust_strbuf (strlen (linebuffer), stream);
+             tui_file_adjust_strbuf (strlen (linebuffer), stream);
              strcat (stream->ts_strbuf, linebuffer);
            }
          else
@@ -2031,7 +2154,7 @@ tui_file_fputs (linebuffer, file)
 #else
       if (stream->ts_streamtype == astring)
        {
-         gdb_file_adjust_strbuf (strlen (linebuffer), file);
+         tui_file_adjust_strbuf (strlen (linebuffer), file);
          strcat (stream->ts_strbuf, linebuffer);
        }
       else
@@ -2040,60 +2163,24 @@ tui_file_fputs (linebuffer, file)
     }
 }
 
-/* DEPRECATED: Use tui_sfileopen() instead */
-
-GDB_FILE *
-gdb_file_init_astring (n)
-     int n;
-{
-  struct gdb_file *file = tui_file_new ();
-  struct tui_stream *tmpstream = gdb_file_data (file);
-  if (tmpstream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
-
-  tmpstream->ts_streamtype = astring;
-  tmpstream->ts_filestream = NULL;
-  if (n > 0)
-    {
-      tmpstream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
-      tmpstream->ts_strbuf[0] = '\0';
-    }
-  else
-    tmpstream->ts_strbuf = NULL;
-  tmpstream->ts_buflen = n;
-
-  return file;
-}
-
-void
-gdb_file_deallocate (streamptr)
-     GDB_FILE **streamptr;
-{
-  gdb_file_delete (*streamptr);
-  *streamptr = NULL;
-}
-
 char *
-gdb_file_get_strbuf (file)
-     GDB_FILE *file;
+tui_file_get_strbuf (struct gdb_file *file)
 {
   struct tui_stream *stream = gdb_file_data (file);
   if (stream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_get_strbuf: bad magic number");
   return (stream->ts_strbuf);
 }
 
 /* adjust the length of the buffer by the amount necessary
    to accomodate appending a string of length N to the buffer contents */
 void
-gdb_file_adjust_strbuf (n, file)
-     int n;
-     GDB_FILE *file;
+tui_file_adjust_strbuf (int n, struct gdb_file *file)
 {
   struct tui_stream *stream = gdb_file_data (file);
   int non_null_chars;
   if (stream->ts_magic != &tui_file_magic)
-    error ("Internal error: bad magic number");
+    internal_error ("tui_file_adjust_strbuf: bad magic number");
 
   if (stream->ts_streamtype != astring)
     return;
@@ -2150,18 +2237,10 @@ tui_file_flush (file)
     }
 }
 
-void
-gdb_fclose (streamptr)
-     GDB_FILE **streamptr;
-{
-  gdb_file_delete (*streamptr);
-  *streamptr = NULL;
-}
-
-
 /* Implement the ``struct gdb_file'' object. */
 
 static gdb_file_isatty_ftype null_file_isatty;
+static gdb_file_write_ftype null_file_write;
 static gdb_file_fputs_ftype null_file_fputs;
 static gdb_file_flush_ftype null_file_flush;
 static gdb_file_delete_ftype null_file_delete;
@@ -2170,7 +2249,9 @@ static gdb_file_put_ftype null_file_put;
 
 struct gdb_file
   {
+    int *magic;
     gdb_file_flush_ftype *to_flush;
+    gdb_file_write_ftype *to_write;
     gdb_file_fputs_ftype *to_fputs;
     gdb_file_delete_ftype *to_delete;
     gdb_file_isatty_ftype *to_isatty;
@@ -2178,13 +2259,16 @@ struct gdb_file
     gdb_file_put_ftype *to_put;
     void *to_data;
   };
+int gdb_file_magic;
 
 struct gdb_file *
 gdb_file_new ()
 {
   struct gdb_file *file = xmalloc (sizeof (struct gdb_file));
+  file->magic = &gdb_file_magic;
   set_gdb_file_data (file, NULL, null_file_delete);
   set_gdb_file_flush (file, null_file_flush);
+  set_gdb_file_write (file, null_file_write);
   set_gdb_file_fputs (file, null_file_fputs);
   set_gdb_file_isatty (file, null_file_isatty);
   set_gdb_file_rewind (file, null_file_rewind);
@@ -2215,9 +2299,9 @@ null_file_rewind (file)
 }
 
 static void
-null_file_put (file, src)
-     struct gdb_file *file;
-     struct gdb_file *src;
+null_file_put (struct gdb_file *file,
+              gdb_file_put_method_ftype *write,
+              void *dest)
 {
   return;
 }
@@ -2229,12 +2313,48 @@ null_file_flush (file)
   return;
 }
 
+static void
+null_file_write (struct gdb_file *file,
+                const char *buf,
+                long sizeof_buf)
+{
+  if (file->to_fputs == null_file_fputs)
+    /* Both the write and fputs methods are null. Discard the
+       request. */
+    return;
+  else
+    {
+      /* The fputs method isn't null, slowly pass the write request
+         onto that.  FYI, this isn't as bad as it may look - the
+         current (as of 1999-11-07) printf_* function calls fputc and
+         fputc does exactly the below.  By having a write function it
+         is possible to clean up that code.  */
+      int i;
+      char b[2];
+      b[1] = '\0';
+      for (i = 0; i < sizeof_buf; i++)
+       {
+         b[0] = buf[i];
+         file->to_fputs (b, file);
+       }
+      return;
+    }
+}
+
 static void
 null_file_fputs (buf, file)
      const char *buf;
      struct gdb_file *file;
 {
-  return;
+  if (file->to_write == null_file_write)
+    /* Both the write and fputs methods are null. Discard the
+       request. */
+    return;
+  else
+    {
+      /* The write method was implemented, use that. */
+      file->to_write (file, buf, strlen (buf));
+    }
 }
 
 static void
@@ -2248,6 +2368,8 @@ void *
 gdb_file_data (file)
      struct gdb_file *file;
 {
+  if (file->magic != &gdb_file_magic)
+    internal_error ("gdb_file_data: bad magic number");
   return file->to_data;
 }
 
@@ -2273,11 +2395,19 @@ gdb_file_rewind (file)
 }
 
 void
-gdb_file_put (file, dest)
-     struct gdb_file *file;
-     struct gdb_file *dest;
+gdb_file_put (struct gdb_file *file,
+             gdb_file_put_method_ftype *write,
+             void *dest)
 {
-  file->to_put (file, dest);
+  file->to_put (file, write, dest);
+}
+
+void
+gdb_file_write (struct gdb_file *file,
+               const char *buf,
+               long length_buf)
+{
+  file->to_write (file, buf, length_buf);
 }
 
 void
@@ -2320,6 +2450,13 @@ set_gdb_file_put (file, put)
   file->to_put = put;
 }
 
+void
+set_gdb_file_write (struct gdb_file *file,
+                   gdb_file_write_ftype *write)
+{
+  file->to_write = write;
+}
+
 void
 set_gdb_file_fputs (file, fputs)
      struct gdb_file *file;
@@ -2338,6 +2475,43 @@ set_gdb_file_data (file, data, delete)
   file->to_delete = delete;
 }
 
+/* gdb_file utility function for converting a ``struct gdb_file'' into
+   a memory buffer''. */
+
+struct accumulated_gdb_file
+{
+  char *buffer;
+  long length;
+};
+
+static void
+do_gdb_file_xstrdup (void *context, const char *buffer, long length)
+{
+  struct accumulated_gdb_file *acc = context;
+  if (acc->buffer == NULL)
+    acc->buffer = xmalloc (length + 1);
+  else
+    acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
+  memcpy (acc->buffer + acc->length, buffer, length);
+  acc->length += length;
+  acc->buffer[acc->length] = '\0';
+}
+
+char *
+gdb_file_xstrdup (struct gdb_file *file,
+                 long *length)
+{
+  struct accumulated_gdb_file acc;
+  acc.buffer = NULL;
+  acc.length = 0;
+  gdb_file_put (file, do_gdb_file_xstrdup, &acc);
+  if (acc.buffer == NULL)
+    acc.buffer = xstrdup ("");
+  *length = acc.length;
+  return acc.buffer;
+}
+
+
 /* Like fputs but if FILTER is true, pause after every screenful.
 
    Regardless of FILTER can wrap at points other than the final
@@ -2467,11 +2641,8 @@ int
 putchar_unfiltered (c)
      int c;
 {
-  char buf[2];
-
-  buf[0] = c;
-  buf[1] = 0;
-  fputs_unfiltered (buf, gdb_stdout);
+  char buf = c;
+  gdb_file_write (gdb_stdout, &buf, 1);
   return c;
 }
 
@@ -2480,11 +2651,8 @@ fputc_unfiltered (c, stream)
      int c;
      GDB_FILE *stream;
 {
-  char buf[2];
-
-  buf[0] = c;
-  buf[1] = 0;
-  fputs_unfiltered (buf, stream);
+  char buf = c;
+  gdb_file_write (stream, &buf, 1);
   return c;
 }
 
@@ -3122,9 +3290,12 @@ floatformat_to_doublest (fmt, from, to)
 
   special_exponent = exponent == 0 || exponent == fmt->exp_nan;
 
-/* Don't bias zero's, denorms or NaNs.  */
+/* Don't bias NaNs. Use minimum exponent for denorms. For simplicity,
+   we don't check for zero as the exponent doesn't matter. */
   if (!special_exponent)
     exponent -= fmt->exp_bias;
+  else if (exponent == 0)
+    exponent = 1 - fmt->exp_bias;
 
   /* Build the result algebraically.  Might go infinite, underflow, etc;
      who cares. */
This page took 0.039147 seconds and 4 git commands to generate.