From 0ff7e0c998bb4fbc67925be762b528ae6585c4f3 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 1 Oct 2010 10:34:14 +0200 Subject: samba: share readline wrappers among all buildsystems. Guenther --- libcli/smbreadline/readline.m4 | 96 +++++++++++++++++++ libcli/smbreadline/smbreadline.c | 180 +++++++++++++++++++++++++++++++++++ libcli/smbreadline/smbreadline.h | 10 ++ libcli/smbreadline/wscript_build | 8 ++ libcli/smbreadline/wscript_configure | 52 ++++++++++ 5 files changed, 346 insertions(+) create mode 100644 libcli/smbreadline/readline.m4 create mode 100644 libcli/smbreadline/smbreadline.c create mode 100644 libcli/smbreadline/smbreadline.h create mode 100644 libcli/smbreadline/wscript_build create mode 100644 libcli/smbreadline/wscript_configure (limited to 'libcli') diff --git a/libcli/smbreadline/readline.m4 b/libcli/smbreadline/readline.m4 new file mode 100644 index 0000000000..f450cacac9 --- /dev/null +++ b/libcli/smbreadline/readline.m4 @@ -0,0 +1,96 @@ +############################################### +# Readline included by default unless explicitly asked not to +test "${with_readline+set}" != "set" && with_readline=yes + +EXTERNAL_READLINE=no +# test for where we get readline() from +AC_MSG_CHECKING(whether to use readline) +AC_ARG_WITH(readline, +[AS_HELP_STRING([--with-readline[=DIR]], [Look for readline include/libs in DIR (default=auto)])], +[ case "$with_readline" in + yes) + AC_MSG_RESULT(yes) + + AC_CHECK_HEADERS(readline.h history.h readline/readline.h) + AC_CHECK_HEADERS(readline/history.h) + + AC_CHECK_HEADERS(readline.h readline/readline.h,[ + for termlib in ncurses curses termcap terminfo termlib tinfo; do + AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break]) + done + AC_CHECK_LIB(readline, rl_callback_handler_install, + [TERMLIBS="-lreadline $TERMLIBS" + EXTERNAL_READLINE=yes + break], [TERMLIBS=], $TERMLIBS)]) + ;; + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + + # Needed for AC_CHECK_HEADERS and AC_CHECK_LIB to look at + # alternate readline path + _ldflags=${LDFLAGS} + _cppflags=${CPPFLAGS} + + # Add additional search path + LDFLAGS="-L$with_readline/lib $LDFLAGS" + CPPFLAGS="-I$with_readline/include $CPPFLAGS" + + AC_CHECK_HEADERS(readline.h history.h readline/readline.h) + AC_CHECK_HEADERS(readline/history.h) + + AC_CHECK_HEADERS(readline.h readline/readline.h,[ + for termlib in ncurses curses termcap terminfo termlib; do + AC_CHECK_LIB(${termlib}, tgetent, [TERMLIBS="-l${termlib}"; break]) + done + AC_CHECK_LIB(readline, rl_callback_handler_install, + [TERMLDFLAGS="-L$with_readline/lib" + TERMCPPFLAGS="-I$with_readline/include" + LDFLAGS="-L$with_readline/lib $LDFLAGS" + CPPFLAGS="-I$with_readline/include $CPPFLAGS" + TERMLIBS="-lreadline $TERMLIBS" + EXTERNAL_READLINE=yes + break], [TERMLIBS= CPPFLAGS=$_cppflags], $TERMLIBS)]) + + ;; + esac], + AC_MSG_RESULT(no) +) + +# The readline API changed slightly from readline3 to readline4, so +# code will generate warnings on one of them unless we have a few +# special cases. +AC_CHECK_LIB(readline, rl_completion_matches, + [AC_DEFINE(HAVE_NEW_LIBREADLINE, 1, + [Do we have rl_completion_matches?])], + [], + [$TERMLIBS]) + +# not all readline libs have rl_event_hook or history_list +AC_CHECK_DECLS(rl_event_hook, [], [], [ + #include + #include +]) +AC_CHECK_LIB(readline, history_list, + [AC_DEFINE(HAVE_HISTORY_LIST, 1, [Do we have history_list?])], + [], + [$TERMLIBS]) + +AC_CHECK_LIB(readline, add_history, + [AC_DEFINE(HAVE_ADD_HISTORY, 1, [Do we have add_history?])], + [], + [$TERMLIBS]) + +AC_MSG_CHECKING(whether to use extern readline) +if test x"$EXTERNAL_READLINE" = x"yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBREADLINE,1,[Whether the system has readline]) + SMB_SUBSYSTEM(SMBREADLINE, [\$(smbreadlinesrcdir)/smbreadline.o], [READLINE]) + SMB_EXT_LIB(READLINE, [${TERMLIBS}]) + SMB_ENABLE(READLINE,YES) +else + SMB_SUBSYSTEM(SMBREADLINE, [\$(smbreadlinesrcdir)/smbreadline.o], []) + AC_MSG_RESULT(no) +fi diff --git a/libcli/smbreadline/smbreadline.c b/libcli/smbreadline/smbreadline.c new file mode 100644 index 0000000000..f8441ac5a3 --- /dev/null +++ b/libcli/smbreadline/smbreadline.c @@ -0,0 +1,180 @@ +/* + Unix SMB/CIFS implementation. + Samba readline wrapper implementation + Copyright (C) Simo Sorce 2001 + Copyright (C) Andrew Tridgell 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "../lib/util/select.h" +#include "system/filesys.h" +#include "system/select.h" +#include "system/readline.h" +#include "libcli/smbreadline/smbreadline.h" + +#undef malloc + +#ifdef HAVE_LIBREADLINE +# ifdef HAVE_READLINE_READLINE_H +# include +# ifdef HAVE_READLINE_HISTORY_H +# include +# endif +# else +# ifdef HAVE_READLINE_H +# include +# ifdef HAVE_HISTORY_H +# include +# endif +# else +# undef HAVE_LIBREADLINE +# endif +# endif +#endif + +static bool smb_rl_done; + +#if HAVE_LIBREADLINE +/* + * MacOS/X does not have rl_done in readline.h, but + * readline.so has it + */ +extern int rl_done; +#endif + +void smb_readline_done(void) +{ + smb_rl_done = true; +#if HAVE_LIBREADLINE + rl_done = 1; +#endif +} + +/**************************************************************************** + Display the prompt and wait for input. Call callback() regularly +****************************************************************************/ + +static char *smb_readline_replacement(const char *prompt, void (*callback)(void), + char **(completion_fn)(const char *text, int start, int end)) +{ + fd_set fds; + char *line = NULL; + struct timeval timeout; + int fd = x_fileno(x_stdin); + char *ret; + + /* Prompt might be NULL in non-interactive mode. */ + if (prompt) { + x_fprintf(x_stdout, "%s", prompt); + x_fflush(x_stdout); + } + + line = (char *)malloc(BUFSIZ); + if (!line) { + return NULL; + } + + while (!smb_rl_done) { + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(fd,&fds); + + if (sys_select_intr(fd+1,&fds,NULL,NULL,&timeout) == 1) { + ret = x_fgets(line, BUFSIZ, x_stdin); + if (ret == 0) { + SAFE_FREE(line); + } + return ret; + } + if (callback) { + callback(); + } + } + SAFE_FREE(line); + return NULL; +} + +/**************************************************************************** + Display the prompt and wait for input. Call callback() regularly. +****************************************************************************/ + +char *smb_readline(const char *prompt, void (*callback)(void), + char **(completion_fn)(const char *text, int start, int end)) +{ + char *ret; + bool interactive; + + interactive = isatty(x_fileno(x_stdin)) || getenv("CLI_FORCE_INTERACTIVE"); + if (!interactive) { + return smb_readline_replacement(NULL, callback, completion_fn); + } + +#if HAVE_LIBREADLINE + + /* Aargh! Readline does bizzare things with the terminal width + that mucks up expect(1). Set CLI_NO_READLINE in the environment + to force readline not to be used. */ + + if (getenv("CLI_NO_READLINE")) + return smb_readline_replacement(prompt, callback, completion_fn); + + if (completion_fn) { + /* The callback prototype has changed slightly between + different versions of Readline, so the same function + works in all of them to date, but we get compiler + warnings in some. */ + rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn; + } + +#if HAVE_DECL_RL_EVENT_HOOK + if (callback) + rl_event_hook = (Function *)callback; +#endif + ret = readline(prompt); + if (ret && *ret) + add_history(ret); + +#else + ret = smb_readline_replacement(prompt, callback, completion_fn); +#endif + + return ret; +} + +/**************************************************************************** + * return line buffer text + ****************************************************************************/ +const char *smb_readline_get_line_buffer(void) +{ +#if defined(HAVE_LIBREADLINE) + return rl_line_buffer; +#else + return NULL; +#endif +} + + +/**************************************************************************** + * set completion append character + ***************************************************************************/ +void smb_readline_ca_char(char c) +{ +#if defined(HAVE_LIBREADLINE) + rl_completion_append_character = c; +#endif +} diff --git a/libcli/smbreadline/smbreadline.h b/libcli/smbreadline/smbreadline.h new file mode 100644 index 0000000000..102106f262 --- /dev/null +++ b/libcli/smbreadline/smbreadline.h @@ -0,0 +1,10 @@ +#ifndef __SMBREADLINE_H__ +#define __SMBREADLINE_H__ + +char *smb_readline(const char *prompt, void (*callback)(void), + char **(completion_fn)(const char *text, int start, int end)); +const char *smb_readline_get_line_buffer(void); +void smb_readline_ca_char(char c); +void smb_readline_done(void); + +#endif /* __SMBREADLINE_H__ */ diff --git a/libcli/smbreadline/wscript_build b/libcli/smbreadline/wscript_build new file mode 100644 index 0000000000..17699eafa2 --- /dev/null +++ b/libcli/smbreadline/wscript_build @@ -0,0 +1,8 @@ +#!/usr/bin/env python + + +termlib=bld.env.READLINE_TERMLIB or '' + +bld.SAMBA_SUBSYSTEM('SMBREADLINE', + source='smbreadline.c', + deps=termlib + ' readline talloc') diff --git a/libcli/smbreadline/wscript_configure b/libcli/smbreadline/wscript_configure new file mode 100644 index 0000000000..cec6526898 --- /dev/null +++ b/libcli/smbreadline/wscript_configure @@ -0,0 +1,52 @@ +#!/usr/bin/env python + + +conf.CHECK_HEADERS('readline.h history.h readline/readline.h readline/history.h') +for termlib in ['ncurses', 'curses', 'termcap', 'terminfo', 'termlib', 'tinfo']: + if conf.CHECK_FUNCS_IN('tgetent', termlib): + conf.env['READLINE_TERMLIB'] = termlib + break + +conf.CHECK_CODE(''' +#ifdef HAVE_READLINE_READLINE_H +# include +# ifdef HAVE_READLINE_HISTORY_H +# include +# endif +#else +# ifdef HAVE_READLINE_H +# include +# ifdef HAVE_HISTORY_H +# include +# endif +# endif +#endif +int main(void) {rl_completion_t f; return 0;} +''', +'HAVE_RL_COMPLETION_FUNC_T', execute=False, addmain=False, +msg='Checking for rl_completion_t') + +conf.CHECK_CODE(''' +#ifdef HAVE_READLINE_READLINE_H +# include +# ifdef HAVE_READLINE_HISTORY_H +# include +# endif +#else +# ifdef HAVE_READLINE_H +# include +# ifdef HAVE_HISTORY_H +# include +# endif +# endif +#endif +int main(void) {CPPFunction f; return 0;} +''', +'HAVE_CPPFUNCTION', execute=False, addmain=False, +msg='Checking for CPPFunction') + +if conf.CHECK_FUNCS_IN('rl_completion_matches', 'readline'): + conf.DEFINE('HAVE_NEW_LIBREADLINE', 1) + +if conf.CHECK_FUNCS_IN('rl_event_hook', 'readline'): + conf.DEFINE('HAVE_HISTORY_LIST', 1) -- cgit