typedef struct fr_cmd_t fr_cmd_t;
-typedef int (*fr_cmd_func_t)(FILE *fp, void *ctx, int argc, char const *argv[]);
+typedef int (*fr_cmd_func_t)(FILE *fp, void *ctx, int argc, char *argv[]);
-typedef struct fr_cmd_tab_info_t {
- int argc;
- char const **argv; //!< last argument is to be expanded
-} fr_cmd_tab_info_t;
+typedef struct fr_cmd_info_t {
+ int argc; //!< current argument count
+ int max_argc; //!< maximum number of arguments
+ bool runnable; //!< is the command runnable?
+ char **argv; //!< text version of commands
+ fr_value_box_t **box; //!< value_box version of commands.
+} fr_cmd_info_t;
-typedef int (*fr_cmd_tab_t)(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_tab_info_t *info, int max_expansions, char const **expansions);
+typedef int (*fr_cmd_tab_t)(TALLOC_CTX *talloc_ctx, void *ctx, fr_cmd_info_t *info, int max_expansions, char const **expansions);
typedef struct fr_cmd_table_t {
char const **parents; //!< e.g. "show module"
int fr_command_add(TALLOC_CTX *talloc_ctx, fr_cmd_t **head_p, char const *name, void *ctx, fr_cmd_table_t const *table);
int fr_command_add_multi(TALLOC_CTX *talloc_ctx, fr_cmd_t **heap_p, char const *name, void *ctx, fr_cmd_table_t const *table);
int fr_command_walk(fr_cmd_t *head, void **walk_ctx, void *ctx, fr_cmd_walk_t callback);
-int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, int argc, char const *argv[], int max_expansions, char const **expansions);
-char const *fr_command_help(fr_cmd_t *head, int argc, char const *argv[]);
-int fr_command_run(FILE *fp, fr_cmd_t *head, int argc, char const *argv[]);
+int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, fr_cmd_info_t *info, int max_expansions, char const **expansions);
+char const *fr_command_help(fr_cmd_t *head, int argc, char *argv[]);
+int fr_command_run(FILE *fp, fr_cmd_t *head, fr_cmd_info_t *info);
void fr_command_debug(FILE *fp, fr_cmd_t *head);
-int fr_command_str_to_argv(UNUSED fr_cmd_t *head, int argc, char *argv[], int max_argc, char *str, bool *runnable);
+int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char *str);
#ifdef __cplusplus
}
* get a data type instead, do the callback to ask the caller to
* expand it.
*/
-static int fr_command_tab_expand_syntax(TALLOC_CTX *ctx, fr_cmd_t *cmd, int argc, char const *argv[], int max_expansions, char const **expansions)
+static int fr_command_tab_expand_syntax(TALLOC_CTX *ctx, fr_cmd_t *cmd, fr_cmd_info_t *info, int max_expansions, char const **expansions)
{
int i;
*
* @todo - allow for varargs
*/
- if (argc > cmd->syntax_argc) return 0;
- rad_assert(argc > 0);
+ if (info->argc > cmd->syntax_argc) return 0;
+ rad_assert(info->argc > 0);
- for (i = 0; i < argc; i++) {
+ for (i = 0; i < info->argc; i++) {
char const *p, *q;
/*
* MAY be expanded.
*/
if (cmd->syntax_types[i] != FR_TYPE_INVALID) {
- fr_cmd_tab_info_t info;
-
- if (i < (argc - 1)) {
+ if (i < (info->argc - 1)) {
continue;
}
return 1;
}
- /*
- * Set up the callback structure and ask
- * the callback to fill out the
- * expansions. Note that we pass the
- * callback the FULL argv. The callback
- * should verify
- */
- info.argc = argc;
- info.argv = argv;
-
- return cmd->tab_expand(ctx, cmd->ctx, &info, max_expansions, expansions);
+ return cmd->tab_expand(ctx, cmd->ctx, info, max_expansions, expansions);
}
/*
* Match intermediate commands exactly.
*/
- if (strcmp(cmd->syntax_argv[i], argv[i]) == 0) continue;
+ if (strcmp(cmd->syntax_argv[i], info->argv[i]) == 0) continue;
/*
* We're not yet at the end of the input syntax,
* but we don't have a match. There's clearly no
* more tab expansions to have.
*/
- if (i < (argc - 1)) return 0;
+ if (i < (info->argc - 1)) return 0;
/*
* Not a full match, but we're at the last
* which means creating a tree of allowed
* syntaxes. <sigh>
*/
- for (p = argv[i], q = cmd->syntax_argv[i];
+ for (p = info->argv[i], q = cmd->syntax_argv[i];
(*p != '\0') && (*q != '\0');
p++, q++) {
/*
* @param ctx talloc context for dynamically allocated expansions. The caller should free it to free all expansions it created.
* Expansions added by this function are "const char *", and are managed by the command hierarchy.
* @param head the head of the hierarchy.
- * @param argc the number of arguments in the argv array
- * @param argv the commands leading up to this one.
+ * @param info the structure describing the command to expand
* @param max_expansions the maximum number of entries in the expansions array
* @param expansions where the expansions will be stored.
* @return
* - <0 on error
* - number of entries in the expansions array
*/
-int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, int argc, char const *argv[], int max_expansions, char const **expansions)
+int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, fr_cmd_info_t *info, int max_expansions, char const **expansions)
{
int i;
fr_cmd_t *cmd, *start;
* Walk down the children until we find the correct
* location.
*/
- for (i = 0; i < argc; i++) {
- cmd = fr_command_find(&start, argv[i], NULL);
+ for (i = 0; i < info->argc; i++) {
+ cmd = fr_command_find(&start, info->argv[i], NULL);
/*
* The command wasn't found in the list. Walk
* any partial matches.
*/
if (!cmd) {
- return fr_command_tab_expand_partial(start, argv[i], max_expansions, expansions);
+ return fr_command_tab_expand_partial(start, info->argv[i], max_expansions, expansions);
}
start = cmd;
i++;
rad_assert(cmd->child == NULL);
- return fr_command_tab_expand_syntax(ctx, cmd, argc - i, &argv[i], max_expansions, expansions);
+ return fr_command_tab_expand_syntax(ctx, cmd, info, max_expansions, expansions);
}
rad_assert(cmd->child != NULL);
* be child commands under that hierarchy. In which
* case, show them as expansions.
*/
- rad_assert(i == argc);
+ rad_assert(i == info->argc);
rad_assert(cmd->child != NULL);
for (i = 0, cmd = cmd->child; (i < max_expansions) && (cmd != NULL); i++, cmd = cmd->next) {
*
* @param fp where the output is sent
* @param head the head of the command hierarchy.
- * @param argc the number of arguments in the argv array
- * @param argv the commands leading up to this one.
+ * @param info the structure describing the command to expand
* @return
* - <0 on error
* - 0 the command was run successfully
*/
-int fr_command_run(FILE *fp, fr_cmd_t *head, int argc, char const *argv[])
+int fr_command_run(FILE *fp, fr_cmd_t *head, fr_cmd_info_t *info)
{
int i;
fr_cmd_t *cmd, *start;
/*
* Asked to do nothing, do nothing.
*/
- if (argc == 0) return 0;
+ if (info->argc == 0) return 0;
- for (i = 0; i < argc; i++) {
- cmd = fr_command_find(&start, argv[i], NULL);
+ for (i = 0; i < info->argc; i++) {
+ int rcode;
+
+ cmd = fr_command_find(&start, info->argv[i], NULL);
if (!cmd) {
- if (argc == 1) {
- fr_strerror_printf("No such command '%s'", argv[i]);
+ if (info->argc == 1) {
+ fr_strerror_printf("No such command '%s'", info->argv[i]);
} else {
- fr_strerror_printf("No such command '... %s'", argv[i]);
+ fr_strerror_printf("No such command '... %s'", info->argv[i]);
}
return -1;
}
if (!cmd->syntax) {
if (cmd->func) {
- if (argc > (i + 1)) {
+ if (info->argc > (i + 1)) {
fr_strerror_printf("Input has too many parameters for command.");
return -1;
}
- rad_assert(cmd->func != NULL);
- return cmd->func(fp, cmd->ctx, argc - i - 1, &argv[i + 1]);
+
+ goto run;
}
rad_assert(cmd->child != NULL);
* @todo - allow varargs
* @todo - return which argument was broken?
*/
- if (argc != (i + 1 + cmd->syntax_argc)) {
+ if (info->argc != (i + 1 + cmd->syntax_argc)) {
fr_strerror_printf("Input has too many or too few parameters for command");
return -1;
}
* The arguments have already been verified by
* fr_command_str_to_argv().
*/
- return cmd->func(fp, cmd->ctx, argc - i - 1, &argv[i + 1]);
+ run:
+ rcode = cmd->func(fp, cmd->ctx, info->argc - i - 1, &info->argv[i + 1]);
+
+ // @todo - clean up value boxes, too!
+ info->argc = 0;
+ return rcode;
}
return 0;
/** Get help text for a particular command.
*
* @param head the head of the hierarchy.
- * @param argc the number of arguments in the argv array
- * @param argv the commands leading up to this one.
+ * @param argc the number of arguments in argv
+ * @param argv the arguments
* @return
* - NULL on "no help text"
* - !NULL is the help text. Do not free or access it.
*/
-char const *fr_command_help(fr_cmd_t *head, int argc, char const *argv[])
+char const *fr_command_help(fr_cmd_t *head, int argc, char *argv[])
{
int i;
fr_cmd_t *cmd, *start;
* fr_command_run().
*
* @param head the head of the hierarchy.
- * @param input_argc the number of arguments already in the argv array
- * @param argv the commands leading up to this string
- * @param max_argc the maximum number of entries in the argv array
+ * @param info the structure describing the command to expand
* @param str the string to split
- * @param[out] runnable whether or not the command is runnable.
* @return
* - <0 on error.
* - total number of arguments in the argv[] array. Always >= argc.
*/
-int fr_command_str_to_argv(fr_cmd_t *head, int input_argc, char *argv[], int max_argc, char *str, bool *runnable)
+int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char *str)
{
int i, argc, cmd_argc, syntax_argc;
char *p;
fr_cmd_t *cmd, *start;
- if ((input_argc < 0) || (max_argc == 0) || !str) {
+ if ((info->argc < 0) || (info->max_argc <= 0) || !str) {
fr_strerror_printf("Invalid arguments passed to parse routine.");
return -1;
}
}
p = str;
- *runnable = false;
+ info->runnable = false;
/*
* Split the input.
*/
- for (i = input_argc; i < max_argc; i++) {
+ for (i = info->argc; i < info->max_argc; i++) {
int rcode;
- rcode = split(&p, &argv[i]);
+ rcode = split(&p, &info->argv[i]);
if (rcode < 0) return -1;
if (!rcode) break;
}
- if (i == max_argc) {
+ if (i == info->max_argc) {
+ fprintf(stderr, "HERE %d\n", __LINE__);
too_many:
fr_strerror_printf("Too many arguments for command.");
return -1;
/*
* Find the matching command.
-6 */
+ */
for (i = 0; i < argc; i++) {
+ printf("argv[%d] = %s\n", i, info->argv[i]);
/*
* Look for a child command.
*/
- cmd = fr_command_find(&start, argv[i], NULL);
+ cmd = fr_command_find(&start, info->argv[i], NULL);
if (!cmd) {
- fr_strerror_printf("No matching command: %s", argv[i]);
+ fr_strerror_printf("No matching command: %s", info->argv[i]);
return -1;
}
* Walked the entire input without finding a runnable
* command. Ask for more input.
*/
- if (i == argc) return argc;
+ if (i == argc) {
+ info->argc = argc;
+ return argc;
+ }
rad_assert(cmd != NULL);
rad_assert(cmd->func != NULL);
* runnable.
*/
if (!cmd->syntax) {
- if (syntax_argc > 0) goto too_many;
+ if (syntax_argc > 0) {
+ fprintf(stderr, "HERE %d\n", __LINE__);
+ goto too_many;
+ }
- *runnable = true;
+ info->runnable = true;
+ info->argc = argc;
return argc;
}
*
* @todo - allow varargs
*/
- if (syntax_argc > cmd->syntax_argc) goto too_many;
+ if (syntax_argc > cmd->syntax_argc) {
+ fprintf(stderr, "HERE %d - %d > %d\n", __LINE__, syntax_argc, cmd->syntax_argc);
+ goto too_many;
+ }
/*
* If there are enough arguments to pass anything to the
* command, and there are more arguments than we had on
* input, do syntax checks on the new arguments.
*/
- if ((argc > cmd_argc) && (argc > input_argc)) {
+ if ((argc > cmd_argc) && (argc > info->argc)) {
int start_argc;
/*
* skip the arguments we were given on input.
*/
start_argc = cmd_argc + 1;
- if (start_argc < input_argc) start_argc = input_argc;
+ if (start_argc < info->argc) start_argc = info->argc;
for (i = start_argc; i < argc; i++) {
int j;
fr_type_t type;
fr_value_box_t box;
- j = i - start_argc;
+ /*
+ * Offset from the argument after the command.
+ */
+ j = i - (cmd_argc + 1);
/*
* May be written to for things like
quote = '\0';
if (type == FR_TYPE_STRING) {
- if ((argv[i][0] == '"') ||
- (argv[i][0] == '\'')) {
- quote = argv[i][0];
+ if ((info->argv[i][0] == '"') ||
+ (info->argv[i][0] == '\'')) {
+ quote = info->argv[i][0];
}
}
* Parse the data to be sure it's well formed.
*/
if (fr_value_box_from_str(NULL, &box, &type,
- NULL, argv[i], -1, quote, true) < 0) {
+ NULL, info->argv[i], -1, quote, true) < 0) {
fr_strerror_printf("Failed parsing argument %d - %s",
i, fr_strerror());
return -1;
/*
* Too few arguments to run the command.
*/
- if (syntax_argc < cmd->syntax_argc) return argc;
+ if (syntax_argc < cmd->syntax_argc) {
+ info->argc = argc;
+ return argc;
+ }
/*
* It's just right.
*/
- *runnable = true;
+ info->runnable = true;
+ info->argc = argc;
return argc;
}
#define CMD_MAX_ARGV (32)
-static int cmd_help(FILE *fp, UNUSED void *ctx, int argc, char const *argv[]);
+static int cmd_help(FILE *fp, UNUSED void *ctx, int argc, char *argv[]);
static void *fr_radmin(UNUSED void *input_ctx)
{
int argc, context;
- bool runnable;
- char **argv;
- char const **const_argv;
char *argv_buffer;
- char *current_argv;
+ char *current_str;
int *context_exit;
char const *prompt;
size_t size, room;
TALLOC_CTX *ctx;
+ fr_cmd_info_t info;
context = 0;
prompt = "radmin> ";
+ info.max_argc = CMD_MAX_ARGV;
ctx = talloc_init("radmin");
size = room = 8192;
argv_buffer = talloc_array(ctx, char, size);
- current_argv = argv_buffer;
+ current_str = argv_buffer;
- /* -Wincompatible-pointer-types-discards-qualifiers */
- argv = talloc_zero_array(ctx, char *, CMD_MAX_ARGV);
- memcpy(&const_argv, &argv, sizeof(argv));
+ info.max_argc = CMD_MAX_ARGV;
+ info.argv = talloc_zero_array(ctx, char *, CMD_MAX_ARGV);
+ info.box = talloc_zero_array(ctx, fr_value_box_t *, CMD_MAX_ARGV);
context_exit = talloc_zero_array(ctx, int, CMD_MAX_ARGV + 1);
* It's just polite.
*/
if (strcmp(line, "help") == 0) {
- cmd_help(stdout, NULL, context, const_argv);
+ cmd_help(stdout, NULL, context, info.argv);
goto next;
}
if (context == 0) {
prompt = "radmin> ";
} else {
- prompt = talloc_asprintf(ctx, "... %s> ", argv[context - 1]);
+ prompt = talloc_asprintf(ctx, "... %s> ", info.argv[context - 1]);
}
+ info.runnable = false;
goto next;
}
}
* "line" is dynamically allocated and we don't
* want argv[] pointing to it. Also, splitting
* the line mangles it in-place. So we need to
- * copy the line to "current_argv" for splitting.
+ * copy the line to "current_str" for splitting.
* We also copy it to "current_line" for adding
* to the history.
*
* up-arrow, only produces the RELEVANT line from
* the current context.
*/
- strlcpy(current_argv, line, room);
- argc = fr_command_str_to_argv(radmin_cmd, context, argv, CMD_MAX_ARGV, current_argv, &runnable);
+ strlcpy(current_str, line, room);
+ info.argc = context;
+ argc = fr_command_str_to_argv(radmin_cmd, &info, current_str);
/*
* Parse error! Oops..
* It's a partial command. Add it to the context
* and continue.
*
- * Note that we have to update `current_argv`, because
+ * Note that we have to update `current_str`, because
* argv[context] currently points there...
*/
- if (!runnable) {
+ if (!info.runnable) {
size_t len;
rad_assert(argc > 0);
- rad_assert(argv[argc - 1] != NULL);
- len = strlen(argv[argc - 1]) + 1;
+ rad_assert(info.argv[argc - 1] != NULL);
+ len = strlen(info.argv[argc - 1]) + 1;
/*
* Not enough room for more commands, refuse to do it.
* Move the pointer down the buffer and
* keep reading more.
*/
- current_argv = argv[argc - 1] + len + 1;
+ current_str = info.argv[argc - 1] + len + 1;
room -= (len + 1);
if (context > 0) {
*/
context_exit[argc] = context;
context = argc;
- prompt = talloc_asprintf(ctx, "... %s> ", argv[context - 1]);
+ prompt = talloc_asprintf(ctx, "... %s> ", info.argv[context - 1]);
goto next;
}
/*
- * Else it's a runnable command. Add it to the
+ * Else it's a info.runnable command. Add it to the
* history
*/
add_history(line);
- if (fr_command_run(stdout, radmin_cmd, argc, const_argv) < 0) {
+ if (fr_command_run(stdout, radmin_cmd, &info) < 0) {
fprintf(stderr, "Failing running command: %s\n", fr_strerror());
}
if (stop) break;
}
- talloc_free(argv);
+ talloc_free(ctx);
return NULL;
}
*/
static struct timeval start_time;
-static int cmd_exit(UNUSED FILE *fp, UNUSED void *ctx, UNUSED int argc, UNUSED char const *argv[])
+static int cmd_exit(UNUSED FILE *fp, UNUSED void *ctx, UNUSED int argc, UNUSED char *argv[])
{
radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
stop = true;
return 0;
}
-static int cmd_help(FILE *fp, UNUSED void *ctx, int argc, char const *argv[])
+static int cmd_help(FILE *fp, UNUSED void *ctx, int argc, char *argv[])
{
char const *help;
return 0;
}
-static int cmd_uptime(FILE *fp, UNUSED void *ctx, UNUSED int argc, UNUSED char const *argv[])
+static int cmd_uptime(FILE *fp, UNUSED void *ctx, UNUSED int argc, UNUSED char *argv[])
{
struct timeval now;
return 0;
}
-static int cmd_test(FILE *fp, UNUSED void *ctx, UNUSED int argc, char const *argv[])
+static int cmd_test(FILE *fp, UNUSED void *ctx, UNUSED int argc, char *argv[])
{
fprintf(fp, "woo! %s %s\n", argv[0], argv[2]);
return 0;