1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo * Command line editing and history wrapper for readline
3f05cddf9SRui Paulo * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
4f05cddf9SRui Paulo *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
7f05cddf9SRui Paulo */
8f05cddf9SRui Paulo
9f05cddf9SRui Paulo #include "includes.h"
10f05cddf9SRui Paulo #include <readline/readline.h>
11f05cddf9SRui Paulo #include <readline/history.h>
12f05cddf9SRui Paulo
13f05cddf9SRui Paulo #include "common.h"
14f05cddf9SRui Paulo #include "eloop.h"
15f05cddf9SRui Paulo #include "edit.h"
16f05cddf9SRui Paulo
17f05cddf9SRui Paulo
18f05cddf9SRui Paulo static void *edit_cb_ctx;
19f05cddf9SRui Paulo static void (*edit_cmd_cb)(void *ctx, char *cmd);
20f05cddf9SRui Paulo static void (*edit_eof_cb)(void *ctx);
21f05cddf9SRui Paulo static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
22f05cddf9SRui Paulo NULL;
23f05cddf9SRui Paulo
24f05cddf9SRui Paulo static char **pending_completions = NULL;
25f05cddf9SRui Paulo
26f05cddf9SRui Paulo
readline_free_completions(void)27f05cddf9SRui Paulo static void readline_free_completions(void)
28f05cddf9SRui Paulo {
29f05cddf9SRui Paulo int i;
30f05cddf9SRui Paulo if (pending_completions == NULL)
31f05cddf9SRui Paulo return;
32f05cddf9SRui Paulo for (i = 0; pending_completions[i]; i++)
33f05cddf9SRui Paulo os_free(pending_completions[i]);
34f05cddf9SRui Paulo os_free(pending_completions);
35f05cddf9SRui Paulo pending_completions = NULL;
36f05cddf9SRui Paulo }
37f05cddf9SRui Paulo
38f05cddf9SRui Paulo
readline_completion_func(const char * text,int state)39f05cddf9SRui Paulo static char * readline_completion_func(const char *text, int state)
40f05cddf9SRui Paulo {
41f05cddf9SRui Paulo static int pos = 0;
42f05cddf9SRui Paulo static size_t len = 0;
43f05cddf9SRui Paulo
44f05cddf9SRui Paulo if (pending_completions == NULL) {
45f05cddf9SRui Paulo rl_attempted_completion_over = 1;
46f05cddf9SRui Paulo return NULL;
47f05cddf9SRui Paulo }
48f05cddf9SRui Paulo
49f05cddf9SRui Paulo if (state == 0) {
50f05cddf9SRui Paulo pos = 0;
51f05cddf9SRui Paulo len = os_strlen(text);
52f05cddf9SRui Paulo }
53f05cddf9SRui Paulo for (; pending_completions[pos]; pos++) {
54f05cddf9SRui Paulo if (strncmp(pending_completions[pos], text, len) == 0)
55f05cddf9SRui Paulo return strdup(pending_completions[pos++]);
56f05cddf9SRui Paulo }
57f05cddf9SRui Paulo
58f05cddf9SRui Paulo rl_attempted_completion_over = 1;
59f05cddf9SRui Paulo return NULL;
60f05cddf9SRui Paulo }
61f05cddf9SRui Paulo
62f05cddf9SRui Paulo
readline_completion(const char * text,int start,int end)63f05cddf9SRui Paulo static char ** readline_completion(const char *text, int start, int end)
64f05cddf9SRui Paulo {
65f05cddf9SRui Paulo readline_free_completions();
66f05cddf9SRui Paulo if (edit_completion_cb)
67f05cddf9SRui Paulo pending_completions = edit_completion_cb(edit_cb_ctx,
68f05cddf9SRui Paulo rl_line_buffer, end);
69f05cddf9SRui Paulo return rl_completion_matches(text, readline_completion_func);
70f05cddf9SRui Paulo }
71f05cddf9SRui Paulo
72f05cddf9SRui Paulo
edit_read_char(int sock,void * eloop_ctx,void * sock_ctx)73f05cddf9SRui Paulo static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
74f05cddf9SRui Paulo {
75f05cddf9SRui Paulo rl_callback_read_char();
76f05cddf9SRui Paulo }
77f05cddf9SRui Paulo
78f05cddf9SRui Paulo
trunc_nl(char * str)79f05cddf9SRui Paulo static void trunc_nl(char *str)
80f05cddf9SRui Paulo {
81f05cddf9SRui Paulo char *pos = str;
82f05cddf9SRui Paulo while (*pos != '\0') {
83f05cddf9SRui Paulo if (*pos == '\n') {
84f05cddf9SRui Paulo *pos = '\0';
85f05cddf9SRui Paulo break;
86f05cddf9SRui Paulo }
87f05cddf9SRui Paulo pos++;
88f05cddf9SRui Paulo }
89f05cddf9SRui Paulo }
90f05cddf9SRui Paulo
91f05cddf9SRui Paulo
readline_cmd_handler(char * cmd)92f05cddf9SRui Paulo static void readline_cmd_handler(char *cmd)
93f05cddf9SRui Paulo {
94f05cddf9SRui Paulo if (cmd && *cmd) {
95f05cddf9SRui Paulo HIST_ENTRY *h;
96f05cddf9SRui Paulo while (next_history())
97f05cddf9SRui Paulo ;
98f05cddf9SRui Paulo h = previous_history();
99f05cddf9SRui Paulo if (h == NULL || os_strcmp(cmd, h->line) != 0)
100f05cddf9SRui Paulo add_history(cmd);
101f05cddf9SRui Paulo next_history();
102f05cddf9SRui Paulo }
103f05cddf9SRui Paulo if (cmd == NULL) {
104f05cddf9SRui Paulo edit_eof_cb(edit_cb_ctx);
105f05cddf9SRui Paulo return;
106f05cddf9SRui Paulo }
107f05cddf9SRui Paulo trunc_nl(cmd);
108f05cddf9SRui Paulo edit_cmd_cb(edit_cb_ctx, cmd);
109f05cddf9SRui Paulo }
110f05cddf9SRui Paulo
111f05cddf9SRui Paulo
edit_init(void (* cmd_cb)(void * ctx,char * cmd),void (* eof_cb)(void * ctx),char ** (* completion_cb)(void * ctx,const char * cmd,int pos),void * ctx,const char * history_file,const char * ps)112f05cddf9SRui Paulo int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
113f05cddf9SRui Paulo void (*eof_cb)(void *ctx),
114f05cddf9SRui Paulo char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
115f05cddf9SRui Paulo void *ctx, const char *history_file, const char *ps)
116f05cddf9SRui Paulo {
117f05cddf9SRui Paulo edit_cb_ctx = ctx;
118f05cddf9SRui Paulo edit_cmd_cb = cmd_cb;
119f05cddf9SRui Paulo edit_eof_cb = eof_cb;
120f05cddf9SRui Paulo edit_completion_cb = completion_cb;
121f05cddf9SRui Paulo
122f05cddf9SRui Paulo rl_attempted_completion_function = readline_completion;
123f05cddf9SRui Paulo if (history_file) {
124f05cddf9SRui Paulo read_history(history_file);
125f05cddf9SRui Paulo stifle_history(100);
126f05cddf9SRui Paulo }
127f05cddf9SRui Paulo
128f05cddf9SRui Paulo eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
129f05cddf9SRui Paulo
130f05cddf9SRui Paulo if (ps) {
131f05cddf9SRui Paulo size_t blen = os_strlen(ps) + 3;
132f05cddf9SRui Paulo char *ps2 = os_malloc(blen);
133f05cddf9SRui Paulo if (ps2) {
134f05cddf9SRui Paulo os_snprintf(ps2, blen, "%s> ", ps);
135f05cddf9SRui Paulo rl_callback_handler_install(ps2, readline_cmd_handler);
136f05cddf9SRui Paulo os_free(ps2);
137f05cddf9SRui Paulo return 0;
138f05cddf9SRui Paulo }
139f05cddf9SRui Paulo }
140f05cddf9SRui Paulo
141f05cddf9SRui Paulo rl_callback_handler_install("> ", readline_cmd_handler);
142f05cddf9SRui Paulo
143f05cddf9SRui Paulo return 0;
144f05cddf9SRui Paulo }
145f05cddf9SRui Paulo
146f05cddf9SRui Paulo
edit_deinit(const char * history_file,int (* filter_cb)(void * ctx,const char * cmd))147f05cddf9SRui Paulo void edit_deinit(const char *history_file,
148f05cddf9SRui Paulo int (*filter_cb)(void *ctx, const char *cmd))
149f05cddf9SRui Paulo {
150f05cddf9SRui Paulo rl_set_prompt("");
151f05cddf9SRui Paulo rl_replace_line("", 0);
152f05cddf9SRui Paulo rl_redisplay();
153f05cddf9SRui Paulo rl_callback_handler_remove();
154f05cddf9SRui Paulo readline_free_completions();
155f05cddf9SRui Paulo
156f05cddf9SRui Paulo eloop_unregister_read_sock(STDIN_FILENO);
157f05cddf9SRui Paulo
158f05cddf9SRui Paulo if (history_file) {
159f05cddf9SRui Paulo /* Save command history, excluding lines that may contain
160f05cddf9SRui Paulo * passwords. */
161f05cddf9SRui Paulo HIST_ENTRY *h;
162f05cddf9SRui Paulo history_set_pos(0);
163f05cddf9SRui Paulo while ((h = current_history())) {
164f05cddf9SRui Paulo char *p = h->line;
165f05cddf9SRui Paulo while (*p == ' ' || *p == '\t')
166f05cddf9SRui Paulo p++;
167f05cddf9SRui Paulo if (filter_cb && filter_cb(edit_cb_ctx, p)) {
168f05cddf9SRui Paulo h = remove_history(where_history());
169f05cddf9SRui Paulo if (h) {
170*5b9c547cSRui Paulo free(h->line);
171f05cddf9SRui Paulo free(h->data);
172*5b9c547cSRui Paulo free(h);
173f05cddf9SRui Paulo } else
174f05cddf9SRui Paulo next_history();
175f05cddf9SRui Paulo } else
176f05cddf9SRui Paulo next_history();
177f05cddf9SRui Paulo }
178f05cddf9SRui Paulo write_history(history_file);
179f05cddf9SRui Paulo }
180f05cddf9SRui Paulo }
181f05cddf9SRui Paulo
182f05cddf9SRui Paulo
edit_clear_line(void)183f05cddf9SRui Paulo void edit_clear_line(void)
184f05cddf9SRui Paulo {
185f05cddf9SRui Paulo }
186f05cddf9SRui Paulo
187f05cddf9SRui Paulo
edit_redraw(void)188f05cddf9SRui Paulo void edit_redraw(void)
189f05cddf9SRui Paulo {
190f05cddf9SRui Paulo rl_on_new_line();
191f05cddf9SRui Paulo rl_redisplay();
192f05cddf9SRui Paulo }
193