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