/* Handle lists of commands, their decoding and documentation, for GDB.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 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
#include "ui-out.h"
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
-#include "common/gdb_optional.h"
+#include "cli/cli-style.h"
+#include "gdbsupport/gdb_optional.h"
/* Prototypes for local functions. */
int ignore_help_classes,
int *nfound);
+static void help_cmd_list (struct cmd_list_element *list,
+ enum command_class theclass,
+ bool recurse,
+ struct ui_file *stream);
+
static void help_all (struct ui_file *stream);
/* Look up a command whose 'prefixlist' is KEY. Return the command if found,
if (p->prefixlist == NULL)
continue;
else if (p->prefixlist == key)
- return p;
+ {
+ /* If we found an alias, we must return the aliased
+ command. */
+ return p->cmd_pointer ? p->cmd_pointer : p;
+ }
q = lookup_cmd_for_prefixlist (key, *(p->prefixlist));
if (q != NULL)
}
static void
-set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list)
-{
- struct cmd_list_element *p;
-
- /* Check to see if *LIST contains any element other than C. */
- for (p = *list; p != NULL; p = p->next)
- if (p != c)
- break;
-
- if (p == NULL)
- {
- /* *SET_LIST only contains SET. */
- p = lookup_cmd_for_prefixlist (list, setlist);
-
- c->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p;
- }
- else
- c->prefix = p->prefix;
-}
-
-static void
-print_help_for_command (struct cmd_list_element *c, const char *prefix,
- int recurse, struct ui_file *stream);
+print_help_for_command (struct cmd_list_element *c,
+ bool recurse, struct ui_file *stream);
\f
/* Set the callback function for the specified command. For each both
p->next = c;
}
+ /* Search the prefix cmd of C, and assigns it to C->prefix.
+ See also add_prefix_cmd and update_prefix_field_of_prefixed_commands. */
+ struct cmd_list_element *prefixcmd = lookup_cmd_for_prefixlist (list,
+ cmdlist);
+ c->prefix = prefixcmd;
+
+
return c;
}
return result;
}
+/* Add an element with a suppress notification to the LIST of commands. */
+
+struct cmd_list_element *
+add_cmd_suppress_notification (const char *name, enum command_class theclass,
+ cmd_const_cfunc_ftype *fun, const char *doc,
+ struct cmd_list_element **list,
+ int *suppress_notification)
+{
+ struct cmd_list_element *element;
+
+ element = add_cmd (name, theclass, fun, doc, list);
+ element->suppress_notification = suppress_notification;
+
+ return element;
+}
+
+
/* Deprecates a command CMD.
REPLACEMENT is the name of the command which should be used in
place of this command, or NULL if no such command exists.
c->alias_chain = old->aliases;
old->aliases = c;
- set_cmd_prefix (c, list);
return c;
}
}
+/* Update the prefix field of all sub-commands of the prefix command C.
+ We must do this when a prefix command is defined as the GDB init sequence
+ does not guarantee that a prefix command is created before its sub-commands.
+ For example, break-catch-sig.c initialization runs before breakpoint.c
+ initialization, but it is breakpoint.c that creates the "catch" command used
+ by the "catch signal" command created by break-catch-sig.c. */
+
+static void
+update_prefix_field_of_prefixed_commands (struct cmd_list_element *c)
+{
+ for (cmd_list_element *p = *c->prefixlist; p != NULL; p = p->next)
+ {
+ p->prefix = c;
+
+ /* We must recursively update the prefix field to cover
+ e.g. 'info auto-load libthread-db' where the creation
+ order was:
+ libthread-db
+ auto-load
+ info
+ In such a case, when 'auto-load' was created by do_add_cmd,
+ the 'libthread-db' prefix field could not be updated, as the
+ 'auto-load' command was not yet reachable by
+ lookup_cmd_for_prefixlist (list, cmdlist)
+ that searches from the top level 'cmdlist'. */
+ if (p->prefixlist != nullptr)
+ update_prefix_field_of_prefixed_commands (p);
+ }
+}
+
+
/* Like add_cmd but adds an element for a command prefix: a name that
should be followed by a subcommand to be looked up in another
command list. PREFIXLIST should be the address of the variable
struct cmd_list_element **list)
{
struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list);
- struct cmd_list_element *p;
c->prefixlist = prefixlist;
c->prefixname = prefixname;
c->allow_unknown = allow_unknown;
- if (list == &cmdlist)
- c->prefix = NULL;
- else
- set_cmd_prefix (c, list);
-
- /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */
- for (p = *prefixlist; p != NULL; p = p->next)
- p->prefix = c;
+ /* Now that prefix command C is defined, we need to set the prefix field
+ of all prefixed commands that were defined before C itself was defined. */
+ update_prefix_field_of_prefixed_commands (c);
return c;
}
+/* A helper function for add_basic_prefix_cmd. This is a command
+ function that just forwards to help_list. */
+
+static void
+do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
+{
+ /* Look past all aliases. */
+ while (c->cmd_pointer != nullptr)
+ c = c->cmd_pointer;
+
+ help_list (*c->prefixlist, c->prefixname, all_commands, gdb_stdout);
+}
+
+/* See command.h. */
+
+struct cmd_list_element *
+add_basic_prefix_cmd (const char *name, enum command_class theclass,
+ const char *doc, struct cmd_list_element **prefixlist,
+ const char *prefixname, int allow_unknown,
+ struct cmd_list_element **list)
+{
+ struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr,
+ doc, prefixlist, prefixname,
+ allow_unknown, list);
+ set_cmd_sfunc (cmd, do_prefix_cmd);
+ return cmd;
+}
+
+/* A helper function for add_show_prefix_cmd. This is a command
+ function that just forwards to cmd_show_list. */
+
+static void
+do_show_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
+{
+ cmd_show_list (*c->prefixlist, from_tty);
+}
+
+/* See command.h. */
+
+struct cmd_list_element *
+add_show_prefix_cmd (const char *name, enum command_class theclass,
+ const char *doc, struct cmd_list_element **prefixlist,
+ const char *prefixname, int allow_unknown,
+ struct cmd_list_element **list)
+{
+ struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr,
+ doc, prefixlist, prefixname,
+ allow_unknown, list);
+ set_cmd_sfunc (cmd, do_show_prefix_cmd);
+ return cmd;
+}
+
+/* Like ADD_PREFIX_CMD but sets the suppress_notification pointer on the
+ new command list element. */
+
+struct cmd_list_element *
+add_prefix_cmd_suppress_notification
+ (const char *name, enum command_class theclass,
+ cmd_const_cfunc_ftype *fun,
+ const char *doc, struct cmd_list_element **prefixlist,
+ const char *prefixname, int allow_unknown,
+ struct cmd_list_element **list,
+ int *suppress_notification)
+{
+ struct cmd_list_element *element
+ = add_prefix_cmd (name, theclass, fun, doc, prefixlist,
+ prefixname, allow_unknown, list);
+ element->suppress_notification = suppress_notification;
+ return element;
+}
+
/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */
struct cmd_list_element *
if (set_func != NULL)
set_cmd_sfunc (set, set_func);
- set_cmd_prefix (set, set_list);
-
show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, var,
full_show_doc, show_list);
show->doc_allocated = 1;
show->show_value_func = show_func;
+ /* Disable the default symbol completer. Doesn't make much sense
+ for the "show" command to complete on anything. */
+ set_cmd_completer (show, nullptr);
if (set_result != NULL)
*set_result = set;
cmd_const_sfunc_ftype *set_func,
show_value_ftype *show_func,
struct cmd_list_element **set_list,
- struct cmd_list_element **show_list)
+ struct cmd_list_element **show_list,
+ void *context)
{
- struct cmd_list_element *c;
+ struct cmd_list_element *c, *show;
add_setshow_cmd_full (name, theclass, var_enum, var,
set_doc, show_doc, help_doc,
set_func, show_func,
set_list, show_list,
- &c, NULL);
+ &c, &show);
c->enums = enumlist;
+
+ set_cmd_context (c, context);
+ set_cmd_context (show, context);
}
+/* See cli-decode.h. */
const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL };
/* Add an auto-boolean command named NAME to both the set and show
c->enums = auto_boolean_enums;
}
+/* See cli-decode.h. */
+const char * const boolean_enums[] = { "on", "off", NULL };
+
/* Add element named NAME to both the set and show command LISTs (the
list for set/show or some sublist thereof). CLASS is as in
add_cmd. VAR is address of the variable which will contain the
- value. SET_DOC and SHOW_DOC are the documentation strings. */
-void
-add_setshow_boolean_cmd (const char *name, enum command_class theclass, int *var,
+ value. SET_DOC and SHOW_DOC are the documentation strings.
+ Returns the new command element. */
+
+cmd_list_element *
+add_setshow_boolean_cmd (const char *name, enum command_class theclass, bool *var,
const char *set_doc, const char *show_doc,
const char *help_doc,
cmd_const_sfunc_ftype *set_func,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
- static const char *boolean_enums[] = { "on", "off", NULL };
struct cmd_list_element *c;
add_setshow_cmd_full (name, theclass, var_boolean, var,
set_list, show_list,
&c, NULL);
c->enums = boolean_enums;
+
+ return c;
}
/* Add element named NAME to both the set and show command LISTs (the
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
+ cmd_list_element *set_cmd;
+
add_setshow_cmd_full (name, theclass, var_string, var,
set_doc, show_doc, help_doc,
set_func, show_func,
set_list, show_list,
- NULL, NULL);
+ &set_cmd, NULL);
+
+ /* Disable the default symbol completer. */
+ set_cmd_completer (set_cmd, nullptr);
}
/* Add element named NAME to both the set and show command LISTs (the
set_func, show_func,
set_list, show_list,
&set_cmd, NULL);
+
+ /* Disable the default symbol completer. */
+ set_cmd_completer (set_cmd, nullptr);
+
return set_cmd;
}
return add_cmd (name, theclass, fun, doc, &cmdlist);
}
-/* Add an alias or abbreviation command to the list of commands. */
+/* Add an alias or abbreviation command to the list of commands.
+ For aliases predefined by GDB (such as bt), THECLASS must be
+ different of class_alias, as class_alias is used to identify
+ user defined aliases. */
struct cmd_list_element *
add_com_alias (const char *name, const char *oldname, enum command_class theclass,
cmd_const_cfunc_ftype *fun, const char *doc,
int *suppress_notification)
{
- struct cmd_list_element *element;
+ return add_cmd_suppress_notification (name, theclass, fun, doc,
+ &cmdlist, suppress_notification);
+}
- element = add_cmd (name, theclass, fun, doc, &cmdlist);
- element->suppress_notification = suppress_notification;
+/* Print the prefix of C followed by name of C in title style. */
- return element;
+static void
+fput_command_name_styled (struct cmd_list_element *c, struct ui_file *stream)
+{
+ const char *prefixname
+ = c->prefix == nullptr ? "" : c->prefix->prefixname;
+
+ fprintf_styled (stream, title_style.style (), "%s%s", prefixname, c->name);
+}
+
+/* If C has one or more aliases, style print the name of C and
+ the name of its aliases, separated by commas.
+ If ALWAYS_FPUT_C_NAME, print the name of C even if it has no aliases.
+ If one or more names are printed, POSTFIX is printed after the last name.
+*/
+
+static void
+fput_command_names_styled (struct cmd_list_element *c,
+ bool always_fput_c_name, const char *postfix,
+ struct ui_file *stream)
+{
+ if (always_fput_c_name || c->aliases != nullptr)
+ fput_command_name_styled (c, stream);
+ if (c->aliases != nullptr)
+ {
+ for (cmd_list_element *iter = c->aliases; iter; iter = iter->alias_chain)
+ {
+ fputs_filtered (", ", stream);
+ wrap_here (" ");
+ fput_command_name_styled (iter, stream);
+ }
+ }
+ if (always_fput_c_name || c->aliases != nullptr)
+ fputs_filtered (postfix, stream);
+}
+
+/* If VERBOSE, print the full help for command C and highlight the
+ documentation parts matching HIGHLIGHT,
+ otherwise print only one-line help for command C. */
+
+static void
+print_doc_of_command (struct cmd_list_element *c, const char *prefix,
+ bool verbose, compiled_regex &highlight,
+ struct ui_file *stream)
+{
+ /* When printing the full documentation, add a line to separate
+ this documentation from the previous command help, in the likely
+ case that apropos finds several commands. */
+ if (verbose)
+ fputs_filtered ("\n", stream);
+
+ fput_command_names_styled (c, true, " -- ", stream);
+ if (verbose)
+ fputs_highlighted (c->doc, highlight, stream);
+ else
+ print_doc_line (stream, c->doc, false);
+ fputs_filtered ("\n", stream);
}
/* Recursively walk the commandlist structures, and print out the
documentation of commands that match our regex in either their
name, or their documentation.
+ If VERBOSE, prints the complete documentation and highlight the
+ documentation parts matching REGEX, otherwise prints only
+ the first line.
*/
-void
-apropos_cmd (struct ui_file *stream,
+void
+apropos_cmd (struct ui_file *stream,
struct cmd_list_element *commandlist,
- compiled_regex ®ex, const char *prefix)
+ bool verbose, compiled_regex ®ex, const char *prefix)
{
struct cmd_list_element *c;
int returnvalue;
/* Walk through the commands. */
for (c=commandlist;c;c=c->next)
{
+ if (c->cmd_pointer != nullptr)
+ {
+ /* Command aliases/abbreviations are skipped to ensure we print the
+ doc of a command only once, when encountering the aliased
+ command. */
+ continue;
+ }
+
returnvalue = -1; /* Needed to avoid double printing. */
if (c->name != NULL)
{
/* Try to match against the name. */
returnvalue = regex.search (c->name, name_len, 0, name_len, NULL);
if (returnvalue >= 0)
+ print_doc_of_command (c, prefix, verbose, regex, stream);
+
+ /* Try to match against the name of the aliases. */
+ for (cmd_list_element *iter = c->aliases;
+ returnvalue < 0 && iter;
+ iter = iter->alias_chain)
{
- print_help_for_command (c, prefix,
- 0 /* don't recurse */, stream);
+ name_len = strlen (iter->name);
+ returnvalue = regex.search (iter->name, name_len, 0, name_len, NULL);
+ if (returnvalue >= 0)
+ print_doc_of_command (c, prefix, verbose, regex, stream);
}
}
if (c->doc != NULL && returnvalue < 0)
/* Try to match against documentation. */
if (regex.search (c->doc, doc_len, 0, doc_len, NULL) >= 0)
- {
- print_help_for_command (c, prefix,
- 0 /* don't recurse */, stream);
- }
+ print_doc_of_command (c, prefix, verbose, regex, stream);
}
- /* Check if this command has subcommands and is not an
- abbreviation. We skip listing subcommands of abbreviations
- in order to avoid duplicates in the output. */
- if (c->prefixlist != NULL && !c->abbrev_flag)
+ /* Check if this command has subcommands. */
+ if (c->prefixlist != NULL)
{
/* Recursively call ourselves on the subcommand list,
passing the right prefix in. */
- apropos_cmd (stream,*c->prefixlist,regex,c->prefixname);
+ apropos_cmd (stream, *c->prefixlist, verbose, regex, c->prefixname);
}
}
}
command that requires subcommands. Also called by saying just
"help".)
- I am going to split this into two seperate comamnds, help_cmd and
+ I am going to split this into two separate commands, help_cmd and
help_list. */
void
help_cmd (const char *command, struct ui_file *stream)
{
- struct cmd_list_element *c;
+ struct cmd_list_element *c, *alias, *prefix_cmd, *c_cmd;
if (!command)
{
return;
}
+ const char *orig_command = command;
c = lookup_cmd (&command, cmdlist, "", 0, 0);
if (c == 0)
return;
+ lookup_cmd_composition (orig_command, &alias, &prefix_cmd, &c_cmd);
+
/* There are three cases here.
If c->prefixlist is nonzero, we have a prefix command.
Print its documentation, then list its subcommands.
number of this class so that the commands in the class will be
listed. */
+ /* If the user asked 'help somecommand' and there is no alias,
+ the false indicates to not output the (single) command name. */
+ fput_command_names_styled (c, false, "\n", stream);
fputs_filtered (c->doc, stream);
fputs_filtered ("\n", stream);
else
fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2);
- help_cmd_list (list, theclass, cmdtype, (int) theclass >= 0, stream);
+ help_cmd_list (list, theclass, theclass >= 0, stream);
if (theclass == all_classes)
{
fputs_filtered ("documentation.\n", stream);
fputs_filtered ("Type \"apropos word\" to search "
"for commands related to \"word\".\n", stream);
+ fputs_filtered ("Type \"apropos -v word\" for full documentation", stream);
+ wrap_here ("");
+ fputs_filtered (" of commands related to \"word\".\n", stream);
fputs_filtered ("Command name abbreviations are allowed if unambiguous.\n",
stream);
}
if (c->func == NULL)
{
fprintf_filtered (stream, "\nCommand class: %s\n\n", c->name);
- help_cmd_list (cmdlist, c->theclass, "", 1, stream);
+ help_cmd_list (cmdlist, c->theclass, true, stream);
}
}
fprintf_filtered (stream, "\nUnclassified commands\n\n");
seen_unclassified = 1;
}
- print_help_for_command (c, "", 1, stream);
+ print_help_for_command (c, 1, stream);
}
}
}
-/* Print only the first line of STR on STREAM. */
+/* See cli-decode.h. */
+
void
-print_doc_line (struct ui_file *stream, const char *str)
+print_doc_line (struct ui_file *stream, const char *str,
+ bool for_value_prefix)
{
static char *line_buffer = 0;
static int line_size;
line_buffer = (char *) xmalloc (line_size);
}
- /* Keep printing '.' or ',' not followed by a whitespace for embedded strings
- like '.gdbinit'. */
+ /* Searches for the first end of line or the end of STR. */
p = str;
- while (*p && *p != '\n'
- && ((*p != '.' && *p != ',') || (p[1] && !isspace (p[1]))))
+ while (*p && *p != '\n')
p++;
if (p - str > line_size - 1)
{
line_buffer = (char *) xmalloc (line_size);
}
strncpy (line_buffer, str, p - str);
- line_buffer[p - str] = '\0';
- if (islower (line_buffer[0]))
- line_buffer[0] = toupper (line_buffer[0]);
+ if (for_value_prefix)
+ {
+ if (islower (line_buffer[0]))
+ line_buffer[0] = toupper (line_buffer[0]);
+ gdb_assert (p > str);
+ if (line_buffer[p - str - 1] == '.')
+ line_buffer[p - str - 1] = '\0';
+ else
+ line_buffer[p - str] = '\0';
+ }
+ else
+ line_buffer[p - str] = '\0';
fputs_filtered (line_buffer, stream);
}
If RECURSE is non-zero, also print one-line descriptions
of all prefixed subcommands. */
static void
-print_help_for_command (struct cmd_list_element *c, const char *prefix,
- int recurse, struct ui_file *stream)
+print_help_for_command (struct cmd_list_element *c,
+ bool recurse, struct ui_file *stream)
{
- fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
- print_doc_line (stream, c->doc);
+ fput_command_names_styled (c, true, " -- ", stream);
+ print_doc_line (stream, c->doc, false);
fputs_filtered ("\n", stream);
-
+
if (recurse
&& c->prefixlist != 0
&& c->abbrev_flag == 0)
/* Subcommands of a prefix command typically have 'all_commands'
as class. If we pass CLASS to recursive invocation,
most often we won't see anything. */
- help_cmd_list (*c->prefixlist, all_commands, c->prefixname, 1, stream);
+ help_cmd_list (*c->prefixlist, all_commands, true, stream);
}
/*
* Implement a help command on command list LIST.
* RECURSE should be non-zero if this should be done recursively on
* all sublists of LIST.
- * PREFIX is the prefix to print before each command name.
* STREAM is the stream upon which the output should be written.
* THECLASS should be:
* A non-negative class number to list only commands in that
- * class.
* ALL_COMMANDS to list all commands in list.
* ALL_CLASSES to list all classes in list.
*
+ * Note that aliases are only shown when THECLASS is class_alias.
+ * In the other cases, the aliases will be shown together with their
+ * aliased command.
+ *
* Note that RECURSE will be active on *all* sublists, not just the
* ones selected by the criteria above (ie. the selection mechanism
* is at the low level, not the high-level).
*/
-void
+
+static void
help_cmd_list (struct cmd_list_element *list, enum command_class theclass,
- const char *prefix, int recurse, struct ui_file *stream)
+ bool recurse, struct ui_file *stream)
{
struct cmd_list_element *c;
for (c = list; c; c = c->next)
{
- if (c->abbrev_flag == 0
- && !c->cmd_deprecated
- && (theclass == all_commands
- || (theclass == all_classes && c->func == NULL)
- || (theclass == c->theclass && c->func != NULL)))
+ if (c->abbrev_flag == 1 || c->cmd_deprecated)
+ {
+ /* Do not show abbreviations or deprecated commands. */
+ continue;
+ }
+
+ if (c->cmd_pointer != nullptr && theclass != class_alias)
+ {
+ /* Do not show an alias, unless specifically showing the
+ list of aliases: for all other classes, an alias is
+ shown (if needed) together with its aliased command. */
+ continue;
+ }
+
+ if (theclass == all_commands
+ || (theclass == all_classes && c->func == NULL)
+ || (theclass == c->theclass && c->func != NULL))
+ {
+ /* show C when
+ - showing all commands
+ - showing all classes and C is a help class
+ - showing commands of THECLASS and C is not the help class */
+
+ /* If we show the class_alias and C is an alias, do not recurse,
+ as this would show the (possibly very long) not very useful
+ list of sub-commands of the aliased command. */
+ print_help_for_command
+ (c,
+ recurse && (theclass != class_alias || c->cmd_pointer == nullptr),
+ stream);
+ continue;
+ }
+
+ if (recurse
+ && (theclass == class_user || theclass == class_alias)
+ && c->prefixlist != NULL)
{
- print_help_for_command (c, prefix, recurse, stream);
+ /* User-defined commands or aliases may be subcommands. */
+ help_cmd_list (*c->prefixlist, theclass, recurse, stream);
+ continue;
}
- else if (c->abbrev_flag == 0
- && recurse
- && !c->cmd_deprecated
- && theclass == class_user && c->prefixlist != NULL)
- /* User-defined commands may be subcommands. */
- help_cmd_list (*c->prefixlist, theclass, c->prefixname,
- recurse, stream);
+
+ /* Do not show C or recurse on C, e.g. because C does not belong to
+ THECLASS or because C is a help class. */
}
}
\f
Note that this is larger than the character set allowed when
creating user-defined commands. */
- /* Recognize '!' as a single character command so that, e.g., "!ls"
+ /* Recognize the single character commands so that, e.g., "!ls"
works as expected. */
- if (*p == '!')
+ if (*p == '!' || *p == '|')
return 1;
- while (isalnum (*p) || *p == '-' || *p == '_'
+ while (valid_cmd_char_p (*p)
/* Characters used by TUI specific commands. */
|| *p == '+' || *p == '<' || *p == '>' || *p == '$')
p++;
return p - text;
}
-/* Return TRUE if NAME is a valid user-defined command name.
- This is a stricter subset of all gdb commands,
- see find_command_name_length. */
+/* See command.h. */
-int
+bool
+valid_cmd_char_p (int c)
+{
+ /* Alas "42" is a legitimate user-defined command.
+ In the interests of not breaking anything we preserve that. */
+
+ return isalnum (c) || c == '-' || c == '_' || c == '.';
+}
+
+/* See command.h. */
+
+bool
valid_user_defined_cmd_name_p (const char *name)
{
const char *p;
if (*name == '\0')
- return FALSE;
-
- /* Alas "42" is a legitimate user-defined command.
- In the interests of not breaking anything we preserve that. */
+ return false;
for (p = name; *p != '\0'; ++p)
{
- if (isalnum (*p)
- || *p == '-'
- || *p == '_')
+ if (valid_cmd_char_p (*p))
; /* Ok. */
else
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* This routine takes a line of TEXT and a CLIST in which to start the
unless ALLOW_UNKNOWN is negative.
CMDTYPE precedes the word "command" in the error message.
- If INGNORE_HELP_CLASSES is nonzero, ignore any command list
+ If IGNORE_HELP_CLASSES is nonzero, ignore any command list
elements which are actually help classes rather than commands (i.e.
the function field of the struct cmd_list_element is 0). */
}
-/* Look up the contents of LINE as a command in the command list 'cmdlist'.
+/* Look up the contents of TEXT as a command in the command list 'cmdlist'.
Return 1 on success, 0 on failure.
-
- If LINE refers to an alias, *alias will point to that alias.
-
- If LINE is a postfix command (i.e. one that is preceded by a prefix
- command) set *prefix_cmd.
-
- Set *cmd to point to the command LINE indicates.
-
- If any of *alias, *prefix_cmd, or *cmd cannot be determined or do not
+
+ If TEXT refers to an alias, *ALIAS will point to that alias.
+
+ If TEXT is a subcommand (i.e. one that is preceded by a prefix
+ command) set *PREFIX_CMD.
+
+ Set *CMD to point to the command TEXT indicates.
+
+ If any of *ALIAS, *PREFIX_CMD, or *CMD cannot be determined or do not
exist, they are NULL when we return.
-
+
*/
int
lookup_cmd_composition (const char *text,
- struct cmd_list_element **alias,
- struct cmd_list_element **prefix_cmd,
- struct cmd_list_element **cmd)
+ struct cmd_list_element **alias,
+ struct cmd_list_element **prefix_cmd,
+ struct cmd_list_element **cmd)
{
char *command;
int len, nfound;
*alias = NULL;
*prefix_cmd = NULL;
*cmd = NULL;
-
+
cur_list = cmdlist;
-
+
+ text = skip_spaces (text);
+
while (1)
- {
+ {
/* Go through as many command lists as we need to,
to find the command TEXT refers to. */
-
+
prev_cmd = *cmd;
-
- while (*text == ' ' || *text == '\t')
- (text)++;
-
+
/* Identify the name of the command. */
len = find_command_name_length (text);
-
+
/* If nothing but whitespace, return. */
if (len == 0)
return 0;
-
- /* Text is the start of the first command word to lookup (and
- it's length is len). We copy this into a local temporary. */
-
+
+ /* TEXT is the start of the first command word to lookup (and
+ it's length is LEN). We copy this into a local temporary. */
+
command = (char *) alloca (len + 1);
memcpy (command, text, len);
command[len] = '\0';
-
+
/* Look it up. */
*cmd = 0;
nfound = 0;
*cmd = find_cmd (command, len, cur_list, 1, &nfound);
-
+
if (*cmd == CMD_LIST_AMBIGUOUS)
{
return 0; /* ambiguous */
}
-
+
if (*cmd == NULL)
return 0; /* nothing found */
else
if ((*cmd)->cmd_pointer)
{
/* cmd was actually an alias, we note that an alias was
- used (by assigning *alais) and we set *cmd. */
+ used (by assigning *ALIAS) and we set *CMD. */
*alias = *cmd;
*cmd = (*cmd)->cmd_pointer;
}
*prefix_cmd = prev_cmd;
}
- if ((*cmd)->prefixlist)
+
+ text += len;
+ text = skip_spaces (text);
+
+ if ((*cmd)->prefixlist && *text != '\0')
cur_list = *(*cmd)->prefixlist;
else
return 1;
-
- text += len;
}
}