diff -r 2df7c958974e Modules/readline.c --- a/Modules/readline.c Sat May 23 18:08:55 2015 -0700 +++ b/Modules/readline.c Sun May 24 09:16:23 2015 +0000 @@ -27,10 +27,14 @@ # define RESTORE_LOCALE(sl) #endif +#ifdef HAVE_EDITLINE_READLINE_H +# include +#else /* GNU readline definitions */ -#undef HAVE_CONFIG_H /* Else readline/chardefs.h includes strings.h */ -#include -#include +# undef HAVE_CONFIG_H /* Else readline/chardefs.h includes strings.h */ +# include +# include +#endif #ifdef HAVE_RL_COMPLETION_MATCHES #define completion_matches(x, y) \ @@ -40,32 +44,25 @@ extern char **completion_matches(char *, rl_compentry_func_t *); #else -#if !defined(__APPLE__) +#ifndef HAVE_EDITLINE extern char **completion_matches(char *, CPFunction *); #endif #endif #endif -#ifdef __APPLE__ +#ifdef HAVE_EDITLINE /* * 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 known API incompatibility: * - 'get_history' has a 1-based index with GNU readline, and a 0-based * index with older versions of libedit's emulation. * - Note that replace_history and remove_history use a 0-based index * with both implementations. */ -static int using_libedit_emulation = 0; -static const char libedit_version_tag[] = "EditLine wrapper"; - static int libedit_history_start = 0; -#endif /* __APPLE__ */ +#endif /* HAVE_EDITLINE */ #ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK static void @@ -642,15 +639,7 @@ static int _py_get_history_length(void) { - HISTORY_STATE *hist_st = history_get_history_state(); - int length = hist_st->length; - /* the history docs don't say so, but the address of hist_st changes each - time history_get_history_state is called which makes me think it's - freshly malloc'd memory... on the other hand, the address of the last - line stays the same as long as history isn't extended, so it appears to - be malloc'd but managed by the history package... */ - free(hist_st); - return length; + return history_length; } /* Exported function to get any element of history */ @@ -663,27 +652,27 @@ if (!PyArg_ParseTuple(args, "i:index", &idx)) return NULL; -#ifdef __APPLE__ - if (using_libedit_emulation) { - /* Older versions of libedit's readline emulation - * use 0-based indexes, while readline and newer - * versions of libedit use 1-based indexes. - */ - int length = _py_get_history_length(); +#ifdef HAVE_EDITLINE + /* Older versions of libedit's readline emulation + * use 0-based indexes, while readline and newer + * versions of libedit use 1-based indexes. + */ + idx = idx - 1 + libedit_history_start; - idx = idx - 1 + libedit_history_start; +#ifdef __APPLE__ + /* + * Apple's readline emulation crashes when + * the index is out of range, therefore + * test for that and fail gracefully. + */ + int length = _py_get_history_length(); - /* - * Apple's readline emulation crashes when - * the index is out of range, therefore - * test for that and fail gracefully. - */ - if (idx < (0 + libedit_history_start) - || idx >= (length + libedit_history_start)) { - Py_RETURN_NONE; - } + if (idx < (0 + libedit_history_start) + || idx >= (length + libedit_history_start)) { + Py_RETURN_NONE; } -#endif /* __APPLE__ */ +#endif +#endif /* HAVE_EDITLINE */ if ((hist_ent = history_get(idx))) return PyUnicode_FromString(hist_ent->line); else { @@ -1018,12 +1007,11 @@ Py_FatalError("not enough memory to save locale"); #endif -#ifdef __APPLE__ +#ifdef HAVE_EDITLINE /* the libedit readline emulation resets key bindings etc * when calling rl_initialize. So call it upfront */ - if (using_libedit_emulation) - rl_initialize(); + rl_initialize(); /* Detect if libedit's readline emulation uses 0-based * indexing or 1-based indexing. @@ -1035,7 +1023,7 @@ libedit_history_start = 1; } clear_history(); -#endif /* __APPLE__ */ +#endif /* HAVE_EDITLINE */ using_history(); @@ -1080,12 +1068,11 @@ * XXX: A bug in the readline-2.2 library causes a memory leak * inside this function. Nothing we can do about it. */ -#ifdef __APPLE__ - if (using_libedit_emulation) - rl_read_init_file(NULL); - else -#endif /* __APPLE__ */ - rl_initialize(); +#ifdef HAVE_EDITLINE + rl_read_init_file(NULL); +#else + rl_initialize(); +#endif /* HAVE_EDITLINE */ RESTORE_LOCALE(saved_locale) } @@ -1249,15 +1236,24 @@ if (n > 0) { const char *line; int length = _py_get_history_length(); - if (length > 0) -#ifdef __APPLE__ - if (using_libedit_emulation) { - /* handle older 0-based or newer 1-based indexing */ - line = (const char *)history_get(length + libedit_history_start - 1)->line; - } else -#endif /* __APPLE__ */ - line = (const char *)history_get(length)->line; - else + if (length > 0) { + HIST_ENTRY *entry; +#ifdef HAVE_EDITLINE + /* handle older 0-based or newer 1-based indexing */ + entry = history_get(length + libedit_history_start - 1); +#else + entry = history_get(length); +#endif /* HAVE_EDITLINE */ + /* + * FreeBSD's libedit implementation returns NULL on out of bound + * accesses. For whatever reason it incorrectly claims that it has + * an element when it doesn't really have one. + */ + if (entry == NULL) + line = ""; + else + line = (const char *)entry->line; + } else line = ""; if (strcmp(p, line)) add_history(p); @@ -1279,13 +1275,13 @@ /* Initialize the module */ +#ifdef HAVE_EDITLINE +PyDoc_STRVAR(doc_module, +"Importing this module enables command line editing using libedit readline."); +#else 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__ */ +#endif static struct PyModuleDef readlinemodule = { PyModuleDef_HEAD_INIT, @@ -1306,16 +1302,6 @@ PyObject *m; readlinestate *mod_state; -#ifdef __APPLE__ - if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) { - using_libedit_emulation = 1; - } - - if (using_libedit_emulation) - readlinemodule.m_doc = doc_module_le; - -#endif /* __APPLE__ */ - m = PyModule_Create(&readlinemodule); if (m == NULL) diff -r 2df7c958974e configure.ac --- a/configure.ac Sat May 23 18:08:55 2015 -0700 +++ b/configure.ac Sun May 24 09:16:23 2015 +0000 @@ -1289,6 +1289,8 @@ UNIVERSAL_ARCH_FLAGS= AC_SUBST(UNIVERSAL_ARCH_FLAGS) +DEFAULT_LIBREADLINE=readline + # tweak BASECFLAGS based on compiler and platform case $GCC in yes) @@ -1448,6 +1450,7 @@ ;; esac AC_MSG_RESULT($CC) + DEFAULT_LIBREADLINE=editline fi if test "${enable_universalsdk}" @@ -4371,93 +4374,157 @@ [Define this if you have flockfile(), getc_unlocked(), and funlockfile()]) fi +AC_ARG_WITH([readline], + [AS_HELP_STRING([--with-readline], + [enable support for the readline module. You can also specify readline, editline, etc, or no to disable detection. Defaults to $DEFAULT_LIBREADLINE])], + [], + [with_readline=$DEFAULT_LIBREADLINE]) + # check where readline lives # save the value of LIBS so we don't actually link Python with readline LIBS_no_readline=$LIBS -# On some systems we need to link readline to a termcap compatible -# library. NOTE: Keep the precedence of listed libraries synchronised -# with setup.py. -py_cv_lib_readline=no -AC_MSG_CHECKING([how to link readline libs]) -for py_libtermcap in "" tinfo ncursesw ncurses curses termcap; do - if test -z "$py_libtermcap"; then - READLINE_LIBS="-lreadline" +if test "x$with_readline" != "xno" +then + + if test "x$with_readline" = xeditline + then + LIBREADLINE=edit + AC_CHECK_HEADERS(editline/readline.h) + elif test "x$with_readline" = xreadline + then + LIBREADLINE=readline else - READLINE_LIBS="-lreadline -l$py_libtermcap" + LIBREADLINE=$DEFAULT_LIBREADLINE fi - LIBS="$READLINE_LIBS $LIBS_no_readline" - AC_LINK_IFELSE( - [AC_LANG_CALL([],[readline])], - [py_cv_lib_readline=yes]) - if test $py_cv_lib_readline = yes; then - break + + # On some systems we need to link readline to a termcap compatible + # library. NOTE: Keep the precedence of listed libraries synchronised + # with setup.py. + py_cv_lib_readline=no + AC_MSG_CHECKING([how to link readline libs]) + for py_libtermcap in "" tinfo ncursesw ncurses curses termcap; do + if test -z "$py_libtermcap"; then + READLINE_LIBS="-l$LIBREADLINE" + else + READLINE_LIBS="-l$LIBREADLINE -l$py_libtermcap" + fi + LIBS="$READLINE_LIBS $LIBS_no_readline" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([ +#include /* Must be first for Gnu Readline */ +#ifdef HAVE_EDITLINE_READLINE_H +# include +#else +# include +#endif +],[ +readline("this is a prompt"); +])],[py_cv_lib_readline=yes]) + if test $py_cv_lib_readline = yes; then + break + fi + done + + # Uncomment this line if you want to use READINE_LIBS in Makefile or scripts + #AC_SUBST([READLINE_LIBS]) + if test $py_cv_lib_readline = no; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([$READLINE_LIBS]) + if test "x$LIBREADLINE" = xedit + then + AC_DEFINE(HAVE_EDITLINE, 1, + [Define if you have the editline library (-ledit).]) + else + AC_DEFINE(HAVE_LIBREADLINE, 1, + [Define if you have the readline library (-lreadline).]) + fi fi -done -# Uncomment this line if you want to use READINE_LIBS in Makefile or scripts -#AC_SUBST([READLINE_LIBS]) -if test $py_cv_lib_readline = no; then - AC_MSG_RESULT([none]) -else - AC_MSG_RESULT([$READLINE_LIBS]) - AC_DEFINE(HAVE_LIBREADLINE, 1, - [Define if you have the readline library (-lreadline).]) -fi - -# check for readline 2.1 -AC_CHECK_LIB(readline, rl_callback_handler_install, + + fi + +if test "x$py_cv_lib_readline" = "xyes" +then + + # check for readline 2.1 + AC_CHECK_LIB($LIBREADLINE, rl_callback_handler_install, AC_DEFINE(HAVE_RL_CALLBACK, 1, [Define if you have readline 2.1]), ,$READLINE_LIBS) -# check for readline 2.2 -AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])], - [have_readline=yes], - [have_readline=no] -) -if test $have_readline = yes + # check for readline 2.2 + AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])], + [have_readline=yes], + [have_readline=no] + ) +fi + +if test "x$have_readline" = xyes then - AC_EGREP_HEADER([extern int rl_completion_append_character;], - [readline/readline.h], - AC_DEFINE(HAVE_RL_COMPLETION_APPEND_CHARACTER, 1, - [Define if you have readline 2.2]), ) - AC_EGREP_HEADER([extern int rl_completion_suppress_append;], - [readline/readline.h], - AC_DEFINE(HAVE_RL_COMPLETION_SUPPRESS_APPEND, 1, - [Define if you have rl_completion_suppress_append]), ) -fi - -# check for readline 4.0 -AC_CHECK_LIB(readline, rl_pre_input_hook, + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include /* Must be first for Gnu Readline */ +#ifdef HAVE_EDITLINE_READLINE_H +# include +#else +# include +#endif +],[ +int i = 0; +rl_completion_append_character = i; +])],[ + AC_DEFINE(HAVE_RL_COMPLETION_APPEND_CHARACTER,1, + [Define if you have readline 2.2]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include /* Must be first for Gnu Readline */ +#ifdef HAVE_EDITLINE_READLINE_H +# include +#else +# include +#endif +],[ +int i = 0; +rl_completion_suppress_append = i; +])],[ + AC_DEFINE(HAVE_RL_COMPLETION_SUPPRESS_APPEND,1, + [Define if you have rl_completion_suppress_append]) +])]) + + # check for readline 4.0 + AC_CHECK_LIB($LIBREADLINE, rl_pre_input_hook, AC_DEFINE(HAVE_RL_PRE_INPUT_HOOK, 1, - [Define if you have readline 4.0]), ,$READLINE_LIBS) - -# also in 4.0 -AC_CHECK_LIB(readline, rl_completion_display_matches_hook, + [Define if you have readline 4.0]),,$READLINE_LIBS) + + # also in 4.0 + AC_CHECK_LIB($LIBREADLINE, rl_completion_display_matches_hook, AC_DEFINE(HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK, 1, - [Define if you have readline 4.0]), ,$READLINE_LIBS) - -# check for readline 4.2 -AC_CHECK_LIB(readline, rl_completion_matches, + [Define if you have readline 4.0]),,$READLINE_LIBS) + + # check for readline 4.2 + AC_CHECK_LIB($LIBREADLINE, rl_completion_matches, AC_DEFINE(HAVE_RL_COMPLETION_MATCHES, 1, - [Define if you have readline 4.2]), ,$READLINE_LIBS) - -# also in readline 4.2 -AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])], - [have_readline=yes], - [have_readline=no] -) -if test $have_readline = yes -then - AC_EGREP_HEADER([extern int rl_catch_signals;], - [readline/readline.h], - AC_DEFINE(HAVE_RL_CATCH_SIGNAL, 1, - [Define if you can turn off readline's signal handling.]), ) -fi - -AC_CHECK_LIB(readline, append_history, + [Define if you have readline 4.2]),,$READLINE_LIBS) + +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include /* Must be first for Gnu Readline */ +#ifdef HAVE_EDITLINE_READLINE_H +# include +#else +# include +#endif +],[ +int i = 0; +rl_catch_signals = i; +])],[ + AC_DEFINE(HAVE_RL_CATCH_SIGNAL,1, + [Define if you can turn off readline's signal handling.]) +]) + + AC_CHECK_LIB($LIBREADLINE, append_history, AC_DEFINE(HAVE_RL_APPEND_HISTORY, 1, [Define if readline supports append_history]), ,$READLINE_LIBS) +fi + # End of readline checks: restore LIBS LIBS=$LIBS_no_readline diff -r 2df7c958974e setup.py --- a/setup.py Sat May 23 18:08:55 2015 -0700 +++ b/setup.py Sun May 24 09:16:23 2015 +0000 @@ -678,7 +678,12 @@ exts.append( Extension('audioop', ['audioop.c']) ) # readline - do_readline = self.compiler.find_library_file(lib_dirs, 'readline') + if sysconfig.get_config_var('HAVE_LIBREADLINE'): + readline_lib = 'readline' + elif sysconfig.get_config_var('HAVE_EDITLINE'): + readline_lib = 'edit' + else: + readline_lib = None readline_termcap_library = "" curses_library = "" # Cannot use os.popen here in py3k. @@ -686,7 +691,9 @@ if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) # Determine if readline is already linked against curses or tinfo. - if do_readline: + if readline_lib: + do_readline = self.compiler.find_library_file(lib_dirs, + readline_lib) if cross_compiling: ret = os.system("%s -d %s | grep '(NEEDED)' > %s" \ % (sysconfig.get_config_var('READELF'), @@ -709,6 +716,8 @@ break if os.path.exists(tmpfile): os.unlink(tmpfile) + else: + do_readline = False # Issue 7384: If readline is already linked against curses, # use the same library for the readline and curses modules. if 'curses' in readline_termcap_library: @@ -744,7 +753,7 @@ else: readline_extra_link_args = () - readline_libs = ['readline'] + readline_libs = [readline_lib] if readline_termcap_library: pass # Issue 7384: Already linked against curses or tinfo. elif curses_library: