Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC][python] Add support for commands implemented in Python
@ 2009-02-02 13:13 Thiago Jung Bauermann
  2009-02-02 20:08 ` Eli Zaretskii
  2009-02-04  0:32 ` Daniel Jacobowitz
  0 siblings, 2 replies; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-02 13:13 UTC (permalink / raw)
  To: gdb-patches ml

Hi,

This patch allows implementing CLI commands in Python.
It assumes the "fixes for existing Python code" patch has been applied.
Initially, I was going to submit just the patch for convenience
functions in Python, but it has a small dependency on this one, so I
decided to submit this as well.

Regtested on ppc-linux. WDYT?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


gdb/
2009-02-02  Tom Tromey  <tromey@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-cmd.o.
	(SUBDIR_PYTHON_SRCS): Add python-cmd.c.
	(python-cmd.o): New target.
	* cli/cli-decode.c (set_cmd_completer): Add self parameter to
	completer prototype.
	(add_cmd): Initialize destroyer member of cmd_list_element. Use
	make_symbol_completion_list_fn as completer.
	(delete_cmd): Call destroyer if one is set.
	* cli/cli-decode.h (cmd_list_element): Add cmd parameter to
	completer member.  Add destroyer member.
	(set_cmd_completer): Add self parameter to
	completer prototype.
	* command.h (set_cmd_completer): Add cmd parameter to
	completer prototype.
	* completer.c (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	to new completer prototype.
	(complete_line_internal): Pass new parameter to completer function.
	* completer.h (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	prototypes to new completer prototype.
	* interps.c (interpreter_completer): Adapt to new completer
	prototype.
	* python/python-cmd.c: New file.
	* python/python-internal.h (gdbpy_initialize_commands): Add
	prototype.
	(gdbpy_doc_cst): Add forward declaration.
	* python/python.c (gdbpy_doc_cst): Declare.
	(_initialize_python): Call gdbpy_initialize_commands.  Initialize
	gdbpy_doc_cst.
	* symtab.c (make_symbol_completion_list_fn): New function.
	* symtab.h (make_symbol_completion_list_fn): Add prototype.

gdb/doc/
2009-02-02  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Python API): Add entry for Commands In Python.
	(Commands In Python): New node.

gdb/testsuite/
2009-02-02  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.python/python-cmd.exp: New file.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6a4f77d..7400702 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -270,10 +270,12 @@ SUBDIR_TUI_CFLAGS= \
 #
 SUBDIR_PYTHON_OBS = \
 	python.o \
+	python-cmd.o \
 	python-utils.o \
 	python-value.o
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
+	python/python-cmd.c \
 	python/python-utils.c \
 	python/python-value.c
 SUBDIR_PYTHON_DEPS =
@@ -1836,6 +1838,10 @@ python.o: $(srcdir)/python/python.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
 	$(POSTCOMPILE)
 
+python-cmd.o: $(srcdir)/python/python-cmd.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
+	$(POSTCOMPILE)
+
 python-utils.o: $(srcdir)/python/python-utils.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
 	$(POSTCOMPILE)
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 556c027..8760ebf 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -132,7 +132,8 @@ cmd_type (struct cmd_list_element *cmd)
 
 void
 set_cmd_completer (struct cmd_list_element *cmd,
-		   char **(*completer) (char *text, char *word))
+		   char **(*completer) (struct cmd_list_element *self,
+					char *text, char *word))
 {
   cmd->completer = completer; /* Ok.  */
 }
@@ -207,7 +208,8 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
   c->prefixname = NULL;
   c->allow_unknown = 0;
   c->abbrev_flag = 0;
-  set_cmd_completer (c, make_symbol_completion_list);
+  set_cmd_completer (c, make_symbol_completion_list_fn);
+  c->destroyer = NULL;
   c->type = not_set_cmd;
   c->var = NULL;
   c->var_type = var_boolean;
@@ -688,6 +690,8 @@ delete_cmd (char *name, struct cmd_list_element **list,
     {
       if (strcmp (iter->name, name) == 0)
 	{
+	  if (iter->destroyer)
+	    iter->destroyer (iter, iter->context);
 	  if (iter->hookee_pre)
 	    iter->hookee_pre->hook_pre = 0;
 	  *prehook = iter->hook_pre;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 56ea9bf..26ca2f7 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -167,7 +167,12 @@ struct cmd_list_element
        returned relative to this position.  For example, suppose TEXT is "foo"
        and we want to complete to "foobar".  If WORD is "oo", return
        "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
-    char **(*completer) (char *text, char *word);
+    char **(*completer) (struct cmd_list_element *cmd, char *text, char *word);
+
+    /* Destruction routine for this command.  If non-NULL, this is
+       called when this command instance is destroyed.  This may be
+       used to finalize the CONTEXT field, if needed.  */
+    void (*destroyer) (struct cmd_list_element *self, void *context);
 
     /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
        or "show").  */
@@ -242,7 +247,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 					  struct cmd_list_element * c));
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *self,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/command.h b/gdb/command.h
index b3f7013..bed615c 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -138,7 +138,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 			   cmd_sfunc_ftype *sfunc);
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *cmd,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/completer.c b/gdb/completer.c
index b1b0cf3..c96efcf 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -105,14 +105,14 @@ readline_line_completion_function (const char *text, int matches)
 /* This can be used for functions which don't want to complete on symbols
    but don't want to complete on anything else either.  */
 char **
-noop_completer (char *text, char *prefix)
+noop_completer (struct cmd_list_element *ignore, char *text, char *prefix)
 {
   return NULL;
 }
 
 /* Complete on filenames.  */
 char **
-filename_completer (char *text, char *word)
+filename_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int subsequent_name;
   char **return_val;
@@ -195,7 +195,7 @@ filename_completer (char *text, char *word)
 
    This is intended to be used in commands that set breakpoints etc.  */
 char **
-location_completer (char *text, char *word)
+location_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int n_syms = 0, n_files = 0;
   char ** fn_list = NULL;
@@ -384,7 +384,7 @@ add_struct_fields (struct type *type, int *nextp, char **output,
    names, but some language parsers also have support for completing
    field names.  */
 char **
-expression_completer (char *text, char *word)
+expression_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   struct type *type;
   char *fieldname, *p;
@@ -428,7 +428,7 @@ expression_completer (char *text, char *word)
     ;
 
   /* Not ideal but it is what we used to do before... */
-  return location_completer (p, word);
+  return location_completer (ignore, p, word);
 }
 
 /* Here are some useful test cases for completion.  FIXME: These should
@@ -623,7 +623,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 			   p--)
 			;
 		    }
-		  list = (*c->completer) (p, word);
+		  list = (*c->completer) (c, p, word);
 		}
 	    }
 	  else
@@ -691,7 +691,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 		       p--)
 		    ;
 		}
-	      list = (*c->completer) (p, word);
+	      list = (*c->completer) (c, p, word);
 	    }
 	}
     }
@@ -709,7 +709,7 @@ complete_line (const char *text, char *line_buffer, int point)
 
 /* Complete on command names.  Used by "help".  */
 char **
-command_completer (char *text, char *word)
+command_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   return complete_line_internal (word, text, strlen (text), 1);
 }
diff --git a/gdb/completer.h b/gdb/completer.h
index da1c381..6adbf1b 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -21,15 +21,15 @@ extern char **complete_line (const char *text, char *line_buffer, int point);
 
 extern char *readline_line_completion_function (const char *text, int matches);
 
-extern char **noop_completer (char *, char *);
+extern char **noop_completer (struct cmd_list_element *, char *, char *);
 
-extern char **filename_completer (char *, char *);
+extern char **filename_completer (struct cmd_list_element *, char *, char *);
 
-extern char **expression_completer (char *, char *);
+extern char **expression_completer (struct cmd_list_element *, char *, char *);
 
-extern char **location_completer (char *, char *);
+extern char **location_completer (struct cmd_list_element *, char *, char *);
 
-extern char **command_completer (char *, char *);
+extern char **command_completer (struct cmd_list_element *, char *, char *);
 
 extern char *get_gdb_completer_quote_characters (void);
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2c6c2ea..45e3a91 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18064,6 +18064,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * Basic Python::                Basic Python Functions.
 * Exception Handling::
 * Values From Inferior::
+* Commands In Python::          Implementing new commands in Python.
 @end menu
 
 @node Basic Python
@@ -18244,6 +18245,224 @@ The optional @var{errors} argument is the same as the corresponding
 argument to Python's @code{string.decode} method.
 @end defmethod
 
+@node Commands In Python
+@subsubsection Commands In Python
+
+@cindex commands in python
+@cindex python commands
+@tindex Command
+@tindex gdb.Command
+You can implement new @value{GDBN} CLI commands in Python.  A CLI
+command is implemented using an instance of the @code{gdb.Command}
+class, most commonly using a subclass.
+
+@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]}
+The object initializer for @code{Command} registers the new command
+with @value{GDBN}.  This initializer is normally invoked from the
+subclass' own @code{__init__} method.
+
+@var{name} is the name of the command.  If @var{name} consists of
+multiple words, then the initial words are looked for as prefix
+commands.  In this case, if one of the prefix commands does not exist,
+an exception is raised.
+
+There is no support for multi-line commands.
+
+@var{command-class} should be one of the @samp{COMMAND_} constants
+defined below.  This argument tells @value{GDBN} how to categorize the
+new command in the help system.
+
+@var{completer-class} is an optional argument.  If given, it should be
+one of the @samp{COMPLETE_} constants defined below.  This argument
+tells @value{GDBN} how to perform completion for this command.  If not
+given, @value{GDBN} will attempt to complete using the object's
+@code{complete} method (see below); if no such method is found, an
+error will occur when completion is attempted.
+
+@var{prefix} is an optional argument.  If @code{True}, then the new
+command is a prefix command; sub-commands of this command may be
+registered.
+
+The help text for the new command is taken from the Python
+documentation string for the command's class, if there is one.  If
+there is no documentation string, a default value is used.
+@end defmethod
+
+@defmethod Command dont_repeat
+By default, a @value{GDBN} command is repeated when the user enters a
+blank line at the command prompt.  A command can suppress this
+behavior by invoking the @code{dont_repeat} method.  This is similar
+to the user command @code{dont-repeat}, see @ref{Define, dont-repeat}.
+@end defmethod
+
+@defmethod Command invoke argument from_tty
+This method is called by @value{GDBN} when this command is invoked.
+
+@var{argument} is the argument to the command.  The argument
+ordinarily is a string, but may be @code{None}, meaning that there was
+no argument.
+
+@var{from_tty} is a boolean argument.  When true, this means that the
+command was entered by the user at the terminal; when false it means
+that the command came from elsewhere.
+
+If this method throws an exception, it is turned into a @value{GDBN}
+@code{error} call.  Otherwise, the return value is ignored.
+@end defmethod
+
+@defmethod Command complete text word
+This method is called by @value{GDBN} when the user attempts @key{TAB}
+completion on this command.
+
+The arguments @var{text} and @var{word} are both strings.  @var{text}
+holds the complete command line up to the cursor's location.
+@var{word} holds the last word of the command line; this is computed
+using a word-breaking heuristic.
+
+The @code{invoke} method can return several values:
+@itemize @bullet
+@item
+If the return value is a sequence, the contents of the sequence are
+used as the completions.  It is up to @code{invoke} to ensure that the
+contents actually do complete the word.  A zero-length sequence is
+allowed, it means that there were no completions available.  Only
+string elements of the sequence are used; other elements in the
+sequence are ignored.
+
+@item
+If the return value is one of the @samp{COMPLETE_} constants defined
+below, then the corresponding @value{GDBN}-internal completion
+function is invoked, and its result is used.
+
+@item
+All other results are treated as though there were no available
+completions.
+@end itemize
+@end defmethod
+
+
+When a new command is registered, it must be declared as a member of
+some general class of commands.  This is used to classify the command
+in the on-line help system.  The available classifications are
+represented by constants defined in the @code{gdb} module:
+
+@table @code
+@findex COMMAND_NONE
+@findex gdb.COMMAND_NONE
+@item COMMAND_NONE
+The command does not belong to any particular class.
+
+@findex COMMAND_RUN
+@findex gdb.COMMAND_RUN
+@item COMMAND_RUN
+The command is related to running the inferior.
+
+@findex COMMAND_VARS
+@findex gdb.COMMAND_VARS
+@item COMMAND_VARS
+The command is related to variables.
+
+@findex COMMAND_STACK
+@findex gdb.COMMAND_STACK
+@item COMMAND_STACK
+The command has to do with manipulation of the stack.
+
+@findex COMMAND_FILES
+@findex gdb.COMMAND_FILES
+@item COMMAND_FILES
+This class is used for file-related commands.
+
+@findex COMMAND_SUPPORT
+@findex gdb.COMMAND_SUPPORT
+@item COMMAND_SUPPORT
+This should be used for ``support facilities'', generally meaning
+things that are useful to the user when interacting with @value{GDBN},
+but not related to the state of the inferior.
+
+@findex COMMAND_INFO
+@findex gdb.COMMAND_INFO
+@item COMMAND_INFO
+The command is an @samp{info}-related command, that is, related to the
+state of @value{GDBN} itself.
+
+@findex COMMAND_BREAKPOINT
+@findex gdb.COMMAND_BREAKPOINT
+@item COMMAND_BREAKPOINT
+The command has to do with breakpoints.
+
+@findex COMMAND_TRACE
+@findex gdb.COMMAND_TRACE
+@item COMMAND_TRACE
+The command has to do with tracepoints.
+
+@findex COMMAND_OBSCURE
+@findex gdb.COMMAND_OBSCURE
+@item COMMAND_OBSCURE
+The command is only used in unusual circumstances, or is not of
+general interest to users.
+
+@findex COMMAND_MAINTENANCE
+@findex gdb.COMMAND_MAINTENANCE
+@item COMMAND_MAINTENANCE
+The command is only useful to @value{GDBN} maintainers.
+@end table
+
+
+A new command can use a predefined completion function, either by
+specifying it via an argument at initialization, or by return it from
+the @code{complete} method.  These predefined completion constants are
+all defined in the @code{gdb} module:
+
+@table @code
+@findex COMPLETE_NONE
+@findex gdb.COMPLETE_NONE
+@item COMPLETE_NONE
+This constant means that no completion should be done.
+
+@findex COMPLETE_FILENAME
+@findex gdb.COMPLETE_FILENAME
+@item COMPLETE_FILENAME
+This constant means that filename completion should be performed.
+
+@findex COMPLETE_LOCATION
+@findex gdb.COMPLETE_LOCATION
+@item COMPLETE_LOCATION
+This constant means that location completion should be done.
+
+@findex COMPLETE_COMMAND
+@findex gdb.COMPLETE_COMMAND
+@item COMPLETE_COMMAND
+This constant means that completion should examine @value{GDBN}
+command names.
+
+@findex COMPLETE_SYMBOL
+@findex gdb.COMPLETE_SYMBOL
+@item COMPLETE_SYMBOL
+This constant means that completion should be done using symbol names
+as the source.
+@end table
+
+The following code snippet shows how a trivial CLI command can be
+implemented in Python:
+
+@smallexample
+class HelloWorld (gdb.Command):
+  """Greet the whole world."""
+
+  def __init__ (self):
+    super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+
+  def invoke (self, arg, from_tty):
+    print "Hello, World!"
+
+HelloWorld ()
+@end smallexample
+
+The last line instantiates the class, and is necessary to trigger the
+registration of the command with @value{GDBN}.  Depending on how the
+Python code is read into @value{GDBN}, you may need to import the
+@code{gdb} module explicitly.
+
 @node Interpreters
 @chapter Command Interpreters
 @cindex command interpreters
diff --git a/gdb/interps.c b/gdb/interps.c
index 6814a72..da05ee2 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -71,7 +71,8 @@ struct interp
 
 /* Functions local to this file. */
 static void initialize_interps (void);
-static char **interpreter_completer (char *text, char *word);
+static char **interpreter_completer (struct cmd_list_element *cmd,
+				     char *text, char *word);
 
 /* The magic initialization routine for this module. */
 
@@ -416,7 +417,7 @@ interpreter_exec_cmd (char *args, int from_tty)
 
 /* List the possible interpreters which could complete the given text. */
 static char **
-interpreter_completer (char *text, char *word)
+interpreter_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int alloced = 0;
   int textlen;
diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c
new file mode 100644
index 0000000..6f6aa59
--- /dev/null
+++ b/gdb/python/python-cmd.c
@@ -0,0 +1,586 @@
+/* gdb commands implemented in Python
+
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+#include "completer.h"
+
+/* Struct representing built-in completion types.  */
+struct cmdpy_completer
+{
+  /* Python symbol name.  */
+  char *name;
+  /* Completion function.  */
+  char **(*completer) (struct cmd_list_element *, char *, char *);
+};
+
+static struct cmdpy_completer completers[] =
+{
+  { "COMPLETE_NONE", noop_completer },
+  { "COMPLETE_FILENAME", filename_completer },
+  { "COMPLETE_LOCATION", location_completer },
+  { "COMPLETE_COMMAND", command_completer },
+  { "COMPLETE_SYMBOL", make_symbol_completion_list_fn },
+};
+
+#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0]))
+
+/* A gdb command.  For the time being only ordinary commands (not
+   set/show commands) are allowed.  */
+struct cmdpy_object
+{
+  PyObject_HEAD
+
+  /* The corresponding gdb command object, or NULL if the command is
+     no longer installed.  */
+  struct cmd_list_element *command;
+
+  /* For a prefix command, this is the list of sub-commands.  */
+  struct cmd_list_element *sub_list;
+};
+
+typedef struct cmdpy_object cmdpy_object;
+
+static PyTypeObject cmdpy_object_type;
+
+
+/* Constants used by this module.  */
+static PyObject *invoke_cst;
+static PyObject *complete_cst;
+
+\f
+
+/* Python function which wraps dont_repeat.  */
+static PyObject *
+cmdpy_dont_repeat (PyObject *self, PyObject *args)
+{
+  dont_repeat ();
+  Py_RETURN_NONE;
+}
+
+\f
+
+/* Called if the gdb cmd_list_element is destroyed.  */
+static void
+cmdpy_destroyer (struct cmd_list_element *self, void *context)
+{
+  cmdpy_object *cmd;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+
+  /* Release our hold on the command object.  */
+  cmd = (cmdpy_object *) context;
+  cmd->command = NULL;
+  Py_DECREF (cmd);
+
+  /* We allocated the name, doc string, and perhaps the prefix
+     name.  */
+  xfree (self->name);
+  xfree (self->doc);
+  xfree (self->prefixname);
+
+  PyGILState_Release (state);
+}
+
+/* Called by gdb to invoke the command.  */
+static void
+cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *argobj, *ttyobj, *result;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst))
+    {
+      if (obj->command->prefixname)
+	{
+	  /* A prefix command does not need an invoke method.  */
+	  do_cleanups (cleanup);
+	  return;
+	}
+      error (_("Python command object missing 'invoke' method."));
+    }
+
+  if (! args)
+    {
+      argobj = Py_None;
+      Py_INCREF (argobj);
+    }
+  else
+    {
+      argobj = PyString_FromString (args);
+      if (! argobj)
+	error (_("Could not convert arguments to Python string."));
+    }
+  ttyobj = from_tty ? Py_True : Py_False;
+  Py_INCREF (ttyobj);
+  result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj,
+				       ttyobj, NULL);
+  Py_DECREF (argobj);
+  Py_DECREF (ttyobj);
+  if (! result)
+    {
+      PyObject *ptype, *pvalue, *ptraceback;
+      char *s, *str;
+
+      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
+
+      if (pvalue && PyString_Check (pvalue))
+	{
+	  /* Make a temporary copy of the string data.  */
+	  char *s = PyString_AsString (pvalue);
+	  char *copy = alloca (strlen (s) + 1);
+	  strcpy (copy, s);
+
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command: %s"), copy);
+	}
+      else
+	{
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command."));
+	}
+    }
+  Py_DECREF (result);
+  do_cleanups (cleanup);
+}
+
+/* Called by gdb for command completion.  */
+static char **
+cmdpy_completer (struct cmd_list_element *command, char *text, char *word)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *textobj, *wordobj, *resultobj = NULL;
+  char **result = NULL;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, complete_cst))
+    {
+      /* If there is no complete method, don't error -- instead, just
+	 say that there are no completions.  */
+      goto done;
+    }
+
+  textobj = PyString_FromString (text);
+  if (! textobj)
+    error (_("Could not convert argument to Python string."));
+  wordobj = PyString_FromString (word);
+  if (! wordobj)
+    error (_("Could not convert argument to Python string."));
+
+  resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst,
+					  textobj, wordobj, NULL);
+  Py_DECREF (textobj);
+  Py_DECREF (wordobj);
+  if (! resultobj)
+    {
+      /* Just swallow errors here.  */
+      PyErr_Clear ();
+      goto done;
+    }
+  make_cleanup_py_decref (resultobj);
+
+  result = NULL;
+  if (PySequence_Check (resultobj))
+    {
+      Py_ssize_t i, len = PySequence_Size (resultobj);
+      Py_ssize_t out;
+      if (len < 0)
+	goto done;
+
+      result = (char **) xmalloc ((len + 1) * sizeof (char *));
+      for (i = out = 0; i < len; ++i)
+	{
+	  int l;
+	  PyObject *elt = PySequence_GetItem (resultobj, i);
+	  if (elt == NULL || ! gdbpy_is_string (elt))
+	    {
+	      /* Skip problem elements.  */
+	      PyErr_Clear ();
+	      continue;
+	    }
+	  result[out] = python_string_to_host_string (elt);
+	  ++out;
+	}
+      result[out] = NULL;
+    }
+  else if (PyInt_Check (resultobj))
+    {
+      /* User code may also return one of the completion constants,
+	 thus requesting that sort of completion.  */
+      long value = PyInt_AsLong (resultobj);
+      if (value >= 0 && value < (long) N_COMPLETERS)
+	result = completers[value].completer (command, text, word);
+    }
+
+ done:
+
+  do_cleanups (cleanup);
+
+  return result;
+}
+
+/* Helper for cmdpy_init which locates the command list to use and
+   pulls out the command name.
+   
+   TEXT is the command name list.  The final word in the list is the
+   name of the new command.  All earlier words must be existing prefix
+   commands.
+
+   *BASE_LIST is set to the final prefix command's list of
+   *sub-commands.
+   
+   This function returns the xmalloc()d name of the new command.  On
+   error sets the Python error and returns NULL.  */
+static char *
+parse_command_name (char *text, struct cmd_list_element ***base_list)
+{
+  struct cmd_list_element *elt;
+  int len = strlen (text);
+  int i, lastchar;
+  char *prefix_text;
+  char *result;
+
+  /* Skip trailing whitespace.  */
+  for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      PyErr_SetString (PyExc_RuntimeError, _("no command name found"));
+      return NULL;
+    }
+  lastchar = i;
+
+  /* Find first character of the final word.  */
+  for (; i > 0 && (isalnum (text[i - 1])
+		   || text[i - 1] == '-'
+		   || text[i - 1] == '_');
+       --i)
+    ;
+  result = xmalloc (lastchar - i + 2);
+  memcpy (result, &text[i], lastchar - i + 1);
+  result[lastchar - i + 1] = '\0';
+
+  /* Skip whitespace again.  */
+  for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      *base_list = &cmdlist;
+      return result;
+    }
+
+  prefix_text = xmalloc (i + 2);
+  memcpy (prefix_text, text, i + 1);
+  prefix_text[i + 1] = '\0';
+
+  text = prefix_text;
+  elt = lookup_cmd_1 (&text, cmdlist, NULL, 1);
+  if (!elt || elt == (struct cmd_list_element *) -1)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"),
+		    prefix_text);
+      xfree (prefix_text);
+      xfree (result);
+      return NULL;
+    }
+
+  if (elt->prefixlist)
+    {
+      xfree (prefix_text);
+      *base_list = elt->prefixlist;
+      return result;
+    }
+
+  PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"),
+		prefix_text);
+  xfree (prefix_text);
+  xfree (result);
+  return NULL;
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+   Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]).
+
+   NAME is the name of the command.  It may consist of multiple words,
+   in which case the final word is the name of the new command, and
+   earlier words must be prefix commands.
+
+   CMDCLASS is the kind of command.  It should be one of the COMMAND_*
+   constants defined in the gdb module.
+
+   COMPLETERCLASS is the kind of completer.  If not given, the
+   "complete" method will be used.  Otherwise, it should be one of the
+   COMPLETE_* constants defined in the gdb module.
+
+   If PREFIX is True, then this command is a prefix command.
+
+   The documentation for the command is taken from the doc string for
+   the python class.
+   
+*/
+static int
+cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+  cmdpy_object *obj = (cmdpy_object *) self;
+  char *name;
+  int cmdtype;
+  int completetype = -1;
+  char *docstring = NULL;
+  volatile struct gdb_exception except;
+  struct cmd_list_element **cmd_list;
+  char *cmd_name, *pfx_name;
+  PyObject *is_prefix = NULL;
+  int cmp;
+
+  if (obj->command)
+    {
+      /* Note: this is apparently not documented in Python.  We return
+	 0 for success, -1 for failure.  */
+      PyErr_Format (PyExc_RuntimeError,
+		    _("command object already initialized"));
+      return -1;
+    }
+
+  if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype,
+			  &completetype, &is_prefix))
+    return -1;
+
+  if (cmdtype != no_class && cmdtype != class_run
+      && cmdtype != class_vars && cmdtype != class_stack
+      && cmdtype != class_files && cmdtype != class_support
+      && cmdtype != class_info && cmdtype != class_breakpoint
+      && cmdtype != class_trace && cmdtype != class_obscure
+      && cmdtype != class_maintenance)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid command class argument"));
+      return -1;
+    }
+
+  if (completetype < -1 || completetype >= (int) N_COMPLETERS)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid completion type argument"));
+      return -1;
+    }
+
+  cmd_name = parse_command_name (name, &cmd_list);
+  if (! cmd_name)
+    return -1;
+
+  pfx_name = NULL;
+  if (is_prefix != NULL) 
+    {
+      cmp = PyObject_IsTrue (is_prefix);
+      if (cmp == 1)
+	{
+	  int i, out;
+	  
+	  /* Make a normalized form of the command name.  */
+	  pfx_name = xmalloc (strlen (name) + 2);
+	  
+	  i = 0;
+	  out = 0;
+	  while (name[i])
+	    {
+	      /* Skip whitespace.  */
+	      while (name[i] == ' ' || name[i] == '\t')
+		++i;
+	      /* Copy non-whitespace characters.  */
+	      while (name[i] && name[i] != ' ' && name[i] != '\t')
+		pfx_name[out++] = name[i++];
+	      /* Add a single space after each word -- including the final
+		 word.  */
+	      pfx_name[out++] = ' ';
+	    }
+	  pfx_name[out] = '\0';
+	}
+      else if (cmp < 0)
+	  return -1;
+    }
+  if (PyObject_HasAttr (self, gdbpy_doc_cst))
+    {
+      PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst);
+      if (ds_obj && gdbpy_is_string (ds_obj))
+	docstring = python_string_to_host_string (ds_obj);
+    }
+  if (! docstring)
+    docstring = xstrdup (_("This command is not documented."));
+
+  Py_INCREF (self);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      struct cmd_list_element *cmd;
+
+      if (pfx_name)
+	{
+	  int allow_unknown;
+
+	  /* If we have our own "invoke" method, then allow unknown
+	     sub-commands.  */
+	  allow_unknown = PyObject_HasAttr (self, invoke_cst);
+	  cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype,
+				NULL, docstring, &obj->sub_list,
+				pfx_name, allow_unknown, cmd_list);
+	}
+      else
+	cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL,
+		       docstring, cmd_list);
+
+      /* There appears to be no API to set this.  */
+      cmd->func = cmdpy_function;
+      cmd->destroyer = cmdpy_destroyer;
+
+      obj->command = cmd;
+      set_cmd_context (cmd, self);
+      set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer
+			       : completers[completetype].completer));
+    }
+  if (except.reason < 0)
+    {
+      xfree (cmd_name);
+      xfree (docstring);
+      xfree (pfx_name);
+      Py_DECREF (self);
+      PyErr_Format (except.reason == RETURN_QUIT
+		    ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+		    "%s", except.message);
+      return -1;
+    }
+  return 0;
+}
+
+\f
+
+/* Initialize the 'commands' code.  */
+void
+gdbpy_initialize_commands (void)
+{
+  int i;
+
+  if (PyType_Ready (&cmdpy_object_type) < 0)
+    return;
+
+  /* Note: alias and user seem to be special; pseudo appears to be
+     unused, and there is no reason to expose tui or xdb, I think.  */
+  if (PyModule_AddIntConstant (gdb_module, "COMMAND_NONE", no_class) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_RUN", class_run) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_VARS", class_vars) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_STACK", class_stack) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_FILES", class_files) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_SUPPORT",
+				  class_support) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_INFO", class_info) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINT",
+				  class_breakpoint) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACE", class_trace) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
+				  class_obscure) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
+				  class_maintenance) < 0)
+    return;
+
+  for (i = 0; i < N_COMPLETERS; ++i)
+    {
+      if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0)
+	return;
+    }
+
+  Py_INCREF (&cmdpy_object_type);
+  PyModule_AddObject (gdb_module, "Command",
+		      (PyObject *) &cmdpy_object_type);
+
+  invoke_cst = PyString_FromString ("invoke");
+  complete_cst = PyString_FromString ("complete");
+}
+
+\f
+
+static PyMethodDef cmdpy_object_methods[] =
+{
+  { "dont_repeat", cmdpy_dont_repeat, METH_NOARGS,
+    "Prevent command repetition when user enters empty line." },
+
+  { 0 }
+};
+
+static PyTypeObject cmdpy_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Command",		  /*tp_name*/
+  sizeof (cmdpy_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  0,				  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  "GDB command object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  cmdpy_object_methods,		  /* tp_methods */
+  0,				  /* tp_members */
+  0,				  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  cmdpy_init,			  /* tp_init */
+  0,				  /* tp_alloc */
+  PyType_GenericNew		  /* tp_new */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1457928..02dbfc4 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -70,6 +70,7 @@ PyObject *value_to_value_object (struct value *v);
 struct value *convert_value_from_python (PyObject *obj);
 
 void gdbpy_initialize_values (void);
+void gdbpy_initialize_commands (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
@@ -94,4 +95,6 @@ char *python_string_to_host_string (PyObject *obj);
 PyObject *target_string_to_unicode (const gdb_byte *str, int length);
 int gdbpy_is_string (PyObject *obj);
 
+extern PyObject *gdbpy_doc_cst;
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 96bb5f5..4f97416 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -46,6 +46,8 @@ static PyMethodDef GdbMethods[];
 
 PyObject *gdb_module;
 
+PyObject *gdbpy_doc_cst;
+
 /* Given a command_line, return a command string suitable for passing
    to Python.  Lines in the string are separated by newlines.  The
    return value is allocated using xmalloc and the caller is
@@ -407,9 +409,12 @@ Enables or disables printing of Python stack traces."),
   PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
 
   gdbpy_initialize_values ();
+  gdbpy_initialize_commands ();
 
   PyRun_SimpleString ("import gdb");
 
+  gdbpy_doc_cst = PyString_FromString ("__doc__");
+
   /* Create a couple objects which are used for Python's stdout and
      stderr.  */
   PyRun_SimpleString ("\
diff --git a/gdb/symtab.c b/gdb/symtab.c
index b9befed..97d7950 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3890,6 +3890,16 @@ make_symbol_completion_list (char *text, char *word)
   return current_language->la_make_symbol_completion_list (text, word);
 }
 
+/* Like make_symbol_completion_list, but suitable for use as a
+   completion function.  */
+
+char **
+make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+				char *text, char *word)
+{
+  return make_symbol_completion_list (text, word);
+}
+
 /* Like make_symbol_completion_list, but returns a list of symbols
    defined in a source file FILE.  */
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 2446d1e..8b086f3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1238,6 +1238,8 @@ extern void select_source_symtab (struct symtab *);
 
 extern char **default_make_symbol_completion_list (char *, char *);
 extern char **make_symbol_completion_list (char *, char *);
+extern char **make_symbol_completion_list_fn (struct cmd_list_element *,
+					      char *, char *);
 
 extern char **make_file_symbol_completion_list (char *, char *, char *);
 
diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp
new file mode 100644
index 0000000..6c73ff2
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-cmd.exp
@@ -0,0 +1,107 @@
+# Copyright (C) 2009 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/>.
+
+# This file is part of the GDB testsuite.  It tests the mechanism
+# for defining new GDB commands in Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+proc gdb_py_test_multiple {name args} {
+    global gdb_prompt
+    foreach {input result} $args {
+	if {[gdb_test_multiple $input "$name - $input" {
+	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+		pass "$name - $input"
+	    }
+	}]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+    -re "not supported.*$gdb_prompt $"	{
+      unsupported "python support is disabled"
+      return -1
+    }
+    -re "$gdb_prompt $"	{}
+}
+
+# Test a simple command.
+
+gdb_py_test_multiple "input simple command" \
+  "python" "" \
+  "class test_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"test_cmd output, arg = %s\" % arg" "" \
+  "test_cmd ()" "" \
+  "end" ""
+
+gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command"
+
+# Test a prefix command, and a subcommand within it.
+
+gdb_py_test_multiple "input prefix command" \
+  "python" "" \
+  "class prefix_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"prefix_cmd output, arg = %s\" % arg" "" \
+  "prefix_cmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command"
+
+gdb_py_test_multiple "input subcommand" \
+  "python" "" \
+  "class subcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"subcmd output, arg = %s\" % arg" "" \
+  "subcmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"
+
+# Test a subcommand in an existing GDB prefix.
+
+gdb_py_test_multiple "input new subcommand" \
+  "python" "" \
+  "class newsubcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"newsubcmd output, arg = %s\" % arg" "" \
+  "newsubcmd ()" "" \
+  "end" ""
+
+gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd"



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-02 13:13 [RFC][python] Add support for commands implemented in Python Thiago Jung Bauermann
@ 2009-02-02 20:08 ` Eli Zaretskii
  2009-02-04 19:50   ` Tom Tromey
  2009-02-05 22:40   ` Thiago Jung Bauermann
  2009-02-04  0:32 ` Daniel Jacobowitz
  1 sibling, 2 replies; 15+ messages in thread
From: Eli Zaretskii @ 2009-02-02 20:08 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Date: Mon, 02 Feb 2009 11:13:25 -0200
> 
> gdb/doc/
> 2009-02-02  Tom Tromey  <tromey@redhat.com>
> 
> 	* gdb.texinfo (Python API): Add entry for Commands In Python.
> 	(Commands In Python): New node.

Approved, with comments:

> +The help text for the new command is taken from the Python
> +documentation string for the command's class, if there is one.  If
> +there is no documentation string, a default value is used.

Regarding the last sentence above: when I read this I asked myself
what was the default value for the doc string.  I suggest to state
that.

> +@defmethod Command complete text word
> +This method is called by @value{GDBN} when the user attempts @key{TAB}
> +completion on this command.

Only TAB, or the other completion-related keys? what about M-?, for
example?

> +@item COMMAND_RUN
> +The command is related to running the inferior.
> +
> +@findex COMMAND_VARS
> +@findex gdb.COMMAND_VARS
> +@item COMMAND_VARS
> +The command is related to variables.

I think it would be useful either to give a couple of examples of
existing CLI commands that belong to each class, or at least explain
how to use the "help" command to show commands in each class.  I
imagined myself sitting in front of this list and trying to figure out
to which class to assign some command I wrote, and I think I would
find these hints useful.  Please keep in mind that users who would
want to write new CLI commands are not necessarily GDB hackers privy
to the add_cmd function and its ilk.

> +@item COMMAND_FILES
> +This class is used for file-related commands.

Here's a case in point: many (most) GDB commands related to files
actually deal with _executable_ files.

> +@item COMMAND_SUPPORT

Another case in point: what is ``support facilities''?  Without an
example, it leaves me wondering.

Another question that was on my mind after reading this: what class is
for help commands?

> +A new command can use a predefined completion function, either by
> +specifying it via an argument at initialization, or by return it from
                                                          ^^^^^^
"returning"

> +@item COMPLETE_LOCATION
> +This constant means that location completion should be done.

A cross-reference to where "locations" are described would be a good
idea here.

Finally, I think we need a NEWS entry for this feature.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-02 13:13 [RFC][python] Add support for commands implemented in Python Thiago Jung Bauermann
  2009-02-02 20:08 ` Eli Zaretskii
@ 2009-02-04  0:32 ` Daniel Jacobowitz
  2009-02-04 20:02   ` Tom Tromey
  1 sibling, 1 reply; 15+ messages in thread
From: Daniel Jacobowitz @ 2009-02-04  0:32 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

On Mon, Feb 02, 2009 at 11:13:25AM -0200, Thiago Jung Bauermann wrote:
> +@defmethod Command invoke argument from_tty
> +This method is called by @value{GDBN} when this command is invoked.
> +
> +@var{argument} is the argument to the command.  The argument
> +ordinarily is a string, but may be @code{None}, meaning that there was
> +no argument.

Any opinion on making it always a string?  The 'do I get NULL or an
empty string?' ambiguity shows up every time I write a new command in
C.  If you prefer None, let's document what whitespace trimming does
or does not happen before it is converted from a string to None.

> +@defmethod Command complete text word
> +This method is called by @value{GDBN} when the user attempts @key{TAB}
> +completion on this command.
> +
> +The arguments @var{text} and @var{word} are both strings.  @var{text}
> +holds the complete command line up to the cursor's location.
> +@var{word} holds the last word of the command line; this is computed
> +using a word-breaking heuristic.
> +
> +The @code{invoke} method can return several values:

Isn't this @code{complete} method?  Same problem repeated below.

> +/* A gdb command.  For the time being only ordinary commands (not
> +   set/show commands) are allowed.  */
> +struct cmdpy_object
> +{
> +  PyObject_HEAD
> +
> +  /* The corresponding gdb command object, or NULL if the command is
> +     no longer installed.  */
> +  struct cmd_list_element *command;
> +
> +  /* For a prefix command, this is the list of sub-commands.  */
> +  struct cmd_list_element *sub_list;
> +};

What's sub_list for?  There's *command->prefixlist too.  Overall, I'm
confused about why prefix commands are 'special' here.  When core GDB
adds a command, it doesn't need any new code to handle it as a prefix;
just calls add_prefix_cmd.  I'd expect to do the same here but fill in
a local FUN.

> +  /* Note: alias and user seem to be special; pseudo appears to be
> +     unused, and there is no reason to expose tui or xdb, I think.  */

Yes, alias and user are special.  User is where "define"'d commands
go; should there be a command to show all Python-defined
commands similar to "show user"?

The rest of the code looks fine.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-02 20:08 ` Eli Zaretskii
@ 2009-02-04 19:50   ` Tom Tromey
  2009-02-05 22:40   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2009-02-04 19:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Thiago Jung Bauermann, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> +@defmethod Command complete text word
>> +This method is called by @value{GDBN} when the user attempts @key{TAB}
>> +completion on this command.

Eli> Only TAB, or the other completion-related keys? what about M-?, for
Eli> example?

Yes, it is also used to implement M-? and the CLI "complete" command.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-04  0:32 ` Daniel Jacobowitz
@ 2009-02-04 20:02   ` Tom Tromey
  2009-02-04 20:12     ` Daniel Jacobowitz
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2009-02-04 20:02 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

>>>>> "Daniel" == Daniel Jacobowitz <drow@false.org> writes:

>> +@var{argument} is the argument to the command.  The argument
>> +ordinarily is a string, but may be @code{None}, meaning that there was
>> +no argument.

Daniel> Any opinion on making it always a string?  The 'do I get NULL
Daniel> or an empty string?' ambiguity shows up every time I write a
Daniel> new command in C.

An empty string would be fine by me.  I initially chose None to
parallel the C API, but it isn't clear how useful that is.  An empty
string is friendlier and doesn't seem to lose anything important.

>> +  /* For a prefix command, this is the list of sub-commands.  */
>> +  struct cmd_list_element *sub_list;

Daniel> What's sub_list for?  There's *command->prefixlist too.  Overall, I'm
Daniel> confused about why prefix commands are 'special' here.  When core GDB
Daniel> adds a command, it doesn't need any new code to handle it as a prefix;
Daniel> just calls add_prefix_cmd.  I'd expect to do the same here but fill in
Daniel> a local FUN.

I might be confused here.

The reason I wrote things this way is because elsewhere in gdb there
are global cmdlists which are passed by address to the various add_*
functions.  The 'prefixlist' field of the prefix command points to one
of these globals.

E.g.: in breakpoint.c, there is a global breakpoint_set_cmdlist.  The
"set breakpoint" prefix command is constructed:

  add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, _("\
Breakpoint specific settings\n\
Configure various breakpoint-specific variables such as\n\
pending breakpoint behavior"),
		  &breakpoint_set_cmdlist, "set breakpoint ",
		  0/*allow-unknown*/, &setlist);

... this sets the new prefix command's prefixlist to
&breakpoint_set_cmdlist.

Then, calls to add_* to create sub-commands of this prefix are given
&breakpoint_set_cmdlist as an argument.

So, the idea behind this part of the patch is that we need to create
storage for this list somewhere.  In the rest of gdb this is done as a
global, but that won't fly here -- so we allocate it in the Command.

Does that answer your question?  Or, if I'm misunderstanding
something, could you say what?  I looked at this again and I still
don't see what might be wrong.

Daniel> Yes, alias and user are special.  User is where "define"'d commands
Daniel> go; should there be a command to show all Python-defined
Daniel> commands similar to "show user"?

As a user I don't really care if a command is implemented in Python.
But I don't oppose the idea if you think it is useful.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-04 20:02   ` Tom Tromey
@ 2009-02-04 20:12     ` Daniel Jacobowitz
  0 siblings, 0 replies; 15+ messages in thread
From: Daniel Jacobowitz @ 2009-02-04 20:12 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Thiago Jung Bauermann, gdb-patches ml

On Wed, Feb 04, 2009 at 01:02:09PM -0700, Tom Tromey wrote:
> An empty string would be fine by me.  I initially chose None to
> parallel the C API, but it isn't clear how useful that is.  An empty
> string is friendlier and doesn't seem to lose anything important.

Let's do that then.

> Does that answer your question?  Or, if I'm misunderstanding
> something, could you say what?  I looked at this again and I still
> don't see what might be wrong.

Thanks, that explains sub_list; an expanded comment would help.  I was
confused about the use of parse_command_name - but now I see what it's
for.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-02 20:08 ` Eli Zaretskii
  2009-02-04 19:50   ` Tom Tromey
@ 2009-02-05 22:40   ` Thiago Jung Bauermann
  2009-02-05 23:01     ` Tom Tromey
  2009-02-06  6:18     ` Eli Zaretskii
  1 sibling, 2 replies; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-05 22:40 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

El lun, 02-02-2009 a las 22:08 +0200, Eli Zaretskii escribió:
> > gdb/doc/
> > 2009-02-02  Tom Tromey  <tromey@redhat.com>
> > 
> > 	* gdb.texinfo (Python API): Add entry for Commands In Python.
> > 	(Commands In Python): New node.
> 
> Approved, with comments:

Tromey worked on them, here's a new version which addresses your
comments and Daniel's. I also changed cmdpy_function and cmdpy_completer
to convert the command arguments to a Unicode string instead of an 8-bit
Python string.

> > +The help text for the new command is taken from the Python
> > +documentation string for the command's class, if there is one.  If
> > +there is no documentation string, a default value is used.
> 
> Regarding the last sentence above: when I read this I asked myself
> what was the default value for the doc string.  I suggest to state
> that.

Stated.

> > +@defmethod Command complete text word
> > +This method is called by @value{GDBN} when the user attempts @key{TAB}
> > +completion on this command.
> 
> Only TAB, or the other completion-related keys? what about M-?, for
> example?

The text explicitly mentions the other completion keys as well.

> > +@item COMMAND_RUN
> > +The command is related to running the inferior.
> > +
> > +@findex COMMAND_VARS
> > +@findex gdb.COMMAND_VARS
> > +@item COMMAND_VARS
> > +The command is related to variables.
> 
> I think it would be useful either to give a couple of examples of
> existing CLI commands that belong to each class, or at least explain
> how to use the "help" command to show commands in each class.  I
> imagined myself sitting in front of this list and trying to figure out
> to which class to assign some command I wrote, and I think I would
> find these hints useful.  Please keep in mind that users who would
> want to write new CLI commands are not necessarily GDB hackers privy
> to the add_cmd function and its ilk.

The text now both gives examples and mentions how to get help to list
the commands in the class.

> > +A new command can use a predefined completion function, either by
> > +specifying it via an argument at initialization, or by return it from
>                                                           ^^^^^^
> "returning"

Fixed.

> > +@item COMPLETE_LOCATION
> > +This constant means that location completion should be done.
> 
> A cross-reference to where "locations" are described would be a good
> idea here.

Cross-referenced.

> Finally, I think we need a NEWS entry for this feature.

NEWS entry added.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


gdb/
2009-02-05  Tom Tromey  <tromey@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-cmd.o.
	(SUBDIR_PYTHON_SRCS): Add python-cmd.c.
	(python-cmd.o): New target.
	* cli/cli-decode.c (set_cmd_completer): Add self parameter to
	completer prototype.
	(add_cmd): Initialize destroyer member of cmd_list_element. Use
	make_symbol_completion_list_fn as completer.
	(delete_cmd): Call destroyer if one is set.
	* cli/cli-decode.h (cmd_list_element): Add cmd parameter to
	completer member.  Add destroyer member.
	(set_cmd_completer): Add self parameter to
	completer prototype.
	* command.h (set_cmd_completer): Add cmd parameter to
	completer prototype.
	* completer.c (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	to new completer prototype.
	(complete_line_internal): Pass new parameter to completer function.
	* completer.h (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	prototypes to new completer prototype.
	* interps.c (interpreter_completer): Adapt to new completer
	prototype.
	* python/python-cmd.c: New file.
	* python/python-internal.h (gdbpy_initialize_commands): Add
	prototype.
	(gdbpy_doc_cst): Add forward declaration.
	* python/python.c (gdbpy_doc_cst): Declare.
	(_initialize_python): Call gdbpy_initialize_commands.  Initialize
	gdbpy_doc_cst.
	* symtab.c (make_symbol_completion_list_fn): New function.
	* symtab.h (make_symbol_completion_list_fn): Add prototype.

gdb/doc/
2009-02-05  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Python API): Add entry for Commands In Python.
	(Commands In Python): New node.

gdb/testsuite/
2009-02-05  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.python/python-cmd.exp: New file.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6a4f77d..7400702 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -270,10 +270,12 @@ SUBDIR_TUI_CFLAGS= \
 #
 SUBDIR_PYTHON_OBS = \
 	python.o \
+	python-cmd.o \
 	python-utils.o \
 	python-value.o
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
+	python/python-cmd.c \
 	python/python-utils.c \
 	python/python-value.c
 SUBDIR_PYTHON_DEPS =
@@ -1836,6 +1838,10 @@ python.o: $(srcdir)/python/python.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
 	$(POSTCOMPILE)
 
+python-cmd.o: $(srcdir)/python/python-cmd.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
+	$(POSTCOMPILE)
+
 python-utils.o: $(srcdir)/python/python-utils.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index a85caeb..d1abf0c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -96,6 +96,8 @@ are treated as the standard definitions, regardless of context.
   GDB now has support for scripting using Python.  Whether this is
   available is determined at configure time.
 
+  New GDB commands can now be written in Python.
+
 * Ada tasking support
 
   Ada tasks can now be inspected in GDB. The following commands have
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 556c027..8760ebf 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -132,7 +132,8 @@ cmd_type (struct cmd_list_element *cmd)
 
 void
 set_cmd_completer (struct cmd_list_element *cmd,
-		   char **(*completer) (char *text, char *word))
+		   char **(*completer) (struct cmd_list_element *self,
+					char *text, char *word))
 {
   cmd->completer = completer; /* Ok.  */
 }
@@ -207,7 +208,8 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
   c->prefixname = NULL;
   c->allow_unknown = 0;
   c->abbrev_flag = 0;
-  set_cmd_completer (c, make_symbol_completion_list);
+  set_cmd_completer (c, make_symbol_completion_list_fn);
+  c->destroyer = NULL;
   c->type = not_set_cmd;
   c->var = NULL;
   c->var_type = var_boolean;
@@ -688,6 +690,8 @@ delete_cmd (char *name, struct cmd_list_element **list,
     {
       if (strcmp (iter->name, name) == 0)
 	{
+	  if (iter->destroyer)
+	    iter->destroyer (iter, iter->context);
 	  if (iter->hookee_pre)
 	    iter->hookee_pre->hook_pre = 0;
 	  *prehook = iter->hook_pre;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 56ea9bf..26ca2f7 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -167,7 +167,12 @@ struct cmd_list_element
        returned relative to this position.  For example, suppose TEXT is "foo"
        and we want to complete to "foobar".  If WORD is "oo", return
        "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
-    char **(*completer) (char *text, char *word);
+    char **(*completer) (struct cmd_list_element *cmd, char *text, char *word);
+
+    /* Destruction routine for this command.  If non-NULL, this is
+       called when this command instance is destroyed.  This may be
+       used to finalize the CONTEXT field, if needed.  */
+    void (*destroyer) (struct cmd_list_element *self, void *context);
 
     /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
        or "show").  */
@@ -242,7 +247,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 					  struct cmd_list_element * c));
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *self,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/command.h b/gdb/command.h
index b3f7013..bed615c 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -138,7 +138,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 			   cmd_sfunc_ftype *sfunc);
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *cmd,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/completer.c b/gdb/completer.c
index 298cdd0..43fcf7a 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -105,14 +105,14 @@ readline_line_completion_function (const char *text, int matches)
 /* This can be used for functions which don't want to complete on symbols
    but don't want to complete on anything else either.  */
 char **
-noop_completer (char *text, char *prefix)
+noop_completer (struct cmd_list_element *ignore, char *text, char *prefix)
 {
   return NULL;
 }
 
 /* Complete on filenames.  */
 char **
-filename_completer (char *text, char *word)
+filename_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int subsequent_name;
   char **return_val;
@@ -195,7 +195,7 @@ filename_completer (char *text, char *word)
 
    This is intended to be used in commands that set breakpoints etc.  */
 char **
-location_completer (char *text, char *word)
+location_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int n_syms = 0, n_files = 0;
   char ** fn_list = NULL;
@@ -412,7 +412,7 @@ add_struct_fields (struct type *type, int *nextp, char **output,
    names, but some language parsers also have support for completing
    field names.  */
 char **
-expression_completer (char *text, char *word)
+expression_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   struct type *type;
   char *fieldname, *p;
@@ -456,7 +456,7 @@ expression_completer (char *text, char *word)
     ;
 
   /* Not ideal but it is what we used to do before... */
-  return location_completer (p, word);
+  return location_completer (ignore, p, word);
 }
 
 /* Here are some useful test cases for completion.  FIXME: These should
@@ -651,7 +651,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 			   p--)
 			;
 		    }
-		  list = (*c->completer) (p, word);
+		  list = (*c->completer) (c, p, word);
 		}
 	    }
 	  else
@@ -719,7 +719,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 		       p--)
 		    ;
 		}
-	      list = (*c->completer) (p, word);
+	      list = (*c->completer) (c, p, word);
 	    }
 	}
     }
@@ -737,7 +737,7 @@ complete_line (const char *text, char *line_buffer, int point)
 
 /* Complete on command names.  Used by "help".  */
 char **
-command_completer (char *text, char *word)
+command_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   return complete_line_internal (word, text, strlen (text), 1);
 }
diff --git a/gdb/completer.h b/gdb/completer.h
index da1c381..6adbf1b 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -21,15 +21,15 @@ extern char **complete_line (const char *text, char *line_buffer, int point);
 
 extern char *readline_line_completion_function (const char *text, int matches);
 
-extern char **noop_completer (char *, char *);
+extern char **noop_completer (struct cmd_list_element *, char *, char *);
 
-extern char **filename_completer (char *, char *);
+extern char **filename_completer (struct cmd_list_element *, char *, char *);
 
-extern char **expression_completer (char *, char *);
+extern char **expression_completer (struct cmd_list_element *, char *, char *);
 
-extern char **location_completer (char *, char *);
+extern char **location_completer (struct cmd_list_element *, char *, char *);
 
-extern char **command_completer (char *, char *);
+extern char **command_completer (struct cmd_list_element *, char *, char *);
 
 extern char *get_gdb_completer_quote_characters (void);
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a2ed0b8..b729b06 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18064,6 +18064,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * Basic Python::                Basic Python Functions.
 * Exception Handling::
 * Values From Inferior::
+* Commands In Python::          Implementing new commands in Python.
 @end menu
 
 @node Basic Python
@@ -18246,6 +18247,259 @@ The optional @var{errors} argument is the same as the corresponding
 argument to Python's @code{string.decode} method.
 @end defmethod
 
+@node Commands In Python
+@subsubsection Commands In Python
+
+@cindex commands in python
+@cindex python commands
+@tindex Command
+@tindex gdb.Command
+You can implement new @value{GDBN} CLI commands in Python.  A CLI
+command is implemented using an instance of the @code{gdb.Command}
+class, most commonly using a subclass.
+
+@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]}
+The object initializer for @code{Command} registers the new command
+with @value{GDBN}.  This initializer is normally invoked from the
+subclass' own @code{__init__} method.
+
+@var{name} is the name of the command.  If @var{name} consists of
+multiple words, then the initial words are looked for as prefix
+commands.  In this case, if one of the prefix commands does not exist,
+an exception is raised.
+
+There is no support for multi-line commands.
+
+@var{command-class} should be one of the @samp{COMMAND_} constants
+defined below.  This argument tells @value{GDBN} how to categorize the
+new command in the help system.
+
+@var{completer-class} is an optional argument.  If given, it should be
+one of the @samp{COMPLETE_} constants defined below.  This argument
+tells @value{GDBN} how to perform completion for this command.  If not
+given, @value{GDBN} will attempt to complete using the object's
+@code{complete} method (see below); if no such method is found, an
+error will occur when completion is attempted.
+
+@var{prefix} is an optional argument.  If @code{True}, then the new
+command is a prefix command; sub-commands of this command may be
+registered.
+
+The help text for the new command is taken from the Python
+documentation string for the command's class, if there is one.  If no
+documentation string is provided, the default value ``This command is
+not documented.'' is used.
+@end defmethod
+
+@defmethod Command dont_repeat
+By default, a @value{GDBN} command is repeated when the user enters a
+blank line at the command prompt.  A command can suppress this
+behavior by invoking the @code{dont_repeat} method.  This is similar
+to the user command @code{dont-repeat}, see @ref{Define, dont-repeat}.
+@end defmethod
+
+@defmethod Command invoke argument from_tty
+This method is called by @value{GDBN} when this command is invoked.
+
+@var{argument} is a string.  It is the argument to the command, after
+leading and trailing whitespace has been stripped.
+
+@var{from_tty} is a boolean argument.  When true, this means that the
+command was entered by the user at the terminal; when false it means
+that the command came from elsewhere.
+
+If this method throws an exception, it is turned into a @value{GDBN}
+@code{error} call.  Otherwise, the return value is ignored.
+@end defmethod
+
+@defmethod Command complete text word
+This method is called by @value{GDBN} when the user attempts
+completion on this command.  All forms of completion are handled by
+this method, that is, the @key{TAB} and @key{M-?} key bindings, and
+the @code{complete} command.
+
+The arguments @var{text} and @var{word} are both strings.  @var{text}
+holds the complete command line up to the cursor's location.
+@var{word} holds the last word of the command line; this is computed
+using a word-breaking heuristic.
+
+The @code{complete} method can return several values:
+@itemize @bullet
+@item
+If the return value is a sequence, the contents of the sequence are
+used as the completions.  It is up to @code{complete} to ensure that the
+contents actually do complete the word.  A zero-length sequence is
+allowed, it means that there were no completions available.  Only
+string elements of the sequence are used; other elements in the
+sequence are ignored.
+
+@item
+If the return value is one of the @samp{COMPLETE_} constants defined
+below, then the corresponding @value{GDBN}-internal completion
+function is invoked, and its result is used.
+
+@item
+All other results are treated as though there were no available
+completions.
+@end itemize
+@end defmethod
+
+
+When a new command is registered, it must be declared as a member of
+some general class of commands.  This is used to classify top-level
+commands in the on-line help system; note that prefix commands are not
+listed under their own category but rather that of their top-level
+command.  The available classifications are represented by constants
+defined in the @code{gdb} module:
+
+@table @code
+@findex COMMAND_NONE
+@findex gdb.COMMAND_NONE
+@item COMMAND_NONE
+The command does not belong to any particular class.  A command in
+this category will not be displayed in any of the help categories.
+
+@findex COMMAND_RUN
+@findex gdb.COMMAND_RUN
+@item COMMAND_RUN
+The command is related to running the inferior.  For example,
+@code{start}, @code{step}, and @code{continue} are in this category.
+Type @code{help running} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_VARS
+@findex gdb.COMMAND_VARS
+@item COMMAND_VARS
+The command is related to data or variables.  For example,
+@code{call}, @code{find}, and @code{print} are in this category.  Type
+@code{help data} at the @value{GDBN} prompt to see a list of commands
+in this category.
+
+@findex COMMAND_STACK
+@findex gdb.COMMAND_STACK
+@item COMMAND_STACK
+The command has to do with manipulation of the stack.  For example,
+@code{backtrace}, @code{frame}, and @code{return} are in this
+category.  Type @code{help stack} at the @value{GDBN} prompt to see a
+list of commands in this category.
+
+@findex COMMAND_FILES
+@findex gdb.COMMAND_FILES
+@item COMMAND_FILES
+This class is used for file-related commands.  For example,
+@code{file}, @code{list} and @code{section} are in this category.
+Type @code{help files} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_SUPPORT
+@findex gdb.COMMAND_SUPPORT
+@item COMMAND_SUPPORT
+This should be used for ``support facilities'', generally meaning
+things that are useful to the user when interacting with @value{GDBN},
+but not related to the state of the inferior.  For example,
+@code{help}, @code{make}, and @code{shell} are in this category.  Type
+@code{help support} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_INFO
+@findex gdb.COMMAND_INFO
+@item COMMAND_INFO
+The command is an @samp{info}-related command, that is, related to the
+state of @value{GDBN} itself.  For example, @code{info}, @code{macro},
+and @code{show} are in this category.  Type @code{help status} at the
+@value{GDBN} prompt to see a list of commands in this category.
+
+@findex COMMAND_BREAKPOINT
+@findex gdb.COMMAND_BREAKPOINT
+@item COMMAND_BREAKPOINT
+The command has to do with breakpoints.  For example, @code{break},
+@code{clear}, and @code{delete} are in this category.  Type @code{help
+breakpoints} at the @value{GDBN} prompt to see a list of commands in
+this category.
+
+@findex COMMAND_TRACE
+@findex gdb.COMMAND_TRACE
+@item COMMAND_TRACE
+The command has to do with tracepoints.  For example, @code{trace},
+@code{actions}, and @code{tfind} are in this category.  Type
+@code{help tracepoints} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_OBSCURE
+@findex gdb.COMMAND_OBSCURE
+@item COMMAND_OBSCURE
+The command is only used in unusual circumstances, or is not of
+general interest to users.  For example, @code{checkpoint},
+@code{fork}, and @code{stop} are in this category.  Type @code{help
+obscure} at the @value{GDBN} prompt to see a list of commands in this
+category.
+
+@findex COMMAND_MAINTENANCE
+@findex gdb.COMMAND_MAINTENANCE
+@item COMMAND_MAINTENANCE
+The command is only useful to @value{GDBN} maintainers.  The
+@code{maintenance} and @code{flushregs} commands are in this category.
+Type @code{help internals} at the @value{GDBN} prompt to see a list of
+commands in this category.
+@end table
+
+
+A new command can use a predefined completion function, either by
+specifying it via an argument at initialization, or by returning it
+from the @code{complete} method.  These predefined completion
+constants are all defined in the @code{gdb} module:
+
+@table @code
+@findex COMPLETE_NONE
+@findex gdb.COMPLETE_NONE
+@item COMPLETE_NONE
+This constant means that no completion should be done.
+
+@findex COMPLETE_FILENAME
+@findex gdb.COMPLETE_FILENAME
+@item COMPLETE_FILENAME
+This constant means that filename completion should be performed.
+
+@findex COMPLETE_LOCATION
+@findex gdb.COMPLETE_LOCATION
+@item COMPLETE_LOCATION
+This constant means that location completion should be done.
+@xref{Specify Location}.
+
+@findex COMPLETE_COMMAND
+@findex gdb.COMPLETE_COMMAND
+@item COMPLETE_COMMAND
+This constant means that completion should examine @value{GDBN}
+command names.
+
+@findex COMPLETE_SYMBOL
+@findex gdb.COMPLETE_SYMBOL
+@item COMPLETE_SYMBOL
+This constant means that completion should be done using symbol names
+as the source.
+@end table
+
+The following code snippet shows how a trivial CLI command can be
+implemented in Python:
+
+@smallexample
+class HelloWorld (gdb.Command):
+  """Greet the whole world."""
+
+  def __init__ (self):
+    super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+
+  def invoke (self, arg, from_tty):
+    print "Hello, World!"
+
+HelloWorld ()
+@end smallexample
+
+The last line instantiates the class, and is necessary to trigger the
+registration of the command with @value{GDBN}.  Depending on how the
+Python code is read into @value{GDBN}, you may need to import the
+@code{gdb} module explicitly.
+
 @node Interpreters
 @chapter Command Interpreters
 @cindex command interpreters
diff --git a/gdb/interps.c b/gdb/interps.c
index 6814a72..da05ee2 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -71,7 +71,8 @@ struct interp
 
 /* Functions local to this file. */
 static void initialize_interps (void);
-static char **interpreter_completer (char *text, char *word);
+static char **interpreter_completer (struct cmd_list_element *cmd,
+				     char *text, char *word);
 
 /* The magic initialization routine for this module. */
 
@@ -416,7 +417,7 @@ interpreter_exec_cmd (char *args, int from_tty)
 
 /* List the possible interpreters which could complete the given text. */
 static char **
-interpreter_completer (char *text, char *word)
+interpreter_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int alloced = 0;
   int textlen;
diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c
new file mode 100644
index 0000000..92ae4fb
--- /dev/null
+++ b/gdb/python/python-cmd.c
@@ -0,0 +1,584 @@
+/* gdb commands implemented in Python
+
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+#include "completer.h"
+
+/* Struct representing built-in completion types.  */
+struct cmdpy_completer
+{
+  /* Python symbol name.  */
+  char *name;
+  /* Completion function.  */
+  char **(*completer) (struct cmd_list_element *, char *, char *);
+};
+
+static struct cmdpy_completer completers[] =
+{
+  { "COMPLETE_NONE", noop_completer },
+  { "COMPLETE_FILENAME", filename_completer },
+  { "COMPLETE_LOCATION", location_completer },
+  { "COMPLETE_COMMAND", command_completer },
+  { "COMPLETE_SYMBOL", make_symbol_completion_list_fn },
+};
+
+#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0]))
+
+/* A gdb command.  For the time being only ordinary commands (not
+   set/show commands) are allowed.  */
+struct cmdpy_object
+{
+  PyObject_HEAD
+
+  /* The corresponding gdb command object, or NULL if the command is
+     no longer installed.  */
+  struct cmd_list_element *command;
+
+  /* A prefix command requires storage for a list of its sub-commands.
+     A pointer to this is passed to add_prefix_command, and to add_cmd
+     for sub-commands of that prefix.  If this Command is not a prefix
+     command, then this field is unused.  */
+  struct cmd_list_element *sub_list;
+};
+
+typedef struct cmdpy_object cmdpy_object;
+
+static PyTypeObject cmdpy_object_type;
+
+
+/* Constants used by this module.  */
+static PyObject *invoke_cst;
+static PyObject *complete_cst;
+
+\f
+
+/* Python function which wraps dont_repeat.  */
+static PyObject *
+cmdpy_dont_repeat (PyObject *self, PyObject *args)
+{
+  dont_repeat ();
+  Py_RETURN_NONE;
+}
+
+\f
+
+/* Called if the gdb cmd_list_element is destroyed.  */
+static void
+cmdpy_destroyer (struct cmd_list_element *self, void *context)
+{
+  cmdpy_object *cmd;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+
+  /* Release our hold on the command object.  */
+  cmd = (cmdpy_object *) context;
+  cmd->command = NULL;
+  Py_DECREF (cmd);
+
+  /* We allocated the name, doc string, and perhaps the prefix
+     name.  */
+  xfree (self->name);
+  xfree (self->doc);
+  xfree (self->prefixname);
+
+  PyGILState_Release (state);
+}
+
+/* Called by gdb to invoke the command.  */
+static void
+cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *argobj, *ttyobj, *result;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst))
+    {
+      if (obj->command->prefixname)
+	{
+	  /* A prefix command does not need an invoke method.  */
+	  do_cleanups (cleanup);
+	  return;
+	}
+      error (_("Python command object missing 'invoke' method."));
+    }
+
+  if (! args)
+    args = "";
+  argobj = PyUnicode_Decode (args, strlen (args), host_charset (), NULL);
+  if (! argobj)
+    error (_("Could not convert arguments to Python string."));
+
+  ttyobj = from_tty ? Py_True : Py_False;
+  Py_INCREF (ttyobj);
+  result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj,
+				       ttyobj, NULL);
+  Py_DECREF (argobj);
+  Py_DECREF (ttyobj);
+  if (! result)
+    {
+      PyObject *ptype, *pvalue, *ptraceback;
+      char *s, *str;
+
+      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
+
+      if (pvalue && PyString_Check (pvalue))
+	{
+	  /* Make a temporary copy of the string data.  */
+	  char *s = PyString_AsString (pvalue);
+	  char *copy = alloca (strlen (s) + 1);
+	  strcpy (copy, s);
+
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command: %s"), copy);
+	}
+      else
+	{
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command."));
+	}
+    }
+  Py_DECREF (result);
+  do_cleanups (cleanup);
+}
+
+/* Called by gdb for command completion.  */
+static char **
+cmdpy_completer (struct cmd_list_element *command, char *text, char *word)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *textobj, *wordobj, *resultobj = NULL;
+  char **result = NULL;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, complete_cst))
+    {
+      /* If there is no complete method, don't error -- instead, just
+	 say that there are no completions.  */
+      goto done;
+    }
+
+  textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL);
+  if (! textobj)
+    error (_("Could not convert argument to Python string."));
+  wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL);
+  if (! wordobj)
+    error (_("Could not convert argument to Python string."));
+
+  resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst,
+					  textobj, wordobj, NULL);
+  Py_DECREF (textobj);
+  Py_DECREF (wordobj);
+  if (! resultobj)
+    {
+      /* Just swallow errors here.  */
+      PyErr_Clear ();
+      goto done;
+    }
+  make_cleanup_py_decref (resultobj);
+
+  result = NULL;
+  if (PySequence_Check (resultobj))
+    {
+      Py_ssize_t i, len = PySequence_Size (resultobj);
+      Py_ssize_t out;
+      if (len < 0)
+	goto done;
+
+      result = (char **) xmalloc ((len + 1) * sizeof (char *));
+      for (i = out = 0; i < len; ++i)
+	{
+	  int l;
+	  PyObject *elt = PySequence_GetItem (resultobj, i);
+	  if (elt == NULL || ! gdbpy_is_string (elt))
+	    {
+	      /* Skip problem elements.  */
+	      PyErr_Clear ();
+	      continue;
+	    }
+	  result[out] = python_string_to_host_string (elt);
+	  ++out;
+	}
+      result[out] = NULL;
+    }
+  else if (PyInt_Check (resultobj))
+    {
+      /* User code may also return one of the completion constants,
+	 thus requesting that sort of completion.  */
+      long value = PyInt_AsLong (resultobj);
+      if (value >= 0 && value < (long) N_COMPLETERS)
+	result = completers[value].completer (command, text, word);
+    }
+
+ done:
+
+  do_cleanups (cleanup);
+
+  return result;
+}
+
+/* Helper for cmdpy_init which locates the command list to use and
+   pulls out the command name.
+   
+   TEXT is the command name list.  The final word in the list is the
+   name of the new command.  All earlier words must be existing prefix
+   commands.
+
+   *BASE_LIST is set to the final prefix command's list of
+   *sub-commands.
+   
+   This function returns the xmalloc()d name of the new command.  On
+   error sets the Python error and returns NULL.  */
+static char *
+parse_command_name (char *text, struct cmd_list_element ***base_list)
+{
+  struct cmd_list_element *elt;
+  int len = strlen (text);
+  int i, lastchar;
+  char *prefix_text;
+  char *result;
+
+  /* Skip trailing whitespace.  */
+  for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      PyErr_SetString (PyExc_RuntimeError, _("no command name found"));
+      return NULL;
+    }
+  lastchar = i;
+
+  /* Find first character of the final word.  */
+  for (; i > 0 && (isalnum (text[i - 1])
+		   || text[i - 1] == '-'
+		   || text[i - 1] == '_');
+       --i)
+    ;
+  result = xmalloc (lastchar - i + 2);
+  memcpy (result, &text[i], lastchar - i + 1);
+  result[lastchar - i + 1] = '\0';
+
+  /* Skip whitespace again.  */
+  for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      *base_list = &cmdlist;
+      return result;
+    }
+
+  prefix_text = xmalloc (i + 2);
+  memcpy (prefix_text, text, i + 1);
+  prefix_text[i + 1] = '\0';
+
+  text = prefix_text;
+  elt = lookup_cmd_1 (&text, cmdlist, NULL, 1);
+  if (!elt || elt == (struct cmd_list_element *) -1)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"),
+		    prefix_text);
+      xfree (prefix_text);
+      xfree (result);
+      return NULL;
+    }
+
+  if (elt->prefixlist)
+    {
+      xfree (prefix_text);
+      *base_list = elt->prefixlist;
+      return result;
+    }
+
+  PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"),
+		prefix_text);
+  xfree (prefix_text);
+  xfree (result);
+  return NULL;
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+   Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]).
+
+   NAME is the name of the command.  It may consist of multiple words,
+   in which case the final word is the name of the new command, and
+   earlier words must be prefix commands.
+
+   CMDCLASS is the kind of command.  It should be one of the COMMAND_*
+   constants defined in the gdb module.
+
+   COMPLETERCLASS is the kind of completer.  If not given, the
+   "complete" method will be used.  Otherwise, it should be one of the
+   COMPLETE_* constants defined in the gdb module.
+
+   If PREFIX is True, then this command is a prefix command.
+
+   The documentation for the command is taken from the doc string for
+   the python class.
+   
+*/
+static int
+cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+  cmdpy_object *obj = (cmdpy_object *) self;
+  char *name;
+  int cmdtype;
+  int completetype = -1;
+  char *docstring = NULL;
+  volatile struct gdb_exception except;
+  struct cmd_list_element **cmd_list;
+  char *cmd_name, *pfx_name;
+  PyObject *is_prefix = NULL;
+  int cmp;
+
+  if (obj->command)
+    {
+      /* Note: this is apparently not documented in Python.  We return
+	 0 for success, -1 for failure.  */
+      PyErr_Format (PyExc_RuntimeError,
+		    _("command object already initialized"));
+      return -1;
+    }
+
+  if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype,
+			  &completetype, &is_prefix))
+    return -1;
+
+  if (cmdtype != no_class && cmdtype != class_run
+      && cmdtype != class_vars && cmdtype != class_stack
+      && cmdtype != class_files && cmdtype != class_support
+      && cmdtype != class_info && cmdtype != class_breakpoint
+      && cmdtype != class_trace && cmdtype != class_obscure
+      && cmdtype != class_maintenance)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid command class argument"));
+      return -1;
+    }
+
+  if (completetype < -1 || completetype >= (int) N_COMPLETERS)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid completion type argument"));
+      return -1;
+    }
+
+  cmd_name = parse_command_name (name, &cmd_list);
+  if (! cmd_name)
+    return -1;
+
+  pfx_name = NULL;
+  if (is_prefix != NULL) 
+    {
+      cmp = PyObject_IsTrue (is_prefix);
+      if (cmp == 1)
+	{
+	  int i, out;
+	  
+	  /* Make a normalized form of the command name.  */
+	  pfx_name = xmalloc (strlen (name) + 2);
+	  
+	  i = 0;
+	  out = 0;
+	  while (name[i])
+	    {
+	      /* Skip whitespace.  */
+	      while (name[i] == ' ' || name[i] == '\t')
+		++i;
+	      /* Copy non-whitespace characters.  */
+	      while (name[i] && name[i] != ' ' && name[i] != '\t')
+		pfx_name[out++] = name[i++];
+	      /* Add a single space after each word -- including the final
+		 word.  */
+	      pfx_name[out++] = ' ';
+	    }
+	  pfx_name[out] = '\0';
+	}
+      else if (cmp < 0)
+	  return -1;
+    }
+  if (PyObject_HasAttr (self, gdbpy_doc_cst))
+    {
+      PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst);
+      if (ds_obj && gdbpy_is_string (ds_obj))
+	docstring = python_string_to_host_string (ds_obj);
+    }
+  if (! docstring)
+    docstring = xstrdup (_("This command is not documented."));
+
+  Py_INCREF (self);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      struct cmd_list_element *cmd;
+
+      if (pfx_name)
+	{
+	  int allow_unknown;
+
+	  /* If we have our own "invoke" method, then allow unknown
+	     sub-commands.  */
+	  allow_unknown = PyObject_HasAttr (self, invoke_cst);
+	  cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype,
+				NULL, docstring, &obj->sub_list,
+				pfx_name, allow_unknown, cmd_list);
+	}
+      else
+	cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL,
+		       docstring, cmd_list);
+
+      /* There appears to be no API to set this.  */
+      cmd->func = cmdpy_function;
+      cmd->destroyer = cmdpy_destroyer;
+
+      obj->command = cmd;
+      set_cmd_context (cmd, self);
+      set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer
+			       : completers[completetype].completer));
+    }
+  if (except.reason < 0)
+    {
+      xfree (cmd_name);
+      xfree (docstring);
+      xfree (pfx_name);
+      Py_DECREF (self);
+      PyErr_Format (except.reason == RETURN_QUIT
+		    ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+		    "%s", except.message);
+      return -1;
+    }
+  return 0;
+}
+
+\f
+
+/* Initialize the 'commands' code.  */
+void
+gdbpy_initialize_commands (void)
+{
+  int i;
+
+  if (PyType_Ready (&cmdpy_object_type) < 0)
+    return;
+
+  /* Note: alias and user are special; pseudo appears to be unused,
+     and there is no reason to expose tui or xdb, I think.  */
+  if (PyModule_AddIntConstant (gdb_module, "COMMAND_NONE", no_class) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_RUN", class_run) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_VARS", class_vars) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_STACK", class_stack) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_FILES", class_files) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_SUPPORT",
+				  class_support) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_INFO", class_info) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINT",
+				  class_breakpoint) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACE", class_trace) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
+				  class_obscure) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
+				  class_maintenance) < 0)
+    return;
+
+  for (i = 0; i < N_COMPLETERS; ++i)
+    {
+      if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0)
+	return;
+    }
+
+  Py_INCREF (&cmdpy_object_type);
+  PyModule_AddObject (gdb_module, "Command",
+		      (PyObject *) &cmdpy_object_type);
+
+  invoke_cst = PyString_FromString ("invoke");
+  complete_cst = PyString_FromString ("complete");
+}
+
+\f
+
+static PyMethodDef cmdpy_object_methods[] =
+{
+  { "dont_repeat", cmdpy_dont_repeat, METH_NOARGS,
+    "Prevent command repetition when user enters empty line." },
+
+  { 0 }
+};
+
+static PyTypeObject cmdpy_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Command",		  /*tp_name*/
+  sizeof (cmdpy_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  0,				  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  "GDB command object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  cmdpy_object_methods,		  /* tp_methods */
+  0,				  /* tp_members */
+  0,				  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  cmdpy_init,			  /* tp_init */
+  0,				  /* tp_alloc */
+  PyType_GenericNew		  /* tp_new */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1457928..02dbfc4 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -70,6 +70,7 @@ PyObject *value_to_value_object (struct value *v);
 struct value *convert_value_from_python (PyObject *obj);
 
 void gdbpy_initialize_values (void);
+void gdbpy_initialize_commands (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
@@ -94,4 +95,6 @@ char *python_string_to_host_string (PyObject *obj);
 PyObject *target_string_to_unicode (const gdb_byte *str, int length);
 int gdbpy_is_string (PyObject *obj);
 
+extern PyObject *gdbpy_doc_cst;
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 96bb5f5..4f97416 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -46,6 +46,8 @@ static PyMethodDef GdbMethods[];
 
 PyObject *gdb_module;
 
+PyObject *gdbpy_doc_cst;
+
 /* Given a command_line, return a command string suitable for passing
    to Python.  Lines in the string are separated by newlines.  The
    return value is allocated using xmalloc and the caller is
@@ -407,9 +409,12 @@ Enables or disables printing of Python stack traces."),
   PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
 
   gdbpy_initialize_values ();
+  gdbpy_initialize_commands ();
 
   PyRun_SimpleString ("import gdb");
 
+  gdbpy_doc_cst = PyString_FromString ("__doc__");
+
   /* Create a couple objects which are used for Python's stdout and
      stderr.  */
   PyRun_SimpleString ("\
diff --git a/gdb/symtab.c b/gdb/symtab.c
index b9befed..97d7950 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3890,6 +3890,16 @@ make_symbol_completion_list (char *text, char *word)
   return current_language->la_make_symbol_completion_list (text, word);
 }
 
+/* Like make_symbol_completion_list, but suitable for use as a
+   completion function.  */
+
+char **
+make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+				char *text, char *word)
+{
+  return make_symbol_completion_list (text, word);
+}
+
 /* Like make_symbol_completion_list, but returns a list of symbols
    defined in a source file FILE.  */
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 2446d1e..8b086f3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1238,6 +1238,8 @@ extern void select_source_symtab (struct symtab *);
 
 extern char **default_make_symbol_completion_list (char *, char *);
 extern char **make_symbol_completion_list (char *, char *);
+extern char **make_symbol_completion_list_fn (struct cmd_list_element *,
+					      char *, char *);
 
 extern char **make_file_symbol_completion_list (char *, char *, char *);
 
diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp
new file mode 100644
index 0000000..6c73ff2
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-cmd.exp
@@ -0,0 +1,107 @@
+# Copyright (C) 2009 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/>.
+
+# This file is part of the GDB testsuite.  It tests the mechanism
+# for defining new GDB commands in Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+proc gdb_py_test_multiple {name args} {
+    global gdb_prompt
+    foreach {input result} $args {
+	if {[gdb_test_multiple $input "$name - $input" {
+	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+		pass "$name - $input"
+	    }
+	}]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+    -re "not supported.*$gdb_prompt $"	{
+      unsupported "python support is disabled"
+      return -1
+    }
+    -re "$gdb_prompt $"	{}
+}
+
+# Test a simple command.
+
+gdb_py_test_multiple "input simple command" \
+  "python" "" \
+  "class test_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"test_cmd output, arg = %s\" % arg" "" \
+  "test_cmd ()" "" \
+  "end" ""
+
+gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command"
+
+# Test a prefix command, and a subcommand within it.
+
+gdb_py_test_multiple "input prefix command" \
+  "python" "" \
+  "class prefix_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"prefix_cmd output, arg = %s\" % arg" "" \
+  "prefix_cmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command"
+
+gdb_py_test_multiple "input subcommand" \
+  "python" "" \
+  "class subcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"subcmd output, arg = %s\" % arg" "" \
+  "subcmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"
+
+# Test a subcommand in an existing GDB prefix.
+
+gdb_py_test_multiple "input new subcommand" \
+  "python" "" \
+  "class newsubcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"newsubcmd output, arg = %s\" % arg" "" \
+  "newsubcmd ()" "" \
+  "end" ""
+
+gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd"



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-05 22:40   ` Thiago Jung Bauermann
@ 2009-02-05 23:01     ` Tom Tromey
  2009-02-06  6:18     ` Eli Zaretskii
  1 sibling, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2009-02-05 23:01 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Eli Zaretskii, gdb-patches

>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:

Thiago> Tromey worked on them, here's a new version which addresses
Thiago> your comments and Daniel's. I also changed cmdpy_function and
Thiago> cmdpy_completer to convert the command arguments to a Unicode
Thiago> string instead of an 8-bit Python string.

The code bits are ok.

thanks,
Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-05 22:40   ` Thiago Jung Bauermann
  2009-02-05 23:01     ` Tom Tromey
@ 2009-02-06  6:18     ` Eli Zaretskii
  2009-02-06 22:12       ` Thiago Jung Bauermann
  1 sibling, 1 reply; 15+ messages in thread
From: Eli Zaretskii @ 2009-02-06  6:18 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 05 Feb 2009 20:40:05 -0200
> 
> gdb/doc/
> 2009-02-05  Tom Tromey  <tromey@redhat.com>
> 
> 	* gdb.texinfo (Python API): Add entry for Commands In Python.
> 	(Commands In Python): New node.

Thanks.  My only comment to the new text is that perhaps the COMMAND_*
constants should have followed the respective GDB command classes more
closely.  For example, COMMAND_RUNNING instead of COMMAND_RUN,
COMMAND_DATA instead of COMMAND_VARS, etc.  But that's a minor
concern, especially if you had a good reason to deviate from the GDB
interactive nomenclature.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-06 22:12       ` Thiago Jung Bauermann
@ 2009-02-06 20:52         ` Tom Tromey
  2009-02-06 21:35           ` Thiago Jung Bauermann
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2009-02-06 20:52 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Eli Zaretskii, gdb-patches

>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:

>> Thanks.  My only comment to the new text is that perhaps the COMMAND_*
>> constants should have followed the respective GDB command classes more
>> closely.  For example, COMMAND_RUNNING instead of COMMAND_RUN,
>> COMMAND_DATA instead of COMMAND_VARS, etc.  But that's a minor
>> concern, especially if you had a good reason to deviate from the GDB
>> interactive nomenclature.

Thiago> I like your idea, I'm not sure if there was good reason for the
Thiago> deviation other than that it was already present in the GDB source code
Thiago> already. Tom, what do you think?

It would be fine by me.  I chose these names to mostly follow the
internals, but following the help categories would also be ok.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-06 20:52         ` Tom Tromey
@ 2009-02-06 21:35           ` Thiago Jung Bauermann
  2009-02-07 10:02             ` Eli Zaretskii
  2009-02-15 15:47             ` Thiago Jung Bauermann
  0 siblings, 2 replies; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-06 21:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Eli Zaretskii, gdb-patches

El vie, 06-02-2009 a las 13:52 -0700, Tom Tromey escribió:
> Thiago> I like your idea, I'm not sure if there was good reason for the
> Thiago> deviation other than that it was already present in the GDB source code
> Thiago> already. Tom, what do you think?
> 
> It would be fine by me.  I chose these names to mostly follow the
> internals, but following the help categories would also be ok.

Great, I committed the following.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


gdb/
2009-02-06  Tom Tromey  <tromey@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-cmd.o.
	(SUBDIR_PYTHON_SRCS): Add python-cmd.c.
	(python-cmd.o): New target.
	* cli/cli-decode.c (set_cmd_completer): Add self parameter to
	completer prototype.
	(add_cmd): Initialize destroyer member of cmd_list_element. Use
	make_symbol_completion_list_fn as completer.
	(delete_cmd): Call destroyer if one is set.
	* cli/cli-decode.h (cmd_list_element): Add cmd parameter to
	completer member.  Add destroyer member.
	(set_cmd_completer): Add self parameter to
	completer prototype.
	* command.h (set_cmd_completer): Add cmd parameter to
	completer prototype.
	* completer.c (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	to new completer prototype.
	(complete_line_internal): Pass new parameter to completer function.
	* completer.h (noop_completer, filename_completer,
	location_completer, expression_completer, command_completer): Adapt
	prototypes to new completer prototype.
	* interps.c (interpreter_completer): Adapt to new completer
	prototype.
	* python/python-cmd.c: New file.
	* python/python-internal.h (gdbpy_initialize_commands): Add
	prototype.
	(gdbpy_doc_cst): Add forward declaration.
	* python/python.c (gdbpy_doc_cst): Declare.
	(_initialize_python): Call gdbpy_initialize_commands.  Initialize
	gdbpy_doc_cst.
	* symtab.c (make_symbol_completion_list_fn): New function.
	* symtab.h (make_symbol_completion_list_fn): Add prototype.

gdb/doc/
2009-02-06  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Python API): Add entry for Commands In Python.
	(Commands In Python): New node.

gdb/testsuite/
2009-02-06  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.python/python-cmd.exp: New file.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6a4f77d..7400702 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -270,10 +270,12 @@ SUBDIR_TUI_CFLAGS= \
 #
 SUBDIR_PYTHON_OBS = \
 	python.o \
+	python-cmd.o \
 	python-utils.o \
 	python-value.o
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
+	python/python-cmd.c \
 	python/python-utils.c \
 	python/python-value.c
 SUBDIR_PYTHON_DEPS =
@@ -1836,6 +1838,10 @@ python.o: $(srcdir)/python/python.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
 	$(POSTCOMPILE)
 
+python-cmd.o: $(srcdir)/python/python-cmd.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c
+	$(POSTCOMPILE)
+
 python-utils.o: $(srcdir)/python/python-utils.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index a85caeb..d1abf0c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -96,6 +96,8 @@ are treated as the standard definitions, regardless of context.
   GDB now has support for scripting using Python.  Whether this is
   available is determined at configure time.
 
+  New GDB commands can now be written in Python.
+
 * Ada tasking support
 
   Ada tasks can now be inspected in GDB. The following commands have
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 556c027..8760ebf 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -132,7 +132,8 @@ cmd_type (struct cmd_list_element *cmd)
 
 void
 set_cmd_completer (struct cmd_list_element *cmd,
-		   char **(*completer) (char *text, char *word))
+		   char **(*completer) (struct cmd_list_element *self,
+					char *text, char *word))
 {
   cmd->completer = completer; /* Ok.  */
 }
@@ -207,7 +208,8 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
   c->prefixname = NULL;
   c->allow_unknown = 0;
   c->abbrev_flag = 0;
-  set_cmd_completer (c, make_symbol_completion_list);
+  set_cmd_completer (c, make_symbol_completion_list_fn);
+  c->destroyer = NULL;
   c->type = not_set_cmd;
   c->var = NULL;
   c->var_type = var_boolean;
@@ -688,6 +690,8 @@ delete_cmd (char *name, struct cmd_list_element **list,
     {
       if (strcmp (iter->name, name) == 0)
 	{
+	  if (iter->destroyer)
+	    iter->destroyer (iter, iter->context);
 	  if (iter->hookee_pre)
 	    iter->hookee_pre->hook_pre = 0;
 	  *prehook = iter->hook_pre;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 56ea9bf..26ca2f7 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -167,7 +167,12 @@ struct cmd_list_element
        returned relative to this position.  For example, suppose TEXT is "foo"
        and we want to complete to "foobar".  If WORD is "oo", return
        "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
-    char **(*completer) (char *text, char *word);
+    char **(*completer) (struct cmd_list_element *cmd, char *text, char *word);
+
+    /* Destruction routine for this command.  If non-NULL, this is
+       called when this command instance is destroyed.  This may be
+       used to finalize the CONTEXT field, if needed.  */
+    void (*destroyer) (struct cmd_list_element *self, void *context);
 
     /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
        or "show").  */
@@ -242,7 +247,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 					  struct cmd_list_element * c));
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *self,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/command.h b/gdb/command.h
index b3f7013..bed615c 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -138,7 +138,8 @@ extern void set_cmd_sfunc (struct cmd_list_element *cmd,
 			   cmd_sfunc_ftype *sfunc);
 
 extern void set_cmd_completer (struct cmd_list_element *cmd,
-			       char **(*completer) (char *text, char *word));
+			       char **(*completer) (struct cmd_list_element *cmd,
+						    char *text, char *word));
 
 /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
    around in cmd objects to test the value of the commands sfunc().  */
diff --git a/gdb/completer.c b/gdb/completer.c
index 298cdd0..43fcf7a 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -105,14 +105,14 @@ readline_line_completion_function (const char *text, int matches)
 /* This can be used for functions which don't want to complete on symbols
    but don't want to complete on anything else either.  */
 char **
-noop_completer (char *text, char *prefix)
+noop_completer (struct cmd_list_element *ignore, char *text, char *prefix)
 {
   return NULL;
 }
 
 /* Complete on filenames.  */
 char **
-filename_completer (char *text, char *word)
+filename_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int subsequent_name;
   char **return_val;
@@ -195,7 +195,7 @@ filename_completer (char *text, char *word)
 
    This is intended to be used in commands that set breakpoints etc.  */
 char **
-location_completer (char *text, char *word)
+location_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int n_syms = 0, n_files = 0;
   char ** fn_list = NULL;
@@ -412,7 +412,7 @@ add_struct_fields (struct type *type, int *nextp, char **output,
    names, but some language parsers also have support for completing
    field names.  */
 char **
-expression_completer (char *text, char *word)
+expression_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   struct type *type;
   char *fieldname, *p;
@@ -456,7 +456,7 @@ expression_completer (char *text, char *word)
     ;
 
   /* Not ideal but it is what we used to do before... */
-  return location_completer (p, word);
+  return location_completer (ignore, p, word);
 }
 
 /* Here are some useful test cases for completion.  FIXME: These should
@@ -651,7 +651,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 			   p--)
 			;
 		    }
-		  list = (*c->completer) (p, word);
+		  list = (*c->completer) (c, p, word);
 		}
 	    }
 	  else
@@ -719,7 +719,7 @@ complete_line_internal (const char *text, char *line_buffer, int point,
 		       p--)
 		    ;
 		}
-	      list = (*c->completer) (p, word);
+	      list = (*c->completer) (c, p, word);
 	    }
 	}
     }
@@ -737,7 +737,7 @@ complete_line (const char *text, char *line_buffer, int point)
 
 /* Complete on command names.  Used by "help".  */
 char **
-command_completer (char *text, char *word)
+command_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   return complete_line_internal (word, text, strlen (text), 1);
 }
diff --git a/gdb/completer.h b/gdb/completer.h
index da1c381..6adbf1b 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -21,15 +21,15 @@ extern char **complete_line (const char *text, char *line_buffer, int point);
 
 extern char *readline_line_completion_function (const char *text, int matches);
 
-extern char **noop_completer (char *, char *);
+extern char **noop_completer (struct cmd_list_element *, char *, char *);
 
-extern char **filename_completer (char *, char *);
+extern char **filename_completer (struct cmd_list_element *, char *, char *);
 
-extern char **expression_completer (char *, char *);
+extern char **expression_completer (struct cmd_list_element *, char *, char *);
 
-extern char **location_completer (char *, char *);
+extern char **location_completer (struct cmd_list_element *, char *, char *);
 
-extern char **command_completer (char *, char *);
+extern char **command_completer (struct cmd_list_element *, char *, char *);
 
 extern char *get_gdb_completer_quote_characters (void);
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a2ed0b8..354b888 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18064,6 +18064,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * Basic Python::                Basic Python Functions.
 * Exception Handling::
 * Values From Inferior::
+* Commands In Python::          Implementing new commands in Python.
 @end menu
 
 @node Basic Python
@@ -18246,6 +18247,259 @@ The optional @var{errors} argument is the same as the corresponding
 argument to Python's @code{string.decode} method.
 @end defmethod
 
+@node Commands In Python
+@subsubsection Commands In Python
+
+@cindex commands in python
+@cindex python commands
+@tindex Command
+@tindex gdb.Command
+You can implement new @value{GDBN} CLI commands in Python.  A CLI
+command is implemented using an instance of the @code{gdb.Command}
+class, most commonly using a subclass.
+
+@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]}
+The object initializer for @code{Command} registers the new command
+with @value{GDBN}.  This initializer is normally invoked from the
+subclass' own @code{__init__} method.
+
+@var{name} is the name of the command.  If @var{name} consists of
+multiple words, then the initial words are looked for as prefix
+commands.  In this case, if one of the prefix commands does not exist,
+an exception is raised.
+
+There is no support for multi-line commands.
+
+@var{command-class} should be one of the @samp{COMMAND_} constants
+defined below.  This argument tells @value{GDBN} how to categorize the
+new command in the help system.
+
+@var{completer-class} is an optional argument.  If given, it should be
+one of the @samp{COMPLETE_} constants defined below.  This argument
+tells @value{GDBN} how to perform completion for this command.  If not
+given, @value{GDBN} will attempt to complete using the object's
+@code{complete} method (see below); if no such method is found, an
+error will occur when completion is attempted.
+
+@var{prefix} is an optional argument.  If @code{True}, then the new
+command is a prefix command; sub-commands of this command may be
+registered.
+
+The help text for the new command is taken from the Python
+documentation string for the command's class, if there is one.  If no
+documentation string is provided, the default value ``This command is
+not documented.'' is used.
+@end defmethod
+
+@defmethod Command dont_repeat
+By default, a @value{GDBN} command is repeated when the user enters a
+blank line at the command prompt.  A command can suppress this
+behavior by invoking the @code{dont_repeat} method.  This is similar
+to the user command @code{dont-repeat}, see @ref{Define, dont-repeat}.
+@end defmethod
+
+@defmethod Command invoke argument from_tty
+This method is called by @value{GDBN} when this command is invoked.
+
+@var{argument} is a string.  It is the argument to the command, after
+leading and trailing whitespace has been stripped.
+
+@var{from_tty} is a boolean argument.  When true, this means that the
+command was entered by the user at the terminal; when false it means
+that the command came from elsewhere.
+
+If this method throws an exception, it is turned into a @value{GDBN}
+@code{error} call.  Otherwise, the return value is ignored.
+@end defmethod
+
+@defmethod Command complete text word
+This method is called by @value{GDBN} when the user attempts
+completion on this command.  All forms of completion are handled by
+this method, that is, the @key{TAB} and @key{M-?} key bindings, and
+the @code{complete} command.
+
+The arguments @var{text} and @var{word} are both strings.  @var{text}
+holds the complete command line up to the cursor's location.
+@var{word} holds the last word of the command line; this is computed
+using a word-breaking heuristic.
+
+The @code{complete} method can return several values:
+@itemize @bullet
+@item
+If the return value is a sequence, the contents of the sequence are
+used as the completions.  It is up to @code{complete} to ensure that the
+contents actually do complete the word.  A zero-length sequence is
+allowed, it means that there were no completions available.  Only
+string elements of the sequence are used; other elements in the
+sequence are ignored.
+
+@item
+If the return value is one of the @samp{COMPLETE_} constants defined
+below, then the corresponding @value{GDBN}-internal completion
+function is invoked, and its result is used.
+
+@item
+All other results are treated as though there were no available
+completions.
+@end itemize
+@end defmethod
+
+
+When a new command is registered, it must be declared as a member of
+some general class of commands.  This is used to classify top-level
+commands in the on-line help system; note that prefix commands are not
+listed under their own category but rather that of their top-level
+command.  The available classifications are represented by constants
+defined in the @code{gdb} module:
+
+@table @code
+@findex COMMAND_NONE
+@findex gdb.COMMAND_NONE
+@item COMMAND_NONE
+The command does not belong to any particular class.  A command in
+this category will not be displayed in any of the help categories.
+
+@findex COMMAND_RUNNING
+@findex gdb.COMMAND_RUNNING
+@item COMMAND_RUN
+The command is related to running the inferior.  For example,
+@code{start}, @code{step}, and @code{continue} are in this category.
+Type @code{help running} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_DATA
+@findex gdb.COMMAND_DATA
+@item COMMAND_VARS
+The command is related to data or variables.  For example,
+@code{call}, @code{find}, and @code{print} are in this category.  Type
+@code{help data} at the @value{GDBN} prompt to see a list of commands
+in this category.
+
+@findex COMMAND_STACK
+@findex gdb.COMMAND_STACK
+@item COMMAND_STACK
+The command has to do with manipulation of the stack.  For example,
+@code{backtrace}, @code{frame}, and @code{return} are in this
+category.  Type @code{help stack} at the @value{GDBN} prompt to see a
+list of commands in this category.
+
+@findex COMMAND_FILES
+@findex gdb.COMMAND_FILES
+@item COMMAND_FILES
+This class is used for file-related commands.  For example,
+@code{file}, @code{list} and @code{section} are in this category.
+Type @code{help files} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_SUPPORT
+@findex gdb.COMMAND_SUPPORT
+@item COMMAND_SUPPORT
+This should be used for ``support facilities'', generally meaning
+things that are useful to the user when interacting with @value{GDBN},
+but not related to the state of the inferior.  For example,
+@code{help}, @code{make}, and @code{shell} are in this category.  Type
+@code{help support} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_STATUS
+@findex gdb.COMMAND_STATUS
+@item COMMAND_INFO
+The command is an @samp{info}-related command, that is, related to the
+state of @value{GDBN} itself.  For example, @code{info}, @code{macro},
+and @code{show} are in this category.  Type @code{help status} at the
+@value{GDBN} prompt to see a list of commands in this category.
+
+@findex COMMAND_BREAKPOINTS
+@findex gdb.COMMAND_BREAKPOINTS
+@item COMMAND_BREAKPOINT
+The command has to do with breakpoints.  For example, @code{break},
+@code{clear}, and @code{delete} are in this category.  Type @code{help
+breakpoints} at the @value{GDBN} prompt to see a list of commands in
+this category.
+
+@findex COMMAND_TRACEPOINTS
+@findex gdb.COMMAND_TRACEPOINTS
+@item COMMAND_TRACE
+The command has to do with tracepoints.  For example, @code{trace},
+@code{actions}, and @code{tfind} are in this category.  Type
+@code{help tracepoints} at the @value{GDBN} prompt to see a list of
+commands in this category.
+
+@findex COMMAND_OBSCURE
+@findex gdb.COMMAND_OBSCURE
+@item COMMAND_OBSCURE
+The command is only used in unusual circumstances, or is not of
+general interest to users.  For example, @code{checkpoint},
+@code{fork}, and @code{stop} are in this category.  Type @code{help
+obscure} at the @value{GDBN} prompt to see a list of commands in this
+category.
+
+@findex COMMAND_MAINTENANCE
+@findex gdb.COMMAND_MAINTENANCE
+@item COMMAND_MAINTENANCE
+The command is only useful to @value{GDBN} maintainers.  The
+@code{maintenance} and @code{flushregs} commands are in this category.
+Type @code{help internals} at the @value{GDBN} prompt to see a list of
+commands in this category.
+@end table
+
+
+A new command can use a predefined completion function, either by
+specifying it via an argument at initialization, or by returning it
+from the @code{complete} method.  These predefined completion
+constants are all defined in the @code{gdb} module:
+
+@table @code
+@findex COMPLETE_NONE
+@findex gdb.COMPLETE_NONE
+@item COMPLETE_NONE
+This constant means that no completion should be done.
+
+@findex COMPLETE_FILENAME
+@findex gdb.COMPLETE_FILENAME
+@item COMPLETE_FILENAME
+This constant means that filename completion should be performed.
+
+@findex COMPLETE_LOCATION
+@findex gdb.COMPLETE_LOCATION
+@item COMPLETE_LOCATION
+This constant means that location completion should be done.
+@xref{Specify Location}.
+
+@findex COMPLETE_COMMAND
+@findex gdb.COMPLETE_COMMAND
+@item COMPLETE_COMMAND
+This constant means that completion should examine @value{GDBN}
+command names.
+
+@findex COMPLETE_SYMBOL
+@findex gdb.COMPLETE_SYMBOL
+@item COMPLETE_SYMBOL
+This constant means that completion should be done using symbol names
+as the source.
+@end table
+
+The following code snippet shows how a trivial CLI command can be
+implemented in Python:
+
+@smallexample
+class HelloWorld (gdb.Command):
+  """Greet the whole world."""
+
+  def __init__ (self):
+    super (HelloWorld, self).__init__ ("hello-world", gdb.COMMAND_OBSCURE)
+
+  def invoke (self, arg, from_tty):
+    print "Hello, World!"
+
+HelloWorld ()
+@end smallexample
+
+The last line instantiates the class, and is necessary to trigger the
+registration of the command with @value{GDBN}.  Depending on how the
+Python code is read into @value{GDBN}, you may need to import the
+@code{gdb} module explicitly.
+
 @node Interpreters
 @chapter Command Interpreters
 @cindex command interpreters
diff --git a/gdb/interps.c b/gdb/interps.c
index 6814a72..da05ee2 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -71,7 +71,8 @@ struct interp
 
 /* Functions local to this file. */
 static void initialize_interps (void);
-static char **interpreter_completer (char *text, char *word);
+static char **interpreter_completer (struct cmd_list_element *cmd,
+				     char *text, char *word);
 
 /* The magic initialization routine for this module. */
 
@@ -416,7 +417,7 @@ interpreter_exec_cmd (char *args, int from_tty)
 
 /* List the possible interpreters which could complete the given text. */
 static char **
-interpreter_completer (char *text, char *word)
+interpreter_completer (struct cmd_list_element *ignore, char *text, char *word)
 {
   int alloced = 0;
   int textlen;
diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c
new file mode 100644
index 0000000..36cde34
--- /dev/null
+++ b/gdb/python/python-cmd.c
@@ -0,0 +1,585 @@
+/* gdb commands implemented in Python
+
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+#include "completer.h"
+
+/* Struct representing built-in completion types.  */
+struct cmdpy_completer
+{
+  /* Python symbol name.  */
+  char *name;
+  /* Completion function.  */
+  char **(*completer) (struct cmd_list_element *, char *, char *);
+};
+
+static struct cmdpy_completer completers[] =
+{
+  { "COMPLETE_NONE", noop_completer },
+  { "COMPLETE_FILENAME", filename_completer },
+  { "COMPLETE_LOCATION", location_completer },
+  { "COMPLETE_COMMAND", command_completer },
+  { "COMPLETE_SYMBOL", make_symbol_completion_list_fn },
+};
+
+#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0]))
+
+/* A gdb command.  For the time being only ordinary commands (not
+   set/show commands) are allowed.  */
+struct cmdpy_object
+{
+  PyObject_HEAD
+
+  /* The corresponding gdb command object, or NULL if the command is
+     no longer installed.  */
+  struct cmd_list_element *command;
+
+  /* A prefix command requires storage for a list of its sub-commands.
+     A pointer to this is passed to add_prefix_command, and to add_cmd
+     for sub-commands of that prefix.  If this Command is not a prefix
+     command, then this field is unused.  */
+  struct cmd_list_element *sub_list;
+};
+
+typedef struct cmdpy_object cmdpy_object;
+
+static PyTypeObject cmdpy_object_type;
+
+
+/* Constants used by this module.  */
+static PyObject *invoke_cst;
+static PyObject *complete_cst;
+
+\f
+
+/* Python function which wraps dont_repeat.  */
+static PyObject *
+cmdpy_dont_repeat (PyObject *self, PyObject *args)
+{
+  dont_repeat ();
+  Py_RETURN_NONE;
+}
+
+\f
+
+/* Called if the gdb cmd_list_element is destroyed.  */
+static void
+cmdpy_destroyer (struct cmd_list_element *self, void *context)
+{
+  cmdpy_object *cmd;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+
+  /* Release our hold on the command object.  */
+  cmd = (cmdpy_object *) context;
+  cmd->command = NULL;
+  Py_DECREF (cmd);
+
+  /* We allocated the name, doc string, and perhaps the prefix
+     name.  */
+  xfree (self->name);
+  xfree (self->doc);
+  xfree (self->prefixname);
+
+  PyGILState_Release (state);
+}
+
+/* Called by gdb to invoke the command.  */
+static void
+cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *argobj, *ttyobj, *result;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst))
+    {
+      if (obj->command->prefixname)
+	{
+	  /* A prefix command does not need an invoke method.  */
+	  do_cleanups (cleanup);
+	  return;
+	}
+      error (_("Python command object missing 'invoke' method."));
+    }
+
+  if (! args)
+    args = "";
+  argobj = PyUnicode_Decode (args, strlen (args), host_charset (), NULL);
+  if (! argobj)
+    error (_("Could not convert arguments to Python string."));
+
+  ttyobj = from_tty ? Py_True : Py_False;
+  Py_INCREF (ttyobj);
+  result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj,
+				       ttyobj, NULL);
+  Py_DECREF (argobj);
+  Py_DECREF (ttyobj);
+  if (! result)
+    {
+      PyObject *ptype, *pvalue, *ptraceback;
+      char *s, *str;
+
+      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
+
+      if (pvalue && PyString_Check (pvalue))
+	{
+	  /* Make a temporary copy of the string data.  */
+	  char *s = PyString_AsString (pvalue);
+	  char *copy = alloca (strlen (s) + 1);
+	  strcpy (copy, s);
+
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command: %s"), copy);
+	}
+      else
+	{
+	  PyErr_Restore (ptype, pvalue, ptraceback);
+	  gdbpy_print_stack ();
+	  error (_("Error occurred in Python command."));
+	}
+    }
+  Py_DECREF (result);
+  do_cleanups (cleanup);
+}
+
+/* Called by gdb for command completion.  */
+static char **
+cmdpy_completer (struct cmd_list_element *command, char *text, char *word)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *textobj, *wordobj, *resultobj = NULL;
+  char **result = NULL;
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  if (! obj)
+    error (_("Invalid invocation of Python command object."));
+  if (! PyObject_HasAttr ((PyObject *) obj, complete_cst))
+    {
+      /* If there is no complete method, don't error -- instead, just
+	 say that there are no completions.  */
+      goto done;
+    }
+
+  textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL);
+  if (! textobj)
+    error (_("Could not convert argument to Python string."));
+  wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL);
+  if (! wordobj)
+    error (_("Could not convert argument to Python string."));
+
+  resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst,
+					  textobj, wordobj, NULL);
+  Py_DECREF (textobj);
+  Py_DECREF (wordobj);
+  if (! resultobj)
+    {
+      /* Just swallow errors here.  */
+      PyErr_Clear ();
+      goto done;
+    }
+  make_cleanup_py_decref (resultobj);
+
+  result = NULL;
+  if (PySequence_Check (resultobj))
+    {
+      Py_ssize_t i, len = PySequence_Size (resultobj);
+      Py_ssize_t out;
+      if (len < 0)
+	goto done;
+
+      result = (char **) xmalloc ((len + 1) * sizeof (char *));
+      for (i = out = 0; i < len; ++i)
+	{
+	  int l;
+	  PyObject *elt = PySequence_GetItem (resultobj, i);
+	  if (elt == NULL || ! gdbpy_is_string (elt))
+	    {
+	      /* Skip problem elements.  */
+	      PyErr_Clear ();
+	      continue;
+	    }
+	  result[out] = python_string_to_host_string (elt);
+	  ++out;
+	}
+      result[out] = NULL;
+    }
+  else if (PyInt_Check (resultobj))
+    {
+      /* User code may also return one of the completion constants,
+	 thus requesting that sort of completion.  */
+      long value = PyInt_AsLong (resultobj);
+      if (value >= 0 && value < (long) N_COMPLETERS)
+	result = completers[value].completer (command, text, word);
+    }
+
+ done:
+
+  do_cleanups (cleanup);
+
+  return result;
+}
+
+/* Helper for cmdpy_init which locates the command list to use and
+   pulls out the command name.
+   
+   TEXT is the command name list.  The final word in the list is the
+   name of the new command.  All earlier words must be existing prefix
+   commands.
+
+   *BASE_LIST is set to the final prefix command's list of
+   *sub-commands.
+   
+   This function returns the xmalloc()d name of the new command.  On
+   error sets the Python error and returns NULL.  */
+static char *
+parse_command_name (char *text, struct cmd_list_element ***base_list)
+{
+  struct cmd_list_element *elt;
+  int len = strlen (text);
+  int i, lastchar;
+  char *prefix_text;
+  char *result;
+
+  /* Skip trailing whitespace.  */
+  for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      PyErr_SetString (PyExc_RuntimeError, _("no command name found"));
+      return NULL;
+    }
+  lastchar = i;
+
+  /* Find first character of the final word.  */
+  for (; i > 0 && (isalnum (text[i - 1])
+		   || text[i - 1] == '-'
+		   || text[i - 1] == '_');
+       --i)
+    ;
+  result = xmalloc (lastchar - i + 2);
+  memcpy (result, &text[i], lastchar - i + 1);
+  result[lastchar - i + 1] = '\0';
+
+  /* Skip whitespace again.  */
+  for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i)
+    ;
+  if (i < 0)
+    {
+      *base_list = &cmdlist;
+      return result;
+    }
+
+  prefix_text = xmalloc (i + 2);
+  memcpy (prefix_text, text, i + 1);
+  prefix_text[i + 1] = '\0';
+
+  text = prefix_text;
+  elt = lookup_cmd_1 (&text, cmdlist, NULL, 1);
+  if (!elt || elt == (struct cmd_list_element *) -1)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"),
+		    prefix_text);
+      xfree (prefix_text);
+      xfree (result);
+      return NULL;
+    }
+
+  if (elt->prefixlist)
+    {
+      xfree (prefix_text);
+      *base_list = elt->prefixlist;
+      return result;
+    }
+
+  PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"),
+		prefix_text);
+  xfree (prefix_text);
+  xfree (result);
+  return NULL;
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+   Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]).
+
+   NAME is the name of the command.  It may consist of multiple words,
+   in which case the final word is the name of the new command, and
+   earlier words must be prefix commands.
+
+   CMDCLASS is the kind of command.  It should be one of the COMMAND_*
+   constants defined in the gdb module.
+
+   COMPLETERCLASS is the kind of completer.  If not given, the
+   "complete" method will be used.  Otherwise, it should be one of the
+   COMPLETE_* constants defined in the gdb module.
+
+   If PREFIX is True, then this command is a prefix command.
+
+   The documentation for the command is taken from the doc string for
+   the python class.
+   
+*/
+static int
+cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+  cmdpy_object *obj = (cmdpy_object *) self;
+  char *name;
+  int cmdtype;
+  int completetype = -1;
+  char *docstring = NULL;
+  volatile struct gdb_exception except;
+  struct cmd_list_element **cmd_list;
+  char *cmd_name, *pfx_name;
+  PyObject *is_prefix = NULL;
+  int cmp;
+
+  if (obj->command)
+    {
+      /* Note: this is apparently not documented in Python.  We return
+	 0 for success, -1 for failure.  */
+      PyErr_Format (PyExc_RuntimeError,
+		    _("command object already initialized"));
+      return -1;
+    }
+
+  if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype,
+			  &completetype, &is_prefix))
+    return -1;
+
+  if (cmdtype != no_class && cmdtype != class_run
+      && cmdtype != class_vars && cmdtype != class_stack
+      && cmdtype != class_files && cmdtype != class_support
+      && cmdtype != class_info && cmdtype != class_breakpoint
+      && cmdtype != class_trace && cmdtype != class_obscure
+      && cmdtype != class_maintenance)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid command class argument"));
+      return -1;
+    }
+
+  if (completetype < -1 || completetype >= (int) N_COMPLETERS)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("invalid completion type argument"));
+      return -1;
+    }
+
+  cmd_name = parse_command_name (name, &cmd_list);
+  if (! cmd_name)
+    return -1;
+
+  pfx_name = NULL;
+  if (is_prefix != NULL) 
+    {
+      cmp = PyObject_IsTrue (is_prefix);
+      if (cmp == 1)
+	{
+	  int i, out;
+	  
+	  /* Make a normalized form of the command name.  */
+	  pfx_name = xmalloc (strlen (name) + 2);
+	  
+	  i = 0;
+	  out = 0;
+	  while (name[i])
+	    {
+	      /* Skip whitespace.  */
+	      while (name[i] == ' ' || name[i] == '\t')
+		++i;
+	      /* Copy non-whitespace characters.  */
+	      while (name[i] && name[i] != ' ' && name[i] != '\t')
+		pfx_name[out++] = name[i++];
+	      /* Add a single space after each word -- including the final
+		 word.  */
+	      pfx_name[out++] = ' ';
+	    }
+	  pfx_name[out] = '\0';
+	}
+      else if (cmp < 0)
+	  return -1;
+    }
+  if (PyObject_HasAttr (self, gdbpy_doc_cst))
+    {
+      PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst);
+      if (ds_obj && gdbpy_is_string (ds_obj))
+	docstring = python_string_to_host_string (ds_obj);
+    }
+  if (! docstring)
+    docstring = xstrdup (_("This command is not documented."));
+
+  Py_INCREF (self);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      struct cmd_list_element *cmd;
+
+      if (pfx_name)
+	{
+	  int allow_unknown;
+
+	  /* If we have our own "invoke" method, then allow unknown
+	     sub-commands.  */
+	  allow_unknown = PyObject_HasAttr (self, invoke_cst);
+	  cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype,
+				NULL, docstring, &obj->sub_list,
+				pfx_name, allow_unknown, cmd_list);
+	}
+      else
+	cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL,
+		       docstring, cmd_list);
+
+      /* There appears to be no API to set this.  */
+      cmd->func = cmdpy_function;
+      cmd->destroyer = cmdpy_destroyer;
+
+      obj->command = cmd;
+      set_cmd_context (cmd, self);
+      set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer
+			       : completers[completetype].completer));
+    }
+  if (except.reason < 0)
+    {
+      xfree (cmd_name);
+      xfree (docstring);
+      xfree (pfx_name);
+      Py_DECREF (self);
+      PyErr_Format (except.reason == RETURN_QUIT
+		    ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+		    "%s", except.message);
+      return -1;
+    }
+  return 0;
+}
+
+\f
+
+/* Initialize the 'commands' code.  */
+void
+gdbpy_initialize_commands (void)
+{
+  int i;
+
+  if (PyType_Ready (&cmdpy_object_type) < 0)
+    return;
+
+  /* Note: alias and user are special; pseudo appears to be unused,
+     and there is no reason to expose tui or xdb, I think.  */
+  if (PyModule_AddIntConstant (gdb_module, "COMMAND_NONE", no_class) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_RUNNING", class_run) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_DATA", class_vars) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_STACK", class_stack) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_FILES", class_files) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_SUPPORT",
+				  class_support) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_STATUS", class_info) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINTS",
+				  class_breakpoint) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACEPOINTS",
+				  class_trace) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
+				  class_obscure) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
+				  class_maintenance) < 0)
+    return;
+
+  for (i = 0; i < N_COMPLETERS; ++i)
+    {
+      if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0)
+	return;
+    }
+
+  Py_INCREF (&cmdpy_object_type);
+  PyModule_AddObject (gdb_module, "Command",
+		      (PyObject *) &cmdpy_object_type);
+
+  invoke_cst = PyString_FromString ("invoke");
+  complete_cst = PyString_FromString ("complete");
+}
+
+\f
+
+static PyMethodDef cmdpy_object_methods[] =
+{
+  { "dont_repeat", cmdpy_dont_repeat, METH_NOARGS,
+    "Prevent command repetition when user enters empty line." },
+
+  { 0 }
+};
+
+static PyTypeObject cmdpy_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Command",		  /*tp_name*/
+  sizeof (cmdpy_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  0,				  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  "GDB command object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  cmdpy_object_methods,		  /* tp_methods */
+  0,				  /* tp_members */
+  0,				  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  cmdpy_init,			  /* tp_init */
+  0,				  /* tp_alloc */
+  PyType_GenericNew		  /* tp_new */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1457928..02dbfc4 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -70,6 +70,7 @@ PyObject *value_to_value_object (struct value *v);
 struct value *convert_value_from_python (PyObject *obj);
 
 void gdbpy_initialize_values (void);
+void gdbpy_initialize_commands (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
@@ -94,4 +95,6 @@ char *python_string_to_host_string (PyObject *obj);
 PyObject *target_string_to_unicode (const gdb_byte *str, int length);
 int gdbpy_is_string (PyObject *obj);
 
+extern PyObject *gdbpy_doc_cst;
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 96bb5f5..4f97416 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -46,6 +46,8 @@ static PyMethodDef GdbMethods[];
 
 PyObject *gdb_module;
 
+PyObject *gdbpy_doc_cst;
+
 /* Given a command_line, return a command string suitable for passing
    to Python.  Lines in the string are separated by newlines.  The
    return value is allocated using xmalloc and the caller is
@@ -407,9 +409,12 @@ Enables or disables printing of Python stack traces."),
   PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
 
   gdbpy_initialize_values ();
+  gdbpy_initialize_commands ();
 
   PyRun_SimpleString ("import gdb");
 
+  gdbpy_doc_cst = PyString_FromString ("__doc__");
+
   /* Create a couple objects which are used for Python's stdout and
      stderr.  */
   PyRun_SimpleString ("\
diff --git a/gdb/symtab.c b/gdb/symtab.c
index b9befed..97d7950 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3890,6 +3890,16 @@ make_symbol_completion_list (char *text, char *word)
   return current_language->la_make_symbol_completion_list (text, word);
 }
 
+/* Like make_symbol_completion_list, but suitable for use as a
+   completion function.  */
+
+char **
+make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+				char *text, char *word)
+{
+  return make_symbol_completion_list (text, word);
+}
+
 /* Like make_symbol_completion_list, but returns a list of symbols
    defined in a source file FILE.  */
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 2446d1e..8b086f3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1238,6 +1238,8 @@ extern void select_source_symtab (struct symtab *);
 
 extern char **default_make_symbol_completion_list (char *, char *);
 extern char **make_symbol_completion_list (char *, char *);
+extern char **make_symbol_completion_list_fn (struct cmd_list_element *,
+					      char *, char *);
 
 extern char **make_file_symbol_completion_list (char *, char *, char *);
 
diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp
new file mode 100644
index 0000000..6c73ff2
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-cmd.exp
@@ -0,0 +1,107 @@
+# Copyright (C) 2009 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/>.
+
+# This file is part of the GDB testsuite.  It tests the mechanism
+# for defining new GDB commands in Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+proc gdb_py_test_multiple {name args} {
+    global gdb_prompt
+    foreach {input result} $args {
+	if {[gdb_test_multiple $input "$name - $input" {
+	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+		pass "$name - $input"
+	    }
+	}]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+    -re "not supported.*$gdb_prompt $"	{
+      unsupported "python support is disabled"
+      return -1
+    }
+    -re "$gdb_prompt $"	{}
+}
+
+# Test a simple command.
+
+gdb_py_test_multiple "input simple command" \
+  "python" "" \
+  "class test_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"test_cmd output, arg = %s\" % arg" "" \
+  "test_cmd ()" "" \
+  "end" ""
+
+gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command"
+
+# Test a prefix command, and a subcommand within it.
+
+gdb_py_test_multiple "input prefix command" \
+  "python" "" \
+  "class prefix_cmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"prefix_cmd output, arg = %s\" % arg" "" \
+  "prefix_cmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command"
+
+gdb_py_test_multiple "input subcommand" \
+  "python" "" \
+  "class subcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"subcmd output, arg = %s\" % arg" "" \
+  "subcmd ()" "" \
+  "end" ""
+
+gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"
+
+# Test a subcommand in an existing GDB prefix.
+
+gdb_py_test_multiple "input new subcommand" \
+  "python" "" \
+  "class newsubcmd (gdb.Command):" "" \
+  "  def __init__ (self):" "" \
+  "    super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \
+  "  def invoke (self, arg, from_tty):" "" \
+  "    print \"newsubcmd output, arg = %s\" % arg" "" \
+  "newsubcmd ()" "" \
+  "end" ""
+
+gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd"



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-06  6:18     ` Eli Zaretskii
@ 2009-02-06 22:12       ` Thiago Jung Bauermann
  2009-02-06 20:52         ` Tom Tromey
  0 siblings, 1 reply; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-06 22:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, Tom Tromey

El vie, 06-02-2009 a las 08:18 +0200, Eli Zaretskii escribió:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: gdb-patches@sourceware.org
> > Date: Thu, 05 Feb 2009 20:40:05 -0200
> > 
> > gdb/doc/
> > 2009-02-05  Tom Tromey  <tromey@redhat.com>
> > 
> > 	* gdb.texinfo (Python API): Add entry for Commands In Python.
> > 	(Commands In Python): New node.
> 
> Thanks.  My only comment to the new text is that perhaps the COMMAND_*
> constants should have followed the respective GDB command classes more
> closely.  For example, COMMAND_RUNNING instead of COMMAND_RUN,
> COMMAND_DATA instead of COMMAND_VARS, etc.  But that's a minor
> concern, especially if you had a good reason to deviate from the GDB
> interactive nomenclature.

I like your idea, I'm not sure if there was good reason for the
deviation other than that it was already present in the GDB source code
already. Tom, what do you think?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-06 21:35           ` Thiago Jung Bauermann
@ 2009-02-07 10:02             ` Eli Zaretskii
  2009-02-08 23:57               ` Thiago Jung Bauermann
  2009-02-15 15:47             ` Thiago Jung Bauermann
  1 sibling, 1 reply; 15+ messages in thread
From: Eli Zaretskii @ 2009-02-07 10:02 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: tromey, gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches@sourceware.org
> Date: Fri, 06 Feb 2009 19:34:42 -0200
> 
> El vie, 06-02-2009 a las 13:52 -0700, Tom Tromey escribió:
> > Thiago> I like your idea, I'm not sure if there was good reason for the
> > Thiago> deviation other than that it was already present in the GDB source code
> > Thiago> already. Tom, what do you think?
> > 
> > It would be fine by me.  I chose these names to mostly follow the
> > internals, but following the help categories would also be ok.
> 
> Great, I committed the following.

Thanks.  I fixed a few typos in your last patch, and also fixed a typo
in a previous change from several days ago.  While at that, I changed
@code to @kbd in describing interactive input, and added a few
cross-references and index entries.  Here's what I checked in:

2009-02-07  Eli Zaretskii  <eliz@gnu.org>

	* gdb.texinfo (Basic Python): Fix change from 2009-02-04.
	(Commands In Python): Fix COMMAND_* constants in last change.  Use
	@kbd for interactive input.  Add cross-references and index
	entries.

Index: gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.557
diff -u -r1.557 gdb.texinfo
--- gdb.texinfo	6 Feb 2009 22:59:01 -0000	1.557
+++ gdb.texinfo	7 Feb 2009 09:57:44 -0000
@@ -18171,7 +18171,7 @@
 If @var{number} is negative, then @value{GDBN} will take its absolute value
 and count backward from the last element (i.e., the most recent element) to
 find the value to return.  If @var{number} is zero, then @value{GDBN} will
-return the most recent element.  If the element specified by @value{number}
+return the most recent element.  If the element specified by @var{number}
 doesn't exist in the value history, a @code{RuntimeError} exception will be
 raised.
 
@@ -18353,6 +18353,7 @@
 not documented.'' is used.
 @end defmethod
 
+@cindex don't repeat Python command
 @defmethod Command dont_repeat
 By default, a @value{GDBN} command is repeated when the user enters a
 blank line at the command prompt.  A command can suppress this
@@ -18374,11 +18375,13 @@
 @code{error} call.  Otherwise, the return value is ignored.
 @end defmethod
 
+@cindex completion of Python commands
 @defmethod Command complete text word
 This method is called by @value{GDBN} when the user attempts
 completion on this command.  All forms of completion are handled by
-this method, that is, the @key{TAB} and @key{M-?} key bindings, and
-the @code{complete} command.
+this method, that is, the @key{TAB} and @key{M-?} key bindings
+(@pxref{Completion}), and the @code{complete} command (@pxref{Help,
+complete}).
 
 The arguments @var{text} and @var{word} are both strings.  @var{text}
 holds the complete command line up to the cursor's location.
@@ -18423,18 +18426,18 @@
 
 @findex COMMAND_RUNNING
 @findex gdb.COMMAND_RUNNING
-@item COMMAND_RUN
+@item COMMAND_RUNNING
 The command is related to running the inferior.  For example,
 @code{start}, @code{step}, and @code{continue} are in this category.
-Type @code{help running} at the @value{GDBN} prompt to see a list of
+Type @kbd{help running} at the @value{GDBN} prompt to see a list of
 commands in this category.
 
 @findex COMMAND_DATA
 @findex gdb.COMMAND_DATA
-@item COMMAND_VARS
+@item COMMAND_DATA
 The command is related to data or variables.  For example,
 @code{call}, @code{find}, and @code{print} are in this category.  Type
-@code{help data} at the @value{GDBN} prompt to see a list of commands
+@kbd{help data} at the @value{GDBN} prompt to see a list of commands
 in this category.
 
 @findex COMMAND_STACK
@@ -18442,7 +18445,7 @@
 @item COMMAND_STACK
 The command has to do with manipulation of the stack.  For example,
 @code{backtrace}, @code{frame}, and @code{return} are in this
-category.  Type @code{help stack} at the @value{GDBN} prompt to see a
+category.  Type @kbd{help stack} at the @value{GDBN} prompt to see a
 list of commands in this category.
 
 @findex COMMAND_FILES
@@ -18450,7 +18453,7 @@
 @item COMMAND_FILES
 This class is used for file-related commands.  For example,
 @code{file}, @code{list} and @code{section} are in this category.
-Type @code{help files} at the @value{GDBN} prompt to see a list of
+Type @kbd{help files} at the @value{GDBN} prompt to see a list of
 commands in this category.
 
 @findex COMMAND_SUPPORT
@@ -18460,31 +18463,31 @@
 things that are useful to the user when interacting with @value{GDBN},
 but not related to the state of the inferior.  For example,
 @code{help}, @code{make}, and @code{shell} are in this category.  Type
-@code{help support} at the @value{GDBN} prompt to see a list of
+@kbd{help support} at the @value{GDBN} prompt to see a list of
 commands in this category.
 
 @findex COMMAND_STATUS
 @findex gdb.COMMAND_STATUS
-@item COMMAND_INFO
+@item COMMAND_STATUS
 The command is an @samp{info}-related command, that is, related to the
 state of @value{GDBN} itself.  For example, @code{info}, @code{macro},
-and @code{show} are in this category.  Type @code{help status} at the
+and @code{show} are in this category.  Type @kbd{help status} at the
 @value{GDBN} prompt to see a list of commands in this category.
 
 @findex COMMAND_BREAKPOINTS
 @findex gdb.COMMAND_BREAKPOINTS
-@item COMMAND_BREAKPOINT
+@item COMMAND_BREAKPOINTS
 The command has to do with breakpoints.  For example, @code{break},
-@code{clear}, and @code{delete} are in this category.  Type @code{help
+@code{clear}, and @code{delete} are in this category.  Type @kbd{help
 breakpoints} at the @value{GDBN} prompt to see a list of commands in
 this category.
 
 @findex COMMAND_TRACEPOINTS
 @findex gdb.COMMAND_TRACEPOINTS
-@item COMMAND_TRACE
+@item COMMAND_TRACEPOINTS
 The command has to do with tracepoints.  For example, @code{trace},
 @code{actions}, and @code{tfind} are in this category.  Type
-@code{help tracepoints} at the @value{GDBN} prompt to see a list of
+@kbd{help tracepoints} at the @value{GDBN} prompt to see a list of
 commands in this category.
 
 @findex COMMAND_OBSCURE
@@ -18492,7 +18495,7 @@
 @item COMMAND_OBSCURE
 The command is only used in unusual circumstances, or is not of
 general interest to users.  For example, @code{checkpoint},
-@code{fork}, and @code{stop} are in this category.  Type @code{help
+@code{fork}, and @code{stop} are in this category.  Type @kbd{help
 obscure} at the @value{GDBN} prompt to see a list of commands in this
 category.
 
@@ -18501,7 +18504,7 @@
 @item COMMAND_MAINTENANCE
 The command is only useful to @value{GDBN} maintainers.  The
 @code{maintenance} and @code{flushregs} commands are in this category.
-Type @code{help internals} at the @value{GDBN} prompt to see a list of
+Type @kbd{help internals} at the @value{GDBN} prompt to see a list of
 commands in this category.
 @end table
 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-07 10:02             ` Eli Zaretskii
@ 2009-02-08 23:57               ` Thiago Jung Bauermann
  0 siblings, 0 replies; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-08 23:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tromey, gdb-patches

El sáb, 07-02-2009 a las 12:02 +0200, Eli Zaretskii escribió:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: Eli Zaretskii <eliz@gnu.org>, gdb-patches@sourceware.org
> > Date: Fri, 06 Feb 2009 19:34:42 -0200
> > 
> > Great, I committed the following.
> 
> Thanks.  I fixed a few typos in your last patch, and also fixed a typo
> in a previous change from several days ago.  While at that, I changed
> @code to @kbd in describing interactive input, and added a few
> cross-references and index entries.  Here's what I checked in:

Thanks for cleaning this up! 
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][python] Add support for commands implemented in Python
  2009-02-06 21:35           ` Thiago Jung Bauermann
  2009-02-07 10:02             ` Eli Zaretskii
@ 2009-02-15 15:47             ` Thiago Jung Bauermann
  1 sibling, 0 replies; 15+ messages in thread
From: Thiago Jung Bauermann @ 2009-02-15 15:47 UTC (permalink / raw)
  To: gdb-patches ml

El vie, 06-02-2009 a las 19:34 -0200, Thiago Jung Bauermann escribió:
> gdb/testsuite/
> 2009-02-06  Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* gdb.python/python-cmd.exp: New file.

Er, I actually forgot to commit this file. Fixed now.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-02-14 21:59 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-02 13:13 [RFC][python] Add support for commands implemented in Python Thiago Jung Bauermann
2009-02-02 20:08 ` Eli Zaretskii
2009-02-04 19:50   ` Tom Tromey
2009-02-05 22:40   ` Thiago Jung Bauermann
2009-02-05 23:01     ` Tom Tromey
2009-02-06  6:18     ` Eli Zaretskii
2009-02-06 22:12       ` Thiago Jung Bauermann
2009-02-06 20:52         ` Tom Tromey
2009-02-06 21:35           ` Thiago Jung Bauermann
2009-02-07 10:02             ` Eli Zaretskii
2009-02-08 23:57               ` Thiago Jung Bauermann
2009-02-15 15:47             ` Thiago Jung Bauermann
2009-02-04  0:32 ` Daniel Jacobowitz
2009-02-04 20:02   ` Tom Tromey
2009-02-04 20:12     ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox