* NEWS: Document "define" for prefixed commands.
authorDaniel Jacobowitz <drow@false.org>
Wed, 14 Jan 2009 20:40:09 +0000 (20:40 +0000)
committerDaniel Jacobowitz <drow@false.org>
Wed, 14 Jan 2009 20:40:09 +0000 (20:40 +0000)
* cli/cli-cmds.c (show_user): Update calls to show_user_1.  Call
show_user_1 for prefix commands.
* cli/cli-decode.c (help_cmd_list): Recurse for "help user-defined".
* cli/cli-script.c (validate_comname): Rewrite to handle prefix
commands.  Return the containing command list.
(define_command, document_command): Update to handle prefix commands.
(show_user_1): Add prefix and name arguments.  Handle prefix
commands.
* cli/cli-script.h (show_user_1): Update prototype.

doc/
* gdb.texinfo (Define, Hooks): Document prefix command support.

testsuite/
* gdb.base/define.exp: Test defining and hooking prefix commands.
* gdb.python/python.exp: Update test for "show user" output.

gdb/ChangeLog
gdb/NEWS
gdb/cli/cli-cmds.c
gdb/cli/cli-decode.c
gdb/cli/cli-script.c
gdb/cli/cli-script.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/define.exp
gdb/testsuite/gdb.python/python.exp

index 056623569154be5e116f9b70fddc95fc1e49b6f4..04022f9065271f6dadae0c13fecdbe795cab4b4b 100644 (file)
@@ -1,3 +1,16 @@
+2009-01-14  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * NEWS: Document "define" for prefixed commands.
+       * cli/cli-cmds.c (show_user): Update calls to show_user_1.  Call
+       show_user_1 for prefix commands.
+       * cli/cli-decode.c (help_cmd_list): Recurse for "help user-defined".
+       * cli/cli-script.c (validate_comname): Rewrite to handle prefix
+       commands.  Return the containing command list.
+       (define_command, document_command): Update to handle prefix commands.
+       (show_user_1): Add prefix and name arguments.  Handle prefix
+       commands.
+       * cli/cli-script.h (show_user_1): Update prototype.
+
 2009-01-14  Kai Tietz  <kai.tietz@onevision.com>
 
        * mingw-ser.c (console_select_thread): Add return to make
index 4532f9e0bdbc99c53821ee5f86811578545ef49d..027ab027672f4a29c3843c755e88f6df6ee4c13a 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -110,6 +110,9 @@ are treated as the standard definitions, regardless of context.
     task N
       Switch the context of debugging to task number N.
 
+* Support for user-defined prefixed commands.  The "define" command can
+add new commands to existing prefixes, e.g. "target".
+
 * New commands
 
 find [/size-char] [/max-count] start-address, end-address|+search-space-size,
index d3694e43481be29b3c2807ac22383bd94dc45555..4d9c4f385dae0b6e54466732937ffe0ea251072a 100644 (file)
@@ -1050,17 +1050,18 @@ show_user (char *args, int from_tty)
 
   if (args)
     {
-      c = lookup_cmd (&args, cmdlist, "", 0, 1);
+      char *comname = args;
+      c = lookup_cmd (&comname, cmdlist, "", 0, 1);
       if (c->class != class_user)
        error (_("Not a user command."));
-      show_user_1 (c, gdb_stdout);
+      show_user_1 (c, "", args, gdb_stdout);
     }
   else
     {
       for (c = cmdlist; c; c = c->next)
        {
-         if (c->class == class_user)
-           show_user_1 (c, gdb_stdout);
+         if (c->class == class_user || c->prefixlist != NULL)
+           show_user_1 (c, "", c->name, gdb_stdout);
        }
     }
 }
index b4bc8cf1056138846272a2ae196c47c118b39535..d71d516975dc159db24b300a510e1d6b7075d2dd 100644 (file)
@@ -1052,6 +1052,10 @@ help_cmd_list (struct cmd_list_element *list, enum command_class class,
        {
          print_help_for_command (c, prefix, recurse, stream);
        }
+      else if (c->abbrev_flag == 0 && recurse
+              && class == class_user && c->prefixlist != NULL)
+       /* User-defined commands may be subcommands.  */
+       help_cmd_list (*c->prefixlist, class, c->prefixname, recurse, stream);
     }
 }
 \f
index 835d29ca2bd0f41881b5ef49bdb56b23f3c6283e..a7f56d053b1a927700073eea12bba48b18cbc795 100644 (file)
@@ -45,8 +45,6 @@ static char *insert_args (char *line);
 
 static struct cleanup * setup_user_args (char *p);
 
-static void validate_comname (char *);
-
 /* Level of control structure when reading.  */
 static int control_level;
 
@@ -1254,21 +1252,57 @@ copy_command_lines (struct command_line *cmds)
   return result;
 }
 \f
-static void
-validate_comname (char *comname)
+/* Validate that *COMNAME is a valid name for a command.  Return the
+   containing command list, in case it starts with a prefix command.
+   The prefix must already exist.  *COMNAME is advanced to point after
+   any prefix, and a NUL character overwrites the space after the
+   prefix.  */
+
+static struct cmd_list_element **
+validate_comname (char **comname)
 {
-  char *p;
+  struct cmd_list_element **list = &cmdlist;
+  char *p, *last_word;
 
-  if (comname == 0)
+  if (*comname == 0)
     error_no_arg (_("name of command to define"));
 
-  p = comname;
+  /* Find the last word of the argument.  */
+  p = *comname + strlen (*comname);
+  while (p > *comname && isspace (p[-1]))
+    p--;
+  while (p > *comname && !isspace (p[-1]))
+    p--;
+  last_word = p;
+
+  /* Find the corresponding command list.  */
+  if (last_word != *comname)
+    {
+      struct cmd_list_element *c;
+      char saved_char, *tem = *comname;
+
+      /* Separate the prefix and the command.  */
+      saved_char = last_word[-1];
+      last_word[-1] = '\0';
+
+      c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+      if (c->prefixlist == NULL)
+       error (_("\"%s\" is not a prefix command."), *comname);
+
+      list = c->prefixlist;
+      last_word[-1] = saved_char;
+      *comname = last_word;
+    }
+
+  p = *comname;
   while (*p)
     {
       if (!isalnum (*p) && *p != '-' && *p != '_')
        error (_("Junk in argument list: \"%s\""), p);
       p++;
     }
+
+  return list;
 }
 
 /* This is just a placeholder in the command data structures.  */
@@ -1288,9 +1322,8 @@ define_command (char *comname, int from_tty)
       CMD_POST_HOOK
     };
   struct command_line *cmds;
-  struct cmd_list_element *c, *newc, *oldc, *hookc = 0;
-  char *tem = comname;
-  char *tem2; 
+  struct cmd_list_element *c, *newc, *oldc, *hookc = 0, **list;
+  char *tem, *tem2, *comfull;
   char tmpbuf[MAX_TMPBUF];
   int  hook_type      = CMD_NO_HOOK;
   int  hook_name_size = 0;
@@ -1300,10 +1333,12 @@ define_command (char *comname, int from_tty)
 #define HOOK_POST_STRING "hookpost-"
 #define HOOK_POST_LEN    9
 
-  validate_comname (comname);
+  comfull = comname;
+  list = validate_comname (&comname);
 
   /* Look it up, and verify that we got an exact match.  */
-  c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+  tem = comname;
+  c = lookup_cmd (&tem, *list, "", -1, 1);
   if (c && strcmp (comname, c->name) != 0)
     c = 0;
 
@@ -1337,13 +1372,13 @@ define_command (char *comname, int from_tty)
     {
       /* Look up cmd it hooks, and verify that we got an exact match.  */
       tem = comname + hook_name_size;
-      hookc = lookup_cmd (&tem, cmdlist, "", -1, 0);
+      hookc = lookup_cmd (&tem, *list, "", -1, 0);
       if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
        hookc = 0;
       if (!hookc)
        {
          warning (_("Your new `%s' command does not hook any existing command."),
-                  comname);
+                  comfull);
          if (!query ("Proceed? "))
            error (_("Not confirmed."));
        }
@@ -1357,7 +1392,7 @@ define_command (char *comname, int from_tty)
     if (isupper (*tem))
       *tem = tolower (*tem);
 
-  sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname);
+  sprintf (tmpbuf, "Type commands for definition of \"%s\".", comfull);
   cmds = read_command_lines (tmpbuf, from_tty, 1);
 
   if (c && c->class == class_user)
@@ -1365,7 +1400,7 @@ define_command (char *comname, int from_tty)
 
   newc = add_cmd (comname, class_user, user_defined_command,
                  (c && c->class == class_user)
-                 ? c->doc : savestring ("User-defined.", 13), &cmdlist);
+                 ? c->doc : savestring ("User-defined.", 13), list);
   newc->user_commands = cmds;
 
   /* If this new command is a hook, then mark both commands as being
@@ -1393,18 +1428,20 @@ void
 document_command (char *comname, int from_tty)
 {
   struct command_line *doclines;
-  struct cmd_list_element *c;
-  char *tem = comname;
+  struct cmd_list_element *c, **list;
+  char *tem, *comfull;
   char tmpbuf[128];
 
-  validate_comname (comname);
+  comfull = comname;
+  list = validate_comname (&comname);
 
-  c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+  tem = comname;
+  c = lookup_cmd (&tem, *list, "", 0, 1);
 
   if (c->class != class_user)
-    error (_("Command \"%s\" is built-in."), comname);
+    error (_("Command \"%s\" is built-in."), comfull);
 
-  sprintf (tmpbuf, "Type documentation for \"%s\".", comname);
+  sprintf (tmpbuf, "Type documentation for \"%s\".", comfull);
   doclines = read_command_lines (tmpbuf, from_tty, 0);
 
   if (c->doc)
@@ -1505,17 +1542,29 @@ script_from_file (FILE *stream, char *file)
   do_cleanups (old_cleanups);
 }
 
+/* Print the definition of user command C to STREAM.  Or, if C is a
+   prefix command, show the definitions of all user commands under C
+   (recursively).  PREFIX and NAME combined are the name of the
+   current command.  */
 void
-show_user_1 (struct cmd_list_element *c, struct ui_file *stream)
+show_user_1 (struct cmd_list_element *c, char *prefix, char *name,
+            struct ui_file *stream)
 {
   struct command_line *cmdlines;
 
+  if (c->prefixlist != NULL)
+    {
+      char *prefixname = c->prefixname;
+      for (c = *c->prefixlist; c != NULL; c = c->next)
+       if (c->class == class_user || c->prefixlist != NULL)
+         show_user_1 (c, prefixname, c->name, gdb_stdout);
+      return;
+    }
+
   cmdlines = c->user_commands;
   if (!cmdlines)
     return;
-  fputs_filtered ("User command ", stream);
-  fputs_filtered (c->name, stream);
-  fputs_filtered (":\n", stream);
+  fprintf_filtered (stream, "User command \"%s%s\":\n", prefix, name);
 
   print_command_lines (uiout, cmdlines, 1);
   fputs_filtered ("\n", stream);
index dafd3da8fc8e2e55f3e49e51c84824b5c74b6d2c..c65223fe03c5344cf677c7b5b511f53a002b5b24 100644 (file)
@@ -33,7 +33,8 @@ extern void while_command (char *arg, int from_tty);
 
 extern void if_command (char *arg, int from_tty);
 
-extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream);
+extern void show_user_1 (struct cmd_list_element *c, char *prefix,
+                        char *name, struct ui_file *stream);
 
 /* Exported to gdb/breakpoint.c */
 
index a729066c11a8ac49fd4485c0bc64c086a4e4310c..f768eb2ed8eac6aaf594bf88ec813e1fb98431b7 100644 (file)
@@ -1,3 +1,7 @@
+2009-01-14  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.texinfo (Define, Hooks): Document prefix command support.
+
 2009-01-14  Joseph Myers  <joseph@codesourcery.com>
             Carlos O'Donell  <carlos@codesourcery.com>
 
index 817b96b9b6de6f2bbc590781967dbddebcafeb95..583d96c85d64a7937166255c2bc93d8f8b7e35dd 100644 (file)
@@ -17573,6 +17573,10 @@ end
 @item define @var{commandname}
 Define a command named @var{commandname}.  If there is already a command
 by that name, you are asked to confirm that you want to redefine it.
+@var{commandname} may be a bare command name consisting of letters,
+numbers, dashes, and underscores.  It may also start with any predefined
+prefix command.  For example, @samp{define target my-target} creates
+a user-defined @samp{target my-target} command.
 
 The definition of the command is made up of other @value{GDBN} command lines,
 which are given following the @code{define} command.  The end of these
@@ -17707,6 +17711,10 @@ not for command aliases; you should define a hook for the basic command
 name, e.g.@:  @code{backtrace} rather than @code{bt}.
 @c FIXME!  So how does Joe User discover whether a command is an alias
 @c or not?
+You can hook a multi-word command by adding @code{hook-} or
+@code{hookpost-} to the last word of the command, e.g.@:
+@samp{define target hook-remote} to add a hook to @samp{target remote}.
+
 If an error occurs during the execution of your hook, execution of
 @value{GDBN} commands stops and @value{GDBN} issues a prompt
 (before the command that you actually typed had a chance to run).
index c8266764330221df8bf9a84bb4c6971d799574b2..0795f587acd20946f759b2e331642f71d9843205 100644 (file)
@@ -1,3 +1,8 @@
+2009-01-14  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.base/define.exp: Test defining and hooking prefix commands.
+       * gdb.python/python.exp: Update test for "show user" output.
+
 2009-01-07  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * gdb.fortran/derived-type.exp: New variables int4 and real4.  Match
index bce5bdb35d0ea990a832edbd69a95f020bc764a2..3ef27ae09189b907d1494b45ee05839724d04cfe 100644 (file)
@@ -346,6 +346,37 @@ gdb_expect {
   timeout {fail "(timeout) define hook undefined command: bar"}
 }
 
+# Test creation of an additional target subcommand.
+gdb_test_multiple "define target testsuite" "" {
+    -re "Type commands for definition of \"target testsuite\".\r\nEnd with a line saying just \"end\".\r\n>$" {
+       gdb_test "printf \"hello\\n\"\nend" "" "define target testsuite"
+    }
+}
+gdb_test_multiple "document target testsuite" "" {
+    -re "Type documentation for \"target testsuite\".\r\nEnd with a line saying just \"end\".\r\n>$" {
+       gdb_test "A test target.\nend" "" "document target testsuite"
+    }
+}
+
+gdb_test "help target" ".*A test target.*"
+gdb_test "target testsuite" "hello"
+gdb_test "show user target testsuite" "User command \"target testsuite\":\r\n  printf \"hello\\\\n\"\r\n"
+
+# We should even be able to hook subcommands.
+gdb_test_multiple "define target hook-testsuite" "" {
+    -re "Type commands for definition of \"target hook-testsuite\".\r\nEnd with a line saying just \"end\".\r\n>$" {
+       gdb_test "printf \"one\\n\"\nend" "" "define target hook-testsuite"
+    }
+}
+
+gdb_test_multiple "define target hookpost-testsuite" "" {
+    -re "Type commands for definition of \"target hookpost-testsuite\".\r\nEnd with a line saying just \"end\".\r\n>$" {
+       gdb_test "printf \"two\\n\"\nend" "" "define target hookpost-testsuite"
+    }
+}
+
+gdb_test "target testsuite" "one\r\nhello\r\ntwo" "target testsuite with hooks"
+
 # This is a quasi-define command: Verify that the user can redefine
 # GDB's gdb_prompt.
 #
@@ -367,9 +398,3 @@ gdb_expect {
 
 gdb_exit
 return 0
-
-
-
-
-
-
index 201e1c5f16ed2cdf9bbf80cb8420d6dbd030026b..a0c9b391cd41398c4b8f32afd62c5247c871944b 100644 (file)
@@ -63,7 +63,7 @@ gdb_py_test_multiple "show python command" \
   "print 23" "" \
   "end" "" \
   "end" "" \
-  "show user zzq" "User command zzq:.*  python.*print 23.*  end"
+  "show user zzq" "User command \"zzq\":.*  python.*print 23.*  end"
 
 gdb_py_test_multiple "indented multi-line python command" \
   "python" "" \