readline.c revision 220370
1220329Sobrien/* $NetBSD: readline.c,v 1.90 2010/08/04 20:29:18 christos Exp $ */ 2220176Sobrien 3220176Sobrien/*- 4220176Sobrien * Copyright (c) 1997 The NetBSD Foundation, Inc. 5220176Sobrien * All rights reserved. 6220176Sobrien * 7220176Sobrien * This code is derived from software contributed to The NetBSD Foundation 8220176Sobrien * by Jaromir Dolecek. 9220176Sobrien * 10220176Sobrien * Redistribution and use in source and binary forms, with or without 11220176Sobrien * modification, are permitted provided that the following conditions 12220176Sobrien * are met: 13220176Sobrien * 1. Redistributions of source code must retain the above copyright 14220176Sobrien * notice, this list of conditions and the following disclaimer. 15220176Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16220176Sobrien * notice, this list of conditions and the following disclaimer in the 17220176Sobrien * documentation and/or other materials provided with the distribution. 18220176Sobrien * 19220176Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20220176Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21220176Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22220176Sobrien * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23220176Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24220176Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25220176Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26220176Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27220176Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28220176Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29220176Sobrien * POSSIBILITY OF SUCH DAMAGE. 30220176Sobrien */ 31220176Sobrien 32220370Sobrien#include <sys/cdefs.h> 33220329Sobrien__RCSID("$NetBSD: readline.c,v 1.90 2010/08/04 20:29:18 christos Exp $"); 34220370Sobrien__FBSDID("$FreeBSD: head/lib/libedit/readline.c 220370 2011-04-05 18:41:01Z obrien $"); 35220176Sobrien 36220176Sobrien#include <sys/types.h> 37220176Sobrien#include <sys/stat.h> 38220176Sobrien#include <stdio.h> 39220176Sobrien#include <dirent.h> 40220176Sobrien#include <string.h> 41220176Sobrien#include <pwd.h> 42220176Sobrien#include <ctype.h> 43220176Sobrien#include <stdlib.h> 44220176Sobrien#include <unistd.h> 45220176Sobrien#include <limits.h> 46220178Sobrien#include <errno.h> 47220178Sobrien#include <fcntl.h> 48220218Sobrien#include <setjmp.h> 49220178Sobrien#include <vis.h> 50220370Sobrien#include "sys.h" 51220220Sobrien#include "readline/readline.h" 52220370Sobrien#include "chartype.h" 53220178Sobrien#include "el.h" 54220178Sobrien#include "fcns.h" /* for EL_NUM_FCNS */ 55220176Sobrien#include "histedit.h" 56220178Sobrien#include "filecomplete.h" 57220176Sobrien 58220218Sobrienvoid rl_prep_terminal(int); 59220218Sobrienvoid rl_deprep_terminal(void); 60220218Sobrien 61220176Sobrien/* for rl_complete() */ 62220178Sobrien#define TAB '\r' 63220176Sobrien 64220176Sobrien/* see comment at the #ifdef for sense of this */ 65220178Sobrien/* #define GDB_411_HACK */ 66220176Sobrien 67220176Sobrien/* readline compatibility stuff - look at readline sources/documentation */ 68220176Sobrien/* to see what these variables mean */ 69220176Sobrienconst char *rl_library_version = "EditLine wrapper"; 70220220Sobrienint rl_readline_version = RL_READLINE_VERSION; 71220178Sobrienstatic char empty[] = { '\0' }; 72220178Sobrienstatic char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; 73220178Sobrienstatic char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', 74220178Sobrien '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; 75220178Sobrienchar *rl_readline_name = empty; 76220176SobrienFILE *rl_instream = NULL; 77220176SobrienFILE *rl_outstream = NULL; 78220176Sobrienint rl_point = 0; 79220176Sobrienint rl_end = 0; 80220176Sobrienchar *rl_line_buffer = NULL; 81220178SobrienVCPFunction *rl_linefunc = NULL; 82220178Sobrienint rl_done = 0; 83220178SobrienVFunction *rl_event_hook = NULL; 84220218SobrienKEYMAP_ENTRY_ARRAY emacs_standard_keymap, 85220218Sobrien emacs_meta_keymap, 86220218Sobrien emacs_ctlx_keymap; 87220176Sobrien 88220176Sobrienint history_base = 1; /* probably never subject to change */ 89220176Sobrienint history_length = 0; 90220176Sobrienint max_input_history = 0; 91220176Sobrienchar history_expansion_char = '!'; 92220176Sobrienchar history_subst_char = '^'; 93220178Sobrienchar *history_no_expand_chars = expand_chars; 94220176SobrienFunction *history_inhibit_expansion_function = NULL; 95220178Sobrienchar *history_arg_extract(int start, int end, const char *str); 96220176Sobrien 97220176Sobrienint rl_inhibit_completion = 0; 98220176Sobrienint rl_attempted_completion_over = 0; 99220178Sobrienchar *rl_basic_word_break_characters = break_chars; 100220176Sobrienchar *rl_completer_word_break_characters = NULL; 101220176Sobrienchar *rl_completer_quote_characters = NULL; 102220178SobrienFunction *rl_completion_entry_function = NULL; 103220176SobrienCPPFunction *rl_attempted_completion_function = NULL; 104220178SobrienFunction *rl_pre_input_hook = NULL; 105220178SobrienFunction *rl_startup1_hook = NULL; 106220220Sobrienint (*rl_getc_function)(FILE *) = NULL; 107220178Sobrienchar *rl_terminal_name = NULL; 108220178Sobrienint rl_already_prompted = 0; 109220178Sobrienint rl_filename_completion_desired = 0; 110220178Sobrienint rl_ignore_completion_duplicates = 0; 111220178Sobrienint rl_catch_signals = 1; 112220218Sobrienint readline_echoing_p = 1; 113220218Sobrienint _rl_print_completions_horizontally = 0; 114220178SobrienVFunction *rl_redisplay_function = NULL; 115220178SobrienFunction *rl_startup_hook = NULL; 116220178SobrienVFunction *rl_completion_display_matches_hook = NULL; 117220218SobrienVFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; 118220218SobrienVFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; 119220220SobrienKEYMAP_ENTRY_ARRAY emacs_meta_keymap; 120220176Sobrien 121220220Sobrien#ifdef WIDECHAR 122220220Sobrienstatic ct_buffer_t conv; 123220220Sobrien#endif 124220220Sobrien 125220176Sobrien/* 126220178Sobrien * The current prompt string. 127220178Sobrien */ 128220178Sobrienchar *rl_prompt = NULL; 129220178Sobrien/* 130220176Sobrien * This is set to character indicating type of completion being done by 131220176Sobrien * rl_complete_internal(); this is available for application completion 132220176Sobrien * functions. 133220176Sobrien */ 134220176Sobrienint rl_completion_type = 0; 135220176Sobrien 136220176Sobrien/* 137220176Sobrien * If more than this number of items results from query for possible 138220176Sobrien * completions, we ask user if they are sure to really display the list. 139220176Sobrien */ 140220176Sobrienint rl_completion_query_items = 100; 141220176Sobrien 142220176Sobrien/* 143220176Sobrien * List of characters which are word break characters, but should be left 144220176Sobrien * in the parsed text when it is passed to the completion function. 145220176Sobrien * Shell uses this to help determine what kind of completing to do. 146220176Sobrien */ 147220178Sobrienchar *rl_special_prefixes = NULL; 148220176Sobrien 149220176Sobrien/* 150220176Sobrien * This is the character appended to the completed words if at the end of 151220176Sobrien * the line. Default is ' ' (a space). 152220176Sobrien */ 153220176Sobrienint rl_completion_append_character = ' '; 154220176Sobrien 155220176Sobrien/* stuff below is used internally by libedit for readline emulation */ 156220176Sobrien 157220220Sobrienstatic TYPE(History) *h = NULL; 158220176Sobrienstatic EditLine *e = NULL; 159220178Sobrienstatic Function *map[256]; 160220218Sobrienstatic jmp_buf topbuf; 161220176Sobrien 162220176Sobrien/* internal functions */ 163220176Sobrienstatic unsigned char _el_rl_complete(EditLine *, int); 164220178Sobrienstatic unsigned char _el_rl_tstp(EditLine *, int); 165220176Sobrienstatic char *_get_prompt(EditLine *); 166220216Sobrienstatic int _getc_function(EditLine *, char *); 167220176Sobrienstatic HIST_ENTRY *_move_history(int); 168220178Sobrienstatic int _history_expand_command(const char *, size_t, size_t, 169220178Sobrien char **); 170220176Sobrienstatic char *_rl_compat_sub(const char *, const char *, 171220178Sobrien const char *, int); 172220178Sobrienstatic int _rl_event_read_char(EditLine *, char *); 173220178Sobrienstatic void _rl_update_pos(void); 174220176Sobrien 175220176Sobrien 176220176Sobrien/* ARGSUSED */ 177220176Sobrienstatic char * 178220178Sobrien_get_prompt(EditLine *el __attribute__((__unused__))) 179220176Sobrien{ 180220178Sobrien rl_already_prompted = 1; 181220178Sobrien return (rl_prompt); 182220176Sobrien} 183220176Sobrien 184220176Sobrien 185220176Sobrien/* 186220176Sobrien * generic function for moving around history 187220176Sobrien */ 188220176Sobrienstatic HIST_ENTRY * 189220176Sobrien_move_history(int op) 190220176Sobrien{ 191220220Sobrien TYPE(HistEvent) ev; 192220176Sobrien static HIST_ENTRY rl_he; 193220176Sobrien 194220220Sobrien if (FUNW(history)(h, &ev, op) != 0) 195220176Sobrien return (HIST_ENTRY *) NULL; 196220176Sobrien 197220220Sobrien rl_he.line = ct_encode_string(ev.str, &conv); 198220178Sobrien rl_he.data = NULL; 199220176Sobrien 200220176Sobrien return (&rl_he); 201220176Sobrien} 202220176Sobrien 203220176Sobrien 204220176Sobrien/* 205220216Sobrien * read one key from user defined input function 206220216Sobrien */ 207220216Sobrienstatic int 208220216Sobrien/*ARGSUSED*/ 209220216Sobrien_getc_function(EditLine *el, char *c) 210220216Sobrien{ 211220216Sobrien int i; 212220216Sobrien 213220220Sobrien i = (*rl_getc_function)(NULL); 214220216Sobrien if (i == -1) 215220216Sobrien return 0; 216220216Sobrien *c = i; 217220216Sobrien return 1; 218220216Sobrien} 219220216Sobrien 220220220Sobrienstatic const char _dothistory[] = "/.history"; 221220216Sobrien 222220220Sobrienstatic const char * 223220220Sobrien_default_history_file(void) 224220220Sobrien{ 225220220Sobrien struct passwd *p; 226220220Sobrien static char path[PATH_MAX]; 227220220Sobrien 228220220Sobrien if (*path) 229220220Sobrien return path; 230220220Sobrien if ((p = getpwuid(getuid())) == NULL) 231220220Sobrien return NULL; 232220220Sobrien strlcpy(path, p->pw_dir, PATH_MAX); 233220220Sobrien strlcat(path, _dothistory, PATH_MAX); 234220220Sobrien return path; 235220220Sobrien} 236220220Sobrien 237220216Sobrien/* 238220176Sobrien * READLINE compatibility stuff 239220176Sobrien */ 240220176Sobrien 241220176Sobrien/* 242220220Sobrien * Set the prompt 243220220Sobrien */ 244220220Sobrienint 245220220Sobrienrl_set_prompt(const char *prompt) 246220220Sobrien{ 247220220Sobrien char *p; 248220220Sobrien 249220220Sobrien if (!prompt) 250220220Sobrien prompt = ""; 251220220Sobrien if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) 252220220Sobrien return 0; 253220220Sobrien if (rl_prompt) 254220220Sobrien free(rl_prompt); 255220220Sobrien rl_prompt = strdup(prompt); 256220220Sobrien if (rl_prompt == NULL) 257220220Sobrien return -1; 258220220Sobrien 259220220Sobrien while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) 260220220Sobrien *p = RL_PROMPT_START_IGNORE; 261220220Sobrien 262220220Sobrien return 0; 263220220Sobrien} 264220220Sobrien 265220220Sobrien/* 266220176Sobrien * initialize rl compat stuff 267220176Sobrien */ 268220176Sobrienint 269220176Sobrienrl_initialize(void) 270220176Sobrien{ 271220220Sobrien TYPE(HistEvent) ev; 272220176Sobrien const LineInfo *li; 273220176Sobrien int editmode = 1; 274220176Sobrien struct termios t; 275220176Sobrien 276220176Sobrien if (e != NULL) 277220176Sobrien el_end(e); 278220176Sobrien if (h != NULL) 279220220Sobrien FUN(history,end)(h); 280220176Sobrien 281220176Sobrien if (!rl_instream) 282220176Sobrien rl_instream = stdin; 283220176Sobrien if (!rl_outstream) 284220176Sobrien rl_outstream = stdout; 285220176Sobrien 286220176Sobrien /* 287220176Sobrien * See if we don't really want to run the editor 288220176Sobrien */ 289220176Sobrien if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) 290220176Sobrien editmode = 0; 291220176Sobrien 292220176Sobrien e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); 293220176Sobrien 294220176Sobrien if (!editmode) 295220220Sobrien FUN(el,set)(e, EL_EDITMODE, 0); 296220176Sobrien 297220220Sobrien h = FUN(history,init)(); 298220176Sobrien if (!e || !h) 299220176Sobrien return (-1); 300220176Sobrien 301220220Sobrien FUNW(history)(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ 302220176Sobrien history_length = 0; 303220176Sobrien max_input_history = INT_MAX; 304220176Sobrien el_set(e, EL_HIST, history, h); 305220176Sobrien 306220216Sobrien /* setup getc function if valid */ 307220216Sobrien if (rl_getc_function) 308220216Sobrien el_set(e, EL_GETCFN, _getc_function); 309220216Sobrien 310220176Sobrien /* for proper prompt printing in readline() */ 311220220Sobrien if (rl_set_prompt("") == -1) { 312220220Sobrien FUN(history,end)(h); 313220178Sobrien el_end(e); 314220178Sobrien return -1; 315220178Sobrien } 316220220Sobrien el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); 317220178Sobrien el_set(e, EL_SIGNAL, rl_catch_signals); 318220176Sobrien 319220176Sobrien /* set default mode to "emacs"-style and read setting afterwards */ 320220176Sobrien /* so this can be overriden */ 321220176Sobrien el_set(e, EL_EDITOR, "emacs"); 322220178Sobrien if (rl_terminal_name != NULL) 323220178Sobrien el_set(e, EL_TERMINAL, rl_terminal_name); 324220178Sobrien else 325220178Sobrien el_get(e, EL_TERMINAL, &rl_terminal_name); 326220176Sobrien 327220176Sobrien /* 328220178Sobrien * Word completion - this has to go AFTER rebinding keys 329220176Sobrien * to emacs-style. 330220176Sobrien */ 331220176Sobrien el_set(e, EL_ADDFN, "rl_complete", 332220178Sobrien "ReadLine compatible completion function", 333220176Sobrien _el_rl_complete); 334220176Sobrien el_set(e, EL_BIND, "^I", "rl_complete", NULL); 335220176Sobrien 336220176Sobrien /* 337220178Sobrien * Send TSTP when ^Z is pressed. 338220176Sobrien */ 339220178Sobrien el_set(e, EL_ADDFN, "rl_tstp", 340220178Sobrien "ReadLine compatible suspend function", 341220178Sobrien _el_rl_tstp); 342220178Sobrien el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); 343220176Sobrien 344220176Sobrien /* read settings from configuration file */ 345220176Sobrien el_source(e, NULL); 346220176Sobrien 347220176Sobrien /* 348220176Sobrien * Unfortunately, some applications really do use rl_point 349220176Sobrien * and rl_line_buffer directly. 350220176Sobrien */ 351220176Sobrien li = el_line(e); 352220178Sobrien /* a cheesy way to get rid of const cast. */ 353220178Sobrien rl_line_buffer = memchr(li->buffer, *li->buffer, 1); 354220178Sobrien _rl_update_pos(); 355220176Sobrien 356220178Sobrien if (rl_startup_hook) 357220178Sobrien (*rl_startup_hook)(NULL, 0); 358220178Sobrien 359220176Sobrien return (0); 360220176Sobrien} 361220176Sobrien 362220176Sobrien 363220176Sobrien/* 364220176Sobrien * read one line from input stream and return it, chomping 365220176Sobrien * trailing newline (if there is any) 366220176Sobrien */ 367220176Sobrienchar * 368220218Sobrienreadline(const char *p) 369220176Sobrien{ 370220220Sobrien TYPE(HistEvent) ev; 371220218Sobrien const char * volatile prompt = p; 372220176Sobrien int count; 373220176Sobrien const char *ret; 374220178Sobrien char *buf; 375220178Sobrien static int used_event_hook; 376220176Sobrien 377220176Sobrien if (e == NULL || h == NULL) 378220176Sobrien rl_initialize(); 379220176Sobrien 380220178Sobrien rl_done = 0; 381220178Sobrien 382220218Sobrien (void)setjmp(topbuf); 383220218Sobrien 384220176Sobrien /* update prompt accordingly to what has been passed */ 385220220Sobrien if (rl_set_prompt(prompt) == -1) 386220220Sobrien return NULL; 387220178Sobrien 388220178Sobrien if (rl_pre_input_hook) 389220178Sobrien (*rl_pre_input_hook)(NULL, 0); 390220178Sobrien 391220178Sobrien if (rl_event_hook && !(e->el_flags&NO_TTY)) { 392220178Sobrien el_set(e, EL_GETCFN, _rl_event_read_char); 393220178Sobrien used_event_hook = 1; 394220178Sobrien } 395220178Sobrien 396220178Sobrien if (!rl_event_hook && used_event_hook) { 397220178Sobrien el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); 398220178Sobrien used_event_hook = 0; 399220178Sobrien } 400220178Sobrien 401220178Sobrien rl_already_prompted = 0; 402220178Sobrien 403220176Sobrien /* get one line from input stream */ 404220176Sobrien ret = el_gets(e, &count); 405220176Sobrien 406220176Sobrien if (ret && count > 0) { 407220176Sobrien int lastidx; 408220176Sobrien 409220178Sobrien buf = strdup(ret); 410220178Sobrien if (buf == NULL) 411220178Sobrien return NULL; 412220176Sobrien lastidx = count - 1; 413220178Sobrien if (buf[lastidx] == '\n') 414220178Sobrien buf[lastidx] = '\0'; 415220176Sobrien } else 416220178Sobrien buf = NULL; 417220176Sobrien 418220220Sobrien FUNW(history)(h, &ev, H_GETSIZE); 419220176Sobrien history_length = ev.num; 420220176Sobrien 421220178Sobrien return buf; 422220176Sobrien} 423220176Sobrien 424220176Sobrien/* 425220176Sobrien * history functions 426220176Sobrien */ 427220176Sobrien 428220176Sobrien/* 429220176Sobrien * is normally called before application starts to use 430220176Sobrien * history expansion functions 431220176Sobrien */ 432220176Sobrienvoid 433220176Sobrienusing_history(void) 434220176Sobrien{ 435220176Sobrien if (h == NULL || e == NULL) 436220176Sobrien rl_initialize(); 437220176Sobrien} 438220176Sobrien 439220176Sobrien 440220176Sobrien/* 441220176Sobrien * substitute ``what'' with ``with'', returning resulting string; if 442220178Sobrien * globally == 1, substitutes all occurrences of what, otherwise only the 443220176Sobrien * first one 444220176Sobrien */ 445220176Sobrienstatic char * 446220176Sobrien_rl_compat_sub(const char *str, const char *what, const char *with, 447220176Sobrien int globally) 448220176Sobrien{ 449220178Sobrien const char *s; 450220178Sobrien char *r, *result; 451220178Sobrien size_t len, with_len, what_len; 452220176Sobrien 453220178Sobrien len = strlen(str); 454220176Sobrien with_len = strlen(with); 455220176Sobrien what_len = strlen(what); 456220178Sobrien 457220178Sobrien /* calculate length we need for result */ 458220178Sobrien s = str; 459220178Sobrien while (*s) { 460220178Sobrien if (*s == *what && !strncmp(s, what, what_len)) { 461220178Sobrien len += with_len - what_len; 462220178Sobrien if (!globally) 463220178Sobrien break; 464220178Sobrien s += what_len; 465220178Sobrien } else 466220178Sobrien s++; 467220178Sobrien } 468220178Sobrien r = result = malloc(len + 1); 469220178Sobrien if (result == NULL) 470220178Sobrien return NULL; 471220178Sobrien s = str; 472220178Sobrien while (*s) { 473220178Sobrien if (*s == *what && !strncmp(s, what, what_len)) { 474220178Sobrien (void)strncpy(r, with, with_len); 475220178Sobrien r += with_len; 476220178Sobrien s += what_len; 477220178Sobrien if (!globally) { 478220178Sobrien (void)strcpy(r, s); 479220178Sobrien return(result); 480220176Sobrien } 481220178Sobrien } else 482220178Sobrien *r++ = *s++; 483220178Sobrien } 484220220Sobrien *r = '\0'; 485220178Sobrien return(result); 486220178Sobrien} 487220178Sobrien 488220178Sobrienstatic char *last_search_pat; /* last !?pat[?] search pattern */ 489220178Sobrienstatic char *last_search_match; /* last !?pat[?] that matched */ 490220178Sobrien 491220178Sobrienconst char * 492220178Sobrienget_history_event(const char *cmd, int *cindex, int qchar) 493220178Sobrien{ 494220178Sobrien int idx, sign, sub, num, begin, ret; 495220178Sobrien size_t len; 496220178Sobrien char *pat; 497220178Sobrien const char *rptr; 498220220Sobrien TYPE(HistEvent) ev; 499220178Sobrien 500220178Sobrien idx = *cindex; 501220178Sobrien if (cmd[idx++] != history_expansion_char) 502220178Sobrien return(NULL); 503220178Sobrien 504220178Sobrien /* find out which event to take */ 505220220Sobrien if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { 506220220Sobrien if (FUNW(history)(h, &ev, H_FIRST) != 0) 507220178Sobrien return(NULL); 508220178Sobrien *cindex = cmd[idx]? (idx + 1):idx; 509220220Sobrien return ct_encode_string(ev.str, &conv); 510220178Sobrien } 511220178Sobrien sign = 0; 512220178Sobrien if (cmd[idx] == '-') { 513220178Sobrien sign = 1; 514220178Sobrien idx++; 515220178Sobrien } 516220178Sobrien 517220178Sobrien if ('0' <= cmd[idx] && cmd[idx] <= '9') { 518220178Sobrien HIST_ENTRY *rl_he; 519220178Sobrien 520220178Sobrien num = 0; 521220178Sobrien while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { 522220178Sobrien num = num * 10 + cmd[idx] - '0'; 523220178Sobrien idx++; 524220176Sobrien } 525220178Sobrien if (sign) 526220178Sobrien num = history_length - num + 1; 527220176Sobrien 528220178Sobrien if (!(rl_he = history_get(num))) 529220178Sobrien return(NULL); 530220178Sobrien 531220178Sobrien *cindex = idx; 532220178Sobrien return(rl_he->line); 533220178Sobrien } 534220178Sobrien sub = 0; 535220178Sobrien if (cmd[idx] == '?') { 536220178Sobrien sub = 1; 537220178Sobrien idx++; 538220178Sobrien } 539220178Sobrien begin = idx; 540220178Sobrien while (cmd[idx]) { 541220178Sobrien if (cmd[idx] == '\n') 542220178Sobrien break; 543220178Sobrien if (sub && cmd[idx] == '?') 544220178Sobrien break; 545220178Sobrien if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' 546220178Sobrien || cmd[idx] == '\t' || cmd[idx] == qchar)) 547220178Sobrien break; 548220178Sobrien idx++; 549220178Sobrien } 550220178Sobrien len = idx - begin; 551220178Sobrien if (sub && cmd[idx] == '?') 552220178Sobrien idx++; 553220178Sobrien if (sub && len == 0 && last_search_pat && *last_search_pat) 554220178Sobrien pat = last_search_pat; 555220178Sobrien else if (len == 0) 556220178Sobrien return(NULL); 557220178Sobrien else { 558220178Sobrien if ((pat = malloc(len + 1)) == NULL) 559220178Sobrien return NULL; 560220178Sobrien (void)strncpy(pat, cmd + begin, len); 561220178Sobrien pat[len] = '\0'; 562220178Sobrien } 563220178Sobrien 564220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) { 565220178Sobrien if (pat != last_search_pat) 566220178Sobrien free(pat); 567220178Sobrien return (NULL); 568220178Sobrien } 569220178Sobrien num = ev.num; 570220178Sobrien 571220178Sobrien if (sub) { 572220178Sobrien if (pat != last_search_pat) { 573220178Sobrien if (last_search_pat) 574220178Sobrien free(last_search_pat); 575220178Sobrien last_search_pat = pat; 576220178Sobrien } 577220178Sobrien ret = history_search(pat, -1); 578220178Sobrien } else 579220178Sobrien ret = history_search_prefix(pat, -1); 580220178Sobrien 581220178Sobrien if (ret == -1) { 582220178Sobrien /* restore to end of list on failed search */ 583220220Sobrien FUNW(history)(h, &ev, H_FIRST); 584220178Sobrien (void)fprintf(rl_outstream, "%s: Event not found\n", pat); 585220178Sobrien if (pat != last_search_pat) 586220178Sobrien free(pat); 587220178Sobrien return(NULL); 588220178Sobrien } 589220178Sobrien 590220178Sobrien if (sub && len) { 591220178Sobrien if (last_search_match && last_search_match != pat) 592220178Sobrien free(last_search_match); 593220178Sobrien last_search_match = pat; 594220178Sobrien } 595220178Sobrien 596220178Sobrien if (pat != last_search_pat) 597220178Sobrien free(pat); 598220178Sobrien 599220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 600220178Sobrien return(NULL); 601220178Sobrien *cindex = idx; 602220220Sobrien rptr = ct_encode_string(ev.str, &conv); 603220178Sobrien 604220178Sobrien /* roll back to original position */ 605220220Sobrien (void)FUNW(history)(h, &ev, H_SET, num); 606220178Sobrien 607220178Sobrien return rptr; 608220176Sobrien} 609220176Sobrien 610220176Sobrien/* 611220176Sobrien * the real function doing history expansion - takes as argument command 612220176Sobrien * to do and data upon which the command should be executed 613220176Sobrien * does expansion the way I've understood readline documentation 614220176Sobrien * 615220176Sobrien * returns 0 if data was not modified, 1 if it was and 2 if the string 616220176Sobrien * should be only printed and not executed; in case of error, 617220176Sobrien * returns -1 and *result points to NULL 618220176Sobrien * it's callers responsibility to free() string returned in *result 619220176Sobrien */ 620220176Sobrienstatic int 621220178Sobrien_history_expand_command(const char *command, size_t offs, size_t cmdlen, 622220178Sobrien char **result) 623220176Sobrien{ 624220178Sobrien char *tmp, *search = NULL, *aptr; 625220178Sobrien const char *ptr, *cmd; 626220176Sobrien static char *from = NULL, *to = NULL; 627220178Sobrien int start, end, idx, has_mods = 0; 628220178Sobrien int p_on = 0, g_on = 0; 629220176Sobrien 630220176Sobrien *result = NULL; 631220178Sobrien aptr = NULL; 632220178Sobrien ptr = NULL; 633220176Sobrien 634220178Sobrien /* First get event specifier */ 635220178Sobrien idx = 0; 636220176Sobrien 637220178Sobrien if (strchr(":^*$", command[offs + 1])) { 638220178Sobrien char str[4]; 639220178Sobrien /* 640220178Sobrien * "!:" is shorthand for "!!:". 641220178Sobrien * "!^", "!*" and "!$" are shorthand for 642220178Sobrien * "!!:^", "!!:*" and "!!:$" respectively. 643220178Sobrien */ 644220178Sobrien str[0] = str[1] = '!'; 645220178Sobrien str[2] = '0'; 646220178Sobrien ptr = get_history_event(str, &idx, 0); 647220178Sobrien idx = (command[offs + 1] == ':')? 1:0; 648220178Sobrien has_mods = 1; 649220176Sobrien } else { 650220178Sobrien if (command[offs + 1] == '#') { 651220178Sobrien /* use command so far */ 652220178Sobrien if ((aptr = malloc(offs + 1)) == NULL) 653220178Sobrien return -1; 654220178Sobrien (void)strncpy(aptr, command, offs); 655220178Sobrien aptr[offs] = '\0'; 656220178Sobrien idx = 1; 657220176Sobrien } else { 658220178Sobrien int qchar; 659220176Sobrien 660220178Sobrien qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; 661220178Sobrien ptr = get_history_event(command + offs, &idx, qchar); 662220178Sobrien } 663220178Sobrien has_mods = command[offs + idx] == ':'; 664220178Sobrien } 665220176Sobrien 666220178Sobrien if (ptr == NULL && aptr == NULL) 667220178Sobrien return(-1); 668220176Sobrien 669220178Sobrien if (!has_mods) { 670220220Sobrien *result = strdup(aptr ? aptr : ptr); 671220178Sobrien if (aptr) 672220178Sobrien free(aptr); 673220220Sobrien if (*result == NULL) 674220220Sobrien return -1; 675220178Sobrien return(1); 676220178Sobrien } 677220176Sobrien 678220178Sobrien cmd = command + offs + idx + 1; 679220176Sobrien 680220178Sobrien /* Now parse any word designators */ 681220178Sobrien 682220178Sobrien if (*cmd == '%') /* last word matched by ?pat? */ 683220178Sobrien tmp = strdup(last_search_match? last_search_match:""); 684220178Sobrien else if (strchr("^*$-0123456789", *cmd)) { 685220178Sobrien start = end = -1; 686220178Sobrien if (*cmd == '^') 687220178Sobrien start = end = 1, cmd++; 688220178Sobrien else if (*cmd == '$') 689220178Sobrien start = -1, cmd++; 690220178Sobrien else if (*cmd == '*') 691220178Sobrien start = 1, cmd++; 692220178Sobrien else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { 693220178Sobrien start = 0; 694220178Sobrien while (*cmd && '0' <= *cmd && *cmd <= '9') 695220178Sobrien start = start * 10 + *cmd++ - '0'; 696220178Sobrien 697220178Sobrien if (*cmd == '-') { 698220178Sobrien if (isdigit((unsigned char) cmd[1])) { 699220178Sobrien cmd++; 700220178Sobrien end = 0; 701220178Sobrien while (*cmd && '0' <= *cmd && *cmd <= '9') 702220178Sobrien end = end * 10 + *cmd++ - '0'; 703220178Sobrien } else if (cmd[1] == '$') { 704220178Sobrien cmd += 2; 705220178Sobrien end = -1; 706220178Sobrien } else { 707220178Sobrien cmd++; 708220178Sobrien end = -2; 709220178Sobrien } 710220178Sobrien } else if (*cmd == '*') 711220178Sobrien end = -1, cmd++; 712220178Sobrien else 713220178Sobrien end = start; 714220176Sobrien } 715220178Sobrien tmp = history_arg_extract(start, end, aptr? aptr:ptr); 716220178Sobrien if (tmp == NULL) { 717220178Sobrien (void)fprintf(rl_outstream, "%s: Bad word specifier", 718220178Sobrien command + offs + idx); 719220178Sobrien if (aptr) 720220178Sobrien free(aptr); 721220178Sobrien return(-1); 722220178Sobrien } 723220176Sobrien } else 724220178Sobrien tmp = strdup(aptr? aptr:ptr); 725220176Sobrien 726220178Sobrien if (aptr) 727220178Sobrien free(aptr); 728220176Sobrien 729220220Sobrien if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { 730220178Sobrien *result = tmp; 731220178Sobrien return(1); 732220176Sobrien } 733220176Sobrien 734220176Sobrien for (; *cmd; cmd++) { 735220176Sobrien if (*cmd == ':') 736220176Sobrien continue; 737220178Sobrien else if (*cmd == 'h') { /* remove trailing path */ 738220178Sobrien if ((aptr = strrchr(tmp, '/')) != NULL) 739220220Sobrien *aptr = '\0'; 740220178Sobrien } else if (*cmd == 't') { /* remove leading path */ 741220178Sobrien if ((aptr = strrchr(tmp, '/')) != NULL) { 742220178Sobrien aptr = strdup(aptr + 1); 743220178Sobrien free(tmp); 744220178Sobrien tmp = aptr; 745220178Sobrien } 746220178Sobrien } else if (*cmd == 'r') { /* remove trailing suffix */ 747220178Sobrien if ((aptr = strrchr(tmp, '.')) != NULL) 748220220Sobrien *aptr = '\0'; 749220178Sobrien } else if (*cmd == 'e') { /* remove all but suffix */ 750220178Sobrien if ((aptr = strrchr(tmp, '.')) != NULL) { 751220178Sobrien aptr = strdup(aptr); 752220178Sobrien free(tmp); 753220178Sobrien tmp = aptr; 754220178Sobrien } 755220178Sobrien } else if (*cmd == 'p') /* print only */ 756220178Sobrien p_on = 1; 757220176Sobrien else if (*cmd == 'g') 758220176Sobrien g_on = 2; 759220176Sobrien else if (*cmd == 's' || *cmd == '&') { 760220176Sobrien char *what, *with, delim; 761220178Sobrien size_t len, from_len; 762220176Sobrien size_t size; 763220176Sobrien 764220176Sobrien if (*cmd == '&' && (from == NULL || to == NULL)) 765220176Sobrien continue; 766220176Sobrien else if (*cmd == 's') { 767220176Sobrien delim = *(++cmd), cmd++; 768220176Sobrien size = 16; 769220176Sobrien what = realloc(from, size); 770220178Sobrien if (what == NULL) { 771220178Sobrien free(from); 772220216Sobrien free(tmp); 773220178Sobrien return 0; 774220178Sobrien } 775220176Sobrien len = 0; 776220176Sobrien for (; *cmd && *cmd != delim; cmd++) { 777220178Sobrien if (*cmd == '\\' && cmd[1] == delim) 778220176Sobrien cmd++; 779220178Sobrien if (len >= size) { 780220178Sobrien char *nwhat; 781220178Sobrien nwhat = realloc(what, 782220178Sobrien (size <<= 1)); 783220178Sobrien if (nwhat == NULL) { 784220178Sobrien free(what); 785220216Sobrien free(tmp); 786220178Sobrien return 0; 787220178Sobrien } 788220178Sobrien what = nwhat; 789220178Sobrien } 790220176Sobrien what[len++] = *cmd; 791220176Sobrien } 792220176Sobrien what[len] = '\0'; 793220176Sobrien from = what; 794220176Sobrien if (*what == '\0') { 795220176Sobrien free(what); 796220178Sobrien if (search) { 797220176Sobrien from = strdup(search); 798220216Sobrien if (from == NULL) { 799220216Sobrien free(tmp); 800220178Sobrien return 0; 801220216Sobrien } 802220178Sobrien } else { 803220176Sobrien from = NULL; 804220216Sobrien free(tmp); 805220176Sobrien return (-1); 806220176Sobrien } 807220176Sobrien } 808220176Sobrien cmd++; /* shift after delim */ 809220176Sobrien if (!*cmd) 810220176Sobrien continue; 811220176Sobrien 812220176Sobrien size = 16; 813220176Sobrien with = realloc(to, size); 814220178Sobrien if (with == NULL) { 815220178Sobrien free(to); 816220216Sobrien free(tmp); 817220178Sobrien return -1; 818220178Sobrien } 819220176Sobrien len = 0; 820220176Sobrien from_len = strlen(from); 821220176Sobrien for (; *cmd && *cmd != delim; cmd++) { 822220176Sobrien if (len + from_len + 1 >= size) { 823220178Sobrien char *nwith; 824220176Sobrien size += from_len + 1; 825220178Sobrien nwith = realloc(with, size); 826220178Sobrien if (nwith == NULL) { 827220178Sobrien free(with); 828220216Sobrien free(tmp); 829220178Sobrien return -1; 830220178Sobrien } 831220178Sobrien with = nwith; 832220176Sobrien } 833220176Sobrien if (*cmd == '&') { 834220176Sobrien /* safe */ 835220178Sobrien (void)strcpy(&with[len], from); 836220176Sobrien len += from_len; 837220176Sobrien continue; 838220176Sobrien } 839220176Sobrien if (*cmd == '\\' 840220176Sobrien && (*(cmd + 1) == delim 841220176Sobrien || *(cmd + 1) == '&')) 842220176Sobrien cmd++; 843220176Sobrien with[len++] = *cmd; 844220176Sobrien } 845220176Sobrien with[len] = '\0'; 846220176Sobrien to = with; 847220178Sobrien } 848220176Sobrien 849220178Sobrien aptr = _rl_compat_sub(tmp, from, to, g_on); 850220178Sobrien if (aptr) { 851220178Sobrien free(tmp); 852220178Sobrien tmp = aptr; 853220176Sobrien } 854220178Sobrien g_on = 0; 855220176Sobrien } 856220176Sobrien } 857220178Sobrien *result = tmp; 858220178Sobrien return (p_on? 2:1); 859220176Sobrien} 860220176Sobrien 861220176Sobrien 862220176Sobrien/* 863220176Sobrien * csh-style history expansion 864220176Sobrien */ 865220176Sobrienint 866220176Sobrienhistory_expand(char *str, char **output) 867220176Sobrien{ 868220178Sobrien int ret = 0; 869220178Sobrien size_t idx, i, size; 870220178Sobrien char *tmp, *result; 871220176Sobrien 872220176Sobrien if (h == NULL || e == NULL) 873220176Sobrien rl_initialize(); 874220176Sobrien 875220178Sobrien if (history_expansion_char == 0) { 876220178Sobrien *output = strdup(str); 877220178Sobrien return(0); 878220178Sobrien } 879220176Sobrien 880220178Sobrien *output = NULL; 881220176Sobrien if (str[0] == history_subst_char) { 882220176Sobrien /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ 883220178Sobrien *output = malloc(strlen(str) + 4 + 1); 884220178Sobrien if (*output == NULL) 885220178Sobrien return 0; 886220178Sobrien (*output)[0] = (*output)[1] = history_expansion_char; 887220178Sobrien (*output)[2] = ':'; 888220178Sobrien (*output)[3] = 's'; 889220178Sobrien (void)strcpy((*output) + 4, str); 890220178Sobrien str = *output; 891220178Sobrien } else { 892220178Sobrien *output = strdup(str); 893220178Sobrien if (*output == NULL) 894220178Sobrien return 0; 895220176Sobrien } 896220178Sobrien 897220216Sobrien#define ADD_STRING(what, len, fr) \ 898220176Sobrien { \ 899220178Sobrien if (idx + len + 1 > size) { \ 900220178Sobrien char *nresult = realloc(result, (size += len + 1));\ 901220178Sobrien if (nresult == NULL) { \ 902220178Sobrien free(*output); \ 903220216Sobrien if (/*CONSTCOND*/fr) \ 904220216Sobrien free(tmp); \ 905220178Sobrien return 0; \ 906220178Sobrien } \ 907220178Sobrien result = nresult; \ 908220178Sobrien } \ 909220176Sobrien (void)strncpy(&result[idx], what, len); \ 910220176Sobrien idx += len; \ 911220176Sobrien result[idx] = '\0'; \ 912220176Sobrien } 913220176Sobrien 914220176Sobrien result = NULL; 915220176Sobrien size = idx = 0; 916220216Sobrien tmp = NULL; 917220176Sobrien for (i = 0; str[i];) { 918220178Sobrien int qchar, loop_again; 919220178Sobrien size_t len, start, j; 920220176Sobrien 921220178Sobrien qchar = 0; 922220176Sobrien loop_again = 1; 923220176Sobrien start = j = i; 924220176Sobrienloop: 925220176Sobrien for (; str[j]; j++) { 926220176Sobrien if (str[j] == '\\' && 927220176Sobrien str[j + 1] == history_expansion_char) { 928220178Sobrien (void)strcpy(&str[j], &str[j + 1]); 929220176Sobrien continue; 930220176Sobrien } 931220176Sobrien if (!loop_again) { 932220178Sobrien if (isspace((unsigned char) str[j]) 933220178Sobrien || str[j] == qchar) 934220176Sobrien break; 935220176Sobrien } 936220176Sobrien if (str[j] == history_expansion_char 937220176Sobrien && !strchr(history_no_expand_chars, str[j + 1]) 938220176Sobrien && (!history_inhibit_expansion_function || 939220178Sobrien (*history_inhibit_expansion_function)(str, 940220178Sobrien (int)j) == 0)) 941220176Sobrien break; 942220176Sobrien } 943220176Sobrien 944220178Sobrien if (str[j] && loop_again) { 945220176Sobrien i = j; 946220178Sobrien qchar = (j > 0 && str[j - 1] == '"' )? '"':0; 947220176Sobrien j++; 948220176Sobrien if (str[j] == history_expansion_char) 949220176Sobrien j++; 950220176Sobrien loop_again = 0; 951220176Sobrien goto loop; 952220176Sobrien } 953220176Sobrien len = i - start; 954220216Sobrien ADD_STRING(&str[start], len, 0); 955220176Sobrien 956220178Sobrien if (str[i] == '\0' || str[i] != history_expansion_char) { 957220176Sobrien len = j - i; 958220216Sobrien ADD_STRING(&str[i], len, 0); 959220176Sobrien if (start == 0) 960220178Sobrien ret = 0; 961220176Sobrien else 962220178Sobrien ret = 1; 963220176Sobrien break; 964220176Sobrien } 965220178Sobrien ret = _history_expand_command (str, i, (j - i), &tmp); 966220178Sobrien if (ret > 0 && tmp) { 967220178Sobrien len = strlen(tmp); 968220216Sobrien ADD_STRING(tmp, len, 1); 969220216Sobrien } 970220216Sobrien if (tmp) { 971220178Sobrien free(tmp); 972220216Sobrien tmp = NULL; 973220176Sobrien } 974220176Sobrien i = j; 975220178Sobrien } 976220176Sobrien 977220178Sobrien /* ret is 2 for "print only" option */ 978220178Sobrien if (ret == 2) { 979220178Sobrien add_history(result); 980220176Sobrien#ifdef GDB_411_HACK 981220176Sobrien /* gdb 4.11 has been shipped with readline, where */ 982220176Sobrien /* history_expand() returned -1 when the line */ 983220176Sobrien /* should not be executed; in readline 2.1+ */ 984220176Sobrien /* it should return 2 in such a case */ 985220178Sobrien ret = -1; 986220176Sobrien#endif 987220176Sobrien } 988220176Sobrien free(*output); 989220176Sobrien *output = result; 990220176Sobrien 991220178Sobrien return (ret); 992220176Sobrien} 993220176Sobrien 994220178Sobrien/* 995220178Sobrien* Return a string consisting of arguments of "str" from "start" to "end". 996220178Sobrien*/ 997220178Sobrienchar * 998220178Sobrienhistory_arg_extract(int start, int end, const char *str) 999220178Sobrien{ 1000220178Sobrien size_t i, len, max; 1001220220Sobrien char **arr, *result = NULL; 1002220176Sobrien 1003220178Sobrien arr = history_tokenize(str); 1004220178Sobrien if (!arr) 1005220220Sobrien return NULL; 1006220220Sobrien if (arr && *arr == NULL) 1007220220Sobrien goto out; 1008220178Sobrien 1009220178Sobrien for (max = 0; arr[max]; max++) 1010220178Sobrien continue; 1011220178Sobrien max--; 1012220178Sobrien 1013220178Sobrien if (start == '$') 1014220220Sobrien start = (int)max; 1015220178Sobrien if (end == '$') 1016220220Sobrien end = (int)max; 1017220178Sobrien if (end < 0) 1018220220Sobrien end = (int)max + end + 1; 1019220178Sobrien if (start < 0) 1020220178Sobrien start = end; 1021220178Sobrien 1022220220Sobrien if (start < 0 || end < 0 || (size_t)start > max || 1023220220Sobrien (size_t)end > max || start > end) 1024220220Sobrien goto out; 1025220178Sobrien 1026220220Sobrien for (i = start, len = 0; i <= (size_t)end; i++) 1027220178Sobrien len += strlen(arr[i]) + 1; 1028220178Sobrien len++; 1029220178Sobrien result = malloc(len); 1030220178Sobrien if (result == NULL) 1031220220Sobrien goto out; 1032220178Sobrien 1033220220Sobrien for (i = start, len = 0; i <= (size_t)end; i++) { 1034220178Sobrien (void)strcpy(result + len, arr[i]); 1035220178Sobrien len += strlen(arr[i]); 1036220220Sobrien if (i < (size_t)end) 1037220178Sobrien result[len++] = ' '; 1038220178Sobrien } 1039220220Sobrien result[len] = '\0'; 1040220178Sobrien 1041220220Sobrienout: 1042220178Sobrien for (i = 0; arr[i]; i++) 1043220178Sobrien free(arr[i]); 1044220178Sobrien free(arr); 1045220178Sobrien 1046220220Sobrien return result; 1047220178Sobrien} 1048220178Sobrien 1049220176Sobrien/* 1050220178Sobrien * Parse the string into individual tokens, 1051220178Sobrien * similar to how shell would do it. 1052220176Sobrien */ 1053220176Sobrienchar ** 1054220176Sobrienhistory_tokenize(const char *str) 1055220176Sobrien{ 1056220178Sobrien int size = 1, idx = 0, i, start; 1057220176Sobrien size_t len; 1058220176Sobrien char **result = NULL, *temp, delim = '\0'; 1059220176Sobrien 1060220178Sobrien for (i = 0; str[i];) { 1061220176Sobrien while (isspace((unsigned char) str[i])) 1062220176Sobrien i++; 1063220176Sobrien start = i; 1064220178Sobrien for (; str[i];) { 1065220176Sobrien if (str[i] == '\\') { 1066220176Sobrien if (str[i+1] != '\0') 1067220176Sobrien i++; 1068220176Sobrien } else if (str[i] == delim) 1069220176Sobrien delim = '\0'; 1070220176Sobrien else if (!delim && 1071220176Sobrien (isspace((unsigned char) str[i]) || 1072220176Sobrien strchr("()<>;&|$", str[i]))) 1073220176Sobrien break; 1074220176Sobrien else if (!delim && strchr("'`\"", str[i])) 1075220176Sobrien delim = str[i]; 1076220178Sobrien if (str[i]) 1077220178Sobrien i++; 1078220176Sobrien } 1079220176Sobrien 1080220178Sobrien if (idx + 2 >= size) { 1081220178Sobrien char **nresult; 1082220176Sobrien size <<= 1; 1083220178Sobrien nresult = realloc(result, size * sizeof(char *)); 1084220178Sobrien if (nresult == NULL) { 1085220178Sobrien free(result); 1086220178Sobrien return NULL; 1087220178Sobrien } 1088220178Sobrien result = nresult; 1089220176Sobrien } 1090220176Sobrien len = i - start; 1091220176Sobrien temp = malloc(len + 1); 1092220178Sobrien if (temp == NULL) { 1093220178Sobrien for (i = 0; i < idx; i++) 1094220178Sobrien free(result[i]); 1095220178Sobrien free(result); 1096220178Sobrien return NULL; 1097220178Sobrien } 1098220178Sobrien (void)strncpy(temp, &str[start], len); 1099220176Sobrien temp[len] = '\0'; 1100220178Sobrien result[idx++] = temp; 1101220178Sobrien result[idx] = NULL; 1102220178Sobrien if (str[i]) 1103220178Sobrien i++; 1104220176Sobrien } 1105220176Sobrien return (result); 1106220176Sobrien} 1107220176Sobrien 1108220176Sobrien 1109220176Sobrien/* 1110220176Sobrien * limit size of history record to ``max'' events 1111220176Sobrien */ 1112220176Sobrienvoid 1113220176Sobrienstifle_history(int max) 1114220176Sobrien{ 1115220220Sobrien TYPE(HistEvent) ev; 1116220176Sobrien 1117220176Sobrien if (h == NULL || e == NULL) 1118220176Sobrien rl_initialize(); 1119220176Sobrien 1120220220Sobrien if (FUNW(history)(h, &ev, H_SETSIZE, max) == 0) 1121220176Sobrien max_input_history = max; 1122220176Sobrien} 1123220176Sobrien 1124220176Sobrien 1125220176Sobrien/* 1126220176Sobrien * "unlimit" size of history - set the limit to maximum allowed int value 1127220176Sobrien */ 1128220176Sobrienint 1129220176Sobrienunstifle_history(void) 1130220176Sobrien{ 1131220220Sobrien TYPE(HistEvent) ev; 1132220176Sobrien int omax; 1133220176Sobrien 1134220220Sobrien FUNW(history)(h, &ev, H_SETSIZE, INT_MAX); 1135220176Sobrien omax = max_input_history; 1136220176Sobrien max_input_history = INT_MAX; 1137220176Sobrien return (omax); /* some value _must_ be returned */ 1138220176Sobrien} 1139220176Sobrien 1140220176Sobrien 1141220176Sobrienint 1142220176Sobrienhistory_is_stifled(void) 1143220176Sobrien{ 1144220176Sobrien 1145220176Sobrien /* cannot return true answer */ 1146220176Sobrien return (max_input_history != INT_MAX); 1147220176Sobrien} 1148220176Sobrien 1149220220Sobrienstatic const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; 1150220176Sobrien 1151220220Sobrienint 1152220220Sobrienhistory_truncate_file (const char *filename, int nlines) 1153220220Sobrien{ 1154220220Sobrien int ret = 0; 1155220220Sobrien FILE *fp, *tp; 1156220220Sobrien char template[sizeof(_history_tmp_template)]; 1157220220Sobrien char buf[4096]; 1158220220Sobrien int fd; 1159220220Sobrien char *cp; 1160220220Sobrien off_t off; 1161220220Sobrien int count = 0; 1162220220Sobrien ssize_t left = 0; 1163220220Sobrien 1164220220Sobrien if (filename == NULL && (filename = _default_history_file()) == NULL) 1165220220Sobrien return errno; 1166220220Sobrien if ((fp = fopen(filename, "r+")) == NULL) 1167220220Sobrien return errno; 1168220220Sobrien strcpy(template, _history_tmp_template); 1169220220Sobrien if ((fd = mkstemp(template)) == -1) { 1170220220Sobrien ret = errno; 1171220220Sobrien goto out1; 1172220220Sobrien } 1173220220Sobrien 1174220220Sobrien if ((tp = fdopen(fd, "r+")) == NULL) { 1175220220Sobrien close(fd); 1176220220Sobrien ret = errno; 1177220220Sobrien goto out2; 1178220220Sobrien } 1179220220Sobrien 1180220220Sobrien for(;;) { 1181220220Sobrien if (fread(buf, sizeof(buf), 1, fp) != 1) { 1182220220Sobrien if (ferror(fp)) { 1183220220Sobrien ret = errno; 1184220220Sobrien break; 1185220220Sobrien } 1186220220Sobrien if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == 1187220220Sobrien (off_t)-1) { 1188220220Sobrien ret = errno; 1189220220Sobrien break; 1190220220Sobrien } 1191220220Sobrien left = fread(buf, 1, sizeof(buf), fp); 1192220220Sobrien if (ferror(fp)) { 1193220220Sobrien ret = errno; 1194220220Sobrien break; 1195220220Sobrien } 1196220220Sobrien if (left == 0) { 1197220220Sobrien count--; 1198220220Sobrien left = sizeof(buf); 1199220220Sobrien } else if (fwrite(buf, (size_t)left, 1, tp) != 1) { 1200220220Sobrien ret = errno; 1201220220Sobrien break; 1202220220Sobrien } 1203220220Sobrien fflush(tp); 1204220220Sobrien break; 1205220220Sobrien } 1206220220Sobrien if (fwrite(buf, sizeof(buf), 1, tp) != 1) { 1207220220Sobrien ret = errno; 1208220220Sobrien break; 1209220220Sobrien } 1210220220Sobrien count++; 1211220220Sobrien } 1212220220Sobrien if (ret) 1213220220Sobrien goto out3; 1214220220Sobrien cp = buf + left - 1; 1215220220Sobrien if(*cp != '\n') 1216220220Sobrien cp++; 1217220220Sobrien for(;;) { 1218220220Sobrien while (--cp >= buf) { 1219220220Sobrien if (*cp == '\n') { 1220220220Sobrien if (--nlines == 0) { 1221220220Sobrien if (++cp >= buf + sizeof(buf)) { 1222220220Sobrien count++; 1223220220Sobrien cp = buf; 1224220220Sobrien } 1225220220Sobrien break; 1226220220Sobrien } 1227220220Sobrien } 1228220220Sobrien } 1229220220Sobrien if (nlines <= 0 || count == 0) 1230220220Sobrien break; 1231220220Sobrien count--; 1232220220Sobrien if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { 1233220220Sobrien ret = errno; 1234220220Sobrien break; 1235220220Sobrien } 1236220220Sobrien if (fread(buf, sizeof(buf), 1, tp) != 1) { 1237220220Sobrien if (ferror(tp)) { 1238220220Sobrien ret = errno; 1239220220Sobrien break; 1240220220Sobrien } 1241220220Sobrien ret = EAGAIN; 1242220220Sobrien break; 1243220220Sobrien } 1244220220Sobrien cp = buf + sizeof(buf); 1245220220Sobrien } 1246220220Sobrien 1247220220Sobrien if (ret || nlines > 0) 1248220220Sobrien goto out3; 1249220220Sobrien 1250220220Sobrien if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { 1251220220Sobrien ret = errno; 1252220220Sobrien goto out3; 1253220220Sobrien } 1254220220Sobrien 1255220220Sobrien if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == 1256220220Sobrien (off_t)-1) { 1257220220Sobrien ret = errno; 1258220220Sobrien goto out3; 1259220220Sobrien } 1260220220Sobrien 1261220220Sobrien for(;;) { 1262220220Sobrien if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { 1263220220Sobrien if (ferror(fp)) 1264220220Sobrien ret = errno; 1265220220Sobrien break; 1266220220Sobrien } 1267220220Sobrien if (fwrite(buf, (size_t)left, 1, fp) != 1) { 1268220220Sobrien ret = errno; 1269220220Sobrien break; 1270220220Sobrien } 1271220220Sobrien } 1272220220Sobrien fflush(fp); 1273220220Sobrien if((off = ftello(fp)) > 0) 1274220220Sobrien (void)ftruncate(fileno(fp), off); 1275220220Sobrienout3: 1276220220Sobrien fclose(tp); 1277220220Sobrienout2: 1278220220Sobrien unlink(template); 1279220220Sobrienout1: 1280220220Sobrien fclose(fp); 1281220220Sobrien 1282220220Sobrien return ret; 1283220220Sobrien} 1284220220Sobrien 1285220220Sobrien 1286220176Sobrien/* 1287220176Sobrien * read history from a file given 1288220176Sobrien */ 1289220176Sobrienint 1290220176Sobrienread_history(const char *filename) 1291220176Sobrien{ 1292220220Sobrien TYPE(HistEvent) ev; 1293220176Sobrien 1294220176Sobrien if (h == NULL || e == NULL) 1295220176Sobrien rl_initialize(); 1296220220Sobrien if (filename == NULL && (filename = _default_history_file()) == NULL) 1297220220Sobrien return errno; 1298220220Sobrien return (FUNW(history)(h, &ev, H_LOAD, filename) == -1 ? 1299220220Sobrien (errno ? errno : EINVAL) : 0); 1300220176Sobrien} 1301220176Sobrien 1302220176Sobrien 1303220176Sobrien/* 1304220176Sobrien * write history to a file given 1305220176Sobrien */ 1306220176Sobrienint 1307220176Sobrienwrite_history(const char *filename) 1308220176Sobrien{ 1309220220Sobrien TYPE(HistEvent) ev; 1310220176Sobrien 1311220176Sobrien if (h == NULL || e == NULL) 1312220176Sobrien rl_initialize(); 1313220220Sobrien if (filename == NULL && (filename = _default_history_file()) == NULL) 1314220220Sobrien return errno; 1315220220Sobrien return (FUNW(history)(h, &ev, H_SAVE, filename) == -1 ? 1316220220Sobrien (errno ? errno : EINVAL) : 0); 1317220176Sobrien} 1318220176Sobrien 1319220176Sobrien 1320220176Sobrien/* 1321220176Sobrien * returns history ``num''th event 1322220176Sobrien * 1323220176Sobrien * returned pointer points to static variable 1324220176Sobrien */ 1325220176SobrienHIST_ENTRY * 1326220176Sobrienhistory_get(int num) 1327220176Sobrien{ 1328220176Sobrien static HIST_ENTRY she; 1329220220Sobrien TYPE(HistEvent) ev; 1330220178Sobrien int curr_num; 1331220176Sobrien 1332220176Sobrien if (h == NULL || e == NULL) 1333220176Sobrien rl_initialize(); 1334220176Sobrien 1335220178Sobrien /* save current position */ 1336220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1337220176Sobrien return (NULL); 1338220176Sobrien curr_num = ev.num; 1339220178Sobrien 1340220220Sobrien /* start from the oldest */ 1341220220Sobrien if (FUNW(history)(h, &ev, H_LAST) != 0) 1342220176Sobrien return (NULL); /* error */ 1343220176Sobrien 1344220220Sobrien /* look forwards for event matching specified offset */ 1345220220Sobrien if (FUNW(history)(h, &ev, H_NEXT_EVDATA, num, &she.data)) 1346220178Sobrien return (NULL); 1347220178Sobrien 1348220220Sobrien she.line = ct_encode_string(ev.str, &conv); 1349220176Sobrien 1350220178Sobrien /* restore pointer to where it was */ 1351220220Sobrien (void)FUNW(history)(h, &ev, H_SET, curr_num); 1352220176Sobrien 1353220176Sobrien return (&she); 1354220176Sobrien} 1355220176Sobrien 1356220176Sobrien 1357220176Sobrien/* 1358220176Sobrien * add the line to history table 1359220176Sobrien */ 1360220176Sobrienint 1361220176Sobrienadd_history(const char *line) 1362220176Sobrien{ 1363220220Sobrien TYPE(HistEvent) ev; 1364220220Sobrien const Char *wline; 1365220176Sobrien 1366220176Sobrien if (h == NULL || e == NULL) 1367220176Sobrien rl_initialize(); 1368220176Sobrien 1369220220Sobrien wline = ct_decode_string(line, &conv); 1370220220Sobrien 1371220220Sobrien (void)FUNW(history)(h, &ev, H_ENTER, wline); 1372220220Sobrien if (FUNW(history)(h, &ev, H_GETSIZE) == 0) 1373220176Sobrien history_length = ev.num; 1374220176Sobrien 1375220178Sobrien return (!(history_length > 0)); /* return 0 if all is okay */ 1376220176Sobrien} 1377220176Sobrien 1378220176Sobrien 1379220176Sobrien/* 1380220178Sobrien * remove the specified entry from the history list and return it. 1381220178Sobrien */ 1382220178SobrienHIST_ENTRY * 1383220178Sobrienremove_history(int num) 1384220178Sobrien{ 1385220220Sobrien HIST_ENTRY *he; 1386220220Sobrien TYPE(HistEvent) ev; 1387220178Sobrien 1388220178Sobrien if (h == NULL || e == NULL) 1389220178Sobrien rl_initialize(); 1390220178Sobrien 1391220220Sobrien if ((he = malloc(sizeof(*he))) == NULL) 1392220178Sobrien return NULL; 1393220178Sobrien 1394220220Sobrien if (FUNW(history)(h, &ev, H_DELDATA, num, &he->data) != 0) { 1395220220Sobrien free(he); 1396220220Sobrien return NULL; 1397220220Sobrien } 1398220178Sobrien 1399220220Sobrien he->line = ct_encode_string(ev.str, &conv); 1400220220Sobrien if (FUNW(history)(h, &ev, H_GETSIZE) == 0) 1401220220Sobrien history_length = ev.num; 1402220220Sobrien 1403220220Sobrien return he; 1404220178Sobrien} 1405220178Sobrien 1406220178Sobrien 1407220178Sobrien/* 1408220220Sobrien * replace the line and data of the num-th entry 1409220220Sobrien */ 1410220220SobrienHIST_ENTRY * 1411220220Sobrienreplace_history_entry(int num, const char *line, histdata_t data) 1412220220Sobrien{ 1413220220Sobrien HIST_ENTRY *he; 1414220220Sobrien TYPE(HistEvent) ev; 1415220220Sobrien int curr_num; 1416220220Sobrien 1417220220Sobrien if (h == NULL || e == NULL) 1418220220Sobrien rl_initialize(); 1419220220Sobrien 1420220220Sobrien /* save current position */ 1421220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1422220220Sobrien return NULL; 1423220220Sobrien curr_num = ev.num; 1424220220Sobrien 1425220220Sobrien /* start from the oldest */ 1426220220Sobrien if (FUNW(history)(h, &ev, H_LAST) != 0) 1427220220Sobrien return NULL; /* error */ 1428220220Sobrien 1429220220Sobrien if ((he = malloc(sizeof(*he))) == NULL) 1430220220Sobrien return NULL; 1431220220Sobrien 1432220220Sobrien /* look forwards for event matching specified offset */ 1433220220Sobrien if (FUNW(history)(h, &ev, H_NEXT_EVDATA, num, &he->data)) 1434220220Sobrien goto out; 1435220220Sobrien 1436220220Sobrien he->line = strdup(ct_encode_string(ev.str, &e->el_scratch)); 1437220220Sobrien if (he->line == NULL) 1438220220Sobrien goto out; 1439220220Sobrien 1440220220Sobrien if (FUNW(history)(h, &ev, H_REPLACE, line, data)) 1441220220Sobrien goto out; 1442220220Sobrien 1443220220Sobrien /* restore pointer to where it was */ 1444220220Sobrien if (FUNW(history)(h, &ev, H_SET, curr_num)) 1445220220Sobrien goto out; 1446220220Sobrien 1447220220Sobrien return he; 1448220220Sobrienout: 1449220220Sobrien free(he); 1450220220Sobrien return NULL; 1451220220Sobrien} 1452220220Sobrien 1453220220Sobrien/* 1454220176Sobrien * clear the history list - delete all entries 1455220176Sobrien */ 1456220176Sobrienvoid 1457220176Sobrienclear_history(void) 1458220176Sobrien{ 1459220220Sobrien TYPE(HistEvent) ev; 1460220176Sobrien 1461220220Sobrien (void)FUNW(history)(h, &ev, H_CLEAR); 1462220220Sobrien history_length = 0; 1463220176Sobrien} 1464220176Sobrien 1465220176Sobrien 1466220176Sobrien/* 1467220176Sobrien * returns offset of the current history event 1468220176Sobrien */ 1469220176Sobrienint 1470220176Sobrienwhere_history(void) 1471220176Sobrien{ 1472220220Sobrien TYPE(HistEvent) ev; 1473220176Sobrien int curr_num, off; 1474220176Sobrien 1475220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1476220176Sobrien return (0); 1477220176Sobrien curr_num = ev.num; 1478220176Sobrien 1479220220Sobrien (void)FUNW(history)(h, &ev, H_FIRST); 1480220176Sobrien off = 1; 1481220220Sobrien while (ev.num != curr_num && FUNW(history)(h, &ev, H_NEXT) == 0) 1482220176Sobrien off++; 1483220176Sobrien 1484220176Sobrien return (off); 1485220176Sobrien} 1486220176Sobrien 1487220176Sobrien 1488220176Sobrien/* 1489220176Sobrien * returns current history event or NULL if there is no such event 1490220176Sobrien */ 1491220176SobrienHIST_ENTRY * 1492220176Sobriencurrent_history(void) 1493220176Sobrien{ 1494220176Sobrien 1495220176Sobrien return (_move_history(H_CURR)); 1496220176Sobrien} 1497220176Sobrien 1498220176Sobrien 1499220176Sobrien/* 1500220176Sobrien * returns total number of bytes history events' data are using 1501220176Sobrien */ 1502220176Sobrienint 1503220176Sobrienhistory_total_bytes(void) 1504220176Sobrien{ 1505220220Sobrien TYPE(HistEvent) ev; 1506220220Sobrien int curr_num; 1507220220Sobrien size_t size; 1508220176Sobrien 1509220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1510220176Sobrien return (-1); 1511220176Sobrien curr_num = ev.num; 1512220176Sobrien 1513220220Sobrien (void)FUNW(history)(h, &ev, H_FIRST); 1514220176Sobrien size = 0; 1515220176Sobrien do 1516220220Sobrien size += Strlen(ev.str) * sizeof(*ev.str); 1517220220Sobrien while (FUNW(history)(h, &ev, H_NEXT) == 0); 1518220176Sobrien 1519220176Sobrien /* get to the same position as before */ 1520220220Sobrien FUNW(history)(h, &ev, H_PREV_EVENT, curr_num); 1521220176Sobrien 1522220220Sobrien return (int)(size); 1523220176Sobrien} 1524220176Sobrien 1525220176Sobrien 1526220176Sobrien/* 1527220176Sobrien * sets the position in the history list to ``pos'' 1528220176Sobrien */ 1529220176Sobrienint 1530220176Sobrienhistory_set_pos(int pos) 1531220176Sobrien{ 1532220220Sobrien TYPE(HistEvent) ev; 1533220178Sobrien int curr_num; 1534220176Sobrien 1535220220Sobrien if (pos >= history_length || pos < 0) 1536220176Sobrien return (-1); 1537220176Sobrien 1538220220Sobrien (void)FUNW(history)(h, &ev, H_CURR); 1539220176Sobrien curr_num = ev.num; 1540220176Sobrien 1541220220Sobrien /* 1542220220Sobrien * use H_DELDATA to set to nth history (without delete) by passing 1543220220Sobrien * (void **)-1 1544220220Sobrien */ 1545220220Sobrien if (FUNW(history)(h, &ev, H_DELDATA, pos, (void **)-1)) { 1546220220Sobrien (void)FUNW(history)(h, &ev, H_SET, curr_num); 1547220178Sobrien return(-1); 1548220176Sobrien } 1549220176Sobrien return (0); 1550220176Sobrien} 1551220176Sobrien 1552220176Sobrien 1553220176Sobrien/* 1554220176Sobrien * returns previous event in history and shifts pointer accordingly 1555220176Sobrien */ 1556220176SobrienHIST_ENTRY * 1557220176Sobrienprevious_history(void) 1558220176Sobrien{ 1559220176Sobrien 1560220176Sobrien return (_move_history(H_PREV)); 1561220176Sobrien} 1562220176Sobrien 1563220176Sobrien 1564220176Sobrien/* 1565220176Sobrien * returns next event in history and shifts pointer accordingly 1566220176Sobrien */ 1567220176SobrienHIST_ENTRY * 1568220176Sobriennext_history(void) 1569220176Sobrien{ 1570220176Sobrien 1571220176Sobrien return (_move_history(H_NEXT)); 1572220176Sobrien} 1573220176Sobrien 1574220176Sobrien 1575220176Sobrien/* 1576220178Sobrien * searches for first history event containing the str 1577220176Sobrien */ 1578220178Sobrienint 1579220178Sobrienhistory_search(const char *str, int direction) 1580220176Sobrien{ 1581220220Sobrien TYPE(HistEvent) ev; 1582220220Sobrien const Char *strp; 1583220220Sobrien const Char *wstr; 1584220176Sobrien int curr_num; 1585220176Sobrien 1586220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1587220176Sobrien return (-1); 1588220176Sobrien curr_num = ev.num; 1589220176Sobrien 1590220220Sobrien wstr = ct_decode_string(str, &conv); 1591220176Sobrien for (;;) { 1592220220Sobrien if ((strp = Strstr(ev.str, wstr)) != NULL) 1593220176Sobrien return (int) (strp - ev.str); 1594220220Sobrien if (FUNW(history)(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) 1595220176Sobrien break; 1596220176Sobrien } 1597220220Sobrien (void)FUNW(history)(h, &ev, H_SET, curr_num); 1598220176Sobrien return (-1); 1599220176Sobrien} 1600220176Sobrien 1601220176Sobrien 1602220176Sobrien/* 1603220176Sobrien * searches for first history event beginning with str 1604220176Sobrien */ 1605220176Sobrienint 1606220176Sobrienhistory_search_prefix(const char *str, int direction) 1607220176Sobrien{ 1608220220Sobrien TYPE(HistEvent) ev; 1609220176Sobrien 1610220220Sobrien return (FUNW(history)(h, &ev, direction < 0 ? 1611220220Sobrien H_PREV_STR : H_NEXT_STR, str)); 1612220176Sobrien} 1613220176Sobrien 1614220176Sobrien 1615220176Sobrien/* 1616220176Sobrien * search for event in history containing str, starting at offset 1617220176Sobrien * abs(pos); continue backward, if pos<0, forward otherwise 1618220176Sobrien */ 1619220176Sobrien/* ARGSUSED */ 1620220176Sobrienint 1621220178Sobrienhistory_search_pos(const char *str, 1622220178Sobrien int direction __attribute__((__unused__)), int pos) 1623220176Sobrien{ 1624220220Sobrien TYPE(HistEvent) ev; 1625220176Sobrien int curr_num, off; 1626220220Sobrien const Char *wstr; 1627220176Sobrien 1628220176Sobrien off = (pos > 0) ? pos : -pos; 1629220176Sobrien pos = (pos > 0) ? 1 : -1; 1630220176Sobrien 1631220220Sobrien if (FUNW(history)(h, &ev, H_CURR) != 0) 1632220176Sobrien return (-1); 1633220176Sobrien curr_num = ev.num; 1634220176Sobrien 1635220220Sobrien if (history_set_pos(off) != 0 || FUNW(history)(h, &ev, H_CURR) != 0) 1636220176Sobrien return (-1); 1637220176Sobrien 1638220220Sobrien wstr = ct_decode_string(str, &conv); 1639220176Sobrien for (;;) { 1640220220Sobrien if (Strstr(ev.str, wstr)) 1641220176Sobrien return (off); 1642220220Sobrien if (FUNW(history)(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) 1643220176Sobrien break; 1644220176Sobrien } 1645220176Sobrien 1646220176Sobrien /* set "current" pointer back to previous state */ 1647220220Sobrien (void)FUNW(history)(h, &ev, 1648220220Sobrien pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); 1649220176Sobrien 1650220176Sobrien return (-1); 1651220176Sobrien} 1652220176Sobrien 1653220176Sobrien 1654220176Sobrien/********************************/ 1655220178Sobrien/* completion functions */ 1656220176Sobrien 1657220176Sobrienchar * 1658220178Sobrientilde_expand(char *name) 1659220176Sobrien{ 1660220178Sobrien return fn_tilde_expand(name); 1661220176Sobrien} 1662220176Sobrien 1663220176Sobrienchar * 1664220178Sobrienfilename_completion_function(const char *name, int state) 1665220176Sobrien{ 1666220178Sobrien return fn_filename_completion_function(name, state); 1667220176Sobrien} 1668220176Sobrien 1669220176Sobrien/* 1670220176Sobrien * a completion generator for usernames; returns _first_ username 1671220176Sobrien * which starts with supplied text 1672220176Sobrien * text contains a partial username preceded by random character 1673220176Sobrien * (usually '~'); state is ignored 1674220176Sobrien * it's callers responsibility to free returned value 1675220176Sobrien */ 1676220176Sobrienchar * 1677220176Sobrienusername_completion_function(const char *text, int state) 1678220176Sobrien{ 1679220178Sobrien struct passwd *pwd, pwres; 1680220178Sobrien char pwbuf[1024]; 1681220176Sobrien 1682220176Sobrien if (text[0] == '\0') 1683220176Sobrien return (NULL); 1684220176Sobrien 1685220176Sobrien if (*text == '~') 1686220176Sobrien text++; 1687220176Sobrien 1688220176Sobrien if (state == 0) 1689220176Sobrien setpwent(); 1690220176Sobrien 1691220178Sobrien while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0 1692220178Sobrien && pwd != NULL && text[0] == pwd->pw_name[0] 1693220176Sobrien && strcmp(text, pwd->pw_name) == 0); 1694220176Sobrien 1695220176Sobrien if (pwd == NULL) { 1696220176Sobrien endpwent(); 1697220220Sobrien return NULL; 1698220176Sobrien } 1699220220Sobrien return strdup(pwd->pw_name); 1700220176Sobrien} 1701220176Sobrien 1702220176Sobrien 1703220176Sobrien/* 1704220178Sobrien * el-compatible wrapper to send TSTP on ^Z 1705220176Sobrien */ 1706220176Sobrien/* ARGSUSED */ 1707220176Sobrienstatic unsigned char 1708220178Sobrien_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) 1709220176Sobrien{ 1710220178Sobrien (void)kill(0, SIGTSTP); 1711220178Sobrien return CC_NORM; 1712220176Sobrien} 1713220176Sobrien 1714220176Sobrien/* 1715220176Sobrien * Display list of strings in columnar format on readline's output stream. 1716220176Sobrien * 'matches' is list of strings, 'len' is number of strings in 'matches', 1717220176Sobrien * 'max' is maximum length of string in 'matches'. 1718220176Sobrien */ 1719220176Sobrienvoid 1720220178Sobrienrl_display_match_list(char **matches, int len, int max) 1721220176Sobrien{ 1722220176Sobrien 1723220220Sobrien fn_display_match_list(e, matches, (size_t)len, (size_t)max); 1724220176Sobrien} 1725220176Sobrien 1726220178Sobrienstatic const char * 1727220178Sobrien/*ARGSUSED*/ 1728220178Sobrien_rl_completion_append_character_function(const char *dummy 1729220178Sobrien __attribute__((__unused__))) 1730220176Sobrien{ 1731220178Sobrien static char buf[2]; 1732220220Sobrien buf[0] = rl_completion_append_character; 1733220220Sobrien buf[1] = '\0'; 1734220178Sobrien return buf; 1735220176Sobrien} 1736220176Sobrien 1737220176Sobrien 1738220176Sobrien/* 1739220176Sobrien * complete word at current point 1740220176Sobrien */ 1741220178Sobrien/* ARGSUSED */ 1742220176Sobrienint 1743220178Sobrienrl_complete(int ignore __attribute__((__unused__)), int invoking_key) 1744220176Sobrien{ 1745220220Sobrien#ifdef WIDECHAR 1746220220Sobrien static ct_buffer_t wbreak_conv, sprefix_conv; 1747220220Sobrien#endif 1748220220Sobrien 1749220176Sobrien if (h == NULL || e == NULL) 1750220176Sobrien rl_initialize(); 1751220176Sobrien 1752220176Sobrien if (rl_inhibit_completion) { 1753220178Sobrien char arr[2]; 1754220178Sobrien arr[0] = (char)invoking_key; 1755220178Sobrien arr[1] = '\0'; 1756220178Sobrien el_insertstr(e, arr); 1757220176Sobrien return (CC_REFRESH); 1758220178Sobrien } 1759220178Sobrien 1760220178Sobrien /* Just look at how many global variables modify this operation! */ 1761220178Sobrien return fn_complete(e, 1762220178Sobrien (CPFunction *)rl_completion_entry_function, 1763220178Sobrien rl_attempted_completion_function, 1764220220Sobrien ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), 1765220220Sobrien ct_decode_string(rl_special_prefixes, &sprefix_conv), 1766220220Sobrien _rl_completion_append_character_function, 1767220220Sobrien (size_t)rl_completion_query_items, 1768220178Sobrien &rl_completion_type, &rl_attempted_completion_over, 1769220370Sobrien &rl_point, &rl_end, NULL, NULL, NULL); 1770220176Sobrien} 1771220176Sobrien 1772220176Sobrien 1773220178Sobrien/* ARGSUSED */ 1774220178Sobrienstatic unsigned char 1775220178Sobrien_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) 1776220178Sobrien{ 1777220178Sobrien return (unsigned char)rl_complete(0, ch); 1778220178Sobrien} 1779220178Sobrien 1780220176Sobrien/* 1781220176Sobrien * misc other functions 1782220176Sobrien */ 1783220176Sobrien 1784220176Sobrien/* 1785220176Sobrien * bind key c to readline-type function func 1786220176Sobrien */ 1787220176Sobrienint 1788220220Sobrienrl_bind_key(int c, rl_command_func_t *func) 1789220176Sobrien{ 1790220176Sobrien int retval = -1; 1791220176Sobrien 1792220176Sobrien if (h == NULL || e == NULL) 1793220176Sobrien rl_initialize(); 1794220176Sobrien 1795220176Sobrien if (func == rl_insert) { 1796220176Sobrien /* XXX notice there is no range checking of ``c'' */ 1797220176Sobrien e->el_map.key[c] = ED_INSERT; 1798220176Sobrien retval = 0; 1799220176Sobrien } 1800220176Sobrien return (retval); 1801220176Sobrien} 1802220176Sobrien 1803220176Sobrien 1804220176Sobrien/* 1805220176Sobrien * read one key from input - handles chars pushed back 1806220176Sobrien * to input stream also 1807220176Sobrien */ 1808220176Sobrienint 1809220176Sobrienrl_read_key(void) 1810220176Sobrien{ 1811220176Sobrien char fooarr[2 * sizeof(int)]; 1812220176Sobrien 1813220176Sobrien if (e == NULL || h == NULL) 1814220176Sobrien rl_initialize(); 1815220176Sobrien 1816220176Sobrien return (el_getc(e, fooarr)); 1817220176Sobrien} 1818220176Sobrien 1819220176Sobrien 1820220176Sobrien/* 1821220176Sobrien * reset the terminal 1822220176Sobrien */ 1823220176Sobrien/* ARGSUSED */ 1824220176Sobrienvoid 1825220178Sobrienrl_reset_terminal(const char *p __attribute__((__unused__))) 1826220176Sobrien{ 1827220176Sobrien 1828220176Sobrien if (h == NULL || e == NULL) 1829220176Sobrien rl_initialize(); 1830220176Sobrien el_reset(e); 1831220176Sobrien} 1832220176Sobrien 1833220176Sobrien 1834220176Sobrien/* 1835220176Sobrien * insert character ``c'' back into input stream, ``count'' times 1836220176Sobrien */ 1837220176Sobrienint 1838220176Sobrienrl_insert(int count, int c) 1839220176Sobrien{ 1840220176Sobrien char arr[2]; 1841220176Sobrien 1842220176Sobrien if (h == NULL || e == NULL) 1843220176Sobrien rl_initialize(); 1844220176Sobrien 1845220176Sobrien /* XXX - int -> char conversion can lose on multichars */ 1846220176Sobrien arr[0] = c; 1847220176Sobrien arr[1] = '\0'; 1848220176Sobrien 1849220176Sobrien for (; count > 0; count--) 1850220176Sobrien el_push(e, arr); 1851220176Sobrien 1852220176Sobrien return (0); 1853220176Sobrien} 1854220178Sobrien 1855220220Sobrienint 1856220220Sobrienrl_insert_text(const char *text) 1857220220Sobrien{ 1858220220Sobrien if (!text || *text == 0) 1859220220Sobrien return (0); 1860220220Sobrien 1861220220Sobrien if (h == NULL || e == NULL) 1862220220Sobrien rl_initialize(); 1863220220Sobrien 1864220220Sobrien if (el_insertstr(e, text) < 0) 1865220220Sobrien return (0); 1866220220Sobrien return (int)strlen(text); 1867220220Sobrien} 1868220220Sobrien 1869220178Sobrien/*ARGSUSED*/ 1870220178Sobrienint 1871220178Sobrienrl_newline(int count, int c) 1872220178Sobrien{ 1873220178Sobrien /* 1874220178Sobrien * Readline-4.0 appears to ignore the args. 1875220178Sobrien */ 1876220178Sobrien return rl_insert(1, '\n'); 1877220178Sobrien} 1878220178Sobrien 1879220178Sobrien/*ARGSUSED*/ 1880220178Sobrienstatic unsigned char 1881220178Sobrienrl_bind_wrapper(EditLine *el, unsigned char c) 1882220178Sobrien{ 1883220178Sobrien if (map[c] == NULL) 1884220178Sobrien return CC_ERROR; 1885220178Sobrien 1886220178Sobrien _rl_update_pos(); 1887220178Sobrien 1888220178Sobrien (*map[c])(NULL, c); 1889220178Sobrien 1890220178Sobrien /* If rl_done was set by the above call, deal with it here */ 1891220178Sobrien if (rl_done) 1892220178Sobrien return CC_EOF; 1893220178Sobrien 1894220178Sobrien return CC_NORM; 1895220178Sobrien} 1896220178Sobrien 1897220178Sobrienint 1898220178Sobrienrl_add_defun(const char *name, Function *fun, int c) 1899220178Sobrien{ 1900220178Sobrien char dest[8]; 1901220220Sobrien if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) 1902220178Sobrien return -1; 1903220178Sobrien map[(unsigned char)c] = fun; 1904220178Sobrien el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); 1905220178Sobrien vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); 1906220178Sobrien el_set(e, EL_BIND, dest, name); 1907220178Sobrien return 0; 1908220178Sobrien} 1909220178Sobrien 1910220178Sobrienvoid 1911220178Sobrienrl_callback_read_char() 1912220178Sobrien{ 1913220178Sobrien int count = 0, done = 0; 1914220178Sobrien const char *buf = el_gets(e, &count); 1915220178Sobrien char *wbuf; 1916220178Sobrien 1917220178Sobrien if (buf == NULL || count-- <= 0) 1918220178Sobrien return; 1919220216Sobrien if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) 1920220178Sobrien done = 1; 1921220178Sobrien if (buf[count] == '\n' || buf[count] == '\r') 1922220178Sobrien done = 2; 1923220178Sobrien 1924220178Sobrien if (done && rl_linefunc != NULL) { 1925220178Sobrien el_set(e, EL_UNBUFFERED, 0); 1926220178Sobrien if (done == 2) { 1927220178Sobrien if ((wbuf = strdup(buf)) != NULL) 1928220178Sobrien wbuf[count] = '\0'; 1929220178Sobrien } else 1930220178Sobrien wbuf = NULL; 1931220178Sobrien (*(void (*)(const char *))rl_linefunc)(wbuf); 1932220220Sobrien //el_set(e, EL_UNBUFFERED, 1); 1933220178Sobrien } 1934220178Sobrien} 1935220178Sobrien 1936220178Sobrienvoid 1937220220Sobrienrl_callback_handler_install(const char *prompt, VCPFunction *linefunc) 1938220178Sobrien{ 1939220178Sobrien if (e == NULL) { 1940220178Sobrien rl_initialize(); 1941220178Sobrien } 1942220220Sobrien (void)rl_set_prompt(prompt); 1943220178Sobrien rl_linefunc = linefunc; 1944220178Sobrien el_set(e, EL_UNBUFFERED, 1); 1945220178Sobrien} 1946220178Sobrien 1947220178Sobrienvoid 1948220178Sobrienrl_callback_handler_remove(void) 1949220178Sobrien{ 1950220178Sobrien el_set(e, EL_UNBUFFERED, 0); 1951220220Sobrien rl_linefunc = NULL; 1952220178Sobrien} 1953220178Sobrien 1954220178Sobrienvoid 1955220178Sobrienrl_redisplay(void) 1956220178Sobrien{ 1957220178Sobrien char a[2]; 1958220216Sobrien a[0] = e->el_tty.t_c[TS_IO][C_REPRINT]; 1959220178Sobrien a[1] = '\0'; 1960220178Sobrien el_push(e, a); 1961220178Sobrien} 1962220178Sobrien 1963220178Sobrienint 1964220178Sobrienrl_get_previous_history(int count, int key) 1965220178Sobrien{ 1966220178Sobrien char a[2]; 1967220178Sobrien a[0] = key; 1968220178Sobrien a[1] = '\0'; 1969220178Sobrien while (count--) 1970220178Sobrien el_push(e, a); 1971220178Sobrien return 0; 1972220178Sobrien} 1973220178Sobrien 1974220178Sobrienvoid 1975220178Sobrien/*ARGSUSED*/ 1976220178Sobrienrl_prep_terminal(int meta_flag) 1977220178Sobrien{ 1978220178Sobrien el_set(e, EL_PREP_TERM, 1); 1979220178Sobrien} 1980220178Sobrien 1981220178Sobrienvoid 1982220218Sobrienrl_deprep_terminal(void) 1983220178Sobrien{ 1984220178Sobrien el_set(e, EL_PREP_TERM, 0); 1985220178Sobrien} 1986220178Sobrien 1987220178Sobrienint 1988220178Sobrienrl_read_init_file(const char *s) 1989220178Sobrien{ 1990220178Sobrien return(el_source(e, s)); 1991220178Sobrien} 1992220178Sobrien 1993220178Sobrienint 1994220178Sobrienrl_parse_and_bind(const char *line) 1995220178Sobrien{ 1996220178Sobrien const char **argv; 1997220178Sobrien int argc; 1998220178Sobrien Tokenizer *tok; 1999220178Sobrien 2000220178Sobrien tok = tok_init(NULL); 2001220178Sobrien tok_str(tok, line, &argc, &argv); 2002220178Sobrien argc = el_parse(e, argc, argv); 2003220178Sobrien tok_end(tok); 2004220178Sobrien return (argc ? 1 : 0); 2005220178Sobrien} 2006220178Sobrien 2007220178Sobrienint 2008220178Sobrienrl_variable_bind(const char *var, const char *value) 2009220178Sobrien{ 2010220178Sobrien /* 2011220178Sobrien * The proper return value is undocument, but this is what the 2012220178Sobrien * readline source seems to do. 2013220178Sobrien */ 2014220178Sobrien return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); 2015220178Sobrien} 2016220178Sobrien 2017220178Sobrienvoid 2018220178Sobrienrl_stuff_char(int c) 2019220178Sobrien{ 2020220178Sobrien char buf[2]; 2021220178Sobrien 2022220178Sobrien buf[0] = c; 2023220178Sobrien buf[1] = '\0'; 2024220178Sobrien el_insertstr(e, buf); 2025220178Sobrien} 2026220178Sobrien 2027220178Sobrienstatic int 2028220178Sobrien_rl_event_read_char(EditLine *el, char *cp) 2029220178Sobrien{ 2030220220Sobrien int n; 2031220220Sobrien ssize_t num_read = 0; 2032220178Sobrien 2033220220Sobrien *cp = '\0'; 2034220178Sobrien while (rl_event_hook) { 2035220178Sobrien 2036220178Sobrien (*rl_event_hook)(); 2037220178Sobrien 2038220178Sobrien#if defined(FIONREAD) 2039220178Sobrien if (ioctl(el->el_infd, FIONREAD, &n) < 0) 2040220178Sobrien return(-1); 2041220178Sobrien if (n) 2042220178Sobrien num_read = read(el->el_infd, cp, 1); 2043220178Sobrien else 2044220178Sobrien num_read = 0; 2045220178Sobrien#elif defined(F_SETFL) && defined(O_NDELAY) 2046220178Sobrien if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) 2047220178Sobrien return(-1); 2048220178Sobrien if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) 2049220178Sobrien return(-1); 2050220178Sobrien num_read = read(el->el_infd, cp, 1); 2051220178Sobrien if (fcntl(el->el_infd, F_SETFL, n)) 2052220178Sobrien return(-1); 2053220178Sobrien#else 2054220178Sobrien /* not non-blocking, but what you gonna do? */ 2055220178Sobrien num_read = read(el->el_infd, cp, 1); 2056220178Sobrien return(-1); 2057220178Sobrien#endif 2058220178Sobrien 2059220178Sobrien if (num_read < 0 && errno == EAGAIN) 2060220178Sobrien continue; 2061220178Sobrien if (num_read == 0) 2062220178Sobrien continue; 2063220178Sobrien break; 2064220178Sobrien } 2065220178Sobrien if (!rl_event_hook) 2066220178Sobrien el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); 2067220220Sobrien return (int)num_read; 2068220178Sobrien} 2069220178Sobrien 2070220178Sobrienstatic void 2071220178Sobrien_rl_update_pos(void) 2072220178Sobrien{ 2073220178Sobrien const LineInfo *li = el_line(e); 2074220178Sobrien 2075220220Sobrien rl_point = (int)(li->cursor - li->buffer); 2076220220Sobrien rl_end = (int)(li->lastchar - li->buffer); 2077220178Sobrien} 2078220218Sobrien 2079220218Sobrienvoid 2080220218Sobrienrl_get_screen_size(int *rows, int *cols) 2081220218Sobrien{ 2082220218Sobrien if (rows) 2083220218Sobrien el_get(e, EL_GETTC, "li", rows); 2084220218Sobrien if (cols) 2085220218Sobrien el_get(e, EL_GETTC, "co", cols); 2086220218Sobrien} 2087220218Sobrien 2088220218Sobrienvoid 2089220218Sobrienrl_set_screen_size(int rows, int cols) 2090220218Sobrien{ 2091220218Sobrien char buf[64]; 2092220218Sobrien (void)snprintf(buf, sizeof(buf), "%d", rows); 2093220218Sobrien el_set(e, EL_SETTC, "li", buf); 2094220218Sobrien (void)snprintf(buf, sizeof(buf), "%d", cols); 2095220218Sobrien el_set(e, EL_SETTC, "co", buf); 2096220218Sobrien} 2097220218Sobrien 2098220220Sobrienchar ** 2099220220Sobrienrl_completion_matches(const char *str, rl_compentry_func_t *fun) 2100220220Sobrien{ 2101220220Sobrien size_t len, max, i, j, min; 2102220220Sobrien char **list, *match, *a, *b; 2103220220Sobrien 2104220220Sobrien len = 1; 2105220220Sobrien max = 10; 2106220220Sobrien if ((list = malloc(max * sizeof(*list))) == NULL) 2107220220Sobrien return NULL; 2108220220Sobrien 2109220220Sobrien while ((match = (*fun)(str, (int)(len - 1))) != NULL) { 2110220220Sobrien list[len++] = match; 2111220220Sobrien if (len == max) { 2112220220Sobrien char **nl; 2113220220Sobrien max += 10; 2114220220Sobrien if ((nl = realloc(list, max * sizeof(*nl))) == NULL) 2115220220Sobrien goto out; 2116220220Sobrien list = nl; 2117220220Sobrien } 2118220220Sobrien } 2119220220Sobrien if (len == 1) 2120220220Sobrien goto out; 2121220220Sobrien list[len] = NULL; 2122220220Sobrien if (len == 2) { 2123220220Sobrien if ((list[0] = strdup(list[1])) == NULL) 2124220220Sobrien goto out; 2125220220Sobrien return list; 2126220220Sobrien } 2127220220Sobrien qsort(&list[1], len - 1, sizeof(*list), 2128220220Sobrien (int (*)(const void *, const void *)) strcmp); 2129220220Sobrien min = SIZE_T_MAX; 2130220220Sobrien for (i = 1, a = list[i]; i < len - 1; i++, a = b) { 2131220220Sobrien b = list[i + 1]; 2132220220Sobrien for (j = 0; a[j] && a[j] == b[j]; j++) 2133220220Sobrien continue; 2134220220Sobrien if (min > j) 2135220220Sobrien min = j; 2136220220Sobrien } 2137220220Sobrien if (min == 0 && *str) { 2138220220Sobrien if ((list[0] = strdup(str)) == NULL) 2139220220Sobrien goto out; 2140220220Sobrien } else { 2141220220Sobrien if ((list[0] = malloc(min + 1)) == NULL) 2142220220Sobrien goto out; 2143220220Sobrien (void)memcpy(list[0], list[1], min); 2144220220Sobrien list[0][min] = '\0'; 2145220220Sobrien } 2146220220Sobrien return list; 2147220220Sobrien 2148220220Sobrienout: 2149220220Sobrien free(list); 2150220220Sobrien return NULL; 2151220220Sobrien} 2152220220Sobrien 2153220218Sobrienchar * 2154220218Sobrienrl_filename_completion_function (const char *text, int state) 2155220218Sobrien{ 2156220218Sobrien return fn_filename_completion_function(text, state); 2157220218Sobrien} 2158220218Sobrien 2159220220Sobrienvoid 2160220220Sobrienrl_forced_update_display(void) 2161220220Sobrien{ 2162220220Sobrien el_set(e, EL_REFRESH); 2163220220Sobrien} 2164220220Sobrien 2165220218Sobrienint 2166220218Sobrien_rl_abort_internal(void) 2167220218Sobrien{ 2168220218Sobrien el_beep(e); 2169220218Sobrien longjmp(topbuf, 1); 2170220218Sobrien /*NOTREACHED*/ 2171220218Sobrien} 2172220218Sobrien 2173220218Sobrienint 2174220218Sobrien_rl_qsort_string_compare(char **s1, char **s2) 2175220218Sobrien{ 2176220218Sobrien return strcoll(*s1, *s2); 2177220218Sobrien} 2178220218Sobrien 2179220220SobrienHISTORY_STATE * 2180220220Sobrienhistory_get_history_state(void) 2181220220Sobrien{ 2182220220Sobrien HISTORY_STATE *hs; 2183220220Sobrien 2184220220Sobrien if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL) 2185220220Sobrien return (NULL); 2186220220Sobrien hs->length = history_length; 2187220220Sobrien return (hs); 2188220220Sobrien} 2189220220Sobrien 2190220218Sobrienint 2191220218Sobrien/*ARGSUSED*/ 2192220218Sobrienrl_kill_text(int from, int to) 2193220218Sobrien{ 2194220218Sobrien return 0; 2195220218Sobrien} 2196220218Sobrien 2197220218SobrienKeymap 2198220218Sobrienrl_make_bare_keymap(void) 2199220218Sobrien{ 2200220218Sobrien return NULL; 2201220218Sobrien} 2202220218Sobrien 2203220218SobrienKeymap 2204220218Sobrienrl_get_keymap(void) 2205220218Sobrien{ 2206220218Sobrien return NULL; 2207220218Sobrien} 2208220218Sobrien 2209220218Sobrienvoid 2210220218Sobrien/*ARGSUSED*/ 2211220218Sobrienrl_set_keymap(Keymap k) 2212220218Sobrien{ 2213220218Sobrien} 2214220218Sobrien 2215220218Sobrienint 2216220218Sobrien/*ARGSUSED*/ 2217220218Sobrienrl_generic_bind(int type, const char * keyseq, const char * data, Keymap k) 2218220218Sobrien{ 2219220218Sobrien return 0; 2220220218Sobrien} 2221220218Sobrien 2222220218Sobrienint 2223220218Sobrien/*ARGSUSED*/ 2224220220Sobrienrl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k) 2225220218Sobrien{ 2226220218Sobrien return 0; 2227220218Sobrien} 2228220218Sobrien 2229220220Sobrien/* unsupported, but needed by python */ 2230220220Sobrienvoid 2231220220Sobrienrl_cleanup_after_signal(void) 2232220220Sobrien{ 2233220220Sobrien} 2234220329Sobrien 2235220329Sobrienint 2236220329Sobrienrl_on_new_line(void) 2237220329Sobrien{ 2238220329Sobrien return 0; 2239220329Sobrien} 2240