diff --git a/Mmakefile b/Mmakefile index 1598e5bb3..d288f1600 100644 --- a/Mmakefile +++ b/Mmakefile @@ -174,7 +174,7 @@ tags_profiler: #-----------------------------------------------------------------------------# -configure: configure.in +configure: configure.in aclocal.m4 autoconf config.status: configure VERSION diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 000000000..1103943d5 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,63 @@ +#-----------------------------------------------------------------------------# +# Copyright (C) 1999 The University of Melbourne. +# This file may only be copied under the terms of the GNU General +# Public Licence - see the file COPYING in the Mercury distribution. +#-----------------------------------------------------------------------------# +# +# aclocal.m4 +# +# This file contains Mercury-specific autoconf tests. +# +# We ought to move most of the code in configure.in and +# bindist/bindist.configure.in into this file... +# +#-----------------------------------------------------------------------------# +# +# Check for readline and related header files and libraries +# +AC_DEFUN(MERCURY_CHECK_READLINE, +[ + +# check for the readline header files +AC_CHECK_HEADER(readline/readline.h, HAVE_READLINE_READLINE_H=1) +if test "$HAVE_READLINE_READLINE_H" = 1; then + AC_DEFINE(HAVE_READLINE_READLINE) +fi +AC_CHECK_HEADER(readline/history.h, HAVE_READLINE_HISTORY_H=1) +if test "$HAVE_READLINE_HISTORY_H" = 1; then + AC_DEFINE(HAVE_READLINE_HISTORY) +fi + +# check for the readline library +AC_CHECK_LIB(readline, readline, mercury_cv_have_readline=yes, + mercury_cv_have_readline=no) + +# check for the libraries that readline depends on +if test $mercury_cv_have_readline = yes; then + MERCURY_MSG('looking for termcap or curses (needed by readline)...') + AC_CHECK_LIB(termcap, tgetent, mercury_cv_termcap_lib=-ltermcap, + [AC_CHECK_LIB(curses, tgetent, mercury_cv_termcap_lib=-lcurses, + [AC_CHECK_LIB(ncurses, tgetent, mercury_cv_termcap_lib=-lncurses, + mercury_cv_termcap_lib=none)])]) +fi + +# Now figure out whether we can use readline, and define variables according. +# Note that on most systems, we don't actually need the header files in +# order to use readline. (Ain't C grand? ;-). + +if test $mercury_cv_have_readline = no || + test $mercury_cv_termcap_lib = none +then + TERMCAP_LIBRARY="" + READLINE_LIBRARIES="" + AC_DEFINE(MR_NO_USE_READLINE) +else + TERMCAP_LIBRARY="$mercury_cv_termcap_lib" + READLINE_LIBRARIES="-lreadline $TERMCAP_LIBRARY" +fi +AC_SUBST(TERMCAP_LIBRARY) +AC_SUBST(READLINE_LIBRARIES) + +]) + +#-----------------------------------------------------------------------------# diff --git a/configure.in b/configure.in index 6ca63e87d..d54a701d5 100644 --- a/configure.in +++ b/configure.in @@ -245,7 +245,7 @@ AC_CHECK_HEADER(dlfcn.h, HAVE_DLFCN_H=1) if test "$HAVE_DLFCN_H" = 1; then AC_DEFINE(HAVE_DLFCN_H) fi -AC_CHECK_LIB(dl,dlopen,DL_LIBRARY="-ldl",DL_LIBRARY="") +AC_CHECK_LIB(dl, dlopen, DL_LIBRARY="-ldl", DL_LIBRARY="") AC_SUBST(DL_LIBRARY) # temporarily add $DL_LIBRARY to LIBS while we check for dlopen etc. @@ -1814,13 +1814,12 @@ AC_SUBST_FILE(INIT_GRADE_OPTIONS) AC_SUBST_FILE(PARSE_GRADE_OPTIONS) AC_SUBST_FILE(FINAL_GRADE_OPTIONS) - #-----------------------------------------------------------------------------# # # check whether we need -lsocket # -AC_CHECK_LIB(socket,socket,SOCKET_LIBRARY=-lsocket,SOCKET_LIBRARY="") +AC_CHECK_LIB(socket, socket, SOCKET_LIBRARY=-lsocket, SOCKET_LIBRARY="") AC_SUBST(SOCKET_LIBRARY) # @@ -2000,7 +1999,8 @@ fi # restore the previous value of LIBS # LIBS="$save_LIBS" - +#-----------------------------------------------------------------------------# +MERCURY_CHECK_READLINE #-----------------------------------------------------------------------------# AC_OUTPUT(Mmake.common scripts/Mmake.vars scripts/mmc scripts/mprof scripts/mercury_update_interface scripts/mgnuc scripts/ml diff --git a/scripts/ml.in b/scripts/ml.in index 27229d320..a86079c46 100644 --- a/scripts/ml.in +++ b/scripts/ml.in @@ -65,6 +65,8 @@ Debugging options: then you don't need to explicitly specify \`--trace'. Note that \`--trace' is incompatible with \`--static' on some platforms (e.g. sparc-sun-solaris2.6). + -r-, --no-readline + Don't link in the GPL'd GNU Readline Library. -g, --c-debug, --no-strip Do not strip C debugging information. @@ -111,6 +113,9 @@ SOCKET_LIBRARY="@SOCKET_LIBRARY@" # Likewise for -ldl (libdl.so), which is often needed for dlopen() etc. DL_LIBRARY="@DL_LIBRARY@" +# Likewise for -lreadline -l{termcap,curses,ncurses} +READLINE_LIBRARIES="@READLINE_LIBRARIES@" + # If you change these, you will also need to change Mmake.common.in, # scripts/c2init.in, tools/bootcheck, tools/binary, tools/binary_step # and tools/linear. @@ -121,6 +126,7 @@ BROWSER_LIB_NAME=mer_browser verbose=false trace=false +readline=true case $FULLARCH in *-win95|*-winnt|*-win32|*-cygwin32|*-cygwin) # `gcc -s' is broken in gnu-win32 @@ -161,6 +167,12 @@ while : ; do -t-|--no-trace) trace=false ;; + -r|--readline) + readline=true + ;; + -r-|--no-readline) + readline=false + ;; -g-|--no-c-debug|--strip) strip=true ;; @@ -365,13 +377,19 @@ case "$GRADE" in ;; esac +case $readline in + true) ;; + false) READLINE_LIBRARIES= + ;; +esac + case $trace in true) TRACE_LIBS="-l$TRACE_LIB_NAME -l$BROWSER_LIB_NAME \ - $SOCKET_LIBRARY $DL_LIBRARY" + $SOCKET_LIBRARY $DL_LIBRARY $READLINE_LIBRARIES" TRACE_STATIC_LIBS="\ $LIBDIR/$GRADE/$FULLARCH/lib$TRACE_LIB_NAME.a \ $LIBDIR/$GRADE/$FULLARCH/lib$BROWSER_LIB_NAME.a \ - $SOCKET_LIBRARY $DL_LIBRARY" + $SOCKET_LIBRARY $DL_LIBRARY $READLINE_LIBRARIES" ;; false) TRACE_LIBS= TRACE_STATIC_LIBS= diff --git a/trace/Mmakefile b/trace/Mmakefile index 1eaa114ae..fa36e5eb2 100644 --- a/trace/Mmakefile +++ b/trace/Mmakefile @@ -16,13 +16,20 @@ include $(MERCURY_DIR)/Mmake.common CFLAGS = -I$(MERCURY_DIR)/browser -I$(MERCURY_DIR)/library \ -I$(MERCURY_DIR)/runtime -I$(MERCURY_DIR)/boehm_gc \ - -g $(DLL_CFLAGS) $(EXTRA_CFLAGS) + -g $(DLL_CFLAGS) MGNUC = MERCURY_C_INCL_DIR=. $(SCRIPTS_DIR)/mgnuc -MGNUCFLAGS = --no-ansi $(EXTRA_MGNUCFLAGS) $(CFLAGS) +MGNUCFLAGS = --no-ansi MOD2C = $(SCRIPTS_DIR)/mod2c #-----------------------------------------------------------------------------# +# mercury_readline.c #includes the GNU readline headers, which +# lack prototypes and `const', so we need to disable warnings +# when compiling that file. +MGNUCFLAGS-mercury_trace_readline = --no-check + +#-----------------------------------------------------------------------------# + # keep this list in alphabetical order, please HDRS = \ mercury_trace.h \ @@ -32,6 +39,7 @@ HDRS = \ mercury_trace_external.h \ mercury_trace_help.h \ mercury_trace_internal.h \ + mercury_trace_readline.h \ mercury_trace_spy.h \ mercury_trace_tables.h \ mercury_trace_util.h @@ -45,6 +53,7 @@ CFILES = \ mercury_trace_external.c \ mercury_trace_help.c \ mercury_trace_internal.c \ + mercury_trace_readline.c \ mercury_trace_spy.c \ mercury_trace_tables.c diff --git a/trace/mercury_trace_internal.c b/trace/mercury_trace_internal.c index 1a5c64896..c987dccdb 100644 --- a/trace/mercury_trace_internal.c +++ b/trace/mercury_trace_internal.c @@ -20,10 +20,13 @@ #include "mercury_trace_spy.h" #include "mercury_trace_tables.h" #include "mercury_trace_util.h" +#include "mercury_trace_readline.h" #include "mercury_layout_util.h" #include "mercury_array_macros.h" #include "mercury_getopt.h" + #include "browse.h" + #include #include #include @@ -36,9 +39,6 @@ /* The initial size of arrays of words. */ #define MR_INIT_WORD_COUNT 20 -/* The initial size of arrays of characters. */ -#define MR_INIT_BUF_LEN 80 - /* The initial number of lines in documentation entries. */ #define MR_INIT_DOC_CHARS 800 @@ -202,9 +202,8 @@ static void MR_trace_expand_aliases(char ***words, int *word_max, int *word_count); static bool MR_trace_source(const char *filename); static void MR_trace_source_from_open_file(FILE *fp); -static char *MR_trace_getline(const char *prompt, FILE *fp); +static char *MR_trace_getline(const char *prompt); static char *MR_trace_getline_queue(void); -static char *MR_trace_getline_raw(FILE *fp); static void MR_insert_line_at_head(const char *line); static void MR_insert_line_at_tail(const char *line); @@ -262,7 +261,7 @@ MR_trace_event_internal(MR_Trace_Cmd_Info *cmd, bool interactive, jumpaddr = NULL; do { - line = MR_trace_getline("mdb> ", MR_mdb_in); + line = MR_trace_getline("mdb> "); res = MR_trace_debug_cmd(line, cmd, event_info, &event_details, &ancestor_level, &jumpaddr); } while (res == KEEP_INTERACTING); @@ -1303,9 +1302,8 @@ MR_trace_handle_cmd(char **words, int word_count, MR_Trace_Cmd_Info *cmd, if (! confirmed) { char *line2; - line2 = MR_trace_getline( - "mdb: are you sure you want to quit? ", - MR_mdb_in); + line2 = MR_trace_getline("mdb: " + "are you sure you want to quit? "); if (line2 == NULL) { /* This means the user input EOF. */ confirmed = TRUE; @@ -1930,7 +1928,7 @@ MR_trace_read_help_text(void) int i; next_char_slot = 0; - while ((text = MR_trace_getline("cat> ", MR_mdb_in)) != NULL) { + while ((text = MR_trace_getline("cat> ")) != NULL) { if (streq(text, "end")) { free(text); break; @@ -2181,7 +2179,7 @@ MR_trace_source_from_open_file(FILE *fp) { char *line; - while ((line = MR_trace_getline_raw(fp)) != NULL) { + while ((line = MR_trace_readline_raw(fp)) != NULL) { MR_insert_line_at_tail(line); } @@ -2190,14 +2188,15 @@ MR_trace_source_from_open_file(FILE *fp) /* ** If there any lines waiting in the queue, return the first of these. -** If not, print the prompt, read a line from the given file, and return it -** in a malloc'd buffer holding the line (without the final newline). +** If not, print the prompt to MR_mdb_out, read a line from MR_mdb_in, +** and return it in a malloc'd buffer holding the line (without the final +** newline). ** If EOF occurs on a nonempty line, treat the EOF as a newline; if EOF ** occurs on an empty line, return NULL. */ static char * -MR_trace_getline(const char *prompt, FILE *fp) +MR_trace_getline(const char *prompt) { char *line; @@ -2207,10 +2206,8 @@ MR_trace_getline(const char *prompt, FILE *fp) } MR_trace_internal_interacting = TRUE; - fprintf(MR_mdb_out, "%s", prompt); - fflush(MR_mdb_out); - return MR_trace_getline_raw(fp); + return MR_trace_readline(prompt, MR_mdb_in, MR_mdb_out); } /* @@ -2238,40 +2235,6 @@ MR_trace_getline_queue(void) } } -/* -** Read a line from a file, and return a pointer to a malloc'd buffer -** holding the line (without the final newline). If EOF occurs on a -** nonempty line, treat the EOF as a newline; if EOF occurs on an empty -** line, return NULL. -*/ - -static char * -MR_trace_getline_raw(FILE *fp) -{ - char *contents; - int content_max; - int c; - int i; - - contents = NULL; - content_max = 0; - - i = 0; - while ((c = getc(fp)) != EOF && c != '\n') { - MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); - contents[i++] = c; - } - - if (c == '\n' || i > 0) { - MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); - contents[i] = '\0'; - return contents; - } else { - free(contents); - return NULL; - } -} - static void MR_insert_line_at_head(const char *contents) { @@ -2321,7 +2284,7 @@ MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd, /* We try to leave one line for the prompt itself. */ if (MR_scroll_control && MR_scroll_next >= MR_scroll_limit - 1) { try_again: - buf = MR_trace_getline("--more-- ", MR_mdb_in); + buf = MR_trace_getline("--more-- "); if (buf != NULL) { for (i = 0; buf[i] != '\0' && MR_isspace(buf[i]); i++) ; diff --git a/trace/mercury_trace_readline.c b/trace/mercury_trace_readline.c new file mode 100644 index 000000000..898a9362a --- /dev/null +++ b/trace/mercury_trace_readline.c @@ -0,0 +1,104 @@ +/* +** Copyright (C) 1998-1999 The University of Melbourne. +** This file may only be copied under the terms of the GNU Library General +** Public License - see the file COPYING.LIB in the Mercury distribution. +*/ + +/* +** A simple interface to read a line, normally done using GNU readline. +** +** This module is compiled with warnings disabled (mgnuc --no-check), +** since the GNU readline headers don't use prototypes, const, etc. +** +** Main authors: fjh, zs. +*/ + +#include "mercury_imp.h" +#include "mercury_trace_readline.h" +#include "mercury_array_macros.h" +#include "mercury_memory.h" +#include "mercury_std.h" + +#ifndef MR_NO_USE_READLINE + #ifdef HAVE_READLINE_READLINE + #include "readline/readline.h" + #endif + #ifdef HAVE_READLINE_HISTORY + #include "readline/history.h" + #endif +#endif + +#include +#include + +/* The initial size of the array of characters used to hold the line. */ +#define MR_INIT_BUF_LEN 80 + +/* +** Print the prompt to the `out' file, read a line from the `in' file, +** and return it in a malloc'd buffer holding the line (without the final +** newline). +** If EOF occurs on a nonempty line, treat the EOF as a newline; if EOF +** occurs on an empty line, return NULL. +*/ +char * +MR_trace_readline(const char *prompt, FILE *in, FILE *out) +{ + char *line; + +#ifdef MR_NO_USE_READLINE + + fprintf(out, "%s", prompt); + fflush(out); + line = MR_trace_readline_raw(in); + +#else /* use readline */ + + size_t len; + + rl_instream = in; + rl_outstream = out; + + line = readline((char *) prompt); + + if (line != NULL && line[0] != '\0') { + add_history(line); + } + +#endif + + return line; +} + +/* +** Read a line from a file, and return a pointer to a malloc'd buffer +** holding the line (without the final newline). If EOF occurs on a +** nonempty line, treat the EOF as a newline; if EOF occurs on an empty +** line, return NULL. +*/ +char * +MR_trace_readline_raw(FILE *fp) +{ + char *contents; + int content_max; + int c; + int i; + + contents = NULL; + content_max = 0; + + i = 0; + while ((c = getc(fp)) != EOF && c != '\n') { + MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); + contents[i++] = c; + } + + if (c == '\n' || i > 0) { + MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN); + contents[i] = '\0'; + return contents; + } else { + free(contents); + return NULL; + } +}