Index: head/lib/libedit/chartype.c =================================================================== --- head/lib/libedit/chartype.c (revision 283083) +++ head/lib/libedit/chartype.c (revision 283084) @@ -1,352 +1,360 @@ -/* $NetBSD: chartype.c,v 1.10 2011/08/16 16:25:15 christos Exp $ */ +/* $NetBSD: chartype.c,v 1.12 2015/02/22 02:16:19 christos Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * chartype.c: character classification and meta information */ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: chartype.c,v 1.10 2011/08/16 16:25:15 christos Exp $"); +__RCSID("$NetBSD: chartype.c,v 1.12 2015/02/22 02:16:19 christos Exp $"); #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); #include "el.h" #include #define CT_BUFSIZ ((size_t)1024) #ifdef WIDECHAR -protected void -ct_conv_buff_resize(ct_buffer_t *conv, size_t mincsize, size_t minwsize) +protected int +ct_conv_cbuff_resize(ct_buffer_t *conv, size_t csize) { void *p; - if (mincsize > conv->csize) { - conv->csize = mincsize; - p = el_realloc(conv->cbuff, conv->csize * sizeof(*conv->cbuff)); - if (p == NULL) { - conv->csize = 0; - el_free(conv->cbuff); - conv->cbuff = NULL; - } else - conv->cbuff = p; + + if (csize <= conv->csize) + return 0; + + conv->csize = csize; + + p = el_realloc(conv->cbuff, conv->csize * sizeof(*conv->cbuff)); + if (p == NULL) { + conv->csize = 0; + el_free(conv->cbuff); + conv->cbuff = NULL; + return -1; } + conv->cbuff = p; + return 0; +} - if (minwsize > conv->wsize) { - conv->wsize = minwsize; - p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff)); - if (p == NULL) { - conv->wsize = 0; - el_free(conv->wbuff); - conv->wbuff = NULL; - } else - conv->wbuff = p; +protected int +ct_conv_wbuff_resize(ct_buffer_t *conv, size_t wsize) +{ + void *p; + + if (wsize <= conv->wsize) + return 0; + + conv->wsize = wsize; + + p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff)); + if (p == NULL) { + conv->wsize = 0; + el_free(conv->wbuff); + conv->wbuff = NULL; + return -1; } + conv->wbuff = p; + return 0; } public char * ct_encode_string(const Char *s, ct_buffer_t *conv) { char *dst; - ssize_t used = 0; + ssize_t used; if (!s) return NULL; - if (!conv->cbuff) - ct_conv_buff_resize(conv, CT_BUFSIZ, (size_t)0); - if (!conv->cbuff) - return NULL; dst = conv->cbuff; - while (*s) { - used = (ssize_t)(conv->csize - (size_t)(dst - conv->cbuff)); - if (used < 5) { - used = dst - conv->cbuff; - ct_conv_buff_resize(conv, conv->csize + CT_BUFSIZ, - (size_t)0); - if (!conv->cbuff) + for (;;) { + used = (ssize_t)(dst - conv->cbuff); + if ((conv->csize - (size_t)used) < 5) { + if (ct_conv_cbuff_resize(conv, + conv->csize + CT_BUFSIZ) == -1) return NULL; dst = conv->cbuff + used; } + if (!*s) + break; used = ct_encode_char(dst, (size_t)5, *s); if (used == -1) /* failed to encode, need more buffer space */ abort(); ++s; dst += used; } *dst = '\0'; return conv->cbuff; } public Char * ct_decode_string(const char *s, ct_buffer_t *conv) { - size_t len = 0; + size_t len; if (!s) return NULL; - if (!conv->wbuff) - ct_conv_buff_resize(conv, (size_t)0, CT_BUFSIZ); - if (!conv->wbuff) - return NULL; len = ct_mbstowcs(NULL, s, (size_t)0); if (len == (size_t)-1) return NULL; - if (len > conv->wsize) - ct_conv_buff_resize(conv, (size_t)0, len + 1); - if (!conv->wbuff) - return NULL; + + if (conv->wsize < ++len) + if (ct_conv_wbuff_resize(conv, len + CT_BUFSIZ) == -1) + return NULL; + ct_mbstowcs(conv->wbuff, s, conv->wsize); return conv->wbuff; } protected Char ** ct_decode_argv(int argc, const char *argv[], ct_buffer_t *conv) { size_t bufspace; int i; Char *p; Char **wargv; ssize_t bytes; /* Make sure we have enough space in the conversion buffer to store all * the argv strings. */ for (i = 0, bufspace = 0; i < argc; ++i) bufspace += argv[i] ? strlen(argv[i]) + 1 : 0; - ct_conv_buff_resize(conv, (size_t)0, bufspace); - if (!conv->wsize) - return NULL; + if (conv->wsize < ++bufspace) + if (ct_conv_wbuff_resize(conv, bufspace + CT_BUFSIZ) == -1) + return NULL; wargv = el_malloc((size_t)argc * sizeof(*wargv)); for (i = 0, p = conv->wbuff; i < argc; ++i) { if (!argv[i]) { /* don't pass null pointers to mbstowcs */ wargv[i] = NULL; continue; } else { wargv[i] = p; bytes = (ssize_t)mbstowcs(p, argv[i], bufspace); } if (bytes == -1) { el_free(wargv); return NULL; } else bytes++; /* include '\0' in the count */ bufspace -= (size_t)bytes; p += bytes; } return wargv; } protected size_t ct_enc_width(Char c) { /* UTF-8 encoding specific values */ if (c < 0x80) return 1; else if (c < 0x0800) return 2; else if (c < 0x10000) return 3; else if (c < 0x110000) return 4; else return 0; /* not a valid codepoint */ } protected ssize_t ct_encode_char(char *dst, size_t len, Char c) { ssize_t l = 0; if (len < ct_enc_width(c)) return -1; l = ct_wctomb(dst, c); if (l < 0) { ct_wctomb_reset; l = 0; } return l; } #endif protected const Char * ct_visual_string(const Char *s) { static Char *buff = NULL; static size_t buffsize = 0; void *p; Char *dst; ssize_t used = 0; if (!s) return NULL; if (!buff) { buffsize = CT_BUFSIZ; buff = el_malloc(buffsize * sizeof(*buff)); } dst = buff; while (*s) { used = ct_visual_char(dst, buffsize - (size_t)(dst - buff), *s); if (used == -1) { /* failed to encode, need more buffer space */ used = dst - buff; buffsize += CT_BUFSIZ; p = el_realloc(buff, buffsize * sizeof(*buff)); if (p == NULL) goto out; buff = p; dst = buff + used; /* don't increment s here - we want to retry it! */ } else ++s; dst += used; } if (dst >= (buff + buffsize)) { /* sigh */ buffsize += 1; p = el_realloc(buff, buffsize * sizeof(*buff)); if (p == NULL) goto out; buff = p; dst = buff + buffsize - 1; } *dst = 0; return buff; out: el_free(buff); buffsize = 0; return NULL; } protected int ct_visual_width(Char c) { int t = ct_chr_class(c); switch (t) { case CHTYPE_ASCIICTL: return 2; /* ^@ ^? etc. */ case CHTYPE_TAB: return 1; /* Hmm, this really need to be handled outside! */ case CHTYPE_NL: return 0; /* Should this be 1 instead? */ #ifdef WIDECHAR case CHTYPE_PRINT: return wcwidth(c); case CHTYPE_NONPRINT: if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ return 8; /* \U+12345 */ else return 7; /* \U+1234 */ #else case CHTYPE_PRINT: return 1; case CHTYPE_NONPRINT: return 4; /* \123 */ #endif default: return 0; /* should not happen */ } } protected ssize_t ct_visual_char(Char *dst, size_t len, Char c) { int t = ct_chr_class(c); switch (t) { case CHTYPE_TAB: case CHTYPE_NL: case CHTYPE_ASCIICTL: if (len < 2) return -1; /* insufficient space */ *dst++ = '^'; if (c == '\177') *dst = '?'; /* DEL -> ^? */ else *dst = c | 0100; /* uncontrolify it */ return 2; case CHTYPE_PRINT: if (len < 1) return -1; /* insufficient space */ *dst = c; return 1; case CHTYPE_NONPRINT: /* we only use single-width glyphs for display, * so this is right */ if ((ssize_t)len < ct_visual_width(c)) return -1; /* insufficient space */ #ifdef WIDECHAR *dst++ = '\\'; *dst++ = 'U'; *dst++ = '+'; #define tohexdigit(v) "0123456789ABCDEF"[v] if (c > 0xffff) /* prefer standard 4-byte display over 5-byte */ *dst++ = tohexdigit(((unsigned int) c >> 16) & 0xf); *dst++ = tohexdigit(((unsigned int) c >> 12) & 0xf); *dst++ = tohexdigit(((unsigned int) c >> 8) & 0xf); *dst++ = tohexdigit(((unsigned int) c >> 4) & 0xf); *dst = tohexdigit(((unsigned int) c ) & 0xf); return c > 0xffff ? 8 : 7; #else *dst++ = '\\'; #define tooctaldigit(v) ((v) + '0') *dst++ = tooctaldigit(((unsigned int) c >> 6) & 0x7); *dst++ = tooctaldigit(((unsigned int) c >> 3) & 0x7); *dst++ = tooctaldigit(((unsigned int) c ) & 0x7); #endif /*FALLTHROUGH*/ /* these two should be handled outside this function */ default: /* we should never hit the default */ return 0; } } protected int ct_chr_class(Char c) { if (c == '\t') return CHTYPE_TAB; else if (c == '\n') return CHTYPE_NL; else if (IsASCII(c) && Iscntrl(c)) return CHTYPE_ASCIICTL; else if (Isprint(c)) return CHTYPE_PRINT; else return CHTYPE_NONPRINT; } Index: head/lib/libedit/chartype.h =================================================================== --- head/lib/libedit/chartype.h (revision 283083) +++ head/lib/libedit/chartype.h (revision 283084) @@ -1,245 +1,249 @@ -/* $NetBSD: chartype.h,v 1.10 2011/11/16 01:45:10 christos Exp $ */ +/* $NetBSD: chartype.h,v 1.15 2015/05/17 13:14:41 christos Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _h_chartype_f #define _h_chartype_f #ifdef WIDECHAR /* Ideally we should also test the value of the define to see if it * supports non-BMP code points without requiring UTF-16, but nothing * seems to actually advertise this properly, despite Unicode 3.1 having * been around since 2001... */ -#if !defined(__NetBSD__) && !defined(__sun) && !(defined(__APPLE__) && defined(__MACH__)) && !defined(__FreeBSD__) +#if !defined(__NetBSD__) && !defined(__sun) && !(defined(__APPLE__) && defined(__MACH__)) && !defined(__OpenBSD__) && !defined(__FreeBSD__) #ifndef __STDC_ISO_10646__ /* In many places it is assumed that the first 127 code points are ASCII * compatible, so ensure wchar_t indeed does ISO 10646 and not some other * funky encoding that could break us in weird and wonderful ways. */ #error wchar_t must store ISO 10646 characters #endif #endif /* Oh for a with char32_t and __STDC_UTF_32__ in it... * ref: ISO/IEC DTR 19769 */ #if WCHAR_MAX < INT32_MAX #warning Build environment does not support non-BMP characters #endif #define ct_mbtowc mbtowc #define ct_mbtowc_reset mbtowc(0,0,(size_t)0) #define ct_wctomb wctomb #define ct_wctomb_reset wctomb(0,0) #define ct_wcstombs wcstombs #define ct_mbstowcs mbstowcs #define Char wchar_t #define Int wint_t #define FUN(prefix,rest) prefix ## _w ## rest #define FUNW(type) type ## _w #define TYPE(type) type ## W +#define FCHAR "%lc" #define FSTR "%ls" #define STR(x) L ## x #define UC(c) c #define Isalpha(x) iswalpha(x) #define Isalnum(x) iswalnum(x) #define Isgraph(x) iswgraph(x) #define Isspace(x) iswspace(x) #define Isdigit(x) iswdigit(x) #define Iscntrl(x) iswcntrl(x) #define Isprint(x) iswprint(x) #define Isupper(x) iswupper(x) #define Islower(x) iswlower(x) #define Toupper(x) towupper(x) #define Tolower(x) towlower(x) #define IsASCII(x) (x < 0x100) #define Strlen(x) wcslen(x) #define Strchr(s,c) wcschr(s,c) #define Strrchr(s,c) wcsrchr(s,c) #define Strstr(s,v) wcsstr(s,v) #define Strdup(x) wcsdup(x) #define Strcpy(d,s) wcscpy(d,s) #define Strncpy(d,s,n) wcsncpy(d,s,n) #define Strncat(d,s,n) wcsncat(d,s,n) #define Strcmp(s,v) wcscmp(s,v) #define Strncmp(s,v,n) wcsncmp(s,v,n) #define Strcspn(s,r) wcscspn(s,r) #define Strtol(p,e,b) wcstol(p,e,b) static inline int Width(wchar_t c) { int w = wcwidth(c); return w < 0 ? 0 : w; } #else /* NARROW */ #define ct_mbtowc error #define ct_mbtowc_reset #define ct_wctomb error #define ct_wctomb_reset #define ct_wcstombs(a, b, c) (strncpy(a, b, c), strlen(a)) #define ct_mbstowcs(a, b, c) (strncpy(a, b, c), strlen(a)) #define Char char #define Int int #define FUN(prefix,rest) prefix ## _ ## rest #define FUNW(type) type #define TYPE(type) type +#define FCHAR "%c" #define FSTR "%s" #define STR(x) x #define UC(c) (unsigned char)(c) #define Isalpha(x) isalpha((unsigned char)x) #define Isalnum(x) isalnum((unsigned char)x) #define Isgraph(x) isgraph((unsigned char)x) #define Isspace(x) isspace((unsigned char)x) #define Isdigit(x) isdigit((unsigned char)x) #define Iscntrl(x) iscntrl((unsigned char)x) #define Isprint(x) isprint((unsigned char)x) #define Isupper(x) isupper((unsigned char)x) #define Islower(x) islower((unsigned char)x) #define Toupper(x) toupper((unsigned char)x) #define Tolower(x) tolower((unsigned char)x) #define IsASCII(x) isascii((unsigned char)x) #define Strlen(x) strlen(x) #define Strchr(s,c) strchr(s,c) #define Strrchr(s,c) strrchr(s,c) #define Strstr(s,v) strstr(s,v) #define Strdup(x) strdup(x) #define Strcpy(d,s) strcpy(d,s) #define Strncpy(d,s,n) strncpy(d,s,n) #define Strncat(d,s,n) strncat(d,s,n) #define Strcmp(s,v) strcmp(s,v) #define Strncmp(s,v,n) strncmp(s,v,n) #define Strcspn(s,r) strcspn(s,r) #define Strtol(p,e,b) strtol(p,e,b) #define Width(c) 1 #endif #ifdef WIDECHAR /* * Conversion buffer */ typedef struct ct_buffer_t { char *cbuff; size_t csize; Char *wbuff; size_t wsize; } ct_buffer_t; #define ct_encode_string __ct_encode_string /* Encode a wide-character string and return the UTF-8 encoded result. */ public char *ct_encode_string(const Char *, ct_buffer_t *); #define ct_decode_string __ct_decode_string /* Decode a (multi)?byte string and return the wide-character string result. */ public Char *ct_decode_string(const char *, ct_buffer_t *); /* Decode a (multi)?byte argv string array. * The pointer returned must be free()d when done. */ protected Char **ct_decode_argv(int, const char *[], ct_buffer_t *); /* Resizes the conversion buffer(s) if needed. */ -protected void ct_conv_buff_resize(ct_buffer_t *, size_t, size_t); +protected int ct_conv_cbuff_resize(ct_buffer_t *, size_t); +protected int ct_conv_wbuff_resize(ct_buffer_t *, size_t); protected ssize_t ct_encode_char(char *, size_t, Char); protected size_t ct_enc_width(Char); #define ct_free_argv(s) el_free(s) #else #define ct_encode_string(s, b) (s) #define ct_decode_string(s, b) (s) #define ct_decode_argv(l, s, b) (s) -#define ct_conv_buff_resize(b, os, ns) +#define ct_conv_cbuff_resize(b, s) ((s) == (0)) +#define ct_conv_wbuff_resize(b, s) ((s) == (0)) #define ct_encode_char(d, l, s) (*d = s, 1) #define ct_free_argv(s) #endif #ifndef NARROWCHAR /* Encode a characted into the destination buffer, provided there is sufficent * buffer space available. Returns the number of bytes used up (zero if the * character cannot be encoded, -1 if there was not enough space available). */ /* The maximum buffer size to hold the most unwieldly visual representation, * in this case \U+nnnnn. */ #define VISUAL_WIDTH_MAX ((size_t)8) /* The terminal is thought of in terms of X columns by Y lines. In the cases * where a wide character takes up more than one column, the adjacent * occupied column entries will contain this faux character. */ #define MB_FILL_CHAR ((Char)-1) /* Visual width of character c, taking into account ^? , \0177 and \U+nnnnn * style visual expansions. */ protected int ct_visual_width(Char); /* Turn the given character into the appropriate visual format, matching * the width given by ct_visual_width(). Returns the number of characters used * up, or -1 if insufficient space. Buffer length is in count of Char's. */ protected ssize_t ct_visual_char(Char *, size_t, Char); /* Convert the given string into visual format, using the ct_visual_char() * function. Uses a static buffer, so not threadsafe. */ protected const Char *ct_visual_string(const Char *); /* printable character, use ct_visual_width() to find out display width */ #define CHTYPE_PRINT ( 0) /* control character found inside the ASCII portion of the charset */ #define CHTYPE_ASCIICTL (-1) /* a \t */ #define CHTYPE_TAB (-2) /* a \n */ #define CHTYPE_NL (-3) /* non-printable character */ #define CHTYPE_NONPRINT (-4) /* classification of character c, as one of the above defines */ protected int ct_chr_class(Char c); #endif #endif /* _chartype_f */ Index: head/lib/libedit/edit/readline/readline.h =================================================================== --- head/lib/libedit/edit/readline/readline.h (revision 283083) +++ head/lib/libedit/edit/readline/readline.h (revision 283084) @@ -1,226 +1,226 @@ -/* $NetBSD: readline.h,v 1.31 2010/08/04 20:29:18 christos Exp $ */ +/* $NetBSD: readline.h,v 1.34 2013/05/28 00:10:34 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jaromir Dolecek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _READLINE_H_ #define _READLINE_H_ #include #include /* list of readline stuff supported by editline library's readline wrapper */ /* typedefs */ typedef int Function(const char *, int); typedef void VFunction(void); typedef void VCPFunction(char *); typedef char *CPFunction(const char *, int); typedef char **CPPFunction(const char *, int, int); typedef char *rl_compentry_func_t(const char *, int); typedef int rl_command_func_t(int, int); /* only supports length */ typedef struct { int length; } HISTORY_STATE; typedef void *histdata_t; typedef struct _hist_entry { const char *line; histdata_t data; } HIST_ENTRY; typedef struct _keymap_entry { char type; #define ISFUNC 0 #define ISKMAP 1 #define ISMACR 2 Function *function; } KEYMAP_ENTRY; #define KEYMAP_SIZE 256 typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; typedef KEYMAP_ENTRY *Keymap; #define control_character_threshold 0x20 #define control_character_bit 0x40 #ifndef CTRL #include #if !defined(__sun) && !defined(__hpux) && !defined(_AIX) #include #endif #ifndef CTRL #define CTRL(c) ((c) & 037) #endif #endif #ifndef UNCTRL #define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit) #endif #define RUBOUT 0x7f #define ABORT_CHAR CTRL('G') #define RL_READLINE_VERSION 0x0402 #define RL_PROMPT_START_IGNORE '\1' #define RL_PROMPT_END_IGNORE '\2' /* global variables used by readline enabled applications */ #ifdef __cplusplus extern "C" { #endif extern const char *rl_library_version; extern int rl_readline_version; extern char *rl_readline_name; extern FILE *rl_instream; extern FILE *rl_outstream; extern char *rl_line_buffer; extern int rl_point, rl_end; extern int history_base, history_length; extern int max_input_history; extern char *rl_basic_word_break_characters; extern char *rl_completer_word_break_characters; extern char *rl_completer_quote_characters; extern Function *rl_completion_entry_function; extern char *(*rl_completion_word_break_hook)(void); extern CPPFunction *rl_attempted_completion_function; extern int rl_attempted_completion_over; extern int rl_completion_type; extern int rl_completion_query_items; extern char *rl_special_prefixes; extern int rl_completion_append_character; extern int rl_inhibit_completion; extern Function *rl_pre_input_hook; extern Function *rl_startup_hook; extern char *rl_terminal_name; extern int rl_already_prompted; extern char *rl_prompt; /* * The following is not implemented */ extern int rl_catch_signals; extern int rl_catch_sigwinch; extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; extern int rl_filename_completion_desired; extern int rl_ignore_completion_duplicates; extern int (*rl_getc_function)(FILE *); extern VFunction *rl_redisplay_function; extern VFunction *rl_completion_display_matches_hook; extern VFunction *rl_prep_term_function; extern VFunction *rl_deprep_term_function; extern int readline_echoing_p; extern int _rl_print_completions_horizontally; /* supported functions */ char *readline(const char *); int rl_initialize(void); void using_history(void); int add_history(const char *); void clear_history(void); void stifle_history(int); int unstifle_history(void); int history_is_stifled(void); int where_history(void); HIST_ENTRY *current_history(void); HIST_ENTRY *history_get(int); HIST_ENTRY *remove_history(int); HIST_ENTRY *replace_history_entry(int, const char *, histdata_t); int history_total_bytes(void); int history_set_pos(int); HIST_ENTRY *previous_history(void); HIST_ENTRY *next_history(void); int history_search(const char *, int); int history_search_prefix(const char *, int); int history_search_pos(const char *, int, int); int read_history(const char *); int write_history(const char *); int history_truncate_file (const char *, int); int history_expand(char *, char **); char **history_tokenize(const char *); const char *get_history_event(const char *, int *, int); char *history_arg_extract(int, int, const char *); char *tilde_expand(char *); char *filename_completion_function(const char *, int); char *username_completion_function(const char *, int); int rl_complete(int, int); int rl_read_key(void); char **completion_matches(const char *, CPFunction *); void rl_display_match_list(char **, int, int); int rl_insert(int, int); int rl_insert_text(const char *); void rl_reset_terminal(const char *); int rl_bind_key(int, rl_command_func_t *); int rl_newline(int, int); void rl_callback_read_char(void); void rl_callback_handler_install(const char *, VCPFunction *); void rl_callback_handler_remove(void); void rl_redisplay(void); int rl_get_previous_history(int, int); void rl_prep_terminal(int); void rl_deprep_terminal(void); int rl_read_init_file(const char *); int rl_parse_and_bind(const char *); int rl_variable_bind(const char *, const char *); void rl_stuff_char(int); int rl_add_defun(const char *, Function *, int); HISTORY_STATE *history_get_history_state(void); void rl_get_screen_size(int *, int *); void rl_set_screen_size(int, int); char *rl_filename_completion_function (const char *, int); int _rl_abort_internal(void); int _rl_qsort_string_compare(char **, char **); char **rl_completion_matches(const char *, rl_compentry_func_t *); void rl_forced_update_display(void); int rl_set_prompt(const char *); int rl_on_new_line(void); /* * The following are not implemented */ int rl_kill_text(int, int); Keymap rl_get_keymap(void); void rl_set_keymap(Keymap); Keymap rl_make_bare_keymap(void); int rl_generic_bind(int, const char *, const char *, Keymap); int rl_bind_key_in_map(int, rl_command_func_t *, Keymap); void rl_cleanup_after_signal(void); void rl_free_line_state(void); #ifdef __cplusplus } #endif #endif /* _READLINE_H_ */ Index: head/lib/libedit/el.c =================================================================== --- head/lib/libedit/el.c (revision 283083) +++ head/lib/libedit/el.c (revision 283084) @@ -1,634 +1,634 @@ /* $NetBSD: el.c,v 1.73 2014/06/18 18:12:28 christos Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Christos Zoulas of Cornell University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #else __RCSID("$NetBSD: el.c,v 1.73 2014/06/18 18:12:28 christos Exp $"); #endif #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); /* * el.c: EditLine interface functions */ #include #include #include #include #include #include #include #include #include "el.h" /* el_init(): * Initialize editline and set default parameters. */ public EditLine * el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) { return el_init_fd(prog, fin, fout, ferr, fileno(fin), fileno(fout), fileno(ferr)); } public EditLine * el_init_fd(const char *prog, FILE *fin, FILE *fout, FILE *ferr, int fdin, int fdout, int fderr) { EditLine *el = el_malloc(sizeof(*el)); if (el == NULL) return NULL; memset(el, 0, sizeof(EditLine)); el->el_infile = fin; el->el_outfile = fout; el->el_errfile = ferr; el->el_infd = fdin; el->el_outfd = fdout; el->el_errfd = fderr; el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch)); if (el->el_prog == NULL) { el_free(el); return NULL; } /* * Initialize all the modules. Order is important!!! */ el->el_flags = 0; #ifdef WIDECHAR - if (setlocale(LC_CTYPE, NULL) != NULL) { + if (setlocale(LC_CTYPE, NULL) != NULL){ if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) el->el_flags |= CHARSET_IS_UTF8; } #endif if (terminal_init(el) == -1) { el_free(el->el_prog); el_free(el); return NULL; } (void) keymacro_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; (void) ch_init(el); (void) search_init(el); (void) hist_init(el); (void) prompt_init(el); (void) sig_init(el); (void) read_init(el); return el; } /* el_end(): * Clean up. */ public void el_end(EditLine *el) { if (el == NULL) return; el_reset(el); terminal_end(el); keymacro_end(el); map_end(el); tty_end(el); ch_end(el); search_end(el); hist_end(el); prompt_end(el); sig_end(el); el_free(el->el_prog); #ifdef WIDECHAR el_free(el->el_scratch.cbuff); el_free(el->el_scratch.wbuff); el_free(el->el_lgcyconv.cbuff); el_free(el->el_lgcyconv.wbuff); #endif el_free(el); } /* el_reset(): * Reset the tty and the parser */ public void el_reset(EditLine *el) { tty_cookedmode(el); ch_reset(el, 0); /* XXX: Do we want that? */ } /* el_set(): * set the editline parameters */ public int FUN(el,set)(EditLine *el, int op, ...) { va_list ap; int rv = 0; if (el == NULL) return -1; va_start(ap, op); switch (op) { case EL_PROMPT: case EL_RPROMPT: { el_pfunc_t p = va_arg(ap, el_pfunc_t); rv = prompt_set(el, p, 0, op, 1); break; } case EL_RESIZE: { el_zfunc_t p = va_arg(ap, el_zfunc_t); void *arg = va_arg(ap, void *); rv = ch_resizefun(el, p, arg); break; } case EL_ALIAS_TEXT: { el_afunc_t p = va_arg(ap, el_afunc_t); void *arg = va_arg(ap, void *); rv = ch_aliasfun(el, p, arg); break; } case EL_PROMPT_ESC: case EL_RPROMPT_ESC: { el_pfunc_t p = va_arg(ap, el_pfunc_t); int c = va_arg(ap, int); rv = prompt_set(el, p, c, op, 1); break; } case EL_TERMINAL: rv = terminal_set(el, va_arg(ap, char *)); break; case EL_EDITOR: rv = map_set_editor(el, va_arg(ap, Char *)); break; case EL_SIGNAL: if (va_arg(ap, int)) el->el_flags |= HANDLE_SIGNALS; else el->el_flags &= ~HANDLE_SIGNALS; break; case EL_BIND: case EL_TELLTC: case EL_SETTC: case EL_ECHOTC: case EL_SETTY: { const Char *argv[20]; int i; for (i = 1; i < (int)__arraycount(argv); i++) if ((argv[i] = va_arg(ap, Char *)) == NULL) break; switch (op) { case EL_BIND: argv[0] = STR("bind"); rv = map_bind(el, i, argv); break; case EL_TELLTC: argv[0] = STR("telltc"); rv = terminal_telltc(el, i, argv); break; case EL_SETTC: argv[0] = STR("settc"); rv = terminal_settc(el, i, argv); break; case EL_ECHOTC: argv[0] = STR("echotc"); rv = terminal_echotc(el, i, argv); break; case EL_SETTY: argv[0] = STR("setty"); rv = tty_stty(el, i, argv); break; default: rv = -1; EL_ABORT((el->el_errfile, "Bad op %d\n", op)); break; } break; } case EL_ADDFN: { Char *name = va_arg(ap, Char *); Char *help = va_arg(ap, Char *); el_func_t func = va_arg(ap, el_func_t); rv = map_addfunc(el, name, help, func); break; } case EL_HIST: { hist_fun_t func = va_arg(ap, hist_fun_t); void *ptr = va_arg(ap, void *); rv = hist_set(el, func, ptr); if (!(el->el_flags & CHARSET_IS_UTF8)) el->el_flags &= ~NARROW_HISTORY; break; } case EL_EDITMODE: if (va_arg(ap, int)) el->el_flags &= ~EDIT_DISABLED; else el->el_flags |= EDIT_DISABLED; rv = 0; break; case EL_GETCFN: { el_rfunc_t rc = va_arg(ap, el_rfunc_t); rv = el_read_setfn(el, rc); el->el_flags &= ~NARROW_READ; break; } case EL_CLIENTDATA: el->el_data = va_arg(ap, void *); break; case EL_UNBUFFERED: rv = va_arg(ap, int); if (rv && !(el->el_flags & UNBUFFERED)) { el->el_flags |= UNBUFFERED; read_prepare(el); } else if (!rv && (el->el_flags & UNBUFFERED)) { el->el_flags &= ~UNBUFFERED; read_finish(el); } rv = 0; break; case EL_PREP_TERM: rv = va_arg(ap, int); if (rv) (void) tty_rawmode(el); else (void) tty_cookedmode(el); rv = 0; break; case EL_SETFP: { FILE *fp; int what; what = va_arg(ap, int); fp = va_arg(ap, FILE *); rv = 0; switch (what) { case 0: el->el_infile = fp; el->el_infd = fileno(fp); break; case 1: el->el_outfile = fp; el->el_outfd = fileno(fp); break; case 2: el->el_errfile = fp; el->el_errfd = fileno(fp); break; default: rv = -1; break; } break; } case EL_REFRESH: re_clear_display(el); re_refresh(el); terminal__flush(el); break; default: rv = -1; break; } va_end(ap); return rv; } /* el_get(): * retrieve the editline parameters */ public int FUN(el,get)(EditLine *el, int op, ...) { va_list ap; int rv; if (el == NULL) return -1; va_start(ap, op); switch (op) { case EL_PROMPT: case EL_RPROMPT: { el_pfunc_t *p = va_arg(ap, el_pfunc_t *); rv = prompt_get(el, p, 0, op); break; } case EL_PROMPT_ESC: case EL_RPROMPT_ESC: { el_pfunc_t *p = va_arg(ap, el_pfunc_t *); Char *c = va_arg(ap, Char *); rv = prompt_get(el, p, c, op); break; } case EL_EDITOR: rv = map_get_editor(el, va_arg(ap, const Char **)); break; case EL_SIGNAL: *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS); rv = 0; break; case EL_EDITMODE: *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED); rv = 0; break; case EL_TERMINAL: terminal_get(el, va_arg(ap, const char **)); rv = 0; break; case EL_GETTC: { static char name[] = "gettc"; char *argv[20]; int i; for (i = 1; i < (int)__arraycount(argv); i++) if ((argv[i] = va_arg(ap, char *)) == NULL) break; argv[0] = name; rv = terminal_gettc(el, i, argv); break; } case EL_GETCFN: *va_arg(ap, el_rfunc_t *) = el_read_getfn(el); rv = 0; break; case EL_CLIENTDATA: *va_arg(ap, void **) = el->el_data; rv = 0; break; case EL_UNBUFFERED: *va_arg(ap, int *) = (el->el_flags & UNBUFFERED) != 0; rv = 0; break; case EL_GETFP: { int what; FILE **fpp; what = va_arg(ap, int); fpp = va_arg(ap, FILE **); rv = 0; switch (what) { case 0: *fpp = el->el_infile; break; case 1: *fpp = el->el_outfile; break; case 2: *fpp = el->el_errfile; break; default: rv = -1; break; } break; } default: rv = -1; break; } va_end(ap); return rv; } /* el_line(): * Return editing info */ public const TYPE(LineInfo) * FUN(el,line)(EditLine *el) { return (const TYPE(LineInfo) *)(void *)&el->el_line; } /* el_source(): * Source a file */ public int el_source(EditLine *el, const char *fname) { FILE *fp; size_t len; char *ptr; char *path = NULL; const Char *dptr; int error = 0; fp = NULL; if (fname == NULL) { #ifdef HAVE_ISSETUGID static const char elpath[] = "/.editrc"; size_t plen = sizeof(elpath); if (issetugid()) return -1; if ((ptr = getenv("HOME")) == NULL) return -1; plen += strlen(ptr); if ((path = el_malloc(plen * sizeof(*path))) == NULL) return -1; (void)snprintf(path, plen, "%s%s", ptr, elpath); fname = path; #else /* * If issetugid() is missing, always return an error, in order * to keep from inadvertently opening up the user to a security * hole. */ return -1; #endif } if (fp == NULL) fp = fopen(fname, "r"); if (fp == NULL) { el_free(path); return -1; } while ((ptr = fgetln(fp, &len)) != NULL) { if (*ptr == '\n') continue; /* Empty line. */ dptr = ct_decode_string(ptr, &el->el_scratch); if (!dptr) continue; if (len > 0 && dptr[len - 1] == '\n') --len; /* loop until first non-space char or EOL */ while (*dptr != '\0' && Isspace(*dptr)) dptr++; if (*dptr == '#') continue; /* ignore, this is a comment line */ if ((error = parse_line(el, dptr)) == -1) break; } el_free(path); (void) fclose(fp); return error; } /* el_resize(): * Called from program when terminal is resized */ public void el_resize(EditLine *el) { int lins, cols; sigset_t oset, nset; (void) sigemptyset(&nset); (void) sigaddset(&nset, SIGWINCH); (void) sigprocmask(SIG_BLOCK, &nset, &oset); /* get the correct window size */ if (terminal_get_size(el, &lins, &cols)) terminal_change_size(el, lins, cols); (void) sigprocmask(SIG_SETMASK, &oset, NULL); } /* el_beep(): * Called from the program to beep */ public void el_beep(EditLine *el) { terminal_beep(el); } /* el_editmode() * Set the state of EDIT_DISABLED from the `edit' command. */ protected int /*ARGSUSED*/ el_editmode(EditLine *el, int argc, const Char **argv) { const Char *how; if (argv == NULL || argc != 2 || argv[1] == NULL) return -1; how = argv[1]; if (Strcmp(how, STR("on")) == 0) { el->el_flags &= ~EDIT_DISABLED; tty_rawmode(el); } else if (Strcmp(how, STR("off")) == 0) { tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; } else { (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n", how); return -1; } return 0; } Index: head/lib/libedit/eln.c =================================================================== --- head/lib/libedit/eln.c (revision 283083) +++ head/lib/libedit/eln.c (revision 283084) @@ -1,401 +1,401 @@ -/* $NetBSD: eln.c,v 1.17 2014/06/18 18:12:28 christos Exp $ */ +/* $NetBSD: eln.c,v 1.19 2015/05/18 15:07:04 christos Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: eln.c,v 1.17 2014/06/18 18:12:28 christos Exp $"); +__RCSID("$NetBSD: eln.c,v 1.19 2015/05/18 15:07:04 christos Exp $"); #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); #include "histedit.h" #include "el.h" #include "read.h" #include #include #include public int el_getc(EditLine *el, char *cp) { int num_read; wchar_t wc = 0; if (!(el->el_flags & CHARSET_IS_UTF8)) el->el_flags |= IGNORE_EXTCHARS; num_read = el_wgetc (el, &wc); if (!(el->el_flags & CHARSET_IS_UTF8)) el->el_flags &= ~IGNORE_EXTCHARS; if (num_read > 0) *cp = (char)wc; return num_read; } public void el_push(EditLine *el, const char *str) { /* Using multibyte->wide string decoding works fine under single-byte * character sets too, and Does The Right Thing. */ el_wpush(el, ct_decode_string(str, &el->el_lgcyconv)); } public const char * el_gets(EditLine *el, int *nread) { const wchar_t *tmp; - int nwread; - *nread = 0; - if (!(el->el_flags & CHARSET_IS_UTF8)) el->el_flags |= IGNORE_EXTCHARS; - tmp = el_wgets(el, &nwread); + tmp = el_wgets(el, nread); + if (tmp != NULL) { + size_t nwread = 0; + for (int i = 0; i < *nread; i++) + nwread += ct_enc_width(tmp[i]); + *nread = (int)nwread; + } if (!(el->el_flags & CHARSET_IS_UTF8)) el->el_flags &= ~IGNORE_EXTCHARS; - for (int i = 0; i < nwread; i++) - *nread += ct_enc_width(tmp[i]); - return ct_encode_string(tmp, &el->el_lgcyconv); } public int el_parse(EditLine *el, int argc, const char *argv[]) { int ret; const wchar_t **wargv; wargv = (const wchar_t **) ct_decode_argv(argc, argv, &el->el_lgcyconv); if (!wargv) return -1; ret = el_wparse(el, argc, wargv); ct_free_argv(wargv); return ret; } public int el_set(EditLine *el, int op, ...) { va_list ap; int ret; if (!el) return -1; va_start(ap, op); switch (op) { case EL_PROMPT: /* el_pfunc_t */ case EL_RPROMPT: { el_pfunc_t p = va_arg(ap, el_pfunc_t); ret = prompt_set(el, p, 0, op, 0); break; } case EL_RESIZE: { el_zfunc_t p = va_arg(ap, el_zfunc_t); void *arg = va_arg(ap, void *); ret = ch_resizefun(el, p, arg); break; } case EL_ALIAS_TEXT: { el_afunc_t p = va_arg(ap, el_afunc_t); void *arg = va_arg(ap, void *); ret = ch_aliasfun(el, p, arg); break; } case EL_PROMPT_ESC: case EL_RPROMPT_ESC: { el_pfunc_t p = va_arg(ap, el_pfunc_t); int c = va_arg(ap, int); ret = prompt_set(el, p, c, op, 0); break; } case EL_TERMINAL: /* const char * */ ret = el_wset(el, op, va_arg(ap, char *)); break; case EL_EDITOR: /* const wchar_t * */ ret = el_wset(el, op, ct_decode_string(va_arg(ap, char *), &el->el_lgcyconv)); break; case EL_SIGNAL: /* int */ case EL_EDITMODE: case EL_UNBUFFERED: case EL_PREP_TERM: ret = el_wset(el, op, va_arg(ap, int)); break; case EL_BIND: /* const char * list -> const wchar_t * list */ case EL_TELLTC: case EL_SETTC: case EL_ECHOTC: case EL_SETTY: { const char *argv[20]; int i; const wchar_t **wargv; for (i = 1; i < (int)__arraycount(argv) - 1; ++i) if ((argv[i] = va_arg(ap, const char *)) == NULL) break; argv[0] = argv[i] = NULL; wargv = (const wchar_t **) ct_decode_argv(i + 1, argv, &el->el_lgcyconv); if (!wargv) { ret = -1; goto out; } /* * AFAIK we can't portably pass through our new wargv to * el_wset(), so we have to reimplement the body of * el_wset() for these ops. */ switch (op) { case EL_BIND: wargv[0] = STR("bind"); ret = map_bind(el, i, wargv); break; case EL_TELLTC: wargv[0] = STR("telltc"); ret = terminal_telltc(el, i, wargv); break; case EL_SETTC: wargv[0] = STR("settc"); ret = terminal_settc(el, i, wargv); break; case EL_ECHOTC: wargv[0] = STR("echotc"); ret = terminal_echotc(el, i, wargv); break; case EL_SETTY: wargv[0] = STR("setty"); ret = tty_stty(el, i, wargv); break; default: ret = -1; } ct_free_argv(wargv); break; } /* XXX: do we need to change el_func_t too? */ case EL_ADDFN: { /* const char *, const char *, el_func_t */ const char *args[2]; el_func_t func; wchar_t **wargv; args[0] = va_arg(ap, const char *); args[1] = va_arg(ap, const char *); func = va_arg(ap, el_func_t); wargv = ct_decode_argv(2, args, &el->el_lgcyconv); if (!wargv) { ret = -1; goto out; } // XXX: The two strdup's leak ret = map_addfunc(el, Strdup(wargv[0]), Strdup(wargv[1]), func); ct_free_argv(wargv); break; } case EL_HIST: { /* hist_fun_t, const char * */ hist_fun_t fun = va_arg(ap, hist_fun_t); void *ptr = va_arg(ap, void *); ret = hist_set(el, fun, ptr); el->el_flags |= NARROW_HISTORY; break; } /* XXX: do we need to change el_rfunc_t? */ case EL_GETCFN: /* el_rfunc_t */ ret = el_wset(el, op, va_arg(ap, el_rfunc_t)); el->el_flags |= NARROW_READ; break; case EL_CLIENTDATA: /* void * */ ret = el_wset(el, op, va_arg(ap, void *)); break; case EL_SETFP: { /* int, FILE * */ int what = va_arg(ap, int); FILE *fp = va_arg(ap, FILE *); ret = el_wset(el, op, what, fp); break; } case EL_REFRESH: re_clear_display(el); re_refresh(el); terminal__flush(el); ret = 0; break; default: ret = -1; break; } out: va_end(ap); return ret; } public int el_get(EditLine *el, int op, ...) { va_list ap; int ret; if (!el) return -1; va_start(ap, op); switch (op) { case EL_PROMPT: /* el_pfunc_t * */ case EL_RPROMPT: { el_pfunc_t *p = va_arg(ap, el_pfunc_t *); ret = prompt_get(el, p, 0, op); break; } case EL_PROMPT_ESC: /* el_pfunc_t *, char **/ case EL_RPROMPT_ESC: { el_pfunc_t *p = va_arg(ap, el_pfunc_t *); char *c = va_arg(ap, char *); wchar_t wc = 0; ret = prompt_get(el, p, &wc, op); *c = (char)wc; break; } case EL_EDITOR: { const char **p = va_arg(ap, const char **); const wchar_t *pw; ret = el_wget(el, op, &pw); *p = ct_encode_string(pw, &el->el_lgcyconv); if (!el->el_lgcyconv.csize) ret = -1; break; } case EL_TERMINAL: /* const char ** */ ret = el_wget(el, op, va_arg(ap, const char **)); break; case EL_SIGNAL: /* int * */ case EL_EDITMODE: case EL_UNBUFFERED: case EL_PREP_TERM: ret = el_wget(el, op, va_arg(ap, int *)); break; case EL_GETTC: { char *argv[20]; static char gettc[] = "gettc"; int i; for (i = 1; i < (int)__arraycount(argv); ++i) if ((argv[i] = va_arg(ap, char *)) == NULL) break; argv[0] = gettc; ret = terminal_gettc(el, i, argv); break; } /* XXX: do we need to change el_rfunc_t? */ case EL_GETCFN: /* el_rfunc_t */ ret = el_wget(el, op, va_arg(ap, el_rfunc_t *)); break; case EL_CLIENTDATA: /* void ** */ ret = el_wget(el, op, va_arg(ap, void **)); break; case EL_GETFP: { /* int, FILE ** */ int what = va_arg(ap, int); FILE **fpp = va_arg(ap, FILE **); ret = el_wget(el, op, what, fpp); break; } default: ret = -1; break; } va_end(ap); return ret; } const LineInfo * el_line(EditLine *el) { const LineInfoW *winfo = el_wline(el); LineInfo *info = &el->el_lgcylinfo; size_t offset; const Char *p; info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv); offset = 0; for (p = winfo->buffer; p < winfo->cursor; p++) offset += ct_enc_width(*p); info->cursor = info->buffer + offset; offset = 0; for (p = winfo->buffer; p < winfo->lastchar; p++) offset += ct_enc_width(*p); info->lastchar = info->buffer + offset; return info; } int el_insertstr(EditLine *el, const char *str) { return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv)); } Index: head/lib/libedit/map.c =================================================================== --- head/lib/libedit/map.c (revision 283083) +++ head/lib/libedit/map.c (revision 283084) @@ -1,1424 +1,1424 @@ -/* $NetBSD: map.c,v 1.34 2014/07/06 18:15:34 christos Exp $ */ +/* $NetBSD: map.c,v 1.35 2015/05/14 10:44:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Christos Zoulas of Cornell University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: map.c,v 1.34 2014/07/06 18:15:34 christos Exp $"); +__RCSID("$NetBSD: map.c,v 1.35 2015/05/14 10:44:15 christos Exp $"); #endif #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); /* * map.c: Editor function definitions */ #include #include "el.h" private void map_print_key(EditLine *, el_action_t *, const Char *); private void map_print_some_keys(EditLine *, el_action_t *, Int, Int); private void map_print_all_keys(EditLine *); private void map_init_nls(EditLine *); private void map_init_meta(EditLine *); /* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */ private const el_action_t el_map_emacs[] = { /* 0 */ EM_SET_MARK, /* ^@ */ /* 1 */ ED_MOVE_TO_BEG, /* ^A */ /* 2 */ ED_PREV_CHAR, /* ^B */ /* 3 */ ED_TTY_SIGINT, /* ^C */ /* 4 */ EM_DELETE_OR_LIST, /* ^D */ /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ /* 12 */ ED_CLEAR_SCREEN, /* ^L */ /* 13 */ ED_NEWLINE, /* ^M */ /* 14 */ ED_NEXT_HISTORY, /* ^N */ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ /* 16 */ ED_PREV_HISTORY, /* ^P */ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ /* 18 */ ED_REDISPLAY, /* ^R */ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */ /* 21 */ EM_KILL_LINE, /* ^U */ /* 22 */ ED_QUOTED_INSERT, /* ^V */ /* 23 */ EM_KILL_REGION, /* ^W */ /* 24 */ ED_SEQUENCE_LEAD_IN, /* ^X */ /* 25 */ EM_YANK, /* ^Y */ /* 26 */ ED_TTY_SIGTSTP, /* ^Z */ /* 27 */ EM_META_NEXT, /* ^[ */ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ /* 29 */ ED_TTY_DSUSP, /* ^] */ /* 30 */ ED_UNASSIGNED, /* ^^ */ /* 31 */ ED_UNASSIGNED, /* ^_ */ /* 32 */ ED_INSERT, /* SPACE */ /* 33 */ ED_INSERT, /* ! */ /* 34 */ ED_INSERT, /* " */ /* 35 */ ED_INSERT, /* # */ /* 36 */ ED_INSERT, /* $ */ /* 37 */ ED_INSERT, /* % */ /* 38 */ ED_INSERT, /* & */ /* 39 */ ED_INSERT, /* ' */ /* 40 */ ED_INSERT, /* ( */ /* 41 */ ED_INSERT, /* ) */ /* 42 */ ED_INSERT, /* * */ /* 43 */ ED_INSERT, /* + */ /* 44 */ ED_INSERT, /* , */ /* 45 */ ED_INSERT, /* - */ /* 46 */ ED_INSERT, /* . */ /* 47 */ ED_INSERT, /* / */ /* 48 */ ED_DIGIT, /* 0 */ /* 49 */ ED_DIGIT, /* 1 */ /* 50 */ ED_DIGIT, /* 2 */ /* 51 */ ED_DIGIT, /* 3 */ /* 52 */ ED_DIGIT, /* 4 */ /* 53 */ ED_DIGIT, /* 5 */ /* 54 */ ED_DIGIT, /* 6 */ /* 55 */ ED_DIGIT, /* 7 */ /* 56 */ ED_DIGIT, /* 8 */ /* 57 */ ED_DIGIT, /* 9 */ /* 58 */ ED_INSERT, /* : */ /* 59 */ ED_INSERT, /* ; */ /* 60 */ ED_INSERT, /* < */ /* 61 */ ED_INSERT, /* = */ /* 62 */ ED_INSERT, /* > */ /* 63 */ ED_INSERT, /* ? */ /* 64 */ ED_INSERT, /* @ */ /* 65 */ ED_INSERT, /* A */ /* 66 */ ED_INSERT, /* B */ /* 67 */ ED_INSERT, /* C */ /* 68 */ ED_INSERT, /* D */ /* 69 */ ED_INSERT, /* E */ /* 70 */ ED_INSERT, /* F */ /* 71 */ ED_INSERT, /* G */ /* 72 */ ED_INSERT, /* H */ /* 73 */ ED_INSERT, /* I */ /* 74 */ ED_INSERT, /* J */ /* 75 */ ED_INSERT, /* K */ /* 76 */ ED_INSERT, /* L */ /* 77 */ ED_INSERT, /* M */ /* 78 */ ED_INSERT, /* N */ /* 79 */ ED_INSERT, /* O */ /* 80 */ ED_INSERT, /* P */ /* 81 */ ED_INSERT, /* Q */ /* 82 */ ED_INSERT, /* R */ /* 83 */ ED_INSERT, /* S */ /* 84 */ ED_INSERT, /* T */ /* 85 */ ED_INSERT, /* U */ /* 86 */ ED_INSERT, /* V */ /* 87 */ ED_INSERT, /* W */ /* 88 */ ED_INSERT, /* X */ /* 89 */ ED_INSERT, /* Y */ /* 90 */ ED_INSERT, /* Z */ /* 91 */ ED_INSERT, /* [ */ /* 92 */ ED_INSERT, /* \ */ /* 93 */ ED_INSERT, /* ] */ /* 94 */ ED_INSERT, /* ^ */ /* 95 */ ED_INSERT, /* _ */ /* 96 */ ED_INSERT, /* ` */ /* 97 */ ED_INSERT, /* a */ /* 98 */ ED_INSERT, /* b */ /* 99 */ ED_INSERT, /* c */ /* 100 */ ED_INSERT, /* d */ /* 101 */ ED_INSERT, /* e */ /* 102 */ ED_INSERT, /* f */ /* 103 */ ED_INSERT, /* g */ /* 104 */ ED_INSERT, /* h */ /* 105 */ ED_INSERT, /* i */ /* 106 */ ED_INSERT, /* j */ /* 107 */ ED_INSERT, /* k */ /* 108 */ ED_INSERT, /* l */ /* 109 */ ED_INSERT, /* m */ /* 110 */ ED_INSERT, /* n */ /* 111 */ ED_INSERT, /* o */ /* 112 */ ED_INSERT, /* p */ /* 113 */ ED_INSERT, /* q */ /* 114 */ ED_INSERT, /* r */ /* 115 */ ED_INSERT, /* s */ /* 116 */ ED_INSERT, /* t */ /* 117 */ ED_INSERT, /* u */ /* 118 */ ED_INSERT, /* v */ /* 119 */ ED_INSERT, /* w */ /* 120 */ ED_INSERT, /* x */ /* 121 */ ED_INSERT, /* y */ /* 122 */ ED_INSERT, /* z */ /* 123 */ ED_INSERT, /* { */ /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_UNASSIGNED, /* M-^@ */ /* 129 */ ED_UNASSIGNED, /* M-^A */ /* 130 */ ED_UNASSIGNED, /* M-^B */ /* 131 */ ED_UNASSIGNED, /* M-^C */ /* 132 */ ED_UNASSIGNED, /* M-^D */ /* 133 */ ED_UNASSIGNED, /* M-^E */ /* 134 */ ED_UNASSIGNED, /* M-^F */ /* 135 */ ED_UNASSIGNED, /* M-^G */ /* 136 */ ED_DELETE_PREV_WORD, /* M-^H */ /* 137 */ ED_UNASSIGNED, /* M-^I */ /* 138 */ ED_UNASSIGNED, /* M-^J */ /* 139 */ ED_UNASSIGNED, /* M-^K */ /* 140 */ ED_CLEAR_SCREEN, /* M-^L */ /* 141 */ ED_UNASSIGNED, /* M-^M */ /* 142 */ ED_UNASSIGNED, /* M-^N */ /* 143 */ ED_UNASSIGNED, /* M-^O */ /* 144 */ ED_UNASSIGNED, /* M-^P */ /* 145 */ ED_UNASSIGNED, /* M-^Q */ /* 146 */ ED_UNASSIGNED, /* M-^R */ /* 147 */ ED_UNASSIGNED, /* M-^S */ /* 148 */ ED_UNASSIGNED, /* M-^T */ /* 149 */ ED_UNASSIGNED, /* M-^U */ /* 150 */ ED_UNASSIGNED, /* M-^V */ /* 151 */ ED_UNASSIGNED, /* M-^W */ /* 152 */ ED_UNASSIGNED, /* M-^X */ /* 153 */ ED_UNASSIGNED, /* M-^Y */ /* 154 */ ED_UNASSIGNED, /* M-^Z */ /* 155 */ ED_UNASSIGNED, /* M-^[ */ /* 156 */ ED_UNASSIGNED, /* M-^\ */ /* 157 */ ED_UNASSIGNED, /* M-^] */ /* 158 */ ED_UNASSIGNED, /* M-^^ */ /* 159 */ EM_COPY_PREV_WORD, /* M-^_ */ /* 160 */ ED_UNASSIGNED, /* M-SPACE */ /* 161 */ ED_UNASSIGNED, /* M-! */ /* 162 */ ED_UNASSIGNED, /* M-" */ /* 163 */ ED_UNASSIGNED, /* M-# */ /* 164 */ ED_UNASSIGNED, /* M-$ */ /* 165 */ ED_UNASSIGNED, /* M-% */ /* 166 */ ED_UNASSIGNED, /* M-& */ /* 167 */ ED_UNASSIGNED, /* M-' */ /* 168 */ ED_UNASSIGNED, /* M-( */ /* 169 */ ED_UNASSIGNED, /* M-) */ /* 170 */ ED_UNASSIGNED, /* M-* */ /* 171 */ ED_UNASSIGNED, /* M-+ */ /* 172 */ ED_UNASSIGNED, /* M-, */ /* 173 */ ED_UNASSIGNED, /* M-- */ /* 174 */ ED_UNASSIGNED, /* M-. */ /* 175 */ ED_UNASSIGNED, /* M-/ */ /* 176 */ ED_ARGUMENT_DIGIT, /* M-0 */ /* 177 */ ED_ARGUMENT_DIGIT, /* M-1 */ /* 178 */ ED_ARGUMENT_DIGIT, /* M-2 */ /* 179 */ ED_ARGUMENT_DIGIT, /* M-3 */ /* 180 */ ED_ARGUMENT_DIGIT, /* M-4 */ /* 181 */ ED_ARGUMENT_DIGIT, /* M-5 */ /* 182 */ ED_ARGUMENT_DIGIT, /* M-6 */ /* 183 */ ED_ARGUMENT_DIGIT, /* M-7 */ /* 184 */ ED_ARGUMENT_DIGIT, /* M-8 */ /* 185 */ ED_ARGUMENT_DIGIT, /* M-9 */ /* 186 */ ED_UNASSIGNED, /* M-: */ /* 187 */ ED_UNASSIGNED, /* M-; */ /* 188 */ ED_UNASSIGNED, /* M-< */ /* 189 */ ED_UNASSIGNED, /* M-= */ /* 190 */ ED_UNASSIGNED, /* M-> */ /* 191 */ ED_UNASSIGNED, /* M-? */ /* 192 */ ED_UNASSIGNED, /* M-@ */ /* 193 */ ED_UNASSIGNED, /* M-A */ /* 194 */ ED_PREV_WORD, /* M-B */ /* 195 */ EM_CAPITOL_CASE, /* M-C */ /* 196 */ EM_DELETE_NEXT_WORD, /* M-D */ /* 197 */ ED_UNASSIGNED, /* M-E */ /* 198 */ EM_NEXT_WORD, /* M-F */ /* 199 */ ED_UNASSIGNED, /* M-G */ /* 200 */ ED_UNASSIGNED, /* M-H */ /* 201 */ ED_UNASSIGNED, /* M-I */ /* 202 */ ED_UNASSIGNED, /* M-J */ /* 203 */ ED_UNASSIGNED, /* M-K */ /* 204 */ EM_LOWER_CASE, /* M-L */ /* 205 */ ED_UNASSIGNED, /* M-M */ /* 206 */ ED_SEARCH_NEXT_HISTORY, /* M-N */ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */ /* 208 */ ED_SEARCH_PREV_HISTORY, /* M-P */ /* 209 */ ED_UNASSIGNED, /* M-Q */ /* 210 */ ED_UNASSIGNED, /* M-R */ /* 211 */ ED_UNASSIGNED, /* M-S */ /* 212 */ ED_UNASSIGNED, /* M-T */ /* 213 */ EM_UPPER_CASE, /* M-U */ /* 214 */ ED_UNASSIGNED, /* M-V */ /* 215 */ EM_COPY_REGION, /* M-W */ /* 216 */ ED_COMMAND, /* M-X */ /* 217 */ ED_UNASSIGNED, /* M-Y */ /* 218 */ ED_UNASSIGNED, /* M-Z */ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */ /* 220 */ ED_UNASSIGNED, /* M-\ */ /* 221 */ ED_UNASSIGNED, /* M-] */ /* 222 */ ED_UNASSIGNED, /* M-^ */ /* 223 */ ED_UNASSIGNED, /* M-_ */ /* 223 */ ED_UNASSIGNED, /* M-` */ /* 224 */ ED_UNASSIGNED, /* M-a */ /* 225 */ ED_PREV_WORD, /* M-b */ /* 226 */ EM_CAPITOL_CASE, /* M-c */ /* 227 */ EM_DELETE_NEXT_WORD, /* M-d */ /* 228 */ ED_UNASSIGNED, /* M-e */ /* 229 */ EM_NEXT_WORD, /* M-f */ /* 230 */ ED_UNASSIGNED, /* M-g */ /* 231 */ ED_UNASSIGNED, /* M-h */ /* 232 */ ED_UNASSIGNED, /* M-i */ /* 233 */ ED_UNASSIGNED, /* M-j */ /* 234 */ ED_UNASSIGNED, /* M-k */ /* 235 */ EM_LOWER_CASE, /* M-l */ /* 236 */ ED_UNASSIGNED, /* M-m */ /* 237 */ ED_SEARCH_NEXT_HISTORY, /* M-n */ /* 238 */ ED_UNASSIGNED, /* M-o */ /* 239 */ ED_SEARCH_PREV_HISTORY, /* M-p */ /* 240 */ ED_UNASSIGNED, /* M-q */ /* 241 */ ED_UNASSIGNED, /* M-r */ /* 242 */ ED_UNASSIGNED, /* M-s */ /* 243 */ ED_UNASSIGNED, /* M-t */ /* 244 */ EM_UPPER_CASE, /* M-u */ /* 245 */ ED_UNASSIGNED, /* M-v */ /* 246 */ EM_COPY_REGION, /* M-w */ /* 247 */ ED_COMMAND, /* M-x */ /* 248 */ ED_UNASSIGNED, /* M-y */ /* 249 */ ED_UNASSIGNED, /* M-z */ /* 250 */ ED_UNASSIGNED, /* M-{ */ /* 251 */ ED_UNASSIGNED, /* M-| */ /* 252 */ ED_UNASSIGNED, /* M-} */ /* 253 */ ED_UNASSIGNED, /* M-~ */ /* 254 */ ED_DELETE_PREV_WORD /* M-^? */ /* 255 */ }; /* * keymap table for vi. Each index into above tbl; should be * N_KEYS entries long. Vi mode uses a sticky-extend to do command mode: * insert mode characters are in the normal keymap, and command mode * in the extended keymap. */ private const el_action_t el_map_vi_insert[] = { #ifdef KSHVI /* 0 */ ED_UNASSIGNED, /* ^@ */ /* 1 */ ED_INSERT, /* ^A */ /* 2 */ ED_INSERT, /* ^B */ /* 3 */ ED_INSERT, /* ^C */ /* 4 */ VI_LIST_OR_EOF, /* ^D */ /* 5 */ ED_INSERT, /* ^E */ /* 6 */ ED_INSERT, /* ^F */ /* 7 */ ED_INSERT, /* ^G */ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ /* 9 */ ED_INSERT, /* ^I */ /* Tab Key */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_INSERT, /* ^K */ /* 12 */ ED_INSERT, /* ^L */ /* 13 */ ED_NEWLINE, /* ^M */ /* 14 */ ED_INSERT, /* ^N */ /* 15 */ ED_INSERT, /* ^O */ /* 16 */ ED_INSERT, /* ^P */ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ /* 18 */ ED_INSERT, /* ^R */ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ /* 20 */ ED_INSERT, /* ^T */ /* 21 */ VI_KILL_LINE_PREV, /* ^U */ /* 22 */ ED_QUOTED_INSERT, /* ^V */ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ /* ED_DELETE_PREV_WORD: Only until strt edit pos */ /* 24 */ ED_INSERT, /* ^X */ /* 25 */ ED_INSERT, /* ^Y */ /* 26 */ ED_INSERT, /* ^Z */ /* 27 */ VI_COMMAND_MODE, /* ^[ */ /* [ Esc ] key */ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ /* 29 */ ED_INSERT, /* ^] */ /* 30 */ ED_INSERT, /* ^^ */ /* 31 */ ED_INSERT, /* ^_ */ #else /* !KSHVI */ /* * NOTE: These mappings do NOT Correspond well * to the KSH VI editing assignments. * On the other and they are convenient and * many people have have gotten used to them. */ /* 0 */ ED_UNASSIGNED, /* ^@ */ /* 1 */ ED_MOVE_TO_BEG, /* ^A */ /* 2 */ ED_PREV_CHAR, /* ^B */ /* 3 */ ED_TTY_SIGINT, /* ^C */ /* 4 */ VI_LIST_OR_EOF, /* ^D */ /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* Tab Key */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ /* 12 */ ED_CLEAR_SCREEN, /* ^L */ /* 13 */ ED_NEWLINE, /* ^M */ /* 14 */ ED_NEXT_HISTORY, /* ^N */ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ /* 16 */ ED_PREV_HISTORY, /* ^P */ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ /* 18 */ ED_REDISPLAY, /* ^R */ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ /* 20 */ ED_TRANSPOSE_CHARS, /* ^T */ /* 21 */ VI_KILL_LINE_PREV, /* ^U */ /* 22 */ ED_QUOTED_INSERT, /* ^V */ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ /* 24 */ ED_UNASSIGNED, /* ^X */ /* 25 */ ED_TTY_DSUSP, /* ^Y */ /* 26 */ ED_TTY_SIGTSTP, /* ^Z */ /* 27 */ VI_COMMAND_MODE, /* ^[ */ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ /* 29 */ ED_UNASSIGNED, /* ^] */ /* 30 */ ED_UNASSIGNED, /* ^^ */ /* 31 */ ED_UNASSIGNED, /* ^_ */ #endif /* KSHVI */ /* 32 */ ED_INSERT, /* SPACE */ /* 33 */ ED_INSERT, /* ! */ /* 34 */ ED_INSERT, /* " */ /* 35 */ ED_INSERT, /* # */ /* 36 */ ED_INSERT, /* $ */ /* 37 */ ED_INSERT, /* % */ /* 38 */ ED_INSERT, /* & */ /* 39 */ ED_INSERT, /* ' */ /* 40 */ ED_INSERT, /* ( */ /* 41 */ ED_INSERT, /* ) */ /* 42 */ ED_INSERT, /* * */ /* 43 */ ED_INSERT, /* + */ /* 44 */ ED_INSERT, /* , */ /* 45 */ ED_INSERT, /* - */ /* 46 */ ED_INSERT, /* . */ /* 47 */ ED_INSERT, /* / */ /* 48 */ ED_INSERT, /* 0 */ /* 49 */ ED_INSERT, /* 1 */ /* 50 */ ED_INSERT, /* 2 */ /* 51 */ ED_INSERT, /* 3 */ /* 52 */ ED_INSERT, /* 4 */ /* 53 */ ED_INSERT, /* 5 */ /* 54 */ ED_INSERT, /* 6 */ /* 55 */ ED_INSERT, /* 7 */ /* 56 */ ED_INSERT, /* 8 */ /* 57 */ ED_INSERT, /* 9 */ /* 58 */ ED_INSERT, /* : */ /* 59 */ ED_INSERT, /* ; */ /* 60 */ ED_INSERT, /* < */ /* 61 */ ED_INSERT, /* = */ /* 62 */ ED_INSERT, /* > */ /* 63 */ ED_INSERT, /* ? */ /* 64 */ ED_INSERT, /* @ */ /* 65 */ ED_INSERT, /* A */ /* 66 */ ED_INSERT, /* B */ /* 67 */ ED_INSERT, /* C */ /* 68 */ ED_INSERT, /* D */ /* 69 */ ED_INSERT, /* E */ /* 70 */ ED_INSERT, /* F */ /* 71 */ ED_INSERT, /* G */ /* 72 */ ED_INSERT, /* H */ /* 73 */ ED_INSERT, /* I */ /* 74 */ ED_INSERT, /* J */ /* 75 */ ED_INSERT, /* K */ /* 76 */ ED_INSERT, /* L */ /* 77 */ ED_INSERT, /* M */ /* 78 */ ED_INSERT, /* N */ /* 79 */ ED_INSERT, /* O */ /* 80 */ ED_INSERT, /* P */ /* 81 */ ED_INSERT, /* Q */ /* 82 */ ED_INSERT, /* R */ /* 83 */ ED_INSERT, /* S */ /* 84 */ ED_INSERT, /* T */ /* 85 */ ED_INSERT, /* U */ /* 86 */ ED_INSERT, /* V */ /* 87 */ ED_INSERT, /* W */ /* 88 */ ED_INSERT, /* X */ /* 89 */ ED_INSERT, /* Y */ /* 90 */ ED_INSERT, /* Z */ /* 91 */ ED_INSERT, /* [ */ /* 92 */ ED_INSERT, /* \ */ /* 93 */ ED_INSERT, /* ] */ /* 94 */ ED_INSERT, /* ^ */ /* 95 */ ED_INSERT, /* _ */ /* 96 */ ED_INSERT, /* ` */ /* 97 */ ED_INSERT, /* a */ /* 98 */ ED_INSERT, /* b */ /* 99 */ ED_INSERT, /* c */ /* 100 */ ED_INSERT, /* d */ /* 101 */ ED_INSERT, /* e */ /* 102 */ ED_INSERT, /* f */ /* 103 */ ED_INSERT, /* g */ /* 104 */ ED_INSERT, /* h */ /* 105 */ ED_INSERT, /* i */ /* 106 */ ED_INSERT, /* j */ /* 107 */ ED_INSERT, /* k */ /* 108 */ ED_INSERT, /* l */ /* 109 */ ED_INSERT, /* m */ /* 110 */ ED_INSERT, /* n */ /* 111 */ ED_INSERT, /* o */ /* 112 */ ED_INSERT, /* p */ /* 113 */ ED_INSERT, /* q */ /* 114 */ ED_INSERT, /* r */ /* 115 */ ED_INSERT, /* s */ /* 116 */ ED_INSERT, /* t */ /* 117 */ ED_INSERT, /* u */ /* 118 */ ED_INSERT, /* v */ /* 119 */ ED_INSERT, /* w */ /* 120 */ ED_INSERT, /* x */ /* 121 */ ED_INSERT, /* y */ /* 122 */ ED_INSERT, /* z */ /* 123 */ ED_INSERT, /* { */ /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ /* 127 */ VI_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_INSERT, /* M-^@ */ /* 129 */ ED_INSERT, /* M-^A */ /* 130 */ ED_INSERT, /* M-^B */ /* 131 */ ED_INSERT, /* M-^C */ /* 132 */ ED_INSERT, /* M-^D */ /* 133 */ ED_INSERT, /* M-^E */ /* 134 */ ED_INSERT, /* M-^F */ /* 135 */ ED_INSERT, /* M-^G */ /* 136 */ ED_INSERT, /* M-^H */ /* 137 */ ED_INSERT, /* M-^I */ /* 138 */ ED_INSERT, /* M-^J */ /* 139 */ ED_INSERT, /* M-^K */ /* 140 */ ED_INSERT, /* M-^L */ /* 141 */ ED_INSERT, /* M-^M */ /* 142 */ ED_INSERT, /* M-^N */ /* 143 */ ED_INSERT, /* M-^O */ /* 144 */ ED_INSERT, /* M-^P */ /* 145 */ ED_INSERT, /* M-^Q */ /* 146 */ ED_INSERT, /* M-^R */ /* 147 */ ED_INSERT, /* M-^S */ /* 148 */ ED_INSERT, /* M-^T */ /* 149 */ ED_INSERT, /* M-^U */ /* 150 */ ED_INSERT, /* M-^V */ /* 151 */ ED_INSERT, /* M-^W */ /* 152 */ ED_INSERT, /* M-^X */ /* 153 */ ED_INSERT, /* M-^Y */ /* 154 */ ED_INSERT, /* M-^Z */ /* 155 */ ED_INSERT, /* M-^[ */ /* 156 */ ED_INSERT, /* M-^\ */ /* 157 */ ED_INSERT, /* M-^] */ /* 158 */ ED_INSERT, /* M-^^ */ /* 159 */ ED_INSERT, /* M-^_ */ /* 160 */ ED_INSERT, /* M-SPACE */ /* 161 */ ED_INSERT, /* M-! */ /* 162 */ ED_INSERT, /* M-" */ /* 163 */ ED_INSERT, /* M-# */ /* 164 */ ED_INSERT, /* M-$ */ /* 165 */ ED_INSERT, /* M-% */ /* 166 */ ED_INSERT, /* M-& */ /* 167 */ ED_INSERT, /* M-' */ /* 168 */ ED_INSERT, /* M-( */ /* 169 */ ED_INSERT, /* M-) */ /* 170 */ ED_INSERT, /* M-* */ /* 171 */ ED_INSERT, /* M-+ */ /* 172 */ ED_INSERT, /* M-, */ /* 173 */ ED_INSERT, /* M-- */ /* 174 */ ED_INSERT, /* M-. */ /* 175 */ ED_INSERT, /* M-/ */ /* 176 */ ED_INSERT, /* M-0 */ /* 177 */ ED_INSERT, /* M-1 */ /* 178 */ ED_INSERT, /* M-2 */ /* 179 */ ED_INSERT, /* M-3 */ /* 180 */ ED_INSERT, /* M-4 */ /* 181 */ ED_INSERT, /* M-5 */ /* 182 */ ED_INSERT, /* M-6 */ /* 183 */ ED_INSERT, /* M-7 */ /* 184 */ ED_INSERT, /* M-8 */ /* 185 */ ED_INSERT, /* M-9 */ /* 186 */ ED_INSERT, /* M-: */ /* 187 */ ED_INSERT, /* M-; */ /* 188 */ ED_INSERT, /* M-< */ /* 189 */ ED_INSERT, /* M-= */ /* 190 */ ED_INSERT, /* M-> */ /* 191 */ ED_INSERT, /* M-? */ /* 192 */ ED_INSERT, /* M-@ */ /* 193 */ ED_INSERT, /* M-A */ /* 194 */ ED_INSERT, /* M-B */ /* 195 */ ED_INSERT, /* M-C */ /* 196 */ ED_INSERT, /* M-D */ /* 197 */ ED_INSERT, /* M-E */ /* 198 */ ED_INSERT, /* M-F */ /* 199 */ ED_INSERT, /* M-G */ /* 200 */ ED_INSERT, /* M-H */ /* 201 */ ED_INSERT, /* M-I */ /* 202 */ ED_INSERT, /* M-J */ /* 203 */ ED_INSERT, /* M-K */ /* 204 */ ED_INSERT, /* M-L */ /* 205 */ ED_INSERT, /* M-M */ /* 206 */ ED_INSERT, /* M-N */ /* 207 */ ED_INSERT, /* M-O */ /* 208 */ ED_INSERT, /* M-P */ /* 209 */ ED_INSERT, /* M-Q */ /* 210 */ ED_INSERT, /* M-R */ /* 211 */ ED_INSERT, /* M-S */ /* 212 */ ED_INSERT, /* M-T */ /* 213 */ ED_INSERT, /* M-U */ /* 214 */ ED_INSERT, /* M-V */ /* 215 */ ED_INSERT, /* M-W */ /* 216 */ ED_INSERT, /* M-X */ /* 217 */ ED_INSERT, /* M-Y */ /* 218 */ ED_INSERT, /* M-Z */ /* 219 */ ED_INSERT, /* M-[ */ /* 220 */ ED_INSERT, /* M-\ */ /* 221 */ ED_INSERT, /* M-] */ /* 222 */ ED_INSERT, /* M-^ */ /* 223 */ ED_INSERT, /* M-_ */ /* 224 */ ED_INSERT, /* M-` */ /* 225 */ ED_INSERT, /* M-a */ /* 226 */ ED_INSERT, /* M-b */ /* 227 */ ED_INSERT, /* M-c */ /* 228 */ ED_INSERT, /* M-d */ /* 229 */ ED_INSERT, /* M-e */ /* 230 */ ED_INSERT, /* M-f */ /* 231 */ ED_INSERT, /* M-g */ /* 232 */ ED_INSERT, /* M-h */ /* 233 */ ED_INSERT, /* M-i */ /* 234 */ ED_INSERT, /* M-j */ /* 235 */ ED_INSERT, /* M-k */ /* 236 */ ED_INSERT, /* M-l */ /* 237 */ ED_INSERT, /* M-m */ /* 238 */ ED_INSERT, /* M-n */ /* 239 */ ED_INSERT, /* M-o */ /* 240 */ ED_INSERT, /* M-p */ /* 241 */ ED_INSERT, /* M-q */ /* 242 */ ED_INSERT, /* M-r */ /* 243 */ ED_INSERT, /* M-s */ /* 244 */ ED_INSERT, /* M-t */ /* 245 */ ED_INSERT, /* M-u */ /* 246 */ ED_INSERT, /* M-v */ /* 247 */ ED_INSERT, /* M-w */ /* 248 */ ED_INSERT, /* M-x */ /* 249 */ ED_INSERT, /* M-y */ /* 250 */ ED_INSERT, /* M-z */ /* 251 */ ED_INSERT, /* M-{ */ /* 252 */ ED_INSERT, /* M-| */ /* 253 */ ED_INSERT, /* M-} */ /* 254 */ ED_INSERT, /* M-~ */ /* 255 */ ED_INSERT /* M-^? */ }; private const el_action_t el_map_vi_command[] = { /* 0 */ ED_UNASSIGNED, /* ^@ */ /* 1 */ ED_MOVE_TO_BEG, /* ^A */ /* 2 */ ED_UNASSIGNED, /* ^B */ /* 3 */ ED_TTY_SIGINT, /* ^C */ /* 4 */ ED_UNASSIGNED, /* ^D */ /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_UNASSIGNED, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ /* 12 */ ED_CLEAR_SCREEN, /* ^L */ /* 13 */ ED_NEWLINE, /* ^M */ /* 14 */ ED_NEXT_HISTORY, /* ^N */ /* 15 */ ED_TTY_FLUSH_OUTPUT, /* ^O */ /* 16 */ ED_PREV_HISTORY, /* ^P */ /* 17 */ ED_TTY_START_OUTPUT, /* ^Q */ /* 18 */ ED_REDISPLAY, /* ^R */ /* 19 */ ED_TTY_STOP_OUTPUT, /* ^S */ /* 20 */ ED_UNASSIGNED, /* ^T */ /* 21 */ VI_KILL_LINE_PREV, /* ^U */ /* 22 */ ED_UNASSIGNED, /* ^V */ /* 23 */ ED_DELETE_PREV_WORD, /* ^W */ /* 24 */ ED_UNASSIGNED, /* ^X */ /* 25 */ ED_UNASSIGNED, /* ^Y */ /* 26 */ ED_UNASSIGNED, /* ^Z */ /* 27 */ EM_META_NEXT, /* ^[ */ /* 28 */ ED_TTY_SIGQUIT, /* ^\ */ /* 29 */ ED_UNASSIGNED, /* ^] */ /* 30 */ ED_UNASSIGNED, /* ^^ */ /* 31 */ ED_UNASSIGNED, /* ^_ */ /* 32 */ ED_NEXT_CHAR, /* SPACE */ /* 33 */ ED_UNASSIGNED, /* ! */ /* 34 */ ED_UNASSIGNED, /* " */ /* 35 */ VI_COMMENT_OUT, /* # */ /* 36 */ ED_MOVE_TO_END, /* $ */ /* 37 */ VI_MATCH, /* % */ /* 38 */ ED_UNASSIGNED, /* & */ /* 39 */ ED_UNASSIGNED, /* ' */ /* 40 */ ED_UNASSIGNED, /* ( */ /* 41 */ ED_UNASSIGNED, /* ) */ /* 42 */ ED_UNASSIGNED, /* * */ /* 43 */ ED_NEXT_HISTORY, /* + */ /* 44 */ VI_REPEAT_PREV_CHAR, /* , */ /* 45 */ ED_PREV_HISTORY, /* - */ /* 46 */ VI_REDO, /* . */ /* 47 */ VI_SEARCH_PREV, /* / */ /* 48 */ VI_ZERO, /* 0 */ /* 49 */ ED_ARGUMENT_DIGIT, /* 1 */ /* 50 */ ED_ARGUMENT_DIGIT, /* 2 */ /* 51 */ ED_ARGUMENT_DIGIT, /* 3 */ /* 52 */ ED_ARGUMENT_DIGIT, /* 4 */ /* 53 */ ED_ARGUMENT_DIGIT, /* 5 */ /* 54 */ ED_ARGUMENT_DIGIT, /* 6 */ /* 55 */ ED_ARGUMENT_DIGIT, /* 7 */ /* 56 */ ED_ARGUMENT_DIGIT, /* 8 */ /* 57 */ ED_ARGUMENT_DIGIT, /* 9 */ /* 58 */ ED_COMMAND, /* : */ /* 59 */ VI_REPEAT_NEXT_CHAR, /* ; */ /* 60 */ ED_UNASSIGNED, /* < */ /* 61 */ ED_UNASSIGNED, /* = */ /* 62 */ ED_UNASSIGNED, /* > */ /* 63 */ VI_SEARCH_NEXT, /* ? */ /* 64 */ VI_ALIAS, /* @ */ /* 65 */ VI_ADD_AT_EOL, /* A */ /* 66 */ VI_PREV_BIG_WORD, /* B */ /* 67 */ VI_CHANGE_TO_EOL, /* C */ /* 68 */ ED_KILL_LINE, /* D */ /* 69 */ VI_END_BIG_WORD, /* E */ /* 70 */ VI_PREV_CHAR, /* F */ /* 71 */ VI_TO_HISTORY_LINE, /* G */ /* 72 */ ED_UNASSIGNED, /* H */ /* 73 */ VI_INSERT_AT_BOL, /* I */ /* 74 */ ED_SEARCH_NEXT_HISTORY, /* J */ /* 75 */ ED_SEARCH_PREV_HISTORY, /* K */ /* 76 */ ED_UNASSIGNED, /* L */ /* 77 */ ED_UNASSIGNED, /* M */ /* 78 */ VI_REPEAT_SEARCH_PREV, /* N */ /* 79 */ ED_SEQUENCE_LEAD_IN, /* O */ /* 80 */ VI_PASTE_PREV, /* P */ /* 81 */ ED_UNASSIGNED, /* Q */ /* 82 */ VI_REPLACE_MODE, /* R */ /* 83 */ VI_SUBSTITUTE_LINE, /* S */ /* 84 */ VI_TO_PREV_CHAR, /* T */ /* 85 */ VI_UNDO_LINE, /* U */ /* 86 */ ED_UNASSIGNED, /* V */ /* 87 */ VI_NEXT_BIG_WORD, /* W */ /* 88 */ ED_DELETE_PREV_CHAR, /* X */ /* 89 */ VI_YANK_END, /* Y */ /* 90 */ ED_UNASSIGNED, /* Z */ /* 91 */ ED_SEQUENCE_LEAD_IN, /* [ */ /* 92 */ ED_UNASSIGNED, /* \ */ /* 93 */ ED_UNASSIGNED, /* ] */ /* 94 */ ED_MOVE_TO_BEG, /* ^ */ /* 95 */ VI_HISTORY_WORD, /* _ */ /* 96 */ ED_UNASSIGNED, /* ` */ /* 97 */ VI_ADD, /* a */ /* 98 */ VI_PREV_WORD, /* b */ /* 99 */ VI_CHANGE_META, /* c */ /* 100 */ VI_DELETE_META, /* d */ /* 101 */ VI_END_WORD, /* e */ /* 102 */ VI_NEXT_CHAR, /* f */ /* 103 */ ED_UNASSIGNED, /* g */ /* 104 */ ED_PREV_CHAR, /* h */ /* 105 */ VI_INSERT, /* i */ /* 106 */ ED_NEXT_HISTORY, /* j */ /* 107 */ ED_PREV_HISTORY, /* k */ /* 108 */ ED_NEXT_CHAR, /* l */ /* 109 */ ED_UNASSIGNED, /* m */ /* 110 */ VI_REPEAT_SEARCH_NEXT, /* n */ /* 111 */ ED_UNASSIGNED, /* o */ /* 112 */ VI_PASTE_NEXT, /* p */ /* 113 */ ED_UNASSIGNED, /* q */ /* 114 */ VI_REPLACE_CHAR, /* r */ /* 115 */ VI_SUBSTITUTE_CHAR, /* s */ /* 116 */ VI_TO_NEXT_CHAR, /* t */ /* 117 */ VI_UNDO, /* u */ /* 118 */ VI_HISTEDIT, /* v */ /* 119 */ VI_NEXT_WORD, /* w */ /* 120 */ ED_DELETE_NEXT_CHAR, /* x */ /* 121 */ VI_YANK, /* y */ /* 122 */ ED_UNASSIGNED, /* z */ /* 123 */ ED_UNASSIGNED, /* { */ /* 124 */ VI_TO_COLUMN, /* | */ /* 125 */ ED_UNASSIGNED, /* } */ /* 126 */ VI_CHANGE_CASE, /* ~ */ /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_UNASSIGNED, /* M-^@ */ /* 129 */ ED_UNASSIGNED, /* M-^A */ /* 130 */ ED_UNASSIGNED, /* M-^B */ /* 131 */ ED_UNASSIGNED, /* M-^C */ /* 132 */ ED_UNASSIGNED, /* M-^D */ /* 133 */ ED_UNASSIGNED, /* M-^E */ /* 134 */ ED_UNASSIGNED, /* M-^F */ /* 135 */ ED_UNASSIGNED, /* M-^G */ /* 136 */ ED_UNASSIGNED, /* M-^H */ /* 137 */ ED_UNASSIGNED, /* M-^I */ /* 138 */ ED_UNASSIGNED, /* M-^J */ /* 139 */ ED_UNASSIGNED, /* M-^K */ /* 140 */ ED_UNASSIGNED, /* M-^L */ /* 141 */ ED_UNASSIGNED, /* M-^M */ /* 142 */ ED_UNASSIGNED, /* M-^N */ /* 143 */ ED_UNASSIGNED, /* M-^O */ /* 144 */ ED_UNASSIGNED, /* M-^P */ /* 145 */ ED_UNASSIGNED, /* M-^Q */ /* 146 */ ED_UNASSIGNED, /* M-^R */ /* 147 */ ED_UNASSIGNED, /* M-^S */ /* 148 */ ED_UNASSIGNED, /* M-^T */ /* 149 */ ED_UNASSIGNED, /* M-^U */ /* 150 */ ED_UNASSIGNED, /* M-^V */ /* 151 */ ED_UNASSIGNED, /* M-^W */ /* 152 */ ED_UNASSIGNED, /* M-^X */ /* 153 */ ED_UNASSIGNED, /* M-^Y */ /* 154 */ ED_UNASSIGNED, /* M-^Z */ /* 155 */ ED_UNASSIGNED, /* M-^[ */ /* 156 */ ED_UNASSIGNED, /* M-^\ */ /* 157 */ ED_UNASSIGNED, /* M-^] */ /* 158 */ ED_UNASSIGNED, /* M-^^ */ /* 159 */ ED_UNASSIGNED, /* M-^_ */ /* 160 */ ED_UNASSIGNED, /* M-SPACE */ /* 161 */ ED_UNASSIGNED, /* M-! */ /* 162 */ ED_UNASSIGNED, /* M-" */ /* 163 */ ED_UNASSIGNED, /* M-# */ /* 164 */ ED_UNASSIGNED, /* M-$ */ /* 165 */ ED_UNASSIGNED, /* M-% */ /* 166 */ ED_UNASSIGNED, /* M-& */ /* 167 */ ED_UNASSIGNED, /* M-' */ /* 168 */ ED_UNASSIGNED, /* M-( */ /* 169 */ ED_UNASSIGNED, /* M-) */ /* 170 */ ED_UNASSIGNED, /* M-* */ /* 171 */ ED_UNASSIGNED, /* M-+ */ /* 172 */ ED_UNASSIGNED, /* M-, */ /* 173 */ ED_UNASSIGNED, /* M-- */ /* 174 */ ED_UNASSIGNED, /* M-. */ /* 175 */ ED_UNASSIGNED, /* M-/ */ /* 176 */ ED_UNASSIGNED, /* M-0 */ /* 177 */ ED_UNASSIGNED, /* M-1 */ /* 178 */ ED_UNASSIGNED, /* M-2 */ /* 179 */ ED_UNASSIGNED, /* M-3 */ /* 180 */ ED_UNASSIGNED, /* M-4 */ /* 181 */ ED_UNASSIGNED, /* M-5 */ /* 182 */ ED_UNASSIGNED, /* M-6 */ /* 183 */ ED_UNASSIGNED, /* M-7 */ /* 184 */ ED_UNASSIGNED, /* M-8 */ /* 185 */ ED_UNASSIGNED, /* M-9 */ /* 186 */ ED_UNASSIGNED, /* M-: */ /* 187 */ ED_UNASSIGNED, /* M-; */ /* 188 */ ED_UNASSIGNED, /* M-< */ /* 189 */ ED_UNASSIGNED, /* M-= */ /* 190 */ ED_UNASSIGNED, /* M-> */ /* 191 */ ED_UNASSIGNED, /* M-? */ /* 192 */ ED_UNASSIGNED, /* M-@ */ /* 193 */ ED_UNASSIGNED, /* M-A */ /* 194 */ ED_UNASSIGNED, /* M-B */ /* 195 */ ED_UNASSIGNED, /* M-C */ /* 196 */ ED_UNASSIGNED, /* M-D */ /* 197 */ ED_UNASSIGNED, /* M-E */ /* 198 */ ED_UNASSIGNED, /* M-F */ /* 199 */ ED_UNASSIGNED, /* M-G */ /* 200 */ ED_UNASSIGNED, /* M-H */ /* 201 */ ED_UNASSIGNED, /* M-I */ /* 202 */ ED_UNASSIGNED, /* M-J */ /* 203 */ ED_UNASSIGNED, /* M-K */ /* 204 */ ED_UNASSIGNED, /* M-L */ /* 205 */ ED_UNASSIGNED, /* M-M */ /* 206 */ ED_UNASSIGNED, /* M-N */ /* 207 */ ED_SEQUENCE_LEAD_IN, /* M-O */ /* 208 */ ED_UNASSIGNED, /* M-P */ /* 209 */ ED_UNASSIGNED, /* M-Q */ /* 210 */ ED_UNASSIGNED, /* M-R */ /* 211 */ ED_UNASSIGNED, /* M-S */ /* 212 */ ED_UNASSIGNED, /* M-T */ /* 213 */ ED_UNASSIGNED, /* M-U */ /* 214 */ ED_UNASSIGNED, /* M-V */ /* 215 */ ED_UNASSIGNED, /* M-W */ /* 216 */ ED_UNASSIGNED, /* M-X */ /* 217 */ ED_UNASSIGNED, /* M-Y */ /* 218 */ ED_UNASSIGNED, /* M-Z */ /* 219 */ ED_SEQUENCE_LEAD_IN, /* M-[ */ /* 220 */ ED_UNASSIGNED, /* M-\ */ /* 221 */ ED_UNASSIGNED, /* M-] */ /* 222 */ ED_UNASSIGNED, /* M-^ */ /* 223 */ ED_UNASSIGNED, /* M-_ */ /* 224 */ ED_UNASSIGNED, /* M-` */ /* 225 */ ED_UNASSIGNED, /* M-a */ /* 226 */ ED_UNASSIGNED, /* M-b */ /* 227 */ ED_UNASSIGNED, /* M-c */ /* 228 */ ED_UNASSIGNED, /* M-d */ /* 229 */ ED_UNASSIGNED, /* M-e */ /* 230 */ ED_UNASSIGNED, /* M-f */ /* 231 */ ED_UNASSIGNED, /* M-g */ /* 232 */ ED_UNASSIGNED, /* M-h */ /* 233 */ ED_UNASSIGNED, /* M-i */ /* 234 */ ED_UNASSIGNED, /* M-j */ /* 235 */ ED_UNASSIGNED, /* M-k */ /* 236 */ ED_UNASSIGNED, /* M-l */ /* 237 */ ED_UNASSIGNED, /* M-m */ /* 238 */ ED_UNASSIGNED, /* M-n */ /* 239 */ ED_UNASSIGNED, /* M-o */ /* 240 */ ED_UNASSIGNED, /* M-p */ /* 241 */ ED_UNASSIGNED, /* M-q */ /* 242 */ ED_UNASSIGNED, /* M-r */ /* 243 */ ED_UNASSIGNED, /* M-s */ /* 244 */ ED_UNASSIGNED, /* M-t */ /* 245 */ ED_UNASSIGNED, /* M-u */ /* 246 */ ED_UNASSIGNED, /* M-v */ /* 247 */ ED_UNASSIGNED, /* M-w */ /* 248 */ ED_UNASSIGNED, /* M-x */ /* 249 */ ED_UNASSIGNED, /* M-y */ /* 250 */ ED_UNASSIGNED, /* M-z */ /* 251 */ ED_UNASSIGNED, /* M-{ */ /* 252 */ ED_UNASSIGNED, /* M-| */ /* 253 */ ED_UNASSIGNED, /* M-} */ /* 254 */ ED_UNASSIGNED, /* M-~ */ /* 255 */ ED_UNASSIGNED /* M-^? */ }; /* map_init(): * Initialize and allocate the maps */ protected int map_init(EditLine *el) { /* * Make sure those are correct before starting. */ #ifdef MAP_DEBUG if (sizeof(el_map_emacs) != N_KEYS * sizeof(el_action_t)) EL_ABORT((el->errfile, "Emacs map incorrect\n")); if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t)) EL_ABORT((el->errfile, "Vi command map incorrect\n")); if (sizeof(el_map_vi_insert) != N_KEYS * sizeof(el_action_t)) EL_ABORT((el->errfile, "Vi insert map incorrect\n")); #endif el->el_map.alt = el_malloc(sizeof(*el->el_map.alt) * N_KEYS); if (el->el_map.alt == NULL) return -1; el->el_map.key = el_malloc(sizeof(*el->el_map.key) * N_KEYS); if (el->el_map.key == NULL) return -1; el->el_map.emacs = el_map_emacs; el->el_map.vic = el_map_vi_command; el->el_map.vii = el_map_vi_insert; el->el_map.help = el_malloc(sizeof(*el->el_map.help) * EL_NUM_FCNS); if (el->el_map.help == NULL) return -1; (void) memcpy(el->el_map.help, help__get(), sizeof(*el->el_map.help) * EL_NUM_FCNS); el->el_map.func = el_malloc(sizeof(*el->el_map.func) * EL_NUM_FCNS); if (el->el_map.func == NULL) return -1; memcpy(el->el_map.func, func__get(), sizeof(*el->el_map.func) * EL_NUM_FCNS); el->el_map.nfunc = EL_NUM_FCNS; #ifdef VIDEFAULT map_init_vi(el); #else map_init_emacs(el); #endif /* VIDEFAULT */ return 0; } /* map_end(): * Free the space taken by the editor maps */ protected void map_end(EditLine *el) { el_free(el->el_map.alt); el->el_map.alt = NULL; el_free(el->el_map.key); el->el_map.key = NULL; el->el_map.emacs = NULL; el->el_map.vic = NULL; el->el_map.vii = NULL; el_free(el->el_map.help); el->el_map.help = NULL; el_free(el->el_map.func); el->el_map.func = NULL; } /* map_init_nls(): * Find all the printable keys and bind them to self insert */ private void map_init_nls(EditLine *el) { int i; el_action_t *map = el->el_map.key; for (i = 0200; i <= 0377; i++) if (Isprint(i)) map[i] = ED_INSERT; } /* map_init_meta(): * Bind all the meta keys to the appropriate ESC- sequence */ private void map_init_meta(EditLine *el) { Char buf[3]; int i; el_action_t *map = el->el_map.key; el_action_t *alt = el->el_map.alt; for (i = 0; i <= 0377 && map[i] != EM_META_NEXT; i++) continue; if (i > 0377) { for (i = 0; i <= 0377 && alt[i] != EM_META_NEXT; i++) continue; if (i > 0377) { i = 033; if (el->el_map.type == MAP_VI) map = alt; } else map = alt; } buf[0] = (Char) i; buf[2] = 0; for (i = 0200; i <= 0377; i++) switch (map[i]) { case ED_INSERT: case ED_UNASSIGNED: case ED_SEQUENCE_LEAD_IN: break; default: buf[1] = i & 0177; keymacro_add(el, buf, keymacro_map_cmd(el, (int) map[i]), XK_CMD); break; } map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; } /* map_init_vi(): * Initialize the vi bindings */ protected void map_init_vi(EditLine *el) { int i; el_action_t *key = el->el_map.key; el_action_t *alt = el->el_map.alt; const el_action_t *vii = el->el_map.vii; const el_action_t *vic = el->el_map.vic; el->el_map.type = MAP_VI; el->el_map.current = el->el_map.key; keymacro_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = vii[i]; alt[i] = vic[i]; } map_init_meta(el); map_init_nls(el); tty_bind_char(el, 1); terminal_bind_arrow(el); } /* map_init_emacs(): * Initialize the emacs bindings */ protected void map_init_emacs(EditLine *el) { int i; Char buf[3]; el_action_t *key = el->el_map.key; el_action_t *alt = el->el_map.alt; const el_action_t *emacs = el->el_map.emacs; el->el_map.type = MAP_EMACS; el->el_map.current = el->el_map.key; keymacro_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = emacs[i]; alt[i] = ED_UNASSIGNED; } map_init_meta(el); map_init_nls(el); buf[0] = CONTROL('X'); buf[1] = CONTROL('X'); buf[2] = 0; keymacro_add(el, buf, keymacro_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); tty_bind_char(el, 1); terminal_bind_arrow(el); } /* map_set_editor(): * Set the editor */ protected int map_set_editor(EditLine *el, Char *editor) { if (Strcmp(editor, STR("emacs")) == 0) { map_init_emacs(el); return 0; } if (Strcmp(editor, STR("vi")) == 0) { map_init_vi(el); return 0; } return -1; } /* map_get_editor(): * Retrieve the editor */ protected int map_get_editor(EditLine *el, const Char **editor) { if (editor == NULL) return -1; switch (el->el_map.type) { case MAP_EMACS: *editor = STR("emacs"); return 0; case MAP_VI: *editor = STR("vi"); return 0; } return -1; } /* map_print_key(): * Print the function description for 1 key */ private void map_print_key(EditLine *el, el_action_t *map, const Char *in) { char outbuf[EL_BUFSIZ]; el_bindings_t *bp, *ep; if (in[0] == '\0' || in[1] == '\0') { (void) keymacro__decode_str(in, outbuf, sizeof(outbuf), ""); ep = &el->el_map.help[el->el_map.nfunc]; for (bp = el->el_map.help; bp < ep; bp++) if (bp->func == map[(unsigned char) *in]) { (void) fprintf(el->el_outfile, "%s\t->\t" FSTR "\n", outbuf, bp->name); return; } } else keymacro_print(el, in); } /* map_print_some_keys(): * Print keys from first to last */ private void map_print_some_keys(EditLine *el, el_action_t *map, Int first, Int last) { el_bindings_t *bp, *ep; Char firstbuf[2], lastbuf[2]; char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ]; firstbuf[0] = first; firstbuf[1] = 0; lastbuf[0] = last; lastbuf[1] = 0; if (map[first] == ED_UNASSIGNED) { if (first == last) { (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "%-15s-> is undefined\n", unparsbuf); } return; } ep = &el->el_map.help[el->el_map.nfunc]; for (bp = el->el_map.help; bp < ep; bp++) { if (bp->func == map[first]) { if (first == last) { (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "%-15s-> " FSTR "\n", unparsbuf, bp->name); } else { (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) keymacro__decode_str(lastbuf, extrabuf, sizeof(extrabuf), STRQQ); (void) fprintf(el->el_outfile, "%-4s to %-7s-> " FSTR "\n", unparsbuf, extrabuf, bp->name); } return; } } #ifdef MAP_DEBUG if (map == el->el_map.key) { (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", unparsbuf); (void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n", first, el->el_map.key[first]); } else { (void) keymacro__decode_str(firstbuf, unparsbuf, sizeof(unparsbuf), STRQQ); (void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", unparsbuf); (void) fprintf(el->el_outfile, "el->el_map.alt[%d] == %d\n", first, el->el_map.alt[first]); } #endif EL_ABORT((el->el_errfile, "Error printing keys\n")); } /* map_print_all_keys(): * Print the function description for all keys. */ private void map_print_all_keys(EditLine *el) { int prev, i; (void) fprintf(el->el_outfile, "Standard key bindings\n"); prev = 0; for (i = 0; i < N_KEYS; i++) { if (el->el_map.key[prev] == el->el_map.key[i]) continue; map_print_some_keys(el, el->el_map.key, prev, i - 1); prev = i; } map_print_some_keys(el, el->el_map.key, prev, i - 1); (void) fprintf(el->el_outfile, "Alternative key bindings\n"); prev = 0; for (i = 0; i < N_KEYS; i++) { if (el->el_map.alt[prev] == el->el_map.alt[i]) continue; map_print_some_keys(el, el->el_map.alt, prev, i - 1); prev = i; } map_print_some_keys(el, el->el_map.alt, prev, i - 1); (void) fprintf(el->el_outfile, "Multi-character bindings\n"); keymacro_print(el, STR("")); (void) fprintf(el->el_outfile, "Arrow key bindings\n"); terminal_print_arrow(el, STR("")); } /* map_bind(): * Add/remove/change bindings */ protected int map_bind(EditLine *el, int argc, const Char **argv) { el_action_t *map; int ntype, rem; const Char *p; Char inbuf[EL_BUFSIZ]; Char outbuf[EL_BUFSIZ]; const Char *in = NULL; Char *out; el_bindings_t *bp, *ep; int cmd; int key; if (argv == NULL) return -1; map = el->el_map.key; ntype = XK_CMD; key = rem = 0; for (argc = 1; (p = argv[argc]) != NULL; argc++) if (p[0] == '-') switch (p[1]) { case 'a': map = el->el_map.alt; break; case 's': ntype = XK_STR; break; #ifdef notyet case 'c': ntype = XK_EXE; break; #endif case 'k': key = 1; break; case 'r': rem = 1; break; case 'v': map_init_vi(el); return 0; case 'e': map_init_emacs(el); return 0; case 'l': ep = &el->el_map.help[el->el_map.nfunc]; for (bp = el->el_map.help; bp < ep; bp++) (void) fprintf(el->el_outfile, "" FSTR "\n\t" FSTR "\n", bp->name, bp->description); return 0; default: (void) fprintf(el->el_errfile, - "" FSTR ": Invalid switch `%c'.\n", - argv[0], p[1]); + "" FSTR ": Invalid switch `" FCHAR "'.\n", + argv[0], (Int)p[1]); } else break; if (argv[argc] == NULL) { map_print_all_keys(el); return 0; } if (key) in = argv[argc++]; else if ((in = parse__string(inbuf, argv[argc++])) == NULL) { (void) fprintf(el->el_errfile, "" FSTR ": Invalid \\ or ^ in instring.\n", argv[0]); return -1; } if (rem) { if (key) { (void) terminal_clear_arrow(el, in); return -1; } if (in[1]) (void) keymacro_delete(el, in); else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) (void) keymacro_delete(el, in); else map[(unsigned char) *in] = ED_UNASSIGNED; return 0; } if (argv[argc] == NULL) { if (key) terminal_print_arrow(el, in); else map_print_key(el, map, in); return 0; } #ifdef notyet if (argv[argc + 1] != NULL) { bindkeymacro_usage(); return -1; } #endif switch (ntype) { case XK_STR: case XK_EXE: if ((out = parse__string(outbuf, argv[argc])) == NULL) { (void) fprintf(el->el_errfile, "" FSTR ": Invalid \\ or ^ in outstring.\n", argv[0]); return -1; } if (key) terminal_set_arrow(el, in, keymacro_map_str(el, out), ntype); else keymacro_add(el, in, keymacro_map_str(el, out), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; break; case XK_CMD: if ((cmd = parse_cmd(el, argv[argc])) == -1) { (void) fprintf(el->el_errfile, "" FSTR ": Invalid command `" FSTR "'.\n", argv[0], argv[argc]); return -1; } if (key) terminal_set_arrow(el, in, keymacro_map_cmd(el, cmd), ntype); else { if (in[1]) { keymacro_add(el, in, keymacro_map_cmd(el, cmd), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; } else { keymacro_clear(el, map, in); map[(unsigned char) *in] = (el_action_t)cmd; } } break; /* coverity[dead_error_begin] */ default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); break; } return 0; } /* map_addfunc(): * add a user defined function */ protected int map_addfunc(EditLine *el, const Char *name, const Char *help, el_func_t func) { void *p; size_t nf = el->el_map.nfunc + 1; if (name == NULL || help == NULL || func == NULL) return -1; if ((p = el_realloc(el->el_map.func, nf * sizeof(*el->el_map.func))) == NULL) return -1; el->el_map.func = p; if ((p = el_realloc(el->el_map.help, nf * sizeof(*el->el_map.help))) == NULL) return -1; el->el_map.help = p; nf = (size_t)el->el_map.nfunc; el->el_map.func[nf] = func; el->el_map.help[nf].name = name; el->el_map.help[nf].func = (int)nf; el->el_map.help[nf].description = help; el->el_map.nfunc++; return 0; } Index: head/lib/libedit/readline.c =================================================================== --- head/lib/libedit/readline.c (revision 283083) +++ head/lib/libedit/readline.c (revision 283084) @@ -1,2293 +1,2325 @@ -/* $NetBSD: readline.c,v 1.113 2014/10/18 08:33:23 snj Exp $ */ +/* $NetBSD: readline.c,v 1.115 2015/04/01 15:23:15 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jaromir Dolecek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.113 2014/10/18 08:33:23 snj Exp $"); +__RCSID("$NetBSD: readline.c,v 1.115 2015/04/01 15:23:15 christos Exp $"); #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "readline/readline.h" #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ #include "histedit.h" #include "filecomplete.h" void rl_prep_terminal(int); void rl_deprep_terminal(void); /* for rl_complete() */ #define TAB '\r' /* see comment at the #ifdef for sense of this */ /* #define GDB_411_HACK */ /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ const char *rl_library_version = "EditLine wrapper"; int rl_readline_version = RL_READLINE_VERSION; static char empty[] = { '\0' }; static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; char *rl_readline_name = empty; FILE *rl_instream = NULL; FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; VCPFunction *rl_linefunc = NULL; int rl_done = 0; VFunction *rl_event_hook = NULL; KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; /* * The following is not implemented; we always catch signals in the * libedit fashion: set handlers on entry to el_gets() and clear them * on the way out. This simplistic approach works for most cases; if * it does not work for your application, please let us know. */ int rl_catch_signals = 1; int rl_catch_sigwinch = 1; int history_base = 1; /* probably never subject to change */ int history_length = 0; int max_input_history = 0; char history_expansion_char = '!'; char history_subst_char = '^'; char *history_no_expand_chars = expand_chars; Function *history_inhibit_expansion_function = NULL; char *history_arg_extract(int start, int end, const char *str); int rl_inhibit_completion = 0; int rl_attempted_completion_over = 0; char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; char *rl_completer_quote_characters = NULL; Function *rl_completion_entry_function = NULL; char *(*rl_completion_word_break_hook)(void) = NULL; CPPFunction *rl_attempted_completion_function = NULL; Function *rl_pre_input_hook = NULL; Function *rl_startup1_hook = NULL; int (*rl_getc_function)(FILE *) = NULL; char *rl_terminal_name = NULL; int rl_already_prompted = 0; int rl_filename_completion_desired = 0; int rl_ignore_completion_duplicates = 0; int readline_echoing_p = 1; int _rl_print_completions_horizontally = 0; VFunction *rl_redisplay_function = NULL; Function *rl_startup_hook = NULL; VFunction *rl_completion_display_matches_hook = NULL; VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; KEYMAP_ENTRY_ARRAY emacs_meta_keymap; /* * The current prompt string. */ char *rl_prompt = NULL; /* * This is set to character indicating type of completion being done by * rl_complete_internal(); this is available for application completion * functions. */ int rl_completion_type = 0; /* * If more than this number of items results from query for possible * completions, we ask user if they are sure to really display the list. */ int rl_completion_query_items = 100; /* * List of characters which are word break characters, but should be left * in the parsed text when it is passed to the completion function. * Shell uses this to help determine what kind of completing to do. */ char *rl_special_prefixes = NULL; /* * This is the character appended to the completed words if at the end of * the line. Default is ' ' (a space). */ int rl_completion_append_character = ' '; /* stuff below is used internally by libedit for readline emulation */ static History *h = NULL; static EditLine *e = NULL; static Function *map[256]; static jmp_buf topbuf; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); static unsigned char _el_rl_tstp(EditLine *, int); static char *_get_prompt(EditLine *); static int _getc_function(EditLine *, char *); static HIST_ENTRY *_move_history(int); static int _history_expand_command(const char *, size_t, size_t, char **); static char *_rl_compat_sub(const char *, const char *, const char *, int); static int _rl_event_read_char(EditLine *, char *); static void _rl_update_pos(void); /* ARGSUSED */ static char * _get_prompt(EditLine *el __attribute__((__unused__))) { rl_already_prompted = 1; return rl_prompt; } /* * generic function for moving around history */ static HIST_ENTRY * _move_history(int op) { HistEvent ev; static HIST_ENTRY rl_he; if (history(h, &ev, op) != 0) return NULL; rl_he.line = ev.str; rl_he.data = NULL; return &rl_he; } /* * read one key from user defined input function */ static int /*ARGSUSED*/ _getc_function(EditLine *el __attribute__((__unused__)), char *c) { int i; i = (*rl_getc_function)(NULL); if (i == -1) return 0; *c = (char)i; return 1; } static void _resize_fun(EditLine *el, void *a) { const LineInfo *li; char **ap = a; li = el_line(el); /* a cheesy way to get rid of const cast. */ *ap = memchr(li->buffer, *li->buffer, (size_t)1); } static const char * _default_history_file(void) { struct passwd *p; static char *path; size_t len; if (path) return path; if ((p = getpwuid(getuid())) == NULL) return NULL; len = strlen(p->pw_dir) + sizeof("/.history"); if ((path = malloc(len)) == NULL) return NULL; (void)snprintf(path, len, "%s/.history", p->pw_dir); return path; } /* * READLINE compatibility stuff */ /* * Set the prompt */ int rl_set_prompt(const char *prompt) { char *p; if (!prompt) prompt = ""; if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0) return 0; if (rl_prompt) el_free(rl_prompt); rl_prompt = strdup(prompt); if (rl_prompt == NULL) return -1; while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) *p = RL_PROMPT_START_IGNORE; return 0; } /* * initialize rl compat stuff */ int rl_initialize(void) { HistEvent ev; int editmode = 1; struct termios t; if (e != NULL) el_end(e); if (h != NULL) history_end(h); if (!rl_instream) rl_instream = stdin; if (!rl_outstream) rl_outstream = stdout; /* * See if we don't really want to run the editor */ if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) editmode = 0; e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); if (!editmode) el_set(e, EL_EDITMODE, 0); h = history_init(); if (!e || !h) return -1; history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ history_length = 0; max_input_history = INT_MAX; el_set(e, EL_HIST, history, h); /* Setup resize function */ el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); /* setup getc function if valid */ if (rl_getc_function) el_set(e, EL_GETCFN, _getc_function); /* for proper prompt printing in readline() */ if (rl_set_prompt("") == -1) { history_end(h); el_end(e); return -1; } el_set(e, EL_PROMPT, _get_prompt, RL_PROMPT_START_IGNORE); el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ /* so this can be overridden */ el_set(e, EL_EDITOR, "emacs"); if (rl_terminal_name != NULL) el_set(e, EL_TERMINAL, rl_terminal_name); else el_get(e, EL_TERMINAL, &rl_terminal_name); /* * Word completion - this has to go AFTER rebinding keys * to emacs-style. */ el_set(e, EL_ADDFN, "rl_complete", "ReadLine compatible completion function", _el_rl_complete); el_set(e, EL_BIND, "^I", "rl_complete", NULL); /* * Send TSTP when ^Z is pressed. */ el_set(e, EL_ADDFN, "rl_tstp", "ReadLine compatible suspend function", _el_rl_tstp); el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); + /* + * Set some readline compatible key-bindings. + */ + el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL); + + /* + * Allow the use of Home/End keys. + */ + el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL); + el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL); + el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL); + el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL); + + /* + * Allow the use of the Delete/Insert keys. + */ + el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL); + el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL); + + /* + * Ctrl-left-arrow and Ctrl-right-arrow for word moving. + */ + el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); + el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL); + el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL); + el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); + /* read settings from configuration file */ el_source(e, NULL); /* * Unfortunately, some applications really do use rl_point * and rl_line_buffer directly. */ _resize_fun(e, &rl_line_buffer); _rl_update_pos(); if (rl_startup_hook) (*rl_startup_hook)(NULL, 0); return 0; } /* * read one line from input stream and return it, chomping * trailing newline (if there is any) */ char * readline(const char *p) { HistEvent ev; const char * volatile prompt = p; int count; const char *ret; char *buf; static int used_event_hook; if (e == NULL || h == NULL) rl_initialize(); rl_done = 0; (void)setjmp(topbuf); /* update prompt accordingly to what has been passed */ if (rl_set_prompt(prompt) == -1) return NULL; if (rl_pre_input_hook) (*rl_pre_input_hook)(NULL, 0); if (rl_event_hook && !(e->el_flags&NO_TTY)) { el_set(e, EL_GETCFN, _rl_event_read_char); used_event_hook = 1; } if (!rl_event_hook && used_event_hook) { el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); used_event_hook = 0; } rl_already_prompted = 0; /* get one line from input stream */ ret = el_gets(e, &count); if (ret && count > 0) { int lastidx; buf = strdup(ret); if (buf == NULL) return NULL; lastidx = count - 1; if (buf[lastidx] == '\n') buf[lastidx] = '\0'; } else buf = NULL; history(h, &ev, H_GETSIZE); history_length = ev.num; return buf; } /* * history functions */ /* * is normally called before application starts to use * history expansion functions */ void using_history(void) { if (h == NULL || e == NULL) rl_initialize(); } /* * substitute ``what'' with ``with'', returning resulting string; if * globally == 1, substitutes all occurrences of what, otherwise only the * first one */ static char * _rl_compat_sub(const char *str, const char *what, const char *with, int globally) { const char *s; char *r, *result; size_t len, with_len, what_len; len = strlen(str); with_len = strlen(with); what_len = strlen(what); /* calculate length we need for result */ s = str; while (*s) { if (*s == *what && !strncmp(s, what, what_len)) { len += with_len - what_len; if (!globally) break; s += what_len; } else s++; } r = result = el_malloc((len + 1) * sizeof(*r)); if (result == NULL) return NULL; s = str; while (*s) { if (*s == *what && !strncmp(s, what, what_len)) { (void)strncpy(r, with, with_len); r += with_len; s += what_len; if (!globally) { (void)strcpy(r, s); return result; } } else *r++ = *s++; } *r = '\0'; return result; } static char *last_search_pat; /* last !?pat[?] search pattern */ static char *last_search_match; /* last !?pat[?] that matched */ const char * get_history_event(const char *cmd, int *cindex, int qchar) { int idx, sign, sub, num, begin, ret; size_t len; char *pat; const char *rptr; HistEvent ev; idx = *cindex; if (cmd[idx++] != history_expansion_char) return NULL; /* find out which event to take */ if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') { if (history(h, &ev, H_FIRST) != 0) return NULL; *cindex = cmd[idx]? (idx + 1):idx; return ev.str; } sign = 0; if (cmd[idx] == '-') { sign = 1; idx++; } if ('0' <= cmd[idx] && cmd[idx] <= '9') { HIST_ENTRY *rl_he; num = 0; while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { num = num * 10 + cmd[idx] - '0'; idx++; } if (sign) num = history_length - num + 1; if (!(rl_he = history_get(num))) return NULL; *cindex = idx; return rl_he->line; } sub = 0; if (cmd[idx] == '?') { sub = 1; idx++; } begin = idx; while (cmd[idx]) { if (cmd[idx] == '\n') break; if (sub && cmd[idx] == '?') break; if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' || cmd[idx] == '\t' || cmd[idx] == qchar)) break; idx++; } len = (size_t)idx - (size_t)begin; if (sub && cmd[idx] == '?') idx++; if (sub && len == 0 && last_search_pat && *last_search_pat) pat = last_search_pat; else if (len == 0) return NULL; else { if ((pat = el_malloc((len + 1) * sizeof(*pat))) == NULL) return NULL; (void)strncpy(pat, cmd + begin, len); pat[len] = '\0'; } if (history(h, &ev, H_CURR) != 0) { if (pat != last_search_pat) el_free(pat); return NULL; } num = ev.num; if (sub) { if (pat != last_search_pat) { if (last_search_pat) el_free(last_search_pat); last_search_pat = pat; } ret = history_search(pat, -1); } else ret = history_search_prefix(pat, -1); if (ret == -1) { /* restore to end of list on failed search */ history(h, &ev, H_FIRST); (void)fprintf(rl_outstream, "%s: Event not found\n", pat); if (pat != last_search_pat) el_free(pat); return NULL; } if (sub && len) { if (last_search_match && last_search_match != pat) el_free(last_search_match); last_search_match = pat; } if (pat != last_search_pat) el_free(pat); if (history(h, &ev, H_CURR) != 0) return NULL; *cindex = idx; rptr = ev.str; /* roll back to original position */ (void)history(h, &ev, H_SET, num); return rptr; } /* * the real function doing history expansion - takes as argument command * to do and data upon which the command should be executed * does expansion the way I've understood readline documentation * * returns 0 if data was not modified, 1 if it was and 2 if the string * should be only printed and not executed; in case of error, * returns -1 and *result points to NULL * it's the caller's responsibility to free() the string returned in *result */ static int _history_expand_command(const char *command, size_t offs, size_t cmdlen, char **result) { char *tmp, *search = NULL, *aptr; const char *ptr, *cmd; static char *from = NULL, *to = NULL; int start, end, idx, has_mods = 0; int p_on = 0, g_on = 0; *result = NULL; aptr = NULL; ptr = NULL; /* First get event specifier */ idx = 0; if (strchr(":^*$", command[offs + 1])) { char str[4]; /* * "!:" is shorthand for "!!:". * "!^", "!*" and "!$" are shorthand for * "!!:^", "!!:*" and "!!:$" respectively. */ str[0] = str[1] = '!'; str[2] = '0'; ptr = get_history_event(str, &idx, 0); idx = (command[offs + 1] == ':')? 1:0; has_mods = 1; } else { if (command[offs + 1] == '#') { /* use command so far */ if ((aptr = el_malloc((offs + 1) * sizeof(*aptr))) == NULL) return -1; (void)strncpy(aptr, command, offs); aptr[offs] = '\0'; idx = 1; } else { int qchar; qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; ptr = get_history_event(command + offs, &idx, qchar); } has_mods = command[offs + (size_t)idx] == ':'; } if (ptr == NULL && aptr == NULL) return -1; if (!has_mods) { *result = strdup(aptr ? aptr : ptr); if (aptr) el_free(aptr); if (*result == NULL) return -1; return 1; } cmd = command + offs + idx + 1; /* Now parse any word designators */ if (*cmd == '%') /* last word matched by ?pat? */ tmp = strdup(last_search_match? last_search_match:""); else if (strchr("^*$-0123456789", *cmd)) { start = end = -1; if (*cmd == '^') start = end = 1, cmd++; else if (*cmd == '$') start = -1, cmd++; else if (*cmd == '*') start = 1, cmd++; else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { start = 0; while (*cmd && '0' <= *cmd && *cmd <= '9') start = start * 10 + *cmd++ - '0'; if (*cmd == '-') { if (isdigit((unsigned char) cmd[1])) { cmd++; end = 0; while (*cmd && '0' <= *cmd && *cmd <= '9') end = end * 10 + *cmd++ - '0'; } else if (cmd[1] == '$') { cmd += 2; end = -1; } else { cmd++; end = -2; } } else if (*cmd == '*') end = -1, cmd++; else end = start; } tmp = history_arg_extract(start, end, aptr? aptr:ptr); if (tmp == NULL) { (void)fprintf(rl_outstream, "%s: Bad word specifier", command + offs + idx); if (aptr) el_free(aptr); return -1; } } else tmp = strdup(aptr? aptr:ptr); if (aptr) el_free(aptr); if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) { *result = tmp; return 1; } for (; *cmd; cmd++) { if (*cmd == ':') continue; else if (*cmd == 'h') { /* remove trailing path */ if ((aptr = strrchr(tmp, '/')) != NULL) *aptr = '\0'; } else if (*cmd == 't') { /* remove leading path */ if ((aptr = strrchr(tmp, '/')) != NULL) { aptr = strdup(aptr + 1); el_free(tmp); tmp = aptr; } } else if (*cmd == 'r') { /* remove trailing suffix */ if ((aptr = strrchr(tmp, '.')) != NULL) *aptr = '\0'; } else if (*cmd == 'e') { /* remove all but suffix */ if ((aptr = strrchr(tmp, '.')) != NULL) { aptr = strdup(aptr); el_free(tmp); tmp = aptr; } } else if (*cmd == 'p') /* print only */ p_on = 1; else if (*cmd == 'g') g_on = 2; else if (*cmd == 's' || *cmd == '&') { char *what, *with, delim; size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) continue; else if (*cmd == 's') { delim = *(++cmd), cmd++; size = 16; what = el_realloc(from, size * sizeof(*what)); if (what == NULL) { el_free(from); el_free(tmp); return 0; } len = 0; for (; *cmd && *cmd != delim; cmd++) { if (*cmd == '\\' && cmd[1] == delim) cmd++; if (len >= size) { char *nwhat; nwhat = el_realloc(what, (size <<= 1) * sizeof(*nwhat)); if (nwhat == NULL) { el_free(what); el_free(tmp); return 0; } what = nwhat; } what[len++] = *cmd; } what[len] = '\0'; from = what; if (*what == '\0') { el_free(what); if (search) { from = strdup(search); if (from == NULL) { el_free(tmp); return 0; } } else { from = NULL; el_free(tmp); return -1; } } cmd++; /* shift after delim */ if (!*cmd) continue; size = 16; with = el_realloc(to, size * sizeof(*with)); if (with == NULL) { el_free(to); el_free(tmp); return -1; } len = 0; from_len = strlen(from); for (; *cmd && *cmd != delim; cmd++) { if (len + from_len + 1 >= size) { char *nwith; size += from_len + 1; nwith = el_realloc(with, size * sizeof(*nwith)); if (nwith == NULL) { el_free(with); el_free(tmp); return -1; } with = nwith; } if (*cmd == '&') { /* safe */ (void)strcpy(&with[len], from); len += from_len; continue; } if (*cmd == '\\' && (*(cmd + 1) == delim || *(cmd + 1) == '&')) cmd++; with[len++] = *cmd; } with[len] = '\0'; to = with; } aptr = _rl_compat_sub(tmp, from, to, g_on); if (aptr) { el_free(tmp); tmp = aptr; } g_on = 0; } } *result = tmp; return p_on? 2:1; } /* * csh-style history expansion */ int history_expand(char *str, char **output) { int ret = 0; size_t idx, i, size; char *tmp, *result; if (h == NULL || e == NULL) rl_initialize(); if (history_expansion_char == 0) { *output = strdup(str); return 0; } *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ *output = el_malloc((strlen(str) + 4 + 1) * sizeof(**output)); if (*output == NULL) return 0; (*output)[0] = (*output)[1] = history_expansion_char; (*output)[2] = ':'; (*output)[3] = 's'; (void)strcpy((*output) + 4, str); str = *output; } else { *output = strdup(str); if (*output == NULL) return 0; } #define ADD_STRING(what, len, fr) \ { \ if (idx + len + 1 > size) { \ char *nresult = el_realloc(result, \ (size += len + 1) * sizeof(*nresult)); \ if (nresult == NULL) { \ el_free(*output); \ if (/*CONSTCOND*/fr) \ el_free(tmp); \ return 0; \ } \ result = nresult; \ } \ (void)strncpy(&result[idx], what, len); \ idx += len; \ result[idx] = '\0'; \ } result = NULL; size = idx = 0; tmp = NULL; for (i = 0; str[i];) { int qchar, loop_again; size_t len, start, j; qchar = 0; loop_again = 1; start = j = i; loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { - (void)strcpy(&str[j], &str[j + 1]); + len = strlen(&str[j + 1]) + 1; + memmove(&str[j], &str[j + 1], len); continue; } if (!loop_again) { if (isspace((unsigned char) str[j]) || str[j] == qchar) break; } if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || (*history_inhibit_expansion_function)(str, (int)j) == 0)) break; } if (str[j] && loop_again) { i = j; qchar = (j > 0 && str[j - 1] == '"' )? '"':0; j++; if (str[j] == history_expansion_char) j++; loop_again = 0; goto loop; } len = i - start; ADD_STRING(&str[start], len, 0); if (str[i] == '\0' || str[i] != history_expansion_char) { len = j - i; ADD_STRING(&str[i], len, 0); if (start == 0) ret = 0; else ret = 1; break; } ret = _history_expand_command (str, i, (j - i), &tmp); if (ret > 0 && tmp) { len = strlen(tmp); ADD_STRING(tmp, len, 1); } if (tmp) { el_free(tmp); tmp = NULL; } i = j; } /* ret is 2 for "print only" option */ if (ret == 2) { add_history(result); #ifdef GDB_411_HACK /* gdb 4.11 has been shipped with readline, where */ /* history_expand() returned -1 when the line */ /* should not be executed; in readline 2.1+ */ /* it should return 2 in such a case */ ret = -1; #endif } el_free(*output); *output = result; return ret; } /* * Return a string consisting of arguments of "str" from "start" to "end". */ char * history_arg_extract(int start, int end, const char *str) { size_t i, len, max; char **arr, *result = NULL; arr = history_tokenize(str); if (!arr) return NULL; if (arr && *arr == NULL) goto out; for (max = 0; arr[max]; max++) continue; max--; if (start == '$') start = (int)max; if (end == '$') end = (int)max; if (end < 0) end = (int)max + end + 1; if (start < 0) start = end; if (start < 0 || end < 0 || (size_t)start > max || (size_t)end > max || start > end) goto out; for (i = (size_t)start, len = 0; i <= (size_t)end; i++) len += strlen(arr[i]) + 1; len++; result = el_malloc(len * sizeof(*result)); if (result == NULL) goto out; for (i = (size_t)start, len = 0; i <= (size_t)end; i++) { (void)strcpy(result + len, arr[i]); len += strlen(arr[i]); if (i < (size_t)end) result[len++] = ' '; } result[len] = '\0'; out: for (i = 0; arr[i]; i++) el_free(arr[i]); el_free(arr); return result; } /* * Parse the string into individual tokens, * similar to how shell would do it. */ char ** history_tokenize(const char *str) { int size = 1, idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; for (i = 0; str[i];) { while (isspace((unsigned char) str[i])) i++; start = i; for (; str[i];) { if (str[i] == '\\') { if (str[i+1] != '\0') i++; } else if (str[i] == delim) delim = '\0'; else if (!delim && (isspace((unsigned char) str[i]) || strchr("()<>;&|$", str[i]))) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; if (str[i]) i++; } if (idx + 2 >= size) { char **nresult; size <<= 1; nresult = el_realloc(result, (size_t)size * sizeof(*nresult)); if (nresult == NULL) { el_free(result); return NULL; } result = nresult; } len = (size_t)i - (size_t)start; temp = el_malloc((size_t)(len + 1) * sizeof(*temp)); if (temp == NULL) { for (i = 0; i < idx; i++) el_free(result[i]); el_free(result); return NULL; } (void)strncpy(temp, &str[start], len); temp[len] = '\0'; result[idx++] = temp; result[idx] = NULL; if (str[i]) i++; } return result; } /* * limit size of history record to ``max'' events */ void stifle_history(int max) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); if (history(h, &ev, H_SETSIZE, max) == 0) max_input_history = max; } /* * "unlimit" size of history - set the limit to maximum allowed int value */ int unstifle_history(void) { HistEvent ev; int omax; history(h, &ev, H_SETSIZE, INT_MAX); omax = max_input_history; max_input_history = INT_MAX; return omax; /* some value _must_ be returned */ } int history_is_stifled(void) { /* cannot return true answer */ return max_input_history != INT_MAX; } static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; int history_truncate_file (const char *filename, int nlines) { int ret = 0; FILE *fp, *tp; char template[sizeof(_history_tmp_template)]; char buf[4096]; int fd; char *cp; off_t off; int count = 0; ssize_t left = 0; if (filename == NULL && (filename = _default_history_file()) == NULL) return errno; if ((fp = fopen(filename, "r+")) == NULL) return errno; strcpy(template, _history_tmp_template); if ((fd = mkstemp(template)) == -1) { ret = errno; goto out1; } if ((tp = fdopen(fd, "r+")) == NULL) { close(fd); ret = errno; goto out2; } for(;;) { if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) { if (ferror(fp)) { ret = errno; break; } if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == (off_t)-1) { ret = errno; break; } left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp); if (ferror(fp)) { ret = errno; break; } if (left == 0) { count--; left = sizeof(buf); } else if (fwrite(buf, (size_t)left, (size_t)1, tp) != 1) { ret = errno; break; } fflush(tp); break; } if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) { ret = errno; break; } count++; } if (ret) goto out3; cp = buf + left - 1; if(*cp != '\n') cp++; for(;;) { while (--cp >= buf) { if (*cp == '\n') { if (--nlines == 0) { if (++cp >= buf + sizeof(buf)) { count++; cp = buf; } break; } } } if (nlines <= 0 || count == 0) break; count--; if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { ret = errno; break; } if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) { if (ferror(tp)) { ret = errno; break; } ret = EAGAIN; break; } cp = buf + sizeof(buf); } if (ret || nlines > 0) goto out3; if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) { ret = errno; goto out3; } if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == (off_t)-1) { ret = errno; goto out3; } for(;;) { if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) { if (ferror(fp)) ret = errno; break; } if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) { ret = errno; break; } } fflush(fp); if((off = ftello(fp)) > 0) (void)ftruncate(fileno(fp), off); out3: fclose(tp); out2: unlink(template); out1: fclose(fp); return ret; } /* * read history from a file given */ int read_history(const char *filename) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); if (filename == NULL && (filename = _default_history_file()) == NULL) return errno; return history(h, &ev, H_LOAD, filename) == -1 ? (errno ? errno : EINVAL) : 0; } /* * write history to a file given */ int write_history(const char *filename) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); if (filename == NULL && (filename = _default_history_file()) == NULL) return errno; return history(h, &ev, H_SAVE, filename) == -1 ? (errno ? errno : EINVAL) : 0; } /* * returns history ``num''th event * * returned pointer points to static variable */ HIST_ENTRY * history_get(int num) { static HIST_ENTRY she; HistEvent ev; int curr_num; if (h == NULL || e == NULL) rl_initialize(); /* save current position */ if (history(h, &ev, H_CURR) != 0) return NULL; curr_num = ev.num; /* start from the oldest */ if (history(h, &ev, H_LAST) != 0) return NULL; /* error */ /* look forwards for event matching specified offset */ if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) return NULL; she.line = ev.str; /* restore pointer to where it was */ (void)history(h, &ev, H_SET, curr_num); return &she; } /* * add the line to history table */ int add_history(const char *line) { HistEvent ev; if (line == NULL) return 0; if (h == NULL || e == NULL) rl_initialize(); (void)history(h, &ev, H_ENTER, line); if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; return !(history_length > 0); /* return 0 if all is okay */ } /* * remove the specified entry from the history list and return it. */ HIST_ENTRY * remove_history(int num) { HIST_ENTRY *he; HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); if ((he = el_malloc(sizeof(*he))) == NULL) return NULL; if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { el_free(he); return NULL; } he->line = ev.str; if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; return he; } /* * replace the line and data of the num-th entry */ HIST_ENTRY * replace_history_entry(int num, const char *line, histdata_t data) { HIST_ENTRY *he; HistEvent ev; int curr_num; if (h == NULL || e == NULL) rl_initialize(); /* save current position */ if (history(h, &ev, H_CURR) != 0) return NULL; curr_num = ev.num; /* start from the oldest */ if (history(h, &ev, H_LAST) != 0) return NULL; /* error */ if ((he = el_malloc(sizeof(*he))) == NULL) return NULL; /* look forwards for event matching specified offset */ if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) goto out; he->line = strdup(ev.str); if (he->line == NULL) goto out; if (history(h, &ev, H_REPLACE, line, data)) goto out; /* restore pointer to where it was */ if (history(h, &ev, H_SET, curr_num)) goto out; return he; out: el_free(he); return NULL; } /* * clear the history list - delete all entries */ void clear_history(void) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); (void)history(h, &ev, H_CLEAR); history_length = 0; } /* * returns offset of the current history event */ int where_history(void) { HistEvent ev; int curr_num, off; if (history(h, &ev, H_CURR) != 0) return 0; curr_num = ev.num; (void)history(h, &ev, H_FIRST); off = 1; while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) off++; return off; } /* * returns current history event or NULL if there is no such event */ HIST_ENTRY * current_history(void) { return _move_history(H_CURR); } /* * returns total number of bytes history events' data are using */ int history_total_bytes(void) { HistEvent ev; int curr_num; size_t size; if (history(h, &ev, H_CURR) != 0) return -1; curr_num = ev.num; (void)history(h, &ev, H_FIRST); size = 0; do size += strlen(ev.str) * sizeof(*ev.str); while (history(h, &ev, H_NEXT) == 0); /* get to the same position as before */ history(h, &ev, H_PREV_EVENT, curr_num); return (int)size; } /* * sets the position in the history list to ``pos'' */ int history_set_pos(int pos) { HistEvent ev; int curr_num; if (pos >= history_length || pos < 0) return -1; (void)history(h, &ev, H_CURR); curr_num = ev.num; /* * use H_DELDATA to set to nth history (without delete) by passing * (void **)-1 */ if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { (void)history(h, &ev, H_SET, curr_num); return -1; } return 0; } /* * returns previous event in history and shifts pointer accordingly */ HIST_ENTRY * previous_history(void) { return _move_history(H_PREV); } /* * returns next event in history and shifts pointer accordingly */ HIST_ENTRY * next_history(void) { return _move_history(H_NEXT); } /* * searches for first history event containing the str */ int history_search(const char *str, int direction) { HistEvent ev; const char *strp; int curr_num; if (history(h, &ev, H_CURR) != 0) return -1; curr_num = ev.num; for (;;) { if ((strp = strstr(ev.str, str)) != NULL) return (int)(strp - ev.str); if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } (void)history(h, &ev, H_SET, curr_num); return -1; } /* * searches for first history event beginning with str */ int history_search_prefix(const char *str, int direction) { HistEvent ev; return (history(h, &ev, direction < 0 ? H_PREV_STR : H_NEXT_STR, str)); } /* * search for event in history containing str, starting at offset * abs(pos); continue backward, if pos<0, forward otherwise */ /* ARGSUSED */ int history_search_pos(const char *str, int direction __attribute__((__unused__)), int pos) { HistEvent ev; int curr_num, off; off = (pos > 0) ? pos : -pos; pos = (pos > 0) ? 1 : -1; if (history(h, &ev, H_CURR) != 0) return -1; curr_num = ev.num; if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) return -1; for (;;) { if (strstr(ev.str, str)) return off; if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) break; } /* set "current" pointer back to previous state */ (void)history(h, &ev, pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); return -1; } /********************************/ /* completion functions */ char * tilde_expand(char *name) { return fn_tilde_expand(name); } char * filename_completion_function(const char *name, int state) { return fn_filename_completion_function(name, state); } /* * a completion generator for usernames; returns _first_ username * which starts with supplied text * text contains a partial username preceded by random character * (usually '~'); state resets search from start (??? should we do that anyway) * it's the caller's responsibility to free the returned value */ char * username_completion_function(const char *text, int state) { #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) struct passwd pwres; char pwbuf[1024]; #endif struct passwd *pass = NULL; if (text[0] == '\0') return NULL; if (*text == '~') text++; if (state == 0) setpwent(); while ( #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL #else (pass = getpwent()) != NULL #endif && text[0] == pass->pw_name[0] && strcmp(text, pass->pw_name) == 0) continue; if (pass == NULL) { endpwent(); return NULL; } return strdup(pass->pw_name); } /* * el-compatible wrapper to send TSTP on ^Z */ /* ARGSUSED */ static unsigned char _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) { (void)kill(0, SIGTSTP); return CC_NORM; } /* * Display list of strings in columnar format on readline's output stream. * 'matches' is list of strings, 'len' is number of strings in 'matches', * 'max' is maximum length of string in 'matches'. */ void rl_display_match_list(char **matches, int len, int max) { fn_display_match_list(e, matches, (size_t)len, (size_t)max); } static const char * /*ARGSUSED*/ _rl_completion_append_character_function(const char *dummy __attribute__((__unused__))) { static char buf[2]; buf[0] = (char)rl_completion_append_character; buf[1] = '\0'; return buf; } /* * complete word at current point */ /* ARGSUSED */ int rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { #ifdef WIDECHAR static ct_buffer_t wbreak_conv, sprefix_conv; #endif char *breakchars; if (h == NULL || e == NULL) rl_initialize(); if (rl_inhibit_completion) { char arr[2]; arr[0] = (char)invoking_key; arr[1] = '\0'; el_insertstr(e, arr); return CC_REFRESH; } if (rl_completion_word_break_hook != NULL) breakchars = (*rl_completion_word_break_hook)(); else breakchars = rl_basic_word_break_characters; /* Just look at how many global variables modify this operation! */ return fn_complete(e, (CPFunction *)rl_completion_entry_function, rl_attempted_completion_function, ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), ct_decode_string(breakchars, &sprefix_conv), _rl_completion_append_character_function, (size_t)rl_completion_query_items, &rl_completion_type, &rl_attempted_completion_over, &rl_point, &rl_end, NULL, NULL, NULL); } /* ARGSUSED */ static unsigned char _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) { return (unsigned char)rl_complete(0, ch); } /* * misc other functions */ /* * bind key c to readline-type function func */ int rl_bind_key(int c, rl_command_func_t *func) { int retval = -1; if (h == NULL || e == NULL) rl_initialize(); if (func == rl_insert) { /* XXX notice there is no range checking of ``c'' */ e->el_map.key[c] = ED_INSERT; retval = 0; } return retval; } /* * read one key from input - handles chars pushed back * to input stream also */ int rl_read_key(void) { char fooarr[2 * sizeof(int)]; if (e == NULL || h == NULL) rl_initialize(); return el_getc(e, fooarr); } /* * reset the terminal */ /* ARGSUSED */ void rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) rl_initialize(); el_reset(e); } /* * insert character ``c'' back into input stream, ``count'' times */ int rl_insert(int count, int c) { char arr[2]; if (h == NULL || e == NULL) rl_initialize(); /* XXX - int -> char conversion can lose on multichars */ arr[0] = (char)c; arr[1] = '\0'; for (; count > 0; count--) el_push(e, arr); return 0; } int rl_insert_text(const char *text) { if (!text || *text == 0) return 0; if (h == NULL || e == NULL) rl_initialize(); if (el_insertstr(e, text) < 0) return 0; return (int)strlen(text); } /*ARGSUSED*/ int rl_newline(int count __attribute__((__unused__)), int c __attribute__((__unused__))) { /* * Readline-4.0 appears to ignore the args. */ return rl_insert(1, '\n'); } /*ARGSUSED*/ static unsigned char rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c) { if (map[c] == NULL) return CC_ERROR; _rl_update_pos(); (*map[c])(NULL, c); /* If rl_done was set by the above call, deal with it here */ if (rl_done) return CC_EOF; return CC_NORM; } int rl_add_defun(const char *name, Function *fun, int c) { char dest[8]; if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0) return -1; map[(unsigned char)c] = fun; el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); el_set(e, EL_BIND, dest, name, NULL); return 0; } void rl_callback_read_char(void) { int count = 0, done = 0; const char *buf = el_gets(e, &count); char *wbuf; if (buf == NULL || count-- <= 0) return; if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF]) done = 1; if (buf[count] == '\n' || buf[count] == '\r') done = 2; if (done && rl_linefunc != NULL) { el_set(e, EL_UNBUFFERED, 0); if (done == 2) { if ((wbuf = strdup(buf)) != NULL) wbuf[count] = '\0'; } else wbuf = NULL; (*(void (*)(const char *))rl_linefunc)(wbuf); el_set(e, EL_UNBUFFERED, 1); } } void rl_callback_handler_install(const char *prompt, VCPFunction *linefunc) { if (e == NULL) { rl_initialize(); } (void)rl_set_prompt(prompt); rl_linefunc = linefunc; el_set(e, EL_UNBUFFERED, 1); } void rl_callback_handler_remove(void) { el_set(e, EL_UNBUFFERED, 0); rl_linefunc = NULL; } void rl_redisplay(void) { char a[2]; a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT]; a[1] = '\0'; el_push(e, a); } int rl_get_previous_history(int count, int key) { char a[2]; a[0] = (char)key; a[1] = '\0'; while (count--) el_push(e, a); return 0; } void /*ARGSUSED*/ rl_prep_terminal(int meta_flag __attribute__((__unused__))) { el_set(e, EL_PREP_TERM, 1); } void rl_deprep_terminal(void) { el_set(e, EL_PREP_TERM, 0); } int rl_read_init_file(const char *s) { return el_source(e, s); } int rl_parse_and_bind(const char *line) { const char **argv; int argc; Tokenizer *tok; tok = tok_init(NULL); tok_str(tok, line, &argc, &argv); argc = el_parse(e, argc, argv); tok_end(tok); return argc ? 1 : 0; } int rl_variable_bind(const char *var, const char *value) { /* * The proper return value is undocument, but this is what the * readline source seems to do. */ return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0; } void rl_stuff_char(int c) { char buf[2]; buf[0] = (char)c; buf[1] = '\0'; el_insertstr(e, buf); } static int _rl_event_read_char(EditLine *el, char *cp) { int n; ssize_t num_read = 0; *cp = '\0'; while (rl_event_hook) { (*rl_event_hook)(); #if defined(FIONREAD) if (ioctl(el->el_infd, FIONREAD, &n) < 0) return -1; if (n) num_read = read(el->el_infd, cp, (size_t)1); else num_read = 0; #elif defined(F_SETFL) && defined(O_NDELAY) if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) return -1; if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) return -1; num_read = read(el->el_infd, cp, 1); if (fcntl(el->el_infd, F_SETFL, n)) return -1; #else /* not non-blocking, but what you gonna do? */ num_read = read(el->el_infd, cp, 1); return -1; #endif if (num_read < 0 && errno == EAGAIN) continue; if (num_read == 0) continue; break; } if (!rl_event_hook) el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); return (int)num_read; } static void _rl_update_pos(void) { const LineInfo *li = el_line(e); rl_point = (int)(li->cursor - li->buffer); rl_end = (int)(li->lastchar - li->buffer); } void rl_get_screen_size(int *rows, int *cols) { if (rows) el_get(e, EL_GETTC, "li", rows, (void *)0); if (cols) el_get(e, EL_GETTC, "co", cols, (void *)0); } void rl_set_screen_size(int rows, int cols) { char buf[64]; (void)snprintf(buf, sizeof(buf), "%d", rows); el_set(e, EL_SETTC, "li", buf, NULL); (void)snprintf(buf, sizeof(buf), "%d", cols); el_set(e, EL_SETTC, "co", buf, NULL); } char ** rl_completion_matches(const char *str, rl_compentry_func_t *fun) { size_t len, max, i, j, min; char **list, *match, *a, *b; len = 1; max = 10; if ((list = el_malloc(max * sizeof(*list))) == NULL) return NULL; while ((match = (*fun)(str, (int)(len - 1))) != NULL) { list[len++] = match; if (len == max) { char **nl; max += 10; if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL) goto out; list = nl; } } if (len == 1) goto out; list[len] = NULL; if (len == 2) { if ((list[0] = strdup(list[1])) == NULL) goto out; return list; } qsort(&list[1], len - 1, sizeof(*list), (int (*)(const void *, const void *)) strcmp); min = SIZE_T_MAX; for (i = 1, a = list[i]; i < len - 1; i++, a = b) { b = list[i + 1]; for (j = 0; a[j] && a[j] == b[j]; j++) continue; if (min > j) min = j; } if (min == 0 && *str) { if ((list[0] = strdup(str)) == NULL) goto out; } else { if ((list[0] = el_malloc((min + 1) * sizeof(*list[0]))) == NULL) goto out; (void)memcpy(list[0], list[1], min); list[0][min] = '\0'; } return list; out: el_free(list); return NULL; } char * rl_filename_completion_function (const char *text, int state) { return fn_filename_completion_function(text, state); } void rl_forced_update_display(void) { el_set(e, EL_REFRESH); } int _rl_abort_internal(void) { el_beep(e); longjmp(topbuf, 1); /*NOTREACHED*/ } int _rl_qsort_string_compare(char **s1, char **s2) { return strcoll(*s1, *s2); } HISTORY_STATE * history_get_history_state(void) { HISTORY_STATE *hs; if ((hs = el_malloc(sizeof(*hs))) == NULL) return NULL; hs->length = history_length; return hs; } int /*ARGSUSED*/ rl_kill_text(int from __attribute__((__unused__)), int to __attribute__((__unused__))) { return 0; } Keymap rl_make_bare_keymap(void) { return NULL; } Keymap rl_get_keymap(void) { return NULL; } void /*ARGSUSED*/ rl_set_keymap(Keymap k __attribute__((__unused__))) { } int /*ARGSUSED*/ rl_generic_bind(int type __attribute__((__unused__)), const char * keyseq __attribute__((__unused__)), const char * data __attribute__((__unused__)), Keymap k __attribute__((__unused__))) { return 0; } int /*ARGSUSED*/ rl_bind_key_in_map(int key __attribute__((__unused__)), rl_command_func_t *fun __attribute__((__unused__)), Keymap k __attribute__((__unused__))) { return 0; } /* unsupported, but needed by python */ void rl_cleanup_after_signal(void) { } int rl_on_new_line(void) { return 0; } void rl_free_line_state(void) { } Index: head/lib/libedit/tty.c =================================================================== --- head/lib/libedit/tty.c (revision 283083) +++ head/lib/libedit/tty.c (revision 283084) @@ -1,1327 +1,1327 @@ -/* $NetBSD: tty.c,v 1.46 2014/06/18 18:52:49 christos Exp $ */ +/* $NetBSD: tty.c,v 1.47 2015/05/14 10:44:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Christos Zoulas of Cornell University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: tty.c,v 1.46 2014/06/18 18:52:49 christos Exp $"); +__RCSID("$NetBSD: tty.c,v 1.47 2015/05/14 10:44:15 christos Exp $"); #endif #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); /* * tty.c: tty interface stuff */ #include #include #include /* for isatty */ #include /* for ffs */ #include /* for abort */ #include "el.h" #include "tty.h" typedef struct ttymodes_t { const char *m_name; unsigned int m_value; int m_type; } ttymodes_t; typedef struct ttymap_t { Int nch, och; /* Internal and termio rep of chars */ el_action_t bind[3]; /* emacs, vi, and vi-cmd */ } ttymap_t; private const ttyperm_t ttyperm = { { {"iflag:", ICRNL, (INLCR | IGNCR)}, {"oflag:", (OPOST | ONLCR), ONLRET}, {"cflag:", 0, 0}, {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN), (NOFLSH | ECHONL | EXTPROC | FLUSHO)}, {"chars:", 0, 0}, }, { {"iflag:", (INLCR | ICRNL), IGNCR}, {"oflag:", (OPOST | ONLCR), ONLRET}, {"cflag:", 0, 0}, {"lflag:", ISIG, (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)}, {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) | C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) | C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0} }, { {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL}, {"oflag:", 0, 0}, {"cflag:", 0, 0}, {"lflag:", 0, ISIG | IEXTEN}, {"chars:", 0, 0}, } }; private const ttychar_t ttychar = { { CINTR, CQUIT, CERASE, CKILL, CEOF, CEOL, CEOL2, CSWTCH, CDSWTCH, CERASE2, CSTART, CSTOP, CWERASE, CSUSP, CDSUSP, CREPRINT, CDISCARD, CLNEXT, CSTATUS, CPAGE, CPGOFF, CKILL2, CBRK, CMIN, CTIME }, { CINTR, CQUIT, CERASE, CKILL, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, CERASE2, CSTART, CSTOP, _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE, CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; private const ttymap_t tty_map[] = { #ifdef VERASE {C_ERASE, VERASE, {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE */ #ifdef VERASE2 {C_ERASE2, VERASE2, {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE2 */ #ifdef VKILL {C_KILL, VKILL, {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, #endif /* VKILL */ #ifdef VKILL2 {C_KILL2, VKILL2, {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, #endif /* VKILL2 */ #ifdef VEOF {C_EOF, VEOF, {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}}, #endif /* VEOF */ #ifdef VWERASE {C_WERASE, VWERASE, {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}}, #endif /* VWERASE */ #ifdef VREPRINT {C_REPRINT, VREPRINT, {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}}, #endif /* VREPRINT */ #ifdef VLNEXT {C_LNEXT, VLNEXT, {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}}, #endif /* VLNEXT */ {(Int)-1, (Int)-1, {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} }; private const ttymodes_t ttymodes[] = { #ifdef IGNBRK {"ignbrk", IGNBRK, MD_INP}, #endif /* IGNBRK */ #ifdef BRKINT {"brkint", BRKINT, MD_INP}, #endif /* BRKINT */ #ifdef IGNPAR {"ignpar", IGNPAR, MD_INP}, #endif /* IGNPAR */ #ifdef PARMRK {"parmrk", PARMRK, MD_INP}, #endif /* PARMRK */ #ifdef INPCK {"inpck", INPCK, MD_INP}, #endif /* INPCK */ #ifdef ISTRIP {"istrip", ISTRIP, MD_INP}, #endif /* ISTRIP */ #ifdef INLCR {"inlcr", INLCR, MD_INP}, #endif /* INLCR */ #ifdef IGNCR {"igncr", IGNCR, MD_INP}, #endif /* IGNCR */ #ifdef ICRNL {"icrnl", ICRNL, MD_INP}, #endif /* ICRNL */ #ifdef IUCLC {"iuclc", IUCLC, MD_INP}, #endif /* IUCLC */ #ifdef IXON {"ixon", IXON, MD_INP}, #endif /* IXON */ #ifdef IXANY {"ixany", IXANY, MD_INP}, #endif /* IXANY */ #ifdef IXOFF {"ixoff", IXOFF, MD_INP}, #endif /* IXOFF */ #ifdef IMAXBEL {"imaxbel", IMAXBEL, MD_INP}, #endif /* IMAXBEL */ #ifdef OPOST {"opost", OPOST, MD_OUT}, #endif /* OPOST */ #ifdef OLCUC {"olcuc", OLCUC, MD_OUT}, #endif /* OLCUC */ #ifdef ONLCR {"onlcr", ONLCR, MD_OUT}, #endif /* ONLCR */ #ifdef OCRNL {"ocrnl", OCRNL, MD_OUT}, #endif /* OCRNL */ #ifdef ONOCR {"onocr", ONOCR, MD_OUT}, #endif /* ONOCR */ #ifdef ONOEOT {"onoeot", ONOEOT, MD_OUT}, #endif /* ONOEOT */ #ifdef ONLRET {"onlret", ONLRET, MD_OUT}, #endif /* ONLRET */ #ifdef OFILL {"ofill", OFILL, MD_OUT}, #endif /* OFILL */ #ifdef OFDEL {"ofdel", OFDEL, MD_OUT}, #endif /* OFDEL */ #ifdef NLDLY {"nldly", NLDLY, MD_OUT}, #endif /* NLDLY */ #ifdef CRDLY {"crdly", CRDLY, MD_OUT}, #endif /* CRDLY */ #ifdef TABDLY {"tabdly", TABDLY, MD_OUT}, #endif /* TABDLY */ #ifdef XTABS {"xtabs", XTABS, MD_OUT}, #endif /* XTABS */ #ifdef BSDLY {"bsdly", BSDLY, MD_OUT}, #endif /* BSDLY */ #ifdef VTDLY {"vtdly", VTDLY, MD_OUT}, #endif /* VTDLY */ #ifdef FFDLY {"ffdly", FFDLY, MD_OUT}, #endif /* FFDLY */ #ifdef PAGEOUT {"pageout", PAGEOUT, MD_OUT}, #endif /* PAGEOUT */ #ifdef WRAP {"wrap", WRAP, MD_OUT}, #endif /* WRAP */ #ifdef CIGNORE {"cignore", CIGNORE, MD_CTL}, #endif /* CBAUD */ #ifdef CBAUD {"cbaud", CBAUD, MD_CTL}, #endif /* CBAUD */ #ifdef CSTOPB {"cstopb", CSTOPB, MD_CTL}, #endif /* CSTOPB */ #ifdef CREAD {"cread", CREAD, MD_CTL}, #endif /* CREAD */ #ifdef PARENB {"parenb", PARENB, MD_CTL}, #endif /* PARENB */ #ifdef PARODD {"parodd", PARODD, MD_CTL}, #endif /* PARODD */ #ifdef HUPCL {"hupcl", HUPCL, MD_CTL}, #endif /* HUPCL */ #ifdef CLOCAL {"clocal", CLOCAL, MD_CTL}, #endif /* CLOCAL */ #ifdef LOBLK {"loblk", LOBLK, MD_CTL}, #endif /* LOBLK */ #ifdef CIBAUD {"cibaud", CIBAUD, MD_CTL}, #endif /* CIBAUD */ #ifdef CRTSCTS #ifdef CCTS_OFLOW {"ccts_oflow", CCTS_OFLOW, MD_CTL}, #else {"crtscts", CRTSCTS, MD_CTL}, #endif /* CCTS_OFLOW */ #endif /* CRTSCTS */ #ifdef CRTS_IFLOW {"crts_iflow", CRTS_IFLOW, MD_CTL}, #endif /* CRTS_IFLOW */ #ifdef CDTRCTS {"cdtrcts", CDTRCTS, MD_CTL}, #endif /* CDTRCTS */ #ifdef MDMBUF {"mdmbuf", MDMBUF, MD_CTL}, #endif /* MDMBUF */ #ifdef RCV1EN {"rcv1en", RCV1EN, MD_CTL}, #endif /* RCV1EN */ #ifdef XMT1EN {"xmt1en", XMT1EN, MD_CTL}, #endif /* XMT1EN */ #ifdef ISIG {"isig", ISIG, MD_LIN}, #endif /* ISIG */ #ifdef ICANON {"icanon", ICANON, MD_LIN}, #endif /* ICANON */ #ifdef XCASE {"xcase", XCASE, MD_LIN}, #endif /* XCASE */ #ifdef ECHO {"echo", ECHO, MD_LIN}, #endif /* ECHO */ #ifdef ECHOE {"echoe", ECHOE, MD_LIN}, #endif /* ECHOE */ #ifdef ECHOK {"echok", ECHOK, MD_LIN}, #endif /* ECHOK */ #ifdef ECHONL {"echonl", ECHONL, MD_LIN}, #endif /* ECHONL */ #ifdef NOFLSH {"noflsh", NOFLSH, MD_LIN}, #endif /* NOFLSH */ #ifdef TOSTOP {"tostop", TOSTOP, MD_LIN}, #endif /* TOSTOP */ #ifdef ECHOCTL {"echoctl", ECHOCTL, MD_LIN}, #endif /* ECHOCTL */ #ifdef ECHOPRT {"echoprt", ECHOPRT, MD_LIN}, #endif /* ECHOPRT */ #ifdef ECHOKE {"echoke", ECHOKE, MD_LIN}, #endif /* ECHOKE */ #ifdef DEFECHO {"defecho", DEFECHO, MD_LIN}, #endif /* DEFECHO */ #ifdef FLUSHO {"flusho", FLUSHO, MD_LIN}, #endif /* FLUSHO */ #ifdef PENDIN {"pendin", PENDIN, MD_LIN}, #endif /* PENDIN */ #ifdef IEXTEN {"iexten", IEXTEN, MD_LIN}, #endif /* IEXTEN */ #ifdef NOKERNINFO {"nokerninfo", NOKERNINFO, MD_LIN}, #endif /* NOKERNINFO */ #ifdef ALTWERASE {"altwerase", ALTWERASE, MD_LIN}, #endif /* ALTWERASE */ #ifdef EXTPROC {"extproc", EXTPROC, MD_LIN}, #endif /* EXTPROC */ #if defined(VINTR) {"intr", C_SH(C_INTR), MD_CHAR}, #endif /* VINTR */ #if defined(VQUIT) {"quit", C_SH(C_QUIT), MD_CHAR}, #endif /* VQUIT */ #if defined(VERASE) {"erase", C_SH(C_ERASE), MD_CHAR}, #endif /* VERASE */ #if defined(VKILL) {"kill", C_SH(C_KILL), MD_CHAR}, #endif /* VKILL */ #if defined(VEOF) {"eof", C_SH(C_EOF), MD_CHAR}, #endif /* VEOF */ #if defined(VEOL) {"eol", C_SH(C_EOL), MD_CHAR}, #endif /* VEOL */ #if defined(VEOL2) {"eol2", C_SH(C_EOL2), MD_CHAR}, #endif /* VEOL2 */ #if defined(VSWTCH) {"swtch", C_SH(C_SWTCH), MD_CHAR}, #endif /* VSWTCH */ #if defined(VDSWTCH) {"dswtch", C_SH(C_DSWTCH), MD_CHAR}, #endif /* VDSWTCH */ #if defined(VERASE2) {"erase2", C_SH(C_ERASE2), MD_CHAR}, #endif /* VERASE2 */ #if defined(VSTART) {"start", C_SH(C_START), MD_CHAR}, #endif /* VSTART */ #if defined(VSTOP) {"stop", C_SH(C_STOP), MD_CHAR}, #endif /* VSTOP */ #if defined(VWERASE) {"werase", C_SH(C_WERASE), MD_CHAR}, #endif /* VWERASE */ #if defined(VSUSP) {"susp", C_SH(C_SUSP), MD_CHAR}, #endif /* VSUSP */ #if defined(VDSUSP) {"dsusp", C_SH(C_DSUSP), MD_CHAR}, #endif /* VDSUSP */ #if defined(VREPRINT) {"reprint", C_SH(C_REPRINT), MD_CHAR}, #endif /* VREPRINT */ #if defined(VDISCARD) {"discard", C_SH(C_DISCARD), MD_CHAR}, #endif /* VDISCARD */ #if defined(VLNEXT) {"lnext", C_SH(C_LNEXT), MD_CHAR}, #endif /* VLNEXT */ #if defined(VSTATUS) {"status", C_SH(C_STATUS), MD_CHAR}, #endif /* VSTATUS */ #if defined(VPAGE) {"page", C_SH(C_PAGE), MD_CHAR}, #endif /* VPAGE */ #if defined(VPGOFF) {"pgoff", C_SH(C_PGOFF), MD_CHAR}, #endif /* VPGOFF */ #if defined(VKILL2) {"kill2", C_SH(C_KILL2), MD_CHAR}, #endif /* VKILL2 */ #if defined(VBRK) {"brk", C_SH(C_BRK), MD_CHAR}, #endif /* VBRK */ #if defined(VMIN) {"min", C_SH(C_MIN), MD_CHAR}, #endif /* VMIN */ #if defined(VTIME) {"time", C_SH(C_TIME), MD_CHAR}, #endif /* VTIME */ {NULL, 0, -1}, }; #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1) #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) #define tty__cooked_mode(td) ((td)->c_lflag & ICANON) private int tty_getty(EditLine *, struct termios *); private int tty_setty(EditLine *, int, const struct termios *); private int tty__getcharindex(int); private void tty__getchar(struct termios *, unsigned char *); private void tty__setchar(struct termios *, unsigned char *); private speed_t tty__getspeed(struct termios *); private int tty_setup(EditLine *); private void tty_setup_flags(EditLine *, struct termios *, int); #define t_qu t_ts /* tty_getty(): * Wrapper for tcgetattr to handle EINTR */ private int tty_getty(EditLine *el, struct termios *t) { int rv; while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR) continue; return rv; } /* tty_setty(): * Wrapper for tcsetattr to handle EINTR */ private int tty_setty(EditLine *el, int action, const struct termios *t) { int rv; while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR) continue; return rv; } /* tty_setup(): * Get the tty parameters and initialize the editing state */ private int tty_setup(EditLine *el) { int rst = 1; if (el->el_flags & EDIT_DISABLED) return 0; if (!isatty(el->el_outfd)) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } if (tty_getty(el, &el->el_tty.t_or) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or; el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex); el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex); el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex); tty_setup_flags(el, &el->el_tty.t_ex, EX_IO); /* * Reset the tty chars to reasonable defaults * If they are disabled, then enable them. */ if (rst) { if (tty__cooked_mode(&el->el_tty.t_ts)) { tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); /* * Don't affect CMIN and CTIME for the editor mode */ for (rst = 0; rst < C_NCC - 2; rst++) if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable && el->el_tty.t_c[ED_IO][rst] != el->el_tty.t_vdisable) el->el_tty.t_c[ED_IO][rst] = el->el_tty.t_c[TS_IO][rst]; for (rst = 0; rst < C_NCC; rst++) if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable) el->el_tty.t_c[EX_IO][rst] = el->el_tty.t_c[TS_IO][rst]; } tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } } tty_setup_flags(el, &el->el_tty.t_ed, ED_IO); tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); tty_bind_char(el, 1); return 0; } protected int tty_init(EditLine *el) { el->el_tty.t_mode = EX_IO; el->el_tty.t_vdisable = _POSIX_VDISABLE; (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); return tty_setup(el); } /* tty_end(): * Restore the tty to its original settings */ protected void /*ARGSUSED*/ tty_end(EditLine *el) { if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ } } /* tty__getspeed(): * Get the tty speed */ private speed_t tty__getspeed(struct termios *td) { speed_t spd; if ((spd = cfgetispeed(td)) == 0) spd = cfgetospeed(td); return spd; } /* tty__getspeed(): * Return the index of the asked char in the c_cc array */ private int tty__getcharindex(int i) { switch (i) { #ifdef VINTR case C_INTR: return VINTR; #endif /* VINTR */ #ifdef VQUIT case C_QUIT: return VQUIT; #endif /* VQUIT */ #ifdef VERASE case C_ERASE: return VERASE; #endif /* VERASE */ #ifdef VKILL case C_KILL: return VKILL; #endif /* VKILL */ #ifdef VEOF case C_EOF: return VEOF; #endif /* VEOF */ #ifdef VEOL case C_EOL: return VEOL; #endif /* VEOL */ #ifdef VEOL2 case C_EOL2: return VEOL2; #endif /* VEOL2 */ #ifdef VSWTCH case C_SWTCH: return VSWTCH; #endif /* VSWTCH */ #ifdef VDSWTCH case C_DSWTCH: return VDSWTCH; #endif /* VDSWTCH */ #ifdef VERASE2 case C_ERASE2: return VERASE2; #endif /* VERASE2 */ #ifdef VSTART case C_START: return VSTART; #endif /* VSTART */ #ifdef VSTOP case C_STOP: return VSTOP; #endif /* VSTOP */ #ifdef VWERASE case C_WERASE: return VWERASE; #endif /* VWERASE */ #ifdef VSUSP case C_SUSP: return VSUSP; #endif /* VSUSP */ #ifdef VDSUSP case C_DSUSP: return VDSUSP; #endif /* VDSUSP */ #ifdef VREPRINT case C_REPRINT: return VREPRINT; #endif /* VREPRINT */ #ifdef VDISCARD case C_DISCARD: return VDISCARD; #endif /* VDISCARD */ #ifdef VLNEXT case C_LNEXT: return VLNEXT; #endif /* VLNEXT */ #ifdef VSTATUS case C_STATUS: return VSTATUS; #endif /* VSTATUS */ #ifdef VPAGE case C_PAGE: return VPAGE; #endif /* VPAGE */ #ifdef VPGOFF case C_PGOFF: return VPGOFF; #endif /* VPGOFF */ #ifdef VKILL2 case C_KILL2: return VKILL2; #endif /* KILL2 */ #ifdef VMIN case C_MIN: return VMIN; #endif /* VMIN */ #ifdef VTIME case C_TIME: return VTIME; #endif /* VTIME */ default: return -1; } } /* tty__getchar(): * Get the tty characters */ private void tty__getchar(struct termios *td, unsigned char *s) { #ifdef VINTR s[C_INTR] = td->c_cc[VINTR]; #endif /* VINTR */ #ifdef VQUIT s[C_QUIT] = td->c_cc[VQUIT]; #endif /* VQUIT */ #ifdef VERASE s[C_ERASE] = td->c_cc[VERASE]; #endif /* VERASE */ #ifdef VKILL s[C_KILL] = td->c_cc[VKILL]; #endif /* VKILL */ #ifdef VEOF s[C_EOF] = td->c_cc[VEOF]; #endif /* VEOF */ #ifdef VEOL s[C_EOL] = td->c_cc[VEOL]; #endif /* VEOL */ #ifdef VEOL2 s[C_EOL2] = td->c_cc[VEOL2]; #endif /* VEOL2 */ #ifdef VSWTCH s[C_SWTCH] = td->c_cc[VSWTCH]; #endif /* VSWTCH */ #ifdef VDSWTCH s[C_DSWTCH] = td->c_cc[VDSWTCH]; #endif /* VDSWTCH */ #ifdef VERASE2 s[C_ERASE2] = td->c_cc[VERASE2]; #endif /* VERASE2 */ #ifdef VSTART s[C_START] = td->c_cc[VSTART]; #endif /* VSTART */ #ifdef VSTOP s[C_STOP] = td->c_cc[VSTOP]; #endif /* VSTOP */ #ifdef VWERASE s[C_WERASE] = td->c_cc[VWERASE]; #endif /* VWERASE */ #ifdef VSUSP s[C_SUSP] = td->c_cc[VSUSP]; #endif /* VSUSP */ #ifdef VDSUSP s[C_DSUSP] = td->c_cc[VDSUSP]; #endif /* VDSUSP */ #ifdef VREPRINT s[C_REPRINT] = td->c_cc[VREPRINT]; #endif /* VREPRINT */ #ifdef VDISCARD s[C_DISCARD] = td->c_cc[VDISCARD]; #endif /* VDISCARD */ #ifdef VLNEXT s[C_LNEXT] = td->c_cc[VLNEXT]; #endif /* VLNEXT */ #ifdef VSTATUS s[C_STATUS] = td->c_cc[VSTATUS]; #endif /* VSTATUS */ #ifdef VPAGE s[C_PAGE] = td->c_cc[VPAGE]; #endif /* VPAGE */ #ifdef VPGOFF s[C_PGOFF] = td->c_cc[VPGOFF]; #endif /* VPGOFF */ #ifdef VKILL2 s[C_KILL2] = td->c_cc[VKILL2]; #endif /* KILL2 */ #ifdef VMIN s[C_MIN] = td->c_cc[VMIN]; #endif /* VMIN */ #ifdef VTIME s[C_TIME] = td->c_cc[VTIME]; #endif /* VTIME */ } /* tty__getchar */ /* tty__setchar(): * Set the tty characters */ private void tty__setchar(struct termios *td, unsigned char *s) { #ifdef VINTR td->c_cc[VINTR] = s[C_INTR]; #endif /* VINTR */ #ifdef VQUIT td->c_cc[VQUIT] = s[C_QUIT]; #endif /* VQUIT */ #ifdef VERASE td->c_cc[VERASE] = s[C_ERASE]; #endif /* VERASE */ #ifdef VKILL td->c_cc[VKILL] = s[C_KILL]; #endif /* VKILL */ #ifdef VEOF td->c_cc[VEOF] = s[C_EOF]; #endif /* VEOF */ #ifdef VEOL td->c_cc[VEOL] = s[C_EOL]; #endif /* VEOL */ #ifdef VEOL2 td->c_cc[VEOL2] = s[C_EOL2]; #endif /* VEOL2 */ #ifdef VSWTCH td->c_cc[VSWTCH] = s[C_SWTCH]; #endif /* VSWTCH */ #ifdef VDSWTCH td->c_cc[VDSWTCH] = s[C_DSWTCH]; #endif /* VDSWTCH */ #ifdef VERASE2 td->c_cc[VERASE2] = s[C_ERASE2]; #endif /* VERASE2 */ #ifdef VSTART td->c_cc[VSTART] = s[C_START]; #endif /* VSTART */ #ifdef VSTOP td->c_cc[VSTOP] = s[C_STOP]; #endif /* VSTOP */ #ifdef VWERASE td->c_cc[VWERASE] = s[C_WERASE]; #endif /* VWERASE */ #ifdef VSUSP td->c_cc[VSUSP] = s[C_SUSP]; #endif /* VSUSP */ #ifdef VDSUSP td->c_cc[VDSUSP] = s[C_DSUSP]; #endif /* VDSUSP */ #ifdef VREPRINT td->c_cc[VREPRINT] = s[C_REPRINT]; #endif /* VREPRINT */ #ifdef VDISCARD td->c_cc[VDISCARD] = s[C_DISCARD]; #endif /* VDISCARD */ #ifdef VLNEXT td->c_cc[VLNEXT] = s[C_LNEXT]; #endif /* VLNEXT */ #ifdef VSTATUS td->c_cc[VSTATUS] = s[C_STATUS]; #endif /* VSTATUS */ #ifdef VPAGE td->c_cc[VPAGE] = s[C_PAGE]; #endif /* VPAGE */ #ifdef VPGOFF td->c_cc[VPGOFF] = s[C_PGOFF]; #endif /* VPGOFF */ #ifdef VKILL2 td->c_cc[VKILL2] = s[C_KILL2]; #endif /* VKILL2 */ #ifdef VMIN td->c_cc[VMIN] = s[C_MIN]; #endif /* VMIN */ #ifdef VTIME td->c_cc[VTIME] = s[C_TIME]; #endif /* VTIME */ } /* tty__setchar */ /* tty_bind_char(): * Rebind the editline functions */ protected void tty_bind_char(EditLine *el, int force) { unsigned char *t_n = el->el_tty.t_c[ED_IO]; unsigned char *t_o = el->el_tty.t_ed.c_cc; Char new[2], old[2]; const ttymap_t *tp; el_action_t *map, *alt; const el_action_t *dmap, *dalt; new[1] = old[1] = '\0'; map = el->el_map.key; alt = el->el_map.alt; if (el->el_map.type == MAP_VI) { dmap = el->el_map.vii; dalt = el->el_map.vic; } else { dmap = el->el_map.emacs; dalt = NULL; } for (tp = tty_map; tp->nch != (Int)-1; tp++) { new[0] = t_n[tp->nch]; old[0] = t_o[tp->och]; if (new[0] == old[0] && !force) continue; /* Put the old default binding back, and set the new binding */ keymacro_clear(el, map, old); map[UC(old[0])] = dmap[UC(old[0])]; keymacro_clear(el, map, new); /* MAP_VI == 1, MAP_EMACS == 0... */ map[UC(new[0])] = tp->bind[el->el_map.type]; if (dalt) { keymacro_clear(el, alt, old); alt[UC(old[0])] = dalt[UC(old[0])]; keymacro_clear(el, alt, new); alt[UC(new[0])] = tp->bind[el->el_map.type + 1]; } } } private tcflag_t * tty__get_flag(struct termios *t, int kind) { switch (kind) { case MD_INP: return &t->c_iflag; case MD_OUT: return &t->c_oflag; case MD_CTL: return &t->c_cflag; case MD_LIN: return &t->c_lflag; default: abort(); /*NOTREACHED*/ } } private tcflag_t tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind) { f &= ~el->el_tty.t_t[mode][kind].t_clrmask; f |= el->el_tty.t_t[mode][kind].t_setmask; return f; } private void tty_update_flags(EditLine *el, int kind) { tcflag_t *tt, *ed, *ex; tt = tty__get_flag(&el->el_tty.t_ts, kind); ed = tty__get_flag(&el->el_tty.t_ed, kind); ex = tty__get_flag(&el->el_tty.t_ex, kind); if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) { *ed = tty_update_flag(el, *tt, ED_IO, kind); *ex = tty_update_flag(el, *tt, EX_IO, kind); } } private void tty_update_char(EditLine *el, int mode, int c) { if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c))) && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c])) el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c]; if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c)) el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable; } /* tty_rawmode(): * Set terminal into 1 character at a time mode. */ protected int tty_rawmode(EditLine *el) { if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) return 0; if (el->el_flags & EDIT_DISABLED) return 0; if (tty_getty(el, &el->el_tty.t_ts) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } /* * We always keep up with the eight bit setting and the speed of the * tty. But we only believe changes that are made to cooked mode! */ el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); } if (tty__cooked_mode(&el->el_tty.t_ts)) { int i; for (i = MD_INP; i <= MD_LIN; i++) tty_update_flags(el, i); if (tty__gettabs(&el->el_tty.t_ex) == 0) el->el_tty.t_tabs = 0; else el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); /* * Check if the user made any changes. * If he did, then propagate the changes to the * edit and execute data structures. */ for (i = 0; i < C_NCC; i++) if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]) break; if (i != C_NCC) { /* * Propagate changes only to the unprotected * chars that have been modified just now. */ for (i = 0; i < C_NCC; i++) tty_update_char(el, ED_IO, i); tty_bind_char(el, 0); tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); for (i = 0; i < C_NCC; i++) tty_update_char(el, EX_IO, i); tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); } } if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = ED_IO; return 0; } /* tty_cookedmode(): * Set the tty back to normal mode */ protected int tty_cookedmode(EditLine *el) { /* set tty in normal setup */ if (el->el_tty.t_mode == EX_IO) return 0; if (el->el_flags & EDIT_DISABLED) return 0; if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = EX_IO; return 0; } /* tty_quotemode(): * Turn on quote mode */ protected int tty_quotemode(EditLine *el) { if (el->el_tty.t_mode == QU_IO) return 0; el->el_tty.t_qu = el->el_tty.t_ed; tty_setup_flags(el, &el->el_tty.t_qu, QU_IO); if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = QU_IO; return 0; } /* tty_noquotemode(): * Turn off quote mode */ protected int tty_noquotemode(EditLine *el) { if (el->el_tty.t_mode != QU_IO) return 0; if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } el->el_tty.t_mode = ED_IO; return 0; } /* tty_stty(): * Stty builtin */ protected int /*ARGSUSED*/ tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) { const ttymodes_t *m; char x; int aflag = 0; const Char *s, *d; char name[EL_BUFSIZ]; struct termios *tios = &el->el_tty.t_ex; int z = EX_IO; if (argv == NULL) return -1; strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); name[sizeof(name) - 1] = '\0'; while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') switch (argv[0][1]) { case 'a': aflag++; argv++; break; case 'd': argv++; tios = &el->el_tty.t_ed; z = ED_IO; break; case 'x': argv++; tios = &el->el_tty.t_ex; z = EX_IO; break; case 'q': argv++; tios = &el->el_tty.t_ts; z = QU_IO; break; default: (void) fprintf(el->el_errfile, - "%s: Unknown switch `%c'.\n", - name, argv[0][1]); + "%s: Unknown switch `" FCHAR "'.\n", + name, (Int)argv[0][1]); return -1; } if (!argv || !*argv) { int i = -1; size_t len = 0, st = 0, cu; for (m = ttymodes; m->m_name; m++) { if (m->m_type != i) { (void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "", el->el_tty.t_t[z][m->m_type].t_name); i = m->m_type; st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name); } if (i != -1) { x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0'; if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) x = '-'; } else { x = '\0'; } if (x != '\0' || aflag) { cu = strlen(m->m_name) + (x != '\0') + 1; if (len + cu >= (size_t)el->el_terminal.t_size.h) { (void) fprintf(el->el_outfile, "\n%*s", (int)st, ""); len = st + cu; } else len += cu; if (x != '\0') (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name); else (void) fprintf(el->el_outfile, "%s ", m->m_name); } } (void) fprintf(el->el_outfile, "\n"); return 0; } while (argv && (s = *argv++)) { const Char *p; switch (*s) { case '+': case '-': x = (char)*s++; break; default: x = '\0'; break; } d = s; p = Strchr(s, '='); for (m = ttymodes; m->m_name; m++) if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) : strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 && (p == NULL || m->m_type == MD_CHAR)) break; if (!m->m_name) { (void) fprintf(el->el_errfile, "%s: Invalid argument `" FSTR "'.\n", name, d); return -1; } if (p) { int c = ffs((int)m->m_value); int v = *++p ? parse__escape(&p) : el->el_tty.t_vdisable; assert(c != 0); c--; c = tty__getcharindex(c); assert(c != -1); tios->c_cc[c] = (cc_t)v; continue; } switch (x) { case '+': el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; break; case '-': el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; break; default: el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; break; } } tty_setup_flags(el, tios, z); if (el->el_tty.t_mode == z) { if (tty_setty(el, TCSADRAIN, tios) == -1) { #ifdef DEBUG_TTY (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, strerror(errno)); #endif /* DEBUG_TTY */ return -1; } } return 0; } #ifdef notyet /* tty_printchar(): * DEbugging routine to print the tty characters */ private void tty_printchar(EditLine *el, unsigned char *s) { ttyperm_t *m; int i; for (i = 0; i < C_NCC; i++) { for (m = el->el_tty.t_t; m->m_name; m++) if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) break; if (m->m_name) (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A' - 1); if (i % 5 == 0) (void) fprintf(el->el_errfile, "\n"); } (void) fprintf(el->el_errfile, "\n"); } #endif /* notyet */ private void tty_setup_flags(EditLine *el, struct termios *tios, int mode) { int kind; for (kind = MD_INP; kind <= MD_LIN; kind++) { tcflag_t *f = tty__get_flag(tios, kind); *f = tty_update_flag(el, *f, mode, kind); } }