* @param start offset in the text where the completions should start
* @param max_expansions how many entries in the "expansions" array.
* @param[in,out] expansions where the expansions are stored.
+ * @return
+ * - <0 on error
+ * - >= 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)
return expand_syntax(cmd->syntax_argv, text, start, &word, count, max_expansions, expansions);
}
+
+/** Do readline-style command completions
+ *
+ * Most useful as part of readline tab expansions. The expansions
+ * are strdup() strings, and MUST be free'd by the caller.
+ *
+ * @param head of the command tree
+ * @param text the text to check
+ */
+int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
+{
+ char const *word, *p, *q;
+ fr_cmd_t *cmd;
+
+ cmd = head;
+ word = text;
+
+ /*
+ * Try to do this without mangling "text".
+ */
+ while (cmd) {
+ while (isspace((int) *word)) word++;
+
+ /*
+ * End of the input. Tab expand everything here.
+ */
+ if (!*word) {
+ while (cmd) {
+ if (!cmd->help) {
+ fprintf(fp, "%s\n", cmd->name);
+ } else {
+ fprintf(fp, "%-30s%s\n", cmd->name, cmd->help);
+ }
+ cmd = cmd->next;
+ }
+ return 0;
+ }
+
+ /*
+ * Try to find a matching cmd->name
+ */
+ p = word;
+ q = cmd->name;
+
+ while (*p == *q) {
+ p++;
+ q++;
+ }
+
+ /*
+ * The only matching exit condition is *p is a
+ * space, and *q is the NUL character.
+ */
+ if (!(isspace((int) *p) && !*q)) {
+ cmd = cmd->next;
+ continue;
+ }
+
+ if (cmd->intermediate) {
+ rad_assert(cmd->child != NULL);
+ word = p;
+ cmd = cmd->child;
+ continue;
+ }
+
+ /*
+ * Skip the command name we matched.
+ */
+ word = p;
+ break;
+ }
+
+ /*
+ * No match, can't do anything.
+ */
+ if (!cmd) {
+ return 0;
+ }
+
+ if (!cmd->help) {
+ fprintf(fp, "%s\n", cmd->name);
+ } else {
+ fprintf(fp, "%-30s%s\n", cmd->name, cmd->help);
+ }
+
+ return 0;
+}
static int cmd_help(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info);
static int cmd_exit(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info);
+#ifdef USE_READLINE
/*
* Global variables because readline() is stupid.
*/
return rl_completion_matches(text, radmin_expansion_walk);
}
+static int radmin_help(UNUSED int count, UNUSED int key)
+{
+ char buffer[8192];
+
+ printf("\n");
+
+ /*
+ * @todo make this not retarded.
+ */
+ strlcpy(buffer, radmin_buffer, sizeof(buffer));
+ strlcat(buffer, " ", sizeof(buffer));
+ strlcat(buffer, rl_line_buffer, sizeof(buffer));
+
+ (void) fr_command_print_help(stdout, radmin_cmd, buffer);
+ rl_on_new_line();
+ return 0;
+}
+
+#endif /* USE_READLINE */
+
+
static void *fr_radmin(UNUSED void *input_ctx)
{
int argc;
ctx = talloc_init("radmin");
size = room = 8192;
- radmin_buffer = talloc_array(ctx, char, size);
- argv_buffer = talloc_array(ctx, char, size);
+ radmin_buffer = talloc_zero_array(ctx, char, size);
+ argv_buffer = talloc_zero_array(ctx, char, size);
current_str = argv_buffer;
fr_command_info_init(ctx, info);
fflush(stdout);
+#ifdef USE_READLINE
rl_attempted_completion_function = radmin_completion;
+ (void) rl_bind_key('?', radmin_help);
+#endif
+
while (true) {
char *line;