/** \file input.c Functions for reading a character of input from stdin. */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_TERMIOS_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #include #include #if HAVE_NCURSES_H #include #else #include #endif #if HAVE_TERMIO_H #include #endif #if HAVE_TERM_H #include #elif HAVE_NCURSES_TERM_H #include #endif #include #include #include #include "fallback.h" #include "util.h" #include "wutil.h" #include "reader.h" #include "proc.h" #include "common.h" #include "sanity.h" #include "input_common.h" #include "input.h" #include "parser.h" #include "env.h" #include "expand.h" #include "event.h" #include "signal.h" #include "output.h" #include "intern.h" #include "halloc.h" #include "halloc_util.h" /** Add a new terminfo mapping */ #define TERMINFO_ADD(key) \ { \ terminfo_mapping_t *m = (terminfo_mapping_t *)halloc( terminfo_mappings, sizeof( terminfo_mapping_t ) ); \ m->name = halloc_wcsdup( terminfo_mappings, (L ## #key)+4 ); \ m->seq = key; \ al_push( terminfo_mappings, m ); \ } /** Struct representing a keybinding. Returned by input_get_mappings. */ struct input_mapping_t { wcstring seq; /**< Character sequence which generates this event */ wcstring command; /**< command that should be evaluated by this mapping */ input_mapping_t(const wcstring &s, const wcstring &c) : seq(s), command(c) {} }; /** A struct representing the mapping from a terminfo key name to a terminfo character sequence */ typedef struct { const wchar_t *name; /**< Name of key */ const char *seq; /**< Character sequence generated on keypress */ } terminfo_mapping_t; /** Names of all the input functions supported */ static const wchar_t *name_arr[] = { L"beginning-of-line", L"end-of-line", L"forward-char", L"backward-char", L"forward-word", L"backward-word", L"history-search-backward", L"history-search-forward", L"delete-char", L"backward-delete-char", L"kill-line", L"yank", L"yank-pop", L"complete", L"beginning-of-history", L"end-of-history", L"backward-kill-line", L"kill-whole-line", L"kill-word", L"backward-kill-word", L"dump-functions", L"history-token-search-backward", L"history-token-search-forward", L"self-insert", L"null", L"eof", L"vi-arg-digit", L"execute", L"beginning-of-buffer", L"end-of-buffer", L"repaint", L"up-line", L"down-line" } ; /** Description of each supported input function */ /* static const wchar_t *desc_arr[] = { L"Move to beginning of line", L"Move to end of line", L"Move forward one character", L"Move backward one character", L"Move forward one word", L"Move backward one word", L"Search backward through list of previous commands", L"Search forward through list of previous commands", L"Delete one character forward", L"Delete one character backward", L"Move contents from cursor to end of line to killring", L"Paste contents of killring", L"Rotate to previous killring entry", L"Guess the rest of the next input token", L"Move to first item of history", L"Move to last item of history", L"Clear current line", L"Move contents from beginning of line to cursor to killring", L"Move entire line to killring", L"Move next word to killring", L"Move previous word to killring", L"Write out keybindings", L"Clear entire screen", L"Quit the running program", L"Search backward through list of previous commands for matching token", L"Search forward through list of previous commands for matching token", L"Insert the pressed key", L"Do nothing", L"End of file", L"Repeat command" } ; */ /** Internal code for each supported input function */ static const wchar_t code_arr[] = { R_BEGINNING_OF_LINE, R_END_OF_LINE, R_FORWARD_CHAR, R_BACKWARD_CHAR, R_FORWARD_WORD, R_BACKWARD_WORD, R_HISTORY_SEARCH_BACKWARD, R_HISTORY_SEARCH_FORWARD, R_DELETE_CHAR, R_BACKWARD_DELETE_CHAR, R_KILL_LINE, R_YANK, R_YANK_POP, R_COMPLETE, R_BEGINNING_OF_HISTORY, R_END_OF_HISTORY, R_BACKWARD_KILL_LINE, R_KILL_WHOLE_LINE, R_KILL_WORD, R_BACKWARD_KILL_WORD, R_DUMP_FUNCTIONS, R_HISTORY_TOKEN_SEARCH_BACKWARD, R_HISTORY_TOKEN_SEARCH_FORWARD, R_SELF_INSERT, R_NULL, R_EOF, R_VI_ARG_DIGIT, R_EXECUTE, R_BEGINNING_OF_BUFFER, R_END_OF_BUFFER, R_REPAINT, R_UP_LINE, R_DOWN_LINE } ; /** Mappings for the current input mode */ std::vector mapping_list; /** List of all terminfo mappings */ static array_list_t *terminfo_mappings = 0; /** Set to one when the input subsytem has been initialized. */ static int is_init = 0; /** Initialize terminfo. */ static void input_terminfo_init(); /** Deallocate memory used by terminfo. Or at least try to. Terminfo leaks. */ static void input_terminfo_destroy(); /** Returns the function description for the given function code. */ void input_mapping_add( const wchar_t *sequence, const wchar_t *command ) { size_t i; CHECK( sequence, ); CHECK( command, ); // debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) ); for( i=0; i0 )); j++ ) ; if( str[j] == L'\0' ) { return input_exec_binding( m, m.seq ); } else { /* Return the read characters */ input_unreadch(c); for( k=j-1; k>=0; k-- ) { input_unreadch( m.seq[k] ); } } return 0; } void input_unreadch( wint_t ch ) { input_common_unreadch( ch ); } wint_t input_readch() { size_t i; CHECK_BLOCK( R_NULL ); /* Clear the interrupted flag */ reader_interrupted(); /* Search for sequence in mapping tables */ while( 1 ) { const input_mapping_t *generic = 0; for( i=0; iname ) ) { res = m->seq; err = EILSEQ; break; } } if( !res ) { errno = err; return 0; } if( !buff ) { buff = sb_halloc( global_context ); } sb_clear( buff ); sb_printf( buff, L"%s", res ); return (wchar_t *)buff->buff; } bool input_terminfo_get_name( const wcstring &seq, wcstring &name ) { int i; input_init(); for( i=0; iseq ) { continue; } const wcstring map_buf = format_string(L"%s", m->seq); if (map_buf == seq) { name = m->name; return true; } } return false; } void input_terminfo_get_names( array_list_t *lst, int skip_null ) { int i; CHECK( lst, ); input_init(); for( i=0; iseq ) { continue; } al_push( lst, m->name ); } } void input_function_get_names( array_list_t *lst ) { size_t i; CHECK( lst, ); for( i=0; i<(sizeof(name_arr)/sizeof(wchar_t *)); i++ ) { al_push( lst, name_arr[i] ); } } wchar_t input_function_get_code( const wcstring &name ) { size_t i; for( i = 0; i<(sizeof( code_arr )/sizeof(wchar_t)) ; i++ ) { if( name == name_arr[i] ) { return code_arr[i]; } } return -1; }