+struct gdb_file *
+stdio_fileopen (file)
+ FILE *file;
+{
+ return stdio_file_new (file, 0);
+}
+
+
+/* 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;
+ }
+}
+
+/* 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));
+}
+
+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);
+}
+
+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;
+ }
+}
+
+/* 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;
+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;
+}
+
+
+/* Like fputs but if FILTER is true, pause after every screenful.
+
+ Regardless of FILTER can wrap at points other than the final
+ character of a line.
+
+ Unlike fputs, fputs_maybe_filtered does not return a value.
+ It is OK for LINEBUFFER to be NULL, in which case just don't print
+ anything.
+
+ Note that a longjmp to top level may occur in this routine (only if
+ FILTER is true) (since prompt_for_continue may do so) so this
+ routine should not be called when cleanups are not in place. */
+
+static void
+fputs_maybe_filtered (linebuffer, stream, filter)
+ const char *linebuffer;
+ GDB_FILE *stream;
+ int filter;
+{
+ const char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if ((stream != gdb_stdout) || !pagination_enabled
+ || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+ {
+ fputs_unfiltered (linebuffer, stream);
+ return;
+ }
+
+ /* Go through and output each character. Show line extension
+ when this is necessary; prompt user for new page when this is
+ necessary. */
+
+ lineptr = linebuffer;
+ while (*lineptr)
+ {
+ /* Possible new page. */
+ if (filter &&
+ (lines_printed >= lines_per_page - 1))
+ prompt_for_continue ();
+
+ while (*lineptr && *lineptr != '\n')
+ {
+ /* Print a single line. */
+ if (*lineptr == '\t')
+ {
+ if (wrap_column)
+ *wrap_pointer++ = '\t';
+ else
+ fputc_unfiltered ('\t', stream);
+ /* Shifting right by 3 produces the number of tab stops
+ we have already passed, and then adding one and
+ shifting left 3 advances to the next tab stop. */
+ chars_printed = ((chars_printed >> 3) + 1) << 3;
+ lineptr++;
+ }
+ else
+ {
+ if (wrap_column)
+ *wrap_pointer++ = *lineptr;
+ else
+ fputc_unfiltered (*lineptr, stream);
+ chars_printed++;
+ lineptr++;
+ }
+
+ if (chars_printed >= chars_per_line)
+ {
+ unsigned int save_chars = chars_printed;
+
+ chars_printed = 0;
+ lines_printed++;
+ /* If we aren't actually wrapping, don't output newline --
+ if chars_per_line is right, we probably just overflowed
+ anyway; if it's wrong, let us keep going. */
+ if (wrap_column)
+ fputc_unfiltered ('\n', stream);
+
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ /* Now output indentation and wrapped string */
+ if (wrap_column)
+ {
+ fputs_unfiltered (wrap_indent, stream);
+ *wrap_pointer = '\0'; /* Null-terminate saved stuff */
+ fputs_unfiltered (wrap_buffer, stream); /* and eject it */
+ /* FIXME, this strlen is what prevents wrap_indent from
+ containing tabs. However, if we recurse to print it
+ and count its chars, we risk trouble if wrap_indent is
+ longer than (the user settable) chars_per_line.
+ Note also that this can set chars_printed > chars_per_line
+ if we are printing a long string. */
+ chars_printed = strlen (wrap_indent)
+ + (save_chars - wrap_column);
+ wrap_pointer = wrap_buffer; /* Reset buffer */
+ wrap_buffer[0] = '\0';
+ wrap_column = 0; /* And disable fancy wrap */
+ }
+ }
+ }
+
+ if (*lineptr == '\n')
+ {
+ chars_printed = 0;
+ wrap_here ((char *) 0); /* Spit out chars, cancel further wraps */
+ lines_printed++;
+ fputc_unfiltered ('\n', stream);
+ lineptr++;
+ }
+ }
+}
+
+void
+fputs_filtered (linebuffer, stream)
+ const char *linebuffer;
+ GDB_FILE *stream;
+{
+ fputs_maybe_filtered (linebuffer, stream, 1);
+}
+
+int
+putchar_unfiltered (c)
+ int c;
+{
+ char buf = c;
+ gdb_file_write (gdb_stdout, &buf, 1);
+ return c;
+}
+
+int
+fputc_unfiltered (c, stream)
+ int c;
+ GDB_FILE *stream;
+{
+ char buf = c;
+ gdb_file_write (stream, &buf, 1);
+ return c;
+}
+
+int
+fputc_filtered (c, stream)
+ int c;
+ GDB_FILE *stream;
+{
+ char buf[2];
+
+ buf[0] = c;
+ buf[1] = 0;
+ fputs_filtered (buf, stream);
+ return c;
+}
+
+/* puts_debug is like fputs_unfiltered, except it prints special
+ characters in printable fashion. */
+
+void
+puts_debug (prefix, string, suffix)
+ char *prefix;
+ char *string;
+ char *suffix;
+{
+ int ch;
+
+ /* Print prefix and suffix after each line. */
+ static int new_line = 1;
+ static int return_p = 0;
+ static char *prev_prefix = "";
+ static char *prev_suffix = "";
+
+ if (*string == '\n')
+ return_p = 0;
+
+ /* If the prefix is changing, print the previous suffix, a new line,
+ and the new prefix. */
+ if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line)
+ {
+ fputs_unfiltered (prev_suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ fputs_unfiltered (prefix, gdb_stdlog);
+ }
+
+ /* Print prefix if we printed a newline during the previous call. */
+ if (new_line)
+ {
+ new_line = 0;
+ fputs_unfiltered (prefix, gdb_stdlog);
+ }
+
+ prev_prefix = prefix;
+ prev_suffix = suffix;
+
+ /* Output characters in a printable format. */
+ while ((ch = *string++) != '\0')
+ {
+ switch (ch)
+ {
+ default:
+ if (isprint (ch))
+ fputc_unfiltered (ch, gdb_stdlog);
+
+ else
+ fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff);
+ break;
+
+ case '\\':
+ fputs_unfiltered ("\\\\", gdb_stdlog);
+ break;
+ case '\b':
+ fputs_unfiltered ("\\b", gdb_stdlog);
+ break;
+ case '\f':
+ fputs_unfiltered ("\\f", gdb_stdlog);
+ break;
+ case '\n':
+ new_line = 1;
+ fputs_unfiltered ("\\n", gdb_stdlog);
+ break;
+ case '\r':
+ fputs_unfiltered ("\\r", gdb_stdlog);
+ break;
+ case '\t':
+ fputs_unfiltered ("\\t", gdb_stdlog);
+ break;
+ case '\v':
+ fputs_unfiltered ("\\v", gdb_stdlog);
+ break;
+ }
+
+ return_p = ch == '\r';
+ }
+
+ /* Print suffix if we printed a newline. */
+ if (new_line)
+ {
+ fputs_unfiltered (suffix, gdb_stdlog);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ }