PR fortran/10036:
	* valprint.h (generic_emit_char, generic_printstr): Declare.
	* valprint.c (wchar_printable, append_string_as_wide)
	(print_wchar): Move from c-lang.c.
	(generic_emit_char): New function; mostly taken from c_emit_char.
	(generic_printstr): New function; mostly taken from c_printstr.
	* f-valprint.c (f_val_print) <TYPE_CODE_ARRAY>: Handle strings
	represented as arrays.
	<TYPE_CODE_CHAR>: Treat as TYPE_CODE_INT; recognize as character
	type.
	* f-typeprint.c (f_type_print_base) <TYPE_CODE_CHAR>: Treat
	identically to TYPE_CODE_INT.
	* f-lang.c (f_get_encoding): New function.
	(f_emit_char): Use generic_emit_char.
	(f_printchar): Replace comment.
	(f_printstr): Use generic_printstr.
	* dwarf2read.c (read_base_type) <DW_ATE_unsigned>: Handle Fortran
	"character" types specially.
	<DW_ATE_signed_char, DW_ATE_unsigned_char>: Make TYPE_CODE_CHAR
	for Fortran.
	* c-lang.c (wchar_printable, append_string_as_wide, print_wchar):
	Move to valprint.c
	(c_emit_char): Call generic_emit_char.
	(c_printstr): Call generic_printstr.
gdb/testsuite
	* gdb.fortran/charset.exp: New file.
	* gdb.fortran/charset.f90: New file.
This commit is contained in:
Tom Tromey 2011-06-29 15:32:40 +00:00
parent 168e6d4402
commit 3b2b8feaf4
11 changed files with 616 additions and 528 deletions

View file

@ -140,123 +140,6 @@ classify_type (struct type *elttype, struct gdbarch *gdbarch,
return result;
}
/* 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));
}
}
/* 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. */
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, int *need_escapep)
{
int need_escape = *need_escapep;
*need_escapep = 0;
if (gdb_iswprint (w) && (!need_escape || (!gdb_iswdigit (w)
&& w != LCST ('8')
&& w != LCST ('9'))))
{
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));
}
else
{
switch (w)
{
case LCST ('\a'):
obstack_grow_wstr (output, LCST ("\\a"));
break;
case LCST ('\b'):
obstack_grow_wstr (output, LCST ("\\b"));
break;
case LCST ('\f'):
obstack_grow_wstr (output, LCST ("\\f"));
break;
case LCST ('\n'):
obstack_grow_wstr (output, LCST ("\\n"));
break;
case LCST ('\r'):
obstack_grow_wstr (output, LCST ("\\r"));
break;
case LCST ('\t'):
obstack_grow_wstr (output, LCST ("\\t"));
break;
case LCST ('\v'):
obstack_grow_wstr (output, LCST ("\\v"));
break;
default:
{
int i;
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)
sprintf (octal, "\\%.3o", (int) (value & 0777));
else
sprintf (octal, "\\x%lx", (long) value);
append_string_as_wide (octal, output);
}
/* If we somehow have extra bytes, print them now. */
while (i < orig_len)
{
char octal[5];
sprintf (octal, "\\%.3o", orig[i] & 0xff);
append_string_as_wide (octal, output);
++i;
}
*need_escapep = 1;
}
break;
}
}
}
/* Print the character C on STREAM as part of the contents of a
literal string whose delimiter is QUOTER. Note that that format
for printing characters and strings is language specific. */
@ -265,85 +148,10 @@ void
c_emit_char (int c, struct type *type,
struct ui_file *stream, int quoter)
{
enum bfd_endian byte_order
= gdbarch_byte_order (get_type_arch (type));
struct obstack wchar_buf, output;
struct cleanup *cleanups;
const char *encoding;
gdb_byte *buf;
struct wchar_iterator *iter;
int need_escape = 0;
classify_type (type, get_type_arch (type), &encoding);
buf = alloca (TYPE_LENGTH (type));
pack_long (buf, type, c);
iter = make_wchar_iterator (buf, TYPE_LENGTH (type),
encoding, TYPE_LENGTH (type));
cleanups = make_cleanup_wchar_iterator (iter);
/* This holds the printable form of the wchar_t data. */
obstack_init (&wchar_buf);
make_cleanup_obstack_free (&wchar_buf);
while (1)
{
int num_chars;
gdb_wchar_t *chars;
const gdb_byte *buf;
size_t buflen;
int print_escape = 1;
enum wchar_iterate_result result;
num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen);
if (num_chars < 0)
break;
if (num_chars > 0)
{
/* If all characters are printable, print them. Otherwise,
we're going to have to print an escape sequence. We
check all characters because we want to print the target
bytes in the escape sequence, and we don't know character
boundaries there. */
int i;
print_escape = 0;
for (i = 0; i < num_chars; ++i)
if (!wchar_printable (chars[i]))
{
print_escape = 1;
break;
}
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);
}
}
/* 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);
}
/* The output in the host encoding. */
obstack_init (&output);
make_cleanup_obstack_free (&output);
convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
obstack_base (&wchar_buf),
obstack_object_size (&wchar_buf),
1, &output, translit_char);
obstack_1grow (&output, '\0');
fputs_filtered (obstack_base (&output), stream);
do_cleanups (cleanups);
generic_emit_char (c, type, stream, quoter, encoding);
}
void
@ -385,6 +193,10 @@ c_printstr (struct ui_file *stream, struct type *type,
const char *user_encoding, int force_ellipses,
const struct value_print_options *options)
{
enum c_string_type str_type;
const char *type_encoding;
const char *encoding;
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
unsigned int i;
unsigned int things_printed = 0;
@ -393,35 +205,10 @@ c_printstr (struct ui_file *stream, struct type *type,
int width = TYPE_LENGTH (type);
struct obstack wchar_buf, output;
struct cleanup *cleanup;
enum c_string_type str_type;
const char *type_encoding;
const char *encoding;
struct wchar_iterator *iter;
int finished = 0;
int need_escape = 0;
if (length == -1)
{
unsigned long current_char = 1;
for (i = 0; current_char; ++i)
{
QUIT;
current_char = extract_unsigned_integer (string + i * width,
width, byte_order);
}
length = i;
}
/* If the string was not truncated due to `set print elements', and
the last byte of it is a null, we don't print that, in
traditional C style. */
if (!force_ellipses
&& length > 0
&& (extract_unsigned_integer (string + (length - 1) * width,
width, byte_order) == 0))
length--;
str_type = (classify_type (type, get_type_arch (type), &type_encoding)
& ~C_CHAR);
switch (str_type)
@ -439,193 +226,10 @@ c_printstr (struct ui_file *stream, struct type *type,
break;
}
encoding = (user_encoding && *user_encoding)
? user_encoding : type_encoding;
encoding = (user_encoding && *user_encoding) ? user_encoding : type_encoding;
if (length == 0)
{
fputs_filtered ("\"\"", stream);
return;
}
/* 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);
/* 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)
{
int num_chars;
enum wchar_iterate_result result;
gdb_wchar_t *chars;
const gdb_byte *buf;
size_t buflen;
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;
}
/* 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 ("\\\", "));
else
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 ("\\\""));
else
obstack_grow_wstr (&wchar_buf, LCST ("\""));
in_quotes = 1;
need_escape = 0;
}
while (reps-- > 0)
{
print_wchar (current_char, orig_buf,
orig_len, width,
byte_order, &wchar_buf,
'"', &need_escape);
++things_printed;
}
}
}
/* 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;
}
switch (result)
{
case wchar_iterate_invalid:
if (!in_quotes)
{
if (options->inspect_it)
obstack_grow_wstr (&wchar_buf, LCST ("\\\""));
else
obstack_grow_wstr (&wchar_buf, LCST ("\""));
in_quotes = 1;
}
need_escape = 0;
print_wchar (gdb_WEOF, buf, buflen, width, byte_order,
&wchar_buf, '"', &need_escape);
break;
case wchar_iterate_incomplete:
if (in_quotes)
{
if (options->inspect_it)
obstack_grow_wstr (&wchar_buf, LCST ("\\\","));
else
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;
}
}
/* Terminate the quotes if necessary. */
if (in_quotes)
{
if (options->inspect_it)
obstack_grow_wstr (&wchar_buf, LCST ("\\\""));
else
obstack_grow_wstr (&wchar_buf, LCST ("\""));
}
if (force_ellipses || !finished)
obstack_grow_wstr (&wchar_buf, LCST ("..."));
/* OUTPUT is where we collect `char's for printing. */
obstack_init (&output);
make_cleanup_obstack_free (&output);
convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
obstack_base (&wchar_buf),
obstack_object_size (&wchar_buf),
1, &output, translit_char);
obstack_1grow (&output, '\0');
fputs_filtered (obstack_base (&output), stream);
do_cleanups (cleanup);
generic_printstr (stream, type, string, length, encoding, force_ellipses,
'"', 1, options);
}
/* Obtain a C string from the inferior storing it in a newly allocated