aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2012-11-10 20:19:01 +0000
committerKeith Seitz <keiths@redhat.com>2012-11-10 20:19:01 +0000
commit0d63ecdad04d410698c905283d095505680ba907 (patch)
tree3f894b47be2cfef2d36d71ffb1cb4d33717bd9b7 /gdb
parent9b8d6827200e1b04d3ca860ce52472655e84248c (diff)
downloadgdb-0d63ecdad04d410698c905283d095505680ba907.zip
gdb-0d63ecdad04d410698c905283d095505680ba907.tar.gz
gdb-0d63ecdad04d410698c905283d095505680ba907.tar.bz2
PR gdb/14288
* c-valprint.c (c_val_print): For character arrays with "print null" option on, print ellipses if the output is truncated and the next character is not \000. * valprint.c (MAX_WCHARS): Define. (WCHAR_BUFLEN): Likewise. (WCHAR_BUFLEN_MAX): Likewise. (struct converted_character): New structure. (count_next_character): New function. (print_converted_chars_to_obstack): New function. (generic_printstr): Rewrite using count_next_character and print_converted_chars_to_obstack. * gdb.base/printcmds.c: Add invalid_XXX globals for repeated byte tests. * gdb.base/printcmds.exp (test_repeat_bytes): New procedure. * gdb.base/wchar.c (main): Add and construct a wchar_t array with repeated characters. * gdb.base/wchar.exp: Add repeated character tests.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog15
-rw-r--r--gdb/c-valprint.c18
-rw-r--r--gdb/testsuite/ChangeLog10
-rw-r--r--gdb/testsuite/gdb.base/printcmds.c92
-rw-r--r--gdb/testsuite/gdb.base/printcmds.exp71
-rw-r--r--gdb/testsuite/gdb.base/wchar.c10
-rw-r--r--gdb/testsuite/gdb.base/wchar.exp19
-rw-r--r--gdb/valprint.c469
8 files changed, 549 insertions, 155 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b8fc396..4175f2f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,18 @@
+2012-11-10 Keith Seitz <keiths@redhat.com>
+
+ PR gdb/14288
+ * c-valprint.c (c_val_print): For character arrays
+ with "print null" option on, print ellipses if
+ the output is truncated and the next character is not \000.
+ * valprint.c (MAX_WCHARS): Define.
+ (WCHAR_BUFLEN): Likewise.
+ (WCHAR_BUFLEN_MAX): Likewise.
+ (struct converted_character): New structure.
+ (count_next_character): New function.
+ (print_converted_chars_to_obstack): New function.
+ (generic_printstr): Rewrite using count_next_character
+ and print_converted_chars_to_obstack.
+
2012-11-10 Stephane Carrez <Stephane.Carrez@gmail.com>
* tui/tui.c (tui_rl_command_key): Switch to TUI_ONE_COMMAND_MODE
diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 7a1bb02..dada9e2 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -177,6 +177,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
TARGET_CHAR_BIT * embedded_offset,
TARGET_CHAR_BIT * TYPE_LENGTH (type)))
{
+ int force_ellipses = 0;
+
/* If requested, look for the first null char and only
print elements up to it. */
if (options->stop_print_at_null)
@@ -191,12 +193,26 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
eltlen, byte_order) != 0);
++temp_len)
;
+
+ /* Force LA_PRINT_STRING to print ellipses if
+ we've printed the maximum characters and
+ the next character is not \000. */
+ if (temp_len == options->print_max && temp_len < len)
+ {
+ ULONGEST val
+ = extract_unsigned_integer (valaddr + embedded_offset
+ + temp_len * eltlen,
+ eltlen, byte_order);
+ if (val != 0)
+ force_ellipses = 1;
+ }
+
len = temp_len;
}
LA_PRINT_STRING (stream, unresolved_elttype,
valaddr + embedded_offset, len,
- NULL, 0, options);
+ NULL, force_ellipses, options);
i = len;
}
else
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 26f2b3f..f42ca37 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2012-11-10 Keith Seitz <keiths@redhat.com>
+
+ PR gdb/14288
+ * gdb.base/printcmds.c: Add invalid_XXX globals
+ for repeated byte tests.
+ * gdb.base/printcmds.exp (test_repeat_bytes): New procedure.
+ * gdb.base/wchar.c (main): Add and construct a wchar_t
+ array with repeated characters.
+ * gdb.base/wchar.exp: Add repeated character tests.
+
2012-11-09 Andrew Burgess <aburgess@broadcom.com>
* gdb.mi/mi-disassemble.exp: Expect fullname field in mi
diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c
index 743734b..d80c13d 100644
--- a/gdb/testsuite/gdb.base/printcmds.c
+++ b/gdb/testsuite/gdb.base/printcmds.c
@@ -122,6 +122,98 @@ struct some_struct
}
};
+/* The following variables are used for testing byte repeat sequences.
+ The variable names are encoded: invalid_XYZ where:
+ X = start
+ Y = invalid
+ Z = end
+
+ Each of X and Z can be "E" (empty), "S" (single), "L" (long single),
+ or "R" (repeat).
+
+ Y can be either any of the above except "E" (otherwise there is nothing
+ to test). */
+char invalid_ESE[] = "\240";
+char invalid_SSE[] = "a\240";
+char invalid_LSE[] = "abaabbaaabbb\240";
+char invalid_RSE[] = "aaaaaaaaaaaaaaaaaaaa\240";
+char invalid_ESS[] = "\240c";
+char invalid_SSS[] = "a\240c";
+char invalid_LSS[] = "abaabbaaabbb\240c";
+char invalid_RSS[] = "aaaaaaaaaaaaaaaaaaaa\240c";
+char invalid_ESL[] = "\240cdccddcccddd";
+char invalid_SSL[] = "a\240cdccddcccddd";
+char invalid_LSL[] = "abaabbaaabbb\240cdccddcccddd";
+char invalid_RSL[] = "aaaaaaaaaaaaaaaaaaaa\240cdccddcccddd";
+char invalid_ESR[] = "\240cccccccccccccccccccc";
+char invalid_SSR[] = "a\240cccccccccccccccccccc";
+char invalid_LSR[] = "abaabbaaabbb\240cccccccccccccccccccc";
+char invalid_RSR[] = "aaaaaaaaaaaaaaaaaaaa\240cccccccccccccccccccc";
+char invalid_ELE[] = "\240\240\240\240";
+char invalid_SLE[] = "a\240\240\240\240";
+char invalid_LLE[] = "abaabbaaabbb\240\240\240\240";
+char invalid_RLE[] = "aaaaaaaaaaaaaaaaaaaa\240\240\240\240";
+char invalid_ELS[] = "\240\240\240\240c";
+char invalid_SLS[] = "a\240\240\240\240c";
+char invalid_LLS[] = "abaabbaaabbb\240\240\240\240c";
+char invalid_RLS[] = "aaaaaaaaaaaaaaaaaaaa\240\240\240\240c";
+char invalid_ELL[] = "\240\240\240\240cdccddcccddd";
+char invalid_SLL[] = "a\240\240\240\240cdccddcccddd";
+char invalid_LLL[] = "abaabbaaabbb\240\240\240\240cdccddcccddd";
+char invalid_RLL[] = "aaaaaaaaaaaaaaaaaaaa\240\240\240\240cdccddcccddd";
+char invalid_ELR[] = "\240\240\240\240cccccccccccccccccccc";
+char invalid_SLR[] = "a\240\240\240\240cccccccccccccccccccc";
+char invalid_LLR[] = "abaabbaaabbb\240\240\240\240cccccccccccccccccccc";
+char invalid_RLR[] = "aaaaaaaaaaaaaaaaaaaa\240\240\240\240cccccccccccccccccccc";
+char invalid_ERE[] = ""
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240";
+char invalid_LRE[] = "abaabbaaabbb"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240";
+char invalid_RRE[] = "aaaaaaaaaaaaaaaaaaaa"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240";
+char invalid_ERS[] = ""
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240c";
+char invalid_ERL[] = ""
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cdccddcccddd";
+char invalid_ERR[] = ""
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cccccccccccccccccccc";
+char invalid_SRE[] = "a"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240";
+char invalid_SRS[] = "a"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240c";
+char invalid_SRL[] = "a"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cdccddcccddd";
+char invalid_SRR[] = "a"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cccccccccccccccccccc";
+char invalid_LRS[] = "abaabbaaabbb"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240c";
+char invalid_LRL[] = "abaabbaaabbb"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cdccddcccddd";
+char invalid_LRR[] = "abaabbaaabbb"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cccccccccccccccccccc";
+char invalid_RRS[] = "aaaaaaaaaaaaaaaaaaaa"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240c";
+char invalid_RRL[] = "aaaaaaaaaaaaaaaaaaaa"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cdccddcccddd";
+char invalid_RRR[] = "aaaaaaaaaaaaaaaaaaaa"
+ "\240\240\240\240\240\240\240\240\240\240"
+ "\240\240\240\240\240\240\240\240\240\240cccccccccccccccccccc";
+
/* -- */
int main ()
diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
index 4f76cec..4dfe90f 100644
--- a/gdb/testsuite/gdb.base/printcmds.exp
+++ b/gdb/testsuite/gdb.base/printcmds.exp
@@ -792,6 +792,76 @@ proc gdb_test_escape_braces { args } {
gdb_test [lindex $args 0] $esc_pattern [lindex $args 2]
}
+proc test_repeat_bytes {} {
+ set start(E) {}
+ set start(S) {a}
+ set start(L) {abaabbaaabbb}
+ set start(R) {'a' <repeats 20 times>}
+ set end(E) {}
+ set end(S) {c}
+ set end(L) {cdccddcccddd}
+ set end(R) {'c' <repeats 20 times>}
+ set invalid(S) {\\240}
+ set invalid(L) {\\240\\240\\240\\240}
+ set invalid(R) {'\\240' <repeats 20 times>}
+
+ set fmt(SSS) "\"%s%s%s\""
+ set fmt(SSR) "\"%s%s\", %s"
+ set fmt(SRS) "\"%s\", %s, \"%s\""
+ set fmt(RSS) "%s, \"%s%s\""
+ set fmt(RSR) "%s, \"%s\", %s"
+ set fmt(SRR) "\"%s\", %s, %s"
+ set fmt(RRS) "%s, %s, \"%s\""
+ set fmt(RRR) "%s, %s, %s"
+
+ set fmt(RS) "%s, \"%s\""
+ set fmt(RR) "%s, %s"
+ set fmt(SR) "\"%s\", %s"
+ set fmt(SS) "\"%s%s\""
+
+ # Test the various permutations of invalid characters
+ foreach i [array names invalid] {
+ set I $i
+
+ if {$i == "L"} {
+ set i "S"
+ }
+
+ foreach s [array names start] {
+ set S $s
+
+ if {$s == "L"} {
+ set s "S"
+ }
+
+
+ foreach e [array names end] {
+ set E $e
+
+ if {$e == "L"} {
+ set e "S"
+ }
+
+ # Skip E*E.
+ if {$s == "E" && $e == "E"} { continue }
+
+ # Special cases...
+ if {$s == "E"} {
+ set result [format $fmt($i$e) $invalid($I) $end($E)]
+ } elseif {$e == "E"} {
+ set result [format $fmt($s$i) $start($S) $invalid($I)]
+ } else {
+ set result [format $fmt($s$i$e) \
+ $start($S) $invalid($I) $end($E)]
+ }
+
+ send_log "expecting: = $result\n"
+ gdb_test "print invalid_$S$I$E" "= $result"
+ }
+ }
+ }
+}
+
# Start with a fresh gdb.
gdb_exit
@@ -851,3 +921,4 @@ test_print_enums
test_printf
test_printf_with_dfp
test_print_symbol
+test_repeat_bytes
diff --git a/gdb/testsuite/gdb.base/wchar.c b/gdb/testsuite/gdb.base/wchar.c
index 22f5beb..7bdfd68 100644
--- a/gdb/testsuite/gdb.base/wchar.c
+++ b/gdb/testsuite/gdb.base/wchar.c
@@ -25,11 +25,21 @@ do_nothing (wchar_t *c)
int
main (void)
{
+ int i;
wchar_t narrow = 97;
wchar_t single = 0xbeef;
wchar_t simple[] = L"facile";
wchar_t difficile[] = { 0xdead, 0xbeef, 0xfeed, 0xface};
wchar_t mixed[] = {L'f', 0xdead, L'a', L'c', 0xfeed, 0xface};
+ wchar_t *cent = L"\242";
+ wchar_t repeat[128];
+ wchar_t *repeat_p = repeat;
+
+ repeat[0] = 0;
+ wcscat (repeat, L"A");
+ for (i = 0; i < 21; ++i)
+ wcscat (repeat, cent);
+ wcscat (repeat, L"B");
do_nothing (&narrow); /* START */
do_nothing (&single);
diff --git a/gdb/testsuite/gdb.base/wchar.exp b/gdb/testsuite/gdb.base/wchar.exp
index 2451d92..4c7ebf1 100644
--- a/gdb/testsuite/gdb.base/wchar.exp
+++ b/gdb/testsuite/gdb.base/wchar.exp
@@ -36,3 +36,22 @@ gdb_test "print simple\[2\]" "= 99 L'c'"
gdb_test "print difficile\[2\]" "= 65261 L'\\\\xfeed'"
+set cent "\\\\242"
+gdb_test "print repeat" "= L\"A\", '$cent' <repeats 21 times>, \"B.*"
+
+global hex
+gdb_test "print repeat_p" \
+ "= $hex L\"A\", '$cent' <repeats 21 times>, \"B\""
+
+gdb_test_no_output "set print null on"
+
+gdb_test "print repeat" "= L\"A\", '$cent' <repeats 21 times>, \"B\"" \
+ "print repeat (print null on)"
+
+gdb_test_no_output "set print elements 3"
+
+gdb_test "print repeat" "= L\"A$cent$cent\"\.\.\." \
+ "print repeat (print elements 3)"
+
+gdb_test "print repeat_p" "= $hex L\"A$cent$cent\"\.\.\." \
+ "print repeat_p (print elements 3)"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 583329d..8600be0 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -40,6 +40,43 @@
#include <errno.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;
+};
+
+typedef struct converted_character converted_character_d;
+DEF_VEC_O (converted_character_d);
+
+
/* Prototypes for local functions */
static int partial_memory_read (CORE_ADDR memaddr, gdb_byte *myaddr,
@@ -2045,6 +2082,253 @@ generic_emit_char (int c, struct type *type, struct ui_file *stream,
do_cleanups (cleanups);
}
+/* Return the repeat count of the next character/byte in ITER,
+ storing the result in VEC. */
+
+static int
+count_next_character (struct wchar_iterator *iter,
+ VEC (converted_character_d) **vec)
+{
+ struct converted_character *current;
+
+ if (VEC_empty (converted_character_d, *vec))
+ {
+ struct converted_character tmp;
+ gdb_wchar_t *chars;
+
+ tmp.num_chars
+ = wchar_iterate (iter, &tmp.result, &chars, &tmp.buf, &tmp.buflen);
+ if (tmp.num_chars > 0)
+ {
+ gdb_assert (tmp.num_chars < MAX_WCHARS);
+ memcpy (tmp.chars, chars, tmp.num_chars * sizeof (gdb_wchar_t));
+ }
+ VEC_safe_push (converted_character_d, *vec, &tmp);
+ }
+
+ current = VEC_last (converted_character_d, *vec);
+
+ /* Count repeated characters or bytes. */
+ current->repeat_count = 1;
+ if (current->num_chars == -1)
+ {
+ /* EOF */
+ return -1;
+ }
+ else
+ {
+ gdb_wchar_t *chars;
+ struct converted_character d;
+ int repeat;
+
+ d.repeat_count = 0;
+
+ while (1)
+ {
+ /* Get the next character. */
+ d.num_chars
+ = wchar_iterate (iter, &d.result, &chars, &d.buf, &d.buflen);
+
+ /* If a character was successfully converted, save the character
+ into the converted character. */
+ if (d.num_chars > 0)
+ {
+ gdb_assert (d.num_chars < MAX_WCHARS);
+ memcpy (d.chars, chars, WCHAR_BUFLEN (d.num_chars));
+ }
+
+ /* Determine if the current character is the same as this
+ new character. */
+ if (d.num_chars == current->num_chars && d.result == current->result)
+ {
+ /* There are two cases to consider:
+
+ 1) Equality of converted character (num_chars > 0)
+ 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 == 0
+ && current->buflen == d.buflen
+ && memcmp (current->buf, d.buf, current->buflen) == 0))
+ ++current->repeat_count;
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ /* Push this next converted character onto the result vector. */
+ repeat = current->repeat_count;
+ VEC_safe_push (converted_character_d, *vec, &d);
+ return repeat;
+ }
+}
+
+/* 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 the target byte order. OPTIONS
+ is the user's print options. */
+
+static void
+print_converted_chars_to_obstack (struct obstack *obstack,
+ VEC (converted_character_d) *chars,
+ int quote_char, int width,
+ enum bfd_endian byte_order,
+ const struct value_print_options *options)
+{
+ unsigned int idx;
+ struct converted_character *elem;
+ enum {START, SINGLE, REPEAT, INCOMPLETE, FINISH} state, last;
+ gdb_wchar_t wide_quote_char = gdb_btowc (quote_char);
+ int need_escape = 0;
+
+ /* Set the start state. */
+ idx = 0;
+ last = state = START;
+ elem = NULL;
+
+ while (1)
+ {
+ switch (state)
+ {
+ case START:
+ /* Nothing to do. */
+ break;
+
+ case SINGLE:
+ {
+ int j;
+
+ /* We are outputting a single character
+ (< options->repeat_count_threshold). */
+
+ if (last != SINGLE)
+ {
+ /* 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 (", "));
+ if (options->inspect_it)
+ obstack_grow_wstr (obstack, LCST ("\\"));
+ obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ }
+ /* 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);
+ else
+ print_wchar (gdb_WEOF, elem->buf, elem->buflen, width,
+ byte_order, obstack, quote_char, &need_escape);
+ }
+ }
+ break;
+
+ case REPEAT:
+ {
+ int j;
+ char *s;
+
+ /* We are outputting a character with a repeat count
+ greater than options->repeat_count_threshold. */
+
+ if (last == SINGLE)
+ {
+ /* We were outputting a single string. Terminate the
+ string. */
+ if (options->inspect_it)
+ obstack_grow_wstr (obstack, LCST ("\\"));
+ obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ }
+ if (last != START)
+ obstack_grow_wstr (obstack, 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);
+ else
+ print_wchar (gdb_WEOF, elem->buf, elem->buflen, width,
+ byte_order, obstack, quote_char, &need_escape);
+ obstack_grow_wstr (obstack, LCST ("'"));
+ s = xstrprintf (_(" <repeats %u times>"), 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));
+ }
+ xfree (s);
+ }
+ break;
+
+ case INCOMPLETE:
+ /* We are outputting an incomplete sequence. */
+ if (last == SINGLE)
+ {
+ /* If we were outputting a string of SINGLE characters,
+ terminate the quote. */
+ if (options->inspect_it)
+ obstack_grow_wstr (obstack, LCST ("\\"));
+ obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ }
+ if (last != START)
+ obstack_grow_wstr (obstack, 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 (">"));
+
+ /* We do not attempt to outupt anything after this. */
+ state = FINISH;
+ break;
+
+ case FINISH:
+ /* All done. If we were outputting a string of SINGLE
+ characters, the string must be terminated. Otherwise,
+ REPEAT and INCOMPLETE are always left properly terminated. */
+ if (last == SINGLE)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (obstack, LCST ("\\"));
+ obstack_grow (obstack, &wide_quote_char, sizeof (gdb_wchar_t));
+ }
+
+ return;
+ }
+
+ /* Get the next element and state. */
+ last = state;
+ if (state != FINISH)
+ {
+ elem = VEC_index (converted_character_d, chars, idx++);
+ switch (elem->result)
+ {
+ case wchar_iterate_ok:
+ case wchar_iterate_invalid:
+ if (elem->repeat_count > options->repeat_count_threshold)
+ state = REPEAT;
+ else
+ state = SINGLE;
+ break;
+
+ case wchar_iterate_incomplete:
+ state = INCOMPLETE;
+ break;
+
+ case wchar_iterate_eof:
+ state = FINISH;
+ break;
+ }
+ }
+ }
+}
+
/* 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;
@@ -2064,16 +2348,13 @@ generic_printstr (struct ui_file *stream, struct type *type,
{
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
unsigned int i;
- unsigned int things_printed = 0;
- int in_quotes = 0;
- int need_comma = 0;
int width = TYPE_LENGTH (type);
struct obstack wchar_buf, output;
struct cleanup *cleanup;
struct wchar_iterator *iter;
int finished = 0;
- int need_escape = 0;
- gdb_wchar_t wide_quote_char = gdb_btowc (quote_char);
+ struct converted_character *last;
+ VEC (converted_character_d) *converted_chars;
if (length == -1)
{
@@ -2107,166 +2388,46 @@ generic_printstr (struct ui_file *stream, struct type *type,
/* Arrange to iterate over the characters, in wchar_t form. */
iter = make_wchar_iterator (string, length * width, encoding, width);
cleanup = make_cleanup_wchar_iterator (iter);
+ converted_chars = NULL;
+ make_cleanup (VEC_cleanup (converted_character_d), &converted_chars);
- /* WCHAR_BUF is the obstack we use to represent the string in
- wchar_t form. */
- obstack_init (&wchar_buf);
- make_cleanup_obstack_free (&wchar_buf);
-
- while (!finished && things_printed < options->print_max)
+ /* Convert characters until the string is over or the maximum
+ number of printed characters has been reached. */
+ i = 0;
+ while (i < options->print_max)
{
- int num_chars;
- enum wchar_iterate_result result;
- gdb_wchar_t *chars;
- const gdb_byte *buf;
- size_t buflen;
+ int r;
QUIT;
- if (need_comma)
- {
- obstack_grow_wstr (&wchar_buf, LCST (", "));
- need_comma = 0;
- }
-
- num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen);
- /* We only look at repetitions when we were able to convert a
- single character in isolation. This makes the code simpler
- and probably does the sensible thing in the majority of
- cases. */
- while (num_chars == 1 && things_printed < options->print_max)
- {
- /* Count the number of repetitions. */
- unsigned int reps = 0;
- gdb_wchar_t current_char = chars[0];
- const gdb_byte *orig_buf = buf;
- int orig_len = buflen;
-
- if (need_comma)
- {
- obstack_grow_wstr (&wchar_buf, LCST (", "));
- need_comma = 0;
- }
-
- while (num_chars == 1 && current_char == chars[0])
- {
- num_chars = wchar_iterate (iter, &result, &chars,
- &buf, &buflen);
- ++reps;
- }
+ /* Grab the next character and repeat count. */
+ r = count_next_character (iter, &converted_chars);
- /* Emit CURRENT_CHAR according to the repetition count and
- options. */
- if (reps > options->repeat_count_threshold)
- {
- if (in_quotes)
- {
- if (options->inspect_it)
- obstack_grow_wstr (&wchar_buf, LCST ("\\"));
- obstack_grow (&wchar_buf, &wide_quote_char,
- sizeof (gdb_wchar_t));
- obstack_grow_wstr (&wchar_buf, LCST (", "));
- in_quotes = 0;
- }
- obstack_grow_wstr (&wchar_buf, LCST ("'"));
- need_escape = 0;
- print_wchar (current_char, orig_buf, orig_len, width,
- byte_order, &wchar_buf, '\'', &need_escape);
- obstack_grow_wstr (&wchar_buf, LCST ("'"));
- {
- /* Painful gyrations. */
- int j;
- char *s = xstrprintf (_(" <repeats %u times>"), reps);
-
- for (j = 0; s[j]; ++j)
- {
- gdb_wchar_t w = gdb_btowc (s[j]);
- obstack_grow (&wchar_buf, &w, sizeof (gdb_wchar_t));
- }
- xfree (s);
- }
- things_printed += options->repeat_count_threshold;
- need_comma = 1;
- }
- else
- {
- /* Saw the character one or more times, but fewer than
- the repetition threshold. */
- if (!in_quotes)
- {
- if (options->inspect_it)
- obstack_grow_wstr (&wchar_buf, LCST ("\\"));
- obstack_grow (&wchar_buf, &wide_quote_char,
- sizeof (gdb_wchar_t));
- in_quotes = 1;
- need_escape = 0;
- }
+ /* If less than zero, the end of the input string was reached. */
+ if (r < 0)
+ break;
- while (reps-- > 0)
- {
- print_wchar (current_char, orig_buf,
- orig_len, width,
- byte_order, &wchar_buf,
- quote_char, &need_escape);
- ++things_printed;
- }
- }
- }
+ /* Otherwise, add the count to the total print count and get
+ the next character. */
+ i += r;
+ }
- /* NUM_CHARS and the other outputs from wchar_iterate are valid
- here regardless of which branch was taken above. */
- if (num_chars < 0)
- {
- /* Hit EOF. */
- finished = 1;
- break;
- }
+ /* Get the last element and determine if the entire string was
+ processed. */
+ last = VEC_last (converted_character_d, converted_chars);
+ finished = (last->result == wchar_iterate_eof);
- switch (result)
- {
- case wchar_iterate_invalid:
- if (!in_quotes)
- {
- if (options->inspect_it)
- obstack_grow_wstr (&wchar_buf, LCST ("\\"));
- obstack_grow (&wchar_buf, &wide_quote_char,
- sizeof (gdb_wchar_t));
- in_quotes = 1;
- }
- need_escape = 0;
- print_wchar (gdb_WEOF, buf, buflen, width, byte_order,
- &wchar_buf, quote_char, &need_escape);
- break;
+ /* Ensure that CONVERTED_CHARS is terminated. */
+ last->result = wchar_iterate_eof;
- case wchar_iterate_incomplete:
- if (in_quotes)
- {
- if (options->inspect_it)
- obstack_grow_wstr (&wchar_buf, LCST ("\\"));
- obstack_grow (&wchar_buf, &wide_quote_char,
- sizeof (gdb_wchar_t));
- obstack_grow_wstr (&wchar_buf, LCST (","));
- in_quotes = 0;
- }
- obstack_grow_wstr (&wchar_buf,
- LCST (" <incomplete sequence "));
- print_wchar (gdb_WEOF, buf, buflen, width,
- byte_order, &wchar_buf,
- 0, &need_escape);
- obstack_grow_wstr (&wchar_buf, LCST (">"));
- finished = 1;
- break;
- }
- }
+ /* WCHAR_BUF is the obstack we use to represent the string in
+ wchar_t form. */
+ obstack_init (&wchar_buf);
+ make_cleanup_obstack_free (&wchar_buf);
- /* Terminate the quotes if necessary. */
- if (in_quotes)
- {
- if (options->inspect_it)
- obstack_grow_wstr (&wchar_buf, LCST ("\\"));
- obstack_grow (&wchar_buf, &wide_quote_char,
- sizeof (gdb_wchar_t));
- }
+ /* Print the output string to the obstack. */
+ print_converted_chars_to_obstack (&wchar_buf, converted_chars, quote_char,
+ width, byte_order, options);
if (force_ellipses || !finished)
obstack_grow_wstr (&wchar_buf, LCST ("..."));