/************************************************************************* * * * YAP Prolog * * * * Yap Prolog was developed at NCCUP - Universidade do Porto * * * * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * * * ************************************************************************** * * * File: readline.c * * Last rev: 5/2/88 * * mods: * * comments: Input/Output C implemented predicates * * * *************************************************************************/ #ifdef SCCS static char SccsId[] = "%W% %G%"; #endif /* * This file includes the interface to the readline library, if installed in the system. * */ #include "Yap.h" #include "Yatom.h" #include "YapHeap.h" #include "yapio.h" #include #if HAVE_UNISTD_H #include #endif #if HAVE_STDARG_H #include #endif #ifdef _WIN32 #if HAVE_IO_H /* Windows */ #include #endif #if HAVE_SOCKET #include #endif #include #ifndef S_ISDIR #define S_ISDIR(x) (((x)&_S_IFDIR)==_S_IFDIR) #endif #endif #include "iopreds.h" #if defined(HAVE_LIBREADLINE) #include #include static int ReadlineGetc( int); static int ReadlinePutc( int,int); #define READLINE_OUT_BUF_MAX 256 typedef struct scan_atoms { Int pos; Atom atom; } scan_atoms_t; static char * atom_enumerate(const char *prefix, int state) { CACHE_REGS struct scan_atoms *index; Atom catom; Int i; if ( !state ) { index = (struct scan_atoms *)malloc(sizeof(struct scan_atoms)); i = 0; catom = NIL; } else { CACHE_REGS index = LOCAL_search_atoms; catom = index->atom; i = index->pos; } while (catom != NIL || i < AtomHashTableSize) { // if ( is_signalled() ) /* Notably allow windows version */ // PL_handle_signals(); /* to break out on ^C */ AtomEntry *ap; if (catom == NIL) { /* move away from current hash table line */ READ_LOCK(HashChain[i].AERWLock); catom = HashChain[i].Entry; READ_UNLOCK(HashChain[i].AERWLock); i++; } else { ap = RepAtom(catom); READ_LOCK(ap->ARWLock); if ( strstr( (char *)ap->StrOfAE, prefix) == ( char *)ap->StrOfAE) { index->pos = i; index->atom = ap->NextOfAE; LOCAL_search_atoms = index; READ_UNLOCK(ap->ARWLock); return ap->StrOfAE; } catom = ap->NextOfAE; READ_UNLOCK(ap->ARWLock); } } LOCAL_search_atoms = NULL; free(index); return NULL; } static char * atom_generator(const char *prefix, int state) { char *s = atom_enumerate(prefix, state); if ( s ) { char *copy = malloc(1 + strlen(s)); if ( copy ) /* else pretend no completion */ strcpy(copy, s); s = copy; } 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; } void Yap_ReadlineFlush( int sno ) { if (GLOBAL_Stream[sno].status & Tty_Stream_f && GLOBAL_Stream[sno].status & Output_Stream_f) { rl_redisplay(); } } bool Yap_ReadlinePrompt( StreamDesc * s ) { if (s->status & Tty_Stream_f) { s->stream_getc = ReadlineGetc; if (GLOBAL_Stream[0].status & Tty_Stream_f && s->name == GLOBAL_Stream[0].name) s->stream_putc = ReadlinePutc; return true; } return false; } bool Yap_ReadlineOps( StreamDesc *s ) { if (s->status & Tty_Stream_f) { if (GLOBAL_Stream[0].status & Tty_Stream_f && is_same_tty(s->file,GLOBAL_Stream[0].file)) s->stream_putc = ReadlinePutc; s->stream_getc = ReadlineGetc; return true; } return false; } static int prolog_complete(int ignore, int key) { if ( rl_point > 0 && rl_line_buffer[rl_point-1] != ' ' ) { #if HAVE_DECL_RL_CATCH_SIGNALS_ /* actually version >= 1.2, or true readline */ rl_begin_undo_group(); 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(); #endif } else rl_complete(ignore, key); return 0; } static void InitReadline(void) { // don't call readline within emacs //if (getenv("ËMACS")) // return; GLOBAL_Stream[StdInStream].u.irl.buf = NULL; GLOBAL_Stream[StdInStream].u.irl.ptr = NULL; #if _MSC_VER || defined(__MINGW32__) rl_instream = stdin; #endif rl_outstream = stderr; using_history(); char *s = Yap_AbsoluteFile("~/.YAP.history",NULL); if (!read_history (s)) { FILE *f = fopen(s, "w"); if (f) { fclose(f); read_history (s); } } rl_readline_name = "Prolog"; rl_attempted_completion_function = prolog_completion; #ifdef HAVE_RL_COMPLETION_FUNC_T rl_add_defun("prolog-complete", prolog_complete, '\t'); #else rl_add_defun("prolog-complete", (void *)prolog_complete, '\t'); #endif } static bool getLine( int inp, int out ) { CACHE_REGS rl_instream = GLOBAL_Stream[inp].file; rl_outstream = GLOBAL_Stream[out].file; const char *myrl_line; StreamDesc *s = GLOBAL_Stream+inp; if (!(s->status & Tty_Stream_f)) return false; /* window of vulnerability opened */ LOCAL_PrologMode |= ConsoleGetcMode; if (GLOBAL_Stream[out].linepos == 0) { // no output so far fflush(NULL); myrl_line = readline (LOCAL_Prompt); } else { LOCAL_PrologMode |= ConsoleGetcMode; myrl_line = readline (NULL); } /* Do it the gnu way */ if (LOCAL_PrologMode & InterruptMode) { Yap_external_signal( 0, YAP_INT_SIGNAL ); LOCAL_PrologMode &= ~ConsoleGetcMode; if (LOCAL_PrologMode & AbortMode) { Yap_Error(ABORT_EVENT, TermNil, ""); LOCAL_ErrorMessage = "Abort"; return console_post_process_eof(s); } } else { LOCAL_PrologMode &= ~ConsoleGetcMode; } strncpy (LOCAL_Prompt, RepAtom (LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT); /* window of vulnerability closed */ if (myrl_line == NULL) return false; if (myrl_line[0] != '\0' && myrl_line[1] != '\0') { add_history (myrl_line); write_history ( Yap_AbsoluteFile("~/.YAP.history", NULL)); } s->u.irl.ptr = s->u.irl.buf = myrl_line; return true; } static int ReadlinePutc (int sno, int ch) { StreamDesc *s = &GLOBAL_Stream[sno]; #if MAC || _MSC_VER || defined(__MINGW32__) if (ch == 10) { putc ('\n', s->file); } else #endif putc (ch, s->file); console_count_output_char(ch,s); if (ch == 10) { Yap_ReadlineFlush( sno ); } return ((int) ch); } /* reading from the console is complicated because we need to know whether to prompt and so on... */ static int ReadlineGetc(int sno) { StreamDesc *s = &GLOBAL_Stream[sno]; int ch; bool fetch = (s->u.irl.buf == NULL); if (!fetch || getLine( sno, StdErrStream ) ) { const char *ttyptr = s->u.irl.ptr++, *myrl_line = s->u.irl.buf; ch = *ttyptr; if (ch == '\0') { ch = '\n'; free ((void *)myrl_line); s->u.irl.ptr = s->u.irl.buf = NULL; } } else { return EOF; } return console_post_process_read_char(ch, s); } int Yap_ReadlineForSIGINT(void) { CACHE_REGS int ch; StreamDesc *s = &GLOBAL_Stream[StdInStream]; const char *myrl_line = s->u.irl.buf; if ((LOCAL_PrologMode & ConsoleGetcMode) && myrl_line != (char *) NULL) { ch = myrl_line[0]; free((void *)myrl_line); myrl_line = NULL; return ch; } else { myrl_line = readline ("Action (h for help): "); if (!myrl_line) { ch = EOF; return ch; } else { ch = myrl_line[0]; free((void *)myrl_line); myrl_line = NULL; return ch; } } } static Int has_readline(USES_REGS1) { #if HAVE_LIBREADLINE && HAVE_READLINE_READLINE_H return true; #else return false; #endif } void Yap_InitReadline(void) { Yap_InitCPred ("$has_readline", 0, has_readline, SafePredFlag|HiddenPredFlag); InitReadline(); } #endif