OSDN Git Service

Initial revision
authorJason Molenda <jsm@bugshack.cygnus.com>
Tue, 1 Feb 2000 03:19:29 +0000 (03:19 +0000)
committerJason Molenda <jsm@bugshack.cygnus.com>
Tue, 1 Feb 2000 03:19:29 +0000 (03:19 +0000)
gdb/gdb-file.c [new file with mode: 0644]
gdb/gdb-file.h [new file with mode: 0644]
gdb/tui/tui-file.c [new file with mode: 0644]
gdb/tui/tui-file.h [new file with mode: 0644]

diff --git a/gdb/gdb-file.c b/gdb/gdb-file.c
new file mode 100644 (file)
index 0000000..88d550a
--- /dev/null
@@ -0,0 +1,511 @@
+/* GDB_FILE - a generic STDIO like output stream.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Implement the ``struct gdb_file'' object. */
+
+#include "defs.h"
+#include "gdb-file.h"
+
+#undef XMALLOC
+#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+
+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;
+static gdb_file_rewind_ftype null_file_rewind;
+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;
+    gdb_file_rewind_ftype *to_rewind;
+    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);
+  set_gdb_file_put (file, null_file_put);
+  return file;
+}
+
+void
+gdb_file_delete (file)
+     struct gdb_file *file;
+{
+  file->to_delete (file);
+  free (file);
+}
+
+static int
+null_file_isatty (file)
+     struct gdb_file *file;
+{
+  return 0;
+}
+
+static void
+null_file_rewind (file)
+     struct gdb_file *file;
+{
+  return;
+}
+
+static void
+null_file_put (struct gdb_file *file,
+              gdb_file_put_method_ftype *write,
+              void *dest)
+{
+  return;
+}
+
+static void
+null_file_flush (file)
+     struct gdb_file *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;
+{
+  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
+null_file_delete (file)
+     struct gdb_file *file;
+{
+  return;
+}
+
+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;
+}
+
+void
+gdb_flush (file)
+     struct gdb_file *file;
+{
+  file->to_flush (file);
+}
+
+int
+gdb_file_isatty (file)
+     struct gdb_file *file;
+{
+  return file->to_isatty (file);
+}
+
+void
+gdb_file_rewind (file)
+     struct gdb_file *file;
+{
+  file->to_rewind (file);
+}
+
+void
+gdb_file_put (struct gdb_file *file,
+             gdb_file_put_method_ftype *write,
+             void *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
+fputs_unfiltered (buf, file)
+     const char *buf;
+     struct gdb_file *file;
+{
+  file->to_fputs (buf, file);
+}
+
+void
+set_gdb_file_flush (file, flush)
+     struct gdb_file *file;
+     gdb_file_flush_ftype *flush;
+{
+  file->to_flush = flush;
+}
+
+void
+set_gdb_file_isatty (file, isatty)
+     struct gdb_file *file;
+     gdb_file_isatty_ftype *isatty;
+{
+  file->to_isatty = isatty;
+}
+
+void
+set_gdb_file_rewind (file, rewind)
+     struct gdb_file *file;
+     gdb_file_rewind_ftype *rewind;
+{
+  file->to_rewind = rewind;
+}
+
+void
+set_gdb_file_put (file, put)
+     struct gdb_file *file;
+     gdb_file_put_ftype *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;
+     gdb_file_fputs_ftype *fputs;
+{
+  file->to_fputs = fputs;
+}
+
+void
+set_gdb_file_data (file, data, delete)
+     struct gdb_file *file;
+     void *data;
+     gdb_file_delete_ftype *delete;
+{
+  file->to_data = data;
+  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;
+}
+\f
+/* A pure memory based ``struct gdb_file'' that can be used an output
+   buffer. The buffers accumulated contents are available via
+   gdb_file_put(). */
+
+struct mem_file
+  {
+    int *magic;
+    char *buffer;
+    int sizeof_buffer;
+    int length_buffer;
+  };
+
+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;
+
+static struct gdb_file *
+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_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;
+}
+
+static void
+mem_file_delete (struct gdb_file *file)
+{
+  struct mem_file *stream = gdb_file_data (file);
+  if (stream->magic != &mem_file_magic)
+    internal_error ("mem_file_delete: bad magic number");
+  if (stream->buffer != NULL)
+    free (stream->buffer);
+  free (stream);
+}
+
+struct gdb_file *
+mem_fileopen (void)
+{
+  return mem_file_new ();
+}
+
+static void
+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");
+  stream->length_buffer = 0;
+}
+
+static void
+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->length_buffer > 0)
+    write (dest, stream->buffer, stream->length_buffer);
+}
+
+void
+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_write: bad magic number");
+  if (stream->buffer == NULL)
+    {
+      stream->length_buffer = length_buffer;
+      stream->sizeof_buffer = length_buffer;
+      stream->buffer = xmalloc (stream->sizeof_buffer);
+      memcpy (stream->buffer, buffer, length_buffer);
+    }
+  else
+    {
+      int new_length = stream->length_buffer + length_buffer;
+      if (new_length >= stream->sizeof_buffer)
+       {
+         stream->sizeof_buffer = new_length;
+         stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
+       }
+      memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
+      stream->length_buffer = new_length;
+    }
+}
+\f
+/* ``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;
+static struct gdb_file *stdio_file_new PARAMS ((FILE * file, int close_p));
+static gdb_file_flush_ftype stdio_file_flush;
+
+static int stdio_file_magic;
+
+struct stdio_file
+  {
+    int *magic;
+    FILE *file;
+    int close_p;
+  };
+
+static struct gdb_file *
+stdio_file_new (file, close_p)
+     FILE *file;
+     int close_p;
+{
+  struct gdb_file *gdb_file = gdb_file_new ();
+  struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
+  stdio->magic = &stdio_file_magic;
+  stdio->file = file;
+  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;
+}
+
+static void
+stdio_file_delete (file)
+     struct gdb_file *file;
+{
+  struct stdio_file *stdio = gdb_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    internal_error ("stdio_file_delete: bad magic number");
+  if (stdio->close_p)
+    {
+      fclose (stdio->file);
+    }
+  free (stdio);
+}
+
+static void
+stdio_file_flush (file)
+     struct gdb_file *file;
+{
+  struct stdio_file *stdio = gdb_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    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;
+     struct gdb_file *file;
+{
+  struct stdio_file *stdio = gdb_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    internal_error ("stdio_file_fputs: bad magic number");
+  fputs (linebuffer, stdio->file);
+}
+
+static int
+stdio_file_isatty (file)
+     struct gdb_file *file;
+{
+  struct stdio_file *stdio = gdb_file_data (file);
+  if (stdio->magic != &stdio_file_magic)
+    internal_error ("stdio_file_isatty: bad magic number");
+  return (isatty (fileno (stdio->file)));
+}
+
+/* Like fdopen().  Create a gdb_file from a previously opened FILE. */
+
+struct gdb_file *
+stdio_fileopen (file)
+     FILE *file;
+{
+  return stdio_file_new (file, 0);
+}
+
+GDB_FILE *
+gdb_fopen (name, mode)
+     char *name;
+     char *mode;
+{
+  FILE *f = fopen (name, mode);
+  if (f == NULL)
+    return NULL;
+  return stdio_file_new (f, 1);
+}
diff --git a/gdb/gdb-file.h b/gdb/gdb-file.h
new file mode 100644 (file)
index 0000000..90b9774
--- /dev/null
@@ -0,0 +1,93 @@
+/* GDB_FILE - a generic STDIO like output stream.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef GDB_FILE_H
+#define GDB_FILE_H
+
+struct gdb_file;
+
+/* Create a generic gdb_file object with null methods. */
+
+extern struct gdb_file *gdb_file_new (void);
+
+/* Override methods used by specific implementations of a GDB_FILE
+   object. */
+
+typedef void (gdb_file_flush_ftype) (struct gdb_file * stream);
+extern void set_gdb_file_flush (struct gdb_file *stream, gdb_file_flush_ftype * flush);
+
+/* NOTE: Both fputs and write methods are available. Default
+   implementations that mapping one onto the other are included. */
+typedef void (gdb_file_write_ftype) (struct gdb_file * stream, const char *buf, long length_buf);
+extern void set_gdb_file_write (struct gdb_file *stream, gdb_file_write_ftype *fputs);
+
+typedef void (gdb_file_fputs_ftype) (const char *, struct gdb_file * stream);
+extern void set_gdb_file_fputs (struct gdb_file *stream, gdb_file_fputs_ftype * fputs);
+
+typedef int (gdb_file_isatty_ftype) (struct gdb_file * stream);
+extern void set_gdb_file_isatty (struct gdb_file *stream, gdb_file_isatty_ftype * isatty);
+
+typedef void (gdb_file_rewind_ftype) (struct gdb_file * stream);
+extern void set_gdb_file_rewind (struct gdb_file *stream, gdb_file_rewind_ftype * rewind);
+
+typedef void (gdb_file_put_method_ftype) (void *object, const char *buffer, long length_buffer);
+typedef void (gdb_file_put_ftype) (struct gdb_file *stream, gdb_file_put_method_ftype * method, void *context);
+extern void set_gdb_file_put (struct gdb_file *stream, gdb_file_put_ftype * put);
+
+typedef void (gdb_file_delete_ftype) (struct gdb_file * stream);
+extern void set_gdb_file_data (struct gdb_file *stream, void *data, gdb_file_delete_ftype * delete);
+
+extern void *gdb_file_data (struct gdb_file *file);
+
+
+extern void gdb_flush (struct gdb_file *);
+
+extern void gdb_file_delete (struct gdb_file *stream);
+
+extern void gdb_file_rewind (struct gdb_file *stream);
+
+extern int gdb_file_isatty (struct gdb_file *);
+
+extern void gdb_file_write (struct gdb_file *file, const char *buf, long length_buf);
+
+/* NOTE: copies left to right */
+extern void gdb_file_put (struct gdb_file *src, gdb_file_put_method_ftype *write, void *dest);
+
+/* Returns a freshly allocated buffer containing the entire contents
+   of FILE (as determined by gdb_file_put()) with a NUL character
+   appended.  LENGTH is set to the size of the buffer minus that
+   appended NUL. */
+extern char *gdb_file_xstrdup (struct gdb_file *file, long *length);
+
+
+
+/* Create/open a memory based file. Can be used as a scratch buffer
+   for collecting output. */
+extern struct gdb_file *mem_fileopen (void);
+
+
+
+/* Open/create a an STDIO based GDB_FILE using the already open FILE. */
+extern struct gdb_file *stdio_fileopen (FILE *file);
+
+/* Open NAME returning an STDIO based GDB_FILE. */
+extern GDB_FILE *gdb_fopen (char *name, char *mode);
+
+#endif
diff --git a/gdb/tui/tui-file.c b/gdb/tui/tui-file.c
new file mode 100644 (file)
index 0000000..ae3f842
--- /dev/null
@@ -0,0 +1,298 @@
+/* GDB_FILE - a generic STDIO like output stream.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdb-file.h"
+#include "tui/tui-file.h"
+
+#include <string.h>
+
+/* Called instead of fputs for all TUI_FILE output.  */
+
+void (*fputs_unfiltered_hook) (const char *linebuffer, GDB_FILE * stream);
+
+/* A ``struct gdb_file'' that is compatible with all the legacy
+   code. */
+
+/* new */
+enum streamtype
+{
+  afile,
+  astring
+};
+
+/* new */
+struct tui_stream
+{
+  int *ts_magic;
+  enum streamtype ts_streamtype;
+  FILE *ts_filestream;
+  char *ts_strbuf;
+  int ts_buflen;
+};
+
+static gdb_file_flush_ftype tui_file_flush;
+extern gdb_file_fputs_ftype tui_file_fputs;
+static gdb_file_isatty_ftype tui_file_isatty;
+static gdb_file_rewind_ftype tui_file_rewind;
+static gdb_file_put_ftype tui_file_put;
+static gdb_file_delete_ftype tui_file_delete;
+static struct gdb_file *tui_file_new PARAMS ((void));
+static int tui_file_magic;
+
+static struct gdb_file *
+tui_file_new ()
+{
+  struct tui_stream *tui = xmalloc (sizeof (struct tui_stream));
+  struct gdb_file *file = gdb_file_new ();
+  set_gdb_file_data (file, tui, tui_file_delete);
+  set_gdb_file_flush (file, tui_file_flush);
+  set_gdb_file_fputs (file, tui_file_fputs);
+  set_gdb_file_isatty (file, tui_file_isatty);
+  set_gdb_file_rewind (file, tui_file_rewind);
+  set_gdb_file_put (file, tui_file_put);
+  tui->ts_magic = &tui_file_magic;
+  return file;
+}
+
+static void
+tui_file_delete (file)
+     struct gdb_file *file;
+{
+  struct tui_stream *tmpstream = gdb_file_data (file);
+  if (tmpstream->ts_magic != &tui_file_magic)
+    internal_error ("tui_file_delete: bad magic number");
+  if ((tmpstream->ts_streamtype == astring) &&
+      (tmpstream->ts_strbuf != NULL))
+    {
+      free (tmpstream->ts_strbuf);
+    }
+  free (tmpstream);
+}
+
+struct gdb_file *
+tui_fileopen (stream)
+     FILE *stream;
+{
+  struct gdb_file *file = tui_file_new ();
+  struct tui_stream *tmpstream = gdb_file_data (file);
+  tmpstream->ts_streamtype = afile;
+  tmpstream->ts_filestream = stream;
+  tmpstream->ts_strbuf = NULL;
+  tmpstream->ts_buflen = 0;
+  return file;
+}
+
+struct gdb_file *
+tui_sfileopen (n)
+     int n;
+{
+  struct gdb_file *file = tui_file_new ();
+  struct tui_stream *tmpstream = gdb_file_data (file);
+  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
+    /* Do not allocate the buffer now.  The first time something is printed
+       one will be allocated by tui_file_adjust_strbuf()  */
+    tmpstream->ts_strbuf = NULL;
+  tmpstream->ts_buflen = n;
+  return file;
+}
+
+static int
+tui_file_isatty (file)
+     struct gdb_file *file;
+{
+  struct tui_stream *stream = gdb_file_data (file);
+  if (stream->ts_magic != &tui_file_magic)
+    internal_error ("tui_file_isatty: bad magic number");
+  if (stream->ts_streamtype == afile)
+    return (isatty (fileno (stream->ts_filestream)));
+  else
+    return 0;
+}
+
+static void
+tui_file_rewind (file)
+     struct gdb_file *file;
+{
+  struct tui_stream *stream = gdb_file_data (file);
+  if (stream->ts_magic != &tui_file_magic)
+    internal_error ("tui_file_rewind: bad magic number");
+  stream->ts_strbuf[0] = '\0';
+}
+
+static void
+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)
+    internal_error ("tui_file_put: bad magic number");
+  if (stream->ts_streamtype == astring)
+    write (dest, stream->ts_strbuf, strlen (stream->ts_strbuf));
+}
+
+/* All TUI I/O sent to the *_filtered and *_unfiltered functions
+   eventually ends up here.  The fputs_unfiltered_hook is primarily
+   used by GUIs to collect all output and send it to the GUI, instead
+   of the controlling terminal.  Only output to gdb_stdout and
+   gdb_stderr are sent to the hook.  Everything else is sent on to
+   fputs to allow file I/O to be handled appropriately.  */
+
+/* FIXME: Should be broken up and moved to a TUI specific file. */
+
+void
+tui_file_fputs (linebuffer, file)
+     const char *linebuffer;
+     GDB_FILE *file;
+{
+  struct tui_stream *stream = gdb_file_data (file);
+#if defined(TUI)
+  extern int tui_owns_terminal;
+#endif
+  /* NOTE: cagney/1999-10-13: The use of fputs_unfiltered_hook is
+     seriously discouraged.  Those wanting to hook output should
+     instead implement their own gdb_file object and install that. See
+     also tui_file_flush(). */
+  if (fputs_unfiltered_hook
+      && (file == gdb_stdout
+         || file == gdb_stderr))
+    fputs_unfiltered_hook (linebuffer, file);
+  else
+    {
+#if defined(TUI)
+      if (tui_version && tui_owns_terminal)
+       {
+         /* If we get here somehow while updating the TUI (from
+          * within a tuiDo(), then we need to temporarily 
+          * set up the terminal for GDB output. This probably just
+          * happens on error output.
+          */
+
+         if (stream->ts_streamtype == astring)
+           {
+             tui_file_adjust_strbuf (strlen (linebuffer), stream);
+             strcat (stream->ts_strbuf, linebuffer);
+           }
+         else
+           {
+             tuiTermUnsetup (0, (tui_version) ? cmdWin->detail.commandInfo.curch : 0);
+             fputs (linebuffer, stream->ts_filestream);
+             tuiTermSetup (0);
+             if (linebuffer[strlen (linebuffer) - 1] == '\n')
+               tuiClearCommandCharCount ();
+             else
+               tuiIncrCommandCharCountBy (strlen (linebuffer));
+           }
+       }
+      else
+       {
+         /* The normal case - just do a fputs() */
+         if (stream->ts_streamtype == astring)
+           {
+             tui_file_adjust_strbuf (strlen (linebuffer), stream);
+             strcat (stream->ts_strbuf, linebuffer);
+           }
+         else
+           fputs (linebuffer, stream->ts_filestream);
+       }
+
+
+#else
+      if (stream->ts_streamtype == astring)
+       {
+         tui_file_adjust_strbuf (strlen (linebuffer), file);
+         strcat (stream->ts_strbuf, linebuffer);
+       }
+      else
+       fputs (linebuffer, stream->ts_filestream);
+#endif
+    }
+}
+
+char *
+tui_file_get_strbuf (struct gdb_file *file)
+{
+  struct tui_stream *stream = gdb_file_data (file);
+  if (stream->ts_magic != &tui_file_magic)
+    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
+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)
+    internal_error ("tui_file_adjust_strbuf: bad magic number");
+
+  if (stream->ts_streamtype != astring)
+    return;
+
+  if (stream->ts_strbuf)
+    {
+      /* There is already a buffer allocated */
+      non_null_chars = strlen (stream->ts_strbuf);
+
+      if (n > (stream->ts_buflen - non_null_chars - 1))
+       {
+         stream->ts_buflen = n + non_null_chars + 1;
+         stream->ts_strbuf = xrealloc (stream->ts_strbuf, stream->ts_buflen);
+       }
+    }
+  else
+    /* No buffer yet, so allocate one of the desired size */
+    stream->ts_strbuf = xmalloc ((n + 1) * sizeof (char));
+}
+
+static void
+tui_file_flush (file)
+     GDB_FILE *file;
+{
+  struct tui_stream *stream = gdb_file_data (file);
+  if (stream->ts_magic != &tui_file_magic)
+    internal_error ("tui_file_flush: bad magic number");
+
+  /* NOTE: cagney/1999-10-12: If we've been linked with code that uses
+     fputs_unfiltered_hook then we assume that it doesn't need to know
+     about flushes.  Code that does need to know about flushes can
+     implement a proper gdb_file object. */
+  if (fputs_unfiltered_hook)
+    return;
+
+  switch (stream->ts_streamtype)
+    {
+    case astring:
+      break;
+    case afile:
+      fflush (stream->ts_filestream);
+      break;
+    }
+}
diff --git a/gdb/tui/tui-file.h b/gdb/tui/tui-file.h
new file mode 100644 (file)
index 0000000..c962d4f
--- /dev/null
@@ -0,0 +1,34 @@
+/* GDB_FILE - a generic STDIO like output stream.
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TUI_FILE_H
+#define TUI_FILE_H
+
+extern struct gdb_file *tui_fileopen (FILE *);
+extern struct gdb_file *tui_sfileopen (int);
+extern char *tui_file_get_strbuf (struct gdb_file *);
+extern void tui_file_adjust_strbuf (int, struct gdb_file *);
+
+/* NOTE: cagney/1999-10-14: fputs_unfiltered_hook is deprecated.  Code
+   wanting to control GDB's output should override the gdb_std...
+   files. */
+extern void (*fputs_unfiltered_hook) (const char *linebuffer,
+                                     GDB_FILE * stream);
+#endif