1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <readline/readline.h>
25 #include <readline/history.h>
26 
27 #include "lftp_rl.h"
28 
29 /* complete.cc */
30 void lftp_line_complete();
31 
lftp_add_history_nodups(const char * cmd_buf)32 void lftp_add_history_nodups(const char *cmd_buf)
33 {
34    HIST_ENTRY *temp;
35    char ts[24];
36    if(cmd_buf[0]==' ')
37       return;
38    using_history();
39    temp=previous_history();
40    if(temp==0 || strcmp(temp->line,cmd_buf))
41       add_history(cmd_buf);
42    sprintf(ts," %lld",(long long)time(0));
43    add_history_time(ts);
44    using_history();
45 }
46 
lftp_readline(const char * prompt)47 char *lftp_readline(const char *prompt)
48 {
49    char *ret = readline(prompt);
50    /* Tell completion that we don't need completion data anymore;
51     * it might be taking a good chunk of memory. */
52    lftp_line_complete();
53 
54    return ret;
55 }
56 
lftp_history_expand(const char * what,char ** where)57 int lftp_history_expand(const char *what, char **where)
58 {
59    return history_expand((char*)what,where);
60 }
61 
lftp_history_read(const char * fn)62 int lftp_history_read(const char *fn)
63 {
64    using_history();
65    return read_history(fn);
66 }
67 
lftp_history_write(const char * fn)68 int lftp_history_write(const char *fn)
69 {
70    using_history();
71    return write_history(fn);
72 }
73 
lftp_history_list(int cnt)74 void lftp_history_list(int cnt)
75 {
76    HISTORY_STATE *st = history_get_history_state();
77    HIST_ENTRY *hist;
78    int i;
79    using_history();
80 
81    i = history_base + st->length - cnt;
82    if(cnt == -1 || i < history_base) i = history_base;
83 
84    char ts_str[24];
85    while((hist = history_get(i))) {
86       ts_str[0]=0;
87       if(hist->timestamp[0]) {
88 	 time_t ts=atol(hist->timestamp+1);
89 	 strftime(ts_str,sizeof(ts_str),"%Y-%m-%d %H:%M:%S",localtime(&ts));
90       }
91       printf("%5d%c %s  %s\n", i++, hist->data?'*':' ', ts_str, hist->line);
92    }
93 }
94 
lftp_history_clear()95 void lftp_history_clear()
96 {
97    clear_history();
98 }
99 
100 static int is_clear=0;
101 
lftp_rl_clear()102 void lftp_rl_clear()
103 {
104    extern char *rl_display_prompt;
105    extern int _rl_mark_modified_lines;
106    int old_end=rl_end;
107    char *old_prompt=rl_display_prompt;
108    int old_mark=_rl_mark_modified_lines;
109 
110    rl_end=0;
111    rl_display_prompt="";
112    rl_expand_prompt(0);
113    _rl_mark_modified_lines=0;
114 
115    rl_redisplay();
116 
117    rl_end=old_end;
118    rl_display_prompt=old_prompt;
119    _rl_mark_modified_lines=old_mark;
120    if(rl_display_prompt==rl_prompt)
121       rl_expand_prompt(rl_prompt);
122 
123    is_clear=1;
124 }
125 
lftp_rl_redisplay_maybe()126 void lftp_rl_redisplay_maybe()
127 {
128    if(is_clear)
129       rl_redisplay();
130    is_clear=0;
131 }
132 
133 /* prototype hell differences in various readline versions make it impossible
134  * to use certain functions/variables in C++ */
135 
lftp_rl_set_ignore_some_completions_function(int (* func)(char **))136 void lftp_rl_set_ignore_some_completions_function(int (*func)(char**))
137 {
138    rl_ignore_some_completions_function=func;
139 }
140 
lftp_rl_completion_matches(const char * text,char * (* compentry)(const char *,int))141 char **lftp_rl_completion_matches(const char *text,char *(*compentry)(const char *,int))
142 {
143    return rl_completion_matches(text,compentry);
144 }
145 
146 void completion_display_list (char **matches, int len);
147 
lftp_rl_display_match_list(char ** matches,int len,int max)148 void lftp_rl_display_match_list (char **matches, int len, int max)
149 {
150    printf("\n"); /* get off the input line */
151    completion_display_list(matches, len);
152    rl_forced_update_display(); /* redraw input line */
153 }
154 
lftp_rl_init(const char * readline_name,char ** (* attempted_completion_function)(const char *,int,int),int (* getc_function)(FILE *),const char * completer_quote_characters,const char * completer_word_break_characters,const char * filename_quote_characters,char * (* filename_quoting_function)(char *,int,char *),char * (* filename_dequoting_function)(const char *,int),int (* char_is_quoted_p)(const char *,int))155 void lftp_rl_init(
156    const char *readline_name,
157    char **(*attempted_completion_function)(const char *,int,int),
158    int (*getc_function)(FILE*),
159    const char *completer_quote_characters,
160    const char *completer_word_break_characters,
161    const char *filename_quote_characters,
162    char *(*filename_quoting_function)(char *,int,char *),
163    char *(*filename_dequoting_function)(const char *,int),
164    int (*char_is_quoted_p)(const char *,int))
165 {
166    rl_readline_name                  =readline_name;
167    rl_attempted_completion_function  =attempted_completion_function;
168    rl_getc_function                  =getc_function;
169    rl_completer_quote_characters     =completer_quote_characters;
170    rl_completer_word_break_characters=(char*)completer_word_break_characters;
171    rl_filename_quote_characters      =filename_quote_characters;
172    rl_filename_quoting_function      =filename_quoting_function;
173    rl_filename_dequoting_function    =(rl_dequote_func_t*)filename_dequoting_function;
174    rl_char_is_quoted_p               =(rl_linebuf_func_t*)char_is_quoted_p;
175 
176    rl_completion_display_matches_hook = lftp_rl_display_match_list;
177 
178    history_write_timestamps=1;
179    history_comment_char=' ';
180 }
181 
lftp_rl_add_defun(const char * name,int (* func)(int,int),int key)182 void lftp_rl_add_defun(const char *name,int (*func)(int,int),int key)
183 {
184    rl_add_defun(name,func,key);
185 }
lftp_rl_bind(const char * key,const char * func)186 void lftp_rl_bind(const char *key,const char *func)
187 {
188    char *line=alloca(strlen(key)+2+strlen(func)+1);
189    sprintf(line,"%s: %s",key,func);
190    rl_parse_and_bind(line);
191 }
192 
lftp_rl_set_prompt(const char * p)193 void lftp_rl_set_prompt(const char *p)
194 {
195    rl_set_prompt(p);
196 }
197 
198 extern char *get_lftp_data_dir();
199 
200 static char *lftp_history_file;
lftp_rl_read_history()201 void lftp_rl_read_history()
202 {
203    if(!lftp_history_file)
204    {
205       const char *add="/rl_history";
206       const char *home=get_lftp_data_dir();
207       if(!home)
208 	 return;
209       lftp_history_file=(char*)malloc(strlen(home)+strlen(add)+1);
210       strcat(strcpy(lftp_history_file,home),add);
211    }
212    read_history(lftp_history_file);
213 }
lftp_rl_write_history()214 void lftp_rl_write_history()
215 {
216    if(!lftp_history_file)
217       return;
218    write_history(lftp_history_file);
219 }
220 
lftp_rl_history_stifle(int s)221 void lftp_rl_history_stifle(int s)
222 {
223    if(s==0)
224       unstifle_history();
225    else
226       stifle_history(s);
227 }
228