Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Doug Evans <dje@google.com>
To: Pedro Alves <pedro@codesourcery.com>,
	Eli Zaretskii <eliz@gnu.org>,
	       gdb-patches <gdb-patches@sourceware.org>
Subject: Re: [RFA, doc RFA] Add gdb.add_command_alias
Date: Wed, 21 Sep 2011 21:46:00 -0000	[thread overview]
Message-ID: <CADPb22SVb=CB4O--VttPknOHu56vSKFNzeMeUY4tMO1=CvqSJQ@mail.gmail.com> (raw)
In-Reply-To: <CADPb22Rc1vXOQeOBZMix413KvudujLvQ7F24DO+4VuAEB_WZsg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 999 bytes --]

How about this version?

It depends on a patch to libiberty.
I'll wait before that gets resolved before checking in of course.

I can think of one doc issue.
For command syntax in an @item existing usage would say to write something like

@item alias [-a] -f @var{from} -t @var{to}

instead of what I've written:

@item alias [-a] -f FROM -t TO

But I don't know how to properly refer to -f from in subsequent text
except as @samp{-f FROM} which is why I wrote what I wrote.
Suggestions welcome.

2011-09-21  Doug Evans  <dje@google.com>

        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.

[-- Attachment #2: gdb-110921-alias-1.patch.txt --]
[-- Type: text/plain, Size: 15139 bytes --]

2011-09-21  Doug Evans  <dje@google.com>

	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);
+    }
+}
 \f
 /* 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 <http://www.gnu.org/licenses/>.
+
+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 .*"

  reply	other threads:[~2011-09-21 21:12 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-09 19:25 Doug Evans
2011-09-09 21:15 ` Eli Zaretskii
2011-09-13 17:40   ` Doug Evans
2011-09-13 17:47     ` Pedro Alves
2011-09-13 19:15       ` Doug Evans
2011-09-13 19:32         ` Pedro Alves
2011-09-13 21:42           ` Doug Evans
2011-09-21 21:46             ` Doug Evans [this message]
2011-09-22 14:08               ` Pedro Alves
2011-09-22 17:45                 ` Doug Evans
2011-09-22 18:13               ` Eli Zaretskii
2011-09-22 21:48                 ` Doug Evans
2011-09-23 11:40                   ` Eli Zaretskii
2011-09-13 18:49     ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CADPb22SVb=CB4O--VttPknOHu56vSKFNzeMeUY4tMO1=CvqSJQ@mail.gmail.com' \
    --to=dje@google.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    --cc=pedro@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox