{
int num;
size_t offset;
+ char **expansions = &radmin_expansions[0];
+ char const **expansions_const;
rl_attempted_completion_over = 1;
offset = (radmin_partial_line - radmin_buffer);
strlcpy(radmin_partial_line, rl_line_buffer, 8192 - offset);
+
+ memcpy(&expansions_const, &expansions, sizeof(expansions)); /* const issues */
num = fr_command_complete(radmin_cmd, radmin_buffer, start + offset,
- CMD_MAX_EXPANSIONS, radmin_expansions);
+ CMD_MAX_EXPANSIONS, expansions_const);
if (num <= 0) return NULL;
radmin_num_expansions = num;
return 0;
}
-#define CMD_TEST
+//#define CMD_TEST (1)
#ifdef CMD_TEST
static int cmd_test(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info)
{
int i;
- fprintf(fp, "TEST\n");
+ fprintf(fp, "TEST %d\n", info->argc);
for (i = 0; i < info->argc; i++) {
fprintf(fp, "\t%s\n", info->argv[i]);
return 0;
}
+
+static int cmd_test_tab_expand(UNUSED TALLOC_CTX *talloc_ctx, UNUSED void *ctx, fr_cmd_info_t *info, UNUSED int max_expansions, char const **expansions)
+{
+ char const *text;
+ char *p;
+
+ if (info->argc == 0) return 0;
+
+ text = info->argv[info->argc - 1];
+
+ /*
+ * Expand a list of things
+ */
+ if (!*text) {
+ expansions[0] = strdup("0");
+ expansions[1] = strdup("1");
+ return 2;
+ }
+
+ if ((text[0] < '0') || (text[0] > '9')) {
+ return 0;
+ }
+
+ /*
+ * If the user enters a digit, allow it.
+ */
+ expansions[0] = p = malloc(2);
+ p[0] = text[0];
+ p[1] = '\0';
+
+ return 1;
+}
#endif
static fr_cmd_table_t cmd_table[] = {
#ifdef CMD_TEST
{
.parent = "test",
- .syntax = "foo bar",
+ .syntax = "foo INTEGER",
.func = cmd_test,
- .help = "test foo bar",
+ .tab_expand = cmd_test_tab_expand,
+ .help = "test foo INTEGER",
.read_only = true,
},
#endif
}
-static int expand_all(fr_cmd_t *cmd, fr_cmd_argv_t *argv, int count, int max_expansions, char **expansions)
+static int expand_all(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, int count, int max_expansions, char const **expansions)
{
fr_cmd_argv_t *child;
rad_assert(child->child != NULL);
sub = child->child;
- count = expand_all(cmd, sub, count, max_expansions, expansions);
+ count = expand_all(cmd, info, sub, count, max_expansions, expansions);
}
return count;
rad_assert(child->child != NULL);
sub = child->child;
- count = expand_all(cmd, sub, count, max_expansions, expansions);
+ count = expand_all(cmd, info, sub, count, max_expansions, expansions);
}
return count;
* @todo - might want to do something smarter here?
*/
if (argv->type == FR_TYPE_OPTIONAL) {
- return expand_all(cmd, argv->child, count, max_expansions, expansions);
+ return expand_all(cmd, info, argv->child, count, max_expansions, expansions);
}
if ((argv->type < FR_TYPE_FIXED) && cmd->tab_expand) {
- rad_assert(0 == 1);
- return count;
+ int rcode;
+
+ info->argv[info->argc] = "";
+ info->box[info->argc] = NULL;
+ info->argc++;
+
+ rad_assert(count == 0);
+ rcode = cmd->tab_expand(NULL, cmd->ctx, info, max_expansions - count, expansions + count);
+ if (rcode < 0) return rcode;
+
+ return count + rcode;
}
expansions[count] = strdup(argv->name);
return count + 1;
}
-static int expand_syntax(fr_cmd_t *cmd, fr_cmd_argv_t *argv, char const *text, int start, char const **word_p,
- int count, int max_expansions, char **expansions)
+static int expand_syntax(fr_cmd_t *cmd, fr_cmd_info_t *info, fr_cmd_argv_t *argv, char const *text, int start,
+ char const **word_p, int count, int max_expansions, char const **expansions)
{
char const *p, *q;
char const *word = *word_p;
SKIP_SPACES;
if (!*word) {
- return expand_all(cmd, argv, count, max_expansions, expansions);
+ return expand_all(cmd, info, argv, count, max_expansions, expansions);
}
if (argv->type == FR_TYPE_VARARGS) return count;
my_word = word;
- count = expand_syntax(cmd, argv->child, text, start, &my_word, count, max_expansions, expansions);
+ count = expand_syntax(cmd, info, argv->child, text, start, &my_word, count, max_expansions, expansions);
if (word != my_word) *word_p = word;
continue;
* See if the child eats any of
* the input. If so, use it.
*/
- count = expand_syntax(cmd, sub, text, start, &my_word, count, max_expansions, expansions);
+ count = expand_syntax(cmd, info, sub, text, start, &my_word, count, max_expansions, expansions);
if (my_word != word) {
*word_p = word;
break;
* Check data types.
*/
if (argv->type < FR_TYPE_FIXED) {
+ int rcode;
+ size_t len, offset;
+ char quote, *my_word;
+ fr_type_t type = argv->type;
+
p = skip_word(word);
if (!p) return count;
return count + 1;
}
- // @todo call tab expand callback
- rad_assert(0 == 1);
+ /*
+ * Give the function the partial
+ * text which should be expanded.
+ */
+ info->argv[info->argc] = text;
+ info->box[info->argc] = NULL;
+ info->argc++;
+
+ /*
+ * Expand this thing.
+ */
+ rad_assert(count == 0);
+ rcode = cmd->tab_expand(NULL, cmd->ctx, info, max_expansions - count, expansions + count);
+ if (rcode < 0) return rcode;
+ return count + rcode;
}
*word_p = p;
+
+ len = p - word;
+
+ info->argv[info->argc] = my_word = talloc_zero_array(info->argv, char *, len + 1);
+ memcpy(my_word, word, len);
+ my_word[len] = '\0';
+
+ if (!info->box[info->argc]) {
+ info->box[info->argc] = talloc_zero(info->box, fr_value_box_t);
+ }
+
+ if ((*word == '"') || (*word == '\'')) {
+ quote = *word;
+ offset = 1;
+ } else {
+ quote = 0;
+ offset = 0;
+ }
+
+ rcode = fr_value_box_from_str(info->box[info->argc], info->box[info->argc],
+ &type, NULL,
+ word + offset, len - (offset << 1), quote, false);
+ if (rcode < 0) return -1;
+ info->argc++;
continue;
}
*/
if (MATCHED_NAME) {
*word_p = word;
+ info->argv[info->argc] = word;
+ info->box[info->argc] = NULL;
+ info->argc++;
continue;
}
break;
}
+ /*
+ * Ran out of words to match.
+ */
*word_p = word;
return count;
}
* - >= 0 number of expansions in the array
*/
int fr_command_complete(fr_cmd_t *head, char const *text, int start,
- int max_expansions, char **expansions)
+ int max_expansions, char const **expansions)
{
char const *word, *p, *q;
fr_cmd_t *cmd;
int count;
+ fr_cmd_info_t *info;
cmd = head;
word = text;
count = 0;
+ info = talloc_zero(head, fr_cmd_info_t);
+ fr_command_info_init(head, info);
+
/*
* Try to do this without mangling "text".
*/
}
cmd = cmd->next;
}
+
+ talloc_free(info);
return count;
}
rad_assert(cmd->child != NULL);
word = p;
cmd = cmd->child;
+ info->argv[info->argc] = cmd->name;
+ info->argc++;
continue;
}
* Skip the command name we matched.
*/
word = p;
- // expand this?
break;
}
* No match, can't do anything.
*/
if (!cmd) {
+ talloc_free(info);
return count;
}
* No syntax, can't do anything.
*/
if (!cmd->syntax) {
+ talloc_free(info);
return count;
}
- return expand_syntax(cmd, cmd->syntax_argv, text, start, &word, count, max_expansions, expansions);
+ count = expand_syntax(cmd, info, cmd->syntax_argv, text, start, &word, count, max_expansions, expansions);
+ fr_command_clear(0, info);
+ talloc_free(info);
+ return count;
}
/** Do readline-style command completions