* printcmd.c (printf_c_string,printf_wide_c_string): New functions.
authorDoug Evans <dje@google.com>
Mon, 11 Feb 2013 22:04:58 +0000 (22:04 +0000)
committerDoug Evans <dje@google.com>
Mon, 11 Feb 2013 22:04:58 +0000 (22:04 +0000)
(printf_decfloat): New function.  Broken out from ui_printf.
Remove unnecessary code to shift the entire format string down.
(printf_pointer): New function.
(ui_printf): Code to print C strings, wide C strings, decfloats,
and pointers moved to separate functions.

gdb/ChangeLog
gdb/printcmd.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/printcmds.exp

index c9c39199ffd3eb7fa9d63e5829bc9de9bd6c0135..80d4898e5f677438a9b45bc0102f7abb649ee638 100644 (file)
@@ -1,3 +1,12 @@
+2013-02-11  Doug Evans  <dje@google.com>
+
+       * printcmd.c (printf_c_string,printf_wide_c_string): New functions.
+       (printf_decfloat): New function.  Broken out from ui_printf.
+       Remove unnecessary code to shift the entire format string down.
+       (printf_pointer): New function.
+       (ui_printf): Code to print C strings, wide C strings, decfloats,
+       and pointers moved to separate functions.
+
 2013-02-11  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        * valops.c (value_assign): Handling bitfield offset in
index d94d28d4074bfea75d1536a3706db22077ef88a8..9092f092957f3e5a766d1a294be7035ca9d5dbe5 100644 (file)
@@ -1978,6 +1978,241 @@ print_variable_and_value (const char *name, struct symbol *var,
   fprintf_filtered (stream, "\n");
 }
 
+/* Subroutine of ui_printf to simplify it.
+   Print VALUE to STREAM using FORMAT.
+   VALUE is either a C-style string on the target, or an internal variable.  */
+
+static void
+printf_c_string (struct ui_file *stream, const char *format,
+                struct value *value)
+{
+  gdb_byte *str;
+  CORE_ADDR tem;
+  int j;
+
+  tem = value_as_address (value);
+
+  /* This is a %s argument.  Find the length of the string.  */
+  for (j = 0;; j++)
+    {
+      gdb_byte c;
+
+      QUIT;
+      read_memory (tem + j, &c, 1);
+      if (c == 0)
+       break;
+    }
+
+  /* Copy the string contents into a string inside GDB.  */
+  str = (gdb_byte *) alloca (j + 1);
+  if (j != 0)
+    read_memory (tem, str, j);
+  str[j] = 0;
+
+  fprintf_filtered (stream, format, (char *) str);
+}
+
+/* Subroutine of ui_printf to simplify it.
+   Print VALUE to STREAM using FORMAT.
+   VALUE is either a wide C-style string on the target,
+   or an internal variable.  */
+
+static void
+printf_wide_c_string (struct ui_file *stream, const char *format,
+                     struct value *value)
+{
+  gdb_byte *str;
+  CORE_ADDR tem;
+  int j;
+  struct gdbarch *gdbarch = get_type_arch (value_type (value));
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct type *wctype = lookup_typename (current_language, gdbarch,
+                                        "wchar_t", NULL, 0);
+  int wcwidth = TYPE_LENGTH (wctype);
+  gdb_byte *buf = alloca (wcwidth);
+  struct obstack output;
+  struct cleanup *inner_cleanup;
+
+  tem = value_as_address (value);
+
+  /* This is a %s argument.  Find the length of the string.  */
+  for (j = 0;; j += wcwidth)
+    {
+      QUIT;
+      read_memory (tem + j, buf, wcwidth);
+      if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
+       break;
+    }
+
+  /* Copy the string contents into a string inside GDB.  */
+  str = (gdb_byte *) alloca (j + wcwidth);
+  if (j != 0)
+    read_memory (tem, str, j);
+  memset (&str[j], 0, wcwidth);
+
+  obstack_init (&output);
+  inner_cleanup = make_cleanup_obstack_free (&output);
+
+  convert_between_encodings (target_wide_charset (gdbarch),
+                            host_charset (),
+                            str, j, wcwidth,
+                            &output, translit_char);
+  obstack_grow_str0 (&output, "");
+
+  fprintf_filtered (stream, format, obstack_base (&output));
+  do_cleanups (inner_cleanup);
+}
+
+/* Subroutine of ui_printf to simplify it.
+   Print VALUE, a decimal floating point value, to STREAM using FORMAT.  */
+
+static void
+printf_decfloat (struct ui_file *stream, const char *format,
+                struct value *value)
+{
+  const gdb_byte *param_ptr = value_contents (value);
+
+#if defined (PRINTF_HAS_DECFLOAT)
+  /* If we have native support for Decimal floating
+     printing, handle it here.  */
+  fprintf_filtered (stream, format, param_ptr);
+#else
+  /* As a workaround until vasprintf has native support for DFP
+     we convert the DFP values to string and print them using
+     the %s format specifier.  */
+  const char *p;
+
+  /* Parameter data.  */
+  struct type *param_type = value_type (value);
+  struct gdbarch *gdbarch = get_type_arch (param_type);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  /* DFP output data.  */
+  struct value *dfp_value = NULL;
+  gdb_byte *dfp_ptr;
+  int dfp_len = 16;
+  gdb_byte dec[16];
+  struct type *dfp_type = NULL;
+  char decstr[MAX_DECIMAL_STRING];
+
+  /* Points to the end of the string so that we can go back
+     and check for DFP length modifiers.  */
+  p = format + strlen (format);
+
+  /* Look for the float/double format specifier.  */
+  while (*p != 'f' && *p != 'e' && *p != 'E'
+        && *p != 'g' && *p != 'G')
+    p--;
+
+  /* Search for the '%' char and extract the size and type of
+     the output decimal value based on its modifiers
+     (%Hf, %Df, %DDf).  */
+  while (*--p != '%')
+    {
+      if (*p == 'H')
+       {
+         dfp_len = 4;
+         dfp_type = builtin_type (gdbarch)->builtin_decfloat;
+       }
+      else if (*p == 'D' && *(p - 1) == 'D')
+       {
+         dfp_len = 16;
+         dfp_type = builtin_type (gdbarch)->builtin_declong;
+         p--;
+       }
+      else
+       {
+         dfp_len = 8;
+         dfp_type = builtin_type (gdbarch)->builtin_decdouble;
+       }
+    }
+
+  /* Conversion between different DFP types.  */
+  if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT)
+    decimal_convert (param_ptr, TYPE_LENGTH (param_type),
+                    byte_order, dec, dfp_len, byte_order);
+  else
+    /* If this is a non-trivial conversion, just output 0.
+       A correct converted value can be displayed by explicitly
+       casting to a DFP type.  */
+    decimal_from_string (dec, dfp_len, byte_order, "0");
+
+  dfp_value = value_from_decfloat (dfp_type, dec);
+
+  dfp_ptr = (gdb_byte *) value_contents (dfp_value);
+
+  decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr);
+
+  /* Print the DFP value.  */
+  fprintf_filtered (stream, "%s", decstr);
+#endif
+}
+
+/* Subroutine of ui_printf to simplify it.
+   Print VALUE, a target pointer, to STREAM using FORMAT.  */
+
+static void
+printf_pointer (struct ui_file *stream, const char *format,
+               struct value *value)
+{
+  /* We avoid the host's %p because pointers are too
+     likely to be the wrong size.  The only interesting
+     modifier for %p is a width; extract that, and then
+     handle %p as glibc would: %#x or a literal "(nil)".  */
+
+  const char *p;
+  char *fmt, *fmt_p;
+#ifdef PRINTF_HAS_LONG_LONG
+  long long val = value_as_long (value);
+#else
+  long val = value_as_long (value);
+#endif
+
+  fmt = alloca (strlen (format) + 5);
+
+  /* Copy up to the leading %.  */
+  p = format;
+  fmt_p = fmt;
+  while (*p)
+    {
+      int is_percent = (*p == '%');
+
+      *fmt_p++ = *p++;
+      if (is_percent)
+       {
+         if (*p == '%')
+           *fmt_p++ = *p++;
+         else
+           break;
+       }
+    }
+
+  if (val != 0)
+    *fmt_p++ = '#';
+
+  /* Copy any width.  */
+  while (*p >= '0' && *p < '9')
+    *fmt_p++ = *p++;
+
+  gdb_assert (*p == 'p' && *(p + 1) == '\0');
+  if (val != 0)
+    {
+#ifdef PRINTF_HAS_LONG_LONG
+      *fmt_p++ = 'l';
+#endif
+      *fmt_p++ = 'l';
+      *fmt_p++ = 'x';
+      *fmt_p++ = '\0';
+      fprintf_filtered (stream, fmt, val);
+    }
+  else
+    {
+      *fmt_p++ = 's';
+      *fmt_p++ = '\0';
+      fprintf_filtered (stream, fmt, "(nil)");
+    }
+}
+
 /* printf "printf format string" ARG to STREAM.  */
 
 static void
@@ -2059,78 +2294,10 @@ ui_printf (char *arg, struct ui_file *stream)
        switch (fpieces[fr].argclass)
          {
          case string_arg:
-           {
-             gdb_byte *str;
-             CORE_ADDR tem;
-             int j;
-
-             tem = value_as_address (val_args[i]);
-
-             /* This is a %s argument.  Find the length of the string.  */
-             for (j = 0;; j++)
-               {
-                 gdb_byte c;
-
-                 QUIT;
-                 read_memory (tem + j, &c, 1);
-                 if (c == 0)
-                   break;
-               }
-
-             /* Copy the string contents into a string inside GDB.  */
-             str = (gdb_byte *) alloca (j + 1);
-             if (j != 0)
-               read_memory (tem, str, j);
-             str[j] = 0;
-
-              fprintf_filtered (stream, current_substring, (char *) str);
-           }
+           printf_c_string (stream, current_substring, val_args[i]);
            break;
          case wide_string_arg:
-           {
-             gdb_byte *str;
-             CORE_ADDR tem;
-             int j;
-             struct gdbarch *gdbarch
-               = get_type_arch (value_type (val_args[i]));
-             enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-             struct type *wctype = lookup_typename (current_language, gdbarch,
-                                                    "wchar_t", NULL, 0);
-             int wcwidth = TYPE_LENGTH (wctype);
-             gdb_byte *buf = alloca (wcwidth);
-             struct obstack output;
-             struct cleanup *inner_cleanup;
-
-             tem = value_as_address (val_args[i]);
-
-             /* This is a %s argument.  Find the length of the string.  */
-             for (j = 0;; j += wcwidth)
-               {
-                 QUIT;
-                 read_memory (tem + j, buf, wcwidth);
-                 if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
-                   break;
-               }
-
-             /* Copy the string contents into a string inside GDB.  */
-             str = (gdb_byte *) alloca (j + wcwidth);
-             if (j != 0)
-               read_memory (tem, str, j);
-             memset (&str[j], 0, wcwidth);
-
-             obstack_init (&output);
-             inner_cleanup = make_cleanup_obstack_free (&output);
-
-             convert_between_encodings (target_wide_charset (gdbarch),
-                                        host_charset (),
-                                        str, j, wcwidth,
-                                        &output, translit_char);
-             obstack_grow_str0 (&output, "");
-
-             fprintf_filtered (stream, current_substring,
-                                obstack_base (&output));
-             do_cleanups (inner_cleanup);
-           }
+           printf_wide_c_string (stream, current_substring, val_args[i]);
            break;
          case wide_char_arg:
            {
@@ -2227,169 +2394,13 @@ ui_printf (char *arg, struct ui_file *stream)
               fprintf_filtered (stream, current_substring, val);
              break;
            }
-
          /* Handles decimal floating values.  */
-       case decfloat_arg:
-           {
-             const gdb_byte *param_ptr = value_contents (val_args[i]);
-
-#if defined (PRINTF_HAS_DECFLOAT)
-             /* If we have native support for Decimal floating
-                printing, handle it here.  */
-              fprintf_filtered (stream, current_substring, param_ptr);
-#else
-
-             /* As a workaround until vasprintf has native support for DFP
-              we convert the DFP values to string and print them using
-              the %s format specifier.  */
-
-             char *eos, *sos;
-             int nnull_chars = 0;
-
-             /* Parameter data.  */
-             struct type *param_type = value_type (val_args[i]);
-             struct gdbarch *gdbarch = get_type_arch (param_type);
-             enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-
-             /* DFP output data.  */
-             struct value *dfp_value = NULL;
-             gdb_byte *dfp_ptr;
-             int dfp_len = 16;
-             gdb_byte dec[16];
-             struct type *dfp_type = NULL;
-             char decstr[MAX_DECIMAL_STRING];
-
-             /* Points to the end of the string so that we can go back
-                and check for DFP length modifiers.  */
-             eos = current_substring + strlen (current_substring);
-
-             /* Look for the float/double format specifier.  */
-             while (*eos != 'f' && *eos != 'e' && *eos != 'E'
-                    && *eos != 'g' && *eos != 'G')
-                 eos--;
-
-             sos = eos;
-
-             /* Search for the '%' char and extract the size and type of
-                the output decimal value based on its modifiers
-                (%Hf, %Df, %DDf).  */
-             while (*--sos != '%')
-               {
-                 if (*sos == 'H')
-                   {
-                     dfp_len = 4;
-                     dfp_type = builtin_type (gdbarch)->builtin_decfloat;
-                   }
-                 else if (*sos == 'D' && *(sos - 1) == 'D')
-                   {
-                     dfp_len = 16;
-                     dfp_type = builtin_type (gdbarch)->builtin_declong;
-                     sos--;
-                   }
-                 else
-                   {
-                     dfp_len = 8;
-                     dfp_type = builtin_type (gdbarch)->builtin_decdouble;
-                   }
-               }
-
-             /* Replace %Hf, %Df and %DDf with %s's.  */
-             *++sos = 's';
-
-             /* Go through the whole format string and pull the correct
-                number of chars back to compensate for the change in the
-                format specifier.  */
-             while (nnull_chars < nargs - i)
-               {
-                 if (*eos == '\0')
-                   nnull_chars++;
-
-                 *++sos = *++eos;
-               }
-
-             /* Conversion between different DFP types.  */
-             if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT)
-               decimal_convert (param_ptr, TYPE_LENGTH (param_type),
-                                byte_order, dec, dfp_len, byte_order);
-             else
-               /* If this is a non-trivial conversion, just output 0.
-                  A correct converted value can be displayed by explicitly
-                  casting to a DFP type.  */
-               decimal_from_string (dec, dfp_len, byte_order, "0");
-
-             dfp_value = value_from_decfloat (dfp_type, dec);
-
-             dfp_ptr = (gdb_byte *) value_contents (dfp_value);
-
-             decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr);
-
-             /* Print the DFP value.  */
-              fprintf_filtered (stream, current_substring, decstr);
-
-             break;
-#endif
-           }
-
+         case decfloat_arg:
+           printf_decfloat (stream, current_substring, val_args[i]);
+           break;
          case ptr_arg:
-           {
-             /* We avoid the host's %p because pointers are too
-                likely to be the wrong size.  The only interesting
-                modifier for %p is a width; extract that, and then
-                handle %p as glibc would: %#x or a literal "(nil)".  */
-
-             char *p, *fmt, *fmt_p;
-#ifdef PRINTF_HAS_LONG_LONG
-             long long val = value_as_long (val_args[i]);
-#else
-             long val = value_as_long (val_args[i]);
-#endif
-
-             fmt = alloca (strlen (current_substring) + 5);
-
-             /* Copy up to the leading %.  */
-             p = current_substring;
-             fmt_p = fmt;
-             while (*p)
-               {
-                 int is_percent = (*p == '%');
-
-                 *fmt_p++ = *p++;
-                 if (is_percent)
-                   {
-                     if (*p == '%')
-                       *fmt_p++ = *p++;
-                     else
-                       break;
-                   }
-               }
-
-             if (val != 0)
-               *fmt_p++ = '#';
-
-             /* Copy any width.  */
-             while (*p >= '0' && *p < '9')
-               *fmt_p++ = *p++;
-
-             gdb_assert (*p == 'p' && *(p + 1) == '\0');
-             if (val != 0)
-               {
-#ifdef PRINTF_HAS_LONG_LONG
-                 *fmt_p++ = 'l';
-#endif
-                 *fmt_p++ = 'l';
-                 *fmt_p++ = 'x';
-                 *fmt_p++ = '\0';
-                  fprintf_filtered (stream, fmt, val);
-               }
-             else
-               {
-                 *fmt_p++ = 's';
-                 *fmt_p++ = '\0';
-                  fprintf_filtered (stream, fmt, "(nil)");
-               }
-
-             break;
-           }
+           printf_pointer (stream, current_substring, val_args[i]);
+           break;
          case literal_piece:
            /* Print a portion of the format string that has no
               directives.  Note that this will not include any
index 822e031ea1135c8937e4c515cec1d7e9b007a747..bdbc59a0fc95218c92ac03c420dbbaa260ed4997 100644 (file)
@@ -1,3 +1,8 @@
+2013-02-11  Doug Evans  <dje@google.com>
+
+       * gdb.base/printcmds.exp (test_printf_with_dfp): Add test for printing
+       two decfloats.
+
 2013-02-11  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        * gdb.base/bitfields.c (struct internalvartest): New declaration.
index 735f563172be7d8cd1b434b8d31eee245af2f409..e9e6146a59e6e8f2343629c2d7ccd95ac6af9107 100644 (file)
@@ -770,6 +770,9 @@ proc test_printf_with_dfp {} {
 
     # The largest exponent for 128-bit dfp value is 6144.
     gdb_test "printf \"%DDf\\n\",1.2E6144dl" "1.200000000000000000000000000000000E\\+6144"
+
+    # GDB used to get this wrong.
+    gdb_test "printf \"%Hf %Hf\\n\",1.2df,1.3df" "1.2 1.3"
 }
 
 proc test_print_symbol {} {