| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | /*  $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 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | 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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | #ifdef __WINDOWS__
 | 
					
						
							| 
									
										
										
										
											2013-01-19 11:47:14 +00:00
										 |  |  | #ifndef __YAP_PROLOG__
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #ifdef WIN64
 | 
					
						
							|  |  |  | #include "config/win64.h"
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #include "config/win32.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-01-19 11:47:14 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-07 10:29:17 -05:00
										 |  |  | #if defined(__CYGWIN__) && defined(__YAP_PROLOG__)
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | /* 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
 | 
					
						
							| 
									
										
										
										
											2013-11-15 01:10:25 +00:00
										 |  |  | #ifdef HAVE_SYS_TIME_H
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #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 ... */
 | 
					
						
							| 
									
										
										
										
											2011-02-17 00:57:49 +00:00
										 |  |  | #ifdef META
 | 
					
						
							|  |  |  | #undef META /* conflict with macports readline */
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #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>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 					/* missing prototypes in older */ | 
					
						
							|  |  |  | 					/* readline.h versions */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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(); | 
					
						
							| 
									
										
										
										
											2011-02-17 00:57:49 +00:00
										 |  |  | #ifdef HAVE_RL_RESET_AFTER_SIGNAL
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  |   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
 | 
					
						
							| 
									
										
										
										
											2011-03-02 23:19:39 +00:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2011-02-17 00:57:49 +00:00
										 |  |  | event_hook(void) | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | { 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 | 
					
						
							| 
									
										
										
										
											2011-02-16 21:11:45 +00:00
										 |  |  | reset_readline(void) | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | { 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; | 
					
						
							|  |  |  |   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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-15 03:13:21 -05:00
										 |  |  | #if HAVE_DECL_RL_EVENT_HOOK_
 | 
					
						
							|  |  |  |       if ( !PL_dispatch(0, PL_DISPATCH_INSTALLED) ) { | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 	rl_event_hook = NULL; | 
					
						
							| 
									
										
										
										
											2014-05-28 00:07:08 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #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(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 10:38:18 +00:00
										 |  |  | #if __YAP_PROLOG__
 | 
					
						
							|  |  |  | 	rl_outstream = stderr; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 	if ( in_readline++ ) | 
					
						
							|  |  |  | 	{ int state = rl_readline_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  rl_clear_pending_input(); | 
					
						
							| 
									
										
										
										
											2011-02-17 00:57:49 +00:00
										 |  |  | #ifdef HAVE_RL_DISCARD_ARGUMENT
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 	  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; | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 	  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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return rval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | prolog_complete(int ignore, int key) | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | { if ( rl_point > 0 && rl_line_buffer[rl_point-1] != ' ' ) | 
					
						
							| 
									
										
										
										
											2014-02-16 13:03:09 +00:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2014-09-15 03:13:21 -05:00
										 |  |  | #if HAVE_DECL_RL_CATCH_SIGNALS_	/* actually version >= 1.2, or true readline */
 | 
					
						
							| 
									
										
										
										
											2014-02-16 13:03:09 +00:00
										 |  |  | 	rl_begin_undo_group(); | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |     rl_complete(ignore, key); | 
					
						
							|  |  |  |     if ( rl_point > 0 && rl_line_buffer[rl_point-1] == ' ' ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       rl_delete_text(rl_point-1, rl_point); | 
					
						
							|  |  |  |       rl_point -= 1; | 
					
						
							|  |  |  |       rl_delete(-1, key); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     rl_end_undo_group(); | 
					
						
							| 
									
										
										
										
											2014-02-16 13:03:09 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |   } else | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  |     rl_complete(ignore, key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char * | 
					
						
							|  |  |  | atom_generator(const char *prefix, int state) | 
					
						
							|  |  |  | { char *s = PL_atom_generator(prefix, state); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ( s ) | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |   { char *copy = malloc(1 + strlen(s)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ( copy )				/* else pretend no completion */ | 
					
						
							|  |  |  |       strcpy(copy, s); | 
					
						
							|  |  |  |     s = copy; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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 */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | For some obscure reasons,  notably  libreadline   6  can  show  very bad | 
					
						
							|  |  |  | interactive behaviour. There is a timeout set   to  100000 (0.1 sec). It | 
					
						
							|  |  |  | isn't particularly clear what this timeout is doing. I _think_ it should | 
					
						
							|  |  |  | be synchronized PL_dispatch_hook(),  and  set  to   0  if  this  hook is | 
					
						
							|  |  |  | non-null. | 
					
						
							|  |  |  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | install_t | 
					
						
							| 
									
										
										
										
											2011-02-16 21:11:45 +00:00
										 |  |  | PL_install_readline(void) | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | { GET_LD | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |   access_level_t alevel; | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef __WINDOWS__
 | 
					
						
							|  |  |  |   if ( !truePrologFlag(PLFLAG_TTY_CONTROL) || !isatty(0) ) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2014-03-13 16:57:21 +00:00
										 |  |  |   // don't allow YAP to run readline under an Eclipse Console
 | 
					
						
							|  |  |  |   if (getenv("EclipseVersion")) | 
					
						
							|  |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |   alevel = setAccessLevel(ACCESS_LEVEL_SYSTEM); | 
					
						
							| 
									
										
										
										
											2014-09-15 03:13:21 -05:00
										 |  |  | #if HAVE_DECL_RL_CATCH_SIGNALS_
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  |   rl_catch_signals = 0; | 
					
						
							| 
									
										
										
										
											2014-02-16 13:03:09 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  |   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
 | 
					
						
							| 
									
										
										
										
											2014-05-28 00:35:50 +01:00
										 |  |  | #ifdef HAVE_RL_COMPLETION_FUNC_T
 | 
					
						
							|  |  |  |   rl_add_defun("prolog-complete", prolog_complete, '\t'); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2014-09-15 03:13:21 -05:00
										 |  |  |   rl_add_defun("prolog-complete", (void *)prolog_complete, '\t'); | 
					
						
							| 
									
										
										
										
											2014-05-28 00:35:50 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | #if HAVE_RL_INSERT_CLOSE
 | 
					
						
							|  |  |  |   rl_add_defun("insert-close", rl_insert_close, ')'); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | #if HAVE_RL_SET_KEYBOARD_INPUT_TIMEOUT	/* see (*) */
 | 
					
						
							|  |  |  |   rl_set_keyboard_input_timeout(20000); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | #define PRED(name, arity, func, attr) \
 | 
					
						
							| 
									
										
										
										
											2015-01-18 01:32:13 +00:00
										 |  |  | 	PL_register_foreign_in_module("system", name, arity, func, attr) | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   PRED("rl_read_init_file", 1, pl_rl_read_init_file, 0); | 
					
						
							|  |  |  |   PRED("rl_add_history",    1, pl_rl_add_history,    PL_FA_NOTRACE); | 
					
						
							|  |  |  |   PRED("rl_write_history",  1, pl_rl_write_history,  0); | 
					
						
							|  |  |  |   PRED("rl_read_history",   1, pl_rl_read_history,   0); | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  |   PL_set_prolog_flag("readline",    PL_BOOL, TRUE); | 
					
						
							|  |  |  |   PL_set_prolog_flag("tty_control", PL_BOOL, TRUE); | 
					
						
							|  |  |  |   PL_license("gpl", "GNU Readline library"); | 
					
						
							| 
									
										
										
										
											2013-01-16 00:19:07 +00:00
										 |  |  |   setAccessLevel(alevel); | 
					
						
							| 
									
										
										
										
											2011-02-16 00:23:58 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else /*HAVE_LIBREADLINE*/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | install_t | 
					
						
							|  |  |  | PL_install_readline(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /*HAVE_LIBREADLINE*/
 |