Basic support for custom completion handlers with the two "standard"

rl_complete() and rl_list_possib().  Simply leave out complete.o from
the default build and in all programs require these two functions to
be supplied.

A better alternative would be to use function pointers and check those
for NULL in the running code.  With this code, and no completion handler
the editline code will die.
This commit is contained in:
Joachim Nilsson 2008-10-02 01:52:40 +02:00
parent 4a3fbd9187
commit 5c9f0047bb
7 changed files with 164 additions and 13 deletions

43
configure vendored
View File

@ -695,6 +695,8 @@ CPP
GREP
EGREP
LIBOBJS
COMPLETE_TRUE
COMPLETE_FALSE
LTLIBOBJS'
ac_subst_files=''
ac_precious_vars='build_alias
@ -1283,6 +1285,7 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
--enable-default-complete Enable default completion handler.
Some influential environment variables:
CC C compiler command
@ -4970,6 +4973,35 @@ fi
done
# Check whether --enable-complete was given.
if test "${enable_complete+set}" = set; then
enableval=$enable_complete;
case "${enableval}" in
yes)
complete=true
;;
no)
complete=false
;;
*)
{ { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-default-complete" >&5
echo "$as_me: error: bad value ${enableval} for --enable-default-complete" >&2;}
{ (exit 1); exit 1; }; }
;;
esac
else
complete=false
fi
if test x$complete = xtrue; then
COMPLETE_TRUE=
COMPLETE_FALSE='#'
else
COMPLETE_TRUE='#'
COMPLETE_FALSE=
fi
ac_config_files="$ac_config_files Makefile src/Makefile include/Makefile man/Makefile examples/Makefile"
cat >confcache <<\_ACEOF
@ -5082,6 +5114,13 @@ echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${COMPLETE_TRUE}" && test -z "${COMPLETE_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"COMPLETE\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
echo "$as_me: error: conditional \"COMPLETE\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
: ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files
@ -5698,10 +5737,12 @@ CPP!$CPP$ac_delim
GREP!$GREP$ac_delim
EGREP!$EGREP$ac_delim
LIBOBJS!$LIBOBJS$ac_delim
COMPLETE_TRUE!$COMPLETE_TRUE$ac_delim
COMPLETE_FALSE!$COMPLETE_FALSE$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 81; then
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 83; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5

View File

@ -40,4 +40,19 @@ AC_PROG_GCC_TRADITIONAL
AC_FUNC_STAT
AC_CHECK_FUNCS([strchr strdup strrchr tcgetattr])
AC_ARG_ENABLE([complete],
[ --enable-default-complete Enable default completion handler.],[
case "${enableval}" in
yes)
complete=true
;;
no)
complete=false
;;
*)
AC_MSG_ERROR([bad value ${enableval} for --enable-default-complete])
;;
esac],[complete=false])
AM_CONDITIONAL([COMPLETE], [test x$complete = xtrue])
AC_OUTPUT(Makefile src/Makefile include/Makefile man/Makefile examples/Makefile)

View File

@ -1,10 +1,10 @@
AUTOMAKE_OPTIONS = foreign
LDADD = $(top_builddir)/src/libedit.a
AM_CFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
# TODO: Port "fileman" example from BSD editline
noinst_PROGRAMS = testit
noinst_PROGRAMS = testit cli
testit_SOURCES = testit.c
#fileman_SOURCES = fileman.c

View File

@ -30,7 +30,7 @@ POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
noinst_PROGRAMS = testit$(EXEEXT)
noinst_PROGRAMS = testit$(EXEEXT) cli$(EXEEXT)
subdir = examples
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -41,6 +41,10 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(noinst_PROGRAMS)
cli_SOURCES = cli.c
cli_OBJECTS = cli.$(OBJEXT)
cli_LDADD = $(LDADD)
cli_DEPENDENCIES = $(top_builddir)/src/libedit.a
am_testit_OBJECTS = testit.$(OBJEXT)
testit_OBJECTS = $(am_testit_OBJECTS)
testit_LDADD = $(LDADD)
@ -52,8 +56,8 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(testit_SOURCES)
DIST_SOURCES = $(testit_SOURCES)
SOURCES = cli.c $(testit_SOURCES)
DIST_SOURCES = cli.c $(testit_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -144,7 +148,7 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign
LDADD = $(top_builddir)/src/libedit.a
AM_CFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
testit_SOURCES = testit.c
all: all-am
@ -182,6 +186,9 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
cli$(EXEEXT): $(cli_OBJECTS) $(cli_DEPENDENCIES)
@rm -f cli$(EXEEXT)
$(LINK) $(cli_OBJECTS) $(cli_LDADD) $(LIBS)
testit$(EXEEXT): $(testit_OBJECTS) $(testit_DEPENDENCIES)
@rm -f testit$(EXEEXT)
$(LINK) $(testit_OBJECTS) $(testit_LDADD) $(LIBS)
@ -192,6 +199,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cli.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testit.Po@am__quote@
.c.o:

78
examples/cli.c Normal file
View File

@ -0,0 +1,78 @@
/* The "testit" micro shell, now with command completion.
* To be able to run, don't "--enable-default-complete".
*/
#include "editline.h"
#include <string.h>
char *list[] = {
"foo ", "bar ", "bsd ", "cli ", "ls ", "cd ", "malloc ", "tee ", NULL
};
/*
** Attempt to complete the pathname, returning an allocated copy.
** Fill in *unique if we completed it, or set it to 0 if ambiguous.
*/
char *rl_complete(char *token, int *match)
{
int i;
int index = -1;
int matchlen = 0;
int count = 0;
for (i = 0; list[i]; i++)
{
int partlen = strlen (token); /* Part of token */
if (!strncmp (list[i], token, partlen))
{
index = i;
matchlen = partlen;
count ++;
}
}
if (count == 1)
{
*match = 1;
return strdup (list[index] + matchlen);
}
return NULL;
}
/*
** Return all possible completions.
*/
int rl_list_possib(char *token, char ***av)
{
int i, num, total = 0;
char **copy;
for (num = 0; list[num]; num++)
;
copy = (char **) malloc (num * sizeof(char *));
for (i = 0; i < num; i++)
{
if (!strncmp (list[i], token, strlen (token)))
{
copy[total] = strdup (list[i]);
total ++;
}
}
*av = copy;
return total;
}
int main(int ac, char *av[])
{
char *line;
char *prompt = "cli> ";
while ((line = readline(prompt)) != NULL) {
(void)printf("\t\t\t|%s|\n", line);
free(line);
}
return 0;
}

View File

@ -2,5 +2,8 @@ AUTOMAKE_OPTIONS = foreign
lib_LIBRARIES = libedit.a
libedit_a_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
libedit_a_SOURCES = editline.c editline.h sysunix.c unix.h
if COMPLETE
# Built-in completion handler.
libedit_a_SOURCES += complete.c
endif

View File

@ -30,6 +30,8 @@ POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
# Built-in completion handler.
@COMPLETE_TRUE@am__append_1 = complete.c
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -52,8 +54,11 @@ AR = ar
ARFLAGS = cru
libedit_a_AR = $(AR) $(ARFLAGS)
libedit_a_LIBADD =
am_libedit_a_OBJECTS = editline.$(OBJEXT) complete.$(OBJEXT) \
sysunix.$(OBJEXT)
am__libedit_a_SOURCES_DIST = editline.c editline.h sysunix.c unix.h \
complete.c
@COMPLETE_TRUE@am__objects_1 = complete.$(OBJEXT)
am_libedit_a_OBJECTS = editline.$(OBJEXT) sysunix.$(OBJEXT) \
$(am__objects_1)
libedit_a_OBJECTS = $(am_libedit_a_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
@ -63,7 +68,7 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libedit_a_SOURCES)
DIST_SOURCES = $(libedit_a_SOURCES)
DIST_SOURCES = $(am__libedit_a_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -154,7 +159,8 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign
lib_LIBRARIES = libedit.a
libedit_a_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
libedit_a_SOURCES = editline.c editline.h sysunix.c unix.h \
$(am__append_1)
all: all-am
.SUFFIXES: