From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gproxy3-pub.mail.unifiedlayer.com (gproxy3-pub.mail.unifiedlayer.com [69.89.30.42]) by sourceware.org (Postfix) with ESMTPS id 09724385AC31 for ; Thu, 17 Feb 2022 22:05:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 09724385AC31 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tromey.com Received: from cmgw15.mail.unifiedlayer.com (unknown [10.0.90.130]) by progateway5.mail.pro1.eigbox.com (Postfix) with ESMTP id 6ACF210047BD3 for ; Thu, 17 Feb 2022 22:05:53 +0000 (UTC) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with ESMTP id KouOn7CSskku4KouPnOTtd; Thu, 17 Feb 2022 22:05:53 +0000 X-Authority-Reason: nr=8 X-Authority-Analysis: v=2.4 cv=LOaj/La9 c=1 sm=1 tr=0 ts=620ec6c1 a=ApxJNpeYhEAb1aAlGBBbmA==:117 a=ApxJNpeYhEAb1aAlGBBbmA==:17 a=dLZJa+xiwSxG16/P+YVxDGlgEgI=:19 a=oGFeUVbbRNcA:10:nop_rcvd_month_year a=Qbun_eYptAEA:10:endurance_base64_authed_username_1 a=IVgVhQ2OxdhZNHevmPQA:9 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=sAr98qsR3fUbeqwe49CNKcKVY//fHbz2/i6YY+6X+Gs=; b=tOVUToMymBTUu9JEh/ZErJ/Usw c7wcagItrWmzPWCnc6cAt8pkgQ+wIkYShZlmUDo34aBFps5GJZFF2dByeucOTB5lXK4oJG0iVgCbR 3eoMmPqhiYMRAuP8+nHPj+mIs; Received: from 75-166-146-214.hlrn.qwest.net ([75.166.146.214]:41038 helo=prentzel.Home) by box5379.bluehost.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nKouO-002ABb-Ft; Thu, 17 Feb 2022 15:05:52 -0700 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH v2 11/18] Add an emitter callback to generic_printstr and generic_emit_char Date: Thu, 17 Feb 2022 15:05:39 -0700 Message-Id: <20220217220547.3874030-12-tom@tromey.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220217220547.3874030-1-tom@tromey.com> References: <20220217220547.3874030-1-tom@tromey.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - sourceware.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 75.166.146.214 X-Source-L: No X-Exim-ID: 1nKouO-002ABb-Ft X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 75-166-146-214.hlrn.qwest.net (prentzel.Home) [75.166.146.214]:41038 X-Source-Auth: tom+tromey.com X-Email-Count: 17 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-Spam-Status: No, score=-3031.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 17 Feb 2022 22:05:56 -0000 This adds an emitter callback to generic_printstr and generic_emit_char. print_wchar is renamed, exported, and modified to be suitable for use as the default emitter. This will be used to let languages override the way that escape sequences are emitted. Nothing uses this yet, that comes later in the series. --- gdb/valprint.c | 134 ++++++++++++++++++++++--------------------------- gdb/valprint.h | 65 +++++++++++++++++++++++- 2 files changed, 122 insertions(+), 77 deletions(-) diff --git a/gdb/valprint.c b/gdb/valprint.c index 2d90f61e297..ecb9b3c9871 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -2163,45 +2163,16 @@ wchar_printable (gdb_wchar_t w) || w == LCST ('\v') || w == LCST ('\0')); } -/* A ui_file that writes wide characters to an obstack. */ -class obstack_wide_file : public ui_file -{ -public: - explicit obstack_wide_file (struct obstack *output) - : m_output (output) - { - } - - ~obstack_wide_file () = default; - - void write (const char *buf, long length_buf) override - { - for (long i = 0; i < length_buf; ++i) - { - gdb_wchar_t w = gdb_btowc (buf[i]); - obstack_grow (m_output, &w, sizeof (gdb_wchar_t)); - } - } - -private: - struct obstack *m_output; -}; - -/* Print a wide character W to OUTPUT. ORIG is a pointer to the - original (target) bytes representing the character, ORIG_LEN is the - number of valid bytes. WIDTH is the number of bytes in a base - characters of the type. OUTPUT is an obstack to which wide - characters are emitted. QUOTER is a (narrow) character indicating - the style of quotes surrounding the character to be printed. - NEED_ESCAPE is an in/out flag which is used to track numeric - escapes across calls. */ +/* See valprint.h. */ -static void -print_wchar (gdb_wint_t w, const gdb_byte *orig, - int orig_len, int width, - enum bfd_endian byte_order, - struct obstack *output, - int quoter, bool *need_escapep) +void +default_emit_wchar (obstack_wide_file *stream, + gdb_wint_t w, + gdb::array_view orig, + int width, + enum bfd_endian byte_order, + int quoter, + bool *need_escapep) { bool need_escape = *need_escapep; @@ -2210,64 +2181,61 @@ print_wchar (gdb_wint_t w, const gdb_byte *orig, switch (w) { case LCST ('\a'): - obstack_grow_wstr (output, LCST ("\\a")); + fputs_filtered ("\\a", stream); break; case LCST ('\b'): - obstack_grow_wstr (output, LCST ("\\b")); + fputs_filtered ("\\b", stream); break; case LCST ('\f'): - obstack_grow_wstr (output, LCST ("\\f")); + fputs_filtered ("\\f", stream); break; case LCST ('\n'): - obstack_grow_wstr (output, LCST ("\\n")); + fputs_filtered ("\\n", stream); break; case LCST ('\r'): - obstack_grow_wstr (output, LCST ("\\r")); + fputs_filtered ("\\r", stream); break; case LCST ('\t'): - obstack_grow_wstr (output, LCST ("\\t")); + fputs_filtered ("\\t", stream); break; case LCST ('\v'): - obstack_grow_wstr (output, LCST ("\\v")); + fputs_filtered ("\\v", stream); break; default: { if (gdb_iswprint (w) && !(need_escape && gdb_iswxdigit (w))) { - gdb_wchar_t wchar = w; - if (w == gdb_btowc (quoter) || w == LCST ('\\')) - obstack_grow_wstr (output, LCST ("\\")); - obstack_grow (output, &wchar, sizeof (gdb_wchar_t)); + fputs_filtered ("\\", stream); + stream->write_wide_char (w); } else { int i; - obstack_wide_file file (output); - for (i = 0; i + width <= orig_len; i += width) + for (i = 0; i + width <= orig.size (); i += width) { ULONGEST value; value = extract_unsigned_integer (&orig[i], width, - byte_order); + byte_order); /* If the value fits in 3 octal digits, print it that way. Otherwise, print it as a hex escape. */ if (value <= 0777) { - fprintf_filtered (&file, "\\%.3o", (int) (value & 0777)); + fprintf_filtered (stream, "\\%.3o", (int) (value & 0777)); *need_escapep = false; } else { - fprintf_filtered (&file, "\\x%lx", (long) value); + fprintf_filtered (stream, "\\x%lx", (long) value); *need_escapep = true; } } /* If we somehow have extra bytes, print them now. */ - while (i < orig_len) + while (i < orig.size ()) { - fprintf_filtered (&file, "\\%.3o", orig[i] & 0xff); + fprintf_filtered (stream, "\\%.3o", orig[i] & 0xff); *need_escapep = false; ++i; } @@ -2283,7 +2251,8 @@ print_wchar (gdb_wint_t w, const gdb_byte *orig, void generic_emit_char (int c, struct type *type, struct ui_file *stream, - int quoter, const char *encoding) + int quoter, const char *encoding, + emit_char_ftype emitter) { enum bfd_endian byte_order = type_byte_order (type); @@ -2297,6 +2266,7 @@ generic_emit_char (int c, struct type *type, struct ui_file *stream, /* This holds the printable form of the wchar_t data. */ auto_obstack wchar_buf; + obstack_wide_file wchar_stream (&wchar_buf); while (1) { @@ -2330,16 +2300,17 @@ generic_emit_char (int c, struct type *type, struct ui_file *stream, if (!print_escape) { for (i = 0; i < num_chars; ++i) - print_wchar (chars[i], buf, buflen, - TYPE_LENGTH (type), byte_order, - &wchar_buf, quoter, &need_escape); + emitter (&wchar_stream, chars[i], + gdb::make_array_view (buf, buflen), + TYPE_LENGTH (type), byte_order, + quoter, &need_escape); } } /* This handles the NUM_CHARS == 0 case as well. */ if (print_escape) - print_wchar (gdb_WEOF, buf, buflen, TYPE_LENGTH (type), - byte_order, &wchar_buf, quoter, &need_escape); + emitter (&wchar_stream, gdb_WEOF, gdb::make_array_view (buf, buflen), + TYPE_LENGTH (type), byte_order, quoter, &need_escape); } /* The output in the host encoding. */ @@ -2447,7 +2418,8 @@ print_converted_chars_to_obstack (struct obstack *obstack, const std::vector &chars, int quote_char, int width, enum bfd_endian byte_order, - const struct value_print_options *options) + const struct value_print_options *options, + emit_char_ftype emitter) { unsigned int idx; const converted_character *elem; @@ -2483,15 +2455,19 @@ print_converted_chars_to_obstack (struct obstack *obstack, obstack_grow_wstr (obstack, LCST (", ")); obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t)); } + + obstack_wide_file wchar_stream (obstack); /* Output the character. */ for (j = 0; j < elem->repeat_count; ++j) { if (elem->result == wchar_iterate_ok) - print_wchar (elem->chars[0], elem->buf, elem->buflen, width, - byte_order, obstack, quote_char, &need_escape); + emitter (&wchar_stream, elem->chars[0], + gdb::make_array_view (elem->buf, elem->buflen), + width, byte_order, quote_char, &need_escape); else - print_wchar (gdb_WEOF, elem->buf, elem->buflen, width, - byte_order, obstack, quote_char, &need_escape); + emitter (&wchar_stream, gdb_WEOF, + gdb::make_array_view (elem->buf, elem->buflen), + width, byte_order, quote_char, &need_escape); } } break; @@ -2514,12 +2490,15 @@ print_converted_chars_to_obstack (struct obstack *obstack, /* Output the character and repeat string. */ obstack_grow_wstr (obstack, LCST ("'")); + obstack_wide_file wchar_stream (obstack); if (elem->result == wchar_iterate_ok) - print_wchar (elem->chars[0], elem->buf, elem->buflen, width, - byte_order, obstack, quote_char, &need_escape); + emitter (&wchar_stream, elem->chars[0], + gdb::make_array_view (elem->buf, elem->buflen), + width, byte_order, quote_char, &need_escape); else - print_wchar (gdb_WEOF, elem->buf, elem->buflen, width, - byte_order, obstack, quote_char, &need_escape); + emitter (&wchar_stream, gdb_WEOF, + gdb::make_array_view (elem->buf, elem->buflen), + width, byte_order, quote_char, &need_escape); obstack_grow_wstr (obstack, LCST ("'")); std::string s = string_printf (_(" "), elem->repeat_count); @@ -2544,8 +2523,12 @@ print_converted_chars_to_obstack (struct obstack *obstack, /* Output the incomplete sequence string. */ obstack_grow_wstr (obstack, LCST ("buf, elem->buflen, width, byte_order, - obstack, 0, &need_escape); + { + obstack_wide_file wchar_stream (obstack); + emitter (&wchar_stream, gdb_WEOF, + gdb::make_array_view (elem->buf, elem->buflen), + width, byte_order, 0, &need_escape); + } obstack_grow_wstr (obstack, LCST (">")); /* We do not attempt to output anything after this. */ @@ -2604,7 +2587,8 @@ generic_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, unsigned int length, const char *encoding, int force_ellipses, int quote_char, int c_style_terminator, - const struct value_print_options *options) + const struct value_print_options *options, + emit_char_ftype emitter) { enum bfd_endian byte_order = type_byte_order (type); unsigned int i; @@ -2680,7 +2664,7 @@ generic_printstr (struct ui_file *stream, struct type *type, /* Print the output string to the obstack. */ print_converted_chars_to_obstack (&wchar_buf, converted_chars, quote_char, - width, byte_order, options); + width, byte_order, options, emitter); if (force_ellipses || !finished) obstack_grow_wstr (&wchar_buf, LCST ("...")); diff --git a/gdb/valprint.h b/gdb/valprint.h index 0586836f9e6..0dbdef06c4c 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -233,14 +233,75 @@ extern void generic_value_print (struct value *val, struct ui_file *stream, const struct value_print_options *options, const struct generic_val_print_decorations *d); +/* A ui_file that writes wide characters to an obstack. */ +class obstack_wide_file : public ui_file +{ +public: + explicit obstack_wide_file (struct obstack *output) + : m_output (output) + { + } + + ~obstack_wide_file () = default; + + void write (const char *buf, long length_buf) override + { + for (long i = 0; i < length_buf; ++i) + { + gdb_wchar_t w = gdb_btowc (buf[i]); + obstack_grow (m_output, &w, sizeof (gdb_wchar_t)); + } + } + + void write_wide_char (gdb_wchar_t w) + { + obstack_grow (m_output, &w, sizeof (gdb_wchar_t)); + } + +private: + struct obstack *m_output; +}; + +/* A callback that can be used to print a representation of a wide + character to a stream. + STREAM is the stream to write to. + W is the character. It might be gdb_WEOF, meaning an unconvertible + sequence. + ORIG is the original (target) bytes corresponding to W. + WIDTH is the width of a base character in the encoding. + BYTE_ORDER is the character type's byte order. + QUOTER is the quote character used -- this is a host character. + NEED_ESCAPEP is used to track whether emitting this character may + require a subsequent character to be escaped. */ +typedef gdb::function_view orig, + int width, + enum bfd_endian byte_order, + int quoter, + bool *need_escapep)> emit_char_ftype; + +/* A function suitable for use as a character emitter, that emits + characters in the C style. */ + +extern void default_emit_wchar (obstack_wide_file *stream, + gdb_wint_t w, + gdb::array_view orig, + int width, + enum bfd_endian byte_order, + int quoter, + bool *need_escapep); + extern void generic_emit_char (int c, struct type *type, struct ui_file *stream, - int quoter, const char *encoding); + int quoter, const char *encoding, + emit_char_ftype emitter = default_emit_wchar); extern void generic_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, unsigned int length, const char *encoding, int force_ellipses, int quote_char, int c_style_terminator, - const struct value_print_options *options); + const struct value_print_options *options, + emit_char_ftype emitter = default_emit_wchar); /* Run the "output" command. ARGS and FROM_TTY are the usual arguments passed to all command implementations, except ARGS is -- 2.31.1