[asterisk-commits] rizzo: branch rizzo/astobj2 r47590 - in /team/rizzo/astobj2: include/asterisk...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Nov 14 02:04:12 MST 2006


Author: rizzo
Date: Tue Nov 14 03:04:09 2006
New Revision: 47590

URL: http://svn.digium.com/view/asterisk?view=rev&rev=47590
Log:
a bit of cleanup and documentation of the new internal cli api,
following comments from yesterday on irc/email.

This changes the module ABI because we add two fields
to the struct ast_cli_entry(), so people with binary-only
modules will need to have them rebuilt when this is committed to trunk.
Kevin says this is not a big issue.

There is a way to avoid the breakage, i am still looking at
the best way to do this before putting this stuff into trunk.


Modified:
    team/rizzo/astobj2/include/asterisk/cli.h
    team/rizzo/astobj2/main/astobj2.c
    team/rizzo/astobj2/main/cli.c

Modified: team/rizzo/astobj2/include/asterisk/cli.h
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/include/asterisk/cli.h?view=diff&rev=47590&r1=47589&r2=47590
==============================================================================
--- team/rizzo/astobj2/include/asterisk/cli.h (original)
+++ team/rizzo/astobj2/include/asterisk/cli.h Tue Nov 14 03:04:09 2006
@@ -45,24 +45,104 @@
 #define AST_CLI_COMPLETE_EOF	"_EOF_"
 
 /*!
- * New-style CLI handler use a single function to implement all the
- * functionality of the cli handler. Called with the default arguments,
- * (argc >0), the handler simply implements the command as before.
- * A negative argc indicates one of the other functions, namely
- * generate the usage string, the full command, or implement the generator.
- * As a trick to extend the interface while being backward compatible,
- * argv[-1] points to a struct ast_cli_args, and for the generator,
- * argv[0] is really a pointer to a struct ast_cli_args.
- * The return string is obtained by casting the result to char *
- */
+   CLI commands are described by a struct ast_cli_entry that contains
+   all the components for their implementation.
+   In the "old-style" format, the record must contain:
+   - a NULL-terminated array of words constituting the command, e.g.
+	{ "set", "debug", "on", NULL },
+   - a summary string (short) and a usage string (longer);
+   - a handler which implements the command itself, invoked with
+     a file descriptor and argc/argv as typed by the user
+   - a 'generator' function which, given a partial string, can
+     generate legal completions for it.
+   An example is
+
+	int old_setdebug(int fd, int argc, char *argv[]);
+	char *dbg_complete(const char *line, const char *word, int pos, int n);
+
+	{ { "set", "debug", "on", NULL }, do_setdebug, "Enable debugging",
+	set_debug_usage, dbg_complete },
+
+   In the "new-style" format, all the above functionalities are implemented
+   by a single function, and the arguments tell which output is required.
+
+   NOTE: ideally, the new-style handler would have a different prototype,
+   i.e. something like
+	int new_setdebug(const struct ast_cli *e, int function,
+	    int fd, int argc, char *argv[],	// handler args
+	    int n, int pos, const char *line, const char *word // -complete args)
+   but at this moment we want to help the transition from old-style to new-style
+   functions so we keep the same interface and override some of the traditional
+   arguments.
+
+   To help the transition, a new-style entry has the same interface as the old one,
+   but it is declared as follows:
+
+	int new_setdebug(int fd, int argc, char *argv[]);
+
+	...
+	NEW_CLI(new_setdebug)	// this is how we create the entry to register
+	...
+
+   Called with the default arguments (argc > 0), the new_handler implements
+   the command as before.
+   A negative argc indicates one of the other functions, namely
+   generate the usage string, the full command, or implement the generator.
+   As a trick to extend the interface while being backward compatible,
+   argv[-1] points to a struct ast_cli_args, and, for the generator,
+   argv[0] is really a pointer to a struct ast_cli_args.
+   The return string is obtained by casting the result to char *
+
+   An example of new-style handler is the following
+
+\code
+static int test_new_cli(int fd, int argc, char *argv[])
+{
+        struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
+        struct ast_cli_args *a;
+	static char *choices = { "one", "two", "three", NULL };
+
+        switch(argc) {
+        case CLI_USAGE:
+                return (int)
+			"Usage: do this well <arg>\n"
+			"	typically multiline with body indented\n";
+
+        case CLI_CMD_STRING:
+                return (int)"do this well";
+
+        case CLI_GENERATE:
+                a = (struct ast_cli_args *)argv[0];
+                if (a->pos > e->args)
+                        return NULL;
+        	return ast_cli_complete(a->word, choices, a->n);
+
+        default:        
+                // we are guaranteed to be called with argc >= e->args;
+                if (argc > e->args + 1) // we accept one extra argument
+                        return RESULT_SHOWUSAGE;
+                ast_cli(fd, "done this well for %s\n", e->args[argc-1]);
+                return RESULT_SUCCESS;
+        }
+}
+
+\endcode
+ *
+ */
+
+/*! \brief calling arguments for new-style handlers */
 enum ast_cli_fn {
 	CLI_USAGE = -1,		/* return the usage string */
 	CLI_CMD_STRING = -2,	/* return the command string */
 	CLI_GENERATE = -3,	/* behave as 'generator', remap argv to struct ast_cli_args */
 };
 
+typedef int (*old_cli_fn)(int fd, int argc, char *argv[]);
+
+/*! \brief descriptor for a cli entry */
 struct ast_cli_entry {
-	char * const cmda[AST_MAX_CMD_LEN];
+	char * const cmda[AST_MAX_CMD_LEN];	/*!< words making up the command.
+		* set the first entry to NULL for a new-style entry. */
 	/*! Handler for the command (fd for output, # of args, argument list).
 	  Returns RESULT_SHOWUSAGE for improper arguments.
 	  argv[] has argc 'useful' entries, and an additional NULL entry
@@ -72,10 +152,8 @@
 	  that this memory is deallocated after the handler returns.
 	 */
 	int (*handler)(int fd, int argc, char *argv[]);
-	/*! Summary of the command (< 60 characters) */
-	const char *summary;
-	/*! Detailed usage information */
-	const char *usage;
+	const char *summary; /*!< Summary of the command (< 60 characters) */
+	const char *usage; /*!< Detailed usage information */
 	/*! Generate the n-th (starting from 0) possible completion
 	  for a given 'word' following 'line' in position 'pos'.
 	  'line' and 'word' must not be modified.
@@ -86,25 +164,25 @@
 	 */
 	char *(*generator)(const char *line, const char *word, int pos, int n);
 	struct ast_cli_entry *deprecate_cmd;
-	/*! For keeping track of usage */
-	int inuse;
-	struct module *module;	/*! module this belongs to */
+	int inuse; /*!< For keeping track of usage */
+	struct module *module;	/*!< module this belongs to */
 	char *_full_cmd;	/* built at load time from cmda[] */
 	/* This gets set in ast_cli_register()
 	  It then gets set to something different when the deprecated command
 	  is run for the first time (ie; after we warn the user that it's deprecated)
 	 */
-	char *new_style_buf;		/* new style handler */
-	int args;			/* number of non-null entries in cmda */
+	int args;		/*!< number of non-null entries in cmda */
+	char *command;		/*!< command, non-null for new-style entries */
 	int deprecated;
 	char *_deprecated_by;	/* copied from the "parent" _full_cmd, on deprecated commands */
 	/*! For linking */
 	AST_LIST_ENTRY(ast_cli_entry) list;
 };
 
+#define NEW_CLI(fn)	{ .handler = (old_cli_fn)fn }
+
 /* argument for new-style CLI handler */
 struct ast_cli_args {
-/*! \brief A command line entry */
 	char fake[4];		/* a fake string, in the first position, for safety */
 	const char *line;	/* the current input line */
 	const char *word;	/* the word we want to complete */
@@ -113,7 +191,7 @@
 };
 
 /*!
- * \brief Helper function to generate cli entries from a NULL-terminated array.
+ * Helper function to generate cli entries from a NULL-terminated array.
  * Returns the n-th matching entry from the array, or NULL if not found.
  * Can be used to implement generate() for static entries as below
  * (in this example we complete the word in position 2):

Modified: team/rizzo/astobj2/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/astobj2.c?view=diff&rev=47590&r1=47589&r2=47590
==============================================================================
--- team/rizzo/astobj2/main/astobj2.c (original)
+++ team/rizzo/astobj2/main/astobj2.c Tue Nov 14 03:04:09 2006
@@ -665,6 +665,7 @@
 	return 0;
 }
 
+#if 1
 static int test_new_cli(int fd, int argc, char *argv[])
 {
 	struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
@@ -695,14 +696,13 @@
 		return RESULT_SUCCESS;
 	}
 }
+#endif
+
 static struct ast_cli_entry cli_astobj2[] = {
 	{ { "astobj2", "stats", NULL },
-	handle_astobj2_stats, "Print astobj2 statistics",
-	NULL },
-	{ { "astobj2", "test", NULL },
-	handle_astobj2_test, "Test astobj2",
-	NULL },
-	{ { NULL }, test_new_cli },
+	handle_astobj2_stats, "Print astobj2 statistics", },
+	{ { "astobj2", "test", NULL } , handle_astobj2_test, "Test astobj2", },
+	NEW_CLI(test_new_cli),
 };
 
 int astobj2_init(void);

Modified: team/rizzo/astobj2/main/cli.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/cli.c?view=diff&rev=47590&r1=47589&r2=47590
==============================================================================
--- team/rizzo/astobj2/main/cli.c (original)
+++ team/rizzo/astobj2/main/cli.c Tue Nov 14 03:04:09 2006
@@ -1168,10 +1168,11 @@
 		AST_LIST_UNLOCK(&helpers);
 		free(e->_full_cmd);
 		e->_full_cmd = NULL;
-		if (e->new_style_buf) {
+		if (e->command) {
+			/* this is a new-style entry. Reset fields and free memory. */
 			((char **)e->cmda)[0] = NULL;
-			free(e->new_style_buf);
-			e->new_style_buf = NULL;
+			free(e->command);
+			e->command = NULL;
 			e->usage = NULL;
 		}
 	}
@@ -1190,7 +1191,7 @@
 		char **dst = (char **)e->cmda;	/* need to cast as the entry is readonly */
 
 		s = ast_skip_blanks(s);
-		s = e->new_style_buf = ast_strdup(s);
+		s = e->command = ast_strdup(s);
 		for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
 			*dst++ = s;	/* store string */
 			s = ast_skip_nonblanks(s);
@@ -1201,7 +1202,7 @@
 		}
 		*dst++ = NULL;
 		e->usage = (char *)(e->handler(-1, CLI_USAGE, args+1));
-		ast_verbose("running new-style CLI entry for %s\n", e->new_style_buf);
+		ast_verbose("running new-style CLI entry for %s\n", e->command);
 		sleep(1);
 	}
 	for (i = 0; e->cmda[i]; i++)
@@ -1526,7 +1527,7 @@
 			 */
 			if (e->generator)
 				ret = e->generator(matchstr, word, argindex, state);
-			else if (e->new_style_buf) {	/* new style command */
+			else if (e->command) {	/* new style command */
 				/* prepare fake arguments for the generator.
 				 * argv[-1] is the cli entry we use,
 				 * argv[0] is a pointer to the generator arguments,



More information about the asterisk-commits mailing list