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