+ /* 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
+ && (tolower ((unsigned char) *string1)
+ != 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++;
+ }
+
+ if (string2 == end_str2)
+ {
+ if (mode == strncmp_iw_mode::NORMAL)
+ {
+ /* 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 != '(');
+ }
+ else
+ return 1;
+}
+
+/* See utils.h. */
+
+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, language_minimal);
+}
+
+/* See utils.h. */
+
+int
+strcmp_iw (const char *string1, const char *string2)
+{
+ return strncmp_iw_with_mode (string1, string2, strlen (string2),
+ strncmp_iw_mode::MATCH_PARAMS, language_minimal);
+}
+
+/* This is like strcmp except that it ignores whitespace and treats
+ '(' as the first non-NULL character in terms of ordering. Like
+ strcmp (and unlike strcmp_iw), it returns negative if STRING1 <
+ STRING2, 0 if STRING2 = STRING2, and positive if STRING1 > STRING2
+ according to that ordering.
+
+ If a list is sorted according to this function and if you want to
+ find names in the list that match some fixed NAME according to
+ strcmp_iw(LIST_ELT, NAME), then the place to start looking is right
+ where this function would put NAME.
+
+ This function must be neutral to the CASE_SENSITIVITY setting as the user
+ may choose it during later lookup. Therefore this function always sorts
+ primarily case-insensitively and secondarily case-sensitively.
+
+ Here are some examples of why using strcmp to sort is a bad idea:
+
+ Whitespace example:
+
+ Say your partial symtab contains: "foo<char *>", "goo". Then, if
+ we try to do a search for "foo<char*>", strcmp will locate this
+ after "foo<char *>" and before "goo". Then lookup_partial_symbol
+ will start looking at strings beginning with "goo", and will never
+ see the correct match of "foo<char *>".
+
+ Parenthesis example:
+
+ In practice, this is less like to be an issue, but I'll give it a
+ shot. Let's assume that '$' is a legitimate character to occur in
+ symbols. (Which may well even be the case on some systems.) Then
+ say that the partial symbol table contains "foo$" and "foo(int)".
+ strcmp will put them in this order, since '$' < '('. Now, if the
+ user searches for "foo", then strcmp will sort "foo" before "foo$".
+ Then lookup_partial_symbol will notice that strcmp_iw("foo$",
+ "foo") is false, so it won't proceed to the actual match of
+ "foo(int)" with "foo". */
+
+int
+strcmp_iw_ordered (const char *string1, const char *string2)
+{
+ const char *saved_string1 = string1, *saved_string2 = string2;
+ enum case_sensitivity case_pass = case_sensitive_off;
+
+ for (;;)
+ {
+ /* C1 and C2 are valid only if *string1 != '\0' && *string2 != '\0'.
+ Provide stub characters if we are already at the end of one of the
+ strings. */
+ char c1 = 'X', c2 = 'X';
+
+ while (*string1 != '\0' && *string2 != '\0')
+ {
+ while (isspace (*string1))
+ string1++;
+ while (isspace (*string2))
+ string2++;
+
+ switch (case_pass)