diff options
Diffstat (limited to 'Modules/readline.c')
-rw-r--r-- | Modules/readline.c | 202 |
1 files changed, 142 insertions, 60 deletions
diff --git a/Modules/readline.c b/Modules/readline.c index 8fac526..e9eabf5 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -6,6 +6,7 @@ /* Standard definitions */ #include "Python.h" +#include <stddef.h> #include <setjmp.h> #include <signal.h> #include <errno.h> @@ -76,6 +77,55 @@ on_completion_display_matches_hook(char **matches, (see issue #17289 for the motivation). */ static char *completer_word_break_characters; +typedef struct { + PyObject *completion_display_matches_hook; + PyObject *startup_hook; + PyObject *pre_input_hook; + PyObject *completer; + PyObject *begidx; + PyObject *endidx; +} readlinestate; + + +#define readline_state(o) ((readlinestate *)PyModule_GetState(o)) + +static int +readline_clear(PyObject *m) +{ + readlinestate *state = readline_state(m); + Py_CLEAR(state->completion_display_matches_hook); + Py_CLEAR(state->startup_hook); + Py_CLEAR(state->pre_input_hook); + Py_CLEAR(state->completer); + Py_CLEAR(state->begidx); + Py_CLEAR(state->endidx); + return 0; +} + +static int +readline_traverse(PyObject *m, visitproc visit, void *arg) +{ + readlinestate *state = readline_state(m); + Py_VISIT(state->completion_display_matches_hook); + Py_VISIT(state->startup_hook); + Py_VISIT(state->pre_input_hook); + Py_VISIT(state->completer); + Py_VISIT(state->begidx); + Py_VISIT(state->endidx); + return 0; +} + +static void +readline_free(void *m) +{ + readline_clear((PyObject *)m); +} + +static PyModuleDef readlinemodule; + +#define readlinestate_global ((readlinestate *)PyModule_GetState(PyState_FindModule(&readlinemodule))) + + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -86,12 +136,12 @@ parse_and_bind(PyObject *self, PyObject *args) return NULL; /* Make a copy -- rl_parse_and_bind() modifies its argument */ /* Bernard Herzog */ - copy = malloc(1 + strlen(s)); + copy = PyMem_Malloc(1 + strlen(s)); if (copy == NULL) return PyErr_NoMemory(); strcpy(copy, s); rl_parse_and_bind(copy); - free(copy); /* Free the copy */ + PyMem_Free(copy); /* Free the copy */ Py_RETURN_NONE; } @@ -251,23 +301,21 @@ set_hook(const char *funcname, PyObject **hook_var, PyObject *args) /* Exported functions to specify hook functions in Python */ -static PyObject *completion_display_matches_hook = NULL; -static PyObject *startup_hook = NULL; #ifdef HAVE_RL_PRE_INPUT_HOOK -static PyObject *pre_input_hook = NULL; + #endif static PyObject * set_completion_display_matches_hook(PyObject *self, PyObject *args) { PyObject *result = set_hook("completion_display_matches_hook", - &completion_display_matches_hook, args); + &readlinestate_global->completion_display_matches_hook, args); #ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK /* We cannot set this hook globally, since it replaces the default completion display. */ rl_completion_display_matches_hook = - completion_display_matches_hook ? + readlinestate_global->completion_display_matches_hook ? #if defined(_RL_FUNCTION_TYPEDEF) (rl_compdisp_func_t *)on_completion_display_matches_hook : 0; #else @@ -288,7 +336,7 @@ once each time matches need to be displayed."); static PyObject * set_startup_hook(PyObject *self, PyObject *args) { - return set_hook("startup_hook", &startup_hook, args); + return set_hook("startup_hook", &readlinestate_global->startup_hook, args); } PyDoc_STRVAR(doc_set_startup_hook, @@ -305,7 +353,7 @@ before readline prints the first prompt."); static PyObject * set_pre_input_hook(PyObject *self, PyObject *args) { - return set_hook("pre_input_hook", &pre_input_hook, args); + return set_hook("pre_input_hook", &readlinestate_global->pre_input_hook, args); } PyDoc_STRVAR(doc_set_pre_input_hook, @@ -320,10 +368,10 @@ characters."); /* Exported function to specify a word completer in Python */ -static PyObject *completer = NULL; -static PyObject *begidx = NULL; -static PyObject *endidx = NULL; + + + /* Get the completion type for the scope of the tab-completion */ @@ -343,8 +391,8 @@ Get the type of completion being attempted."); static PyObject * get_begidx(PyObject *self, PyObject *noarg) { - Py_INCREF(begidx); - return begidx; + Py_INCREF(readlinestate_global->begidx); + return readlinestate_global->begidx; } PyDoc_STRVAR(doc_get_begidx, @@ -357,8 +405,8 @@ get the beginning index of the readline tab-completion scope"); static PyObject * get_endidx(PyObject *self, PyObject *noarg) { - Py_INCREF(endidx); - return endidx; + Py_INCREF(readlinestate_global->endidx); + return readlinestate_global->endidx; } PyDoc_STRVAR(doc_get_endidx, @@ -379,10 +427,11 @@ set_completer_delims(PyObject *self, PyObject *args) /* Keep a reference to the allocated memory in the module state in case some other module modifies rl_completer_word_break_characters (see issue #17289). */ - free(completer_word_break_characters); - completer_word_break_characters = strdup(break_chars); - if (completer_word_break_characters) { - rl_completer_word_break_characters = completer_word_break_characters; + break_chars = strdup(break_chars); + if (break_chars) { + free(completer_word_break_characters); + completer_word_break_characters = break_chars; + rl_completer_word_break_characters = break_chars; Py_RETURN_NONE; } else @@ -523,7 +572,7 @@ get the readline word delimiters for tab-completion"); static PyObject * set_completer(PyObject *self, PyObject *args) { - return set_hook("completer", &completer, args); + return set_hook("completer", &readlinestate_global->completer, args); } PyDoc_STRVAR(doc_set_completer, @@ -537,11 +586,11 @@ It should return the next possible completion starting with 'text'."); static PyObject * get_completer(PyObject *self, PyObject *noargs) { - if (completer == NULL) { + if (readlinestate_global->completer == NULL) { Py_RETURN_NONE; } - Py_INCREF(completer); - return completer; + Py_INCREF(readlinestate_global->completer); + return readlinestate_global->completer; } PyDoc_STRVAR(doc_get_completer, @@ -745,9 +794,6 @@ on_hook(PyObject *func) int result = 0; if (func != NULL) { PyObject *r; -#ifdef WITH_THREAD - PyGILState_STATE gilstate = PyGILState_Ensure(); -#endif r = PyObject_CallFunction(func, NULL); if (r == NULL) goto error; @@ -764,9 +810,6 @@ on_hook(PyObject *func) PyErr_Clear(); Py_XDECREF(r); done: -#ifdef WITH_THREAD - PyGILState_Release(gilstate); -#endif return result; } return result; @@ -779,7 +822,15 @@ on_startup_hook(void) on_startup_hook() #endif { - return on_hook(startup_hook); + int r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + r = on_hook(readlinestate_global->startup_hook); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return r; } #ifdef HAVE_RL_PRE_INPUT_HOOK @@ -790,7 +841,15 @@ on_pre_input_hook(void) on_pre_input_hook() #endif { - return on_hook(pre_input_hook); + int r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + r = on_hook(readlinestate_global->pre_input_hook); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return r; } #endif @@ -817,7 +876,7 @@ on_completion_display_matches_hook(char **matches, if (PyList_SetItem(m, i, s) == -1) goto error; } - r = PyObject_CallFunction(completion_display_matches_hook, + r = PyObject_CallFunction(readlinestate_global->completion_display_matches_hook, "sOi", matches[0], m, max_length); Py_DECREF(m); m=NULL; @@ -847,13 +906,13 @@ static char * on_completion(const char *text, int state) { char *result = NULL; - if (completer != NULL) { + if (readlinestate_global->completer != NULL) { PyObject *r; #ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif rl_attempted_completion_over = 1; - r = PyObject_CallFunction(completer, "si", text, state); + r = PyObject_CallFunction(readlinestate_global->completer, "si", text, state); if (r == NULL) goto error; if (r == Py_None) { @@ -886,24 +945,32 @@ on_completion(const char *text, int state) static char ** flex_complete(const char *text, int start, int end) { + char **result; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character ='\0'; #endif #ifdef HAVE_RL_COMPLETION_SUPPRESS_APPEND rl_completion_suppress_append = 0; #endif - Py_XDECREF(begidx); - Py_XDECREF(endidx); - begidx = PyLong_FromLong((long) start); - endidx = PyLong_FromLong((long) end); - return completion_matches(text, *on_completion); + Py_XDECREF(readlinestate_global->begidx); + Py_XDECREF(readlinestate_global->endidx); + readlinestate_global->begidx = PyLong_FromLong((long) start); + readlinestate_global->endidx = PyLong_FromLong((long) end); + result = completion_matches(text, *on_completion); +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return result; } /* Helper to initialize GNU readline properly. */ static void -setup_readline(void) +setup_readline(readlinestate *mod_state) { #ifdef SAVE_LOCALE char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); @@ -933,10 +1000,6 @@ setup_readline(void) using_history(); rl_readline_name = "python"; -#if defined(PYOS_OS2) && defined(PYCC_GCC) - /* Allow $if term= in .inputrc to work */ - rl_terminal_name = getenv("TERM"); -#endif /* Force rebind of TAB to insert-tab */ rl_bind_key('\t', rl_insert); /* Bind both ESC-TAB and ESC-ESC to the completion function */ @@ -955,8 +1018,23 @@ setup_readline(void) strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ - begidx = PyLong_FromLong(0L); - endidx = PyLong_FromLong(0L); + mod_state->begidx = PyLong_FromLong(0L); + mod_state->endidx = PyLong_FromLong(0L); + +#ifndef __APPLE__ + if (!isatty(STDOUT_FILENO)) { + /* Issue #19884: stdout is no a terminal. Disable meta modifier + keys to not write the ANSI sequence "\033[1034h" into stdout. On + terminals supporting 8 bit characters like TERM=xterm-256color + (which is now the default Fedora since Fedora 18), the meta key is + used to enable support of 8 bit characters (ANSI sequence + "\033[1034h"). + + With libedit, this call makes readline() crash. */ + rl_variable_bind ("enable-meta-key", "off"); + } +#endif + /* Initialize (allows .inputrc to override) * * XXX: A bug in the readline-2.2 library causes a memory leak @@ -985,10 +1063,8 @@ rlhandler(char *text) rl_callback_handler_remove(); } -extern PyThreadState* _PyOS_ReadlineTState; - static char * -readline_until_enter_or_signal(char *prompt, int *signal) +readline_until_enter_or_signal(const char *prompt, int *signal) { char * not_done_reading = ""; fd_set selectset; @@ -1063,7 +1139,7 @@ onintr(int sig) static char * -readline_until_enter_or_signal(char *prompt, int *signal) +readline_until_enter_or_signal(const char *prompt, int *signal) { PyOS_sighandler_t old_inthandler; char *p; @@ -1090,7 +1166,7 @@ readline_until_enter_or_signal(char *prompt, int *signal) static char * -call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) +call_readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) { size_t n; char *p, *q; @@ -1119,9 +1195,9 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) return NULL; } - /* We got an EOF, return a empty string. */ + /* We got an EOF, return an empty string. */ if (p == NULL) { - p = PyMem_Malloc(1); + p = PyMem_RawMalloc(1); if (p != NULL) *p = '\0'; RESTORE_LOCALE(saved_locale) @@ -1149,7 +1225,7 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) /* Copy the malloc'ed buffer into a PyMem_Malloc'ed one and release the original. */ q = p; - p = PyMem_Malloc(n+2); + p = PyMem_RawMalloc(n+2); if (p != NULL) { strncpy(p, q, n); p[n] = '\n'; @@ -1175,12 +1251,12 @@ static struct PyModuleDef readlinemodule = { PyModuleDef_HEAD_INIT, "readline", doc_module, - -1, + sizeof(readlinestate), readline_methods, NULL, - NULL, - NULL, - NULL + readline_traverse, + readline_clear, + readline_free }; @@ -1188,6 +1264,7 @@ PyMODINIT_FUNC PyInit_readline(void) { PyObject *m; + readlinestate *mod_state; #ifdef __APPLE__ if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) { @@ -1204,7 +1281,12 @@ PyInit_readline(void) if (m == NULL) return NULL; + mod_state = (readlinestate *) PyModule_GetState(m); PyOS_ReadlineFunctionPointer = call_readline; - setup_readline(); + setup_readline(mod_state); + + PyModule_AddIntConstant(m, "_READLINE_VERSION", RL_READLINE_VERSION); + PyModule_AddIntConstant(m, "_READLINE_RUNTIME_VERSION", rl_readline_version); + return m; } |