+ return gdb::unique_xmalloc_ptr<char> (savestring (start, *inp - start));
+
+ return NULL;
+}
+
+/* Return true if COMMA points past "operator". START is the start of
+ the line that COMMAND points to, hence when reading backwards, we
+ must not read any character before START. */
+
+static bool
+is_cp_operator (const char *start, const char *comma)
+{
+ if (comma != NULL
+ && (comma - start) >= CP_OPERATOR_LEN)
+ {
+ const char *p = comma;
+
+ while (p > start && isspace (p[-1]))
+ p--;
+ if (p - start >= CP_OPERATOR_LEN)
+ {
+ p -= CP_OPERATOR_LEN;
+ if (strncmp (p, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
+ && (p == start
+ || !(isalnum (p[-1]) || p[-1] == '_')))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* When scanning the input string looking for the next explicit
+ location option/delimiter, we jump to the next option by looking
+ for ",", and "-". Such a character can also appear in C++ symbols
+ like "operator," and "operator-". So when we find such a
+ character, we call this function to check if we found such a
+ symbol, meaning we had a false positive for an option string. In
+ that case, we keep looking for the next delimiter, until we find
+ one that is not a false positive, or we reach end of string. FOUND
+ is the character that scanning found (either '-' or ','), and START
+ is the start of the line that FOUND points to, hence when reading
+ backwards, we must not read any character before START. Returns a
+ pointer to the next non-false-positive delimiter character, or NULL
+ if none was found. */
+
+static const char *
+skip_op_false_positives (const char *start, const char *found)
+{
+ while (found != NULL && is_cp_operator (start, found))
+ {
+ if (found[0] == '-' && found[1] == '-')
+ start = found + 2;
+ else
+ start = found + 1;
+ found = find_toplevel_char (start, *found);
+ }
+
+ return found;
+}
+
+/* Assuming both FIRST and NEW_TOK point into the same string, return
+ the pointer that is closer to the start of the string. If FIRST is
+ NULL, returns NEW_TOK. If NEW_TOK is NULL, returns FIRST. */
+
+static const char *
+first_of (const char *first, const char *new_tok)
+{
+ if (first == NULL)
+ return new_tok;
+ else if (new_tok != NULL && new_tok < first)
+ return new_tok;
+ else
+ return first;
+}
+
+/* A lexer for functions in explicit locations. This function will
+ advance INP past a function until the next option, or until end of
+ string. Returns a malloc'd copy of the lexed string or NULL if no
+ lexing was done. */
+
+static gdb::unique_xmalloc_ptr<char>
+explicit_location_lex_one_function (const char **inp,
+ const struct language_defn *language,
+ explicit_completion_info *completion_info)
+{
+ const char *start = *inp;
+
+ if (*start == '\0')
+ return NULL;
+
+ /* If quoted, skip to the ending quote. */
+ if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
+ {
+ char quote_char = *start;
+
+ /* If the input is not an Ada operator, skip to the matching
+ closing quote and return the string. */
+ if (!(language->la_language == language_ada
+ && quote_char == '\"' && is_ada_operator (start)))
+ {
+ if (completion_info != NULL)
+ completion_info->quoted_arg_start = start;
+
+ const char *end = find_toplevel_char (start + 1, quote_char);
+
+ if (end == NULL)
+ {
+ if (completion_info == NULL)
+ error (_("Unmatched quote, %s."), start);
+
+ end = start + strlen (start);
+ *inp = end;
+ char *saved = savestring (start + 1, *inp - start - 1);
+ return gdb::unique_xmalloc_ptr<char> (saved);
+ }
+
+ if (completion_info != NULL)
+ completion_info->quoted_arg_end = end;
+ *inp = end + 1;
+ char *saved = savestring (start + 1, *inp - start - 2);
+ return gdb::unique_xmalloc_ptr<char> (saved);
+ }
+ }
+
+ const char *comma = find_toplevel_char (start, ',');
+
+ /* If we have "-function -myfunction", or perhaps better example,
+ "-function -[BasicClass doIt]" (objc selector), treat
+ "-myfunction" as the function name. I.e., skip the first char if
+ it is an hyphen. Don't skip the first char always, because we
+ may have C++ "operator<", and find_toplevel_char needs to see the
+ 'o' in that case. */
+ const char *hyphen
+ = (*start == '-'
+ ? find_toplevel_char (start + 1, '-')
+ : find_toplevel_char (start, '-'));
+
+ /* Check for C++ "operator," and "operator-". */
+ comma = skip_op_false_positives (start, comma);
+ hyphen = skip_op_false_positives (start, hyphen);
+
+ /* Pick the one that appears first. */
+ const char *end = first_of (hyphen, comma);
+
+ /* See if a linespec keyword appears first. */
+ const char *s = start;
+ const char *ws = find_toplevel_char (start, ' ');
+ while (ws != NULL && linespec_lexer_lex_keyword (ws + 1) == NULL)
+ {
+ s = ws + 1;
+ ws = find_toplevel_char (s, ' ');
+ }
+ if (ws != NULL)
+ end = first_of (end, ws + 1);
+
+ /* If we don't have any terminator, then take the whole string. */
+ if (end == NULL)
+ end = start + strlen (start);
+
+ /* Trim whitespace at the end. */
+ while (end > start && end[-1] == ' ')
+ end--;
+
+ *inp = end;
+
+ if (*inp - start > 0)
+ return gdb::unique_xmalloc_ptr<char> (savestring (start, *inp - start));