Backport the patch that enables linking the readline

module to libedit on OSX 10.5 or later. (Issue 6877)
This commit is contained in:
Ronald Oussoren 2010-02-07 20:04:45 +00:00
parent e9608ad0e5
commit 8ed66ed712
4 changed files with 95 additions and 10 deletions

View File

@ -14,6 +14,17 @@ made using this module affect the behaviour of both the interpreter's
interactive prompt and the prompts offered by the :func:`raw_input` and
:func:`input` built-in functions.
..note::
On MacOS X the :mod:`readline` module can be implemented using
the ``libedit`` library instead of GNU readline.
The configuration file for ``libedit`` is different from that
of GNU readline. If you programmaticly load configuration strings
you can check for the text "libedit" in :const:`readline.__doc__`
to differentiate between GNU readline and libedit.
The :mod:`readline` module defines the following functions:
@ -181,7 +192,6 @@ The :mod:`readline` module defines the following functions:
Append a line to the history buffer, as if it was the last line typed.
.. seealso::
Module :mod:`rlcompleter`

View File

@ -203,6 +203,9 @@ Library
Extension Modules
-----------------
- Issue #6877: Make it possible to link the readline extension to libedit
on OSX.
- Expat: Fix DoS via XML document with malformed UTF-8 sequences
(CVE_2009_3560).

View File

@ -38,9 +38,30 @@
#if defined(_RL_FUNCTION_TYPEDEF)
extern char **completion_matches(char *, rl_compentry_func_t *);
#else
#if !defined(__APPLE__)
extern char **completion_matches(char *, CPFunction *);
#endif
#endif
#endif
#ifdef __APPLE__
/*
* It is possible to link the readline module to the readline
* emulation library of editline/libedit.
*
* On OSX this emulation library is not 100% API compatible
* with the "real" readline and cannot be detected at compile-time,
* hence we use a runtime check to detect if we're using libedit
*
* Currently there is one know API incompatibility:
* - 'get_history' has a 1-based index with GNU readline, and a 0-based
* index with libedit's emulation.
* - Note that replace_history and remove_history use a 0-based index
* with both implementation.
*/
static int using_libedit_emulation = 0;
static const char libedit_version_tag[] = "EditLine wrapper";
#endif /* __APPLE__ */
static void
on_completion_display_matches_hook(char **matches,
@ -478,6 +499,29 @@ get_history_item(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "i:index", &idx))
return NULL;
#ifdef __APPLE__
if (using_libedit_emulation) {
/* Libedit emulation uses 0-based indexes,
* the real one uses 1-based indexes,
* adjust the index to ensure that Python
* code doesn't have to worry about the
* difference.
*/
HISTORY_STATE *hist_st;
hist_st = history_get_history_state();
idx --;
/*
* Apple's readline emulation crashes when
* the index is out of range, therefore
* test for that and fail gracefully.
*/
if (idx < 0 || idx >= hist_st->length) {
Py_RETURN_NONE;
}
}
#endif /* __APPLE__ */
if ((hist_ent = history_get(idx)))
return PyString_FromString(hist_ent->line);
else {
@ -981,6 +1025,15 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
char *line;
HISTORY_STATE *state = history_get_history_state();
if (state->length > 0)
#ifdef __APPLE__
if (using_libedit_emulation) {
/*
* Libedit's emulation uses 0-based indexes,
* the real readline uses 1-based indexes.
*/
line = history_get(state->length - 1)->line;
} else
#endif /* __APPLE__ */
line = history_get(state->length)->line;
else
line = "";
@ -1014,16 +1067,35 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
PyDoc_STRVAR(doc_module,
"Importing this module enables command line editing using GNU readline.");
#ifdef __APPLE__
PyDoc_STRVAR(doc_module_le,
"Importing this module enables command line editing using libedit readline.");
#endif /* __APPLE__ */
PyMODINIT_FUNC
initreadline(void)
{
PyObject *m;
#ifdef __APPLE__
if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) {
using_libedit_emulation = 1;
}
if (using_libedit_emulation)
m = Py_InitModule4("readline", readline_methods, doc_module_le,
(PyObject *)NULL, PYTHON_API_VERSION);
else
#endif /* __APPLE__ */
m = Py_InitModule4("readline", readline_methods, doc_module,
(PyObject *)NULL, PYTHON_API_VERSION);
if (m == NULL)
return;
PyOS_ReadlineFunctionPointer = call_readline;
setup_readline();
}

View File

@ -556,16 +556,16 @@ class PyBuildExt(build_ext):
# readline
do_readline = self.compiler.find_library_file(lib_dirs, 'readline')
if platform == 'darwin': # and os.uname()[2] < '9.':
# MacOSX 10.4 has a broken readline. Don't try to build
# the readline module unless the user has installed a fixed
# readline package
# FIXME: The readline emulation on 10.5 is better, but the
# readline module doesn't compile out of the box.
if find_file('readline/rlconf.h', inc_dirs, []) is None:
do_readline = False
if platform == 'darwin':
os_release = int(os.uname()[2].split('.')[0])
if os_release < 9:
# MacOSX 10.4 has a broken readline. Don't try to build
# the readline module unless the user has installed a fixed
# readline package
if find_file('readline/rlconf.h', inc_dirs, []) is None:
do_readline = False
if do_readline:
if sys.platform == 'darwin':
if platform == 'darwin' and os_release < 9:
# In every directory on the search path search for a dynamic
# library and then a static library, instead of first looking
# for dynamic libraries on the entiry path.