Skip to content

Commit 5585ae5

Browse files
author
Robert Marshall
committed
bpo-13501 Build or disable readline with Editline
I have ported the work done by martin.panter to latest master. * Include <editline/readline.h> if Editline is configured * Redefine HAVE_LIBREADLINE to also indicate if -ledit is used * New flag WITH_EDITLINE to differentiate between -lreadline and -ledit * Remove conditional completion_matches() declarations; use the declaration from the library rather than trying to guess it Resolves bpo-13501 Signed-off-by: Robert Marshall <[email protected]>
1 parent b4bcefe commit 5585ae5

File tree

6 files changed

+357
-309
lines changed

6 files changed

+357
-309
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for using native libedit libraries for readline functionality on BSD derived systems.

Modules/readline.c

Lines changed: 66 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,47 @@
2626
# define RESTORE_LOCALE(sl)
2727
#endif
2828

29+
#ifdef WITH_EDITLINE
30+
# include <editline/readline.h>
31+
#else
2932
/* GNU readline definitions */
30-
#undef HAVE_CONFIG_H /* Else readline/chardefs.h includes strings.h */
31-
#include <readline/readline.h>
32-
#include <readline/history.h>
33+
# undef HAVE_CONFIG_H /* Else readline/chardefs.h includes strings.h */
34+
# include <readline/readline.h>
35+
# include <readline/history.h>
36+
#endif
3337

38+
/* Readline 4.2 deprecated completion_matches() in favour of
39+
+rl_completion_matches() */
3440
#ifdef HAVE_RL_COMPLETION_MATCHES
3541
#define completion_matches(x, y) \
3642
rl_completion_matches((x), ((rl_compentry_func_t *)(y)))
37-
#else
38-
#if defined(_RL_FUNCTION_TYPEDEF)
39-
extern char **completion_matches(char *, rl_compentry_func_t *);
40-
#else
41-
42-
#if !defined(__APPLE__)
43-
extern char **completion_matches(char *, CPFunction *);
44-
#endif
45-
#endif
4643
#endif
4744

48-
#ifdef __APPLE__
4945
/*
5046
* It is possible to link the readline module to the readline
5147
* emulation library of editline/libedit.
5248
*
5349
* On OSX this emulation library is not 100% API compatible
54-
* with the "real" readline and cannot be detected at compile-time,
50+
* with the "real" readline and if WITH_EDITLINE
51+
* was not specified, cannot be detected at compile-time,
5552
* hence we use a runtime check to detect if we're using libedit
56-
*
57-
* Currently there is one known API incompatibility:
53+
*/
54+
#if defined(__APPLE__) && !defined(WITH_EDITLINE)
55+
# define DETECT_EDITLINE
56+
static int using_libedit_emulation = 0;
57+
static const char libedit_version_tag[] = "EditLine wrapper";
58+
#endif
59+
60+
#if defined(WITH_EDITLINE) || defined(__APPLE__)
61+
# define SUPPORT_EDITLINE
62+
/* One incompatibility of Editline:
5863
* - 'get_history' has a 1-based index with GNU readline, and a 0-based
5964
* index with older versions of libedit's emulation.
6065
* - Note that replace_history and remove_history use a 0-based index
6166
* with both implementations.
6267
*/
63-
static int using_libedit_emulation = 0;
64-
static const char libedit_version_tag[] = "EditLine wrapper";
65-
6668
static int libedit_history_start = 0;
67-
#endif /* __APPLE__ */
69+
#endif
6870

6971
#ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK
7072
static void
@@ -664,25 +666,6 @@ PyDoc_STRVAR(doc_get_completer,
664666
\n\
665667
Returns current completer function.");
666668

667-
/* Private function to get current length of history. XXX It may be
668-
* possible to replace this with a direct use of history_length instead,
669-
* but it's not clear whether BSD's libedit keeps history_length up to date.
670-
* See issue #8065.*/
671-
672-
static int
673-
_py_get_history_length(void)
674-
{
675-
HISTORY_STATE *hist_st = history_get_history_state();
676-
int length = hist_st->length;
677-
/* the history docs don't say so, but the address of hist_st changes each
678-
time history_get_history_state is called which makes me think it's
679-
freshly malloc'd memory... on the other hand, the address of the last
680-
line stays the same as long as history isn't extended, so it appears to
681-
be malloc'd but managed by the history package... */
682-
free(hist_st);
683-
return length;
684-
}
685-
686669
/* Exported function to get any element of history */
687670

688671
static PyObject *
@@ -693,27 +676,20 @@ get_history_item(PyObject *self, PyObject *args)
693676

694677
if (!PyArg_ParseTuple(args, "i:get_history_item", &idx))
695678
return NULL;
696-
#ifdef __APPLE__
697-
if (using_libedit_emulation) {
698-
/* Older versions of libedit's readline emulation
699-
* use 0-based indexes, while readline and newer
700-
* versions of libedit use 1-based indexes.
701-
*/
702-
int length = _py_get_history_length();
703-
704-
idx = idx - 1 + libedit_history_start;
705-
706-
/*
707-
* Apple's readline emulation crashes when
708-
* the index is out of range, therefore
709-
* test for that and fail gracefully.
710-
*/
711-
if (idx < (0 + libedit_history_start)
712-
|| idx >= (length + libedit_history_start)) {
713-
Py_RETURN_NONE;
714-
}
679+
680+
#ifdef SUPPORT_EDITLINE
681+
idx = idx - 1 + libedit_history_start;
682+
683+
/*
684+
* Apple's readline emulation crashes when
685+
* the index is out of range, therefore
686+
* test for that and fail gracefully.
687+
*/
688+
if (idx < libedit_history_start
689+
|| idx >= (history_length + libedit_history_start)) {
690+
Py_RETURN_NONE;
715691
}
716-
#endif /* __APPLE__ */
692+
#endif /* SUPPORT_EDITLINE */
717693
if ((hist_ent = history_get(idx)))
718694
return decode(hist_ent->line);
719695
else {
@@ -731,7 +707,7 @@ return the current contents of history item at index.");
731707
static PyObject *
732708
get_current_history_length(PyObject *self, PyObject *noarg)
733709
{
734-
return PyLong_FromLong((long)_py_get_history_length());
710+
return PyLong_FromLong(history_length);
735711
}
736712

737713
PyDoc_STRVAR(doc_get_current_history_length,
@@ -1080,14 +1056,16 @@ setup_readline(readlinestate *mod_state)
10801056
/* The name must be defined before initialization */
10811057
rl_readline_name = "python";
10821058

1083-
#ifdef __APPLE__
1059+
#ifdef SUPPORT_EDITLINE
10841060
/* the libedit readline emulation resets key bindings etc
1085-
* when calling rl_initialize. So call it upfront
1061+
* when calling rl_initialize. So call it before making those settings.
10861062
*/
1063+
# ifdef DETECT_EDITLINE
10871064
if (using_libedit_emulation)
1065+
# endif
10881066
rl_initialize();
10891067

1090-
/* Detect if libedit's readline emulation uses 0-based
1068+
/* Detect if the backend library uses 0-based
10911069
* indexing or 1-based indexing.
10921070
*/
10931071
add_history("1");
@@ -1097,7 +1075,7 @@ setup_readline(readlinestate *mod_state)
10971075
libedit_history_start = 1;
10981076
}
10991077
clear_history();
1100-
#endif /* __APPLE__ */
1078+
#endif /* SUPPORT_EDITLINE */
11011079

11021080
using_history();
11031081

@@ -1126,7 +1104,7 @@ setup_readline(readlinestate *mod_state)
11261104
mod_state->begidx = PyLong_FromLong(0L);
11271105
mod_state->endidx = PyLong_FromLong(0L);
11281106

1129-
#ifdef __APPLE__
1107+
#ifdef SUPPORT_EDITLINE
11301108
if (!using_libedit_emulation)
11311109
#endif
11321110
{
@@ -1147,13 +1125,20 @@ setup_readline(readlinestate *mod_state)
11471125
*
11481126
* XXX: A bug in the readline-2.2 library causes a memory leak
11491127
* inside this function. Nothing we can do about it.
1128+
*
1129+
* For Editline, just invoke the user configuration; initialization was
1130+
* already done above.
11501131
*/
1151-
#ifdef __APPLE__
1132+
#ifdef DETECT_EDITLINE
11521133
if (using_libedit_emulation)
11531134
rl_read_init_file(NULL);
11541135
else
1155-
#endif /* __APPLE__ */
11561136
rl_initialize();
1137+
#elif defined(WITH_EDITLINE)
1138+
rl_read_init_file(NULL);
1139+
#else
1140+
rl_initialize();
1141+
#endif
11571142

11581143
RESTORE_LOCALE(saved_locale)
11591144
}
@@ -1278,16 +1263,13 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
12781263
n = strlen(p);
12791264
if (should_auto_add_history && n > 0) {
12801265
const char *line;
1281-
int length = _py_get_history_length();
1282-
if (length > 0) {
1266+
if (history_length > 0) {
12831267
HIST_ENTRY *hist_ent;
1284-
#ifdef __APPLE__
1285-
if (using_libedit_emulation) {
1286-
/* handle older 0-based or newer 1-based indexing */
1287-
hist_ent = history_get(length + libedit_history_start - 1);
1288-
} else
1289-
#endif /* __APPLE__ */
1290-
hist_ent = history_get(length);
1268+
#ifdef SUPPORT_EDITLINE
1269+
hist_ent = history_get(history_length + libedit_history_start - 1);
1270+
#else
1271+
hist_ent = history_get(history_length);
1272+
#endif
12911273
line = hist_ent ? hist_ent->line : "";
12921274
} else
12931275
line = "";
@@ -1312,12 +1294,15 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
13121294
/* Initialize the module */
13131295

13141296
PyDoc_STRVAR(doc_module,
1297+
#ifndef WITH_EDITLINE
13151298
"Importing this module enables command line editing using GNU readline.");
1316-
1317-
#ifdef __APPLE__
1299+
#endif
1300+
#ifdef DETECT_EDITLINE
13181301
PyDoc_STRVAR(doc_module_le,
1302+
#endif
1303+
#ifdef SUPPORT_EDITLINE
13191304
"Importing this module enables command line editing using libedit readline.");
1320-
#endif /* __APPLE__ */
1305+
#endif
13211306

13221307
static struct PyModuleDef readlinemodule = {
13231308
PyModuleDef_HEAD_INIT,
@@ -1338,15 +1323,14 @@ PyInit_readline(void)
13381323
PyObject *m;
13391324
readlinestate *mod_state;
13401325

1341-
#ifdef __APPLE__
1326+
#ifdef DETECT_EDITLINE
13421327
if (strncmp(rl_library_version, libedit_version_tag, strlen(libedit_version_tag)) == 0) {
13431328
using_libedit_emulation = 1;
13441329
}
13451330

13461331
if (using_libedit_emulation)
13471332
readlinemodule.m_doc = doc_module_le;
1348-
1349-
#endif /* __APPLE__ */
1333+
#endif /* DETECT_EDITLINE */
13501334

13511335
m = PyModule_Create(&readlinemodule);
13521336

0 commit comments

Comments
 (0)