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