From: Simon Marchi <simon.marchi@polymtl.ca>
To: Pedro Alves <palves@redhat.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 5/5] Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
Date: Tue, 17 Jan 2017 19:57:00 -0000 [thread overview]
Message-ID: <5533317a1fdb2e5f36e64731aef84993@polymtl.ca> (raw)
In-Reply-To: <1484617147-2506-6-git-send-email-palves@redhat.com>
I've only looked at ui-file.h/c so far, but overall it looks really
nice.
On 2017-01-16 20:39, Pedro Alves wrote:
> -static void
> -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. */
> - return;
> - else
> - {
> - /* The write method was implemented, use that. */
> - file->to_write (file, buf, strlen (buf));
> - }
> -}
> +\f
Is the insertion of a form feed character on purpose? I know it's
mentioned in the GNU coding style, but I was wondering if they were
useful to anybody today.
> diff --git a/gdb/ui-file.h b/gdb/ui-file.h
> index 4ad3940..f1951e4 100644
> --- a/gdb/ui-file.h
> +++ b/gdb/ui-file.h
> @@ -24,74 +24,86 @@ struct ui_file;
The forward declarations at the beginning of the file can go.
>
> #include <string>
>
> -/* Create a generic ui_file object with null methods. */
> -
> -extern struct ui_file *ui_file_new (void);
> -
> -/* Override methods used by specific implementations of a UI_FILE
> - object. */
> -
> -typedef void (ui_file_flush_ftype) (struct ui_file *stream);
> -extern void set_ui_file_flush (struct ui_file *stream,
> - ui_file_flush_ftype *flush);
> -
> -/* NOTE: Both fputs and write methods are available. Default
> - implementations that mapping one onto the other are included. */
> -typedef void (ui_file_write_ftype) (struct ui_file *stream,
> - const char *buf, long length_buf);
> -extern void set_ui_file_write (struct ui_file *stream,
> - ui_file_write_ftype *fputs);
> -
> -typedef void (ui_file_fputs_ftype) (const char *, struct ui_file
> *stream);
> -extern void set_ui_file_fputs (struct ui_file *stream,
> - ui_file_fputs_ftype *fputs);
> -
> -/* This version of "write" is safe for use in signal handlers.
> - It's not guaranteed that all existing output will have been
> - flushed first.
> - Implementations are also free to ignore some or all of the request.
> - fputs_async is not provided as the async versions are rarely used,
> - no point in having both for a rarely used interface. */
> -typedef void (ui_file_write_async_safe_ftype)
> - (struct ui_file *stream, const char *buf, long length_buf);
> -extern void set_ui_file_write_async_safe
> - (struct ui_file *stream, ui_file_write_async_safe_ftype
> *write_async_safe);
> -
> -typedef long (ui_file_read_ftype) (struct ui_file *stream,
> - char *buf, long length_buf);
> -extern void set_ui_file_read (struct ui_file *stream,
> - ui_file_read_ftype *fread);
> -
> -typedef int (ui_file_isatty_ftype) (struct ui_file *stream);
> -extern void set_ui_file_isatty (struct ui_file *stream,
> - ui_file_isatty_ftype *isatty);
> -
> -typedef void (ui_file_rewind_ftype) (struct ui_file *stream);
> -extern void set_ui_file_rewind (struct ui_file *stream,
> - ui_file_rewind_ftype *rewind);
> -
> typedef void (ui_file_put_method_ftype) (void *object, const char
> *buffer,
> long length_buffer);
This one can go too (actually you've marked it as deleted in the
changelog).
> -typedef void (ui_file_put_ftype) (struct ui_file *stream,
> - ui_file_put_method_ftype *method,
> - void *context);
> -extern void set_ui_file_put (struct ui_file *stream, ui_file_put_ftype
> *put);
>
> -typedef void (ui_file_delete_ftype) (struct ui_file * stream);
> -extern void set_ui_file_data (struct ui_file *stream, void *data,
> - ui_file_delete_ftype *to_delete);
> +/* The ui_file base class. */
>
> -typedef int (ui_file_fseek_ftype) (struct ui_file *stream, long
> offset,
> - int whence);
> -extern void set_ui_file_fseek (struct ui_file *stream,
> - ui_file_fseek_ftype *fseek_ptr);
> +class ui_file
> +{
> +public:
> + ui_file ();
> + virtual ~ui_file ();
>
> -extern void *ui_file_data (struct ui_file *file);
> + /* Public non-virtual API. */
>
> + void printf (const char *, ...) ATTRIBUTE_PRINTF (2, 3);
>
> -extern void gdb_flush (struct ui_file *);
> + /* Print a string whose delimiter is QUOTER. Note that these
> + routines should only be call for printing things which are
call -> called?
> + /* Rewind local buffer. I.e., clear it. */
> + virtual void rewind ()
> + {}
I'm not sure about the implications, but instinctively I would've made
rewind in the base class throw an exception by default, instead of
making the derived types throw one if they don't support rewind.
Actually, except for the null_file, I don't really see when you would
want rewind to be a no-op. If the rewind call returns but does not
actually rewind, isn't it lying to the client code?
>
> -extern void ui_file_delete (struct ui_file *stream);
> + /* Write contents of local buffer onto WRITE. */
> + virtual void write_buffer_on (ui_file &where)
Mismatch between parameter name and doc.
> + /* Provide a few convenience methods with the same API as the
> + underlying std::string. */
> + const char *data () const { return m_string.data (); }
> + const char *c_str () const { return m_string.c_str (); }
> + size_t size () const { return m_string.size (); }
> + bool empty () const;
I am wondering why you didn't implement empty inline like the others,
since it's very similar.
> +
> +private:
> + /* The internal buffer. */
> + std::string m_string;
> +};
> +
> +/* A ui_file implementation that maps directly onto <stdio.h>'s
> + FILE. */
> +
> +class stdio_file : public ui_file
> +{
> +public:
> + /* Create a ui_file from a previously opened FILE. If not CLOSE_P,
> + then behave like like fdopen(). */
"like like". It's also not very clear just saying "behave like
fdopen()". Could it be a bit more explicit?
> + explicit stdio_file (FILE *file, bool close_p = false);
> +
> + /* Create an stdio_file that is not managing any file yet. Call
> + open to actually open something. */
> + stdio_file ();
> +
> + ~stdio_file () override;
> +
> + /* Open NAME in mode MODE. Returns true on success, false
> + otherwise. Destroying the stdio_file closes the underlying FILE
> + handle. */
> + bool open (const char *name, const char *mode);
What happens if you try to reuse that object by calling open twice?
Does it leak an open file?
> +class tee_file : public ui_file
> +{
> +public:
> + /* Create a file which writes to both ONE and TWO. CLOSE_ONE and
> + CLOSE_TWO indicate whether the original files should be closed
> + when the new file is closed. */
> + tee_file (ui_file *one, bool close_one,
> + ui_file *two, bool close_two);
> + ~tee_file () override;
>
> -/* Open/create a STDIO based UI_FILE using the already open FILE. */
> -extern struct ui_file *stdio_fileopen (FILE *file);
> + void write (const char *buf, long length_buf) override;
> + void write_async_safe (const char *buf, long length_buf) override;
> + void puts (const char *) override;
>
> -/* Likewise, for stderr-like streams. */
> -extern struct ui_file *stderr_fileopen (FILE *file);
> + bool isatty () override;
> + void flush () override;
>
> + void rewind () override
> + { gdb_assert_not_reached ("tee_file::rewind called\n"); }
>
> -/* Open NAME returning an STDIO based UI_FILE. */
> -extern struct ui_file *gdb_fopen (const char *name, const char *mode);
> +private:
> + /* The two underlying ui_files, and whether they should each be
> + closed on destruction. */
> + struct ui_file *m_one, *m_two;
Nit: I'm a big fan of dropping the struct keyword.
Thanks,
Simon
next prev parent reply other threads:[~2017-01-17 19:57 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-17 1:39 [PATCH 0/5] Eliminate cleanups & make ui_file a C++ " Pedro Alves
2017-01-17 1:39 ` [PATCH 2/5] gdb/varobj.c: Fix leak Pedro Alves
2017-01-17 1:39 ` [PATCH 5/5] Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy Pedro Alves
2017-01-17 19:57 ` Simon Marchi [this message]
2017-01-17 19:58 ` Simon Marchi
2017-01-23 16:58 ` Pedro Alves
2017-01-23 17:17 ` Pedro Alves
2017-01-23 19:18 ` Simon Marchi
2017-01-23 23:19 ` [PATCH v2 " Pedro Alves
2017-01-24 18:29 ` Simon Marchi
2017-01-24 19:14 ` Simon Marchi
2017-01-25 18:37 ` Pedro Alves
2017-01-25 17:52 ` Pedro Alves
2017-01-25 19:31 ` Pedro Alves
2017-01-25 19:47 ` [PATCH v3 " Pedro Alves
2017-02-01 0:31 ` Pedro Alves
2017-01-25 18:27 ` [PATCH v2 " Pedro Alves
2017-01-24 19:11 ` Simon Marchi
2017-01-25 18:28 ` Pedro Alves
2017-01-25 18:39 ` Simon Marchi
2017-01-25 18:41 ` Pedro Alves
2017-01-17 1:39 ` [PATCH 1/5] gdb: make_scoped_restore and types convertible to T Pedro Alves
2017-01-17 1:39 ` [PATCH 3/5] gdb/stack.c: Remove unused mem_fileopen Pedro Alves
2017-01-17 1:47 ` [PATCH 4/5] gdb/mi/mi-interp.c: Fix typos Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5533317a1fdb2e5f36e64731aef84993@polymtl.ca \
--to=simon.marchi@polymtl.ca \
--cc=gdb-patches@sourceware.org \
--cc=palves@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox