18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Command line editing and history wrapper for readline 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2010, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <readline/readline.h> 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <readline/history.h> 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "edit.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void *edit_cb_ctx; 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void (*edit_cmd_cb)(void *ctx, char *cmd); 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void (*edit_eof_cb)(void *ctx); 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NULL; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char **pending_completions = NULL; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void readline_free_completions(void) 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pending_completions == NULL) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; pending_completions[i]; i++) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(pending_completions[i]); 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(pending_completions); 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pending_completions = NULL; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char * readline_completion_func(const char *text, int state) 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt static int pos = 0; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt static size_t len = 0; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pending_completions == NULL) { 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_attempted_completion_over = 1; 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (state == 0) { 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = 0; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = os_strlen(text); 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (; pending_completions[pos]; pos++) { 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (strncmp(pending_completions[pos], text, len) == 0) 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return strdup(pending_completions[pos++]); 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_attempted_completion_over = 1; 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char ** readline_completion(const char *text, int start, int end) 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt readline_free_completions(); 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (edit_completion_cb) 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pending_completions = edit_completion_cb(edit_cb_ctx, 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_line_buffer, end); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rl_completion_matches(text, readline_completion_func); 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_callback_read_char(); 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void trunc_nl(char *str) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *pos = str; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*pos != '\0') { 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos == '\n') { 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void readline_cmd_handler(char *cmd) 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cmd && *cmd) { 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HIST_ENTRY *h; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (next_history()) 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h = previous_history(); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h == NULL || os_strcmp(cmd, h->line) != 0) 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt add_history(cmd); 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_history(); 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cmd == NULL) { 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_eof_cb(edit_cb_ctx); 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt trunc_nl(cmd); 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_cmd_cb(edit_cb_ctx, cmd); 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint edit_init(void (*cmd_cb)(void *ctx, char *cmd), 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*eof_cb)(void *ctx), 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char ** (*completion_cb)(void *ctx, const char *cmd, int pos), 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt void *ctx, const char *history_file, const char *ps) 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_cb_ctx = ctx; 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_cmd_cb = cmd_cb; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_eof_cb = eof_cb; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt edit_completion_cb = completion_cb; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_attempted_completion_function = readline_completion; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (history_file) { 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt read_history(history_file); 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt stifle_history(100); 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (ps) { 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t blen = os_strlen(ps) + 3; 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt char *ps2 = os_malloc(blen); 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (ps2) { 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_snprintf(ps2, blen, "%s> ", ps); 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rl_callback_handler_install(ps2, readline_cmd_handler); 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(ps2); 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 0; 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_callback_handler_install("> ", readline_cmd_handler); 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid edit_deinit(const char *history_file, 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int (*filter_cb)(void *ctx, const char *cmd)) 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rl_set_prompt(""); 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rl_replace_line("", 0); 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rl_redisplay(); 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_callback_handler_remove(); 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt readline_free_completions(); 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_unregister_read_sock(STDIN_FILENO); 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (history_file) { 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Save command history, excluding lines that may contain 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * passwords. */ 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HIST_ENTRY *h; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt history_set_pos(0); 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while ((h = current_history())) { 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *p = h->line; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*p == ' ' || *p == '\t') 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p++; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (filter_cb && filter_cb(edit_cb_ctx, p)) { 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt h = remove_history(where_history()); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (h) { 17044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt free(h->line); 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt free(h->data); 17244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt free(h); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_history(); 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_history(); 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_history(history_file); 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid edit_clear_line(void) 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid edit_redraw(void) 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_on_new_line(); 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rl_redisplay(); 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 193