2011-09-21 Doug Evans Add new "alias" command. * NEWS: Mention new command. * command.h (valid_user_defined_cmd_name_p): Declare. * cli/cli-decode.c (valid_user_defined_cmd_name_p): New function. * cli/cli-cmds.c (alias_command): New function. (init_cli_cmds): Add new command. doc/ * gdb.texinfo (Extending GDB): Document alias command. testsuite/ * gdb.base/alias.exp: Add tests for alias command. Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.453 diff -u -p -r1.453 NEWS --- NEWS 15 Sep 2011 12:27:18 -0000 1.453 +++ NEWS 21 Sep 2011 20:16:02 -0000 @@ -73,7 +73,8 @@ the first connection is made. The listening port used by GDBserver will become available after that. -* New commands "info macros", and "info definitions" have been added. +* New commands "info macros", and "info definitions", + and "alias" have been added. * Changed commands Index: command.h =================================================================== RCS file: /cvs/src/src/gdb/command.h,v retrieving revision 1.74 diff -u -p -r1.74 command.h --- command.h 14 Feb 2011 23:41:33 -0000 1.74 +++ command.h 21 Sep 2011 20:16:02 -0000 @@ -106,6 +106,8 @@ struct cmd_list_element; /* Forward-declarations of the entry-points of cli/cli-decode.c. */ +extern int valid_user_defined_cmd_name_p (const char *name); + extern struct cmd_list_element *add_cmd (char *, enum command_class, void (*fun) (char *, int), char *, struct cmd_list_element **); Index: cli/cli-cmds.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v retrieving revision 1.115 diff -u -p -r1.115 cli-cmds.c --- cli/cli-cmds.c 4 Aug 2011 19:10:13 -0000 1.115 +++ cli/cli-cmds.c 21 Sep 2011 20:16:02 -0000 @@ -21,6 +21,7 @@ #include "defs.h" #include "exceptions.h" #include "arch-utils.h" +#include "dyn-string.h" #include "readline/readline.h" #include "readline/tilde.h" #include "completer.h" @@ -1272,6 +1273,134 @@ apropos_command (char *searchstr, int fr error (_("Error in regular expression: %s"), err); } } + +/* Make an alias of an existing command. */ + +static void +alias_command (char *args, int from_tty) +{ + int i; + int abbrev_flag = 0; + char **argv, **from_argv, **to_argv; + char *from = NULL; + char *to = NULL; + static const char usage[] = "Usage: alias [-a] -f FROM -t TO"; + + if (args == NULL) + error (_(usage)); + + argv = gdb_buildargv (args); + make_cleanup_freeargv (argv); + + for (i = 0; argv[i] != NULL; ++i) + { + if (strcmp (argv[i], "-a") == 0) + abbrev_flag = 1; + else if (strcmp (argv[i], "-f") == 0) + { + if (from != NULL || argv[i + 1] == NULL) + error (_(usage)); + from = argv[++i]; + } + else if (strcmp (argv[i], "-t") == 0) + { + if (to != NULL || argv[i + 1] == NULL) + error (_(usage)); + to = argv[++i]; + } + else + error (_(usage)); + } + + if (from == NULL) + error (_(usage)); + if (to == NULL) + error (_(usage)); + + from_argv = gdb_buildargv (from); + make_cleanup_freeargv (from_argv); + to_argv = gdb_buildargv (to); + make_cleanup_freeargv (to_argv); + + if (from_argv[0] == NULL) + error (_("Empty FROM command.")); + if (to_argv[0] == NULL) + error (_("Empty TO command.")); + + for (i = 0; to_argv[i] != NULL; ++i) + { + if (! valid_user_defined_cmd_name_p (to_argv[i])) + { + if (i == 0) + error (_("Invalid command name: %s"), to_argv[i]); + else + error (_("Invalid command element name: %s"), to_argv[i]); + } + } + + /* If TO is one word, it is an alias for the entire FROM command. + Example: alias -t spe -f "set print elements". + + Otherwise FROM and TO must have the same number of words, + and every word except the last must match; and the last word of + TO is made an alias of the last word of FROM. + Example: alias -t "set pr elms" -f "set p elem" + Note that unambiguous abbreviations are allowed. */ + + if (to_argv[1] == NULL) + { + /* add_cmd requires *we* allocate space for name, hence the xstrdup. */ + add_com_alias (xstrdup (to_argv[0]), from, class_alias, abbrev_flag); + } + else + { + int i; + dyn_string_t from_prefix, to_prefix; + char *from_prefix_cstr, *to_prefix_cstr; + struct cmd_list_element *c_from, *c_to; + int argc = countargv (from_argv); + + if (countargv (to_argv) != argc) + error (_("Mismatched command length between FROM and TO.")); + c_from = lookup_cmd_1 (& from, cmdlist, NULL, 1); + if (c_from == NULL || c_from == (struct cmd_list_element *) -1) + error (_("Invalid FROM command: %s"), from); + + /* Create copies of FROM and TO without the last word, + and use that to verify the leading elements match. */ + from_prefix = dyn_string_new (10); + make_cleanup ((make_cleanup_ftype *) dyn_string_delete, from_prefix); + to_prefix = dyn_string_new (10); + make_cleanup ((make_cleanup_ftype *) dyn_string_delete, to_prefix); + + for (i = 0; i < argc - 1; ++i) + { + if (i > 0) + dyn_string_append_char (from_prefix, ' '); + dyn_string_append_cstr (from_prefix, from_argv[i]); + } + from_prefix_cstr = dyn_string_buf (from_prefix); + for (i = 0; i < argc - 1; ++i) + { + if (i > 0) + dyn_string_append_char (to_prefix, ' '); + dyn_string_append_cstr (to_prefix, to_argv[i]); + } + to_prefix_cstr = dyn_string_buf (to_prefix); + + c_from = lookup_cmd_1 (& from_prefix_cstr, cmdlist, NULL, 1); + /* We've already tried to look up FROM. */ + gdb_assert (c_from != NULL && c_from != (struct cmd_list_element *) -1); + gdb_assert (c_from->prefixlist != NULL); + c_to = lookup_cmd_1 (& to_prefix_cstr, cmdlist, NULL, 1); + if (c_to != c_from) + error (_("FROM and TO command prefixes do not match.")); + + /* add_cmd requires *we* allocate space for name, hence the xstrdup. */ + add_alias_cmd (xstrdup (to_argv[argc - 1]), from_argv[argc - 1], + class_alias, abbrev_flag, c_from->prefixlist); + } +} /* Print a list of files and line numbers which a user may choose from in order to list a function which was specified ambiguously (as @@ -1674,4 +1803,19 @@ When 'on', each command is displayed as NULL, NULL, &setlist, &showlist); + + c = add_com ("alias", class_support, alias_command, _("\ +Define a new command that is an alias of an existing command.\n\ +Usage: alias [-a] -f FROM -t TO\n\ +FROM is the command to alias from.\n\ +TO is the new command being defined.\n\ +\"-f FROM\" and \"-t TO\" may appear in either order.\n\ +If \"-a\" is specified, the command is an abbreviation,\n\ +and will not appear in help command list output.\n\ +\n\ +Examples:\n\ +Make \"spe\" an alias of \"set print elements\":\n\ + alias -f \"set print elements\" -t spe\n\ +Make \"elms\" an alias of \"elements\" in the \"set print\" command:\n\ + alias -f \"set print elements\" -t \"set print elms\"")); } Index: cli/cli-decode.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-decode.c,v retrieving revision 1.97 diff -u -p -r1.97 cli-decode.c --- cli/cli-decode.c 8 Sep 2011 17:20:43 -0000 1.97 +++ cli/cli-decode.c 21 Sep 2011 20:16:02 -0000 @@ -126,7 +126,6 @@ set_cmd_completer (struct cmd_list_eleme cmd->completer = completer; /* Ok. */ } - /* Add element named NAME. Space for NAME and DOC must be allocated by the caller. CLASS is the top level category into which commands are broken down @@ -1138,6 +1137,31 @@ find_command_name_length (const char *te 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. */ + +int +valid_user_defined_cmd_name_p (const char *name) +{ + const char *p; + + /* Alas "42" is a legitimate user-defined command. + In the interests of not breaking anything we preserve that. */ + + for (p = name; *p != '\0'; ++p) + { + if (isalnum (*p) + || *p == '-' + || *p == '_') + ; /* Ok. */ + else + return FALSE; + } + + return TRUE; +} + /* This routine takes a line of TEXT and a CLIST in which to start the lookup. When it returns it will have incremented the text pointer past the section of text it matched, set *RESULT_LIST to point to the list in Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.862 diff -u -p -r1.862 gdb.texinfo --- doc/gdb.texinfo 16 Sep 2011 09:07:01 -0000 1.862 +++ doc/gdb.texinfo 21 Sep 2011 20:16:02 -0000 @@ -20321,11 +20321,12 @@ Displays whether the debugger is operati @chapter Extending @value{GDBN} @cindex extending GDB -@value{GDBN} provides two mechanisms for extension. The first is based -on composition of @value{GDBN} commands, and the second is based on the -Python scripting language. +@value{GDBN} provides three mechanisms for extension. The first is based +on composition of @value{GDBN} commands, the second is based on the +Python scripting language, and the third is defining new aliases of +existing commands. -To facilitate the use of these extensions, @value{GDBN} is capable +To facilitate the use of the first two extensions, @value{GDBN} is capable of evaluating the contents of a file. When doing so, @value{GDBN} can recognize which scripting language is being used by looking at the filename extension. Files with an unrecognized filename extension @@ -20360,6 +20361,7 @@ Display the current value of the @code{s @menu * Sequences:: Canned Sequences of Commands * Python:: Scripting @value{GDBN} using Python +* Aliases:: Creating new spellings of existing commands @end menu @node Sequences @@ -24058,6 +24060,90 @@ substitute_prompt (``frame: \f, @end smallexample @end table +@node Aliases +@section Creating new spellings of existing commands + +It is often useful to define alternate spellings of existing commands. +For example, if a new @value{GDBN} command defined in Python has +a long name to type, it is handy to have an abbreviated version of it +that involves less typing. + +@value{GDBN} itself uses aliases. For example @samp{s} is an alias +of the @samp{step} command even though it is otherwise an ambiguous +abbreviation of other commands like @samp{set} and @samp{show}. + +Aliases are also used to provide shortened or more common versions +of multi-word commands. For example, @value{GDBN} provides the +@samp{tty} alias of the @samp{set inferior-tty} command. + +Define a new alias with the @samp{alias} command. + +@table @code + +@kindex alias +@item alias [-a] -f FROM -t TO + +@end table + +@samp{-f FROM} and @samp{-t TO} may be specified in either order. + +The @samp{-f FROM} option specifies the name of an existing command +that is being aliased. + +The @samp{-t TO} option specifies the name of the new alias. + +The @samp{-a} option specifies that the new alias is an abbreviation +of the @samp{FROM} command, and will not appear in help command lists. + +Here is a simple example showing how to make an abbreviation +of a command so that there is less to type. +Suppose you were tired of typing @samp{disas}, the current +shortest unambiguous abbreviation of the @samp{disassemble} command +and you wanted an even shorter version named @samp{di}. +The following will accomplish this. + +@smallexample +(gdb) alias -f disas -t di +@end smallexample + +Note that aliases are different than user-defined commands. +With a user-defined command, you also need to write documentation +for it with the @samp{document} command. +An alias automatically picks up the documentation of the existing command. + +Here is an example where we make @samp{elms} an abbreviation of +@samp{elements} in the @samp{set print elements} command. +This is to show that you can make an abbreviation of any part +of a command. + +@smallexample +(gdb) alias -f "set print elements" -t "set print elms" +(gdb) alias -f "show print elements" -t "show print elms" +(gdb) set p elms 20 +(gdb) show p elms +Limit on string chars or array elements to print is 200. +@end smallexample + +Note that if you are defining an alias of a @samp{set} command, +you also need to define the alias of the corresponding @samp{show} +command, if desired. + +Unambiguously abbreviated commands are allowed in @samp{FROM} and +@samp{TO}, just as they are normally. + +@smallexample +(gdb) alias -f "set p ele" -t "set pr elms" +@end smallexample + +Finally, here is an example showing the creation of a one word +alias for a more complex command. +This creates alias @samp{spe} of the command @samp{set print elements}. + +@smallexample +(gdb) alias -f "set print elements" -t spe +(gdb) spe 20 +@end smallexample + @node Interpreters @chapter Command Interpreters @cindex command interpreters Index: testsuite/gdb.base/alias.exp =================================================================== RCS file: testsuite/gdb.base/alias.exp diff -N testsuite/gdb.base/alias.exp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testsuite/gdb.base/alias.exp 21 Sep 2011 20:16:03 -0000 @@ -0,0 +1,52 @@ +# Test the alias command. +# Copyright 2011 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 +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +proc test_abbrev_not_present { alias_name } { + global gdb_prompt + set alias_present 0 + set test_name "abbrev $alias_name not present in help command list" + gdb_test_multiple "help aliases" $test_name { + -re "\[\r\n\]$alias_name \[^\r\n\]*" { + set alias_present 1 + exp_continue + } + -re ".*$gdb_prompt $" { + if { !$alias_present } then { + pass $test_name + } else { + fail $test_name + } + } + } +} + +gdb_test_no_output "alias -a -f set -t set2" +gdb_test_no_output "set2 print elements 42" +gdb_test "show print elements" "Limit .* is 42\[.\]" +test_abbrev_not_present set2 + +gdb_test_no_output "alias -f \"set p elem\" -t spe" +gdb_test_no_output "spe 43" +gdb_test "show print elements" "Limit .* is 43\[.\]" + +gdb_test_no_output "alias -f \"set p elem\" -t \"set pr elm2\"" +gdb_test_no_output "set pr elm2 44" +gdb_test "show print elements" "Limit .* is 44\[.\]" +gdb_test "help set print" "set print elm2 .*"