cd $(dir $@) && autoheader
touch $@
-$(srcdir)/src/client/aclocal.m4: m4/ax_lib_socket_nsl.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
+$(srcdir)/src/client/aclocal.m4: m4/ax_lib_readline.m4 m4/ax_lib_socket_nsl.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
cat $^ >$@
LIBS="$LIBS_SOCKETS $LIBS"
AX_LIB_SOCKET_NSL
LIBS_server="$LIBS"
+AX_LIB_READLINE
### Checks for header files
--- /dev/null
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_lib_readline.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_LIB_READLINE
+#
+# DESCRIPTION
+#
+# Searches for a readline compatible library. If found, defines
+# `HAVE_LIBREADLINE'. If the found library has the `add_history' function,
+# sets also `HAVE_READLINE_HISTORY'. Also checks for the locations of the
+# necessary include files and sets `HAVE_READLINE_H' or
+# `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or
+# 'HAVE_HISTORY_H' if the corresponding include files exists.
+#
+# The libraries that may be readline compatible are `libedit',
+# `libeditline' and `libreadline'. Sometimes we need to link a termcap
+# library for readline to work, this macro tests these cases too by trying
+# to link with `libtermcap', `libcurses' or `libncurses' before giving up.
+#
+# Here is an example of how to use the information provided by this macro
+# to perform the necessary includes or declarations in a C file:
+#
+# #ifdef HAVE_LIBREADLINE
+# # if defined(HAVE_READLINE_READLINE_H)
+# # include <readline/readline.h>
+# # elif defined(HAVE_READLINE_H)
+# # include <readline.h>
+# # else /* !defined(HAVE_READLINE_H) */
+# extern char *readline ();
+# # endif /* !defined(HAVE_READLINE_H) */
+# char *cmdline = NULL;
+# #else /* !defined(HAVE_READLINE_READLINE_H) */
+# /* no readline */
+# #endif /* HAVE_LIBREADLINE */
+#
+# #ifdef HAVE_READLINE_HISTORY
+# # if defined(HAVE_READLINE_HISTORY_H)
+# # include <readline/history.h>
+# # elif defined(HAVE_HISTORY_H)
+# # include <history.h>
+# # else /* !defined(HAVE_HISTORY_H) */
+# extern void add_history ();
+# extern int write_history ();
+# extern int read_history ();
+# # endif /* defined(HAVE_READLINE_HISTORY_H) */
+# /* no history */
+# #endif /* HAVE_READLINE_HISTORY */
+#
+# LICENSE
+#
+# Copyright (c) 2008 Ville Laurikari <vl@iki.fi>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AU_ALIAS([VL_LIB_READLINE], [AX_LIB_READLINE])
+AC_DEFUN([AX_LIB_READLINE], [
+ AC_CACHE_CHECK([for a readline compatible library],
+ ax_cv_lib_readline, [
+ ORIG_LIBS="$LIBS"
+ for readline_lib in readline edit editline; do
+ for termcap_lib in "" termcap curses ncurses; do
+ if test -z "$termcap_lib"; then
+ TRY_LIB="-l$readline_lib"
+ else
+ TRY_LIB="-l$readline_lib -l$termcap_lib"
+ fi
+ LIBS="$ORIG_LIBS $TRY_LIB"
+ AC_TRY_LINK_FUNC(readline, ax_cv_lib_readline="$TRY_LIB")
+ if test -n "$ax_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -n "$ax_cv_lib_readline"; then
+ break
+ fi
+ done
+ if test -z "$ax_cv_lib_readline"; then
+ ax_cv_lib_readline="no"
+ fi
+ LIBS="$ORIG_LIBS"
+ ])
+
+ if test "$ax_cv_lib_readline" != "no"; then
+ LIBS="$LIBS $ax_cv_lib_readline"
+ AC_DEFINE(HAVE_LIBREADLINE, 1,
+ [Define if you have a readline compatible library])
+ AC_CHECK_HEADERS(readline.h readline/readline.h)
+ AC_CACHE_CHECK([whether readline supports history],
+ ax_cv_lib_readline_history, [
+ ax_cv_lib_readline_history="no"
+ AC_TRY_LINK_FUNC(add_history, ax_cv_lib_readline_history="yes")
+ ])
+ if test "$ax_cv_lib_readline_history" = "yes"; then
+ AC_DEFINE(HAVE_READLINE_HISTORY, 1,
+ [Define if your readline library has \`add_history'])
+ AC_CHECK_HEADERS(history.h readline/history.h)
+ fi
+ fi
+])dnl
This requires server version 4.2.21 or later, and a terminal that
understands UTF-8.
.TP
+.B \-H
+Save readline command history to file.
+.IP
+Only available when compiled with readline and history support.
+.TP
.B \-v
Print version information and exit.
.TP
AC_LIBOBJ([w32/w32io])
AC_LIBOBJ([w32/w32sockets])
fi
+AX_LIB_READLINE
### Checks for header files.
#include <string.h>
#ifdef _WIN32
#include <windows.h>
+#include <shlobj.h>
#include "sys/socket.h"
#else
#include <pwd.h>
struct passwd {
char *pw_name;
+ char *pw_dir;
};
static struct passwd *w32_getpw(void);
" -r Restricted mode, no redirections\n"
" -s [HOST:]PORT Specify server HOST and PORT\n"
" -u Use UTF-8\n"
+#ifdef HAVE_READLINE_HISTORY
+ " -H Save readline command history to file\n"
+#endif /* HAVE_READLINE_HISTORY */
" -h display this help and exit\n"
" -v display version information and exit\n",
program_name);
{
int opt;
char *auxfname = NULL;
+ int use_history_file = 0;
int send_kill = 0;
char *host = NULL;
char *port = NULL;
char *country;
char *passwd;
char *uname;
+ char *udir;
char *colon;
int sock;
- while ((opt = getopt(argc, argv, "2:krs:uhv")) != EOF) {
+ while ((opt = getopt(argc, argv, "2:krs:uHhv")) != EOF) {
switch (opt) {
case '2':
auxfname = optarg;
break;
+#ifdef HAVE_READLINE_HISTORY
+ case 'H':
+ use_history_file = 1;
+ break;
+#endif /* HAVE_READLINE_HISTORY */
case 'k':
send_kill = 1;
break;
if (!host)
host = empirehost;
uname = getenv("LOGNAME");
- if (uname == NULL) {
+ udir = getenv("HOME");
+ if (!uname || !udir) {
struct passwd *pwd;
pwd = getpwuid(getuid());
fprintf(stderr, "You don't exist. Go away\n");
exit(1);
}
- uname = pwd->pw_name;
+ if (!uname)
+ uname = pwd->pw_name;
+ if (!udir)
+ udir = pwd->pw_dir;
}
if (*ap) {
fprintf(stderr, "%s: extra operand %s\n", argv[0], *ap);
sock = tcp_connect(host, port);
+ if (use_history_file) {
+ history_file = malloc(1024);
+ strncpy(history_file, udir, 1000);
+ strcat(history_file, "/.empire.history");
+ }
+
if (!login(sock, uname, country, passwd, send_kill, utf8))
exit(1);
#ifdef _WIN32
/*
- * Get Windows user name
+ * Get Windows user name and directory
*/
static struct passwd *
w32_getpw(void)
{
static char unamebuf[128];
+ static char udirbuf[MAX_PATH];
static struct passwd pwd;
DWORD unamesize;
pwd.pw_name = "nobody";
} else
pwd.pw_name = "nobody";
+ if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, udirbuf))
+ && strlen(udirbuf) == 0)
+ pwd.pw_dir = udirbuf;
return &pwd;
}
extern int eight_bit_clean;
extern FILE *auxfp;
extern int restricted;
+extern char *history_file;
#ifdef HAVE_CURSES_TERMINFO
void getsose(void);
#include "ringbuf.h"
#include "secure.h"
+#ifdef HAVE_LIBREADLINE
+# if defined(HAVE_READLINE_READLINE_H)
+# include <readline/readline.h>
+# elif defined(HAVE_READLINE_H)
+# include <readline.h>
+# else /* !defined(HAVE_READLINE_H) */
+extern char *readline ();
+# endif /* !defined(HAVE_READLINE_H) */
+#endif /* HAVE_LIBREADLINE */
+
+#ifdef HAVE_READLINE_HISTORY
+# if defined(HAVE_READLINE_HISTORY_H)
+# include <readline/history.h>
+# elif defined(HAVE_HISTORY_H)
+# include <history.h>
+# else /* !defined(HAVE_HISTORY_H) */
+extern void add_history ();
+extern int write_history ();
+extern int read_history ();
+# endif /* !defined(HAVE_HISTORY_H) */
+#endif /* HAVE_READLINE_HISTORY */
+
#define EOF_COOKIE "ctld\n"
#define INTR_COOKIE "aborted\n"
return n;
}
+char *history_file = NULL;
+#ifdef HAVE_LIBREADLINE
+static char *input_from_rl;
+static int has_rl_input;
+
+static void
+input_handler(char *line)
+{
+ input_from_rl = line;
+ has_rl_input = 1;
+ rl_already_prompted = 1;
+#ifdef HAVE_READLINE_HISTORY
+ if (line && *line)
+ add_history(line);
+#endif /* HAVE_READLINE_HISTORY */
+}
+#endif /* HAVE_LIBREADLINE */
+
/*
* Receive player input from @fd into @inbuf.
* Return 1 on receipt of input, zero on EOF, -1 on error.
{
int n;
int res = 1;
-
- n = ring_from_file(inbuf, fd);
+#ifdef HAVE_LIBREADLINE
+ size_t len;
+
+ if (fd == 0) {
+ if (!has_rl_input)
+ rl_callback_read_char();
+ if (!has_rl_input)
+ return 1;
+ if (input_from_rl) {
+ len = strlen(input_from_rl);
+ n = ring_space(inbuf);
+ assert(n);
+ if (len >= (size_t)n) {
+ ring_putm(inbuf, input_from_rl, n);
+ memmove(input_from_rl, input_from_rl + n, len - n + 1);
+ } else {
+ ring_putm(inbuf, input_from_rl, len);
+ ring_putc(inbuf, '\n');
+ free(input_from_rl);
+ has_rl_input = 0;
+ n = len + 1;
+ }
+ } else
+ n = 0;
+ } else
+#endif
+ n = ring_from_file(inbuf, fd);
if (n < 0)
return -1;
if (n == 0) {
int send_eof; /* need to send EOF_COOKIE */
fd_set rdfd, wrfd;
int n;
+ int ret = -1;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
+#ifdef HAVE_LIBREADLINE
+#ifdef HAVE_READLINE_HISTORY
+ if (history_file)
+ read_history(history_file);
+#endif /* HAVE_READLINE_HISTORY */
+ rl_bind_key('\t', rl_insert); /* Disable tab completion */
+ rl_callback_handler_install("", input_handler);
+#endif /* HAVE_LIBREADLINE */
ring_init(&inbuf);
eof_fd0 = partial_line_sent = send_eof = send_intr = 0;
if (n < 0) {
if (errno != EINTR) {
perror("select");
- return -1;
+ break;
}
}
input_fd = 0;
}
}
-
if (n < 0)
continue;
sigaction(SIGINT, &sa, NULL);
send_intr = 0;
}
- } else
+ } else if (ring_len(&inbuf) > 0)
partial_line_sent = ring_peek(&inbuf, -1) != '\n';
}
n = send_input(sock, &inbuf);
if (n < 0) {
perror("write socket");
- return -1;
+ break;
}
}
n = recv_output(sock);
if (n < 0) {
perror("read socket");
- return -1;
+ break;
+ }
+ if (n == 0) {
+#ifdef HAVE_LIBREADLINE
+#ifdef HAVE_READLINE_HISTORY
+ if (history_file)
+ write_history(history_file);
+#endif /* HAVE_READLINE_HISTORY */
+#endif /* HAVE_LIBREADLINE */
+ ret = 0;
+ break;
}
- if (n == 0)
- return 0;
}
}
+#ifdef HAVE_LIBREADLINE
+ rl_callback_handler_remove();
+#endif
+ return ret;
}
#include "proto.h"
#include "secure.h"
+#ifdef HAVE_LIBREADLINE
+# if defined(HAVE_READLINE_READLINE_H)
+# include <readline/readline.h>
+# elif defined(HAVE_READLINE_H)
+# include <readline.h>
+# endif /* defined(HAVE_READLINE_H) */
+#endif /* HAVE_LIBREADLINE */
+
int eight_bit_clean;
FILE *auxfp;
int restricted;
prompt(int code, char *prompt, char *teles)
{
char *nl;
+ char pr[1024];
nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
- printf("%s%s%s", nl, teles, prompt);
+ snprintf(pr, sizeof(pr), "%s%s", teles, prompt);
+#ifdef HAVE_LIBREADLINE
+ rl_set_prompt(pr);
+ printf("%s", nl);
+ rl_forced_update_display();
+#else /* !HAVE_LIBREADLINE */
+ printf("%s%s", nl, pr);
fflush(stdout);
+#endif /* !HAVE_LIBREADLINE */
if (auxfp) {
fprintf(auxfp, "%s%s%s", nl, teles, prompt);
fflush(auxfp);