Bug Summary

File:src/lib/libedit/readline.c
Warning:line 472, column 13
Null pointer passed as 1st argument to string length function

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 -pic-is-pie -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 -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);
37
Null pointer passed as 1st argument to string length function
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);
1
'to' initialized to a null pointer value
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])) {
2
Assuming the condition is true
3
Taking true branch
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;
4
Assuming the condition is false
5
'?' condition is false
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))
6
Assuming 'ptr' is not equal to NULL
685 return -1;
686
687 if (!has_mods
6.1
'has_mods' is 1
) {
7
Taking false branch
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? */
8
Assuming the condition is true
9
Taking true branch
701 tmp = strdup(last_search_match? last_search_match:"");
10
Assuming 'last_search_match' is null
11
'?' condition is false
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
11.1
'aptr' is null
)
12
Taking false branch
745 free(aptr);
746
747 if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
13
Assuming the condition is false
14
Assuming the condition is false
15
Taking false branch
748 *result = tmp;
749 return 1;
750 }
751
752 for (; *cmd; cmd++) {
16
Loop condition is true. Entering loop body
753 if (*cmd == ':')
17
Assuming the condition is false
18
Taking false branch
754 continue;
755 else if (*cmd == 'h') { /* remove trailing path */
19
Assuming the condition is false
20
Taking false branch
756 if ((aptr = strrchr(tmp, '/')) != NULL((void *)0))
757 *aptr = '\0';
758 } else if (*cmd == 't') { /* remove leading path */
21
Assuming the condition is false
22
Taking false branch
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 */
23
Assuming the condition is false
24
Taking false branch
765 if ((aptr = strrchr(tmp, '.')) != NULL((void *)0))
766 *aptr = '\0';
767 } else if (*cmd == 'e') { /* remove all but suffix */
25
Assuming the condition is false
26
Taking false branch
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 */
27
Assuming the condition is false
28
Taking false branch
774 p_on = 1;
775 else if (*cmd == 'g')
29
Assuming the condition is false
30
Taking false branch
776 g_on = 2;
777 else if (*cmd == 's' || *cmd == '&') {
31
Assuming the condition is true
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)))
32
Assuming the condition is false
783 continue;
784 else if (*cmd == 's') {
33
Assuming the condition is false
34
Taking false branch
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);
35
Passing null pointer value via 3rd parameter 'with'
36
Calling '_rl_compat_sub'
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))
893 rl_initialize();
894
895 if (history_expansion_char == 0) {
896 *output = strdup(str);
897 return 0;
898 }
899
900 *output = NULL((void *)0);
901 if (str[0] == history_subst_char) {
902 /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
903 size_t sz = 4 + strlen(str) + 1;
904 *output = malloc(sz);
905 if (*output == NULL((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))
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];) {
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++) {
947 if (str[j] == '\\' &&
948 str[j + 1] == history_expansion_char) {
949 size_t sz = strlen(&str[j]) + 1;
950 (void)strlcpy(&str[j], &str[j + 1], sz);
951 continue;
952 }
953 if (!loop_again) {
954 if (isspace((unsigned char) str[j])
955 || str[j] == qchar)
956 break;
957 }
958 if (str[j] == history_expansion_char
959 && !strchr(history_no_expand_chars, str[j + 1])
960 && (!history_inhibit_expansion_function ||
961 (*history_inhibit_expansion_function)(str,
962 (int)j) == 0))
963 break;
964 }
965
966 if (str[j] && loop_again) {
967 i = j;
968 qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
969 j++;
970 if (str[j] == history_expansion_char)
971 j++;
972 loop_again = 0;
973 goto loop;
974 }
975 len = i - start;
976 ADD_STRING(&str[start], len, 0){ 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'; }
;
977
978 if (str[i] == '\0' || str[i] != history_expansion_char) {
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) {
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';
}
;
991 }
992 if (tmp) {
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}