Skip to content
Snippets Groups Projects
cli.c 39.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    	/* Join words into a string */
    
    	if (!dest || destsize < 1) {
    		return;
    	}
    	dest[0] = '\0';
    
    Mark Spencer's avatar
    Mark Spencer committed
    	for (x=0;w[x];x++) {
    
    		strncat(dest, w[x], destsize - strlen(dest) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char *find_best(char *argv[])
    {
    	static char cmdline[80];
    	int x;
    	/* See how close we get, then print the  */
    	char *myargv[AST_MAX_CMD_LEN];
    	for (x=0;x<AST_MAX_CMD_LEN;x++)
    		myargv[x]=NULL;
    	for (x=0;argv[x];x++) {
    		myargv[x] = argv[x];
    		if (!find_cli(myargv, -1))
    			break;
    	}
    
    	join(cmdline, sizeof(cmdline), myargv, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return cmdline;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_cli_unregister(struct ast_cli_entry *e)
    {
    	struct ast_cli_entry *cur, *l=NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	cur = helpers;
    	while(cur) {
    		if (e == cur) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (e->inuse) {
    				ast_log(LOG_WARNING, "Can't remove command that is in use\n");
    			} else {
    				/* Rewrite */
    				if (l)
    					l->next = e->next;
    				else
    					helpers = e->next;
    				e->next = NULL;
    				break;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		l = cur;
    		cur = cur->next;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_cli_register(struct ast_cli_entry *e)
    {
    	struct ast_cli_entry *cur, *l=NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char fulle[80] ="", fulltst[80] ="";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	static int len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	join2(fulle, sizeof(fulle), e->cmda);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (find_cli(e->cmda, -1)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    	
    	for (cur = helpers; cur; cur = cur->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		join2(fulltst, sizeof(fulltst), cur->cmda);
    		len = strlen(fulltst);
    		if (strlen(fulle) < len)
    			len = strlen(fulle);
    		if (strncasecmp(fulle, fulltst, len) < 0) {
    			if (l) {
    				e->next = l->next;
    				l->next = e;
    			} else {
    				e->next = helpers;
    				helpers = e;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    		}
    		l = cur;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!cur) {
    		if (l)
    			l->next = e;
    		else
    			helpers = e;
    		e->next = NULL;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    /*
     * register/unregister an array of entries.
     */
    void ast_cli_register_multiple(struct ast_cli_entry *e, int len)
    {
    	int i;
    
    
    		ast_cli_register(e + i);
    }
    
    void ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
    {
    	int i;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int help_workhorse(int fd, char *match[])
    {
    
    	char fullcmd1[80] = "";
    	char fullcmd2[80] = "";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char matchstr[80];
    
    	char *fullcmd = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_cli_entry *e, *e1, *e2;
    	e1 = builtins;
    	e2 = helpers;
    	if (match)
    
    		join(matchstr, sizeof(matchstr), match, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	while(e1->cmda[0] || e2) {
    		if (e2)
    
    			join(fullcmd2, sizeof(fullcmd2), e2->cmda, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (e1->cmda[0])
    
    			join(fullcmd1, sizeof(fullcmd1), e1->cmda, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!e1->cmda[0] || 
    
    Mark Spencer's avatar
    Mark Spencer committed
    				(e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
    			/* Use e2 */
    			e = e2;
    			fullcmd = fullcmd2;
    			/* Increment by going to next */
    			e2 = e2->next;
    		} else {
    			/* Use e1 */
    			e = e1;
    			fullcmd = fullcmd1;
    			e1++;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Hide commands that start with '_' */
    		if (fullcmd[0] == '_')
    			continue;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (match) {
    			if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
    				continue;
    			}
    		}
    
    		ast_cli(fd, "%25.25s  %s\n", fullcmd, e->summary);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	return 0;
    }
    
    static int handle_help(int fd, int argc, char *argv[]) {
    	struct ast_cli_entry *e;
    	char fullcmd[80];
    	if ((argc < 1))
    		return RESULT_SHOWUSAGE;
    	if (argc > 1) {
    		e = find_cli(argv + 1, 1);
    
    				ast_cli(fd, "%s", e->usage);
    
    				join(fullcmd, sizeof(fullcmd), argv+1, 0);
    
    				ast_cli(fd, "No help text available for '%s'.\n", fullcmd);
    			}
    		} else {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (find_cli(argv + 1, -1)) {
    				return help_workhorse(fd, argv + 1);
    			} else {
    
    				join(fullcmd, sizeof(fullcmd), argv+1, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				ast_cli(fd, "No such command '%s'.\n", fullcmd);
    			}
    		}
    	} else {
    		return help_workhorse(fd, NULL);
    	}
    	return RESULT_SUCCESS;
    }
    
    
    static char *parse_args(const char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char *dup, *cur;
    
    	int x = 0;
    	int quoted = 0;
    	int escaped = 0;
    	int whitespace = 1;
    
    
    	*trailingwhitespace = 0;
    
    	if (!(dup = strdup(s)))
    		return NULL;
    
    	cur = dup;
    
    		if ((*s == '"') && !escaped) {
    			quoted = !quoted;
    			if (quoted & whitespace) {
    				/* If we're starting a quoted string, coming off white space, start a new argument */
    				if (x >= (max - 1)) {
    					ast_log(LOG_WARNING, "Too many arguments, truncating\n");
    					break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    				argv[x++] = cur;
    				whitespace = 0;
    			}
    			escaped = 0;
    		} else if (((*s == ' ') || (*s == '\t')) && !(quoted || escaped)) {
    			/* If we are not already in whitespace, and not in a quoted string or
    			   processing an escape sequence, and just entered whitespace, then
    			   finalize the previous argument and remember that we are in whitespace
    			*/
    			if (!whitespace) {
    				*(cur++) = '\0';
    				whitespace = 1;
    			}
    		} else if ((*s == '\\') && !escaped) {
    			escaped = 1;
    		} else {
    			if (whitespace) {
    				/* If we are coming out of whitespace, start a new argument */
    				if (x >= (max - 1)) {
    					ast_log(LOG_WARNING, "Too many arguments, truncating\n");
    					break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    				argv[x++] = cur;
    				whitespace = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    			*(cur++) = *s;
    			escaped = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* Null terminate */
    	*(cur++) = '\0';
    	argv[x] = NULL;
    	*argc = x;
    
    	*trailingwhitespace = whitespace;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return dup;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* This returns the number of unique matches for the generator */
    
    int ast_cli_generatornummatches(const char *text, const char *word)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int matches = 0, i = 0;
    
    	char *buf = NULL, *oldbuf = NULL;
    
    	while ((buf = ast_cli_generator(text, word, i++))) {
    
    		if (!oldbuf || strcmp(buf,oldbuf))
    			matches++;
    		if (oldbuf)
    			free(oldbuf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		oldbuf = buf;
    	}
    
    	if (oldbuf)
    		free(oldbuf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return matches;
    }
    
    
    char **ast_cli_completion_matches(const char *text, const char *word)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char **match_list = NULL, *retstr, *prevstr;
    	size_t match_list_len, max_equal, which, i;
    	int matches = 0;
    
    	match_list_len = 1;
    	while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
    		if (matches + 1 >= match_list_len) {
    			match_list_len <<= 1;
    			match_list = realloc(match_list, match_list_len * sizeof(char *));
    		}
    		match_list[++matches] = retstr;
    	}
    
    	if (!match_list)
    		return (char **) NULL;
    
    	which = 2;
    	prevstr = match_list[1];
    	max_equal = strlen(prevstr);
    	for (; which <= matches; which++) {
    
    		for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
    
    Mark Spencer's avatar
    Mark Spencer committed
    			continue;
    		max_equal = i;
    	}
    
    	retstr = malloc(max_equal + 1);
    
    	strncpy(retstr, match_list[1], max_equal);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	retstr[max_equal] = '\0';
    	match_list[0] = retstr;
    
    	if (matches + 1 >= match_list_len)
    		match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
    	match_list[matches + 1] = (char *) NULL;
    
    
    static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char *argv[AST_MAX_ARGS];
    	struct ast_cli_entry *e, *e1, *e2;
    	int x;
    	int matchnum=0;
    	char *dup, *res;
    
    	char fullcmd1[80] = "";
    	char fullcmd2[80] = "";
    
    	char matchstr[80] = "";
    
    	char *fullcmd = NULL;
    
    	if ((dup = parse_args(text, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
    		join(matchstr, sizeof(matchstr), argv, tws);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lock)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		e1 = builtins;
    		e2 = helpers;
    		while(e1->cmda[0] || e2) {
    			if (e2)
    
    				join(fullcmd2, sizeof(fullcmd2), e2->cmda, tws);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (e1->cmda[0])
    
    				join(fullcmd1, sizeof(fullcmd1), e1->cmda, tws);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (!e1->cmda[0] || 
    
    Mark Spencer's avatar
    Mark Spencer committed
    					(e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
    				/* Use e2 */
    				e = e2;
    				fullcmd = fullcmd2;
    				/* Increment by going to next */
    				e2 = e2->next;
    			} else {
    				/* Use e1 */
    				e = e1;
    				fullcmd = fullcmd1;
    				e1++;
    			}
    
    			if ((fullcmd[0] != '_') && !strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* We contain the first part of one or more commands */
    
    				/* Now, what we're supposed to return is the next word... */
    				if (!ast_strlen_zero(word) && x>0) {
    					res = e->cmda[x-1];
    				} else {
    					res = e->cmda[x];
    				}
    				if (res) {
    					matchnum++;
    					if (matchnum > state) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						if (lock)
    
    						return strdup(res);
    
    			if (e->generator && !strncasecmp(matchstr, fullcmd, strlen(fullcmd)) &&
    				(matchstr[strlen(fullcmd)] < 33)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* We have a command in its entirity within us -- theoretically only one
    				   command can have this occur */
    
    				fullcmd = e->generator(matchstr, word, (!ast_strlen_zero(word) ? (x - 1) : (x)), state);
    
    				if (fullcmd) {
    					if (lock)
    						ast_mutex_unlock(&clilock);
    					free(dup);
    					return fullcmd;
    				}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lock)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		free(dup);
    	}
    	return NULL;
    }
    
    
    char *ast_cli_generator(const char *text, const char *word, int state)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return __ast_cli_generator(text, word, state, 1);
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char *argv[AST_MAX_ARGS];
    	struct ast_cli_entry *e;
    	int x;
    	char *dup;
    
    	dup = parse_args(s, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws);
    	if (!dup) {
    		ast_log(LOG_ERROR, "Out of Memory!\n");
    		return -1;
    	}
    
    	/* We need at least one entry, or ignore */
    	if (x > 0) {
    		ast_mutex_lock(&clilock);
    		e = find_cli(argv, 0);
    		if (e)
    			e->inuse++;
    		ast_mutex_unlock(&clilock);
    		if (e) {
    			switch(e->handler(fd, x, argv)) {
    			case RESULT_SHOWUSAGE:
    				ast_cli(fd, "%s", e->usage);
    				break;
    			}
    		} else 
    			ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv));
    		if (e) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }