Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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