version 1.148, 2019/05/10 18:04:06 |
version 1.149, 2019/05/23 11:13:30 |
|
|
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]); |
log_debug("%s: argv[%d]=%s", prefix, i, argv[i]); |
} |
} |
|
|
|
void |
|
cmd_prepend_argv(int *argc, char ***argv, char *arg) |
|
{ |
|
char **new_argv; |
|
int i; |
|
|
|
new_argv = xreallocarray(NULL, (*argc) + 1, sizeof *new_argv); |
|
new_argv[0] = xstrdup(arg); |
|
for (i = 0; i < *argc; i++) |
|
new_argv[1 + i] = (*argv)[i]; |
|
|
|
free(*argv); |
|
*argv = new_argv; |
|
(*argc)++; |
|
} |
|
|
|
void |
|
cmd_append_argv(int *argc, char ***argv, char *arg) |
|
{ |
|
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv); |
|
(*argv)[(*argc)++] = xstrdup(arg); |
|
} |
|
|
int |
int |
cmd_pack_argv(int argc, char **argv, char *buf, size_t len) |
cmd_pack_argv(int argc, char **argv, char *buf, size_t len) |
{ |
{ |
|
|
return (buf); |
return (buf); |
} |
} |
|
|
static int |
char * |
cmd_try_alias(int *argc, char ***argv) |
cmd_get_alias(const char *name) |
{ |
{ |
struct options_entry *o; |
struct options_entry *o; |
struct options_array_item *a; |
struct options_array_item *a; |
union options_value *ov; |
union options_value *ov; |
int old_argc = *argc, new_argc, i; |
size_t wanted, n; |
char **old_argv = *argv, **new_argv; |
const char *equals; |
size_t wanted; |
|
const char *cp = NULL; |
|
|
|
o = options_get_only(global_options, "command-alias"); |
o = options_get_only(global_options, "command-alias"); |
if (o == NULL) |
if (o == NULL) |
return (-1); |
return (NULL); |
wanted = strlen(old_argv[0]); |
wanted = strlen(name); |
|
|
a = options_array_first(o); |
a = options_array_first(o); |
while (a != NULL) { |
while (a != NULL) { |
ov = options_array_item_value(a); |
ov = options_array_item_value(a); |
cp = strchr(ov->string, '='); |
|
if (cp != NULL && |
equals = strchr(ov->string, '='); |
(size_t)(cp - ov->string) == wanted && |
if (equals != NULL) { |
strncmp(old_argv[0], ov->string, wanted) == 0) |
n = equals - ov->string; |
break; |
if (n == wanted && strncmp(name, ov->string, n) == 0) |
|
return (xstrdup(equals + 1)); |
|
} |
|
|
a = options_array_next(a); |
a = options_array_next(a); |
} |
} |
if (a == NULL) |
return (NULL); |
return (-1); |
} |
|
|
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0) |
static const struct cmd_entry * |
return (-1); |
cmd_find(const char *name, char **cause) |
|
{ |
|
const struct cmd_entry **loop, *entry, *found = NULL; |
|
int ambiguous; |
|
char s[BUFSIZ]; |
|
|
*argc = new_argc + old_argc - 1; |
ambiguous = 0; |
*argv = xcalloc((*argc) + 1, sizeof **argv); |
for (loop = cmd_table; *loop != NULL; loop++) { |
|
entry = *loop; |
|
if (entry->alias != NULL && strcmp(entry->alias, name) == 0) { |
|
ambiguous = 0; |
|
found = entry; |
|
break; |
|
} |
|
|
for (i = 0; i < new_argc; i++) |
if (strncmp(entry->name, name, strlen(name)) != 0) |
(*argv)[i] = xstrdup(new_argv[i]); |
continue; |
for (i = 1; i < old_argc; i++) |
if (found != NULL) |
(*argv)[new_argc + i - 1] = xstrdup(old_argv[i]); |
ambiguous = 1; |
|
found = entry; |
|
|
log_debug("alias: %s=%s", old_argv[0], cp + 1); |
if (strcmp(entry->name, name) == 0) |
for (i = 0; i < *argc; i++) |
break; |
log_debug("alias: argv[%d] = %s", i, (*argv)[i]); |
} |
|
if (ambiguous) |
|
goto ambiguous; |
|
if (found == NULL) { |
|
xasprintf(cause, "unknown command: %s", name); |
|
return (NULL); |
|
} |
|
return (found); |
|
|
cmd_free_argv(new_argc, new_argv); |
ambiguous: |
return (0); |
*s = '\0'; |
|
for (loop = cmd_table; *loop != NULL; loop++) { |
|
entry = *loop; |
|
if (strncmp(entry->name, name, strlen(name)) != 0) |
|
continue; |
|
if (strlcat(s, entry->name, sizeof s) >= sizeof s) |
|
break; |
|
if (strlcat(s, ", ", sizeof s) >= sizeof s) |
|
break; |
|
} |
|
s[strlen(s) - 2] = '\0'; |
|
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s); |
|
return (NULL); |
} |
} |
|
|
struct cmd * |
struct cmd * |
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) |
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) |
{ |
{ |
|
const struct cmd_entry *entry; |
const char *name; |
const char *name; |
const struct cmd_entry **entryp, *entry; |
|
struct cmd *cmd; |
struct cmd *cmd; |
struct args *args; |
struct args *args; |
char s[BUFSIZ]; |
|
int ambiguous, allocated = 0; |
|
|
|
*cause = NULL; |
|
if (argc == 0) { |
if (argc == 0) { |
xasprintf(cause, "no command"); |
xasprintf(cause, "no command"); |
return (NULL); |
return (NULL); |
} |
} |
name = argv[0]; |
name = argv[0]; |
|
|
retry: |
entry = cmd_find(name, cause); |
ambiguous = 0; |
if (entry == NULL) |
entry = NULL; |
|
for (entryp = cmd_table; *entryp != NULL; entryp++) { |
|
if ((*entryp)->alias != NULL && |
|
strcmp((*entryp)->alias, argv[0]) == 0) { |
|
ambiguous = 0; |
|
entry = *entryp; |
|
break; |
|
} |
|
|
|
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) |
|
continue; |
|
if (entry != NULL) |
|
ambiguous = 1; |
|
entry = *entryp; |
|
|
|
/* Bail now if an exact match. */ |
|
if (strcmp(entry->name, argv[0]) == 0) |
|
break; |
|
} |
|
if ((ambiguous || entry == NULL) && |
|
server_proc != NULL && |
|
!allocated && |
|
cmd_try_alias(&argc, &argv) == 0) { |
|
allocated = 1; |
|
goto retry; |
|
} |
|
if (ambiguous) |
|
goto ambiguous; |
|
if (entry == NULL) { |
|
xasprintf(cause, "unknown command: %s", name); |
|
return (NULL); |
return (NULL); |
} |
|
cmd_log_argv(argc, argv, entry->name); |
cmd_log_argv(argc, argv, entry->name); |
|
|
args = args_parse(entry->args.template, argc, argv); |
args = args_parse(entry->args.template, argc, argv); |
|
|
cmd->file = xstrdup(file); |
cmd->file = xstrdup(file); |
cmd->line = line; |
cmd->line = line; |
|
|
if (allocated) |
cmd->alias = NULL; |
cmd_free_argv(argc, argv); |
cmd->argc = argc; |
|
cmd->argv = cmd_copy_argv(argc, argv); |
|
|
return (cmd); |
return (cmd); |
|
|
ambiguous: |
|
*s = '\0'; |
|
for (entryp = cmd_table; *entryp != NULL; entryp++) { |
|
if (strncmp((*entryp)->name, argv[0], strlen(argv[0])) != 0) |
|
continue; |
|
if (strlcat(s, (*entryp)->name, sizeof s) >= sizeof s) |
|
break; |
|
if (strlcat(s, ", ", sizeof s) >= sizeof s) |
|
break; |
|
} |
|
s[strlen(s) - 2] = '\0'; |
|
xasprintf(cause, "ambiguous command: %s, could be: %s", name, s); |
|
return (NULL); |
|
|
|
usage: |
usage: |
if (args != NULL) |
if (args != NULL) |
args_free(args); |
args_free(args); |
xasprintf(cause, "usage: %s %s", entry->name, entry->usage); |
xasprintf(cause, "usage: %s %s", entry->name, entry->usage); |
return (NULL); |
return (NULL); |
|
} |
|
|
|
void |
|
cmd_free(struct cmd *cmd) |
|
{ |
|
free(cmd->alias); |
|
cmd_free_argv(cmd->argc, cmd->argv); |
|
|
|
free(cmd->file); |
|
|
|
args_free(cmd->args); |
|
free(cmd); |
} |
} |
|
|
char * |
char * |