Diff of /tclreadline.c [07f96d] .. [ebfe07]  Maximize  Restore

  Switch to side-by-side view

--- a/tclreadline.c
+++ b/tclreadline.c
@@ -1,634 +1,212 @@
-
- /* ==================================================================
-    FILE: "/home/joze/src/tclreadline/tclreadline.c"
-    LAST MODIFICATION: "Mit, 10 Jan 2001 06:29:33 +0100 (joze)"
-    (C) 1998 - 2001 by Johannes Zellner, <johannes@zellner.org>
-    $Id$
-    ---
-    tclreadline -- gnu readline for tcl
-    http://www.zellner.org/tclreadline/
-    Copyright (c) 1998 - 2001, Johannes Zellner <johannes@zellner.org>
-    This software is copyright under the BSD license.
-    ================================================================== */  
-
-#ifdef HAVE_CONFIG_H
-#   include "config.h"
-#endif
+/* 
+ * FILE: "/home/joze/tmp/tclreadline/tclreadline.c"
+ * LAST MODIFIED: "Sat Oct 03 03:06:54 1998 (joze)"
+ * (c) 1998 by Johannes Zellner
+ * Johannes.Zellner@physik.uni-karlsruhe.de
+ * $Id$
+ */
 
 #include <tcl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-
-#if defined (READLINE_LIBRARY)
-#   include <readline.h>
-#   include <history.h>
-#else
-#   include <readline/readline.h>
-#   include <readline/history.h>
-#endif
+#include <readline.h>
+#include <history.h>
+
+#define MALLOC(size) Tcl_Alloc ((int) size)
+#define FREE(ptr) if (ptr) Tcl_Free ((char *) ptr)
+
+#define _CMD_SET	(1 << 0)
+#define _CMD_GET	(1 << 1)
+#define _CMD_SUB_GET	(1 << 2)
+
+
+typedef struct cmds_t {
+    struct cmds_t *prev;
+    char **cmd;
+    struct cmds_t *next;
+} cmds_t;
+
+
+#define STRIPLEFT(ptr)          \
+do {                            \
+    char *tmp = ptr;            \
+    while (*tmp && *tmp <= ' ') \
+        tmp ++;                 \
+    strcpy (ptr, tmp);          \
+} while (0)
+
+#define STRIPRIGHT(ptr)                                \
+do {                                                   \
+    char *__tmp__;                                     \
+    for (__tmp__ = strchr (ptr, '\0') - 1;             \
+         __tmp__ >= ptr && *__tmp__ <= ' '; __tmp__--) \
+        *__tmp__ = '\0';                               \
+} while (0)
+
+#define STRIPWHITE(ptr) \
+do {                    \
+    STRIPLEFT (ptr);    \
+    STRIPRIGHT (ptr);   \
+} while (0)
+
+
+
+    /*
+extern char *rl_readline_name = "tclreadline";
+    */
 
 
 /*
- * this prototype is missing
- * in readline.h
+ * forward declarations.
  */
-void rl_extend_line_buffer(int len);
-
-#ifdef EXECUTING_MACRO_HACK
-/**
- * this prototype is private in readline's file `macro.c'.
- * We need it here to decide, if we should read more
- * characters from a macro. Dirty, but it should work.
- */
-extern char* _rl_executing_macro;
-#endif
-
-#include "tclreadline.h"
-static const char* tclrl_library = TCLRL_LIBRARY;
-static const char* tclrl_version_str = TCLRL_VERSION_STR;
-static const char* tclrl_patchlevel_str = TCLRL_PATCHLEVEL_STR;
-
-#define MALLOC(size) Tcl_Alloc((int) size)
-#define FREE(ptr) if (ptr) { Tcl_Free((char*) ptr); ptr = 0; }
-
-enum {
-    _CMD_SET     = (1 << 0),
-    _CMD_GET     = (1 << 1)
-};
-
-
-typedef struct cmds_t {
-    struct cmds_t* prev;
-    char**         cmd;
-    struct cmds_t* next;
-} cmds_t;
-
-
-#define ISWHITE(c) ((' ' == c) || ('\t' == c) || ('\n' == c))
-
-/* forward declarations. */
-static char* stripleft(char* in);
-static char* stripright(char* in);
-static char* stripwhite(char* in);
-static int TclReadlineLineComplete(void);
-static void TclReadlineTerminate(int state);
-static char* TclReadlineQuote(char* text, char* quotechars);
-static int TclReadlineCmd(ClientData clientData, Tcl_Interp *interp, int objc,
-                   Tcl_Obj *CONST objv[]);
-static void TclReadlineReadHandler(ClientData clientData, int mask);
-static void TclReadlineLineCompleteHandler(char* ptr);
-static int TclReadlineInitialize(Tcl_Interp* interp, char* historyfile);
-static int blank_line(char* str);
-static char** TclReadlineCompletion(char* text, int start, int end);
-static char* TclReadline0generator(char* text, int state);
-static char* TclReadlineKnownCommands(char* text, int state, int mode);
-static int TclReadlineParse(char** args, int maxargs, char* buf);
-
-
-enum { 
-    LINE_PENDING = -1,
-    LINE_EOF = (1 << 8),
-    LINE_COMPLETE = (1 << 9)
-};
-
-/**
- * global variables
- */
-static int tclrl_state = TCL_OK;
-static char* tclrl_eof_string = (char*) NULL;
-static char* tclrl_custom_completer = (char*) NULL;
-static char* tclrl_last_line = (char*) NULL;
-static int tclrl_use_builtin_completer = 1;
-static int tclrl_history_length = -1;
-Tcl_Interp* tclrl_interp = (Tcl_Interp*) NULL;
-
-static char* tclrl_license =
-"   Copyright (c) 1998 - 2000, Johannes Zellner <johannes@zellner.org>\n"
-"   All rights reserved.\n"
-"   \n"
-"   Redistribution and use in source and binary forms, with or without\n"
-"   modification, are permitted provided that the following conditions\n"
-"   are met:\n"
-"   \n"
-"     * Redistributions of source code must retain the above copyright\n"
-"       notice, this list of conditions and the following disclaimer.\n"
-"     * Redistributions in binary form must reproduce the above copyright\n"
-"       notice, this list of conditions and the following disclaimer in the\n"
-"       documentation and/or other materials provided with the distribution.\n"
-"     * Neither the name of Johannes Zellner nor the names of contributors\n"
-"       to this software may be used to endorse or promote products derived\n"
-"       from this software without specific prior written permission.\n"
-"       \n"
-"   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR\n"
-"   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n"
-"   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n"
-"   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n"
-"   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n"
-"   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n"
-"   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
-"   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
-
-
-
-static char*
-stripleft(char* in)
-{
-    char* ptr = in;
-    while (*ptr && *ptr <= ' ')
-	ptr++;
-    if (in != ptr)
-	memmove(in, ptr, strlen(ptr) + 1);
-    return in;
-}
-
-static char*
-stripright(char* in)
-{
-    char* ptr;
-    for (ptr = strchr(in, '\0') - 1; ptr >= in && *ptr <= ' '; ptr--)
-	*ptr = '\0';
-    return in;
-}
-
-static char*
-stripwhite(char* in)
-{
-    stripleft(in);
-    stripright(in);
-    return in;
-}
-
-static int
-TclReadlineLineComplete(void)
-{
-    return !(tclrl_state == LINE_PENDING);
-}
-
-static void
-TclReadlineTerminate(int state)
-{
-    tclrl_state = state;
-    rl_callback_handler_remove();
-}
-
-static char*
-TclReadlineQuote(char* text, char* quotechars)
-{
-    char* ptr;
-    char* result_c;
-    int i, len = strlen(quotechars);
-    Tcl_DString result;
-
-    Tcl_DStringInit(&result);
-    for (ptr = text; ptr && *ptr; ptr++) {
-	for (i = 0; i < len; i++) {
-	    if (quotechars[i] == *ptr) {
-		Tcl_DStringAppend(&result, "\\", 1);
-		break;
-	    }
-	}
-	Tcl_DStringAppend(&result, ptr, 1);
-    }
-    result_c = strdup(Tcl_DStringValue(&result));
-    return result_c;
-}
-
-static int TclReadlineCmd(ClientData clientData, Tcl_Interp *interp, int objc,
-			  Tcl_Obj *CONST objv[])
-{
-    int obj_idx, status;
-
-    static char *subCmds[] = {
-	"read", "initialize", "write", "add", "complete",
-	"customcompleter", "builtincompleter", "eofchar",
-	"reset-terminal", "bell", "text", "update",
-	(char *) NULL
-    };
-    enum SubCmdIdx {
-	TCLRL_READ, TCLRL_INITIALIZE, TCLRL_WRITE, TCLRL_ADD, TCLRL_COMPLETE,
-	TCLRL_CUSTOMCOMPLETER, TCLRL_BUILTINCOMPLETER, TCLRL_EOFCHAR,
-	TCLRL_RESET_TERMINAL, TCLRL_BELL, TCLRL_TEXT, TCLRL_UPDATE
-    };
-
-    Tcl_ResetResult(interp); /* clear the result space */
-
-    if (objc < 2) {
-	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
+int	TclReadlineCmd	(ClientData clientData, Tcl_Interp *interp,
+                         int argc, char **argv);
+void	TclReadlineDataAvailableHandler	(ClientData clientData, int mask);
+void	TclReadlineLineCompleteHandler	(char *ptr);
+int	Tclreadline_SafeInit	(Tcl_Interp *interp);
+int	Tclreadline_Init	(Tcl_Interp *interp);
+char	*TclReadlineInitialize	(char *historyfile);
+char	**TclReadlineCompletion	(char *text, int start, int end);
+char	*TclReadline0generator	(char *text, int state);
+char	*TclReadline1generator	(char *text, int state);
+char	*TclReadlineKnownCommands	(char *text, int state, int mode);
+int	TclReadlineEventHook	(void);
+int	TclReadlineParse	(char **args, int maxargs, char *buf);
+
+
+static int line_complete = 0;
+static char *line = (char *) NULL;
+
+
+
+int TclReadlineCmd (clientData, interp, argc, argv)
+    ClientData clientData;	/* Main window associated with interpreter  */
+    Tcl_Interp *interp;		/* Current interpreter                      */
+    int argc;			/* Number of arguments                      */
+    char **argv;		/* Argument strings                         */
+{
+    int		c, length;
+    
+
+    if (argc < 2) {
+	interp->result = "wrong # args";
+	for (c = 0; c < argc; c++)
+	    fprintf (stderr, "argv[%d] = %s\n", c, argv[c]);
 	return TCL_ERROR;
     }
 
-    status = Tcl_GetIndexFromObj
-    (interp, objv[1], subCmds, "option", 0, (int *) &obj_idx);
-
-    if (status != TCL_OK) {
-	return status;
-    }
-
-    switch (obj_idx) {
-
-	case TCLRL_READ:
-
-	    rl_callback_handler_install(
-			       objc == 3 ? Tcl_GetStringFromObj(objv[2], 0)
-			       : "%", TclReadlineLineCompleteHandler);
-
-	    Tcl_CreateFileHandler(0, TCL_READABLE,
-		TclReadlineReadHandler, (ClientData) NULL);
-
-	    /**
-	     * Main Loop.
-	     * XXX each modification of the global variables
-	     *     which terminates the main loop must call
-	     *     rl_callback_handler_remove() to leave
-	     *     readline in a defined state.          XXX
-	     */
-	    tclrl_state = LINE_PENDING;
-
-	    while (!TclReadlineLineComplete()) {
-#ifdef EXECUTING_MACRO_HACK
-		/**
-		 * check first, if more characters are
-		 * available from _rl_executing_macro,
-		 * because Tcl_DoOneEvent() will (naturally)
-		 * not detect this `event'.
-		 */
-		if (_rl_executing_macro)
-		    TclReadlineReadHandler((ClientData) NULL, TCL_READABLE);
-		else
-#endif
-		    Tcl_DoOneEvent(TCL_ALL_EVENTS);
-	    }
-
-	    Tcl_DeleteFileHandler(0);
-
-	    switch (tclrl_state) {
-
-		case LINE_COMPLETE:
-
-		    return TCL_OK;
-		    /* NOTREACHED */
-		    break;
-
-		case LINE_EOF:
-		    if (tclrl_eof_string)
-			return Tcl_Eval(interp, tclrl_eof_string);
-		    else
-			return TCL_OK;
-		    /* NOTREACHED */
-		    break;
-
-		default:
-		    return tclrl_state;
-		    /* NOTREACHED */
-		    break;
-	    }
-	    break;
-
-	case TCLRL_INITIALIZE:
-	    if (3 != objc) {
-		Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
-		return TCL_ERROR;
-	    } else {
-		return TclReadlineInitialize(interp,
-					     Tcl_GetStringFromObj(objv[2], 0));
-	    }
-	    break;
-
-	case TCLRL_WRITE:
-	    if (3 != objc) {
-		Tcl_WrongNumArgs(interp, 2, objv, "historyfile");
-		return TCL_ERROR;
-	    }  else if (write_history(Tcl_GetStringFromObj(objv[2], 0))) {
-		Tcl_AppendResult(interp, "unable to write history to `",
-		    Tcl_GetStringFromObj(objv[2], 0), "'\n", (char*) NULL);
-		return TCL_ERROR;
-	    }
-	    if (tclrl_history_length >= 0) {
-		history_truncate_file(Tcl_GetStringFromObj(objv[2], 0),
-				      tclrl_history_length);
-	    }
-	    return TCL_OK;
-	    break;
-
-	case TCLRL_ADD:
-	    if (3 != objc) {
-		Tcl_WrongNumArgs(interp, 2, objv, "completerLine");
-		return TCL_ERROR;
-	    } else if (TclReadlineKnownCommands(
-				     Tcl_GetStringFromObj(objv[2], 0),
-				     (int) 0, _CMD_SET)) {
-		Tcl_AppendResult(interp, "unable to add command \"",
-		    Tcl_GetStringFromObj(objv[2], 0), "\"\n", (char*) NULL);
-	    }
-	    break;
-
-	case TCLRL_COMPLETE:
-	    if (3 != objc) {
-		Tcl_WrongNumArgs(interp, 2, objv, "line");
-		return TCL_ERROR;
-	    } else if (Tcl_CommandComplete(Tcl_GetStringFromObj(objv[2], 0))) {
-		Tcl_AppendResult(interp, "1", (char*) NULL);
-	    } else {
-		Tcl_AppendResult(interp, "0", (char*) NULL);
-	    }
-	    break;
-
-	case TCLRL_CUSTOMCOMPLETER:
-	    if (objc > 3) {
-		Tcl_WrongNumArgs(interp, 2, objv, "?scriptCompleter?");
-		return TCL_ERROR;
-	    } else if (3 == objc) {
-		if (tclrl_custom_completer)
-		    FREE(tclrl_custom_completer);
-		if (!blank_line(Tcl_GetStringFromObj(objv[2], 0)))
-		    tclrl_custom_completer =
-		         stripwhite(strdup(Tcl_GetStringFromObj(objv[2], 0)));
-	    }
-	    Tcl_AppendResult(interp, tclrl_custom_completer, (char*) NULL);
-	    break;
-
-	case TCLRL_BUILTINCOMPLETER:
-	    if (objc > 3) {
-		Tcl_WrongNumArgs(interp, 2, objv, "?boolean?");
-		return TCL_ERROR;
-	    } else if (3 == objc) {
-		int bool = tclrl_use_builtin_completer;
-		if (TCL_OK != Tcl_GetBoolean(interp,
-					     Tcl_GetStringFromObj(objv[2], 0),
-					     &bool)) {
-		    Tcl_AppendResult(interp,
-			"wrong # args: should be a boolean value.",
-			(char*) NULL);
-		    return TCL_ERROR;
-		} else {
-		    tclrl_use_builtin_completer = bool;
-		}
-	    }
-	    Tcl_AppendResult(interp, tclrl_use_builtin_completer ? "1" : "0",
-		(char*) NULL);
-	    break;
-
-	case TCLRL_EOFCHAR:
-	    if (objc > 3) {
-		Tcl_WrongNumArgs(interp, 2, objv, "?script?");
-		return TCL_ERROR;
-	    } else if (3 == objc) {
-		if (tclrl_eof_string)
-		    FREE(tclrl_eof_string);
-		if (!blank_line(Tcl_GetStringFromObj(objv[2], 0)))
-		    tclrl_eof_string = 
-		        stripwhite(strdup(Tcl_GetStringFromObj(objv[2], 0)));
-	    }
-	    Tcl_AppendResult(interp, tclrl_eof_string, (char*) NULL);
-	    break;
-
-	case TCLRL_RESET_TERMINAL:
-	    /* TODO: add this to the completer */
-	    if (objc > 3) {
-		Tcl_WrongNumArgs(interp, 2, objv, "?terminal-name?");
-		return TCL_ERROR;
-	    }
-	    if (3 == objc) {
-		/*
-		 * - tcl8.0 doesn't have Tcl_GetStringFromObj()
-		 * - rl_reset_terminal() might be defined
-		 *   to take no arguments. This might produce
-		 *   a compiler warning.
-		 */
-		rl_reset_terminal(Tcl_GetStringFromObj(objv[2], 0));
-#ifdef CLEANUP_AFER_SIGNAL
-	    } else {
-		rl_cleanup_after_signal();
-#endif
-	    }
-	    break;
-
-	case TCLRL_BELL:
-	    if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 2, objv, "");
-		return TCL_ERROR;
-	    }
-
-
-	    /*
-	     * ring the terminal bell obeying the current
-	     * settings -- audible or visible.
-	     */
-
-	    ding();
-	    break;
-
-        case TCLRL_UPDATE:
-	    if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 2, objv, "");
-		return TCL_ERROR;
-	    }
-
-	    /* Update the input line */
-
-	    if (rl_line_buffer) {
-	        rl_forced_update_display();
-	    }
-
-	    break;
-
-
-        case TCLRL_TEXT:
-	    if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 2, objv, "");
-		return TCL_ERROR;
-	    }
-
-	    /* Return the current input line */
-	    Tcl_SetObjResult(interp,
-		   Tcl_NewStringObj(rl_line_buffer ? rl_line_buffer : "", -1));
-	    break;
-
-	default:
-	    goto BAD_COMMAND;
-	    /* NOTREACHED */
-	    break;
-    }
+    c = argv[1][0];
+    length = strlen(argv[1]);
+
+
+
+    if (c == 'r'  && strncmp (argv[1], "read", length) == 0) {
+        
+        char *expansion = (char *) NULL;
+        int status;
+        
+        line_complete = 0;
+        rl_callback_handler_install (argc == 3 ? argv[2] : "%",
+                TclReadlineLineCompleteHandler);
+
+        Tcl_CreateFileHandler (0, TCL_READABLE,
+                TclReadlineDataAvailableHandler, (ClientData) NULL);
+
+        while (!line_complete) {
+            Tcl_DoOneEvent (0);
+        }
+
+        Tcl_DeleteFileHandler (0);
+
+        status = history_expand (line, &expansion);
+        if (status == 1)
+            printf ("%s\n", expansion);
+        else if (status == -1)
+            Tcl_AppendResult (interp, "error in history expansion\n",
+                    (char *) NULL);
+        
+        if (expansion && *expansion)
+            add_history (expansion);
+
+        Tcl_AppendResult (interp, expansion, (char *) NULL);
+
+        FREE (line);
+        FREE (expansion);
+        return (TCL_OK);
+
+    }
+    else if (c == 'i'  && strncmp (argv[1], "initialize", length) == 0) {
+        if (argc != 3)
+            goto BAD_COMMAND;
+        else
+            Tcl_AppendResult (interp, TclReadlineInitialize (argv[2]),
+                    (char *) NULL);
+    }
+    else if (c == 'w'  && strncmp (argv[1], "write", length) == 0) {
+        if (argc != 3)
+            goto BAD_COMMAND;
+        else if (write_history (argv[2]))
+            Tcl_AppendResult (interp, "unable to write history to \"",
+                    argv[2], "\"\n", (char *) NULL);
+    }
+    else if (c == 'a'  && strncmp (argv[1], "add", length) == 0) {
+        if (argc != 3)
+            goto BAD_COMMAND;
+        else if (TclReadlineKnownCommands (argv[2], (int) 0, _CMD_SET))
+            Tcl_AppendResult (interp, "unable to add command \"",
+                    argv[2], "\"\n", (char *) NULL);
+    }
+    else
+        goto BAD_COMMAND;
+
 
     return TCL_OK;
 
 BAD_COMMAND:
-    Tcl_AppendResult(interp,
-	"wrong # args: should be \"readline option ?arg ...?\"",
-	(char*) NULL);
+    Tcl_AppendResult (interp,
+            "wrong # args: should be \"readline option ?arg ...?\"",
+	    (char *) NULL);
     return TCL_ERROR;
 
 }
 
-static void
-TclReadlineReadHandler(ClientData clientData, int mask)
-{
-    if (mask & TCL_READABLE) {
-#ifdef EXECUTING_MACRO_HACK
-	do {
-#endif
-	    rl_callback_read_char();
-#ifdef EXECUTING_MACRO_HACK
-	    /**
-	     * check, if we're inside a macro and
-	     * if so, read all macro characters
-	     * until the next eol.
-	     */
-	} while (_rl_executing_macro && !TclReadlineLineComplete());
-#endif
-    }
-}
-
-static void
-TclReadlineLineCompleteHandler(char* ptr)
-{
-    if (!ptr) { /* <c-d> */
-
-	TclReadlineTerminate(LINE_EOF);
-
-    } else {
-
-	/**
-	 * From version 0.9.3 upwards, all lines are
-	 * returned, even empty lines. (Only non-empty
-	 * lines are stuffed in readline's history.)
-	 * The calling script is responsible for handling
-	 * empty strings.
-	 */
-
-	char* expansion = (char*) NULL;
-	int status = history_expand(ptr, &expansion);
-
-	if (status >= 1) {
-	    /* TODO: make this a valid tcl output */
-	    printf("%s\n", expansion);
-	} else if (-1 == status) {
-	    Tcl_AppendResult
-	    (tclrl_interp, "error in history expansion\n", (char*) NULL);
-	    TclReadlineTerminate(TCL_ERROR);
-	}
-	/**
-	 * TODO: status == 2 ...
-	 */
-
-	Tcl_AppendResult(tclrl_interp, expansion, (char*) NULL);
-
-#ifdef EXECUTING_MACRO_HACK
-	/**
-	 * don't stuff macro lines
-	 * into readline's history.
-	 */
-	if(!_rl_executing_macro) {
-#endif
-	    /**
-	     * don't stuff empty lines
-	     * into readline's history.
-	     * don't stuff twice the same
-	     * line into readline's history.
-	     */
-	    if (expansion && *expansion && (!tclrl_last_line ||
-		    strcmp(tclrl_last_line, expansion))) {
-		add_history(expansion);
-	    }
-	    if (tclrl_last_line)
-		free(tclrl_last_line);
-	    tclrl_last_line = strdup(expansion);
-#ifdef EXECUTING_MACRO_HACK
-	}
-#endif
-	/**
-	 * tell the calling routines to terminate.
-	 */
-	TclReadlineTerminate(LINE_COMPLETE);
-	FREE(ptr);
-	FREE(expansion);
-    }
-}
-
-int
-Tclreadline_SafeInit(Tcl_Interp *interp)
-{
-    return Tclreadline_Init(interp);
-}
-
-int
-Tclreadline_Init(Tcl_Interp *interp)
-{
-    int status;
-    Tcl_CreateObjCommand(interp, "::tclreadline::readline", TclReadlineCmd,
-	(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
-    tclrl_interp = interp;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::historyLength",
-		(char*) &tclrl_history_length, TCL_LINK_INT)))
-	return status;
-
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::library",
-		(char*) &tclrl_library, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::version",
-		(char*) &tclrl_version_str, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::patchLevel",
-		(char*) &tclrl_patchlevel_str, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "::tclreadline::license",
-		(char*) &tclrl_license, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_library",
-		(char*) &tclrl_library, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_version",
-		(char*) &tclrl_version_str, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-    if (TCL_OK != (status = Tcl_LinkVar(interp, "tclreadline_patchLevel",
-		(char*) &tclrl_patchlevel_str, TCL_LINK_STRING | TCL_LINK_READ_ONLY)))
-	return status;
-
-    return Tcl_PkgProvide(interp, "tclreadline", (char*)tclrl_version_str);
-}
-
-static int
-TclReadlineInitialize(Tcl_Interp* interp, char* historyfile)
-{
-    rl_readline_name = "tclreadline";
-    /*    rl_special_prefixes = "${\"["; */
-    rl_special_prefixes = "$";
-    /**
-     * default is " \t\n\"\\'`@$><=;|&{("
-     * removed "(" <-- arrays
-     * removed "{" <-- `${' variables 
-     * removed "<" <-- completion lists with < ... >
-     * added "[]"
-     * added "}"
-     */
-    /* 11.Sep rl_basic_word_break_characters = " \t\n\"\\@$}=;|&[]"; */
-    /* besser (11. Sept) 2. (removed \") */
-    /* rl_basic_word_break_characters = " \t\n\\@$}=;|&[]"; */
-    /* besser (11. Sept) 3. (removed }) */
-    rl_basic_word_break_characters = " \t\n\\@$=;|&[]";
-#if 0
-    rl_basic_quote_characters = "\"{"; /* XXX ??? XXX */
-    rl_completer_quote_characters = "\"";
-#endif
+void TclReadlineDataAvailableHandler (ClientData clientData, int mask)
+{
+    if (mask & TCL_READABLE)
+        rl_callback_read_char ();
+}
+
+void TclReadlineLineCompleteHandler (char *ptr)
+{
+    if (ptr && *ptr) {
+        line_complete = 1;
+        rl_callback_handler_remove ();
+        line = ptr;
+    }
+}
+
+
+int Tclreadline_SafeInit (Tcl_Interp *interp)
+{
+    return (Tclreadline_Init (interp));
+}
+
+int Tclreadline_Init (Tcl_Interp *interp)
+{
+    Tcl_CreateCommand (interp, "::tclreadline::readline", TclReadlineCmd,
+	    (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
+
+    return (Tcl_PkgProvide (interp, "tclreadline", TCLREADLINE_VERSION));
+}
+
+char *TclReadlineInitialize (char *historyfile)
+{
+
+    using_history ();
     /*
-       rl_filename_quote_characters
-       = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-       rl_filename_quoting_function
-       = (CPFunction*) TclReadlineFilenameQuotingFunction;
-     */
-    /*
-       rl_filename_quoting_desired = 1;
-     */
-
-    using_history();
-    if (!tclrl_eof_string)
-	tclrl_eof_string = strdup("puts {}; exit");
+    rl_event_hook = TclReadlineEventHook;
+    */
 
     /*
      * try to read historyfile in home
@@ -636,251 +214,193 @@
      * is *not* an error.
      */
     rl_attempted_completion_function = (CPPFunction *) TclReadlineCompletion;
-    if (read_history(historyfile)) {
-	if (write_history(historyfile)) {
-	    Tcl_AppendResult (interp, "warning: `",
-		historyfile, "' is not writable.", (char*) NULL);
-	}
-    }
-    return TCL_OK;
-}
-
-static int
-blank_line(char* str)
-{
-    char* ptr;
-    for (ptr = str; ptr && *ptr; ptr++) {
-	if (!ISWHITE(*ptr))
-	    return 0;
-    }
-    return 1;
-}
-
-static char**
-TclReadlineCompletion(char* text, int start, int end)
-{
-    char** matches = (char**) NULL;
-    int status;
-    rl_completion_append_character = ' '; /* reset, just in case ... */
-
-    if (text && ('!' == text[0]
-	    || (start && rl_line_buffer[start - 1] == '!' /* for '$' */))) {
-	char* expansion = (char*) NULL;
-	int oldlen = strlen(rl_line_buffer);
-	status = history_expand(rl_line_buffer, &expansion);
-	if (status >= 1) {
-	    rl_extend_line_buffer(strlen(expansion) + 1);
-	    strcpy(rl_line_buffer, expansion);
-	    rl_end = strlen(expansion);
-	    rl_point += strlen(expansion) - oldlen;
-	    FREE(expansion);
-	    /*
-	     * TODO:
-	     * because we return 0 == matches,
-	     * the filename completer will still beep.
-	     rl_inhibit_completion = 1;
-	     */
-	    return matches;
-	}
-	FREE(expansion);
-    }
-
-    if (tclrl_custom_completer) {
-	char start_s[BUFSIZ], end_s[BUFSIZ];
-	Tcl_Obj* obj;
-	Tcl_Obj** objv;
-	int objc;
-	int state;
-	char* quoted_text = TclReadlineQuote(text, "$[]{}\"");
-	char* quoted_rl_line_buffer = TclReadlineQuote(rl_line_buffer, "$[]{}\"");
-	sprintf(start_s, "%d", start);
-	sprintf(end_s, "%d", end);
-	Tcl_ResetResult(tclrl_interp); /* clear result space */
-	state = Tcl_VarEval(tclrl_interp, tclrl_custom_completer,
-	    " \"", quoted_text, "\" ", start_s, " ", end_s,
-	    " \"", quoted_rl_line_buffer, "\"", (char*) NULL);
-	FREE(quoted_text);
-	FREE(quoted_rl_line_buffer);
-	if (TCL_OK != state) {
-	    Tcl_AppendResult (tclrl_interp, " `", tclrl_custom_completer,
-		" \"", quoted_text, "\" ", start_s, " ", end_s,
-		" \"", quoted_rl_line_buffer, "\"' failed.", (char*) NULL);
-	    TclReadlineTerminate(state);
-	    return matches;
-	}
-	obj = Tcl_GetObjResult(tclrl_interp);
-	status = Tcl_ListObjGetElements(tclrl_interp, obj, &objc, &objv);
-	if (TCL_OK != status)
-	    return matches;
-
-	if (objc) {
-	    int i, length;
-	    matches = (char**) MALLOC(sizeof(char*) * (objc + 1));
-	    for (i = 0; i < objc; i++) {
-		matches[i] = strdup(Tcl_GetStringFromObj(objv[i], &length));
-		if (1 == objc && !strlen(matches[i])) {
-		    FREE(matches[i]);
-		    FREE(matches);
-		    Tcl_ResetResult(tclrl_interp); /* clear result space */
-		    return (char**) NULL;
-		}
-	    }
-
-	    /**
-	     * this is a special one:
-	     * if the script returns exactly two arguments
-	     * and the second argument is the empty string,
-	     * the rl_completion_append_character is set
-	     * temporaryly to NULL.
-	     */
-	    if (2 == objc && !strlen(matches[1])) {
-		i--;
-		FREE(matches[1]);
-		rl_completion_append_character = '\0';
-	    }
-
-	    matches[i] = (char*) NULL; /* terminate */
-	}
-	Tcl_ResetResult(tclrl_interp); /* clear result space */
-    }
-
-    if (!matches && tclrl_use_builtin_completer) {
-	matches = completion_matches(text, TclReadline0generator);
-    }
-
-    return matches;
-}
-
-static char*
-TclReadline0generator(char* text, int state)
-{
-    return TclReadlineKnownCommands(text, state, _CMD_GET);
-}
-
-static char*
-TclReadlineKnownCommands(char* text, int state, int mode)
+    if (read_history (historyfile))
+        return ("unable to read history file");
+    
+    else
+        return ("");
+}
+
+char **TclReadlineCompletion (char *text, int start, int end)
+{
+    char **matches = (char **) NULL;
+    static char local_line[BUFSIZ];
+       
+    strcpy (local_line, rl_line_buffer);
+    
+    STRIPWHITE (local_line);
+    
+    /*
+    fprintf (stderr, "DEBUG> TclReadlineCompletion: text=|%s|\n", text);
+    fprintf (stderr, "DEBUG> TclReadlineCompletion: start=|%d|\n", start);
+    fprintf (stderr, "DEBUG> TclReadlineCompletion: end=|%d|\n", end);
+    */
+
+    if (start == 0 || !strlen (local_line))
+        matches = completion_matches (text, TclReadline0generator);
+    else
+        matches = completion_matches (text, TclReadline1generator);
+    
+    return (matches);
+}
+
+char *TclReadline0generator (char *text, int state)
+{
+    return (TclReadlineKnownCommands (text, state, _CMD_GET));
+}
+
+char *TclReadline1generator (char *text, int state)
+{
+    return (TclReadlineKnownCommands (text, state, _CMD_SUB_GET));
+}
+
+char *TclReadlineKnownCommands (char *text, int state, int mode)
 {
     static int len;
     static cmds_t *cmds = (cmds_t *) NULL, *new;
-    char* tmp;
-    char* args[256];
+    char *tmp, *args[256];
     int i, argc;
-    char** name;
-
-    char* local_line = (char*) NULL;
-    int sub;
-
-
+    char **name;
+    
     switch (mode) {
-
-	case _CMD_SET:
-
-	    new = (cmds_t *) MALLOC(sizeof(cmds_t));
-	    new->next = (cmds_t *) NULL;
-
-	    if (!cmds) {
-		cmds = new;
-		cmds->prev = new;
-	    }
-	    else {
-		cmds->prev->next = new;
-		cmds->prev = new;
-	    }
-
-	    tmp = strdup(text);
-	    argc = TclReadlineParse(args, sizeof(args), tmp);
-
-	    new->cmd = (char**) MALLOC(sizeof(char*) * (argc + 1));
-
-	    for (i = 0; i < argc; i++)
-		new->cmd[i] = args[i];
-
-	    new->cmd[argc] = (char*) NULL;
-
-	    return (char*) NULL;
-	    break;
-
-
-	case _CMD_GET:
-
-	    local_line = strdup(rl_line_buffer);
-	    sub = TclReadlineParse(args, sizeof(args), local_line);
-
-	    if (0 == sub || (1 == sub && '\0' != text[0])) {
-		if (!state) {
-		    new = cmds;
-		    len = strlen(text);
-		}
-		while (new && (name = new->cmd)) {
-		    new = new->next;
-		    if (!strncmp(name[0], text, len))
-			return strdup(name[0]);
-		}
-		return (char*) NULL;
-	    } else {
-
-		if (!state) {
-
-		    new = cmds;
-		    len = strlen(text);
-
-		    while (new && (name = new->cmd)) {
-			if (!strcmp(name[0], args[0]))
-			    break;
-			new = new->next;
-		    }
-
-		    if (!new)
-			return (char*) NULL;
-
-		    for (i = 0; new->cmd[i]; i++) /* EMPTY */;
-
-		    if (sub < i && !strncmp(new->cmd[sub], text, len))
-			return strdup(new->cmd[sub]);
-		    else
-			return (char*) NULL;
-
-		}
-		else
-		    return (char*) NULL;
-
-		/* NOTREACHED */
-		break;
-	    }
-
-
-	default:
-	    return (char*) NULL;
-	    break;
-
-    }
+        
+        case _CMD_SET:
+
+            new = (cmds_t *) MALLOC (sizeof (cmds_t));
+            new->next = (cmds_t *) NULL;
+
+            if (!cmds) {
+                cmds = new;
+                cmds->prev = new;
+            }
+            else {
+                cmds->prev->next = new;
+                cmds->prev = new;
+            }
+
+            tmp = strdup (text);
+            argc = TclReadlineParse (args, sizeof (args), tmp);
+
+            new->cmd = (char **) MALLOC (sizeof (char *) * (argc + 1));
+
+            for (i = 0; i < argc; i++)
+                new->cmd[i] = args[i];
+
+            new->cmd[argc] = (char *) NULL;
+
+            return (char *) NULL;
+            break;
+
+
+        case _CMD_GET:
+
+
+            if (!state) {
+                new = cmds;
+                len = strlen (text);
+            }
+
+            while (new && (name = new->cmd)) {
+                new = new->next;
+                if (!strncmp (name[0], text, len))
+                    return (strdup (name[0]));
+            }
+
+            return (char *) NULL;
+            break;
+
+        case _CMD_SUB_GET:
+            
+
+            if (!state) {
+
+                int sub;
+                char *local_line = strdup (rl_line_buffer);
+                
+                len = strlen (local_line);
+                STRIPRIGHT (local_line);
+
+                if (len != strlen (local_line))
+                    sub = TclReadlineParse (args, sizeof (args), local_line);
+                else
+                    sub = TclReadlineParse (args,
+                                            sizeof (args), local_line) - 1;
+                
+                new = cmds;
+                len = strlen (text);
+                
+                while (new && (name = new->cmd)) {
+                    if (!strcmp (name[0], args[0]))
+                        break;
+                    new = new->next;
+                }
+                
+                if (!new)
+                    return (char *) NULL;
+
+                for (i = 0; new->cmd[i]; i++) /* EMPTY */;
+
+                if (sub < i && !strncmp (new->cmd[sub], text, len))
+                    return (strdup (new->cmd[sub]));
+                else
+                   return (char *) NULL;
+
+            }
+            else
+                return (char *) NULL;
+
+            /* NOTREACHED */
+            break;
+
+
+        default:
+            return (char *) NULL;
+            break;
+
+    }
+    
     /* NOTREACHED */
-}
-
-static int
-TclReadlineParse(char** args, int maxargs, char* buf)
+
+}
+
+int TclReadlineEventHook (void)
+{
+    Tcl_DoOneEvent (TCL_ALL_EVENTS | TCL_DONT_WAIT);
+    return (TCL_OK);
+}
+
+int TclReadlineParse (char **args, int maxargs, char *buf)
 {
     int nr = 0;
 
     while (*buf != '\0' && nr < maxargs) {
-	/*
-	 * Strip whitespace.  Use nulls, so
-	 * that the previous argument is terminated
-	 * automatically.
-	 */
-	while (ISWHITE(*buf))
-	    *buf++ = '\0';
-
-	if (!(*buf)) /* don't count the terminating NULL */
-	    break;
-
-	*args++ = buf;
-	nr++;
-
-	while (('\0' != *buf) && !ISWHITE(*buf))
-	    buf++;
+        /*
+         * Strip whitespace.  Use nulls, so
+         * that the previous argument is terminated
+         * automatically.
+         */
+        while ((*buf == ' ') || (*buf == '\t') || (*buf == '\n'))
+            *buf++ = '\0';
+
+        if (!(*buf)) /* don't count the terminating NULL */
+            break;
+
+        /* -----------------
+         * Save the argument.
+         * -----------------
+         */
+        *args++ = buf;
+        nr++;
+
+        /* ----------------------
+         * Skip over the argument.
+         * ----------------------
+         */
+        while ((*buf!='\0') && (*buf!=' ') && (*buf!='\t') && (*buf!='\n'))
+            buf++;
     }
 
     *args = '\0';
     return nr;
-}
+
+}