gdb
authorTom Tromey <tromey@redhat.com>
Wed, 29 Jun 2011 15:32:40 +0000 (15:32 +0000)
committerTom Tromey <tromey@redhat.com>
Wed, 29 Jun 2011 15:32:40 +0000 (15:32 +0000)
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.

gdb/ChangeLog
gdb/c-lang.c
gdb/dwarf2read.c
gdb/f-lang.c
gdb/f-typeprint.c
gdb/f-valprint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.fortran/charset.exp [new file with mode: 0644]
gdb/testsuite/gdb.fortran/charset.f90 [new file with mode: 0644]
gdb/valprint.c
gdb/valprint.h

index 895d00b5bb33a772a45eaff17f3af0b4cf486224..6961d69af89ae7cd8d7cca9d76567f1991dc7b96 100644 (file)
@@ -1,3 +1,30 @@
+2011-06-29  Tom Tromey  <tromey@redhat.com>
+
+       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.
+
 2011-06-29  Gary Benson  <gbenson@redhat.com>
 
        * breakpoint.c (bpstat_what): Removed duplicated case.
index 255fabe2bfdf1798695da0e96e6df3a4ecc8492b..3a35a78205748bcbf7b8bf131c02ec539f501404 100644 (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;
-
-  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);
+  encoding = (user_encoding && *user_encoding) ? user_encoding : type_encoding;
 
-  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
index cfe0514eb8213e75c74bc6b7ec75642a15ae4584..bc958bb5bfafa5b94136ce2d3783e3e8d2c14659 100644 (file)
@@ -8335,15 +8335,21 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
        break;
       case DW_ATE_unsigned:
        type_flags |= TYPE_FLAG_UNSIGNED;
+       if (cu->language == language_fortran
+           && name
+           && strncmp (name, "character(", sizeof ("character(") - 1) == 0)
+         code = TYPE_CODE_CHAR;
        break;
       case DW_ATE_signed_char:
        if (cu->language == language_ada || cu->language == language_m2
-           || cu->language == language_pascal)
+           || cu->language == language_pascal
+           || cu->language == language_fortran)
          code = TYPE_CODE_CHAR;
        break;
       case DW_ATE_unsigned_char:
        if (cu->language == language_ada || cu->language == language_m2
-           || cu->language == language_pascal)
+           || cu->language == language_pascal
+           || cu->language == language_fortran)
          code = TYPE_CODE_CHAR;
        type_flags |= TYPE_FLAG_UNSIGNED;
        break;
index 61513c121eac654a2da26ba5f912fab1051f138d..f538eee680a7371eb502390e783aaed4090e1bdf 100644 (file)
@@ -32,6 +32,7 @@
 #include "valprint.h"
 #include "value.h"
 #include "cp-support.h"
+#include "charset.h"
 
 
 /* Following is dubious stuff that had been in the xcoff reader.  */
@@ -76,6 +77,33 @@ static void f_printchar (int c, struct type *type, struct ui_file * stream);
 static void f_emit_char (int c, struct type *type,
                         struct ui_file * stream, int quoter);
 
+/* Return the encoding that should be used for the character type
+   TYPE.  */
+
+static const char *
+f_get_encoding (struct type *type)
+{
+  const char *encoding;
+
+  switch (TYPE_LENGTH (type))
+    {
+    case 1:
+      encoding = target_charset (get_type_arch (type));
+      break;
+    case 4:
+      if (gdbarch_byte_order (get_type_arch (type)) == BFD_ENDIAN_BIG)
+       encoding = "UTF-32BE";
+      else
+       encoding = "UTF-32LE";
+      break;
+
+    default:
+      error (_("unrecognized character type"));
+    }
+
+  return encoding;
+}
+
 /* 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.
@@ -85,48 +113,12 @@ static void f_emit_char (int c, struct type *type,
 static void
 f_emit_char (int c, struct type *type, struct ui_file *stream, int quoter)
 {
-  c &= 0xFF;                   /* Avoid sign bit follies.  */
+  const char *encoding = f_get_encoding (type);
 
-  if (PRINT_LITERAL_FORM (c))
-    {
-      if (c == '\\' || c == quoter)
-       fputs_filtered ("\\", stream);
-      fprintf_filtered (stream, "%c", c);
-    }
-  else
-    {
-      switch (c)
-       {
-       case '\n':
-         fputs_filtered ("\\n", stream);
-         break;
-       case '\b':
-         fputs_filtered ("\\b", stream);
-         break;
-       case '\t':
-         fputs_filtered ("\\t", stream);
-         break;
-       case '\f':
-         fputs_filtered ("\\f", stream);
-         break;
-       case '\r':
-         fputs_filtered ("\\r", stream);
-         break;
-       case '\033':
-         fputs_filtered ("\\e", stream);
-         break;
-       case '\007':
-         fputs_filtered ("\\a", stream);
-         break;
-       default:
-         fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
-         break;
-       }
-    }
+  generic_emit_char (c, type, stream, quoter, encoding);
 }
 
-/* FIXME:  This is a copy of the same function from c-exp.y.  It should
-   be replaced with a true F77version.  */
+/* Implementation of la_printchar.  */
 
 static void
 f_printchar (int c, struct type *type, struct ui_file *stream)
@@ -148,83 +140,16 @@ f_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
            unsigned int length, const char *encoding, int force_ellipses,
            const struct value_print_options *options)
 {
-  unsigned int i;
-  unsigned int things_printed = 0;
-  int in_quotes = 0;
-  int need_comma = 0;
-
-  if (length == 0)
-    {
-      fputs_filtered ("''", gdb_stdout);
-      return;
-    }
-
-  for (i = 0; i < length && things_printed < options->print_max; ++i)
-    {
-      /* Position of the character we are examining
-         to see whether it is repeated.  */
-      unsigned int rep1;
-      /* Number of repetitions we have detected so far.  */
-      unsigned int reps;
-
-      QUIT;
-
-      if (need_comma)
-       {
-         fputs_filtered (", ", stream);
-         need_comma = 0;
-       }
+  const char *type_encoding = f_get_encoding (type);
 
-      rep1 = i + 1;
-      reps = 1;
-      while (rep1 < length && string[rep1] == string[i])
-       {
-         ++rep1;
-         ++reps;
-       }
+  if (TYPE_LENGTH (type) == 4)
+    fputs_filtered ("4_", stream);
 
-      if (reps > options->repeat_count_threshold)
-       {
-         if (in_quotes)
-           {
-             if (options->inspect_it)
-               fputs_filtered ("\\', ", stream);
-             else
-               fputs_filtered ("', ", stream);
-             in_quotes = 0;
-           }
-         f_printchar (string[i], type, stream);
-         fprintf_filtered (stream, " <repeats %u times>", reps);
-         i = rep1 - 1;
-         things_printed += options->repeat_count_threshold;
-         need_comma = 1;
-       }
-      else
-       {
-         if (!in_quotes)
-           {
-             if (options->inspect_it)
-               fputs_filtered ("\\'", stream);
-             else
-               fputs_filtered ("'", stream);
-             in_quotes = 1;
-           }
-         LA_EMIT_CHAR (string[i], type, stream, '"');
-         ++things_printed;
-       }
-    }
-
-  /* Terminate the quotes if necessary.  */
-  if (in_quotes)
-    {
-      if (options->inspect_it)
-       fputs_filtered ("\\'", stream);
-      else
-       fputs_filtered ("'", stream);
-    }
+  if (!encoding || !*encoding)
+    encoding = type_encoding;
 
-  if (force_ellipses || i < length)
-    fputs_filtered ("...", stream);
+  generic_printstr (stream, type, string, length, encoding,
+                   force_ellipses, '\'', 0, options);
 }
 \f
 
index ad988d23dd20081d8ff782c7405cc9440be31f38..6d9e6ec17e99dca0c4831c0d125867f4b6e89acd 100644 (file)
@@ -321,10 +321,6 @@ f_type_print_base (struct type *type, struct ui_file *stream, int show,
       break;
 
     case TYPE_CODE_CHAR:
-      /* Override name "char" and make it "character".  */
-      fprintfi_filtered (level, stream, "character");
-      break;
-
     case TYPE_CODE_INT:
       /* There may be some character types that attempt to come
          through as TYPE_CODE_INT since dbxstclass.h is so
index 3280ddcb5d98ff890be0f09184f1c1a370efd311..66b425d78c956b851b1ae9de106a5ce2d862169b 100644 (file)
@@ -271,10 +271,23 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
       break;
 
     case TYPE_CODE_ARRAY:
-      fprintf_filtered (stream, "(");
-      f77_print_array (type, valaddr, embedded_offset,
-                      address, stream, recurse, original_value, options);
-      fprintf_filtered (stream, ")");
+      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_CHAR)
+       {
+         fprintf_filtered (stream, "(");
+         f77_print_array (type, valaddr, embedded_offset,
+                          address, stream, recurse, original_value, options);
+         fprintf_filtered (stream, ")");
+       }
+      else
+       {
+         struct type *ch_type = TYPE_TARGET_TYPE (type);
+
+         f77_get_dynamic_length_of_aggregate (type);
+         LA_PRINT_STRING (stream, ch_type,
+                          valaddr + embedded_offset,
+                          TYPE_LENGTH (type) / TYPE_LENGTH (ch_type),
+                          NULL, 0, options);
+       }
       break;
 
     case TYPE_CODE_PTR:
@@ -363,6 +376,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
       break;
 
     case TYPE_CODE_INT:
+    case TYPE_CODE_CHAR:
       if (options->format || options->output_format)
        {
          struct value_print_options opts = *options;
@@ -379,7 +393,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
             Since we don't know whether the value is really intended to
             be used as an integer or a character, print the character
             equivalent as well.  */
-         if (TYPE_LENGTH (type) == 1)
+         if (TYPE_LENGTH (type) == 1 || TYPE_CODE (type) == TYPE_CODE_CHAR)
            {
              LONGEST c;
 
index 83a1e8f6dc69817a9c20392605fd7060bc5ad470..f156a7c9b85e304d5e1fbdbbc163d246c3f80458 100644 (file)
@@ -1,3 +1,8 @@
+2011-06-29  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.fortran/charset.exp: New file.
+       * gdb.fortran/charset.f90: New file.
+
 2011-06-29  Tom Tromey  <tromey@redhat.com>
 
        PR testsuite/12040:
diff --git a/gdb/testsuite/gdb.fortran/charset.exp b/gdb/testsuite/gdb.fortran/charset.exp
new file mode 100644 (file)
index 0000000..95b7037
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# 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/>.
+
+# This file is part of the gdb testsuite.  It contains tests for evaluating
+# Fortran subarray expression.
+
+if { [skip_fortran_tests] } { return -1 }
+
+set testfile "charset"
+set srcfile ${testfile}.f90
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug additional_flags=-fbackslash f90}] } {
+    return -1
+}
+
+if ![runto MAIN__] {
+    perror "Couldn't run to MAIN__"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "print x" \
+    " = 'j'" \
+    "print fortran narrow character"
+
+gdb_test "print c" \
+    " = 4_'k'" \
+    "print fortran wide character"
+
+gdb_test "print str" \
+    " = 4_'lmnop'" \
+    "print fortran wide string"
diff --git a/gdb/testsuite/gdb.fortran/charset.f90 b/gdb/testsuite/gdb.fortran/charset.f90
new file mode 100644 (file)
index 0000000..15cf360
--- /dev/null
@@ -0,0 +1,10 @@
+character(kind=1) :: x
+character(kind=4) :: c
+character(kind=4,len=5) :: str
+x = 'j'
+c = 4_'k'
+str = 4_'lmnop'
+! break-here
+print *, c
+print *, str
+end
index 9bf19f4b469bc31912b9ece503f2badd5e793491..b26924a6ef4a995e8cb6f890c25c130980ef444f 100644 (file)
@@ -36,6 +36,9 @@
 #include "dfp.h"
 #include "python/python.h"
 #include "ada-lang.h"
+#include "gdb_obstack.h"
+#include "charset.h"
+#include <ctype.h>
 
 #include <errno.h>
 
@@ -1466,6 +1469,450 @@ read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit,
   return errcode;
 }
 
+/* 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.  ENCODING names the
+   encoding of C.  */
+
+void
+generic_emit_char (int c, struct type *type, struct ui_file *stream,
+                  int quoter, const char *encoding)
+{
+  enum bfd_endian byte_order
+    = gdbarch_byte_order (get_type_arch (type));
+  struct obstack wchar_buf, output;
+  struct cleanup *cleanups;
+  gdb_byte *buf;
+  struct wchar_iterator *iter;
+  int need_escape = 0;
+
+  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);
+}
+
+/* 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; 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)
+{
+  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);
+
+  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 (c_style_terminator
+      && !force_ellipses
+      && length > 0
+      && (extract_unsigned_integer (string + (length - 1) * width,
+                                   width, byte_order) == 0))
+    length--;
+
+  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 ("\\"));
+                 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;
+               }
+
+             while (reps-- > 0)
+               {
+                 print_wchar (current_char, orig_buf,
+                              orig_len, width,
+                              byte_order, &wchar_buf,
+                              quote_char, &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 ("\\"));
+             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;
+
+       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;
+       }
+    }
+
+  /* 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));
+    }
+
+  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);
+}
+
 /* 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
index b6ea7a99894fe3e9ddb3bb7d3387c62908db8e21..8aef685fb4a377edb1195b4ca54a33695b0b0a0c 100644 (file)
@@ -158,4 +158,13 @@ extern void val_print_unavailable (struct ui_file *stream);
 
 extern void val_print_invalid_address (struct ui_file *stream);
 
+extern void generic_emit_char (int c, struct type *type, struct ui_file *stream,
+                              int quoter, const char *encoding);
+
+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);
+
 #endif