628 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*  $Id$
 | 
						|
 | 
						|
    Part of SWI-Prolog
 | 
						|
 | 
						|
    Author:        Jan Wielemaker
 | 
						|
    E-mail:        wielemak@science.uva.nl
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 1985-2007, University of Amsterdam
 | 
						|
 | 
						|
    This library is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU Lesser General Public
 | 
						|
    License as published by the Free Software Foundation; either
 | 
						|
    version 2.1 of the License, or (at your option) any later version.
 | 
						|
 | 
						|
    This library 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
 | 
						|
    Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
						|
*/
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
This module binds the  SWI-Prolog  terminal   I/O  to  the  GNU readline
 | 
						|
library. Existence of this  this  library   is  detected  by  configure.
 | 
						|
Binding is achieved by rebinding the read function of the Sinput stream.
 | 
						|
 | 
						|
This  module  only  depends  on  the  public  interface  as  defined  by
 | 
						|
SWI-Prolog.h and SWI-Stream.h
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
 | 
						|
#ifndef __WINDOWS__
 | 
						|
#include "pl-incl.h"
 | 
						|
#endif
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include "SWI-Stream.h"
 | 
						|
#include "SWI-Prolog.h"
 | 
						|
 | 
						|
#if defined(__WINDOWS__) && !defined(__YAP_PROLOG__)
 | 
						|
#ifdef WIN64
 | 
						|
#include "config/win64.h"
 | 
						|
#else
 | 
						|
#include "config/win32.h"
 | 
						|
#endif
 | 
						|
#else
 | 
						|
#include <config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(__CYGWIN__) && defined(__YAP_PROLOG__)
 | 
						|
#include <sys/time.h>
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* Disabled if dmalloc() is used because the readline library is full of
 | 
						|
   leaks and freeing the line returned by readline is considered an
 | 
						|
   error by the dmalloc library
 | 
						|
*/
 | 
						|
 | 
						|
#if defined(HAVE_LIBREADLINE) && defined(HAVE_READLINE_READLINE_H) && !defined(DMALLOC)
 | 
						|
 | 
						|
#ifdef HAVE_UNISTD_H
 | 
						|
#include <unistd.h>
 | 
						|
#endif
 | 
						|
#ifdef HAVE_UXNT_H
 | 
						|
#include <uxnt.h>
 | 
						|
#endif
 | 
						|
#ifdef HAVE_CLOCK
 | 
						|
#include <time.h>
 | 
						|
#endif
 | 
						|
#ifdef __WINDOWS__
 | 
						|
#include <io.h>
 | 
						|
#endif
 | 
						|
#ifdef O_RLC
 | 
						|
#include "win32/console/console.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_RL_INSERT_CLOSE
 | 
						|
#define PAREN_MATCHING 1
 | 
						|
#endif
 | 
						|
 | 
						|
#undef ESC				/* will be redefined ... */
 | 
						|
#ifdef META
 | 
						|
#undef META /* conflict with macports readline */
 | 
						|
#endif
 | 
						|
#include <stdio.h>			/* readline needs it */
 | 
						|
#include <errno.h>
 | 
						|
#define savestring(x)			/* avoid definition there */
 | 
						|
#include <readline/readline.h>
 | 
						|
extern int rl_done;			/* should be in readline.h, but */
 | 
						|
					/* isn't in some versions ... */
 | 
						|
#ifdef HAVE_READLINE_HISTORY_H
 | 
						|
#include <readline/history.h>
 | 
						|
#else
 | 
						|
extern void add_history(char *);	/* should be in readline.h */
 | 
						|
#endif
 | 
						|
					/* missing prototypes in older */
 | 
						|
					/* readline.h versions */
 | 
						|
extern int rl_begin_undo_group(void);	/* delete when conflict arrises! */
 | 
						|
extern int rl_end_undo_group(void);
 | 
						|
extern Function *rl_event_hook;
 | 
						|
 | 
						|
#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
 | 
						|
#define rl_filename_completion_function filename_completion_function
 | 
						|
extern char *filename_completion_function(const char *, int);
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef HAVE_RL_COMPLETION_MATCHES
 | 
						|
#define rl_completion_matches completion_matches
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef RL_STATE_INITIALIZED
 | 
						|
int rl_readline_state = 0;
 | 
						|
#define RL_STATE_INITIALIZED 0
 | 
						|
#endif
 | 
						|
#ifndef HAVE_RL_SET_PROMPT
 | 
						|
#define rl_set_prompt(x) (void)0
 | 
						|
#endif
 | 
						|
#ifndef RL_CLEAR_PENDING_INPUT
 | 
						|
#define rl_clear_pending_input() (void)0
 | 
						|
#endif
 | 
						|
#ifndef RL_CLEANUP_AFTER_SIGNAL
 | 
						|
#define rl_cleanup_after_signal() (void)0
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined(HAVE_RL_DONE) && defined(HAVE_DECL_RL_DONE) && !HAVE_DECL_RL_DONE
 | 
						|
/* surely not provided, so we provide a dummy.  We do this as
 | 
						|
   a global symbol, so if there is one in a dynamic library it
 | 
						|
   will work anyway.
 | 
						|
*/
 | 
						|
int rl_done;
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_read_init_file(term_t file)
 | 
						|
{ char *f;
 | 
						|
 | 
						|
  if ( PL_get_file_name(file, &f, 0) )
 | 
						|
  {
 | 
						|
#ifdef O_XOS
 | 
						|
    char buf[MAXPATHLEN];
 | 
						|
    rl_read_init_file(_xos_os_filename(f, buf));
 | 
						|
#else
 | 
						|
    rl_read_init_file(f);
 | 
						|
#endif
 | 
						|
 | 
						|
    PL_succeed;
 | 
						|
  }
 | 
						|
 | 
						|
  PL_fail;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
This is not really clear using   wide-character  handling. We now assume
 | 
						|
that the readline library can only do   wide characters using UTF-8. Not
 | 
						|
sure this is true, but is certainly covers most installations.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_add_history(term_t text)
 | 
						|
{ GET_LD
 | 
						|
  atom_t a;
 | 
						|
  static atom_t last = 0;
 | 
						|
 | 
						|
  if ( PL_get_atom_ex(text, &a) )
 | 
						|
  { char *txt;
 | 
						|
 | 
						|
    if ( a != last )
 | 
						|
    { if ( last )
 | 
						|
	PL_unregister_atom(last);
 | 
						|
      last = a;
 | 
						|
      PL_register_atom(last);
 | 
						|
 | 
						|
      if ( PL_get_chars(text, &txt, CVT_ATOM|REP_MB|CVT_EXCEPTION) )
 | 
						|
	add_history(txt);
 | 
						|
      else
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_write_history(term_t fn)
 | 
						|
{ char *s;
 | 
						|
  int rc;
 | 
						|
 | 
						|
  if ( !PL_get_file_name(fn, &s, 0) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( (rc=write_history(s)) == 0 )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  errno = rc;
 | 
						|
  return PL_error(NULL, 0, MSG_ERRNO, ERR_FILE_OPERATION,
 | 
						|
		  ATOM_write, ATOM_file, fn);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static foreign_t
 | 
						|
pl_rl_read_history(term_t fn)
 | 
						|
{ char *s;
 | 
						|
  int rc;
 | 
						|
 | 
						|
  if ( !PL_get_file_name(fn, &s, 0) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( (rc=read_history(s)) == 0 )
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  errno = rc;
 | 
						|
  return PL_error(NULL, 0, MSG_ERRNO, ERR_FILE_OPERATION,
 | 
						|
		  ATOM_read, ATOM_file, fn);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static char *my_prompt    = NULL;
 | 
						|
static int   in_readline  = 0;
 | 
						|
static int   sig_at_level = -1;
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Signal handling wrapper.
 | 
						|
 | 
						|
This is tricky. The GNU readline   library places signal handlers around
 | 
						|
the   below   given   signals.   They    re-send   all   signals   using
 | 
						|
kill(getpid(),sig). This goes wrong in our  multi-threaded context as it
 | 
						|
will send signals meant for a thread (using pthread_kill()) to the wrong
 | 
						|
thread. The library time.pl from the  clib   package  was victim of this
 | 
						|
behaviour.
 | 
						|
 | 
						|
We disable readline's signal handling  using   rl_catch_signals  = 0 and
 | 
						|
redo the work ourselves, where we call   the handler directly instead of
 | 
						|
re-sending the signal. See  "info  readline"   for  details  on readline
 | 
						|
signal handling issues.
 | 
						|
 | 
						|
One of the problems is that the signal   handler may not return after ^C
 | 
						|
<abort>. Earlier versions uses PL_abort_handler()   to reset the basics,
 | 
						|
but  since  the  introduction  of  multi-threading  and  exception-based
 | 
						|
aborts, this no longer works. We set sig_at_level to the current nesting
 | 
						|
level if we receive a signal. If this is still the current nesting level
 | 
						|
if we reach readling again we assumed we broke out of the old invocation
 | 
						|
in a non-convential manner.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
typedef struct
 | 
						|
{ int			signo;		/* number of the signal */
 | 
						|
  struct sigaction	old_state;	/* old state for the signal */
 | 
						|
} sigstate;
 | 
						|
 | 
						|
static void rl_sighandler(int sig);
 | 
						|
 | 
						|
static sigstate signals[] =
 | 
						|
{ { SIGINT },
 | 
						|
#ifdef SIGTSTP
 | 
						|
  { SIGTSTP },
 | 
						|
  { SIGTTOU },
 | 
						|
  { SIGTTIN },
 | 
						|
#endif
 | 
						|
  { SIGALRM },
 | 
						|
  { SIGTERM },
 | 
						|
  { SIGQUIT },
 | 
						|
  { -1 },
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
prepare_signals(void)
 | 
						|
{ sigstate *s;
 | 
						|
 | 
						|
  for(s=signals; s->signo != -1; s++)
 | 
						|
  { struct sigaction new;
 | 
						|
 | 
						|
    memset(&new, 0, sizeof(new));
 | 
						|
    new.sa_handler = rl_sighandler;
 | 
						|
    sigaction(s->signo, &new, &s->old_state);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
restore_signals(void)
 | 
						|
{ sigstate *s;
 | 
						|
 | 
						|
  for(s=signals; s->signo != -1; s++)
 | 
						|
  { sigaction(s->signo, &s->old_state, NULL);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
rl_sighandler(int sig)
 | 
						|
{ sigstate *s;
 | 
						|
 | 
						|
  DEBUG(3, Sdprintf("Signal %d in readline\n", sig));
 | 
						|
 | 
						|
  sig_at_level = in_readline;
 | 
						|
 | 
						|
  if ( sig == SIGINT )
 | 
						|
    rl_free_line_state ();
 | 
						|
  rl_cleanup_after_signal ();
 | 
						|
  restore_signals();
 | 
						|
  Sreset();
 | 
						|
 | 
						|
  for(s=signals; s->signo != -1; s++)
 | 
						|
  { if ( s->signo == sig )
 | 
						|
    { void (*func)(int) = s->old_state.sa_handler;
 | 
						|
 | 
						|
      if ( func == SIG_DFL )
 | 
						|
      { unblockSignal(sig);
 | 
						|
	DEBUG(3, Sdprintf("Re-sending signal\n"));
 | 
						|
	raise(sig);			/* was: kill(getpid(), sig); */
 | 
						|
      } else if ( func != SIG_IGN )
 | 
						|
      { (*func)(sig);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG(3, Sdprintf("Resetting after signal\n"));
 | 
						|
  prepare_signals();
 | 
						|
#ifdef HAVE_RL_RESET_AFTER_SIGNAL
 | 
						|
  rl_reset_after_signal ();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static char *
 | 
						|
pl_readline(const char *prompt)
 | 
						|
{ char *line;
 | 
						|
 | 
						|
  prepare_signals();
 | 
						|
  line = readline(prompt);
 | 
						|
  restore_signals();
 | 
						|
 | 
						|
  return line;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
The GNU-readline library is not reentrant (or does not appear to be so).
 | 
						|
Therefore we will detect this and simply   call  the default function if
 | 
						|
reentrant access is tried.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
#ifdef HAVE_RL_EVENT_HOOK
 | 
						|
static int
 | 
						|
input_on_fd(int fd)
 | 
						|
{ fd_set rfds;
 | 
						|
  struct timeval tv;
 | 
						|
 | 
						|
  FD_ZERO(&rfds);
 | 
						|
  FD_SET(fd, &rfds);
 | 
						|
  tv.tv_sec = 0;
 | 
						|
  tv.tv_usec = 0;
 | 
						|
 | 
						|
  return select(fd+1, &rfds, NULL, NULL, &tv) != 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
event_hook(void)
 | 
						|
{ if ( Sinput->position )
 | 
						|
  { int64_t c0 = Sinput->position->charno;
 | 
						|
 | 
						|
    while( !input_on_fd(0) )
 | 
						|
    { PL_dispatch(0, PL_DISPATCH_NOWAIT);
 | 
						|
      if ( Sinput->position->charno != c0 )
 | 
						|
      { if ( my_prompt )
 | 
						|
	  rl_set_prompt(my_prompt);
 | 
						|
	rl_forced_update_display();
 | 
						|
	c0 = Sinput->position->charno;
 | 
						|
	rl_done = FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else
 | 
						|
    PL_dispatch(0, PL_DISPATCH_WAIT);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
reset_readline(void)
 | 
						|
{ if ( in_readline )
 | 
						|
  { restore_signals();
 | 
						|
  }
 | 
						|
 | 
						|
  if ( my_prompt )
 | 
						|
    remove_string(my_prompt);
 | 
						|
  my_prompt = NULL;
 | 
						|
  in_readline = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static ssize_t
 | 
						|
Sread_readline(void *handle, char *buf, size_t size)
 | 
						|
{ GET_LD
 | 
						|
  intptr_t h = (intptr_t)handle;
 | 
						|
  int fd = (int) h;
 | 
						|
  int ttymode = PL_ttymode(Suser_input); /* Not so nice */
 | 
						|
  int rval;
 | 
						|
#ifdef HAVE_CLOCK
 | 
						|
  intptr_t oldclock = clock();
 | 
						|
#endif
 | 
						|
 | 
						|
  PL_write_prompt(ttymode == PL_NOTTY);
 | 
						|
 | 
						|
  switch( ttymode )
 | 
						|
  { case PL_RAWTTY:			/* get_single_char/1 */
 | 
						|
#ifdef O_RLC
 | 
						|
    { int chr = getkey();
 | 
						|
 | 
						|
      if ( chr == 04 || chr == 26 )
 | 
						|
	return 0;			/* EOF */
 | 
						|
 | 
						|
      buf[0] = chr & 0xff;
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    case PL_NOTTY:			/* -tty */
 | 
						|
#ifdef RL_NO_REENTRANT
 | 
						|
    notty:
 | 
						|
#endif
 | 
						|
    { PL_dispatch(fd, PL_DISPATCH_WAIT);
 | 
						|
      rval = read(fd, buf, size);
 | 
						|
      if ( rval > 0 && buf[rval-1] == '\n' )
 | 
						|
	PL_prompt_next(fd);
 | 
						|
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case PL_COOKEDTTY:
 | 
						|
    default:
 | 
						|
    { char *line;
 | 
						|
      const char *prompt;
 | 
						|
 | 
						|
#ifdef RL_NO_REENTRANT
 | 
						|
      if ( in_readline )
 | 
						|
      { Sprintf("[readline disabled] ");
 | 
						|
	PL_write_prompt(TRUE);
 | 
						|
	goto notty;			/* avoid reentrance */
 | 
						|
      }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_RL_EVENT_HOOK
 | 
						|
      if ( PL_dispatch(0, PL_DISPATCH_INSTALLED) )
 | 
						|
	rl_event_hook = event_hook;
 | 
						|
      else
 | 
						|
	rl_event_hook = NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
      prompt = PL_prompt_string(fd);
 | 
						|
      if ( prompt )
 | 
						|
	PL_add_to_protocol(prompt, strlen(prompt));
 | 
						|
 | 
						|
      { char *oldp = my_prompt;
 | 
						|
 | 
						|
	my_prompt = prompt ? store_string(prompt) : (char *)NULL;
 | 
						|
 | 
						|
	if ( sig_at_level == in_readline )
 | 
						|
	{ sig_at_level = -1;
 | 
						|
	  reset_readline();
 | 
						|
	}
 | 
						|
 | 
						|
	if ( in_readline++ )
 | 
						|
	{ int state = rl_readline_state;
 | 
						|
 | 
						|
	  rl_clear_pending_input();
 | 
						|
#ifdef HAVE_RL_DISCARD_ARGUMENT
 | 
						|
	  rl_discard_argument();
 | 
						|
#endif
 | 
						|
	  rl_deprep_terminal();
 | 
						|
	  rl_readline_state = (RL_STATE_INITIALIZED);
 | 
						|
	  line = pl_readline(prompt);
 | 
						|
	  rl_prep_terminal(FALSE);
 | 
						|
	  rl_readline_state = state;
 | 
						|
	  rl_done = 0;
 | 
						|
	} else {
 | 
						|
	  line = pl_readline(prompt);
 | 
						|
	}
 | 
						|
	in_readline--;
 | 
						|
 | 
						|
	if ( my_prompt )
 | 
						|
	  remove_string(my_prompt);
 | 
						|
	my_prompt = oldp;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( line )
 | 
						|
      { size_t l = strlen(line);
 | 
						|
 | 
						|
	if ( l >= size )
 | 
						|
	{ PL_warning("Input line too long");	/* must be tested! */
 | 
						|
	  l = size-1;
 | 
						|
	}
 | 
						|
	memcpy(buf, line, l);
 | 
						|
	buf[l++] = '\n';
 | 
						|
	rval = l;
 | 
						|
 | 
						|
	/*Sdprintf("Read: '%s'\n", line);*/
 | 
						|
	free(line);
 | 
						|
      } else
 | 
						|
	rval = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef HAVE_CLOCK
 | 
						|
  PL_clock_wait_ticks(clock() - oldclock);
 | 
						|
#endif
 | 
						|
 | 
						|
  return rval;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
prolog_complete(int ignore, int key)
 | 
						|
{ 
 | 
						|
  if ( rl_point > 0 && rl_line_buffer[rl_point-1] != ' ' )
 | 
						|
    { rl_begin_undo_group();
 | 
						|
      rl_complete(ignore, key);
 | 
						|
      if ( rl_point > 0 && rl_line_buffer[rl_point-1] == ' ' )
 | 
						|
	{
 | 
						|
#ifdef HAVE_RL_INSERT_CLOSE		/* actually version >= 1.2 */
 | 
						|
	  rl_delete_text(rl_point-1, rl_point);
 | 
						|
	  rl_point -= 1;
 | 
						|
#else
 | 
						|
	  rl_delete(-1, key);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
      rl_end_undo_group();
 | 
						|
    } else
 | 
						|
    rl_complete(ignore, key);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static char *
 | 
						|
atom_generator(const char *prefix, int state)
 | 
						|
{ char *s = PL_atom_generator(prefix, state);
 | 
						|
 | 
						|
  if ( s )
 | 
						|
    return strcpy(PL_malloc(1 + strlen(s)), s);
 | 
						|
 | 
						|
  return s;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static char **
 | 
						|
prolog_completion(const char *text, int start, int end)
 | 
						|
{ char **matches = NULL;
 | 
						|
 | 
						|
  if ( (start == 1 && rl_line_buffer[0] == '[') ||	/* [file */
 | 
						|
       (start == 2 && strncmp(rl_line_buffer, "['", 2)) )
 | 
						|
    matches = rl_completion_matches((char *)text,	/* for pre-4.2 */
 | 
						|
				    rl_filename_completion_function);
 | 
						|
  else
 | 
						|
    matches = rl_completion_matches((char *)text,
 | 
						|
				    atom_generator);
 | 
						|
 | 
						|
  return matches;
 | 
						|
}
 | 
						|
 | 
						|
#undef read				/* UXNT redefinition */
 | 
						|
 | 
						|
install_t
 | 
						|
PL_install_readline(void)
 | 
						|
{ GET_LD
 | 
						|
  bool old;
 | 
						|
 | 
						|
#ifndef __WINDOWS__
 | 
						|
  if ( !truePrologFlag(PLFLAG_TTY_CONTROL) || !isatty(0) )
 | 
						|
    return;
 | 
						|
#endif
 | 
						|
 | 
						|
  old = systemMode(TRUE);
 | 
						|
#if HAVE_DECL_RL_CATCH_SIGNALS
 | 
						|
  rl_catch_signals = 0;
 | 
						|
#endif
 | 
						|
  rl_readline_name = "Prolog";
 | 
						|
  rl_attempted_completion_function = prolog_completion;
 | 
						|
#ifdef __WINDOWS__
 | 
						|
  rl_basic_word_break_characters = "\t\n\"\\'`@$><= [](){}+*!,|%&?";
 | 
						|
#else
 | 
						|
  rl_basic_word_break_characters = ":\t\n\"\\'`@$><= [](){}+*!,|%&?";
 | 
						|
#endif
 | 
						|
  rl_add_defun("prolog-complete", prolog_complete, '\t');
 | 
						|
#if HAVE_RL_INSERT_CLOSE
 | 
						|
  rl_add_defun("insert-close", rl_insert_close, ')');
 | 
						|
#endif
 | 
						|
 | 
						|
  GD->os.rl_functions = *Sinput->functions;	/* structure copy */
 | 
						|
  GD->os.rl_functions.read = Sread_readline;	/* read through readline */
 | 
						|
 | 
						|
  Sinput->functions  = &GD->os.rl_functions;
 | 
						|
  Soutput->functions = &GD->os.rl_functions;
 | 
						|
  Serror->functions  = &GD->os.rl_functions;
 | 
						|
 | 
						|
  PL_register_foreign("rl_read_init_file", 1, pl_rl_read_init_file, 0);
 | 
						|
  PL_register_foreign("rl_add_history",    1, pl_rl_add_history, PL_FA_NOTRACE);
 | 
						|
  PL_register_foreign("rl_write_history",  1, pl_rl_write_history, 0);
 | 
						|
  PL_register_foreign("rl_read_history",   1, pl_rl_read_history, 0);
 | 
						|
  PL_set_prolog_flag("readline",    PL_BOOL, TRUE);
 | 
						|
  PL_set_prolog_flag("tty_control", PL_BOOL, TRUE);
 | 
						|
  PL_license("gpl", "GNU Readline library");
 | 
						|
  systemMode(old);
 | 
						|
}
 | 
						|
 | 
						|
#else /*HAVE_LIBREADLINE*/
 | 
						|
 | 
						|
install_t
 | 
						|
PL_install_readline(void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
#endif /*HAVE_LIBREADLINE*/
 |