Bug Summary

File:src/lib/libedit/readline.c
Warning:line 976, column 3
Potential leak of memory pointed to by 'result'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name readline.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libedit/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -I /usr/src/lib/libedit -I . -I /usr/src/lib/libedit -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libedit/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libedit/readline.c
1/* $OpenBSD: readline.c,v 1.29 2019/08/14 08:31:00 asou 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(*__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_H1
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
59void rl_prep_terminal(int);
60void rl_deprep_terminal(void);
61
62/* for rl_complete() */
63#define TAB'\r' '\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 */
70const char *rl_library_version = "EditLine wrapper";
71int rl_readline_version = RL_READLINE_VERSION0x0402;
72static char empty[] = { '\0' };
73static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
74static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
75 '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
76char *rl_readline_name = empty;
77FILE *rl_instream = NULL((void *)0);
78FILE *rl_outstream = NULL((void *)0);
79int rl_point = 0;
80int rl_end = 0;
81char *rl_line_buffer = NULL((void *)0);
82VCPFunction *rl_linefunc = NULL((void *)0);
83int rl_done = 0;
84VFunction *rl_event_hook = NULL((void *)0);
85KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
86 emacs_meta_keymap,
87 emacs_ctlx_keymap;
88
89int history_base = 1; /* probably never subject to change */
90int history_length = 0;
91int max_input_history = 0;
92char history_expansion_char = '!';
93char history_subst_char = '^';
94char *history_no_expand_chars = expand_chars;
95Function *history_inhibit_expansion_function = NULL((void *)0);
96char *history_arg_extract(int start, int end, const char *str);
97
98int rl_inhibit_completion = 0;
99int rl_attempted_completion_over = 0;
100char *rl_basic_word_break_characters = break_chars;
101char *rl_completer_word_break_characters = NULL((void *)0);
102char *rl_completer_quote_characters = NULL((void *)0);
103Function *rl_completion_entry_function = NULL((void *)0);
104CPPFunction *rl_attempted_completion_function = NULL((void *)0);
105Function *rl_pre_input_hook = NULL((void *)0);
106Function *rl_startup1_hook = NULL((void *)0);
107int (*rl_getc_function)(FILE *) = NULL((void *)0);
108char *rl_terminal_name = NULL((void *)0);
109int rl_already_prompted = 0;
110int rl_filename_completion_desired = 0;
111int rl_ignore_completion_duplicates = 0;
112int rl_catch_signals = 1;
113int readline_echoing_p = 1;
114int _rl_print_completions_horizontally = 0;
115VFunction *rl_redisplay_function = NULL((void *)0);
116Function *rl_startup_hook = NULL((void *)0);
117VFunction *rl_completion_display_matches_hook = NULL((void *)0);
118VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
119VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
120KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
121
122/*
123 * The current prompt string.
124 */
125char *rl_prompt = NULL((void *)0);
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 */
131int 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 */
137int 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 */
144char *rl_special_prefixes = NULL((void *)0);
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 */
150int 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 */
158static int current_history_valid = 1;
159
160/* stuff below is used internally by libedit for readline emulation */
161
162static History *h = NULL((void *)0);
163static EditLine *e = NULL((void *)0);
164static Function *map[256];
165static jmp_buf topbuf;
166
167/* internal functions */
168static unsigned char _el_rl_complete(EditLine *, int);
169static unsigned char _el_rl_tstp(EditLine *, int);
170static char *_get_prompt(EditLine *);
171static int _getc_function(EditLine *, wchar_t *);
172static HIST_ENTRY *_move_history(int);
173static int _history_expand_command(const char *, size_t, size_t,
174 char **);
175static char *_rl_compat_sub(const char *, const char *,
176 const char *, int);
177static int _rl_event_read_char(EditLine *, wchar_t *);
178static void _rl_update_pos(void);
179
180
181/* ARGSUSED */
182static 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 */
193static HIST_ENTRY *
194_move_history(int op)
195{
196 HistEvent ev;
197 static HIST_ENTRY rl_he;
198
199 if (history(h, &ev, op) != 0)
200 return NULL((void *)0);
201
202 rl_he.line = ev.str;
203 rl_he.data = NULL((void *)0);
204
205 return &rl_he;
206}
207
208
209/*
210 * read one key from user defined input function
211 */
212static int
213/*ARGSUSED*/
214_getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c)
215{
216 int i;
217
218 i = (*rl_getc_function)(NULL((void *)0));
219 if (i == -1)
220 return 0;
221 *c = (wchar_t)i;
222 return 1;
223}
224
225static void
226_resize_fun(EditLine *el, void *a)
227{
228 const LineInfo *li;
229 char **ap = a;
230
231 li = el_line(el);
232 /* a cheesy way to get rid of const cast. */
233 *ap = memchr(li->buffer, *li->buffer, 1);
234}
235
236static const char _dothistory[] = "/.history";
237
238static const char *
239_default_history_file(void)
240{
241 struct passwd *p;
242 static char path[PATH_MAX1024];
243
244 if (*path)
245 return path;
246 if ((p = getpwuid(getuid())) == NULL((void *)0))
247 return NULL((void *)0);
248 strlcpy(path, p->pw_dir, PATH_MAX1024);
249 strlcat(path, _dothistory, PATH_MAX1024);
250 return path;
251}
252
253/*
254 * READLINE compatibility stuff
255 */
256
257/*
258 * Set the prompt
259 */
260int
261rl_set_prompt(const char *prompt)
262{
263 char *p;
264
265 if (!prompt)
266 prompt = "";
267 if (rl_prompt != NULL((void *)0) && strcmp(rl_prompt, prompt) == 0)
268 return 0;
269 if (rl_prompt)
270 free(rl_prompt);
271 rl_prompt = strdup(prompt);
272 if (rl_prompt == NULL((void *)0))
273 return -1;
274
275 while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE'\2')) != NULL((void *)0))
276 *p = RL_PROMPT_START_IGNORE'\1';
277
278 return 0;
279}
280
281/*
282 * initialize rl compat stuff
283 */
284int
285rl_initialize(void)
286{
287 HistEvent ev;
288 int editmode = 1;
289 struct termios t;
290
291 current_history_valid = 1;
292
293 if (e != NULL((void *)0))
294 el_end(e);
295 if (h != NULL((void *)0))
296 history_end(h);
297
298 if (!rl_instream)
299 rl_instream = stdin(&__sF[0]);
300 if (!rl_outstream)
301 rl_outstream = stdout(&__sF[1]);
302
303 /*
304 * See if we don't really want to run the editor
305 */
306 if (tcgetattr(fileno(rl_instream)(!__isthreaded ? ((rl_instream)->_file) : (fileno)(rl_instream
))
, &t) != -1 && (t.c_lflag & ECHO0x00000008) == 0)
307 editmode = 0;
308
309 e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr(&__sF[2]));
310
311 if (!editmode)
312 el_set(e, EL_EDITMODE11, 0);
313
314 h = history_init();
315 if (!e || !h)
316 return -1;
317
318 history(h, &ev, H_SETSIZE1, INT_MAX2147483647); /* unlimited */
319 history_length = 0;
320 max_input_history = INT_MAX2147483647;
321 el_set(e, EL_HIST10, history, h);
322
323 /* Setup resize function */
324 el_set(e, EL_RESIZE23, _resize_fun, &rl_line_buffer);
325
326 /* setup getc function if valid */
327 if (rl_getc_function)
328 el_set(e, EL_GETCFN13, _getc_function);
329
330 /* for proper prompt printing in readline() */
331 if (rl_set_prompt("") == -1) {
332 history_end(h);
333 el_end(e);
334 return -1;
335 }
336 el_set(e, EL_PROMPT0, _get_prompt, RL_PROMPT_START_IGNORE'\1');
337 el_set(e, EL_SIGNAL3, rl_catch_signals);
338
339 /* set default mode to "emacs"-style and read setting afterwards */
340 /* so this can be overriden */
341 el_set(e, EL_EDITOR2, "emacs");
342 if (rl_terminal_name != NULL((void *)0))
343 el_set(e, EL_TERMINAL1, rl_terminal_name);
344 else
345 el_get(e, EL_TERMINAL1, &rl_terminal_name);
346
347 /*
348 * Word completion - this has to go AFTER rebinding keys
349 * to emacs-style.
350 */
351 el_set(e, EL_ADDFN9, "rl_complete",
352 "ReadLine compatible completion function",
353 _el_rl_complete);
354 el_set(e, EL_BIND4, "^I", "rl_complete", NULL((void *)0));
355
356 /*
357 * Send TSTP when ^Z is pressed.
358 */
359 el_set(e, EL_ADDFN9, "rl_tstp",
360 "ReadLine compatible suspend function",
361 _el_rl_tstp);
362 el_set(e, EL_BIND4, "^Z", "rl_tstp", NULL((void *)0));
363
364 /* read settings from configuration file */
365 el_source(e, NULL((void *)0));
366
367 /*
368 * Unfortunately, some applications really do use rl_point
369 * and rl_line_buffer directly.
370 */
371 _resize_fun(e, &rl_line_buffer);
372 _rl_update_pos();
373
374 if (rl_startup_hook)
375 (*rl_startup_hook)(NULL((void *)0), 0);
376
377 return 0;
378}
379
380
381/*
382 * read one line from input stream and return it, chomping
383 * trailing newline (if there is any)
384 */
385char *
386readline(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((void *)0) || h == NULL((void *)0))
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((void *)0);
405
406 if (rl_pre_input_hook)
407 (*rl_pre_input_hook)(NULL((void *)0), 0);
408
409 if (rl_event_hook && !(e->el_flags&NO_TTY0x02)) {
410 el_set(e, EL_GETCFN13, _rl_event_read_char);
411 used_event_hook = 1;
412 }
413
414 if (!rl_event_hook && used_event_hook) {
415 el_set(e, EL_GETCFN13, EL_BUILTIN_GETCFN(((void *)0)));
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((void *)0))
429 return NULL((void *)0);
430 lastidx = count - 1;
431 if (buf[lastidx] == '\n')
432 buf[lastidx] = '\0';
433 } else
434 buf = NULL((void *)0);
435
436 history(h, &ev, H_GETSIZE2);
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 */
450void
451using_history(void)
452{
453 if (h == NULL((void *)0) || e == NULL((void *)0))
454 rl_initialize();
455}
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 */
463static 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((void *)0))
488 return NULL((void *)0);
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
506static char *last_search_pat; /* last !?pat[?] search pattern */
507static char *last_search_match; /* last !?pat[?] that matched */
508
509const char *
510get_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((void *)0);
521
522 /* find out which event to take */
523 if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
524 if (history(h, &ev, H_FIRST3) != 0)
525 return NULL((void *)0);
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((void *)0);
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((void *)0);
575 else {
576 if ((pat = malloc(len + 1)) == NULL((void *)0))
577 return NULL((void *)0);
578 (void)strncpy(pat, cmd + begin, len);
579 pat[len] = '\0';
580 }
581
582 if (history(h, &ev, H_CURR8) != 0) {
583 if (pat != last_search_pat)
584 free(pat);
585 return NULL((void *)0);
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_FIRST3);
602 (void)fprintf(rl_outstream, "%s: Event not found\n", pat);
603 if (pat != last_search_pat)
604 free(pat);
605 return NULL((void *)0);
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_CURR8) != 0)
618 return NULL((void *)0);
619 *cindex = idx;
620 rptr = ev.str;
621
622 /* roll back to original position */
623 (void)history(h, &ev, H_SET7, 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 */
638static int
639_history_expand_command(const char *command, size_t offs, size_t cmdlen,
640 char **result)
641{
642 char *tmp, *search = NULL((void *)0), *aptr;
643 const char *ptr, *cmd;
644 static char *from = NULL((void *)0), *to = NULL((void *)0);
645 int start, end, idx, has_mods = 0;
646 int p_on = 0, g_on = 0;
647
648 *result = NULL((void *)0);
649 aptr = NULL((void *)0);
650 ptr = NULL((void *)0);
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((void *)0))
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((void *)0) && aptr == NULL((void *)0))
685 return -1;
686
687 if (!has_mods) {
688 *result = strdup(aptr ? aptr : ptr);
689 if (aptr)
690 free(aptr);
691 if (*result == NULL((void *)0))
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((void *)0)) {
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((void *)0))
757 *aptr = '\0';
758 } else if (*cmd == 't') { /* remove leading path */
759 if ((aptr = strrchr(tmp, '/')) != NULL((void *)0)) {
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((void *)0))
766 *aptr = '\0';
767 } else if (*cmd == 'e') { /* remove all but suffix */
768 if ((aptr = strrchr(tmp, '.')) != NULL((void *)0)) {
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((void *)0) || to == NULL((void *)0)))
783 continue;
784 else if (*cmd == 's') {
785 delim = *(++cmd), cmd++;
786 size = 16;
787 what = realloc(from, size);
788 if (what == NULL((void *)0)) {
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((void *)0)) {
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((void *)0)) {
818 free(tmp);
819 return 0;
820 }
821 } else {
822 from = NULL((void *)0);
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((void *)0)) {
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((void *)0)) {
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 */
885int
886history_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((void *)0) || e == NULL((void *)0))
1
Assuming 'h' is not equal to NULL
2
Assuming 'e' is not equal to NULL
3
Taking false branch
893 rl_initialize();
894
895 if (history_expansion_char == 0) {
4
Assuming 'history_expansion_char' is not equal to 0
5
Taking false branch
896 *output = strdup(str);
897 return 0;
898 }
899
900 *output = NULL((void *)0);
901 if (str[0] == history_subst_char) {
6
Assuming the condition is false
7
Taking false branch
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((void *)0))
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((void *)0))
8
Assuming the condition is false
9
Taking false branch
915 return 0;
916 }
917
918#define ADD_STRING(what, len, fr){ if (idx + len + 1 > size) { char *nresult = realloc(result
, (size += len + 1)); if (nresult == ((void *)0)) { free(*output
); if ( fr) free(tmp); return 0; } result = nresult; } (void)
strncpy(&result[idx], what, len); idx += len; result[idx]
= '\0'; }
\
919 { \
920 if (idx + len + 1 > size) { \
921 char *nresult = realloc(result, (size += len + 1));\
922 if (nresult == NULL((void *)0)) { \
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((void *)0);
936 size = idx = 0;
937 tmp = NULL((void *)0);
938 for (i = 0; str[i];) {
10
Loop condition is true. Entering loop body
44
Loop condition is true. Entering loop body
939 int qchar, loop_again;
940 size_t len, start, j;
941
942 qchar = 0;
943 loop_again = 1;
944 start = j = i;
945loop:
946 for (; str[j]; j++) {
11
Loop condition is true. Entering loop body
25
Loop condition is true. Entering loop body
45
Loop condition is true. Entering loop body
947 if (str[j] == '\\' &&
12
Assuming the condition is false
26
Assuming the condition is false
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
12.1
'loop_again' is 1
26.1
'loop_again' is 0
45.1
'loop_again' is 1
) {
13
Taking false branch
27
Taking true branch
46
Taking false branch
954 if (isspace((unsigned char) str[j])
955 || str[j] == qchar)
956 break;
28
Execution continues on line 966
957 }
958 if (str[j] == history_expansion_char
14
Assuming the condition is true
18
Taking true branch
47
Assuming the condition is true
51
Taking true branch
959 && !strchr(history_no_expand_chars, str[j + 1])
15
Assuming the condition is true
48
Assuming the condition is true
960 && (!history_inhibit_expansion_function ||
16
Assuming 'history_inhibit_expansion_function' is non-null
49
Assuming 'history_inhibit_expansion_function' is non-null
961 (*history_inhibit_expansion_function)(str,
17
Assuming the condition is true
50
Assuming the condition is true
962 (int)j) == 0))
963 break;
19
Execution continues on line 966
52
Execution continues on line 966
964 }
965
966 if (str[j] && loop_again
20.1
'loop_again' is 1
28.1
'loop_again' is 0
) {
20
Assuming the condition is true
21
Taking true branch
29
Taking false branch
53
Assuming the condition is false
967 i = j;
968 qchar = (j
21.1
'j' is <= 0
> 0 && str[j - 1] == '"' )? '"':0;
969 j++;
970 if (str[j] == history_expansion_char)
22
Assuming the condition is false
23
Taking false branch
971 j++;
972 loop_again = 0;
973 goto loop;
24
Control jumps to line 946
974 }
975 len = i - start;
976 ADD_STRING(&str[start], len, 0){ if (idx + len + 1 > size) { char *nresult = realloc(result
, (size += len + 1)); if (nresult == ((void *)0)) { free(*output
); if ( 0) free(tmp); return 0; } result = nresult; } (void)strncpy
(&result[idx], &str[start], len); idx += len; result[
idx] = '\0'; }
;
30
Taking true branch
31
Assuming 'nresult' is not equal to null
32
Taking false branch
54
Assuming the condition is true
55
Taking true branch
56
Attempt to reallocate memory
57
Assuming 'nresult' is equal to null
58
Reallocation failed
59
Taking true branch
60
Potential leak of memory pointed to by 'result'
977
978 if (str[i] == '\0' || str[i] != history_expansion_char) {
33
Assuming the condition is false
34
Taking false branch
979 len = j - i;
980 ADD_STRING(&str[i], len, 0){ if (idx + len + 1 > size) { char *nresult = realloc(result
, (size += len + 1)); if (nresult == ((void *)0)) { free(*output
); if ( 0) free(tmp); return 0; } result = nresult; } (void)strncpy
(&result[idx], &str[i], len); idx += len; result[idx]
= '\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) {
35
Assuming 'ret' is > 0
36
Assuming 'tmp' is non-null
37
Taking true branch
989 len = strlen(tmp);
990 ADD_STRING(tmp, len, 1){ if (idx + len + 1 > size) { char *nresult = realloc(result
, (size += len + 1)); if (nresult == ((void *)0)) { free(*output
); if ( 1) free(tmp); return 0; } result = nresult; } (void)strncpy
(&result[idx], tmp, len); idx += len; result[idx] = '\0';
}
;
38
Assuming the condition is true
39
Taking true branch
40
Memory is allocated
41
Assuming 'nresult' is not equal to null
42
Taking false branch
991 }
992 if (tmp
42.1
'tmp' is non-null
) {
43
Taking true branch
993 free(tmp);
994 tmp = NULL((void *)0);
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*/
1019char *
1020history_arg_extract(int start, int end, const char *str)
1021{
1022 size_t i, len, max;
1023 char **arr, *result = NULL((void *)0);
1024
1025 arr = history_tokenize(str);
1026 if (!arr)
1027 return NULL((void *)0);
1028 if (arr && *arr == NULL((void *)0))
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((void *)0))
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
1064out:
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 */
1076char **
1077history_tokenize(const char *str)
1078{
1079 int size = 1, idx = 0, i, start;
1080 size_t len;
1081 char **result = NULL((void *)0), *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((void *)0)) {
1108 free(result);
1109 return NULL((void *)0);
1110 }
1111 size *= 2;
1112 result = nresult;
1113 }
1114 len = i - start;
1115 temp = malloc(len + 1);
1116 if (temp == NULL((void *)0)) {
1117 for (i = 0; i < idx; i++)
1118 free(result[i]);
1119 free(result);
1120 return NULL((void *)0);
1121 }
1122 (void)strncpy(temp, &str[start], len);
1123 temp[len] = '\0';
1124 result[idx++] = temp;
1125 result[idx] = NULL((void *)0);
1126 if (str[i])
1127 i++;
1128 }
1129 return result;
1130}
1131
1132
1133/*
1134 * limit size of history record to ``max'' events
1135 */
1136void
1137stifle_history(int max)
1138{
1139 HistEvent ev;
1140 HIST_ENTRY *he;
1141 int i, len;
1142
1143 if (h == NULL((void *)0) || e == NULL((void *)0))
1144 rl_initialize();
1145
1146 len = history_length;
1147 if (history(h, &ev, H_SETSIZE1, max) == 0) {
1148 max_input_history = max;
1149 if (max < len)
1150 history_base += len - max;
1151 for (i = 0; i < len - max; i++) {
1152 he = remove_history(0);
1153 free(he->data);
1154 free((void *)he->line);
1155 free(he);
1156 }
1157 }
1158}
1159
1160
1161/*
1162 * "unlimit" size of history - set the limit to maximum allowed int value
1163 */
1164int
1165unstifle_history(void)
1166{
1167 HistEvent ev;
1168 int omax;
1169
1170 history(h, &ev, H_SETSIZE1, INT_MAX2147483647);
1171 omax = max_input_history;
1172 max_input_history = INT_MAX2147483647;
1173 return omax; /* some value _must_ be returned */
1174}
1175
1176
1177int
1178history_is_stifled(void)
1179{
1180
1181 /* cannot return true answer */
1182 return max_input_history != INT_MAX2147483647;
1183}
1184
1185static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
1186
1187int
1188history_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((void *)0) && (filename = _default_history_file()) == NULL((void *)0))
1201 return errno(*__errno());
1202 if ((fp = fopen(filename, "r+")) == NULL((void *)0))
1203 return errno(*__errno());
1204 strlcpy(template, _history_tmp_template, sizeof(template));
1205 if ((fd = mkstemp(template)) == -1) {
1206 ret = errno(*__errno());
1207 goto out1;
1208 }
1209
1210 if ((tp = fdopen(fd, "r+")) == NULL((void *)0)) {
1211 close(fd);
1212 ret = errno(*__errno());
1213 goto out2;
1214 }
1215
1216 for(;;) {
1217 if (fread(buf, sizeof(buf), 1, fp) != 1) {
1218 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
) {
1219 ret = errno(*__errno());
1220 break;
1221 }
1222 if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET0) ==
1223 (off_t)-1) {
1224 ret = errno(*__errno());
1225 break;
1226 }
1227 left = fread(buf, 1, sizeof(buf), fp);
1228 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
) {
1229 ret = errno(*__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(*__errno());
1237 break;
1238 }
1239 fflush(tp);
1240 break;
1241 }
1242 if (fwrite(buf, sizeof(buf), 1, tp) != 1) {
1243 ret = errno(*__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_SET0) == -1) {
1269 ret = errno(*__errno());
1270 break;
1271 }
1272 if (fread(buf, sizeof(buf), 1, tp) != 1) {
1273 if (ferror(tp)(!__isthreaded ? (((tp)->_flags & 0x0040) != 0) : (ferror
)(tp))
) {
1274 ret = errno(*__errno());
1275 break;
1276 }
1277 ret = EAGAIN35;
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_SET0) == (off_t)-1) {
1287 ret = errno(*__errno());
1288 goto out3;
1289 }
1290
1291 if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET0) ==
1292 (off_t)-1) {
1293 ret = errno(*__errno());
1294 goto out3;
1295 }
1296
1297 for(;;) {
1298 if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) {
1299 if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
)
1300 ret = errno(*__errno());
1301 break;
1302 }
1303 if (fwrite(buf, (size_t)left, 1, fp) != 1) {
1304 ret = errno(*__errno());
1305 break;
1306 }
1307 }
1308 fflush(fp);
1309 if((off = ftello(fp)) > 0)
1310 (void)ftruncate(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), off);
1311out3:
1312 fclose(tp);
1313out2:
1314 unlink(template);
1315out1:
1316 fclose(fp);
1317
1318 return ret;
1319}
1320
1321
1322/*
1323 * read history from a file given
1324 */
1325int
1326read_history(const char *filename)
1327{
1328 HistEvent ev;
1329
1330 if (h == NULL((void *)0) || e == NULL((void *)0))
1331 rl_initialize();
1332 if (filename == NULL((void *)0) && (filename = _default_history_file()) == NULL((void *)0))
1333 return errno(*__errno());
1334 return history(h, &ev, H_LOAD17, filename) == -1 ?
1335 (errno(*__errno()) ? errno(*__errno()) : EINVAL22) : 0;
1336}
1337
1338
1339/*
1340 * write history to a file given
1341 */
1342int
1343write_history(const char *filename)
1344{
1345 HistEvent ev;
1346
1347 if (h == NULL((void *)0) || e == NULL((void *)0))
1348 rl_initialize();
1349 if (filename == NULL((void *)0) && (filename = _default_history_file()) == NULL((void *)0))
1350 return errno(*__errno());
1351 return history(h, &ev, H_SAVE18, filename) == -1 ?
1352 (errno(*__errno()) ? errno(*__errno()) : EINVAL22) : 0;
1353}
1354
1355
1356/*
1357 * returns history ``num''th event
1358 *
1359 * returned pointer points to static variable
1360 */
1361HIST_ENTRY *
1362history_get(int num)
1363{
1364 static HIST_ENTRY she;
1365 HistEvent ev;
1366 int curr_num;
1367
1368 if (h == NULL((void *)0) || e == NULL((void *)0))
1369 rl_initialize();
1370
1371 if (num < history_base)
1372 return NULL((void *)0);
1373
1374 /* save current position */
1375 if (history(h, &ev, H_CURR8) != 0)
1376 return NULL((void *)0);
1377 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 if (history(h, &ev, H_DELDATA24, num - history_base, (void **)-1) != 0)
1384 goto out;
1385
1386 /* get current entry */
1387 if (history(h, &ev, H_CURR8) != 0)
1388 goto out;
1389 if (history(h, &ev, H_NEXT_EVDATA23, ev.num, &she.data) != 0)
1390 goto out;
1391 she.line = ev.str;
1392
1393 /* restore pointer to where it was */
1394 (void)history(h, &ev, H_SET7, curr_num);
1395
1396 return &she;
1397
1398out:
1399 /* restore pointer to where it was */
1400 (void)history(h, &ev, H_SET7, curr_num);
1401 return NULL((void *)0);
1402}
1403
1404
1405/*
1406 * add the line to history table
1407 */
1408int
1409add_history(const char *line)
1410{
1411 HistEvent ev;
1412
1413 if (h == NULL((void *)0) || e == NULL((void *)0))
1414 rl_initialize();
1415
1416 (void)history(h, &ev, H_ENTER10, line);
1417 if (history(h, &ev, H_GETSIZE2) == 0)
1418 history_length = ev.num;
1419 current_history_valid = 1;
1420
1421 return !(history_length > 0); /* return 0 if all is okay */
1422}
1423
1424
1425/*
1426 * remove the specified entry from the history list and return it.
1427 */
1428HIST_ENTRY *
1429remove_history(int num)
1430{
1431 HIST_ENTRY *he;
1432 HistEvent ev;
1433
1434 if (h == NULL((void *)0) || e == NULL((void *)0))
1435 rl_initialize();
1436
1437 if ((he = malloc(sizeof(*he))) == NULL((void *)0))
1438 return NULL((void *)0);
1439
1440 if (history(h, &ev, H_DELDATA24, num, &he->data) != 0) {
1441 free(he);
1442 return NULL((void *)0);
1443 }
1444
1445 he->line = ev.str;
1446 if (history(h, &ev, H_GETSIZE2) == 0)
1447 history_length = ev.num;
1448
1449 return he;
1450}
1451
1452
1453/*
1454 * replace the line and data of the num-th entry
1455 */
1456HIST_ENTRY *
1457replace_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((void *)0) || e == NULL((void *)0))
1464 rl_initialize();
1465
1466 /* save current position */
1467 if (history(h, &ev, H_CURR8) != 0)
1468 return NULL((void *)0);
1469 curr_num = ev.num;
1470
1471 /* start from the oldest */
1472 if (history(h, &ev, H_LAST4) != 0)
1473 return NULL((void *)0); /* error */
1474
1475 if ((he = malloc(sizeof(*he))) == NULL((void *)0))
1476 return NULL((void *)0);
1477
1478 /* look forwards for event matching specified offset */
1479 if (history(h, &ev, H_NEXT_EVDATA23, num, &he->data))
1480 goto out;
1481
1482 he->line = strdup(ev.str);
1483 if (he->line == NULL((void *)0))
1484 goto out;
1485
1486 if (history(h, &ev, H_REPLACE25, line, data))
1487 goto out;
1488
1489 /* restore pointer to where it was */
1490 if (history(h, &ev, H_SET7, curr_num))
1491 goto out;
1492
1493 return he;
1494out:
1495 free(he);
1496 return NULL((void *)0);
1497}
1498
1499/*
1500 * clear the history list - delete all entries
1501 */
1502void
1503clear_history(void)
1504{
1505 HistEvent ev;
1506
1507 (void)history(h, &ev, H_CLEAR19);
1508 history_length = 0;
1509 current_history_valid = 1;
1510}
1511
1512
1513/*
1514 * returns offset of the current history event
1515 */
1516int
1517where_history(void)
1518{
1519 HistEvent ev;
1520 int curr_num, off;
1521
1522 if (history(h, &ev, H_CURR8) != 0)
1523 return 0;
1524 curr_num = ev.num;
1525
1526 /* start from the oldest */
1527 (void)history(h, &ev, H_LAST4);
1528
1529 /* position is zero-based */
1530 off = 0;
1531 while (ev.num != curr_num && history(h, &ev, H_PREV5) == 0)
1532 off++;
1533
1534 return off;
1535}
1536
1537
1538/*
1539 * returns current history event or NULL if there is no such event
1540 */
1541HIST_ENTRY *
1542current_history(void)
1543{
1544
1545 return current_history_valid ? _move_history(H_CURR8) : NULL((void *)0);
1546}
1547
1548
1549/*
1550 * returns total number of bytes history events' data are using
1551 */
1552int
1553history_total_bytes(void)
1554{
1555 HistEvent ev;
1556 int curr_num;
1557 size_t size;
1558
1559 if (history(h, &ev, H_CURR8) != 0)
1560 return -1;
1561 curr_num = ev.num;
1562
1563 (void)history(h, &ev, H_FIRST3);
1564 size = 0;
1565 do
1566 size += strlen(ev.str) * sizeof(*ev.str);
1567 while (history(h, &ev, H_NEXT6) == 0);
1568
1569 /* get to the same position as before */
1570 history(h, &ev, H_PREV_EVENT16, curr_num);
1571
1572 return (int)size;
1573}
1574
1575
1576/*
1577 * sets the position in the history list to ``pos''
1578 */
1579int
1580history_set_pos(int pos)
1581{
1582 HistEvent ev;
1583 int curr_num;
1584
1585 if (pos >= history_length || pos < 0)
1586 return 0;
1587
1588 (void)history(h, &ev, H_CURR8);
1589 curr_num = ev.num;
1590 current_history_valid = 1;
1591
1592 /*
1593 * use H_DELDATA to set to nth history (without delete) by passing
1594 * (void **)-1
1595 */
1596 if (history(h, &ev, H_DELDATA24, pos, (void **)-1)) {
1597 (void)history(h, &ev, H_SET7, curr_num);
1598 return 0;
1599 }
1600 return 1;
1601}
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 */
1608HIST_ENTRY *
1609previous_history(void)
1610{
1611
1612 if (current_history_valid == 0) {
1613 current_history_valid = 1;
1614 return _move_history(H_CURR8);
1615 }
1616 return _move_history(H_NEXT6);
1617}
1618
1619
1620/*
1621 * returns next event in history and shifts pointer accordingly
1622 */
1623HIST_ENTRY *
1624next_history(void)
1625{
1626 HIST_ENTRY *he;
1627
1628 he = _move_history(H_PREV5);
1629 if (he == NULL((void *)0))
1630 current_history_valid = 0;
1631 return he;
1632}
1633
1634
1635/*
1636 * searches for first history event containing the str
1637 */
1638int
1639history_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_CURR8) != 0)
1646 return -1;
1647 curr_num = ev.num;
1648
1649 for (;;) {
1650 if ((strp = strstr(ev.str, str)) != NULL((void *)0))
1651 return (int)(strp - ev.str);
1652 if (history(h, &ev, direction < 0 ? H_NEXT6:H_PREV5) != 0)
1653 break;
1654 }
1655 (void)history(h, &ev, H_SET7, curr_num);
1656 return -1;
1657}
1658
1659
1660/*
1661 * searches for first history event beginning with str
1662 */
1663int
1664history_search_prefix(const char *str, int direction)
1665{
1666 HistEvent ev;
1667
1668 return (history(h, &ev, direction < 0 ?
1669 H_PREV_STR14 : H_NEXT_STR13, 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 */
1678int
1679history_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_CURR8) != 0)
1689 return -1;
1690 curr_num = ev.num;
1691
1692 if (!history_set_pos(off) || history(h, &ev, H_CURR8) != 0)
1693 return -1;
1694
1695 for (;;) {
1696 if (strstr(ev.str, str))
1697 return off;
1698 if (history(h, &ev, (pos < 0) ? H_PREV5 : H_NEXT6) != 0)
1699 break;
1700 }
1701
1702 /* set "current" pointer back to previous state */
1703 (void)history(h, &ev,
1704 pos < 0 ? H_NEXT_EVENT15 : H_PREV_EVENT16, curr_num);
1705
1706 return -1;
1707}
1708
1709
1710/********************************/
1711/* completion functions */
1712
1713char *
1714tilde_expand(char *name)
1715{
1716 return fn_tilde_expand(name);
1717}
1718
1719char *
1720filename_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 */
1732char *
1733username_completion_function(const char *text, int state)
1734{
1735 struct passwd *pwd;
1736
1737 if (text[0] == '\0')
1738 return NULL((void *)0);
1739
1740 if (*text == '~')
1741 text++;
1742
1743 if (state == 0)
1744 setpwent();
1745
1746 while ((pwd = getpwent()) != NULL((void *)0) && text[0] == pwd->pw_name[0]
1747 && strcmp(text, pwd->pw_name) == 0);
1748
1749 if (pwd == NULL((void *)0)) {
1750 endpwent();
1751 return NULL((void *)0);
1752 }
1753 return strdup(pwd->pw_name);
1754}
1755
1756
1757/*
1758 * el-compatible wrapper to send TSTP on ^Z
1759 */
1760/* ARGSUSED */
1761static unsigned char
1762_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
1763{
1764 (void)kill(0, SIGTSTP18);
1765 return CC_NORM0;
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 */
1773void
1774rl_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
1780static 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 */
1796int
1797rl_complete(int ignore __attribute__((__unused__)), int invoking_key)
1798{
1799 static ct_buffer_t wbreak_conv, sprefix_conv;
1800
1801 if (h == NULL((void *)0) || e == NULL((void *)0))
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_REFRESH4;
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 */
1828static 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 */
1841int
1842rl_bind_key(int c, rl_command_func_t *func)
1843{
1844 int retval = -1;
1845
1846 if (h == NULL((void *)0) || e == NULL((void *)0))
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_INSERT9;
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 */
1862int
1863rl_read_key(void)
1864{
1865 char fooarr[2 * sizeof(int)];
1866
1867 if (e == NULL((void *)0) || h == NULL((void *)0))
1868 rl_initialize();
1869
1870 return el_getc(e, fooarr);
1871}
1872
1873
1874/*
1875 * reset the terminal
1876 */
1877/* ARGSUSED */
1878void
1879rl_reset_terminal(const char *p __attribute__((__unused__)))
1880{
1881
1882 if (h == NULL((void *)0) || e == NULL((void *)0))
1883 rl_initialize();
1884 el_reset(e);
1885}
1886
1887
1888/*
1889 * insert character ``c'' back into input stream, ``count'' times
1890 */
1891int
1892rl_insert(int count, int c)
1893{
1894 char arr[2];
1895
1896 if (h == NULL((void *)0) || e == NULL((void *)0))
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
1909int
1910rl_insert_text(const char *text)
1911{
1912 if (!text || *text == 0)
1913 return 0;
1914
1915 if (h == NULL((void *)0) || e == NULL((void *)0))
1916 rl_initialize();
1917
1918 if (el_insertstr(e, text) < 0)
1919 return 0;
1920 return (int)strlen(text);
1921}
1922
1923/*ARGSUSED*/
1924int
1925rl_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*/
1934static unsigned char
1935rl_bind_wrapper(EditLine *el, unsigned char c)
1936{
1937 if (map[c] == NULL((void *)0))
1938 return CC_ERROR6;
1939
1940 _rl_update_pos();
1941
1942 (*map[c])(NULL((void *)0), c);
1943
1944 /* If rl_done was set by the above call, deal with it here */
1945 if (rl_done)
1946 return CC_EOF2;
1947
1948 return CC_NORM0;
1949}
1950
1951int
1952rl_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_ADDFN9, name, name, rl_bind_wrapper);
1959 vis(dest, c, VIS_WHITE(0x04 | 0x08 | 0x10)|VIS_NOSLASH0x40, 0);
1960 el_set(e, EL_BIND4, dest, name, NULL((void *)0));
1961 return 0;
1962}
1963
1964void
1965rl_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((void *)0) || count-- <= 0)
1972 return;
1973 if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO2][C_EOF4])
1974 done = 1;
1975 if (buf[count] == '\n' || buf[count] == '\r')
1976 done = 2;
1977
1978 if (done && rl_linefunc != NULL((void *)0)) {
1979 el_set(e, EL_UNBUFFERED15, 0);
1980 if (done == 2) {
1981 if ((wbuf = strdup(buf)) != NULL((void *)0))
1982 wbuf[count] = '\0';
1983 } else
1984 wbuf = NULL((void *)0);
1985 (*(void (*)(const char *))rl_linefunc)(wbuf);
1986 //el_set(e, EL_UNBUFFERED, 1);
1987 }
1988}
1989
1990void
1991rl_callback_handler_install(const char *prompt, VCPFunction *linefunc)
1992{
1993 if (e == NULL((void *)0)) {
1994 rl_initialize();
1995 }
1996 (void)rl_set_prompt(prompt);
1997 rl_linefunc = linefunc;
1998 el_set(e, EL_UNBUFFERED15, 1);
1999}
2000
2001void
2002rl_callback_handler_remove(void)
2003{
2004 el_set(e, EL_UNBUFFERED15, 0);
2005 rl_linefunc = NULL((void *)0);
2006}
2007
2008void
2009rl_redisplay(void)
2010{
2011 char a[2];
2012 a[0] = e->el_tty.t_c[TS_IO2][C_REPRINT15];
2013 a[1] = '\0';
2014 el_push(e, a);
2015}
2016
2017int
2018rl_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
2028void
2029/*ARGSUSED*/
2030rl_prep_terminal(int meta_flag)
2031{
2032 el_set(e, EL_PREP_TERM16, 1);
2033}
2034
2035void
2036rl_deprep_terminal(void)
2037{
2038 el_set(e, EL_PREP_TERM16, 0);
2039}
2040
2041int
2042rl_read_init_file(const char *s)
2043{
2044 return el_source(e, s);
2045}
2046
2047int
2048rl_parse_and_bind(const char *line)
2049{
2050 const char **argv;
2051 int argc;
2052 Tokenizer *tok;
2053
2054 tok = tok_init(NULL((void *)0));
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
2061int
2062rl_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_BIND4, "", var, value, NULL((void *)0)) == -1 ? 1 : 0;
2069}
2070
2071void
2072rl_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
2081static 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((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((127)))
)
2095 if (ioctl(el->el_infd, FIONREAD((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((127)))
, &n) == -1)
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_SETFL4) && defined(O_NDELAY0x0004)
2102 if ((n = fcntl(el->el_infd, F_GETFL3)) == -1)
2103 return -1;
2104 if (fcntl(el->el_infd, F_SETFL4, n|O_NDELAY0x0004) == -1)
2105 return -1;
2106 num_read = read(el->el_infd, &ch, 1);
2107 if (fcntl(el->el_infd, F_SETFL4, 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 == -1 && errno(*__errno()) == EAGAIN35)
2116 continue;
2117 if (num_read == 0)
2118 continue;
2119 break;
2120 }
2121 if (!rl_event_hook)
2122 el_set(el, EL_GETCFN13, EL_BUILTIN_GETCFN(((void *)0)));
2123 *wc = (wchar_t)ch;
2124 return (int)num_read;
2125}
2126
2127static void
2128_rl_update_pos(void)
2129{
2130 const LineInfo *li = el_line(e);
2131
2132 rl_point = (int)(li->cursor - li->buffer);
2133 rl_end = (int)(li->lastchar - li->buffer);
2134}
2135
2136void
2137rl_get_screen_size(int *rows, int *cols)
2138{
2139 if (rows)
2140 el_get(e, EL_GETTC17, "li", rows);
2141 if (cols)
2142 el_get(e, EL_GETTC17, "co", cols);
2143}
2144
2145void
2146rl_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_SETTC6, "li", buf, NULL((void *)0));
2151 (void)snprintf(buf, sizeof(buf), "%d", cols);
2152 el_set(e, EL_SETTC6, "co", buf, NULL((void *)0));
2153}
2154
2155char **
2156rl_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((void *)0), max, sizeof(*list))) == NULL((void *)0))
2164 return NULL((void *)0);
2165
2166 while ((match = (*fun)(str, (int)(len - 1))) != NULL((void *)0)) {
2167 list[len++] = match;
2168 if (len == max) {
2169 char **nl;
2170 max += 10;
2171 if ((nl = reallocarray(list, max, sizeof(*nl))) == NULL((void *)0))
2172 goto out;
2173 list = nl;
2174 }
2175 }
2176 if (len == 1)
2177 goto out;
2178 list[len] = NULL((void *)0);
2179 if (len == 2) {
2180 if ((list[0] = strdup(list[1])) == NULL((void *)0))
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_MAX0xffffffffffffffffUL;
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((void *)0))
2196 goto out;
2197 } else {
2198 if ((list[0] = malloc(min + 1)) == NULL((void *)0))
2199 goto out;
2200 (void)memcpy(list[0], list[1], min);
2201 list[0][min] = '\0';
2202 }
2203 return list;
2204
2205out:
2206 free(list);
2207 return NULL((void *)0);
2208}
2209
2210char *
2211rl_filename_completion_function (const char *text, int state)
2212{
2213 return fn_filename_completion_function(text, state);
2214}
2215
2216void
2217rl_forced_update_display(void)
2218{
2219 el_set(e, EL_REFRESH20);
2220}
2221
2222int
2223_rl_abort_internal(void)
2224{
2225 el_beep(e);
2226 longjmp(topbuf, 1);
2227 /*NOTREACHED*/
2228}
2229
2230int
2231_rl_qsort_string_compare(char **s1, char **s2)
2232{
2233 return strcoll(*s1, *s2);
2234}
2235
2236HISTORY_STATE *
2237history_get_history_state(void)
2238{
2239 HISTORY_STATE *hs;
2240
2241 if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL((void *)0))
2242 return NULL((void *)0);
2243 hs->length = history_length;
2244 return hs;
2245}
2246
2247int
2248/*ARGSUSED*/
2249rl_kill_text(int from, int to)
2250{
2251 return 0;
2252}
2253
2254Keymap
2255rl_make_bare_keymap(void)
2256{
2257 return NULL((void *)0);
2258}
2259
2260Keymap
2261rl_get_keymap(void)
2262{
2263 return NULL((void *)0);
2264}
2265
2266void
2267/*ARGSUSED*/
2268rl_set_keymap(Keymap k)
2269{
2270}
2271
2272int
2273/*ARGSUSED*/
2274rl_generic_bind(int type, const char * keyseq, const char * data, Keymap k)
2275{
2276 return 0;
2277}
2278
2279int
2280/*ARGSUSED*/
2281rl_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 */
2287void
2288rl_cleanup_after_signal(void)
2289{
2290}
2291
2292int
2293rl_on_new_line(void)
2294{
2295 return 0;
2296}
2297
2298int
2299/*ARGSUSED*/
2300rl_set_keyboard_input_timeout(int u __attribute__((__unused__)))
2301{
2302 return 0;
2303}