1 |
|
|
/* $OpenBSD: readline.c,v 1.27 2016/05/31 16:12:00 schwarze Exp $ */ |
2 |
|
|
/* $NetBSD: readline.c,v 1.91 2010/08/28 15:44:59 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1997 The NetBSD Foundation, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to The NetBSD Foundation |
9 |
|
|
* by Jaromir Dolecek. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 |
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include "config.h" |
34 |
|
|
|
35 |
|
|
#include <sys/types.h> |
36 |
|
|
#include <sys/stat.h> |
37 |
|
|
#include <ctype.h> |
38 |
|
|
#include <dirent.h> |
39 |
|
|
#include <errno.h> |
40 |
|
|
#include <fcntl.h> |
41 |
|
|
#include <limits.h> |
42 |
|
|
#include <pwd.h> |
43 |
|
|
#include <setjmp.h> |
44 |
|
|
#include <stdint.h> |
45 |
|
|
#include <stdio.h> |
46 |
|
|
#include <stdlib.h> |
47 |
|
|
#include <string.h> |
48 |
|
|
#include <unistd.h> |
49 |
|
|
#ifdef HAVE_VIS_H |
50 |
|
|
#include <vis.h> |
51 |
|
|
#else |
52 |
|
|
#include "np/vis.h" |
53 |
|
|
#endif |
54 |
|
|
#include "readline/readline.h" |
55 |
|
|
#include "el.h" |
56 |
|
|
#include "fcns.h" |
57 |
|
|
#include "filecomplete.h" |
58 |
|
|
|
59 |
|
|
void rl_prep_terminal(int); |
60 |
|
|
void rl_deprep_terminal(void); |
61 |
|
|
|
62 |
|
|
/* for rl_complete() */ |
63 |
|
|
#define TAB '\r' |
64 |
|
|
|
65 |
|
|
/* see comment at the #ifdef for sense of this */ |
66 |
|
|
/* #define GDB_411_HACK */ |
67 |
|
|
|
68 |
|
|
/* readline compatibility stuff - look at readline sources/documentation */ |
69 |
|
|
/* to see what these variables mean */ |
70 |
|
|
const char *rl_library_version = "EditLine wrapper"; |
71 |
|
|
int rl_readline_version = RL_READLINE_VERSION; |
72 |
|
|
static char empty[] = { '\0' }; |
73 |
|
|
static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; |
74 |
|
|
static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', |
75 |
|
|
'>', '<', '=', ';', '|', '&', '{', '(', '\0' }; |
76 |
|
|
char *rl_readline_name = empty; |
77 |
|
|
FILE *rl_instream = NULL; |
78 |
|
|
FILE *rl_outstream = NULL; |
79 |
|
|
int rl_point = 0; |
80 |
|
|
int rl_end = 0; |
81 |
|
|
char *rl_line_buffer = NULL; |
82 |
|
|
VCPFunction *rl_linefunc = NULL; |
83 |
|
|
int rl_done = 0; |
84 |
|
|
VFunction *rl_event_hook = NULL; |
85 |
|
|
KEYMAP_ENTRY_ARRAY emacs_standard_keymap, |
86 |
|
|
emacs_meta_keymap, |
87 |
|
|
emacs_ctlx_keymap; |
88 |
|
|
|
89 |
|
|
int history_base = 1; /* probably never subject to change */ |
90 |
|
|
int history_length = 0; |
91 |
|
|
int max_input_history = 0; |
92 |
|
|
char history_expansion_char = '!'; |
93 |
|
|
char history_subst_char = '^'; |
94 |
|
|
char *history_no_expand_chars = expand_chars; |
95 |
|
|
Function *history_inhibit_expansion_function = NULL; |
96 |
|
|
char *history_arg_extract(int start, int end, const char *str); |
97 |
|
|
|
98 |
|
|
int rl_inhibit_completion = 0; |
99 |
|
|
int rl_attempted_completion_over = 0; |
100 |
|
|
char *rl_basic_word_break_characters = break_chars; |
101 |
|
|
char *rl_completer_word_break_characters = NULL; |
102 |
|
|
char *rl_completer_quote_characters = NULL; |
103 |
|
|
Function *rl_completion_entry_function = NULL; |
104 |
|
|
CPPFunction *rl_attempted_completion_function = NULL; |
105 |
|
|
Function *rl_pre_input_hook = NULL; |
106 |
|
|
Function *rl_startup1_hook = NULL; |
107 |
|
|
int (*rl_getc_function)(FILE *) = NULL; |
108 |
|
|
char *rl_terminal_name = NULL; |
109 |
|
|
int rl_already_prompted = 0; |
110 |
|
|
int rl_filename_completion_desired = 0; |
111 |
|
|
int rl_ignore_completion_duplicates = 0; |
112 |
|
|
int rl_catch_signals = 1; |
113 |
|
|
int readline_echoing_p = 1; |
114 |
|
|
int _rl_print_completions_horizontally = 0; |
115 |
|
|
VFunction *rl_redisplay_function = NULL; |
116 |
|
|
Function *rl_startup_hook = NULL; |
117 |
|
|
VFunction *rl_completion_display_matches_hook = NULL; |
118 |
|
|
VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; |
119 |
|
|
VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; |
120 |
|
|
KEYMAP_ENTRY_ARRAY emacs_meta_keymap; |
121 |
|
|
|
122 |
|
|
/* |
123 |
|
|
* The current prompt string. |
124 |
|
|
*/ |
125 |
|
|
char *rl_prompt = NULL; |
126 |
|
|
/* |
127 |
|
|
* This is set to character indicating type of completion being done by |
128 |
|
|
* rl_complete_internal(); this is available for application completion |
129 |
|
|
* functions. |
130 |
|
|
*/ |
131 |
|
|
int rl_completion_type = 0; |
132 |
|
|
|
133 |
|
|
/* |
134 |
|
|
* If more than this number of items results from query for possible |
135 |
|
|
* completions, we ask user if they are sure to really display the list. |
136 |
|
|
*/ |
137 |
|
|
int rl_completion_query_items = 100; |
138 |
|
|
|
139 |
|
|
/* |
140 |
|
|
* List of characters which are word break characters, but should be left |
141 |
|
|
* in the parsed text when it is passed to the completion function. |
142 |
|
|
* Shell uses this to help determine what kind of completing to do. |
143 |
|
|
*/ |
144 |
|
|
char *rl_special_prefixes = NULL; |
145 |
|
|
|
146 |
|
|
/* |
147 |
|
|
* This is the character appended to the completed words if at the end of |
148 |
|
|
* the line. Default is ' ' (a space). |
149 |
|
|
*/ |
150 |
|
|
int rl_completion_append_character = ' '; |
151 |
|
|
|
152 |
|
|
/* |
153 |
|
|
* When the history cursor is on the newest element and next_history() |
154 |
|
|
* is called, GNU readline moves the cursor beyond the newest element. |
155 |
|
|
* The editline library does not provide data structures to express |
156 |
|
|
* that state, so we need a local flag. |
157 |
|
|
*/ |
158 |
|
|
static int current_history_valid = 1; |
159 |
|
|
|
160 |
|
|
/* stuff below is used internally by libedit for readline emulation */ |
161 |
|
|
|
162 |
|
|
static History *h = NULL; |
163 |
|
|
static EditLine *e = NULL; |
164 |
|
|
static Function *map[256]; |
165 |
|
|
static jmp_buf topbuf; |
166 |
|
|
|
167 |
|
|
/* internal functions */ |
168 |
|
|
static unsigned char _el_rl_complete(EditLine *, int); |
169 |
|
|
static unsigned char _el_rl_tstp(EditLine *, int); |
170 |
|
|
static char *_get_prompt(EditLine *); |
171 |
|
|
static int _getc_function(EditLine *, wchar_t *); |
172 |
|
|
static HIST_ENTRY *_move_history(int); |
173 |
|
|
static int _history_expand_command(const char *, size_t, size_t, |
174 |
|
|
char **); |
175 |
|
|
static char *_rl_compat_sub(const char *, const char *, |
176 |
|
|
const char *, int); |
177 |
|
|
static int _rl_event_read_char(EditLine *, wchar_t *); |
178 |
|
|
static void _rl_update_pos(void); |
179 |
|
|
|
180 |
|
|
|
181 |
|
|
/* ARGSUSED */ |
182 |
|
|
static char * |
183 |
|
|
_get_prompt(EditLine *el __attribute__((__unused__))) |
184 |
|
|
{ |
185 |
|
|
rl_already_prompted = 1; |
186 |
|
|
return rl_prompt; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
|
190 |
|
|
/* |
191 |
|
|
* generic function for moving around history |
192 |
|
|
*/ |
193 |
|
|
static HIST_ENTRY * |
194 |
|
|
_move_history(int op) |
195 |
|
|
{ |
196 |
|
96 |
HistEvent ev; |
197 |
|
|
static HIST_ENTRY rl_he; |
198 |
|
|
|
199 |
✓✓ |
48 |
if (history(h, &ev, op) != 0) |
200 |
|
12 |
return NULL; |
201 |
|
|
|
202 |
|
36 |
rl_he.line = ev.str; |
203 |
|
36 |
rl_he.data = NULL; |
204 |
|
|
|
205 |
|
36 |
return &rl_he; |
206 |
|
48 |
} |
207 |
|
|
|
208 |
|
|
|
209 |
|
|
/* |
210 |
|
|
* read one key from user defined input function |
211 |
|
|
*/ |
212 |
|
|
static int |
213 |
|
|
/*ARGSUSED*/ |
214 |
|
|
_getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c) |
215 |
|
|
{ |
216 |
|
|
int i; |
217 |
|
|
|
218 |
|
|
i = (*rl_getc_function)(NULL); |
219 |
|
|
if (i == -1) |
220 |
|
|
return 0; |
221 |
|
|
*c = (wchar_t)i; |
222 |
|
|
return 1; |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
static void |
226 |
|
|
_resize_fun(EditLine *el, void *a) |
227 |
|
|
{ |
228 |
|
|
const LineInfo *li; |
229 |
|
12 |
char **ap = a; |
230 |
|
|
|
231 |
|
6 |
li = el_line(el); |
232 |
|
|
/* a cheesy way to get rid of const cast. */ |
233 |
|
6 |
*ap = memchr(li->buffer, *li->buffer, 1); |
234 |
|
6 |
} |
235 |
|
|
|
236 |
|
|
static const char _dothistory[] = "/.history"; |
237 |
|
|
|
238 |
|
|
static const char * |
239 |
|
|
_default_history_file(void) |
240 |
|
|
{ |
241 |
|
|
struct passwd *p; |
242 |
|
|
static char path[PATH_MAX]; |
243 |
|
|
|
244 |
|
|
if (*path) |
245 |
|
|
return path; |
246 |
|
|
if ((p = getpwuid(getuid())) == NULL) |
247 |
|
|
return NULL; |
248 |
|
|
strlcpy(path, p->pw_dir, PATH_MAX); |
249 |
|
|
strlcat(path, _dothistory, PATH_MAX); |
250 |
|
|
return path; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
/* |
254 |
|
|
* READLINE compatibility stuff |
255 |
|
|
*/ |
256 |
|
|
|
257 |
|
|
/* |
258 |
|
|
* Set the prompt |
259 |
|
|
*/ |
260 |
|
|
int |
261 |
|
|
rl_set_prompt(const char *prompt) |
262 |
|
|
{ |
263 |
|
|
char *p; |
264 |
|
|
|
265 |
✗✓ |
12 |
if (!prompt) |
266 |
|
|
prompt = ""; |
267 |
✗✓✗✗
|
6 |
if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) |
268 |
|
|
return 0; |
269 |
✗✓ |
6 |
if (rl_prompt) |
270 |
|
|
free(rl_prompt); |
271 |
|
6 |
rl_prompt = strdup(prompt); |
272 |
✗✓ |
6 |
if (rl_prompt == NULL) |
273 |
|
|
return -1; |
274 |
|
|
|
275 |
✗✓ |
6 |
while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) |
276 |
|
|
*p = RL_PROMPT_START_IGNORE; |
277 |
|
|
|
278 |
|
6 |
return 0; |
279 |
|
6 |
} |
280 |
|
|
|
281 |
|
|
/* |
282 |
|
|
* initialize rl compat stuff |
283 |
|
|
*/ |
284 |
|
|
int |
285 |
|
|
rl_initialize(void) |
286 |
|
|
{ |
287 |
|
12 |
HistEvent ev; |
288 |
|
|
int editmode = 1; |
289 |
|
6 |
struct termios t; |
290 |
|
|
|
291 |
|
6 |
current_history_valid = 1; |
292 |
|
|
|
293 |
✗✓ |
6 |
if (e != NULL) |
294 |
|
|
el_end(e); |
295 |
✗✓ |
6 |
if (h != NULL) |
296 |
|
|
history_end(h); |
297 |
|
|
|
298 |
✓✗ |
6 |
if (!rl_instream) |
299 |
|
6 |
rl_instream = stdin; |
300 |
✓✗ |
6 |
if (!rl_outstream) |
301 |
|
6 |
rl_outstream = stdout; |
302 |
|
|
|
303 |
|
|
/* |
304 |
|
|
* See if we don't really want to run the editor |
305 |
|
|
*/ |
306 |
✓✗✓✗ ✗✓ |
24 |
if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) |
307 |
|
|
editmode = 0; |
308 |
|
|
|
309 |
|
6 |
e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); |
310 |
|
|
|
311 |
✗✓ |
6 |
if (!editmode) |
312 |
|
|
el_set(e, EL_EDITMODE, 0); |
313 |
|
|
|
314 |
|
6 |
h = history_init(); |
315 |
✗✓ |
6 |
if (!e || !h) |
316 |
|
|
return -1; |
317 |
|
|
|
318 |
|
6 |
history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ |
319 |
|
6 |
history_length = 0; |
320 |
|
6 |
max_input_history = INT_MAX; |
321 |
|
6 |
el_set(e, EL_HIST, history, h); |
322 |
|
|
|
323 |
|
|
/* Setup resize function */ |
324 |
|
6 |
el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); |
325 |
|
|
|
326 |
|
|
/* setup getc function if valid */ |
327 |
✗✓ |
6 |
if (rl_getc_function) |
328 |
|
|
el_set(e, EL_GETCFN, _getc_function); |
329 |
|
|
|
330 |
|
|
/* for proper prompt printing in readline() */ |
331 |
✗✓ |
6 |
if (rl_set_prompt("") == -1) { |
332 |
|
|
history_end(h); |
333 |
|
|
el_end(e); |
334 |
|
|
return -1; |
335 |
|
|
} |
336 |
|
6 |
el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); |
337 |
|
6 |
el_set(e, EL_SIGNAL, rl_catch_signals); |
338 |
|
|
|
339 |
|
|
/* set default mode to "emacs"-style and read setting afterwards */ |
340 |
|
|
/* so this can be overriden */ |
341 |
|
6 |
el_set(e, EL_EDITOR, "emacs"); |
342 |
✗✓ |
6 |
if (rl_terminal_name != NULL) |
343 |
|
|
el_set(e, EL_TERMINAL, rl_terminal_name); |
344 |
|
|
else |
345 |
|
6 |
el_get(e, EL_TERMINAL, &rl_terminal_name); |
346 |
|
|
|
347 |
|
|
/* |
348 |
|
|
* Word completion - this has to go AFTER rebinding keys |
349 |
|
|
* to emacs-style. |
350 |
|
|
*/ |
351 |
|
6 |
el_set(e, EL_ADDFN, "rl_complete", |
352 |
|
|
"ReadLine compatible completion function", |
353 |
|
|
_el_rl_complete); |
354 |
|
6 |
el_set(e, EL_BIND, "^I", "rl_complete", NULL); |
355 |
|
|
|
356 |
|
|
/* |
357 |
|
|
* Send TSTP when ^Z is pressed. |
358 |
|
|
*/ |
359 |
|
6 |
el_set(e, EL_ADDFN, "rl_tstp", |
360 |
|
|
"ReadLine compatible suspend function", |
361 |
|
|
_el_rl_tstp); |
362 |
|
6 |
el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); |
363 |
|
|
|
364 |
|
|
/* read settings from configuration file */ |
365 |
|
6 |
el_source(e, NULL); |
366 |
|
|
|
367 |
|
|
/* |
368 |
|
|
* Unfortunately, some applications really do use rl_point |
369 |
|
|
* and rl_line_buffer directly. |
370 |
|
|
*/ |
371 |
|
6 |
_resize_fun(e, &rl_line_buffer); |
372 |
|
6 |
_rl_update_pos(); |
373 |
|
|
|
374 |
✗✓ |
6 |
if (rl_startup_hook) |
375 |
|
|
(*rl_startup_hook)(NULL, 0); |
376 |
|
|
|
377 |
|
6 |
return 0; |
378 |
|
6 |
} |
379 |
|
|
|
380 |
|
|
|
381 |
|
|
/* |
382 |
|
|
* read one line from input stream and return it, chomping |
383 |
|
|
* trailing newline (if there is any) |
384 |
|
|
*/ |
385 |
|
|
char * |
386 |
|
|
readline(const char *p) |
387 |
|
|
{ |
388 |
|
|
HistEvent ev; |
389 |
|
|
const char * volatile prompt = p; |
390 |
|
|
int count; |
391 |
|
|
const char *ret; |
392 |
|
|
char *buf; |
393 |
|
|
static int used_event_hook; |
394 |
|
|
|
395 |
|
|
if (e == NULL || h == NULL) |
396 |
|
|
rl_initialize(); |
397 |
|
|
|
398 |
|
|
rl_done = 0; |
399 |
|
|
|
400 |
|
|
(void)setjmp(topbuf); |
401 |
|
|
|
402 |
|
|
/* update prompt accordingly to what has been passed */ |
403 |
|
|
if (rl_set_prompt(prompt) == -1) |
404 |
|
|
return NULL; |
405 |
|
|
|
406 |
|
|
if (rl_pre_input_hook) |
407 |
|
|
(*rl_pre_input_hook)(NULL, 0); |
408 |
|
|
|
409 |
|
|
if (rl_event_hook && !(e->el_flags&NO_TTY)) { |
410 |
|
|
el_set(e, EL_GETCFN, _rl_event_read_char); |
411 |
|
|
used_event_hook = 1; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
if (!rl_event_hook && used_event_hook) { |
415 |
|
|
el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); |
416 |
|
|
used_event_hook = 0; |
417 |
|
|
} |
418 |
|
|
|
419 |
|
|
rl_already_prompted = 0; |
420 |
|
|
|
421 |
|
|
/* get one line from input stream */ |
422 |
|
|
ret = el_gets(e, &count); |
423 |
|
|
|
424 |
|
|
if (ret && count > 0) { |
425 |
|
|
int lastidx; |
426 |
|
|
|
427 |
|
|
buf = strdup(ret); |
428 |
|
|
if (buf == NULL) |
429 |
|
|
return NULL; |
430 |
|
|
lastidx = count - 1; |
431 |
|
|
if (buf[lastidx] == '\n') |
432 |
|
|
buf[lastidx] = '\0'; |
433 |
|
|
} else |
434 |
|
|
buf = NULL; |
435 |
|
|
|
436 |
|
|
history(h, &ev, H_GETSIZE); |
437 |
|
|
history_length = ev.num; |
438 |
|
|
|
439 |
|
|
return buf; |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
/* |
443 |
|
|
* history functions |
444 |
|
|
*/ |
445 |
|
|
|
446 |
|
|
/* |
447 |
|
|
* is normally called before application starts to use |
448 |
|
|
* history expansion functions |
449 |
|
|
*/ |
450 |
|
|
void |
451 |
|
|
using_history(void) |
452 |
|
|
{ |
453 |
✓✓ |
96 |
if (h == NULL || e == NULL) |
454 |
|
6 |
rl_initialize(); |
455 |
|
48 |
} |
456 |
|
|
|
457 |
|
|
|
458 |
|
|
/* |
459 |
|
|
* substitute ``what'' with ``with'', returning resulting string; if |
460 |
|
|
* globally == 1, substitutes all occurrences of what, otherwise only the |
461 |
|
|
* first one |
462 |
|
|
*/ |
463 |
|
|
static char * |
464 |
|
|
_rl_compat_sub(const char *str, const char *what, const char *with, |
465 |
|
|
int globally) |
466 |
|
|
{ |
467 |
|
|
const char *s; |
468 |
|
|
char *r, *result; |
469 |
|
|
size_t len, with_len, what_len; |
470 |
|
|
|
471 |
|
|
len = strlen(str); |
472 |
|
|
with_len = strlen(with); |
473 |
|
|
what_len = strlen(what); |
474 |
|
|
|
475 |
|
|
/* calculate length we need for result */ |
476 |
|
|
s = str; |
477 |
|
|
while (*s) { |
478 |
|
|
if (*s == *what && !strncmp(s, what, what_len)) { |
479 |
|
|
len += with_len - what_len; |
480 |
|
|
if (!globally) |
481 |
|
|
break; |
482 |
|
|
s += what_len; |
483 |
|
|
} else |
484 |
|
|
s++; |
485 |
|
|
} |
486 |
|
|
r = result = malloc(len + 1); |
487 |
|
|
if (result == NULL) |
488 |
|
|
return NULL; |
489 |
|
|
s = str; |
490 |
|
|
while (*s) { |
491 |
|
|
if (*s == *what && !strncmp(s, what, what_len)) { |
492 |
|
|
(void)strncpy(r, with, with_len); |
493 |
|
|
r += with_len; |
494 |
|
|
s += what_len; |
495 |
|
|
if (!globally) { |
496 |
|
|
(void)strlcpy(r, s, len); |
497 |
|
|
return result; |
498 |
|
|
} |
499 |
|
|
} else |
500 |
|
|
*r++ = *s++; |
501 |
|
|
} |
502 |
|
|
*r = '\0'; |
503 |
|
|
return result; |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
static char *last_search_pat; /* last !?pat[?] search pattern */ |
507 |
|
|
static char *last_search_match; /* last !?pat[?] that matched */ |
508 |
|
|
|
509 |
|
|
const char * |
510 |
|
|
get_history_event(const char *cmd, int *cindex, int qchar) |
511 |
|
|
{ |
512 |
|
|
int idx, sign, sub, num, begin, ret; |
513 |
|
|
size_t len; |
514 |
|
|
char *pat; |
515 |
|
|
const char *rptr; |
516 |
|
|
HistEvent ev; |
517 |
|
|
|
518 |
|
|
idx = *cindex; |
519 |
|
|
if (cmd[idx++] != history_expansion_char) |
520 |
|
|
return NULL; |
521 |
|
|
|
522 |
|
|
/* find out which event to take */ |
523 |
|
|
if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { |
524 |
|
|
if (history(h, &ev, H_FIRST) != 0) |
525 |
|
|
return NULL; |
526 |
|
|
*cindex = cmd[idx]? (idx + 1):idx; |
527 |
|
|
return ev.str; |
528 |
|
|
} |
529 |
|
|
sign = 0; |
530 |
|
|
if (cmd[idx] == '-') { |
531 |
|
|
sign = 1; |
532 |
|
|
idx++; |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
if ('0' <= cmd[idx] && cmd[idx] <= '9') { |
536 |
|
|
HIST_ENTRY *rl_he; |
537 |
|
|
|
538 |
|
|
num = 0; |
539 |
|
|
while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { |
540 |
|
|
num = num * 10 + cmd[idx] - '0'; |
541 |
|
|
idx++; |
542 |
|
|
} |
543 |
|
|
if (sign) |
544 |
|
|
num = history_length - num + 1; |
545 |
|
|
|
546 |
|
|
if (!(rl_he = history_get(num))) |
547 |
|
|
return NULL; |
548 |
|
|
|
549 |
|
|
*cindex = idx; |
550 |
|
|
return rl_he->line; |
551 |
|
|
} |
552 |
|
|
sub = 0; |
553 |
|
|
if (cmd[idx] == '?') { |
554 |
|
|
sub = 1; |
555 |
|
|
idx++; |
556 |
|
|
} |
557 |
|
|
begin = idx; |
558 |
|
|
while (cmd[idx]) { |
559 |
|
|
if (cmd[idx] == '\n') |
560 |
|
|
break; |
561 |
|
|
if (sub && cmd[idx] == '?') |
562 |
|
|
break; |
563 |
|
|
if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' |
564 |
|
|
|| cmd[idx] == '\t' || cmd[idx] == qchar)) |
565 |
|
|
break; |
566 |
|
|
idx++; |
567 |
|
|
} |
568 |
|
|
len = idx - begin; |
569 |
|
|
if (sub && cmd[idx] == '?') |
570 |
|
|
idx++; |
571 |
|
|
if (sub && len == 0 && last_search_pat && *last_search_pat) |
572 |
|
|
pat = last_search_pat; |
573 |
|
|
else if (len == 0) |
574 |
|
|
return NULL; |
575 |
|
|
else { |
576 |
|
|
if ((pat = malloc(len + 1)) == NULL) |
577 |
|
|
return NULL; |
578 |
|
|
(void)strncpy(pat, cmd + begin, len); |
579 |
|
|
pat[len] = '\0'; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
if (history(h, &ev, H_CURR) != 0) { |
583 |
|
|
if (pat != last_search_pat) |
584 |
|
|
free(pat); |
585 |
|
|
return NULL; |
586 |
|
|
} |
587 |
|
|
num = ev.num; |
588 |
|
|
|
589 |
|
|
if (sub) { |
590 |
|
|
if (pat != last_search_pat) { |
591 |
|
|
if (last_search_pat) |
592 |
|
|
free(last_search_pat); |
593 |
|
|
last_search_pat = pat; |
594 |
|
|
} |
595 |
|
|
ret = history_search(pat, -1); |
596 |
|
|
} else |
597 |
|
|
ret = history_search_prefix(pat, -1); |
598 |
|
|
|
599 |
|
|
if (ret == -1) { |
600 |
|
|
/* restore to end of list on failed search */ |
601 |
|
|
history(h, &ev, H_FIRST); |
602 |
|
|
(void)fprintf(rl_outstream, "%s: Event not found\n", pat); |
603 |
|
|
if (pat != last_search_pat) |
604 |
|
|
free(pat); |
605 |
|
|
return NULL; |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
if (sub && len) { |
609 |
|
|
if (last_search_match && last_search_match != pat) |
610 |
|
|
free(last_search_match); |
611 |
|
|
last_search_match = pat; |
612 |
|
|
} |
613 |
|
|
|
614 |
|
|
if (pat != last_search_pat) |
615 |
|
|
free(pat); |
616 |
|
|
|
617 |
|
|
if (history(h, &ev, H_CURR) != 0) |
618 |
|
|
return NULL; |
619 |
|
|
*cindex = idx; |
620 |
|
|
rptr = ev.str; |
621 |
|
|
|
622 |
|
|
/* roll back to original position */ |
623 |
|
|
(void)history(h, &ev, H_SET, num); |
624 |
|
|
|
625 |
|
|
return rptr; |
626 |
|
|
} |
627 |
|
|
|
628 |
|
|
/* |
629 |
|
|
* the real function doing history expansion - takes as argument command |
630 |
|
|
* to do and data upon which the command should be executed |
631 |
|
|
* does expansion the way I've understood readline documentation |
632 |
|
|
* |
633 |
|
|
* returns 0 if data was not modified, 1 if it was and 2 if the string |
634 |
|
|
* should be only printed and not executed; in case of error, |
635 |
|
|
* returns -1 and *result points to NULL |
636 |
|
|
* it's the caller's responsibility to free() the string returned in *result |
637 |
|
|
*/ |
638 |
|
|
static int |
639 |
|
|
_history_expand_command(const char *command, size_t offs, size_t cmdlen, |
640 |
|
|
char **result) |
641 |
|
|
{ |
642 |
|
|
char *tmp, *search = NULL, *aptr; |
643 |
|
|
const char *ptr, *cmd; |
644 |
|
|
static char *from = NULL, *to = NULL; |
645 |
|
|
int start, end, idx, has_mods = 0; |
646 |
|
|
int p_on = 0, g_on = 0; |
647 |
|
|
|
648 |
|
|
*result = NULL; |
649 |
|
|
aptr = NULL; |
650 |
|
|
ptr = NULL; |
651 |
|
|
|
652 |
|
|
/* First get event specifier */ |
653 |
|
|
idx = 0; |
654 |
|
|
|
655 |
|
|
if (strchr(":^*$", command[offs + 1])) { |
656 |
|
|
char str[4]; |
657 |
|
|
/* |
658 |
|
|
* "!:" is shorthand for "!!:". |
659 |
|
|
* "!^", "!*" and "!$" are shorthand for |
660 |
|
|
* "!!:^", "!!:*" and "!!:$" respectively. |
661 |
|
|
*/ |
662 |
|
|
str[0] = str[1] = '!'; |
663 |
|
|
str[2] = '0'; |
664 |
|
|
ptr = get_history_event(str, &idx, 0); |
665 |
|
|
idx = (command[offs + 1] == ':')? 1:0; |
666 |
|
|
has_mods = 1; |
667 |
|
|
} else { |
668 |
|
|
if (command[offs + 1] == '#') { |
669 |
|
|
/* use command so far */ |
670 |
|
|
if ((aptr = malloc(offs + 1)) == NULL) |
671 |
|
|
return -1; |
672 |
|
|
(void)strncpy(aptr, command, offs); |
673 |
|
|
aptr[offs] = '\0'; |
674 |
|
|
idx = 1; |
675 |
|
|
} else { |
676 |
|
|
int qchar; |
677 |
|
|
|
678 |
|
|
qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; |
679 |
|
|
ptr = get_history_event(command + offs, &idx, qchar); |
680 |
|
|
} |
681 |
|
|
has_mods = command[offs + idx] == ':'; |
682 |
|
|
} |
683 |
|
|
|
684 |
|
|
if (ptr == NULL && aptr == NULL) |
685 |
|
|
return -1; |
686 |
|
|
|
687 |
|
|
if (!has_mods) { |
688 |
|
|
*result = strdup(aptr ? aptr : ptr); |
689 |
|
|
if (aptr) |
690 |
|
|
free(aptr); |
691 |
|
|
if (*result == NULL) |
692 |
|
|
return -1; |
693 |
|
|
return 1; |
694 |
|
|
} |
695 |
|
|
|
696 |
|
|
cmd = command + offs + idx + 1; |
697 |
|
|
|
698 |
|
|
/* Now parse any word designators */ |
699 |
|
|
|
700 |
|
|
if (*cmd == '%') /* last word matched by ?pat? */ |
701 |
|
|
tmp = strdup(last_search_match? last_search_match:""); |
702 |
|
|
else if (strchr("^*$-0123456789", *cmd)) { |
703 |
|
|
start = end = -1; |
704 |
|
|
if (*cmd == '^') |
705 |
|
|
start = end = 1, cmd++; |
706 |
|
|
else if (*cmd == '$') |
707 |
|
|
start = -1, cmd++; |
708 |
|
|
else if (*cmd == '*') |
709 |
|
|
start = 1, cmd++; |
710 |
|
|
else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { |
711 |
|
|
start = 0; |
712 |
|
|
while (*cmd && '0' <= *cmd && *cmd <= '9') |
713 |
|
|
start = start * 10 + *cmd++ - '0'; |
714 |
|
|
|
715 |
|
|
if (*cmd == '-') { |
716 |
|
|
if (isdigit((unsigned char) cmd[1])) { |
717 |
|
|
cmd++; |
718 |
|
|
end = 0; |
719 |
|
|
while (*cmd && '0' <= *cmd && *cmd <= '9') |
720 |
|
|
end = end * 10 + *cmd++ - '0'; |
721 |
|
|
} else if (cmd[1] == '$') { |
722 |
|
|
cmd += 2; |
723 |
|
|
end = -1; |
724 |
|
|
} else { |
725 |
|
|
cmd++; |
726 |
|
|
end = -2; |
727 |
|
|
} |
728 |
|
|
} else if (*cmd == '*') |
729 |
|
|
end = -1, cmd++; |
730 |
|
|
else |
731 |
|
|
end = start; |
732 |
|
|
} |
733 |
|
|
tmp = history_arg_extract(start, end, aptr? aptr:ptr); |
734 |
|
|
if (tmp == NULL) { |
735 |
|
|
(void)fprintf(rl_outstream, "%s: Bad word specifier", |
736 |
|
|
command + offs + idx); |
737 |
|
|
if (aptr) |
738 |
|
|
free(aptr); |
739 |
|
|
return -1; |
740 |
|
|
} |
741 |
|
|
} else |
742 |
|
|
tmp = strdup(aptr? aptr:ptr); |
743 |
|
|
|
744 |
|
|
if (aptr) |
745 |
|
|
free(aptr); |
746 |
|
|
|
747 |
|
|
if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { |
748 |
|
|
*result = tmp; |
749 |
|
|
return 1; |
750 |
|
|
} |
751 |
|
|
|
752 |
|
|
for (; *cmd; cmd++) { |
753 |
|
|
if (*cmd == ':') |
754 |
|
|
continue; |
755 |
|
|
else if (*cmd == 'h') { /* remove trailing path */ |
756 |
|
|
if ((aptr = strrchr(tmp, '/')) != NULL) |
757 |
|
|
*aptr = '\0'; |
758 |
|
|
} else if (*cmd == 't') { /* remove leading path */ |
759 |
|
|
if ((aptr = strrchr(tmp, '/')) != NULL) { |
760 |
|
|
aptr = strdup(aptr + 1); |
761 |
|
|
free(tmp); |
762 |
|
|
tmp = aptr; |
763 |
|
|
} |
764 |
|
|
} else if (*cmd == 'r') { /* remove trailing suffix */ |
765 |
|
|
if ((aptr = strrchr(tmp, '.')) != NULL) |
766 |
|
|
*aptr = '\0'; |
767 |
|
|
} else if (*cmd == 'e') { /* remove all but suffix */ |
768 |
|
|
if ((aptr = strrchr(tmp, '.')) != NULL) { |
769 |
|
|
aptr = strdup(aptr); |
770 |
|
|
free(tmp); |
771 |
|
|
tmp = aptr; |
772 |
|
|
} |
773 |
|
|
} else if (*cmd == 'p') /* print only */ |
774 |
|
|
p_on = 1; |
775 |
|
|
else if (*cmd == 'g') |
776 |
|
|
g_on = 2; |
777 |
|
|
else if (*cmd == 's' || *cmd == '&') { |
778 |
|
|
char *what, *with, delim; |
779 |
|
|
size_t len, from_len; |
780 |
|
|
size_t size; |
781 |
|
|
|
782 |
|
|
if (*cmd == '&' && (from == NULL || to == NULL)) |
783 |
|
|
continue; |
784 |
|
|
else if (*cmd == 's') { |
785 |
|
|
delim = *(++cmd), cmd++; |
786 |
|
|
size = 16; |
787 |
|
|
what = realloc(from, size); |
788 |
|
|
if (what == NULL) { |
789 |
|
|
free(from); |
790 |
|
|
free(tmp); |
791 |
|
|
return 0; |
792 |
|
|
} |
793 |
|
|
len = 0; |
794 |
|
|
for (; *cmd && *cmd != delim; cmd++) { |
795 |
|
|
if (*cmd == '\\' && cmd[1] == delim) |
796 |
|
|
cmd++; |
797 |
|
|
if (len >= size) { |
798 |
|
|
char *nwhat; |
799 |
|
|
nwhat = reallocarray(what, |
800 |
|
|
size, 2); |
801 |
|
|
if (nwhat == NULL) { |
802 |
|
|
free(what); |
803 |
|
|
free(tmp); |
804 |
|
|
return 0; |
805 |
|
|
} |
806 |
|
|
size *= 2; |
807 |
|
|
what = nwhat; |
808 |
|
|
} |
809 |
|
|
what[len++] = *cmd; |
810 |
|
|
} |
811 |
|
|
what[len] = '\0'; |
812 |
|
|
from = what; |
813 |
|
|
if (*what == '\0') { |
814 |
|
|
free(what); |
815 |
|
|
if (search) { |
816 |
|
|
from = strdup(search); |
817 |
|
|
if (from == NULL) { |
818 |
|
|
free(tmp); |
819 |
|
|
return 0; |
820 |
|
|
} |
821 |
|
|
} else { |
822 |
|
|
from = NULL; |
823 |
|
|
free(tmp); |
824 |
|
|
return -1; |
825 |
|
|
} |
826 |
|
|
} |
827 |
|
|
cmd++; /* shift after delim */ |
828 |
|
|
if (!*cmd) |
829 |
|
|
continue; |
830 |
|
|
|
831 |
|
|
size = 16; |
832 |
|
|
with = realloc(to, size); |
833 |
|
|
if (with == NULL) { |
834 |
|
|
free(to); |
835 |
|
|
free(tmp); |
836 |
|
|
return -1; |
837 |
|
|
} |
838 |
|
|
len = 0; |
839 |
|
|
from_len = strlen(from); |
840 |
|
|
for (; *cmd && *cmd != delim; cmd++) { |
841 |
|
|
if (len + from_len + 1 >= size) { |
842 |
|
|
char *nwith; |
843 |
|
|
size += from_len + 1; |
844 |
|
|
nwith = realloc(with, size); |
845 |
|
|
if (nwith == NULL) { |
846 |
|
|
free(with); |
847 |
|
|
free(tmp); |
848 |
|
|
return -1; |
849 |
|
|
} |
850 |
|
|
with = nwith; |
851 |
|
|
} |
852 |
|
|
if (*cmd == '&') { |
853 |
|
|
/* safe */ |
854 |
|
|
(void)strlcpy(&with[len], from, |
855 |
|
|
size - len); |
856 |
|
|
len += from_len; |
857 |
|
|
continue; |
858 |
|
|
} |
859 |
|
|
if (*cmd == '\\' |
860 |
|
|
&& (*(cmd + 1) == delim |
861 |
|
|
|| *(cmd + 1) == '&')) |
862 |
|
|
cmd++; |
863 |
|
|
with[len++] = *cmd; |
864 |
|
|
} |
865 |
|
|
with[len] = '\0'; |
866 |
|
|
to = with; |
867 |
|
|
} |
868 |
|
|
|
869 |
|
|
aptr = _rl_compat_sub(tmp, from, to, g_on); |
870 |
|
|
if (aptr) { |
871 |
|
|
free(tmp); |
872 |
|
|
tmp = aptr; |
873 |
|
|
} |
874 |
|
|
g_on = 0; |
875 |
|
|
} |
876 |
|
|
} |
877 |
|
|
*result = tmp; |
878 |
|
|
return p_on? 2:1; |
879 |
|
|
} |
880 |
|
|
|
881 |
|
|
|
882 |
|
|
/* |
883 |
|
|
* csh-style history expansion |
884 |
|
|
*/ |
885 |
|
|
int |
886 |
|
|
history_expand(char *str, char **output) |
887 |
|
|
{ |
888 |
|
|
int ret = 0; |
889 |
|
|
size_t idx, i, size; |
890 |
|
|
char *tmp, *result; |
891 |
|
|
|
892 |
|
|
if (h == NULL || e == NULL) |
893 |
|
|
rl_initialize(); |
894 |
|
|
|
895 |
|
|
if (history_expansion_char == 0) { |
896 |
|
|
*output = strdup(str); |
897 |
|
|
return 0; |
898 |
|
|
} |
899 |
|
|
|
900 |
|
|
*output = NULL; |
901 |
|
|
if (str[0] == history_subst_char) { |
902 |
|
|
/* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ |
903 |
|
|
size_t sz = 4 + strlen(str) + 1; |
904 |
|
|
*output = malloc(sz); |
905 |
|
|
if (*output == NULL) |
906 |
|
|
return 0; |
907 |
|
|
(*output)[0] = (*output)[1] = history_expansion_char; |
908 |
|
|
(*output)[2] = ':'; |
909 |
|
|
(*output)[3] = 's'; |
910 |
|
|
(void)strlcpy((*output) + 4, str, sz - 4); |
911 |
|
|
str = *output; |
912 |
|
|
} else { |
913 |
|
|
*output = strdup(str); |
914 |
|
|
if (*output == NULL) |
915 |
|
|
return 0; |
916 |
|
|
} |
917 |
|
|
|
918 |
|
|
#define ADD_STRING(what, len, fr) \ |
919 |
|
|
{ \ |
920 |
|
|
if (idx + len + 1 > size) { \ |
921 |
|
|
char *nresult = realloc(result, (size += len + 1));\ |
922 |
|
|
if (nresult == NULL) { \ |
923 |
|
|
free(*output); \ |
924 |
|
|
if (/*CONSTCOND*/fr) \ |
925 |
|
|
free(tmp); \ |
926 |
|
|
return 0; \ |
927 |
|
|
} \ |
928 |
|
|
result = nresult; \ |
929 |
|
|
} \ |
930 |
|
|
(void)strncpy(&result[idx], what, len); \ |
931 |
|
|
idx += len; \ |
932 |
|
|
result[idx] = '\0'; \ |
933 |
|
|
} |
934 |
|
|
|
935 |
|
|
result = NULL; |
936 |
|
|
size = idx = 0; |
937 |
|
|
tmp = NULL; |
938 |
|
|
for (i = 0; str[i];) { |
939 |
|
|
int qchar, loop_again; |
940 |
|
|
size_t len, start, j; |
941 |
|
|
|
942 |
|
|
qchar = 0; |
943 |
|
|
loop_again = 1; |
944 |
|
|
start = j = i; |
945 |
|
|
loop: |
946 |
|
|
for (; str[j]; j++) { |
947 |
|
|
if (str[j] == '\\' && |
948 |
|
|
str[j + 1] == history_expansion_char) { |
949 |
|
|
size_t sz = strlen(&str[j]) + 1; |
950 |
|
|
(void)strlcpy(&str[j], &str[j + 1], sz); |
951 |
|
|
continue; |
952 |
|
|
} |
953 |
|
|
if (!loop_again) { |
954 |
|
|
if (isspace((unsigned char) str[j]) |
955 |
|
|
|| str[j] == qchar) |
956 |
|
|
break; |
957 |
|
|
} |
958 |
|
|
if (str[j] == history_expansion_char |
959 |
|
|
&& !strchr(history_no_expand_chars, str[j + 1]) |
960 |
|
|
&& (!history_inhibit_expansion_function || |
961 |
|
|
(*history_inhibit_expansion_function)(str, |
962 |
|
|
(int)j) == 0)) |
963 |
|
|
break; |
964 |
|
|
} |
965 |
|
|
|
966 |
|
|
if (str[j] && loop_again) { |
967 |
|
|
i = j; |
968 |
|
|
qchar = (j > 0 && str[j - 1] == '"' )? '"':0; |
969 |
|
|
j++; |
970 |
|
|
if (str[j] == history_expansion_char) |
971 |
|
|
j++; |
972 |
|
|
loop_again = 0; |
973 |
|
|
goto loop; |
974 |
|
|
} |
975 |
|
|
len = i - start; |
976 |
|
|
ADD_STRING(&str[start], len, 0); |
977 |
|
|
|
978 |
|
|
if (str[i] == '\0' || str[i] != history_expansion_char) { |
979 |
|
|
len = j - i; |
980 |
|
|
ADD_STRING(&str[i], len, 0); |
981 |
|
|
if (start == 0) |
982 |
|
|
ret = 0; |
983 |
|
|
else |
984 |
|
|
ret = 1; |
985 |
|
|
break; |
986 |
|
|
} |
987 |
|
|
ret = _history_expand_command (str, i, (j - i), &tmp); |
988 |
|
|
if (ret > 0 && tmp) { |
989 |
|
|
len = strlen(tmp); |
990 |
|
|
ADD_STRING(tmp, len, 1); |
991 |
|
|
} |
992 |
|
|
if (tmp) { |
993 |
|
|
free(tmp); |
994 |
|
|
tmp = NULL; |
995 |
|
|
} |
996 |
|
|
i = j; |
997 |
|
|
} |
998 |
|
|
|
999 |
|
|
/* ret is 2 for "print only" option */ |
1000 |
|
|
if (ret == 2) { |
1001 |
|
|
add_history(result); |
1002 |
|
|
#ifdef GDB_411_HACK |
1003 |
|
|
/* gdb 4.11 has been shipped with readline, where */ |
1004 |
|
|
/* history_expand() returned -1 when the line */ |
1005 |
|
|
/* should not be executed; in readline 2.1+ */ |
1006 |
|
|
/* it should return 2 in such a case */ |
1007 |
|
|
ret = -1; |
1008 |
|
|
#endif |
1009 |
|
|
} |
1010 |
|
|
free(*output); |
1011 |
|
|
*output = result; |
1012 |
|
|
|
1013 |
|
|
return ret; |
1014 |
|
|
} |
1015 |
|
|
|
1016 |
|
|
/* |
1017 |
|
|
* Return a string consisting of arguments of "str" from "start" to "end". |
1018 |
|
|
*/ |
1019 |
|
|
char * |
1020 |
|
|
history_arg_extract(int start, int end, const char *str) |
1021 |
|
|
{ |
1022 |
|
|
size_t i, len, max; |
1023 |
|
|
char **arr, *result = NULL; |
1024 |
|
|
|
1025 |
|
|
arr = history_tokenize(str); |
1026 |
|
|
if (!arr) |
1027 |
|
|
return NULL; |
1028 |
|
|
if (arr && *arr == NULL) |
1029 |
|
|
goto out; |
1030 |
|
|
|
1031 |
|
|
for (max = 0; arr[max]; max++) |
1032 |
|
|
continue; |
1033 |
|
|
max--; |
1034 |
|
|
|
1035 |
|
|
if (start == '$') |
1036 |
|
|
start = (int)max; |
1037 |
|
|
if (end == '$') |
1038 |
|
|
end = (int)max; |
1039 |
|
|
if (end < 0) |
1040 |
|
|
end = (int)max + end + 1; |
1041 |
|
|
if (start < 0) |
1042 |
|
|
start = end; |
1043 |
|
|
|
1044 |
|
|
if (start < 0 || end < 0 || (size_t)start > max || |
1045 |
|
|
(size_t)end > max || start > end) |
1046 |
|
|
goto out; |
1047 |
|
|
|
1048 |
|
|
for (i = start, len = 0; i <= (size_t)end; i++) |
1049 |
|
|
len += strlen(arr[i]) + 1; |
1050 |
|
|
len++; |
1051 |
|
|
max = len; |
1052 |
|
|
result = malloc(len); |
1053 |
|
|
if (result == NULL) |
1054 |
|
|
goto out; |
1055 |
|
|
|
1056 |
|
|
for (i = start, len = 0; i <= (size_t)end; i++) { |
1057 |
|
|
(void)strlcpy(result + len, arr[i], max - len); |
1058 |
|
|
len += strlen(arr[i]); |
1059 |
|
|
if (i < (size_t)end) |
1060 |
|
|
result[len++] = ' '; |
1061 |
|
|
} |
1062 |
|
|
result[len] = '\0'; |
1063 |
|
|
|
1064 |
|
|
out: |
1065 |
|
|
for (i = 0; arr[i]; i++) |
1066 |
|
|
free(arr[i]); |
1067 |
|
|
free(arr); |
1068 |
|
|
|
1069 |
|
|
return result; |
1070 |
|
|
} |
1071 |
|
|
|
1072 |
|
|
/* |
1073 |
|
|
* Parse the string into individual tokens, |
1074 |
|
|
* similar to how shell would do it. |
1075 |
|
|
*/ |
1076 |
|
|
char ** |
1077 |
|
|
history_tokenize(const char *str) |
1078 |
|
|
{ |
1079 |
|
|
int size = 1, idx = 0, i, start; |
1080 |
|
|
size_t len; |
1081 |
|
|
char **result = NULL, *temp, delim = '\0'; |
1082 |
|
|
|
1083 |
|
|
for (i = 0; str[i];) { |
1084 |
|
|
while (isspace((unsigned char) str[i])) |
1085 |
|
|
i++; |
1086 |
|
|
start = i; |
1087 |
|
|
for (; str[i];) { |
1088 |
|
|
if (str[i] == '\\') { |
1089 |
|
|
if (str[i+1] != '\0') |
1090 |
|
|
i++; |
1091 |
|
|
} else if (str[i] == delim) |
1092 |
|
|
delim = '\0'; |
1093 |
|
|
else if (!delim && |
1094 |
|
|
(isspace((unsigned char) str[i]) || |
1095 |
|
|
strchr("()<>;&|$", str[i]))) |
1096 |
|
|
break; |
1097 |
|
|
else if (!delim && strchr("'`\"", str[i])) |
1098 |
|
|
delim = str[i]; |
1099 |
|
|
if (str[i]) |
1100 |
|
|
i++; |
1101 |
|
|
} |
1102 |
|
|
|
1103 |
|
|
if (idx + 2 >= size) { |
1104 |
|
|
char **nresult; |
1105 |
|
|
nresult = reallocarray(result, size, |
1106 |
|
|
2 * sizeof(char *)); |
1107 |
|
|
if (nresult == NULL) { |
1108 |
|
|
free(result); |
1109 |
|
|
return NULL; |
1110 |
|
|
} |
1111 |
|
|
size *= 2; |
1112 |
|
|
result = nresult; |
1113 |
|
|
} |
1114 |
|
|
len = i - start; |
1115 |
|
|
temp = malloc(len + 1); |
1116 |
|
|
if (temp == NULL) { |
1117 |
|
|
for (i = 0; i < idx; i++) |
1118 |
|
|
free(result[i]); |
1119 |
|
|
free(result); |
1120 |
|
|
return NULL; |
1121 |
|
|
} |
1122 |
|
|
(void)strncpy(temp, &str[start], len); |
1123 |
|
|
temp[len] = '\0'; |
1124 |
|
|
result[idx++] = temp; |
1125 |
|
|
result[idx] = NULL; |
1126 |
|
|
if (str[i]) |
1127 |
|
|
i++; |
1128 |
|
|
} |
1129 |
|
|
return result; |
1130 |
|
|
} |
1131 |
|
|
|
1132 |
|
|
|
1133 |
|
|
/* |
1134 |
|
|
* limit size of history record to ``max'' events |
1135 |
|
|
*/ |
1136 |
|
|
void |
1137 |
|
|
stifle_history(int max) |
1138 |
|
|
{ |
1139 |
|
24 |
HistEvent ev; |
1140 |
|
|
HIST_ENTRY *he; |
1141 |
|
|
int i, len; |
1142 |
|
|
|
1143 |
✗✓ |
12 |
if (h == NULL || e == NULL) |
1144 |
|
|
rl_initialize(); |
1145 |
|
|
|
1146 |
|
12 |
len = history_length; |
1147 |
✓✗ |
12 |
if (history(h, &ev, H_SETSIZE, max) == 0) { |
1148 |
|
12 |
max_input_history = max; |
1149 |
✓✓ |
12 |
if (max < len) |
1150 |
|
6 |
history_base += len - max; |
1151 |
✓✓ |
36 |
for (i = 0; i < len - max; i++) { |
1152 |
|
6 |
he = remove_history(0); |
1153 |
|
6 |
free(he->data); |
1154 |
|
6 |
free((void *)he->line); |
1155 |
|
6 |
free(he); |
1156 |
|
|
} |
1157 |
|
|
} |
1158 |
|
12 |
} |
1159 |
|
|
|
1160 |
|
|
|
1161 |
|
|
/* |
1162 |
|
|
* "unlimit" size of history - set the limit to maximum allowed int value |
1163 |
|
|
*/ |
1164 |
|
|
int |
1165 |
|
|
unstifle_history(void) |
1166 |
|
|
{ |
1167 |
|
192 |
HistEvent ev; |
1168 |
|
|
int omax; |
1169 |
|
|
|
1170 |
|
96 |
history(h, &ev, H_SETSIZE, INT_MAX); |
1171 |
|
96 |
omax = max_input_history; |
1172 |
|
96 |
max_input_history = INT_MAX; |
1173 |
|
96 |
return omax; /* some value _must_ be returned */ |
1174 |
|
96 |
} |
1175 |
|
|
|
1176 |
|
|
|
1177 |
|
|
int |
1178 |
|
|
history_is_stifled(void) |
1179 |
|
|
{ |
1180 |
|
|
|
1181 |
|
|
/* cannot return true answer */ |
1182 |
|
|
return max_input_history != INT_MAX; |
1183 |
|
|
} |
1184 |
|
|
|
1185 |
|
|
static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; |
1186 |
|
|
|
1187 |
|
|
int |
1188 |
|
|
history_truncate_file (const char *filename, int nlines) |
1189 |
|
|
{ |
1190 |
|
|
int ret = 0; |
1191 |
|
|
FILE *fp, *tp; |
1192 |
|
|
char template[sizeof(_history_tmp_template)]; |
1193 |
|
|
char buf[4096]; |
1194 |
|
|
int fd; |
1195 |
|
|
char *cp; |
1196 |
|
|
off_t off; |
1197 |
|
|
int count = 0; |
1198 |
|
|
ssize_t left = 0; |
1199 |
|
|
|
1200 |
|
|
if (filename == NULL && (filename = _default_history_file()) == NULL) |
1201 |
|
|
return errno; |
1202 |
|
|
if ((fp = fopen(filename, "r+")) == NULL) |
1203 |
|
|
return errno; |
1204 |
|
|
strlcpy(template, _history_tmp_template, sizeof(template)); |
1205 |
|
|
if ((fd = mkstemp(template)) == -1) { |
1206 |
|
|
ret = errno; |
1207 |
|
|
goto out1; |
1208 |
|
|
} |
1209 |
|
|
|
1210 |
|
|
if ((tp = fdopen(fd, "r+")) == NULL) { |
1211 |
|
|
close(fd); |
1212 |
|
|
ret = errno; |
1213 |
|
|
goto out2; |
1214 |
|
|
} |
1215 |
|
|
|
1216 |
|
|
for(;;) { |
1217 |
|
|
if (fread(buf, sizeof(buf), 1, fp) != 1) { |
1218 |
|
|
if (ferror(fp)) { |
1219 |
|
|
ret = errno; |
1220 |
|
|
break; |
1221 |
|
|
} |
1222 |
|
|
if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == |
1223 |
|
|
(off_t)-1) { |
1224 |
|
|
ret = errno; |
1225 |
|
|
break; |
1226 |
|
|
} |
1227 |
|
|
left = fread(buf, 1, sizeof(buf), fp); |
1228 |
|
|
if (ferror(fp)) { |
1229 |
|
|
ret = errno; |
1230 |
|
|
break; |
1231 |
|
|
} |
1232 |
|
|
if (left == 0) { |
1233 |
|
|
count--; |
1234 |
|
|
left = sizeof(buf); |
1235 |
|
|
} else if (fwrite(buf, (size_t)left, 1, tp) != 1) { |
1236 |
|
|
ret = errno; |
1237 |
|
|
break; |
1238 |
|
|
} |
1239 |
|
|
fflush(tp); |
1240 |
|
|
break; |
1241 |
|
|
} |
1242 |
|
|
if (fwrite(buf, sizeof(buf), 1, tp) != 1) { |
1243 |
|
|
ret = errno; |
1244 |
|
|
break; |
1245 |
|
|
} |
1246 |
|
|
count++; |
1247 |
|
|
} |
1248 |
|
|
if (ret) |
1249 |
|
|
goto out3; |
1250 |
|
|
cp = buf + left - 1; |
1251 |
|
|
if(*cp != '\n') |
1252 |
|
|
cp++; |
1253 |
|
|
for(;;) { |
1254 |
|
|
while (--cp >= buf) { |
1255 |
|
|
if (*cp == '\n') { |
1256 |
|
|
if (--nlines == 0) { |
1257 |
|
|
if (++cp >= buf + sizeof(buf)) { |
1258 |
|
|
count++; |
1259 |
|
|
cp = buf; |
1260 |
|
|
} |
1261 |
|
|
break; |
1262 |
|
|
} |
1263 |
|
|
} |
1264 |
|
|
} |
1265 |
|
|
if (nlines <= 0 || count == 0) |
1266 |
|
|
break; |
1267 |
|
|
count--; |
1268 |
|
|
if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { |
1269 |
|
|
ret = errno; |
1270 |
|
|
break; |
1271 |
|
|
} |
1272 |
|
|
if (fread(buf, sizeof(buf), 1, tp) != 1) { |
1273 |
|
|
if (ferror(tp)) { |
1274 |
|
|
ret = errno; |
1275 |
|
|
break; |
1276 |
|
|
} |
1277 |
|
|
ret = EAGAIN; |
1278 |
|
|
break; |
1279 |
|
|
} |
1280 |
|
|
cp = buf + sizeof(buf); |
1281 |
|
|
} |
1282 |
|
|
|
1283 |
|
|
if (ret || nlines > 0) |
1284 |
|
|
goto out3; |
1285 |
|
|
|
1286 |
|
|
if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { |
1287 |
|
|
ret = errno; |
1288 |
|
|
goto out3; |
1289 |
|
|
} |
1290 |
|
|
|
1291 |
|
|
if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == |
1292 |
|
|
(off_t)-1) { |
1293 |
|
|
ret = errno; |
1294 |
|
|
goto out3; |
1295 |
|
|
} |
1296 |
|
|
|
1297 |
|
|
for(;;) { |
1298 |
|
|
if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { |
1299 |
|
|
if (ferror(fp)) |
1300 |
|
|
ret = errno; |
1301 |
|
|
break; |
1302 |
|
|
} |
1303 |
|
|
if (fwrite(buf, (size_t)left, 1, fp) != 1) { |
1304 |
|
|
ret = errno; |
1305 |
|
|
break; |
1306 |
|
|
} |
1307 |
|
|
} |
1308 |
|
|
fflush(fp); |
1309 |
|
|
if((off = ftello(fp)) > 0) |
1310 |
|
|
(void)ftruncate(fileno(fp), off); |
1311 |
|
|
out3: |
1312 |
|
|
fclose(tp); |
1313 |
|
|
out2: |
1314 |
|
|
unlink(template); |
1315 |
|
|
out1: |
1316 |
|
|
fclose(fp); |
1317 |
|
|
|
1318 |
|
|
return ret; |
1319 |
|
|
} |
1320 |
|
|
|
1321 |
|
|
|
1322 |
|
|
/* |
1323 |
|
|
* read history from a file given |
1324 |
|
|
*/ |
1325 |
|
|
int |
1326 |
|
|
read_history(const char *filename) |
1327 |
|
|
{ |
1328 |
|
|
HistEvent ev; |
1329 |
|
|
|
1330 |
|
|
if (h == NULL || e == NULL) |
1331 |
|
|
rl_initialize(); |
1332 |
|
|
if (filename == NULL && (filename = _default_history_file()) == NULL) |
1333 |
|
|
return errno; |
1334 |
|
|
return history(h, &ev, H_LOAD, filename) == -1 ? |
1335 |
|
|
(errno ? errno : EINVAL) : 0; |
1336 |
|
|
} |
1337 |
|
|
|
1338 |
|
|
|
1339 |
|
|
/* |
1340 |
|
|
* write history to a file given |
1341 |
|
|
*/ |
1342 |
|
|
int |
1343 |
|
|
write_history(const char *filename) |
1344 |
|
|
{ |
1345 |
|
|
HistEvent ev; |
1346 |
|
|
|
1347 |
|
|
if (h == NULL || e == NULL) |
1348 |
|
|
rl_initialize(); |
1349 |
|
|
if (filename == NULL && (filename = _default_history_file()) == NULL) |
1350 |
|
|
return errno; |
1351 |
|
|
return history(h, &ev, H_SAVE, filename) == -1 ? |
1352 |
|
|
(errno ? errno : EINVAL) : 0; |
1353 |
|
|
} |
1354 |
|
|
|
1355 |
|
|
|
1356 |
|
|
/* |
1357 |
|
|
* returns history ``num''th event |
1358 |
|
|
* |
1359 |
|
|
* returned pointer points to static variable |
1360 |
|
|
*/ |
1361 |
|
|
HIST_ENTRY * |
1362 |
|
|
history_get(int num) |
1363 |
|
|
{ |
1364 |
|
|
static HIST_ENTRY she; |
1365 |
|
36 |
HistEvent ev; |
1366 |
|
|
int curr_num; |
1367 |
|
|
|
1368 |
✗✓ |
18 |
if (h == NULL || e == NULL) |
1369 |
|
|
rl_initialize(); |
1370 |
|
|
|
1371 |
✗✓ |
18 |
if (num < history_base) |
1372 |
|
|
return NULL; |
1373 |
|
|
|
1374 |
|
|
/* save current position */ |
1375 |
✗✓ |
18 |
if (history(h, &ev, H_CURR) != 0) |
1376 |
|
|
return NULL; |
1377 |
|
18 |
curr_num = ev.num; |
1378 |
|
|
|
1379 |
|
|
/* |
1380 |
|
|
* use H_DELDATA to set to nth history (without delete) by passing |
1381 |
|
|
* (void **)-1 -- as in history_set_pos |
1382 |
|
|
*/ |
1383 |
✓✗ |
18 |
if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0) |
1384 |
|
|
goto out; |
1385 |
|
|
|
1386 |
|
|
/* get current entry */ |
1387 |
✓✗ |
18 |
if (history(h, &ev, H_CURR) != 0) |
1388 |
|
|
goto out; |
1389 |
✓✗ |
18 |
if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0) |
1390 |
|
|
goto out; |
1391 |
|
18 |
she.line = ev.str; |
1392 |
|
|
|
1393 |
|
|
/* restore pointer to where it was */ |
1394 |
|
18 |
(void)history(h, &ev, H_SET, curr_num); |
1395 |
|
|
|
1396 |
|
18 |
return &she; |
1397 |
|
|
|
1398 |
|
|
out: |
1399 |
|
|
/* restore pointer to where it was */ |
1400 |
|
|
(void)history(h, &ev, H_SET, curr_num); |
1401 |
|
|
return NULL; |
1402 |
|
18 |
} |
1403 |
|
|
|
1404 |
|
|
|
1405 |
|
|
/* |
1406 |
|
|
* add the line to history table |
1407 |
|
|
*/ |
1408 |
|
|
int |
1409 |
|
|
add_history(const char *line) |
1410 |
|
|
{ |
1411 |
|
288 |
HistEvent ev; |
1412 |
|
|
|
1413 |
✗✓ |
144 |
if (h == NULL || e == NULL) |
1414 |
|
|
rl_initialize(); |
1415 |
|
|
|
1416 |
|
144 |
(void)history(h, &ev, H_ENTER, line); |
1417 |
✓✗ |
144 |
if (history(h, &ev, H_GETSIZE) == 0) |
1418 |
|
144 |
history_length = ev.num; |
1419 |
|
144 |
current_history_valid = 1; |
1420 |
|
|
|
1421 |
|
288 |
return !(history_length > 0); /* return 0 if all is okay */ |
1422 |
|
144 |
} |
1423 |
|
|
|
1424 |
|
|
|
1425 |
|
|
/* |
1426 |
|
|
* remove the specified entry from the history list and return it. |
1427 |
|
|
*/ |
1428 |
|
|
HIST_ENTRY * |
1429 |
|
|
remove_history(int num) |
1430 |
|
|
{ |
1431 |
|
|
HIST_ENTRY *he; |
1432 |
|
36 |
HistEvent ev; |
1433 |
|
|
|
1434 |
✗✓ |
18 |
if (h == NULL || e == NULL) |
1435 |
|
|
rl_initialize(); |
1436 |
|
|
|
1437 |
✗✓ |
18 |
if ((he = malloc(sizeof(*he))) == NULL) |
1438 |
|
|
return NULL; |
1439 |
|
|
|
1440 |
✗✓ |
18 |
if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { |
1441 |
|
|
free(he); |
1442 |
|
|
return NULL; |
1443 |
|
|
} |
1444 |
|
|
|
1445 |
|
18 |
he->line = ev.str; |
1446 |
✓✗ |
18 |
if (history(h, &ev, H_GETSIZE) == 0) |
1447 |
|
18 |
history_length = ev.num; |
1448 |
|
|
|
1449 |
|
18 |
return he; |
1450 |
|
18 |
} |
1451 |
|
|
|
1452 |
|
|
|
1453 |
|
|
/* |
1454 |
|
|
* replace the line and data of the num-th entry |
1455 |
|
|
*/ |
1456 |
|
|
HIST_ENTRY * |
1457 |
|
|
replace_history_entry(int num, const char *line, histdata_t data) |
1458 |
|
|
{ |
1459 |
|
|
HIST_ENTRY *he; |
1460 |
|
|
HistEvent ev; |
1461 |
|
|
int curr_num; |
1462 |
|
|
|
1463 |
|
|
if (h == NULL || e == NULL) |
1464 |
|
|
rl_initialize(); |
1465 |
|
|
|
1466 |
|
|
/* save current position */ |
1467 |
|
|
if (history(h, &ev, H_CURR) != 0) |
1468 |
|
|
return NULL; |
1469 |
|
|
curr_num = ev.num; |
1470 |
|
|
|
1471 |
|
|
/* start from the oldest */ |
1472 |
|
|
if (history(h, &ev, H_LAST) != 0) |
1473 |
|
|
return NULL; /* error */ |
1474 |
|
|
|
1475 |
|
|
if ((he = malloc(sizeof(*he))) == NULL) |
1476 |
|
|
return NULL; |
1477 |
|
|
|
1478 |
|
|
/* look forwards for event matching specified offset */ |
1479 |
|
|
if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) |
1480 |
|
|
goto out; |
1481 |
|
|
|
1482 |
|
|
he->line = strdup(ev.str); |
1483 |
|
|
if (he->line == NULL) |
1484 |
|
|
goto out; |
1485 |
|
|
|
1486 |
|
|
if (history(h, &ev, H_REPLACE, line, data)) |
1487 |
|
|
goto out; |
1488 |
|
|
|
1489 |
|
|
/* restore pointer to where it was */ |
1490 |
|
|
if (history(h, &ev, H_SET, curr_num)) |
1491 |
|
|
goto out; |
1492 |
|
|
|
1493 |
|
|
return he; |
1494 |
|
|
out: |
1495 |
|
|
free(he); |
1496 |
|
|
return NULL; |
1497 |
|
|
} |
1498 |
|
|
|
1499 |
|
|
/* |
1500 |
|
|
* clear the history list - delete all entries |
1501 |
|
|
*/ |
1502 |
|
|
void |
1503 |
|
|
clear_history(void) |
1504 |
|
|
{ |
1505 |
|
96 |
HistEvent ev; |
1506 |
|
|
|
1507 |
|
48 |
(void)history(h, &ev, H_CLEAR); |
1508 |
|
48 |
history_length = 0; |
1509 |
|
48 |
current_history_valid = 1; |
1510 |
|
48 |
} |
1511 |
|
|
|
1512 |
|
|
|
1513 |
|
|
/* |
1514 |
|
|
* returns offset of the current history event |
1515 |
|
|
*/ |
1516 |
|
|
int |
1517 |
|
|
where_history(void) |
1518 |
|
|
{ |
1519 |
|
12 |
HistEvent ev; |
1520 |
|
|
int curr_num, off; |
1521 |
|
|
|
1522 |
✗✓ |
6 |
if (history(h, &ev, H_CURR) != 0) |
1523 |
|
|
return 0; |
1524 |
|
6 |
curr_num = ev.num; |
1525 |
|
|
|
1526 |
|
|
/* start from the oldest */ |
1527 |
|
6 |
(void)history(h, &ev, H_LAST); |
1528 |
|
|
|
1529 |
|
|
/* position is zero-based */ |
1530 |
|
|
off = 0; |
1531 |
✓✓✓✓
|
42 |
while (ev.num != curr_num && history(h, &ev, H_PREV) == 0) |
1532 |
|
6 |
off++; |
1533 |
|
|
|
1534 |
|
6 |
return off; |
1535 |
|
6 |
} |
1536 |
|
|
|
1537 |
|
|
|
1538 |
|
|
/* |
1539 |
|
|
* returns current history event or NULL if there is no such event |
1540 |
|
|
*/ |
1541 |
|
|
HIST_ENTRY * |
1542 |
|
|
current_history(void) |
1543 |
|
|
{ |
1544 |
|
|
|
1545 |
✓✓ |
114 |
return current_history_valid ? _move_history(H_CURR) : NULL; |
1546 |
|
|
} |
1547 |
|
|
|
1548 |
|
|
|
1549 |
|
|
/* |
1550 |
|
|
* returns total number of bytes history events' data are using |
1551 |
|
|
*/ |
1552 |
|
|
int |
1553 |
|
|
history_total_bytes(void) |
1554 |
|
|
{ |
1555 |
|
|
HistEvent ev; |
1556 |
|
|
int curr_num; |
1557 |
|
|
size_t size; |
1558 |
|
|
|
1559 |
|
|
if (history(h, &ev, H_CURR) != 0) |
1560 |
|
|
return -1; |
1561 |
|
|
curr_num = ev.num; |
1562 |
|
|
|
1563 |
|
|
(void)history(h, &ev, H_FIRST); |
1564 |
|
|
size = 0; |
1565 |
|
|
do |
1566 |
|
|
size += strlen(ev.str) * sizeof(*ev.str); |
1567 |
|
|
while (history(h, &ev, H_NEXT) == 0); |
1568 |
|
|
|
1569 |
|
|
/* get to the same position as before */ |
1570 |
|
|
history(h, &ev, H_PREV_EVENT, curr_num); |
1571 |
|
|
|
1572 |
|
|
return (int)size; |
1573 |
|
|
} |
1574 |
|
|
|
1575 |
|
|
|
1576 |
|
|
/* |
1577 |
|
|
* sets the position in the history list to ``pos'' |
1578 |
|
|
*/ |
1579 |
|
|
int |
1580 |
|
|
history_set_pos(int pos) |
1581 |
|
|
{ |
1582 |
|
72 |
HistEvent ev; |
1583 |
|
|
int curr_num; |
1584 |
|
|
|
1585 |
✓✓ |
36 |
if (pos >= history_length || pos < 0) |
1586 |
|
6 |
return 0; |
1587 |
|
|
|
1588 |
|
30 |
(void)history(h, &ev, H_CURR); |
1589 |
|
30 |
curr_num = ev.num; |
1590 |
|
30 |
current_history_valid = 1; |
1591 |
|
|
|
1592 |
|
|
/* |
1593 |
|
|
* use H_DELDATA to set to nth history (without delete) by passing |
1594 |
|
|
* (void **)-1 |
1595 |
|
|
*/ |
1596 |
✗✓ |
30 |
if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { |
1597 |
|
|
(void)history(h, &ev, H_SET, curr_num); |
1598 |
|
|
return 0; |
1599 |
|
|
} |
1600 |
|
30 |
return 1; |
1601 |
|
36 |
} |
1602 |
|
|
|
1603 |
|
|
|
1604 |
|
|
/* |
1605 |
|
|
* returns previous event in history and shifts pointer accordingly |
1606 |
|
|
* Note that readline and editline define directions in opposite ways. |
1607 |
|
|
*/ |
1608 |
|
|
HIST_ENTRY * |
1609 |
|
|
previous_history(void) |
1610 |
|
|
{ |
1611 |
|
|
|
1612 |
✗✓ |
24 |
if (current_history_valid == 0) { |
1613 |
|
|
current_history_valid = 1; |
1614 |
|
|
return _move_history(H_CURR); |
1615 |
|
|
} |
1616 |
|
12 |
return _move_history(H_NEXT); |
1617 |
|
12 |
} |
1618 |
|
|
|
1619 |
|
|
|
1620 |
|
|
/* |
1621 |
|
|
* returns next event in history and shifts pointer accordingly |
1622 |
|
|
*/ |
1623 |
|
|
HIST_ENTRY * |
1624 |
|
|
next_history(void) |
1625 |
|
|
{ |
1626 |
|
|
HIST_ENTRY *he; |
1627 |
|
|
|
1628 |
|
24 |
he = _move_history(H_PREV); |
1629 |
✓✓ |
12 |
if (he == NULL) |
1630 |
|
6 |
current_history_valid = 0; |
1631 |
|
12 |
return he; |
1632 |
|
|
} |
1633 |
|
|
|
1634 |
|
|
|
1635 |
|
|
/* |
1636 |
|
|
* searches for first history event containing the str |
1637 |
|
|
*/ |
1638 |
|
|
int |
1639 |
|
|
history_search(const char *str, int direction) |
1640 |
|
|
{ |
1641 |
|
|
HistEvent ev; |
1642 |
|
|
const char *strp; |
1643 |
|
|
int curr_num; |
1644 |
|
|
|
1645 |
|
|
if (history(h, &ev, H_CURR) != 0) |
1646 |
|
|
return -1; |
1647 |
|
|
curr_num = ev.num; |
1648 |
|
|
|
1649 |
|
|
for (;;) { |
1650 |
|
|
if ((strp = strstr(ev.str, str)) != NULL) |
1651 |
|
|
return (int)(strp - ev.str); |
1652 |
|
|
if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) |
1653 |
|
|
break; |
1654 |
|
|
} |
1655 |
|
|
(void)history(h, &ev, H_SET, curr_num); |
1656 |
|
|
return -1; |
1657 |
|
|
} |
1658 |
|
|
|
1659 |
|
|
|
1660 |
|
|
/* |
1661 |
|
|
* searches for first history event beginning with str |
1662 |
|
|
*/ |
1663 |
|
|
int |
1664 |
|
|
history_search_prefix(const char *str, int direction) |
1665 |
|
|
{ |
1666 |
|
|
HistEvent ev; |
1667 |
|
|
|
1668 |
|
|
return (history(h, &ev, direction < 0 ? |
1669 |
|
|
H_PREV_STR : H_NEXT_STR, str)); |
1670 |
|
|
} |
1671 |
|
|
|
1672 |
|
|
|
1673 |
|
|
/* |
1674 |
|
|
* search for event in history containing str, starting at offset |
1675 |
|
|
* abs(pos); continue backward, if pos<0, forward otherwise |
1676 |
|
|
*/ |
1677 |
|
|
/* ARGSUSED */ |
1678 |
|
|
int |
1679 |
|
|
history_search_pos(const char *str, |
1680 |
|
|
int direction __attribute__((__unused__)), int pos) |
1681 |
|
|
{ |
1682 |
|
|
HistEvent ev; |
1683 |
|
|
int curr_num, off; |
1684 |
|
|
|
1685 |
|
|
off = (pos > 0) ? pos : -pos; |
1686 |
|
|
pos = (pos > 0) ? 1 : -1; |
1687 |
|
|
|
1688 |
|
|
if (history(h, &ev, H_CURR) != 0) |
1689 |
|
|
return -1; |
1690 |
|
|
curr_num = ev.num; |
1691 |
|
|
|
1692 |
|
|
if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0) |
1693 |
|
|
return -1; |
1694 |
|
|
|
1695 |
|
|
for (;;) { |
1696 |
|
|
if (strstr(ev.str, str)) |
1697 |
|
|
return off; |
1698 |
|
|
if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) |
1699 |
|
|
break; |
1700 |
|
|
} |
1701 |
|
|
|
1702 |
|
|
/* set "current" pointer back to previous state */ |
1703 |
|
|
(void)history(h, &ev, |
1704 |
|
|
pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); |
1705 |
|
|
|
1706 |
|
|
return -1; |
1707 |
|
|
} |
1708 |
|
|
|
1709 |
|
|
|
1710 |
|
|
/********************************/ |
1711 |
|
|
/* completion functions */ |
1712 |
|
|
|
1713 |
|
|
char * |
1714 |
|
|
tilde_expand(char *name) |
1715 |
|
|
{ |
1716 |
|
|
return fn_tilde_expand(name); |
1717 |
|
|
} |
1718 |
|
|
|
1719 |
|
|
char * |
1720 |
|
|
filename_completion_function(const char *name, int state) |
1721 |
|
|
{ |
1722 |
|
|
return fn_filename_completion_function(name, state); |
1723 |
|
|
} |
1724 |
|
|
|
1725 |
|
|
/* |
1726 |
|
|
* a completion generator for usernames; returns _first_ username |
1727 |
|
|
* which starts with supplied text |
1728 |
|
|
* text contains a partial username preceded by random character |
1729 |
|
|
* (usually '~'); state is ignored |
1730 |
|
|
* it's the caller's responsibility to free the returned value |
1731 |
|
|
*/ |
1732 |
|
|
char * |
1733 |
|
|
username_completion_function(const char *text, int state) |
1734 |
|
|
{ |
1735 |
|
|
struct passwd *pwd; |
1736 |
|
|
|
1737 |
|
|
if (text[0] == '\0') |
1738 |
|
|
return NULL; |
1739 |
|
|
|
1740 |
|
|
if (*text == '~') |
1741 |
|
|
text++; |
1742 |
|
|
|
1743 |
|
|
if (state == 0) |
1744 |
|
|
setpwent(); |
1745 |
|
|
|
1746 |
|
|
while ((pwd = getpwent()) != NULL && text[0] == pwd->pw_name[0] |
1747 |
|
|
&& strcmp(text, pwd->pw_name) == 0); |
1748 |
|
|
|
1749 |
|
|
if (pwd == NULL) { |
1750 |
|
|
endpwent(); |
1751 |
|
|
return NULL; |
1752 |
|
|
} |
1753 |
|
|
return strdup(pwd->pw_name); |
1754 |
|
|
} |
1755 |
|
|
|
1756 |
|
|
|
1757 |
|
|
/* |
1758 |
|
|
* el-compatible wrapper to send TSTP on ^Z |
1759 |
|
|
*/ |
1760 |
|
|
/* ARGSUSED */ |
1761 |
|
|
static unsigned char |
1762 |
|
|
_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) |
1763 |
|
|
{ |
1764 |
|
|
(void)kill(0, SIGTSTP); |
1765 |
|
|
return CC_NORM; |
1766 |
|
|
} |
1767 |
|
|
|
1768 |
|
|
/* |
1769 |
|
|
* Display list of strings in columnar format on readline's output stream. |
1770 |
|
|
* 'matches' is list of strings, 'len' is number of strings in 'matches', |
1771 |
|
|
* 'max' is maximum length of string in 'matches'. |
1772 |
|
|
*/ |
1773 |
|
|
void |
1774 |
|
|
rl_display_match_list(char **matches, int len, int max) |
1775 |
|
|
{ |
1776 |
|
|
|
1777 |
|
|
fn_display_match_list(e, matches, (size_t)len, (size_t)max); |
1778 |
|
|
} |
1779 |
|
|
|
1780 |
|
|
static const char * |
1781 |
|
|
/*ARGSUSED*/ |
1782 |
|
|
_rl_completion_append_character_function(const char *dummy |
1783 |
|
|
__attribute__((__unused__))) |
1784 |
|
|
{ |
1785 |
|
|
static char buf[2]; |
1786 |
|
|
buf[0] = rl_completion_append_character; |
1787 |
|
|
buf[1] = '\0'; |
1788 |
|
|
return buf; |
1789 |
|
|
} |
1790 |
|
|
|
1791 |
|
|
|
1792 |
|
|
/* |
1793 |
|
|
* complete word at current point |
1794 |
|
|
*/ |
1795 |
|
|
/* ARGSUSED */ |
1796 |
|
|
int |
1797 |
|
|
rl_complete(int ignore __attribute__((__unused__)), int invoking_key) |
1798 |
|
|
{ |
1799 |
|
|
static ct_buffer_t wbreak_conv, sprefix_conv; |
1800 |
|
|
|
1801 |
|
|
if (h == NULL || e == NULL) |
1802 |
|
|
rl_initialize(); |
1803 |
|
|
|
1804 |
|
|
if (rl_inhibit_completion) { |
1805 |
|
|
char arr[2]; |
1806 |
|
|
arr[0] = (char)invoking_key; |
1807 |
|
|
arr[1] = '\0'; |
1808 |
|
|
el_insertstr(e, arr); |
1809 |
|
|
return CC_REFRESH; |
1810 |
|
|
} |
1811 |
|
|
|
1812 |
|
|
/* Just look at how many global variables modify this operation! */ |
1813 |
|
|
return fn_complete(e, |
1814 |
|
|
(CPFunction *)rl_completion_entry_function, |
1815 |
|
|
rl_attempted_completion_function, |
1816 |
|
|
ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), |
1817 |
|
|
ct_decode_string(rl_special_prefixes, &sprefix_conv), |
1818 |
|
|
_rl_completion_append_character_function, |
1819 |
|
|
(size_t)rl_completion_query_items, |
1820 |
|
|
&rl_completion_type, &rl_attempted_completion_over, |
1821 |
|
|
&rl_point, &rl_end); |
1822 |
|
|
|
1823 |
|
|
|
1824 |
|
|
} |
1825 |
|
|
|
1826 |
|
|
|
1827 |
|
|
/* ARGSUSED */ |
1828 |
|
|
static unsigned char |
1829 |
|
|
_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) |
1830 |
|
|
{ |
1831 |
|
|
return (unsigned char)rl_complete(0, ch); |
1832 |
|
|
} |
1833 |
|
|
|
1834 |
|
|
/* |
1835 |
|
|
* misc other functions |
1836 |
|
|
*/ |
1837 |
|
|
|
1838 |
|
|
/* |
1839 |
|
|
* bind key c to readline-type function func |
1840 |
|
|
*/ |
1841 |
|
|
int |
1842 |
|
|
rl_bind_key(int c, rl_command_func_t *func) |
1843 |
|
|
{ |
1844 |
|
|
int retval = -1; |
1845 |
|
|
|
1846 |
|
|
if (h == NULL || e == NULL) |
1847 |
|
|
rl_initialize(); |
1848 |
|
|
|
1849 |
|
|
if (func == rl_insert) { |
1850 |
|
|
/* XXX notice there is no range checking of ``c'' */ |
1851 |
|
|
e->el_map.key[c] = ED_INSERT; |
1852 |
|
|
retval = 0; |
1853 |
|
|
} |
1854 |
|
|
return retval; |
1855 |
|
|
} |
1856 |
|
|
|
1857 |
|
|
|
1858 |
|
|
/* |
1859 |
|
|
* read one key from input - handles chars pushed back |
1860 |
|
|
* to input stream also |
1861 |
|
|
*/ |
1862 |
|
|
int |
1863 |
|
|
rl_read_key(void) |
1864 |
|
|
{ |
1865 |
|
|
char fooarr[2 * sizeof(int)]; |
1866 |
|
|
|
1867 |
|
|
if (e == NULL || h == NULL) |
1868 |
|
|
rl_initialize(); |
1869 |
|
|
|
1870 |
|
|
return el_getc(e, fooarr); |
1871 |
|
|
} |
1872 |
|
|
|
1873 |
|
|
|
1874 |
|
|
/* |
1875 |
|
|
* reset the terminal |
1876 |
|
|
*/ |
1877 |
|
|
/* ARGSUSED */ |
1878 |
|
|
void |
1879 |
|
|
rl_reset_terminal(const char *p __attribute__((__unused__))) |
1880 |
|
|
{ |
1881 |
|
|
|
1882 |
|
|
if (h == NULL || e == NULL) |
1883 |
|
|
rl_initialize(); |
1884 |
|
|
el_reset(e); |
1885 |
|
|
} |
1886 |
|
|
|
1887 |
|
|
|
1888 |
|
|
/* |
1889 |
|
|
* insert character ``c'' back into input stream, ``count'' times |
1890 |
|
|
*/ |
1891 |
|
|
int |
1892 |
|
|
rl_insert(int count, int c) |
1893 |
|
|
{ |
1894 |
|
|
char arr[2]; |
1895 |
|
|
|
1896 |
|
|
if (h == NULL || e == NULL) |
1897 |
|
|
rl_initialize(); |
1898 |
|
|
|
1899 |
|
|
/* XXX - int -> char conversion can lose on multichars */ |
1900 |
|
|
arr[0] = c; |
1901 |
|
|
arr[1] = '\0'; |
1902 |
|
|
|
1903 |
|
|
for (; count > 0; count--) |
1904 |
|
|
el_push(e, arr); |
1905 |
|
|
|
1906 |
|
|
return 0; |
1907 |
|
|
} |
1908 |
|
|
|
1909 |
|
|
int |
1910 |
|
|
rl_insert_text(const char *text) |
1911 |
|
|
{ |
1912 |
|
|
if (!text || *text == 0) |
1913 |
|
|
return 0; |
1914 |
|
|
|
1915 |
|
|
if (h == NULL || e == NULL) |
1916 |
|
|
rl_initialize(); |
1917 |
|
|
|
1918 |
|
|
if (el_insertstr(e, text) < 0) |
1919 |
|
|
return 0; |
1920 |
|
|
return (int)strlen(text); |
1921 |
|
|
} |
1922 |
|
|
|
1923 |
|
|
/*ARGSUSED*/ |
1924 |
|
|
int |
1925 |
|
|
rl_newline(int count, int c) |
1926 |
|
|
{ |
1927 |
|
|
/* |
1928 |
|
|
* Readline-4.0 appears to ignore the args. |
1929 |
|
|
*/ |
1930 |
|
|
return rl_insert(1, '\n'); |
1931 |
|
|
} |
1932 |
|
|
|
1933 |
|
|
/*ARGSUSED*/ |
1934 |
|
|
static unsigned char |
1935 |
|
|
rl_bind_wrapper(EditLine *el, unsigned char c) |
1936 |
|
|
{ |
1937 |
|
|
if (map[c] == NULL) |
1938 |
|
|
return CC_ERROR; |
1939 |
|
|
|
1940 |
|
|
_rl_update_pos(); |
1941 |
|
|
|
1942 |
|
|
(*map[c])(NULL, c); |
1943 |
|
|
|
1944 |
|
|
/* If rl_done was set by the above call, deal with it here */ |
1945 |
|
|
if (rl_done) |
1946 |
|
|
return CC_EOF; |
1947 |
|
|
|
1948 |
|
|
return CC_NORM; |
1949 |
|
|
} |
1950 |
|
|
|
1951 |
|
|
int |
1952 |
|
|
rl_add_defun(const char *name, Function *fun, int c) |
1953 |
|
|
{ |
1954 |
|
|
char dest[8]; |
1955 |
|
|
if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) |
1956 |
|
|
return -1; |
1957 |
|
|
map[(unsigned char)c] = fun; |
1958 |
|
|
el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); |
1959 |
|
|
vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); |
1960 |
|
|
el_set(e, EL_BIND, dest, name, NULL); |
1961 |
|
|
return 0; |
1962 |
|
|
} |
1963 |
|
|
|
1964 |
|
|
void |
1965 |
|
|
rl_callback_read_char() |
1966 |
|
|
{ |
1967 |
|
|
int count = 0, done = 0; |
1968 |
|
|
const char *buf = el_gets(e, &count); |
1969 |
|
|
char *wbuf; |
1970 |
|
|
|
1971 |
|
|
if (buf == NULL || count-- <= 0) |
1972 |
|
|
return; |
1973 |
|
|
if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) |
1974 |
|
|
done = 1; |
1975 |
|
|
if (buf[count] == '\n' || buf[count] == '\r') |
1976 |
|
|
done = 2; |
1977 |
|
|
|
1978 |
|
|
if (done && rl_linefunc != NULL) { |
1979 |
|
|
el_set(e, EL_UNBUFFERED, 0); |
1980 |
|
|
if (done == 2) { |
1981 |
|
|
if ((wbuf = strdup(buf)) != NULL) |
1982 |
|
|
wbuf[count] = '\0'; |
1983 |
|
|
} else |
1984 |
|
|
wbuf = NULL; |
1985 |
|
|
(*(void (*)(const char *))rl_linefunc)(wbuf); |
1986 |
|
|
//el_set(e, EL_UNBUFFERED, 1); |
1987 |
|
|
} |
1988 |
|
|
} |
1989 |
|
|
|
1990 |
|
|
void |
1991 |
|
|
rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) |
1992 |
|
|
{ |
1993 |
|
|
if (e == NULL) { |
1994 |
|
|
rl_initialize(); |
1995 |
|
|
} |
1996 |
|
|
(void)rl_set_prompt(prompt); |
1997 |
|
|
rl_linefunc = linefunc; |
1998 |
|
|
el_set(e, EL_UNBUFFERED, 1); |
1999 |
|
|
} |
2000 |
|
|
|
2001 |
|
|
void |
2002 |
|
|
rl_callback_handler_remove(void) |
2003 |
|
|
{ |
2004 |
|
|
el_set(e, EL_UNBUFFERED, 0); |
2005 |
|
|
rl_linefunc = NULL; |
2006 |
|
|
} |
2007 |
|
|
|
2008 |
|
|
void |
2009 |
|
|
rl_redisplay(void) |
2010 |
|
|
{ |
2011 |
|
|
char a[2]; |
2012 |
|
|
a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; |
2013 |
|
|
a[1] = '\0'; |
2014 |
|
|
el_push(e, a); |
2015 |
|
|
} |
2016 |
|
|
|
2017 |
|
|
int |
2018 |
|
|
rl_get_previous_history(int count, int key) |
2019 |
|
|
{ |
2020 |
|
|
char a[2]; |
2021 |
|
|
a[0] = key; |
2022 |
|
|
a[1] = '\0'; |
2023 |
|
|
while (count--) |
2024 |
|
|
el_push(e, a); |
2025 |
|
|
return 0; |
2026 |
|
|
} |
2027 |
|
|
|
2028 |
|
|
void |
2029 |
|
|
/*ARGSUSED*/ |
2030 |
|
|
rl_prep_terminal(int meta_flag) |
2031 |
|
|
{ |
2032 |
|
|
el_set(e, EL_PREP_TERM, 1); |
2033 |
|
|
} |
2034 |
|
|
|
2035 |
|
|
void |
2036 |
|
|
rl_deprep_terminal(void) |
2037 |
|
|
{ |
2038 |
|
|
el_set(e, EL_PREP_TERM, 0); |
2039 |
|
|
} |
2040 |
|
|
|
2041 |
|
|
int |
2042 |
|
|
rl_read_init_file(const char *s) |
2043 |
|
|
{ |
2044 |
|
|
return el_source(e, s); |
2045 |
|
|
} |
2046 |
|
|
|
2047 |
|
|
int |
2048 |
|
|
rl_parse_and_bind(const char *line) |
2049 |
|
|
{ |
2050 |
|
|
const char **argv; |
2051 |
|
|
int argc; |
2052 |
|
|
Tokenizer *tok; |
2053 |
|
|
|
2054 |
|
|
tok = tok_init(NULL); |
2055 |
|
|
tok_str(tok, line, &argc, &argv); |
2056 |
|
|
argc = el_parse(e, argc, argv); |
2057 |
|
|
tok_end(tok); |
2058 |
|
|
return argc ? 1 : 0; |
2059 |
|
|
} |
2060 |
|
|
|
2061 |
|
|
int |
2062 |
|
|
rl_variable_bind(const char *var, const char *value) |
2063 |
|
|
{ |
2064 |
|
|
/* |
2065 |
|
|
* The proper return value is undocument, but this is what the |
2066 |
|
|
* readline source seems to do. |
2067 |
|
|
*/ |
2068 |
|
|
return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0; |
2069 |
|
|
} |
2070 |
|
|
|
2071 |
|
|
void |
2072 |
|
|
rl_stuff_char(int c) |
2073 |
|
|
{ |
2074 |
|
|
char buf[2]; |
2075 |
|
|
|
2076 |
|
|
buf[0] = c; |
2077 |
|
|
buf[1] = '\0'; |
2078 |
|
|
el_insertstr(e, buf); |
2079 |
|
|
} |
2080 |
|
|
|
2081 |
|
|
static int |
2082 |
|
|
_rl_event_read_char(EditLine *el, wchar_t *wc) |
2083 |
|
|
{ |
2084 |
|
|
char ch; |
2085 |
|
|
int n; |
2086 |
|
|
ssize_t num_read = 0; |
2087 |
|
|
|
2088 |
|
|
ch = '\0'; |
2089 |
|
|
*wc = L'\0'; |
2090 |
|
|
while (rl_event_hook) { |
2091 |
|
|
|
2092 |
|
|
(*rl_event_hook)(); |
2093 |
|
|
|
2094 |
|
|
#if defined(FIONREAD) |
2095 |
|
|
if (ioctl(el->el_infd, FIONREAD, &n) < 0) |
2096 |
|
|
return -1; |
2097 |
|
|
if (n) |
2098 |
|
|
num_read = read(el->el_infd, &ch, 1); |
2099 |
|
|
else |
2100 |
|
|
num_read = 0; |
2101 |
|
|
#elif defined(F_SETFL) && defined(O_NDELAY) |
2102 |
|
|
if ((n = fcntl(el->el_infd, F_GETFL)) < 0) |
2103 |
|
|
return -1; |
2104 |
|
|
if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) |
2105 |
|
|
return -1; |
2106 |
|
|
num_read = read(el->el_infd, &ch, 1); |
2107 |
|
|
if (fcntl(el->el_infd, F_SETFL, n)) |
2108 |
|
|
return -1; |
2109 |
|
|
#else |
2110 |
|
|
/* not non-blocking, but what you gonna do? */ |
2111 |
|
|
num_read = read(el->el_infd, &ch, 1); |
2112 |
|
|
return -1; |
2113 |
|
|
#endif |
2114 |
|
|
|
2115 |
|
|
if (num_read < 0 && errno == EAGAIN) |
2116 |
|
|
continue; |
2117 |
|
|
if (num_read == 0) |
2118 |
|
|
continue; |
2119 |
|
|
break; |
2120 |
|
|
} |
2121 |
|
|
if (!rl_event_hook) |
2122 |
|
|
el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); |
2123 |
|
|
*wc = (wchar_t)ch; |
2124 |
|
|
return (int)num_read; |
2125 |
|
|
} |
2126 |
|
|
|
2127 |
|
|
static void |
2128 |
|
|
_rl_update_pos(void) |
2129 |
|
|
{ |
2130 |
|
12 |
const LineInfo *li = el_line(e); |
2131 |
|
|
|
2132 |
|
6 |
rl_point = (int)(li->cursor - li->buffer); |
2133 |
|
6 |
rl_end = (int)(li->lastchar - li->buffer); |
2134 |
|
6 |
} |
2135 |
|
|
|
2136 |
|
|
void |
2137 |
|
|
rl_get_screen_size(int *rows, int *cols) |
2138 |
|
|
{ |
2139 |
|
|
if (rows) |
2140 |
|
|
el_get(e, EL_GETTC, "li", rows); |
2141 |
|
|
if (cols) |
2142 |
|
|
el_get(e, EL_GETTC, "co", cols); |
2143 |
|
|
} |
2144 |
|
|
|
2145 |
|
|
void |
2146 |
|
|
rl_set_screen_size(int rows, int cols) |
2147 |
|
|
{ |
2148 |
|
|
char buf[64]; |
2149 |
|
|
(void)snprintf(buf, sizeof(buf), "%d", rows); |
2150 |
|
|
el_set(e, EL_SETTC, "li", buf, NULL); |
2151 |
|
|
(void)snprintf(buf, sizeof(buf), "%d", cols); |
2152 |
|
|
el_set(e, EL_SETTC, "co", buf, NULL); |
2153 |
|
|
} |
2154 |
|
|
|
2155 |
|
|
char ** |
2156 |
|
|
rl_completion_matches(const char *str, rl_compentry_func_t *fun) |
2157 |
|
|
{ |
2158 |
|
|
size_t len, max, i, j, min; |
2159 |
|
|
char **list, *match, *a, *b; |
2160 |
|
|
|
2161 |
|
|
len = 1; |
2162 |
|
|
max = 10; |
2163 |
|
|
if ((list = reallocarray(NULL, max, sizeof(*list))) == NULL) |
2164 |
|
|
return NULL; |
2165 |
|
|
|
2166 |
|
|
while ((match = (*fun)(str, (int)(len - 1))) != NULL) { |
2167 |
|
|
list[len++] = match; |
2168 |
|
|
if (len == max) { |
2169 |
|
|
char **nl; |
2170 |
|
|
max += 10; |
2171 |
|
|
if ((nl = reallocarray(list, max, sizeof(*nl))) == NULL) |
2172 |
|
|
goto out; |
2173 |
|
|
list = nl; |
2174 |
|
|
} |
2175 |
|
|
} |
2176 |
|
|
if (len == 1) |
2177 |
|
|
goto out; |
2178 |
|
|
list[len] = NULL; |
2179 |
|
|
if (len == 2) { |
2180 |
|
|
if ((list[0] = strdup(list[1])) == NULL) |
2181 |
|
|
goto out; |
2182 |
|
|
return list; |
2183 |
|
|
} |
2184 |
|
|
qsort(&list[1], len - 1, sizeof(*list), |
2185 |
|
|
(int (*)(const void *, const void *)) strcmp); |
2186 |
|
|
min = SIZE_MAX; |
2187 |
|
|
for (i = 1, a = list[i]; i < len - 1; i++, a = b) { |
2188 |
|
|
b = list[i + 1]; |
2189 |
|
|
for (j = 0; a[j] && a[j] == b[j]; j++) |
2190 |
|
|
continue; |
2191 |
|
|
if (min > j) |
2192 |
|
|
min = j; |
2193 |
|
|
} |
2194 |
|
|
if (min == 0 && *str) { |
2195 |
|
|
if ((list[0] = strdup(str)) == NULL) |
2196 |
|
|
goto out; |
2197 |
|
|
} else { |
2198 |
|
|
if ((list[0] = malloc(min + 1)) == NULL) |
2199 |
|
|
goto out; |
2200 |
|
|
(void)memcpy(list[0], list[1], min); |
2201 |
|
|
list[0][min] = '\0'; |
2202 |
|
|
} |
2203 |
|
|
return list; |
2204 |
|
|
|
2205 |
|
|
out: |
2206 |
|
|
free(list); |
2207 |
|
|
return NULL; |
2208 |
|
|
} |
2209 |
|
|
|
2210 |
|
|
char * |
2211 |
|
|
rl_filename_completion_function (const char *text, int state) |
2212 |
|
|
{ |
2213 |
|
|
return fn_filename_completion_function(text, state); |
2214 |
|
|
} |
2215 |
|
|
|
2216 |
|
|
void |
2217 |
|
|
rl_forced_update_display(void) |
2218 |
|
|
{ |
2219 |
|
|
el_set(e, EL_REFRESH); |
2220 |
|
|
} |
2221 |
|
|
|
2222 |
|
|
int |
2223 |
|
|
_rl_abort_internal(void) |
2224 |
|
|
{ |
2225 |
|
|
el_beep(e); |
2226 |
|
|
longjmp(topbuf, 1); |
2227 |
|
|
/*NOTREACHED*/ |
2228 |
|
|
} |
2229 |
|
|
|
2230 |
|
|
int |
2231 |
|
|
_rl_qsort_string_compare(char **s1, char **s2) |
2232 |
|
|
{ |
2233 |
|
|
return strcoll(*s1, *s2); |
2234 |
|
|
} |
2235 |
|
|
|
2236 |
|
|
HISTORY_STATE * |
2237 |
|
|
history_get_history_state(void) |
2238 |
|
|
{ |
2239 |
|
|
HISTORY_STATE *hs; |
2240 |
|
|
|
2241 |
|
|
if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL) |
2242 |
|
|
return NULL; |
2243 |
|
|
hs->length = history_length; |
2244 |
|
|
return hs; |
2245 |
|
|
} |
2246 |
|
|
|
2247 |
|
|
int |
2248 |
|
|
/*ARGSUSED*/ |
2249 |
|
|
rl_kill_text(int from, int to) |
2250 |
|
|
{ |
2251 |
|
|
return 0; |
2252 |
|
|
} |
2253 |
|
|
|
2254 |
|
|
Keymap |
2255 |
|
|
rl_make_bare_keymap(void) |
2256 |
|
|
{ |
2257 |
|
|
return NULL; |
2258 |
|
|
} |
2259 |
|
|
|
2260 |
|
|
Keymap |
2261 |
|
|
rl_get_keymap(void) |
2262 |
|
|
{ |
2263 |
|
|
return NULL; |
2264 |
|
|
} |
2265 |
|
|
|
2266 |
|
|
void |
2267 |
|
|
/*ARGSUSED*/ |
2268 |
|
|
rl_set_keymap(Keymap k) |
2269 |
|
|
{ |
2270 |
|
|
} |
2271 |
|
|
|
2272 |
|
|
int |
2273 |
|
|
/*ARGSUSED*/ |
2274 |
|
|
rl_generic_bind(int type, const char * keyseq, const char * data, Keymap k) |
2275 |
|
|
{ |
2276 |
|
|
return 0; |
2277 |
|
|
} |
2278 |
|
|
|
2279 |
|
|
int |
2280 |
|
|
/*ARGSUSED*/ |
2281 |
|
|
rl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k) |
2282 |
|
|
{ |
2283 |
|
|
return 0; |
2284 |
|
|
} |
2285 |
|
|
|
2286 |
|
|
/* unsupported, but needed by python */ |
2287 |
|
|
void |
2288 |
|
|
rl_cleanup_after_signal(void) |
2289 |
|
|
{ |
2290 |
|
|
} |
2291 |
|
|
|
2292 |
|
|
int |
2293 |
|
|
rl_on_new_line(void) |
2294 |
|
|
{ |
2295 |
|
|
return 0; |
2296 |
|
|
} |
2297 |
|
|
|
2298 |
|
|
int |
2299 |
|
|
/*ARGSUSED*/ |
2300 |
|
|
rl_set_keyboard_input_timeout(int u __attribute__((__unused__))) |
2301 |
|
|
{ |
2302 |
|
|
return 0; |
2303 |
|
|
} |