Newer
Older
there. */
if (!builtins[x].cmda[y] && !exact)
break;
/* If there are no more words in the command (and we're looking for
an exact match) or there is a difference between the two words,
then this is not a match */
if (!builtins[x].cmda[y] || strcasecmp(builtins[x].cmda[y], cmds[y]))
match = 0;
}
/* If more words are needed to complete the command then this is not
a candidate (unless we're looking for a really inexact answer */
if ((exact > -1) && builtins[x].cmda[y])
match = 0;
if (match)
return &builtins[x];
}
static void join(char *dest, size_t destsize, char *w[], int tws)
Russell Bryant
committed
ast_join(dest, destsize, w);
if (tws && !ast_strlen_zero(dest))
strncat(dest, " ", destsize - strlen(dest) - 1);
static void join2(char *dest, size_t destsize, char *w[])
{
int x;
/* Join words into a string */
if (!dest || destsize < 1) {
return;
}
dest[0] = '\0';
strncat(dest, w[x], destsize - strlen(dest) - 1);
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);
int ast_cli_unregister(struct ast_cli_entry *e)
{
struct ast_cli_entry *cur, *l=NULL;
ast_mutex_lock(&clilock);
cur = helpers;
while(cur) {
if (e == cur) {
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;
}
ast_mutex_unlock(&clilock);
int ast_cli_register(struct ast_cli_entry *e)
{
struct ast_cli_entry *cur, *l=NULL;
ast_mutex_lock(&clilock);
ast_mutex_unlock(&clilock);
ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle);
for (cur = helpers; cur; cur = cur->next) {
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;
}
if (!cur) {
if (l)
l->next = e;
else
helpers = e;
e->next = NULL;
}
ast_mutex_unlock(&clilock);
Kevin P. Fleming
committed
/*
* register/unregister an array of entries.
*/
void ast_cli_register_multiple(struct ast_cli_entry *e, int len)
{
int i;
for (i = 0; i < len; i++)
Kevin P. Fleming
committed
ast_cli_register(e + i);
}
void ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
{
int i;
for (i = 0; i < len; i++)
Kevin P. Fleming
committed
ast_cli_unregister(e + i);
}
static int help_workhorse(int fd, char *match[])
{
char fullcmd1[80] = "";
char fullcmd2[80] = "";
struct ast_cli_entry *e, *e1, *e2;
e1 = builtins;
e2 = helpers;
if (match)
join(matchstr, sizeof(matchstr), match, 0);
join(fullcmd2, sizeof(fullcmd2), e2->cmda, 0);
join(fullcmd1, sizeof(fullcmd1), e1->cmda, 0);
(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++;
}
/* Hide commands that start with '_' */
if (fullcmd[0] == '_')
continue;
if (match) {
if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
continue;
}
}
ast_cli(fd, "%25.25s %s\n", fullcmd, e->summary);
}
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);
if (e) {
if (e->usage)
else {
join(fullcmd, sizeof(fullcmd), argv+1, 0);
ast_cli(fd, "No help text available for '%s'.\n", fullcmd);
}
} else {
if (find_cli(argv + 1, -1)) {
return help_workhorse(fd, argv + 1);
} else {
join(fullcmd, sizeof(fullcmd), argv+1, 0);
ast_cli(fd, "No such command '%s'.\n", fullcmd);
}
}
} else {
return help_workhorse(fd, NULL);
}
return RESULT_SUCCESS;
}
static char *parse_args(char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
int x = 0;
int quoted = 0;
int escaped = 0;
int whitespace = 1;
if (!(dup = strdup(s)))
return NULL;
cur = dup;
while (!ast_strlen_zero(s)) {
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;
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
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;
argv[x++] = cur;
whitespace = 0;
*(cur++) = *s;
escaped = 0;
/* Null terminate */
*(cur++) = '\0';
argv[x] = NULL;
*argc = x;
/* This returns the number of unique matches for the generator */
int ast_cli_generatornummatches(char *text, char *word)
{
int matches = 0, i = 0;
while ((buf = ast_cli_generator(text, word, i++))) {
if (!oldbuf || strcmp(buf,oldbuf))
matches++;
if (oldbuf)
free(oldbuf);
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
return matches;
}
char **ast_cli_completion_matches(char *text, char *word)
{
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++)
continue;
max_equal = i;
}
retstr = malloc(max_equal + 1);
strncpy(retstr, match_list[1], max_equal);
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;
return match_list;
static char *__ast_cli_generator(char *text, char *word, int state, int lock)
{
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] = "";
if ((dup = parse_args(text, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
join(matchstr, sizeof(matchstr), argv, tws);
ast_mutex_lock(&clilock);
e1 = builtins;
e2 = helpers;
while(e1->cmda[0] || e2) {
if (e2)
join(fullcmd2, sizeof(fullcmd2), e2->cmda, tws);
join(fullcmd1, sizeof(fullcmd1), e1->cmda, tws);
(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))) {
/* 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) {
ast_mutex_unlock(&clilock);
Mark Spencer
committed
if (e->generator && !strncasecmp(matchstr, fullcmd, strlen(fullcmd)) &&
(matchstr[strlen(fullcmd)] < 33)) {
/* 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;
}
ast_mutex_unlock(&clilock);
char *ast_cli_generator(char *text, char *word, int state)
{
return __ast_cli_generator(text, word, state, 1);
}
int ast_cli_command(int fd, char *s)
{
char *argv[AST_MAX_ARGS];
struct ast_cli_entry *e;
int x;
char *dup;
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
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) {
ast_mutex_lock(&clilock);
e->inuse--;
ast_mutex_unlock(&clilock);
free(dup);