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

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Nov 13 03:27:07 MST 2006


Author: rizzo
Date: Mon Nov 13 04:27:04 2006
New Revision: 47532

URL: http://svn.digium.com/view/asterisk?view=rev&rev=47532
Log:
Some cleanup to the CLI support routines, and an initial implementation
of an enhanced CLI internal API that simplifies the implementation of the commands.

Basically, the new internal API puts the entire implementation of a CLI
command (command syntax, usage string, handler and "complete" handler)
in a single function, so it is easy to keep them all consistent.
It also passes the function a pointer to the cli entry in use,
where there is a lot of information on the entry (e.g. number of
arguments, etc) so we don't have to hardcode those in the function
itself, and changing the command string (e.g. by adding/removing
words) becomes trivial.
At this stage, the changes are fully backward compatible so
we can have both old-style and new-style commands coexisting.
The generator wrapper is not complete yet (but just a few lines of code away).

The following fixes are trunk (and possibly 1.4) candidates, 
irrespective of the above: 

- the _full_cmd string in the struct ast_cli_entry is not freed on
  unregister, thus leaking memory.
- the loop to complete the function should stop even if the selected
  entry returns NULL due to a malloc failure or end-of-choices.
- if summary == NULL, do not try to print it as %s but produce a
  <no description available> message.


Modified:
    team/rizzo/astobj2/include/asterisk/cli.h
    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=47532&r1=47531&r2=47532
==============================================================================
--- team/rizzo/astobj2/include/asterisk/cli.h (original)
+++ team/rizzo/astobj2/include/asterisk/cli.h Mon Nov 13 04:27:04 2006
@@ -44,7 +44,24 @@
 
 #define AST_CLI_COMPLETE_EOF	"_EOF_"
 
-/*! \brief A command line entry */
+/*!
+ * 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
+ * (for this case, the last argument is cast to struct ast_cli_args
+ * because we need more arguments to it).
+ * As a trick to extend the interface without too much trouble,
+ * argv[-1] points to a struct ast_cli_args.
+ * The return string is obtained by casting the result to char *
+ */
+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 */
+};
+
 struct ast_cli_entry {
 	char * const cmda[AST_MAX_CMD_LEN];
 	/*! Handler for the command (fd for output, # of args, argument list).
@@ -78,10 +95,22 @@
 	  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 deprecated;
 	char *_deprecated_by;	/* copied from the "parent" _full_cmd, on deprecated commands */
 	/*! For linking */
 	AST_LIST_ENTRY(ast_cli_entry) list;
+};
+
+/* argument for new-style CLI handler */
+struct ast_cli_args {
+/*! \brief A command line entry */
+	struct ast_cli_entry *e;	/* pointer to the entry in use */
+	const char *line;	/* the current input line */
+	const char *word;	/* the word we want to complete */
+	int pos;		/* position of the word to complete */
+	int n;			/* the iteration count (n-th entry we generate) */
 };
 
 /*!

Modified: team/rizzo/astobj2/main/cli.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/cli.c?view=diff&rev=47532&r1=47531&r2=47532
==============================================================================
--- team/rizzo/astobj2/main/cli.c (original)
+++ team/rizzo/astobj2/main/cli.c Mon Nov 13 04:27:04 2006
@@ -1166,6 +1166,14 @@
 		AST_LIST_LOCK(&helpers);
 		AST_LIST_REMOVE(&helpers, e, list);
 		AST_LIST_UNLOCK(&helpers);
+		free(e->_full_cmd);
+		e->_full_cmd = NULL;
+		if (e->new_style_buf) {
+			((char **)e->cmda)[0] = NULL;
+			free(e->new_style_buf);
+			e->new_style_buf = NULL;
+			e->usage = NULL;
+		}
 	}
 	return 0;
 }
@@ -1174,8 +1182,30 @@
 {
 	struct ast_cli_entry *cur;
 	char fulle[80] ="";
-	int lf, ret = -1;
-	
+	int i, lf, ret = -1;
+
+	if (e->cmda[0] == NULL) {	/* new style entry, run the handler to init fields */
+		char *s = (char *)(e->handler(-1, CLI_CMD_STRING, NULL));
+		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);
+		for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
+			*dst++ = s;	/* store string */
+			s = ast_skip_nonblanks(s);
+			if (*s == '\0')	/* we are done */
+				break;
+			*s++ = '\0';
+			s = ast_skip_blanks(s);
+		}
+		*dst++ = NULL;
+		e->usage = (char *)(e->handler(-1, CLI_USAGE, NULL));
+		ast_verbose("running new-style CLI entry for %s\n", e->new_style_buf);
+		sleep(1);
+	}
+	for (i = 0; e->cmda[i]; i++)
+		;
+	e->args = i;
 	ast_join(fulle, sizeof(fulle), e->cmda);
 	AST_LIST_LOCK(&helpers);
 	
@@ -1289,7 +1319,7 @@
 			continue;
 		if (match && strncasecmp(matchstr, e->_full_cmd, len))
 			continue;
-		ast_cli(fd, "%25.25s  %s\n", e->_full_cmd, e->summary);
+		ast_cli(fd, "%25.25s  %s\n", e->_full_cmd, S_OR(e->summary, "<no description available>"));
 		found++;
 	}
 	AST_LIST_UNLOCK(&helpers);
@@ -1479,17 +1509,23 @@
 	}
 	if (lock)
 		AST_LIST_LOCK(&helpers);
-	while( !ret && (e = cli_next(&i)) ) {
+	while ( (e = cli_next(&i)) ) {
 		int lc = strlen(e->_full_cmd);
 		if (e->_full_cmd[0] != '_' && lc > 0 && matchlen <= lc &&
 				!strncasecmp(matchstr, e->_full_cmd, matchlen)) {
 			/* Found initial part, return a copy of the next word... */
-			if (e->cmda[argindex] && ++matchnum > state)
+			if (e->cmda[argindex] && ++matchnum > state) {
 				ret = strdup(e->cmda[argindex]); /* we need a malloced string */
-		} else if (e->generator && !strncasecmp(matchstr, e->_full_cmd, lc) && matchstr[lc] < 33) {
-			/* We have a command in its entirity within us -- theoretically only one
-			   command can have this occur */
-			ret = e->generator(matchstr, word, argindex, state);
+				break;
+			}
+		} else if (!strncasecmp(matchstr, e->_full_cmd, lc) && matchstr[lc] < 33) {
+			/* This entry is a prefix of the command string entered
+			 * (only one entry in the list should have this property).
+			 * Run the generator if one is available. In any case we are done.
+			 */
+			if (e->generator)
+				ret = e->generator(matchstr, word, argindex, state);
+			break;
 		}
 	}
 	if (lock)
@@ -1505,24 +1541,28 @@
 
 int ast_cli_command(int fd, const char *s)
 {
-	char *argv[AST_MAX_ARGS];
+	char *args[AST_MAX_ARGS + 1];
 	struct ast_cli_entry *e;
 	int x;
 	char *dup;
 	int tws;
 	
-	if (!(dup = parse_args(s, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws)))
+	if (!(dup = parse_args(s, &x, args + 1, AST_MAX_ARGS, &tws)))
 		return -1;
 
 	/* We need at least one entry, or ignore */
 	if (x > 0) {
 		AST_LIST_LOCK(&helpers);
-		e = find_cli(argv, 0);
+		e = find_cli(args + 1, 0);
 		if (e)
 			e->inuse++;
 		AST_LIST_UNLOCK(&helpers);
 		if (e) {
-			switch(e->handler(fd, x, argv)) {
+			/* within calling the handler, argv[-1] contains a pointer
+			 * to the cli entry, and the array is null-terminated
+			 */
+			args[0] = (char *)e;
+			switch(e->handler(fd, x, args + 1)) {
 			case RESULT_SHOWUSAGE:
 				if (e->usage)
 					ast_cli(fd, "%s", e->usage);
@@ -1539,7 +1579,7 @@
 				break;
 			}
 		} else 
-			ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv));
+			ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(args + 1));
 		if (e)
 			ast_atomic_fetchadd_int(&e->inuse, -1);
 	}



More information about the asterisk-commits mailing list