X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fui-file.c;h=8528793c74de2d1547dd0c9b3acd0f9776114683;hb=55a8c0761da53ea56ce6e196110aa8e83dba248f;hp=d077009956a140754bc958bc9e330dc3c3b50968;hpb=72ec28b8afa357cdde70c612b4e0e9f37a34f8e4;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ui-file.c b/gdb/ui-file.c index d077009956..8528793c74 100644 --- a/gdb/ui-file.c +++ b/gdb/ui-file.c @@ -1,11 +1,12 @@ /* UI_FILE - a generic STDIO like output stream. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + Copyright (C) 1999-2002, 2007-2012 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,21 +15,23 @@ 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. */ + along with this program. If not, see . */ -/* Implement the ``struct ui_file'' object. */ +/* Implement the ``struct ui_file'' object. */ #include "defs.h" #include "ui-file.h" +#include "gdb_obstack.h" +#include "gdb_string.h" +#include "gdb_select.h" -#undef XMALLOC -#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) +#include static ui_file_isatty_ftype null_file_isatty; static ui_file_write_ftype null_file_write; +static ui_file_write_ftype null_file_write_async_safe; static ui_file_fputs_ftype null_file_fputs; +static ui_file_read_ftype null_file_read; static ui_file_flush_ftype null_file_flush; static ui_file_delete_ftype null_file_delete; static ui_file_rewind_ftype null_file_rewind; @@ -39,7 +42,9 @@ struct ui_file int *magic; ui_file_flush_ftype *to_flush; ui_file_write_ftype *to_write; + ui_file_write_async_safe_ftype *to_write_async_safe; ui_file_fputs_ftype *to_fputs; + ui_file_read_ftype *to_read; ui_file_delete_ftype *to_delete; ui_file_isatty_ftype *to_isatty; ui_file_rewind_ftype *to_rewind; @@ -49,14 +54,17 @@ struct ui_file int ui_file_magic; struct ui_file * -ui_file_new () +ui_file_new (void) { struct ui_file *file = xmalloc (sizeof (struct ui_file)); + file->magic = &ui_file_magic; set_ui_file_data (file, NULL, null_file_delete); set_ui_file_flush (file, null_file_flush); set_ui_file_write (file, null_file_write); + set_ui_file_write_async_safe (file, null_file_write_async_safe); set_ui_file_fputs (file, null_file_fputs); + set_ui_file_read (file, null_file_read); set_ui_file_isatty (file, null_file_isatty); set_ui_file_rewind (file, null_file_rewind); set_ui_file_put (file, null_file_put); @@ -64,23 +72,20 @@ ui_file_new () } void -ui_file_delete (file) - struct ui_file *file; +ui_file_delete (struct ui_file *file) { file->to_delete (file); - free (file); + xfree (file); } static int -null_file_isatty (file) - struct ui_file *file; +null_file_isatty (struct ui_file *file) { return 0; } static void -null_file_rewind (file) - struct ui_file *file; +null_file_rewind (struct ui_file *file) { return; } @@ -94,8 +99,7 @@ null_file_put (struct ui_file *file, } static void -null_file_flush (file) - struct ui_file *file; +null_file_flush (struct ui_file *file) { return; } @@ -106,8 +110,8 @@ null_file_write (struct ui_file *file, long sizeof_buf) { if (file->to_fputs == null_file_fputs) - /* Both the write and fputs methods are null. Discard the - request. */ + /* Both the write and fputs methods are null. Discard the + request. */ return; else { @@ -118,6 +122,7 @@ null_file_write (struct ui_file *file, is possible to clean up that code. */ int i; char b[2]; + b[1] = '\0'; for (i = 0; i < sizeof_buf; i++) { @@ -128,55 +133,66 @@ null_file_write (struct ui_file *file, } } +static long +null_file_read (struct ui_file *file, + char *buf, + long sizeof_buf) +{ + errno = EBADF; + return 0; +} + static void -null_file_fputs (buf, file) - const char *buf; - struct ui_file *file; +null_file_fputs (const char *buf, struct ui_file *file) { if (file->to_write == null_file_write) - /* Both the write and fputs methods are null. Discard the - request. */ + /* Both the write and fputs methods are null. Discard the + request. */ return; else { - /* The write method was implemented, use that. */ + /* The write method was implemented, use that. */ file->to_write (file, buf, strlen (buf)); } } static void -null_file_delete (file) - struct ui_file *file; +null_file_write_async_safe (struct ui_file *file, + const char *buf, + long sizeof_buf) +{ + return; +} + +static void +null_file_delete (struct ui_file *file) { return; } void * -ui_file_data (file) - struct ui_file *file; +ui_file_data (struct ui_file *file) { if (file->magic != &ui_file_magic) - internal_error ("ui_file_data: bad magic number"); + internal_error (__FILE__, __LINE__, + _("ui_file_data: bad magic number")); return file->to_data; } void -gdb_flush (file) - struct ui_file *file; +gdb_flush (struct ui_file *file) { file->to_flush (file); } int -ui_file_isatty (file) - struct ui_file *file; +ui_file_isatty (struct ui_file *file) { return file->to_isatty (file); } void -ui_file_rewind (file) - struct ui_file *file; +ui_file_rewind (struct ui_file *file) { file->to_rewind (file); } @@ -198,41 +214,45 @@ ui_file_write (struct ui_file *file, } void -fputs_unfiltered (buf, file) - const char *buf; - struct ui_file *file; +ui_file_write_async_safe (struct ui_file *file, + const char *buf, + long length_buf) +{ + file->to_write_async_safe (file, buf, length_buf); +} + +long +ui_file_read (struct ui_file *file, char *buf, long length_buf) +{ + return file->to_read (file, buf, length_buf); +} + +void +fputs_unfiltered (const char *buf, struct ui_file *file) { file->to_fputs (buf, file); } void -set_ui_file_flush (file, flush) - struct ui_file *file; - ui_file_flush_ftype *flush; +set_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush) { file->to_flush = flush; } void -set_ui_file_isatty (file, isatty) - struct ui_file *file; - ui_file_isatty_ftype *isatty; +set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty) { file->to_isatty = isatty; } void -set_ui_file_rewind (file, rewind) - struct ui_file *file; - ui_file_rewind_ftype *rewind; +set_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind) { file->to_rewind = rewind; } void -set_ui_file_put (file, put) - struct ui_file *file; - ui_file_put_ftype *put; +set_ui_file_put (struct ui_file *file, ui_file_put_ftype *put) { file->to_put = put; } @@ -245,25 +265,34 @@ set_ui_file_write (struct ui_file *file, } void -set_ui_file_fputs (file, fputs) - struct ui_file *file; - ui_file_fputs_ftype *fputs; +set_ui_file_write_async_safe (struct ui_file *file, + ui_file_write_async_safe_ftype *write_async_safe) +{ + file->to_write_async_safe = write_async_safe; +} + +void +set_ui_file_read (struct ui_file *file, ui_file_read_ftype *read) +{ + file->to_read = read; +} + +void +set_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs) { file->to_fputs = fputs; } void -set_ui_file_data (file, data, delete) - struct ui_file *file; - void *data; - ui_file_delete_ftype *delete; +set_ui_file_data (struct ui_file *file, void *data, + ui_file_delete_ftype *delete) { file->to_data = data; file->to_delete = delete; } /* ui_file utility function for converting a ``struct ui_file'' into - a memory buffer''. */ + a memory buffer. */ struct accumulated_ui_file { @@ -275,6 +304,7 @@ static void do_ui_file_xstrdup (void *context, const char *buffer, long length) { struct accumulated_ui_file *acc = context; + if (acc->buffer == NULL) acc->buffer = xmalloc (length + 1); else @@ -285,22 +315,41 @@ do_ui_file_xstrdup (void *context, const char *buffer, long length) } char * -ui_file_xstrdup (struct ui_file *file, - long *length) +ui_file_xstrdup (struct ui_file *file, long *length) { struct accumulated_ui_file acc; + acc.buffer = NULL; acc.length = 0; ui_file_put (file, do_ui_file_xstrdup, &acc); if (acc.buffer == NULL) acc.buffer = xstrdup (""); - *length = acc.length; + if (length != NULL) + *length = acc.length; return acc.buffer; } + +static void +do_ui_file_obsavestring (void *context, const char *buffer, long length) +{ + struct obstack *obstack = (struct obstack *) context; + + obstack_grow (obstack, buffer, length); +} + +char * +ui_file_obsavestring (struct ui_file *file, struct obstack *obstack, + long *length) +{ + ui_file_put (file, do_ui_file_obsavestring, obstack); + *length = obstack_object_size (obstack); + obstack_1grow (obstack, '\0'); + return obstack_finish (obstack); +} /* A pure memory based ``struct ui_file'' that can be used an output - buffer. The buffers accumulated contents are available via - ui_file_put(). */ + buffer. The buffers accumulated contents are available via + ui_file_put(). */ struct mem_file { @@ -314,7 +363,7 @@ static ui_file_rewind_ftype mem_file_rewind; static ui_file_put_ftype mem_file_put; static ui_file_write_ftype mem_file_write; static ui_file_delete_ftype mem_file_delete; -static struct ui_file *mem_file_new PARAMS ((void)); +static struct ui_file *mem_file_new (void); static int mem_file_magic; static struct ui_file * @@ -322,6 +371,7 @@ mem_file_new (void) { struct mem_file *stream = XMALLOC (struct mem_file); struct ui_file *file = ui_file_new (); + set_ui_file_data (file, stream, mem_file_delete); set_ui_file_rewind (file, mem_file_rewind); set_ui_file_put (file, mem_file_put); @@ -337,11 +387,13 @@ static void mem_file_delete (struct ui_file *file) { struct mem_file *stream = ui_file_data (file); + if (stream->magic != &mem_file_magic) - internal_error ("mem_file_delete: bad magic number"); + internal_error (__FILE__, __LINE__, + _("mem_file_delete: bad magic number")); if (stream->buffer != NULL) - free (stream->buffer); - free (stream); + xfree (stream->buffer); + xfree (stream); } struct ui_file * @@ -354,8 +406,10 @@ static void mem_file_rewind (struct ui_file *file) { struct mem_file *stream = ui_file_data (file); + if (stream->magic != &mem_file_magic) - internal_error ("mem_file_rewind: bad magic number"); + internal_error (__FILE__, __LINE__, + _("mem_file_rewind: bad magic number")); stream->length_buffer = 0; } @@ -365,8 +419,10 @@ mem_file_put (struct ui_file *file, void *dest) { struct mem_file *stream = ui_file_data (file); + if (stream->magic != &mem_file_magic) - internal_error ("mem_file_put: bad magic number"); + internal_error (__FILE__, __LINE__, + _("mem_file_put: bad magic number")); if (stream->length_buffer > 0) write (dest, stream->buffer, stream->length_buffer); } @@ -377,8 +433,10 @@ mem_file_write (struct ui_file *file, long length_buffer) { struct mem_file *stream = ui_file_data (file); + if (stream->magic != &mem_file_magic) - internal_error ("mem_file_write: bad magic number"); + internal_error (__FILE__, __LINE__, + _("mem_file_write: bad magic number")); if (stream->buffer == NULL) { stream->length_buffer = length_buffer; @@ -389,6 +447,7 @@ mem_file_write (struct ui_file *file, else { int new_length = stream->length_buffer + length_buffer; + if (new_length >= stream->sizeof_buffer) { stream->sizeof_buffer = new_length; @@ -400,13 +459,15 @@ mem_file_write (struct ui_file *file, } /* ``struct ui_file'' implementation that maps directly onto - 's FILE. */ + 's FILE. */ static ui_file_write_ftype stdio_file_write; +static ui_file_write_async_safe_ftype stdio_file_write_async_safe; static ui_file_fputs_ftype stdio_file_fputs; +static ui_file_read_ftype stdio_file_read; static ui_file_isatty_ftype stdio_file_isatty; static ui_file_delete_ftype stdio_file_delete; -static struct ui_file *stdio_file_new PARAMS ((FILE * file, int close_p)); +static struct ui_file *stdio_file_new (FILE *file, int close_p); static ui_file_flush_ftype stdio_file_flush; static int stdio_file_magic; @@ -415,97 +476,255 @@ struct stdio_file { int *magic; FILE *file; + /* The associated file descriptor is extracted ahead of time for + stdio_file_write_async_safe's benefit, in case fileno isn't async-safe. */ + int fd; int close_p; }; static struct ui_file * -stdio_file_new (file, close_p) - FILE *file; - int close_p; +stdio_file_new (FILE *file, int close_p) { struct ui_file *ui_file = ui_file_new (); struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file)); + stdio->magic = &stdio_file_magic; stdio->file = file; + stdio->fd = fileno (file); stdio->close_p = close_p; set_ui_file_data (ui_file, stdio, stdio_file_delete); set_ui_file_flush (ui_file, stdio_file_flush); set_ui_file_write (ui_file, stdio_file_write); + set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe); set_ui_file_fputs (ui_file, stdio_file_fputs); + set_ui_file_read (ui_file, stdio_file_read); set_ui_file_isatty (ui_file, stdio_file_isatty); return ui_file; } static void -stdio_file_delete (file) - struct ui_file *file; +stdio_file_delete (struct ui_file *file) { struct stdio_file *stdio = ui_file_data (file); + if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_delete: bad magic number"); + internal_error (__FILE__, __LINE__, + _("stdio_file_delete: bad magic number")); if (stdio->close_p) { fclose (stdio->file); } - free (stdio); + xfree (stdio); } static void -stdio_file_flush (file) - struct ui_file *file; +stdio_file_flush (struct ui_file *file) { struct stdio_file *stdio = ui_file_data (file); + if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_flush: bad magic number"); + internal_error (__FILE__, __LINE__, + _("stdio_file_flush: bad magic number")); fflush (stdio->file); } +static long +stdio_file_read (struct ui_file *file, char *buf, long length_buf) +{ + struct stdio_file *stdio = ui_file_data (file); + + if (stdio->magic != &stdio_file_magic) + internal_error (__FILE__, __LINE__, + _("stdio_file_read: bad magic number")); + + /* For the benefit of Windows, call gdb_select before reading from + the file. Wait until at least one byte of data is available. + Control-C can interrupt gdb_select, but not read. */ + { + fd_set readfds; + FD_ZERO (&readfds); + FD_SET (stdio->fd, &readfds); + if (gdb_select (stdio->fd + 1, &readfds, NULL, NULL, NULL) == -1) + return -1; + } + + return read (stdio->fd, buf, length_buf); +} + static void stdio_file_write (struct ui_file *file, const char *buf, long length_buf) { struct stdio_file *stdio = ui_file_data (file); + + if (stdio->magic != &stdio_file_magic) + internal_error (__FILE__, __LINE__, + _("stdio_file_write: bad magic number")); + /* Calling error crashes when we are called from the exception framework. */ + if (fwrite (buf, length_buf, 1, stdio->file)) + ; +} + +static void +stdio_file_write_async_safe (struct ui_file *file, + const char *buf, long length_buf) +{ + struct stdio_file *stdio = ui_file_data (file); + if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_write: bad magic number"); - fwrite (buf, length_buf, 1, stdio->file); + { + /* gettext isn't necessarily async safe, so we can't use _("error message") here. + We could extract the correct translation ahead of time, but this is an extremely + rare event, and one of the other stdio_file_* routines will presumably catch + the problem anyway. For now keep it simple and ignore the error here. */ + return; + } + + /* This is written the way it is to avoid a warning from gcc about not using the + result of write (since it can be declared with attribute warn_unused_result). + Alas casting to void doesn't work for this. */ + if (write (stdio->fd, buf, length_buf)) + ; } static void -stdio_file_fputs (linebuffer, file) - const char *linebuffer; - struct ui_file *file; +stdio_file_fputs (const char *linebuffer, struct ui_file *file) { struct stdio_file *stdio = ui_file_data (file); + if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_fputs: bad magic number"); - fputs (linebuffer, stdio->file); + internal_error (__FILE__, __LINE__, + _("stdio_file_fputs: bad magic number")); + /* Calling error crashes when we are called from the exception framework. */ + if (fputs (linebuffer, stdio->file)) + ; } static int -stdio_file_isatty (file) - struct ui_file *file; +stdio_file_isatty (struct ui_file *file) { struct stdio_file *stdio = ui_file_data (file); + if (stdio->magic != &stdio_file_magic) - internal_error ("stdio_file_isatty: bad magic number"); - return (isatty (fileno (stdio->file))); + internal_error (__FILE__, __LINE__, + _("stdio_file_isatty: bad magic number")); + return (isatty (stdio->fd)); } -/* Like fdopen(). Create a ui_file from a previously opened FILE. */ +/* Like fdopen(). Create a ui_file from a previously opened FILE. */ struct ui_file * -stdio_fileopen (file) - FILE *file; +stdio_fileopen (FILE *file) { return stdio_file_new (file, 0); } struct ui_file * -gdb_fopen (name, mode) - char *name; - char *mode; +gdb_fopen (char *name, char *mode) { FILE *f = fopen (name, mode); + if (f == NULL) return NULL; return stdio_file_new (f, 1); } + +/* ``struct ui_file'' implementation that maps onto two ui-file objects. */ + +static ui_file_write_ftype tee_file_write; +static ui_file_fputs_ftype tee_file_fputs; +static ui_file_isatty_ftype tee_file_isatty; +static ui_file_delete_ftype tee_file_delete; +static ui_file_flush_ftype tee_file_flush; + +static int tee_file_magic; + +struct tee_file + { + int *magic; + struct ui_file *one, *two; + int close_one, close_two; + }; + +struct ui_file * +tee_file_new (struct ui_file *one, int close_one, + struct ui_file *two, int close_two) +{ + struct ui_file *ui_file = ui_file_new (); + struct tee_file *tee = xmalloc (sizeof (struct tee_file)); + + tee->magic = &tee_file_magic; + tee->one = one; + tee->two = two; + tee->close_one = close_one; + tee->close_two = close_two; + set_ui_file_data (ui_file, tee, tee_file_delete); + set_ui_file_flush (ui_file, tee_file_flush); + set_ui_file_write (ui_file, tee_file_write); + set_ui_file_fputs (ui_file, tee_file_fputs); + set_ui_file_isatty (ui_file, tee_file_isatty); + return ui_file; +} + +static void +tee_file_delete (struct ui_file *file) +{ + struct tee_file *tee = ui_file_data (file); + + if (tee->magic != &tee_file_magic) + internal_error (__FILE__, __LINE__, + _("tee_file_delete: bad magic number")); + if (tee->close_one) + ui_file_delete (tee->one); + if (tee->close_two) + ui_file_delete (tee->two); + + xfree (tee); +} + +static void +tee_file_flush (struct ui_file *file) +{ + struct tee_file *tee = ui_file_data (file); + + if (tee->magic != &tee_file_magic) + internal_error (__FILE__, __LINE__, + _("tee_file_flush: bad magic number")); + tee->one->to_flush (tee->one); + tee->two->to_flush (tee->two); +} + +static void +tee_file_write (struct ui_file *file, const char *buf, long length_buf) +{ + struct tee_file *tee = ui_file_data (file); + + if (tee->magic != &tee_file_magic) + internal_error (__FILE__, __LINE__, + _("tee_file_write: bad magic number")); + ui_file_write (tee->one, buf, length_buf); + ui_file_write (tee->two, buf, length_buf); +} + +static void +tee_file_fputs (const char *linebuffer, struct ui_file *file) +{ + struct tee_file *tee = ui_file_data (file); + + if (tee->magic != &tee_file_magic) + internal_error (__FILE__, __LINE__, + _("tee_file_fputs: bad magic number")); + tee->one->to_fputs (linebuffer, tee->one); + tee->two->to_fputs (linebuffer, tee->two); +} + +static int +tee_file_isatty (struct ui_file *file) +{ + struct tee_file *tee = ui_file_data (file); + + if (tee->magic != &tee_file_magic) + internal_error (__FILE__, __LINE__, + _("tee_file_isatty: bad magic number")); + + return ui_file_isatty (tee->one); +}