[GiNaC-list] GiNaC vs readline [Was: Problems]
Sheplyakov Alexei
varg at theor.jinr.ru
Wed Jan 31 14:08:26 CET 2007
Hello,
On Tue, Jan 30, 2007 at 11:41:46AM -0500, David Fang wrote:
> Unfortunately, the problems don't stop there:
>
> ----------->8 snip 8<-------------
> f g++ -DHAVE_CONFIG_H -I. -I../../ginsh -I.. -I../../ginsh/../ginac
> -I../ginac -DIN_GINAC -I/usr/local/include -I/sw/include -g -O2 -MT
> ginsh_parser.o -MD -MP -MF ".deps/ginsh_parser.Tpo" -c -o ginsh_parser.o
> ../../ginsh/ginsh_parser.cc; \
> then mv -f ".deps/ginsh_parser.Tpo" ".deps/ginsh_parser.Po"; else rm -f
> ".deps/ginsh_parser.Tpo"; exit 1; fi
> if g++ -DHAVE_CONFIG_H -I. -I../../ginsh -I.. -I../../ginsh/../ginac
> -I../ginac -DIN_GINAC -I/usr/local/include -I/sw/include -g -O2 -MT
> ginsh_lexer.o -MD -MP -MF ".deps/ginsh_lexer.Tpo" -c -o ginsh_lexer.o
> ../../ginsh/ginsh_lexer.cc; \
> then mv -f ".deps/ginsh_lexer.Tpo" ".deps/ginsh_lexer.Po"; else rm -f
> ".deps/ginsh_lexer.Tpo"; exit 1; fi
> ../../ginsh/ginsh_parser.yy: In function 'char** fcn_completion(const
> char*, int, int)':
> ../../ginsh/ginsh_parser.yy:858: error: invalid conversion from 'const
> char*' to 'char*'
> ../../ginsh/ginsh_parser.yy:863: error: 'rl_filename_completion_function'
> was not declared in this scope
> ../../ginsh/ginsh_parser.yy:863: error: 'rl_completion_matches' was not
> declared in this scope
> ../../ginsh/ginsh_parser.yy:873: error: 'rl_completion_matches' was not
> declared in this scope
> make: *** [ginsh_parser.o] Error 1
> ----------->8 snip 8<-------------
>
> Those three rl_ symbols also happen to be renamed without their "rl_"
> prefixes in the editline wrapper header/library. (I've found this problem
> with old versions of GNU readline too, BTW.) The workaround I devised in
> the magic-7.1 source is the following:
>
> #if defined(READLINE_4_DOT_2_PLUS) || (RL_VERSION_MAJOR >= 5) || (RL_VERSION_MAJOR == 4 && RL_VERSION_MINOR >= 2)
> #define filename_completion_function rl_filename_completion_function
> #define username_completion_function rl_username_completion_function
> #define completion_matches rl_completion_matches
> #endif
GiNaC already has proper hack for this (your solution is not good enough
for C++ anyway: one need also to const_cast<char *> the arguments and
convert pointers to functions so that compiler is happy about them).
Thus, ginsh can be compiled with old (GNU) libreadline (or compatible
non-GNU libraries). The only problem is how to decide if we got such
an old version. This is especially difficult if the library do not
provide any meaningful version information ("EditLine wrapper" is not
really helpful). OK, let's forget about library versions and check for
function/variables declarations themselves:
diff --git a/INSTALL b/INSTALL
index 8d0b703..7feed75 100644
--- a/INSTALL
+++ b/INSTALL
@@ -105,7 +105,7 @@ Problems building ginsh
-----------------------
The most common reason why this doesn't succeed is the absence of
-libreadline and/or the corresponding header files. Depending on what your
+GNU libreadline and/or the corresponding header files. Depending on what your
system/distribution is, you will have to install a package called
libreadline and maybe libreadline-dev. If your system's vendor doesn't
supply such packages, go to <ftp://ftp.gnu.org/gnu/readline/> and compile
diff --git a/acinclude.m4 b/acinclude.m4
index 4ab1387..a45f957 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -4,35 +4,111 @@ dnl additions' names with AC_ but with GINAC_ in order to steer clear of
dnl future trouble.
dnl ===========================================================================
-dnl Usage: GINAC_RLVERSION
+dnl Usage: GINAC_HAVE_READLINE
+dnl Will test for GNU libreadline (or compatible) and termcap. On success
+dnl RL_LIBS is set to libraries to link with and CONFIG_READLINE is set
+dnl to `yes'. If old (pre 4.2) libreadline is detected CONFIG_OLD_READLINE
+dnl will be defined instead.
dnl The maintainers of libreadline are complete morons: they don't care a shit
dnl about compatiblilty (which is not so bad by itself) and at the same time
dnl they don't export the version to the preprocessor so we could kluge around
dnl incomatiblities. The only reliable way to figure out the version is by
dnl checking the extern variable rl_library_version at runtime. &#@$%*!
-AC_DEFUN([GINAC_LIB_READLINE_VERSION],
-[AC_CACHE_CHECK([for version of libreadline], ginac_cv_rlversion, [
+dnl To add even more fun some vendors supply libraries which return non-numeric
+dnl rl_library_version.
+AC_DEFUN([GINAC_HAVE_READLINE],[
+AC_REQUIRE([GINAC_TERMCAP])
+
+AC_CHECK_HEADERS(readline/readline.h readline/history.h)
+save_LIBS="$LIBS"
+AC_CHECK_LIB(readline, readline)
+LIBS="$LIBTERMCAP $LIBS"
+
+if test "x$ac_cv_header_readline_readline_h" != "xyes" -o \
+ "x$ac_cv_header_readline_history_h" != "xyes" -o \
+ "x$ac_cv_lib_readline_readline" != "xyes"; then
+ CONFIG_READLINE="no"
+fi
+
+if test "x$CONFIG_READLINE" != "xno"; then
+dnl To be damn sure we got correct prototype don't use AC_CHECK_LIB
+AC_CACHE_CHECK([for rl_filename_completion_function in libreadline],
+ginac_cv_readline_type, [
+AC_TRY_RUN([
+#include <readline/readline.h>
+static char** fcn_completion(const char* text, int start, int end)
+{
+ return rl_completion_matches(text, rl_filename_completion_function);
+}
+int main()
+{
+ rl_attempted_completion_function = fcn_completion;
+ return 0;
+}], [
+dnl OK
+ginac_cv_readline_type="new" ], [
+dnl failure -- check for older (<= 4.1) readline
AC_TRY_RUN([
-#include <stdio.h>
-#include <sys/types.h>
#include <readline/readline.h>
+static char** fcn_completion(const char* text, int start, int end)
+{
+ return completion_matches(text, filename_completion_function);
+}
+int main()
+{
+ rl_attempted_completion_function = (CPPFunction *)fcn_completion;
+ return 0;
+}], [
+dnl OK
+ginac_cv_readline_type="old" ], [
+dnl failure -- niether "new" nor "old" libreadline
+ginac_cv_readline_type="none"], [])], [
+dnl cross-compiling -- assume "new" libreadline
+ginac_cv_readline_type="new"])])
+fi # CONFIG_READLINE != no
+
+if test "x$ginac_cv_readline_type" = "xnone"; then
+ CONFIG_READLINE="no"
+else
+ CONFIG_READLINE="yes"
+fi
+if test "x$CONFIG_READLINE" != "xno"; then
+AC_CACHE_CHECK([if rl_basic_word_break_characters is const char*],
+ginac_cv_rl_basic_word_break_const, [
+AC_TRY_RUN([
+#include <readline/readline.h>
+static char* orig_basic_word_break_characters;
int main()
{
- FILE *fd;
- fd = fopen("conftest.out", "w");
- fprintf(fd, "%s\n", rl_library_version);
- fclose(fd);
- return 0;
-}], ginac_cv_rlversion=`cat 'conftest.out'`, ginac_cv_rlversion='unknown', ginac_cv_rlversion='4.2')])
-if test "x${ginac_cv_rlversion}" != "xunknown"; then
- RL_VERSION_MAJOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
- AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MAJOR, $RL_VERSION_MAJOR, [Major version of installed readline library.])
- RL_VERSION_MINOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
- AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MINOR, $RL_VERSION_MINOR, [Minor version of installed readline library.])
+ orig_basic_word_break_characters = rl_basic_word_break_characters;
+ return 0;
+}], [
+dnl OK -- so it is char* (pre-5.0 readline)
+ginac_cv_rl_basic_word_break_const="no"
+], [
+dnl failure -- assume it is const char*
+ginac_cv_rl_basic_word_break_const="yes" ], [
+dnl cross-compiling -- assume it is const char*
+ginac_cv_rl_basic_word_break_const="yes" ])])
+fi # CONFIG_READLINE != no
+
+if test "x$CONFIG_READLINE" = "xyes"; then
+ RL_LIBS="$LIBS"
+ AC_DEFINE(CONFIG_READLINE, ,[have GNU readline (or compatible)])
+ if test "x$ginac_cv_rl_basic_word_break_const" = "xyes"; then
+ AC_DEFINE(CONFIG_RL_NEED_CONST_CAST, ,[Define if rl_basic_word_break_characters is const char*])
+ fi
+ if test "x$ginac_cv_readline_type" = "xold"; then
+ AC_DEFINE(CONFIG_OLD_READLINE, , [Define if have GNU readline < 4.2 or compatible])
+ fi
else
- GINAC_WARNING([I could not run a test of libreadline (needed for building ginsh).])
+ GINAC_WARNING([Could not run a test of libreadline (needed for building ginsh).])
fi
+LIBS="$save_LIBS"
+
+AC_SUBST(RL_LIBS)
+AC_SUBST(CONFIG_READLINE)
])
dnl Usage: GINAC_TERMCAP
diff --git a/configure.ac b/configure.ac
index b022b3d..5aa3bb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,22 +83,8 @@ AC_LANG([C++])
dnl Check for stuff needed for building the GiNaC interactive shell (ginsh).
AC_CHECK_HEADERS(unistd.h)
GINAC_HAVE_RUSAGE
-AC_CHECK_HEADERS(readline/readline.h readline/history.h)
-if test "x${ac_cv_header_readline_readline_h}" != "xyes" -o "x${ac_cv_header_readline_history_h}" != "xyes"; then
- GINAC_WARNING([I could not find the headers for libreadline (needed for building ginsh).])
-fi
-GINAC_TERMCAP
-save_LIBS=$LIBS
-LIBS="$LIBTERMCAP $LIBS"
-AC_CHECK_LIB(readline, readline)
-if test "x${ac_cv_lib_readline_readline}" = "xyes"; then
- GINAC_LIB_READLINE_VERSION
-else
- GINAC_WARNING([I could not find libreadline (needed by ginsh).])
-fi
-GINSH_LIBS=$LIBS
-LIBS=$save_LIBS
-AC_SUBST(GINSH_LIBS)
+dnl Check for libreadline
+GINAC_HAVE_READLINE
dnl Make sure all the necessary standard headers are installed on the system.
AC_CHECK_HEADER(iosfwd, , GINAC_ERROR([The standard <iosfwd> header file could not be found.]))
diff --git a/ginsh/Makefile.am b/ginsh/Makefile.am
index 184fbbe..44376a7 100644
--- a/ginsh/Makefile.am
+++ b/ginsh/Makefile.am
@@ -2,7 +2,7 @@
bin_PROGRAMS = ginsh
ginsh_SOURCES = ginsh_parser.yy ginsh_lexer.ll ginsh.h ginsh_extensions.h
-ginsh_LDADD = ../ginac/libginac.la $(GINSH_LIBS)
+ginsh_LDADD = ../ginac/libginac.la $(RL_LIBS)
INCLUDES = -I$(srcdir)/../ginac -I../ginac -DIN_GINAC
AM_YFLAGS = -d
diff --git a/ginsh/ginsh_parser.yy b/ginsh/ginsh_parser.yy
index b252609..f82c9f3 100644
--- a/ginsh/ginsh_parser.yy
+++ b/ginsh/ginsh_parser.yy
@@ -45,19 +45,21 @@
#define YYERROR_VERBOSE 1
+#ifdef CONFIG_READLINE
// Original readline settings
static int orig_completion_append_character;
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
+#ifdef CONFIG_OLD_READLINE
static char *orig_basic_word_break_characters;
#else
static const char *orig_basic_word_break_characters;
#endif
-#if (GINAC_RL_VERSION_MAJOR >= 5)
+#ifdef CONFIG_RL_NEED_CONST_CAST
#define GINAC_RL_COMPLETER_CAST(a) const_cast<char *>((a))
#else
#define GINAC_RL_COMPLETER_CAST(a) (a)
#endif
+#endif // CONFIG_READLINE
// Expression stack for %, %% and %%%
static void push(const ex &e);
@@ -850,6 +852,7 @@ static char *fcn_generator(const char *text, int state)
return NULL;
}
+#ifdef CONFIG_READLINE
static char **fcn_completion(const char *text, int start, int end)
{
if (rl_line_buffer[0] == '!') {
@@ -857,7 +860,7 @@ static char **fcn_completion(const char *text, int start, int end)
rl_completion_append_character = orig_completion_append_character;
rl_basic_word_break_characters = orig_basic_word_break_characters;
rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters);
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
+#ifdef CONFIG_OLD_READLINE
return completion_matches(const_cast<char *>(text), (CPFunction *)filename_completion_function);
#else
return rl_completion_matches(text, rl_filename_completion_function);
@@ -867,13 +870,14 @@ static char **fcn_completion(const char *text, int start, int end)
rl_completion_append_character = '(';
rl_basic_word_break_characters = " \t\n\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~";
rl_completer_word_break_characters = GINAC_RL_COMPLETER_CAST(rl_basic_word_break_characters);
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
+#ifdef CONFIG_OLD_READLINE
return completion_matches(const_cast<char *>(text), (CPFunction *)fcn_generator);
#else
return rl_completion_matches(text, fcn_generator);
#endif
}
}
+#endif // CONFIG_READLINE
void greeting(void)
{
@@ -917,15 +921,17 @@ int main(int argc, char **argv)
insert_help("print_latex", "print_latex(expression) - prints a LaTeX representation of the given expression");
insert_help("print_csrc", "print_csrc(expression) - prints a C source code representation of the given expression");
+#ifdef CONFIG_READLINE
// Init readline completer
rl_readline_name = argv[0];
-#if (GINAC_RL_VERSION_MAJOR < 4) || (GINAC_RL_VERSION_MAJOR == 4 && GINAC_RL_VERSION_MINOR < 2)
+#ifdef CONFIG_OLD_READLINE
rl_attempted_completion_function = (CPPFunction *)fcn_completion;
#else
rl_attempted_completion_function = fcn_completion;
#endif
orig_completion_append_character = rl_completion_append_character;
orig_basic_word_break_characters = rl_basic_word_break_characters;
+#endif
// Init input file list, open first file
num_files = argc - 1;
Best regards,
Alexei
--
All science is either physics or stamp collecting.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 827 bytes
Desc: Digital signature
Url : http://www.cebix.net/pipermail/ginac-list/attachments/20070131/0479f857/attachment.pgp
More information about the GiNaC-list
mailing list