C++ify xmethod_worker, get rid of VEC(xmethod_worker_ptr)
[deliverable/binutils-gdb.git] / gdb / utils.c
index 118fcc3e6d048afab58dba0d3162bd70608a6dce..c531748fe46abdae5ba82a3a6e20078dd41a2473 100644 (file)
@@ -1,6 +1,6 @@
 /* General utility routines for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2017 Free Software Foundation, Inc.
+   Copyright (C) 1986-2018 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -68,6 +68,8 @@
 #include "job-control.h"
 #include "common/selftest.h"
 #include "common/gdb_optional.h"
+#include "cp-support.h"
+#include <algorithm>
 
 #if !HAVE_DECL_MALLOC
 extern PTR malloc ();          /* ARI: PTR */
@@ -185,22 +187,6 @@ make_cleanup_value_free_to_mark (struct value *mark)
   return make_cleanup (do_value_free_to_mark, mark);
 }
 
-/* Helper for make_cleanup_value_free.  */
-
-static void
-do_value_free (void *value)
-{
-  value_free ((struct value *) value);
-}
-
-/* Free VALUE.  */
-
-struct cleanup *
-make_cleanup_value_free (struct value *value)
-{
-  return make_cleanup (do_value_free, value);
-}
-
 /* This function is useful for cleanups.
    Do
 
@@ -566,12 +552,12 @@ demangler_warning (const char *file, int line, const char *string, ...)
 /* Dummy functions to keep add_prefix_cmd happy.  */
 
 static void
-set_internal_problem_cmd (char *args, int from_tty)
+set_internal_problem_cmd (const char *args, int from_tty)
 {
 }
 
 static void
-show_internal_problem_cmd (char *args, int from_tty)
+show_internal_problem_cmd (const char *args, int from_tty)
 {
 }
 
@@ -609,14 +595,14 @@ add_internal_problem_command (struct internal_problem *problem)
   show_doc = xstrprintf (_("Show what GDB does when %s is detected."),
                         problem->name);
 
-  add_prefix_cmd ((char*) problem->name,
+  add_prefix_cmd (problem->name,
                  class_maintenance, set_internal_problem_cmd, set_doc,
                  set_cmd_list,
                  concat ("maintenance set ", problem->name, " ",
                          (char *) NULL),
                  0/*allow-unknown*/, &maintenance_set_cmdlist);
 
-  add_prefix_cmd ((char*) problem->name,
+  add_prefix_cmd (problem->name,
                  class_maintenance, show_internal_problem_cmd, show_doc,
                  show_cmd_list,
                  concat ("maintenance show ", problem->name, " ",
@@ -744,8 +730,6 @@ print_sys_errmsg (const char *string, int errcode)
 void
 quit (void)
 {
-  struct ui *ui = current_ui;
-
   if (sync_quit_force_run)
     {
       sync_quit_force_run = 0;
@@ -906,7 +890,6 @@ private:
 static int ATTRIBUTE_PRINTF (1, 0)
 defaulted_query (const char *ctlstr, const char defchar, va_list args)
 {
-  int ans2;
   int retval;
   int def_value;
   char def_answer, not_def_answer;
@@ -1475,14 +1458,14 @@ set_width (void)
 }
 
 static void
-set_width_command (char *args, int from_tty, struct cmd_list_element *c)
+set_width_command (const char *args, int from_tty, struct cmd_list_element *c)
 {
   set_screen_size ();
   set_width ();
 }
 
 static void
-set_height_command (char *args, int from_tty, struct cmd_list_element *c)
+set_height_command (const char *args, int from_tty, struct cmd_list_element *c)
 {
   set_screen_size ();
 }
@@ -2172,34 +2155,292 @@ fprintf_symbol_filtered (struct ui_file *stream, const char *name,
     }
 }
 
-/* Modes of operation for strncmp_iw_with_mode.  */
+/* True if CH is a character that can be part of a symbol name.  I.e.,
+   either a number, a letter, or a '_'.  */
 
-enum class strncmp_iw_mode
+static bool
+valid_identifier_name_char (int ch)
 {
-  /* Work like strncmp, while ignoring whitespace.  */
-  NORMAL,
+  return (isalnum (ch) || ch == '_');
+}
 
-  /* Like NORMAL, but also apply the strcmp_iw hack.  I.e.,
-     string1=="FOO(PARAMS)" matches string2=="FOO".  */
-  MATCH_PARAMS,
-};
+/* Skip to end of token, or to END, whatever comes first.  Input is
+   assumed to be a C++ operator name.  */
 
-/* Helper for strncmp_iw and strcmp_iw.  */
+static const char *
+cp_skip_operator_token (const char *token, const char *end)
+{
+  const char *p = token;
+  while (p != end && !isspace (*p) && *p != '(')
+    {
+      if (valid_identifier_name_char (*p))
+       {
+         while (p != end && valid_identifier_name_char (*p))
+           p++;
+         return p;
+       }
+      else
+       {
+         /* Note, ordered such that among ops that share a prefix,
+            longer comes first.  This is so that the loop below can
+            bail on first match.  */
+         static const char *ops[] =
+           {
+             "[",
+             "]",
+             "~",
+             ",",
+             "-=", "--", "->", "-",
+             "+=", "++", "+",
+             "*=", "*",
+             "/=", "/",
+             "%=", "%",
+             "|=", "||", "|",
+             "&=", "&&", "&",
+             "^=", "^",
+             "!=", "!",
+             "<<=", "<=", "<<", "<",
+             ">>=", ">=", ">>", ">",
+             "==", "=",
+           };
+
+         for (const char *op : ops)
+           {
+             size_t oplen = strlen (op);
+             size_t lencmp = std::min<size_t> (oplen, end - p);
 
-static int
+             if (strncmp (p, op, lencmp) == 0)
+               return p + lencmp;
+           }
+         /* Some unidentified character.  Return it.  */
+         return p + 1;
+       }
+    }
+
+  return p;
+}
+
+/* Advance STRING1/STRING2 past whitespace.  */
+
+static void
+skip_ws (const char *&string1, const char *&string2, const char *end_str2)
+{
+  while (isspace (*string1))
+    string1++;
+  while (string2 < end_str2 && isspace (*string2))
+    string2++;
+}
+
+/* True if STRING points at the start of a C++ operator name.  START
+   is the start of the string that STRING points to, hence when
+   reading backwards, we must not read any character before START.  */
+
+static bool
+cp_is_operator (const char *string, const char *start)
+{
+  return ((string == start
+          || !valid_identifier_name_char (string[-1]))
+         && strncmp (string, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
+         && !valid_identifier_name_char (string[CP_OPERATOR_LEN]));
+}
+
+/* If *NAME points at an ABI tag, skip it and return true.  Otherwise
+   leave *NAME unmodified and return false.  (see GCC's abi_tag
+   attribute), such names are demangled as e.g.,
+   "function[abi:cxx11]()".  */
+
+static bool
+skip_abi_tag (const char **name)
+{
+  const char *p = *name;
+
+  if (startswith (p, "[abi:"))
+    {
+      p += 5;
+
+      while (valid_identifier_name_char (*p))
+       p++;
+
+      if (*p == ']')
+       {
+         p++;
+         *name = p;
+         return true;
+       }
+    }
+  return false;
+}
+
+/* See utils.h.  */
+
+int
 strncmp_iw_with_mode (const char *string1, const char *string2,
-                     size_t string2_len, strncmp_iw_mode mode)
+                     size_t string2_len, strncmp_iw_mode mode,
+                     enum language language,
+                     completion_match_for_lcd *match_for_lcd)
 {
+  const char *string1_start = string1;
   const char *end_str2 = string2 + string2_len;
+  bool skip_spaces = true;
+  bool have_colon_op = (language == language_cplus
+                       || language == language_rust
+                       || language == language_fortran);
 
   while (1)
     {
-      while (isspace (*string1))
-       string1++;
-      while (string2 < end_str2 && isspace (*string2))
-       string2++;
+      if (skip_spaces
+         || ((isspace (*string1) && !valid_identifier_name_char (*string2))
+             || (isspace (*string2) && !valid_identifier_name_char (*string1))))
+       {
+         skip_ws (string1, string2, end_str2);
+         skip_spaces = false;
+       }
+
+      /* Skip [abi:cxx11] tags in the symbol name if the lookup name
+        doesn't include them.  E.g.:
+
+        string1: function[abi:cxx1](int)
+        string2: function
+
+        string1: function[abi:cxx1](int)
+        string2: function(int)
+
+        string1: Struct[abi:cxx1]::function()
+        string2: Struct::function()
+
+        string1: function(Struct[abi:cxx1], int)
+        string2: function(Struct, int)
+      */
+      if (string2 == end_str2
+         || (*string2 != '[' && !valid_identifier_name_char (*string2)))
+       {
+         const char *abi_start = string1;
+
+         /* There can be more than one tag.  */
+         while (*string1 == '[' && skip_abi_tag (&string1))
+           ;
+
+         if (match_for_lcd != NULL && abi_start != string1)
+           match_for_lcd->mark_ignored_range (abi_start, string1);
+
+         while (isspace (*string1))
+           string1++;
+       }
+
       if (*string1 == '\0' || string2 == end_str2)
        break;
+
+      /* Handle the :: operator.  */
+      if (have_colon_op && string1[0] == ':' && string1[1] == ':')
+       {
+         if (*string2 != ':')
+           return 1;
+
+         string1++;
+         string2++;
+
+         if (string2 == end_str2)
+           break;
+
+         if (*string2 != ':')
+           return 1;
+
+         string1++;
+         string2++;
+
+         while (isspace (*string1))
+           string1++;
+         while (string2 < end_str2 && isspace (*string2))
+           string2++;
+         continue;
+       }
+
+      /* Handle C++ user-defined operators.  */
+      else if (language == language_cplus
+              && *string1 == 'o')
+       {
+         if (cp_is_operator (string1, string1_start))
+           {
+             /* An operator name in STRING1.  Check STRING2.  */
+             size_t cmplen
+               = std::min<size_t> (CP_OPERATOR_LEN, end_str2 - string2);
+             if (strncmp (string1, string2, cmplen) != 0)
+               return 1;
+
+             string1 += cmplen;
+             string2 += cmplen;
+
+             if (string2 != end_str2)
+               {
+                 /* Check for "operatorX" in STRING2.  */
+                 if (valid_identifier_name_char (*string2))
+                   return 1;
+
+                 skip_ws (string1, string2, end_str2);
+               }
+
+             /* Handle operator().  */
+             if (*string1 == '(')
+               {
+                 if (string2 == end_str2)
+                   {
+                     if (mode == strncmp_iw_mode::NORMAL)
+                       return 0;
+                     else
+                       {
+                         /* Don't break for the regular return at the
+                            bottom, because "operator" should not
+                            match "operator()", since this open
+                            parentheses is not the parameter list
+                            start.  */
+                         return *string1 != '\0';
+                       }
+                   }
+
+                 if (*string1 != *string2)
+                   return 1;
+
+                 string1++;
+                 string2++;
+               }
+
+             while (1)
+               {
+                 skip_ws (string1, string2, end_str2);
+
+                 /* Skip to end of token, or to END, whatever comes
+                    first.  */
+                 const char *end_str1 = string1 + strlen (string1);
+                 const char *p1 = cp_skip_operator_token (string1, end_str1);
+                 const char *p2 = cp_skip_operator_token (string2, end_str2);
+
+                 cmplen = std::min (p1 - string1, p2 - string2);
+                 if (p2 == end_str2)
+                   {
+                     if (strncmp (string1, string2, cmplen) != 0)
+                       return 1;
+                   }
+                 else
+                   {
+                     if (p1 - string1 != p2 - string2)
+                       return 1;
+                     if (strncmp (string1, string2, cmplen) != 0)
+                       return 1;
+                   }
+
+                 string1 += cmplen;
+                 string2 += cmplen;
+
+                 if (*string1 == '\0' || string2 == end_str2)
+                   break;
+                 if (*string1 == '(' || *string2 == '(')
+                   break;
+               }
+
+             continue;
+           }
+       }
+
       if (case_sensitivity == case_sensitive_on && *string1 != *string2)
        break;
       if (case_sensitivity == case_sensitive_off
@@ -2207,6 +2448,12 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
              != tolower ((unsigned char) *string2)))
        break;
 
+      /* If we see any non-whitespace, non-identifier-name character
+        (any of "()<>*&" etc.), then skip spaces the next time
+        around.  */
+      if (!isspace (*string1) && !valid_identifier_name_char (*string1))
+       skip_spaces = true;
+
       string1++;
       string2++;
     }
@@ -2214,7 +2461,40 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
   if (string2 == end_str2)
     {
       if (mode == strncmp_iw_mode::NORMAL)
-       return 0;
+       {
+         /* Strip abi tag markers from the matched symbol name.
+            Usually the ABI marker will be found on function name
+            (automatically added because the function returns an
+            object marked with an ABI tag).  However, it's also
+            possible to see a marker in one of the function
+            parameters, for example.
+
+            string2 (lookup name):
+              func
+            symbol name:
+              function(some_struct[abi:cxx11], int)
+
+            and for completion LCD computation we want to say that
+            the match was for:
+              function(some_struct, int)
+         */
+         if (match_for_lcd != NULL)
+           {
+             while ((string1 = strstr (string1, "[abi:")) != NULL)
+               {
+                 const char *abi_start = string1;
+
+                 /* There can be more than one tag.  */
+                 while (skip_abi_tag (&string1) && *string1 == '[')
+                   ;
+
+                 if (abi_start != string1)
+                   match_for_lcd->mark_ignored_range (abi_start, string1);
+               }
+           }
+
+         return 0;
+       }
       else
        return (*string1 != '\0' && *string1 != '(');
     }
@@ -2228,7 +2508,7 @@ int
 strncmp_iw (const char *string1, const char *string2, size_t string2_len)
 {
   return strncmp_iw_with_mode (string1, string2, string2_len,
-                              strncmp_iw_mode::NORMAL);
+                              strncmp_iw_mode::NORMAL, language_minimal);
 }
 
 /* See utils.h.  */
@@ -2237,7 +2517,7 @@ int
 strcmp_iw (const char *string1, const char *string2)
 {
   return strncmp_iw_with_mode (string1, string2, strlen (string2),
-                              strncmp_iw_mode::MATCH_PARAMS);
+                              strncmp_iw_mode::MATCH_PARAMS, language_minimal);
 }
 
 /* This is like strcmp except that it ignores whitespace and treats
@@ -2444,6 +2724,23 @@ When set, debugging messages will be marked with seconds and microseconds."),
                           &setdebuglist, &showdebuglist);
 }
 
+/* See utils.h.  */
+
+CORE_ADDR
+address_significant (gdbarch *gdbarch, CORE_ADDR addr)
+{
+  /* Truncate address to the significant bits of a target address,
+     avoiding shifts larger or equal than the width of a CORE_ADDR.
+     The local variable ADDR_BIT stops the compiler reporting a shift
+     overflow when it won't occur.  */
+  int addr_bit = gdbarch_significant_addr_bit (gdbarch);
+
+  if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+    addr &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+  return addr;
+}
+
 const char *
 paddress (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
This page took 0.030661 seconds and 4 git commands to generate.