new file mode 100644
@@ -0,0 +1,199 @@
+/* Character and string printing
+
+ Copyright (C) 2025 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GDB_CHAR_PRINT_H
+#define GDB_CHAR_PRINT_H
+
+#include "gdb_wchar.h"
+#include "ui-file.h"
+#include "charset.h"
+
+/* 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 (gdb_wchar_t w)
+ {
+ obstack_grow (m_output, &w, sizeof (gdb_wchar_t));
+ }
+
+ void write (const gdb_wchar_t *str)
+ {
+ obstack_grow (m_output, str, sizeof (gdb_wchar_t) * gdb_wcslen (str));
+ }
+
+private:
+ struct obstack *m_output;
+};
+
+/* A class that handles display of a character or string. The object
+ is printed as if it were a literal in the source language. This
+ class implements C-like syntax, but can be subclassed for other
+ languages. */
+class wchar_printer
+{
+private:
+
+ /* Helper function to get a default encoding based on CHTYPE. */
+ static const char *get_default_encoding (type *chtype);
+
+public:
+
+ /* Constructor. CH_TYPE is the type of the underlying character.
+ QUOTER is a (narrow) character that is the quote to print,
+ e.g. '\'' or '"' for C. ENCODING is the encoding to use for the
+ contents; if NULL then a default is chosen based on CH_TYPE. */
+ wchar_printer (type *ch_type, int quoter, const char *encoding = nullptr)
+ : m_wchar_buf (),
+ m_encoding (encoding == nullptr
+ ? get_default_encoding (ch_type)
+ : encoding),
+ m_byte_order (type_byte_order (ch_type)),
+ m_file (&m_wchar_buf),
+ m_quoter (quoter),
+ m_width (ch_type->length ()),
+ m_type (ch_type)
+ {
+ }
+
+ /* Print a target character, C, to STREAM. The character is printed
+ as if it were a character literal; that is, surrounded by the
+ appropriate quotes for the language, and escaped as needed. */
+ void print (int c, ui_file *stream);
+
+ /* Print the character string STRING, printing at most LENGTH
+ characters. LENGTH is -1 if the string is nul terminated.
+ OPTIONS holds the printing options; printing stops early if the
+ number hits print_max_chars; repeat counts are printed as
+ appropriate. Print ellipses at the end if we had to stop before
+ printing LENGTH characters, or if FORCE_ELLIPSES. If
+ C_STYLE_TERMINATOR is true, and the last character is 0, then it
+ is omitted. */
+ void print (struct ui_file *stream, const gdb_byte *string,
+ unsigned int length, int force_ellipses,
+ int c_style_terminator,
+ const struct value_print_options *options);
+
+protected:
+
+ /* Return true if W is printable. This must agree with do_print in
+ the sense that if printable returns true, then do_print is
+ assumed to not emit an escape sequence for that character.
+ "Printable" means that either the character is printed as-is, or
+ that it is printed as a known short escape sequence, like
+ "\\". */
+ virtual bool printable (gdb_wchar_t w) const;
+
+ /* Print a wide character W. This is called for characters where
+ 'printable' returns true. */
+ virtual void print_char (gdb_wchar_t w);
+
+ /* Print an escape sequence for a character. ORIG is a pointer to
+ the original (target) bytes representing the character, ORIG_LEN
+ is the number of valid bytes. W might be gdb_WEOF, in which case
+ an escape sequence for the bytes given by ORIG must be
+ printed. */
+ virtual void print_escape (const gdb_byte *orig, int orig_len);
+
+ /* Maximum number of wchars returned from wchar_iterate. */
+ static constexpr int MAX_WCHARS = 4;
+
+ /* A structure to encapsulate state information from iterated
+ character conversions. */
+ struct converted_character
+ {
+ /* The number of characters converted. */
+ int num_chars;
+
+ /* The result of the conversion. See charset.h for more. */
+ enum wchar_iterate_result result;
+
+ /* The (saved) converted character(s). */
+ gdb_wchar_t chars[MAX_WCHARS];
+
+ /* The first converted target byte. */
+ const gdb_byte *buf;
+
+ /* The number of bytes converted. */
+ size_t buflen;
+
+ /* How many times this character(s) is repeated. */
+ int repeat_count;
+ };
+
+ /* Return the repeat count of the next character/byte in ITER,
+ storing the result in VEC. */
+ int count_next_character (wchar_iterator *iter,
+ std::vector<converted_character> *vec);
+
+ /* Print the characters in CHARS. OPTIONS is the user's print
+ options. *FINISHED is set to 0 if we didn't print all the
+ elements in CHARS. */
+ void print_converted_chars_to_obstack
+ (const std::vector<converted_character> &chars,
+ const struct value_print_options *options,
+ int *finished);
+
+private:
+
+ /* Intermediate output is stored here. */
+ auto_obstack m_wchar_buf;
+ /* The encoding. */
+ const char *m_encoding;
+
+protected:
+
+ /* Byte order for the character type. */
+ bfd_endian m_byte_order;
+ /* The intermediate output file. "print" implementations should
+ write to this file. */
+ obstack_wide_file m_file;
+ /* The current quote character. */
+ int m_quoter;
+ /* The width of a single character. Note that for multi-byte
+ encodings, this is the width of a 'base' character; e.g., for
+ UTF-8 it would be 1. */
+ int m_width;
+ /* The type of character being processed. */
+ type *m_type;
+
+ /* If a character was printed as an escape sequence, and this might
+ force the next character to be an escape sequence as well, then
+ this can be set. This happens in C syntax when a hex escape is
+ followed by a hex digit. */
+ bool m_need_escape = false;
+};
+
+#endif /* GDB_CHAR_PRINT_H */
@@ -45,39 +45,7 @@
#include "inferior.h"
#include "gdbsupport/selftest.h"
#include "selftest-arch.h"
-
-/* Maximum number of wchars returned from wchar_iterate. */
-#define MAX_WCHARS 4
-
-/* A convenience macro to compute the size of a wchar_t buffer containing X
- characters. */
-#define WCHAR_BUFLEN(X) ((X) * sizeof (gdb_wchar_t))
-
-/* Character buffer size saved while iterating over wchars. */
-#define WCHAR_BUFLEN_MAX WCHAR_BUFLEN (MAX_WCHARS)
-
-/* A structure to encapsulate state information from iterated
- character conversions. */
-struct converted_character
-{
- /* The number of characters converted. */
- int num_chars;
-
- /* The result of the conversion. See charset.h for more. */
- enum wchar_iterate_result result;
-
- /* The (saved) converted character(s). */
- gdb_wchar_t chars[WCHAR_BUFLEN_MAX];
-
- /* The first converted target byte. */
- const gdb_byte *buf;
-
- /* The number of bytes converted. */
- size_t buflen;
-
- /* How many times this character(s) is repeated. */
- int repeat_count;
-};
+#include "char-print.h"
/* Command lists for set/show print raw. */
struct cmd_list_element *setprintrawlist;
@@ -2141,151 +2109,141 @@ value_print_array_elements (struct value *val, struct ui_file *stream,
/* Return true if print_wchar can display W without resorting to a
numeric escape, false otherwise. */
-static int
-wchar_printable (gdb_wchar_t w)
-{
- return (gdb_iswprint (w)
- || w == LCST ('\a') || w == LCST ('\b')
- || w == LCST ('\f') || w == LCST ('\n')
- || w == LCST ('\r') || w == LCST ('\t')
- || w == LCST ('\v'));
-}
-
-/* A helper function that converts the contents of STRING to wide
- characters and then appends them to OUTPUT. */
-
-static void
-append_string_as_wide (const char *string,
- struct obstack *output)
-{
- for (; *string; ++string)
- {
- gdb_wchar_t w = gdb_btowc (*string);
- obstack_grow (output, &w, sizeof (gdb_wchar_t));
- }
+bool
+wchar_printer::printable (gdb_wchar_t w) const
+{
+ if (w == LCST ('\a') || w == LCST ('\b')
+ || w == LCST ('\f') || w == LCST ('\n')
+ || w == LCST ('\r') || w == LCST ('\t')
+ || w == LCST ('\v'))
+ return true;
+ if (!gdb_iswprint (w))
+ return false;
+ /* If we previously emitted a hex escape, then we may need to emit
+ an escape again, if W is a hex digit. */
+ if (!m_need_escape)
+ return true;
+ return !gdb_iswxdigit (w);
}
-/* 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 char-print.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
+wchar_printer::print_char (gdb_wchar_t w)
{
- bool need_escape = *need_escapep;
+ m_need_escape = false;
- *need_escapep = false;
-
- /* If any additional cases are added to this switch block, then the
- function wchar_printable will likely need updating too. */
switch (w)
{
case LCST ('\a'):
- obstack_grow_wstr (output, LCST ("\\a"));
+ m_file.write (LCST ("\\a"));
break;
case LCST ('\b'):
- obstack_grow_wstr (output, LCST ("\\b"));
+ m_file.write (LCST ("\\b"));
break;
case LCST ('\f'):
- obstack_grow_wstr (output, LCST ("\\f"));
+ m_file.write (LCST ("\\f"));
break;
case LCST ('\n'):
- obstack_grow_wstr (output, LCST ("\\n"));
+ m_file.write (LCST ("\\n"));
break;
case LCST ('\r'):
- obstack_grow_wstr (output, LCST ("\\r"));
+ m_file.write (LCST ("\\r"));
break;
case LCST ('\t'):
- obstack_grow_wstr (output, LCST ("\\t"));
+ m_file.write (LCST ("\\t"));
break;
case LCST ('\v'):
- obstack_grow_wstr (output, LCST ("\\v"));
+ m_file.write (LCST ("\\v"));
break;
default:
- {
- if (gdb_iswprint (w) && !(need_escape && gdb_iswxdigit (w)))
- {
- gdb_wchar_t wchar = w;
+ if (w == gdb_btowc (m_quoter) || w == LCST ('\\'))
+ m_file.write (LCST ("\\"));
+ m_file.write (w);
+ break;
+ }
+}
- if (w == gdb_btowc (quoter) || w == LCST ('\\'))
- obstack_grow_wstr (output, LCST ("\\"));
- obstack_grow (output, &wchar, sizeof (gdb_wchar_t));
- }
- else
- {
- int i;
+/* See char-print.h. */
- for (i = 0; i + width <= orig_len; i += width)
- {
- char octal[30];
- ULONGEST value;
-
- value = extract_unsigned_integer (&orig[i], width,
- byte_order);
- /* If the value fits in 3 octal digits, print it that
- way. Otherwise, print it as a hex escape. */
- if (value <= 0777)
- {
- xsnprintf (octal, sizeof (octal), "\\%.3o",
- (int) (value & 0777));
- *need_escapep = false;
- }
- else
- {
- xsnprintf (octal, sizeof (octal), "\\x%lx", (long) value);
- /* A hex escape might require the next character
- to be escaped, because, unlike with octal,
- hex escapes have no length limit. */
- *need_escapep = true;
- }
- append_string_as_wide (octal, output);
- }
- /* If we somehow have extra bytes, print them now. */
- while (i < orig_len)
- {
- char octal[5];
+void
+wchar_printer::print_escape (const gdb_byte *orig, int orig_len)
+{
+ m_need_escape = false;
- xsnprintf (octal, sizeof (octal), "\\%.3o", orig[i] & 0xff);
- *need_escapep = false;
- append_string_as_wide (octal, output);
- ++i;
- }
- }
- break;
+ int i;
+ for (i = 0; i + m_width <= orig_len; i += m_width)
+ {
+ ULONGEST value;
+
+ value = extract_unsigned_integer (&orig[i], m_width,
+ m_byte_order);
+ /* If the value fits in 3 octal digits, print it that
+ way. Otherwise, print it as a hex escape. */
+ if (value <= 0777)
+ {
+ gdb_printf (&m_file, "\\%.3o", (int) (value & 0777));
+ m_need_escape = false;
+ }
+ else
+ {
+ gdb_printf (&m_file, "\\x%lx", (long) value);
+ /* A hex escape might require the next character
+ to be escaped, because, unlike with octal,
+ hex escapes have no length limit. */
+ m_need_escape = true;
}
}
+
+ /* If we somehow have extra bytes, print them now. */
+ while (i < orig_len)
+ {
+ gdb_printf (&m_file, "\\%.3o", orig[i] & 0xff);
+ m_need_escape = false;
+ ++i;
+ }
}
-/* Print the character C on STREAM as part of the contents of a
- literal string whose delimiter is QUOTER. ENCODING names the
- encoding of C. */
+const char *
+wchar_printer::get_default_encoding (type *chtype)
+{
+ const char *encoding;
+ if (chtype->length () == 1)
+ encoding = target_charset (chtype->arch ());
+ else if (streq (chtype->name (), "wchar_t"))
+ encoding = target_wide_charset (chtype->arch ());
+ else if (chtype->length () == 2)
+ {
+ if (type_byte_order (chtype) == BFD_ENDIAN_BIG)
+ encoding = "UTF-16BE";
+ else
+ encoding = "UTF-16LE";
+ }
+ else if (chtype->length () == 4)
+ {
+ if (type_byte_order (chtype) == BFD_ENDIAN_BIG)
+ encoding = "UTF-32BE";
+ else
+ encoding = "UTF-32LE";
+ }
+ else
+ {
+ /* No idea. */
+ encoding = target_charset (chtype->arch ());
+ }
+ return encoding;
+}
void
-generic_emit_char (int c, struct type *type, struct ui_file *stream,
- int quoter, const char *encoding)
+wchar_printer::print (int c, ui_file *stream)
{
- enum bfd_endian byte_order
- = type_byte_order (type);
gdb_byte *c_buf;
- bool need_escape = false;
- c_buf = (gdb_byte *) alloca (type->length ());
- pack_long (c_buf, type, c);
+ c_buf = (gdb_byte *) alloca (m_width);
+ pack_long (c_buf, m_type, c);
- gdb_putc (quoter, stream);
- wchar_iterator iter (c_buf, type->length (), encoding, type->length ());
-
- /* This holds the printable form of the wchar_t data. */
- auto_obstack wchar_buf;
+ gdb_putc (m_quoter, stream);
+ wchar_iterator iter (c_buf, m_width, m_encoding, m_width);
while (1)
{
@@ -2293,7 +2251,7 @@ generic_emit_char (int c, struct type *type, struct ui_file *stream,
gdb_wchar_t *chars;
const gdb_byte *buf;
size_t buflen;
- int print_escape = 1;
+ bool need_escape = true;
enum wchar_iterate_result result;
num_chars = iter.iterate (&result, &chars, &buf, &buflen);
@@ -2308,48 +2266,56 @@ generic_emit_char (int c, struct type *type, struct ui_file *stream,
boundaries there. */
int i;
- print_escape = 0;
+ need_escape = false;
for (i = 0; i < num_chars; ++i)
- if (!wchar_printable (chars[i]))
+ if (!printable (chars[i]))
{
- print_escape = 1;
+ need_escape = true;
break;
}
- if (!print_escape)
+ if (!need_escape)
{
for (i = 0; i < num_chars; ++i)
- print_wchar (chars[i], buf, buflen,
- type->length (), byte_order,
- &wchar_buf, quoter, &need_escape);
+ print_char (chars[i]);
}
}
/* This handles the NUM_CHARS == 0 case as well. */
- if (print_escape)
- print_wchar (gdb_WEOF, buf, buflen, type->length (),
- byte_order, &wchar_buf, quoter, &need_escape);
+ if (need_escape)
+ print_escape (buf, buflen);
}
/* The output in the host encoding. */
auto_obstack output;
convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
- (gdb_byte *) obstack_base (&wchar_buf),
- obstack_object_size (&wchar_buf),
+ (gdb_byte *) obstack_base (&m_wchar_buf),
+ obstack_object_size (&m_wchar_buf),
sizeof (gdb_wchar_t), &output, translit_char);
obstack_1grow (&output, '\0');
gdb_puts ((const char *) obstack_base (&output), stream);
- gdb_putc (quoter, stream);
+ gdb_putc (m_quoter, stream);
}
-/* Return the repeat count of the next character/byte in ITER,
- storing the result in VEC. */
+/* Print the character C on STREAM as part of the contents of a
+ literal string whose delimiter is QUOTER. ENCODING names the
+ encoding of C. */
-static int
-count_next_character (wchar_iterator *iter,
- std::vector<converted_character> *vec)
+void
+generic_emit_char (int c, struct type *type, struct ui_file *stream,
+ int quoter, const char *encoding)
+{
+ wchar_printer printer (type, quoter, encoding);
+ printer.print (c, stream);
+}
+
+/* See char-print.h. */
+
+int
+wchar_printer::count_next_character (wchar_iterator *iter,
+ std::vector<converted_character> *vec)
{
struct converted_character *current;
@@ -2395,7 +2361,7 @@ count_next_character (wchar_iterator *iter,
if (d.num_chars > 0)
{
gdb_assert (d.num_chars < MAX_WCHARS);
- memcpy (d.chars, chars, WCHAR_BUFLEN (d.num_chars));
+ memcpy (d.chars, chars, d.num_chars * sizeof (gdb_wchar_t));
}
/* Determine if the current character is the same as this
@@ -2408,7 +2374,7 @@ count_next_character (wchar_iterator *iter,
2) Equality of non-converted character (num_chars == 0) */
if ((current->num_chars > 0
&& memcmp (current->chars, d.chars,
- WCHAR_BUFLEN (current->num_chars)) == 0)
+ current->num_chars * sizeof (gdb_wchar_t)) == 0)
|| (current->num_chars == 0
&& current->buflen == d.buflen
&& memcmp (current->buf, d.buf, current->buflen) == 0))
@@ -2427,25 +2393,18 @@ count_next_character (wchar_iterator *iter,
}
}
-/* Print the characters in CHARS to the OBSTACK. QUOTE_CHAR is the quote
- character to use with string output. WIDTH is the size of the output
- character type. BYTE_ORDER is the target byte order. OPTIONS
- is the user's print options. *FINISHED is set to 0 if we didn't print
- all the elements in CHARS. */
+/* See char-print.h. */
-static void
-print_converted_chars_to_obstack (struct obstack *obstack,
- const std::vector<converted_character> &chars,
- int quote_char, int width,
- enum bfd_endian byte_order,
- const struct value_print_options *options,
- int *finished)
+void
+wchar_printer::print_converted_chars_to_obstack
+ (const std::vector<converted_character> &chars,
+ const struct value_print_options *options,
+ int *finished)
{
unsigned int idx, num_elements;
const converted_character *elem;
enum {START, SINGLE, REPEAT, INCOMPLETE, FINISH} state, last;
- gdb_wchar_t wide_quote_char = gdb_btowc (quote_char);
- bool need_escape = false;
+ gdb_wchar_t wide_quote_char = gdb_btowc (m_quoter);
const int print_max = options->print_max_chars > 0
? options->print_max_chars : options->print_max;
@@ -2474,8 +2433,8 @@ print_converted_chars_to_obstack (struct obstack *obstack,
/* We were outputting some other type of content, so we
must output and a comma and a quote. */
if (last != START)
- obstack_grow_wstr (obstack, LCST (", "));
- obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ m_file.write (LCST (", "));
+ m_file.write (wide_quote_char);
}
/* Output the character. */
int repeat_count = elem->repeat_count;
@@ -2486,12 +2445,11 @@ print_converted_chars_to_obstack (struct obstack *obstack,
}
for (j = 0; j < 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);
+ if (elem->result == wchar_iterate_ok
+ && printable (elem->chars[0]))
+ print_char (elem->chars[0]);
else
- print_wchar (gdb_WEOF, elem->buf, elem->buflen, width,
- byte_order, obstack, quote_char, &need_escape);
+ print_escape (elem->buf, elem->buflen);
num_elements += 1;
}
}
@@ -2508,27 +2466,26 @@ print_converted_chars_to_obstack (struct obstack *obstack,
{
/* We were outputting a single string. Terminate the
string. */
- obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ m_file.write (wide_quote_char);
}
if (last != START)
- obstack_grow_wstr (obstack, LCST (", "));
+ m_file.write (LCST (", "));
/* Output the character and repeat string. */
- obstack_grow_wstr (obstack, LCST ("'"));
- if (elem->result == wchar_iterate_ok)
- print_wchar (elem->chars[0], elem->buf, elem->buflen, width,
- byte_order, obstack, quote_char, &need_escape);
+ m_file.write (LCST ("'"));
+ if (elem->result == wchar_iterate_ok
+ && printable (elem->chars[0]))
+ print_char (elem->chars[0]);
else
- print_wchar (gdb_WEOF, elem->buf, elem->buflen, width,
- byte_order, obstack, quote_char, &need_escape);
- obstack_grow_wstr (obstack, LCST ("'"));
+ print_escape (elem->buf, elem->buflen);
+ m_file.write (LCST ("'"));
std::string s = string_printf (_(" <repeats %u times>"),
elem->repeat_count);
num_elements += elem->repeat_count;
for (j = 0; s[j]; ++j)
{
gdb_wchar_t w = gdb_btowc (s[j]);
- obstack_grow (obstack, &w, sizeof (gdb_wchar_t));
+ m_file.write (w);
}
}
break;
@@ -2539,16 +2496,15 @@ print_converted_chars_to_obstack (struct obstack *obstack,
{
/* If we were outputting a string of SINGLE characters,
terminate the quote. */
- obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ m_file.write (wide_quote_char);
}
if (last != START)
- obstack_grow_wstr (obstack, LCST (", "));
+ m_file.write (LCST (", "));
/* Output the incomplete sequence string. */
- obstack_grow_wstr (obstack, LCST ("<incomplete sequence "));
- print_wchar (gdb_WEOF, elem->buf, elem->buflen, width, byte_order,
- obstack, 0, &need_escape);
- obstack_grow_wstr (obstack, LCST (">"));
+ m_file.write (LCST ("<incomplete sequence "));
+ print_escape (elem->buf, elem->buflen);
+ m_file.write (LCST (">"));
num_elements += 1;
/* We do not attempt to output anything after this. */
@@ -2560,7 +2516,7 @@ print_converted_chars_to_obstack (struct obstack *obstack,
characters, the string must be terminated. Otherwise,
REPEAT and INCOMPLETE are always left properly terminated. */
if (last == SINGLE)
- obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ m_file.write (wide_quote_char);
return;
}
@@ -2592,26 +2548,15 @@ print_converted_chars_to_obstack (struct obstack *obstack,
}
}
-/* Print the character string STRING, printing at most LENGTH
- characters. LENGTH is -1 if the string is nul terminated. TYPE is
- the type of each character. OPTIONS holds the printing options;
- printing stops early if the number hits print_max_chars; repeat
- counts are printed as appropriate. Print ellipses at the end if we
- had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
- QUOTE_CHAR is the character to print at each end of the string. If
- C_STYLE_TERMINATOR is true, and the last character is 0, then it is
- omitted. */
+/* See char-print.h. */
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)
+wchar_printer::print (struct ui_file *stream, const gdb_byte *string,
+ unsigned int length, int force_ellipses,
+ int c_style_terminator,
+ const struct value_print_options *options)
{
- enum bfd_endian byte_order = type_byte_order (type);
unsigned int i;
- int width = type->length ();
int finished = 0;
struct converted_character *last;
@@ -2622,8 +2567,8 @@ generic_printstr (struct ui_file *stream, struct type *type,
for (i = 0; current_char; ++i)
{
QUIT;
- current_char = extract_unsigned_integer (string + i * width,
- width, byte_order);
+ current_char = extract_unsigned_integer (string + i * m_width,
+ m_width, m_byte_order);
}
length = i;
}
@@ -2634,18 +2579,18 @@ generic_printstr (struct ui_file *stream, struct type *type,
if (c_style_terminator
&& !force_ellipses
&& length > 0
- && (extract_unsigned_integer (string + (length - 1) * width,
- width, byte_order) == 0))
+ && (extract_unsigned_integer (string + (length - 1) * m_width,
+ m_width, m_byte_order) == 0))
length--;
if (length == 0)
{
- gdb_printf (stream, "%c%c", quote_char, quote_char);
+ gdb_printf (stream, "%c%c", m_quoter, m_quoter);
return;
}
/* Arrange to iterate over the characters, in wchar_t form. */
- wchar_iterator iter (string, length * width, encoding, width);
+ wchar_iterator iter (string, length * m_width, m_encoding, m_width);
std::vector<converted_character> converted_chars;
/* Convert characters until the string is over or the maximum
@@ -2678,29 +2623,46 @@ generic_printstr (struct ui_file *stream, struct type *type,
/* Ensure that CONVERTED_CHARS is terminated. */
last->result = wchar_iterate_eof;
- /* WCHAR_BUF is the obstack we use to represent the string in
- wchar_t form. */
- auto_obstack wchar_buf;
-
/* Print the output string to the obstack. */
- print_converted_chars_to_obstack (&wchar_buf, converted_chars, quote_char,
- width, byte_order, options, &finished);
+ print_converted_chars_to_obstack (converted_chars, options, &finished);
if (force_ellipses || !finished)
- obstack_grow_wstr (&wchar_buf, LCST ("..."));
+ m_file.write (LCST ("..."));
/* OUTPUT is where we collect `char's for printing. */
auto_obstack output;
convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
- (gdb_byte *) obstack_base (&wchar_buf),
- obstack_object_size (&wchar_buf),
+ (gdb_byte *) obstack_base (&m_wchar_buf),
+ obstack_object_size (&m_wchar_buf),
sizeof (gdb_wchar_t), &output, translit_char);
obstack_1grow (&output, '\0');
gdb_puts ((const char *) obstack_base (&output), stream);
}
+/* Print the character string STRING, printing at most LENGTH
+ characters. LENGTH is -1 if the string is nul terminated. TYPE is
+ the type of each character. OPTIONS holds the printing options;
+ printing stops early if the number hits print_max_chars; repeat
+ counts are printed as appropriate. Print ellipses at the end if we
+ had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ QUOTE_CHAR is the character to print at each end of the string. If
+ C_STYLE_TERMINATOR is true, and the last character is 0, then it is
+ omitted. */
+
+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)
+{
+ wchar_printer printer (type, quote_char, encoding);
+ printer.print (stream, string, length, force_ellipses,
+ c_style_terminator, options);
+}
+
/* Print a string from the inferior, starting at ADDR and printing up to LEN
characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, printing
stops at the first null byte, otherwise printing proceeds (including null
@@ -76,9 +76,6 @@ obstack_new (struct obstack *ob, Args&&... args)
#define obstack_grow_str0(OBSTACK,STRING) \
obstack_grow0 (OBSTACK, STRING, strlen (STRING))
-#define obstack_grow_wstr(OBSTACK, WSTRING) \
- obstack_grow (OBSTACK, WSTRING, sizeof (gdb_wchar_t) * gdb_wcslen (WSTRING))
-
/* Concatenate NULL terminated variable argument list of `const char
*' strings; return the new string. Space is found in the OBSTACKP.
Argument list must be terminated by a sentinel expression `(char *)