This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/os/readline.c

343 lines
8.1 KiB
C
Raw Normal View History

2015-06-18 01:18:24 +01:00
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
2015-11-10 14:13:56 +00:00
* File: readline.c *
2015-06-18 01:18:24 +01:00
* Last rev: 5/2/88 *
* mods: *
* comments: Input/Output C implemented predicates *
* *
*************************************************************************/
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#endif
/*
2015-11-10 14:13:56 +00:00
* This file includes the interface to the readline library, if installed in the
*system.
2015-06-18 01:18:24 +01:00
*
*/
#include "Yap.h"
#include "Yatom.h"
#include "YapHeap.h"
#include "yapio.h"
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef _WIN32
#if HAVE_IO_H
/* Windows */
#include <io.h>
#endif
#if HAVE_SOCKET
#include <winsock2.h>
#endif
#include <windows.h>
#ifndef S_ISDIR
2015-11-10 14:13:56 +00:00
#define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
2015-06-18 01:18:24 +01:00
#endif
#endif
#include "iopreds.h"
2015-11-09 18:22:43 +00:00
#if defined(USE_READLINE)
2015-06-18 01:18:24 +01:00
#include <readline/readline.h>
#include <readline/history.h>
2015-11-10 14:13:56 +00:00
static int ReadlineGetc(int);
static int ReadlinePutc(int, int);
static const char *history_file;
2015-06-18 01:18:24 +01:00
#define READLINE_OUT_BUF_MAX 256
typedef struct scan_atoms {
Int pos;
Atom atom;
} scan_atoms_t;
2015-11-10 14:13:56 +00:00
static char *atom_enumerate(const char *prefix, int state) {
CACHE_REGS
2015-06-18 01:18:24 +01:00
struct scan_atoms *index;
2015-11-10 14:13:56 +00:00
Atom catom;
Int i;
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
if (!state) {
index = (struct scan_atoms *)malloc(sizeof(struct scan_atoms));
i = 0;
catom = NIL;
} else {
CACHE_REGS
index = LOCAL_search_atoms;
2015-06-18 01:18:24 +01:00
catom = index->atom;
i = index->pos;
}
while (catom != NIL || i < AtomHashTableSize) {
// if ( is_signalled() ) /* Notably allow windows version */
2015-11-10 14:13:56 +00:00
// PL_handle_signals(); /* to break out on ^C */
2015-06-18 01:18:24 +01:00
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);
2015-11-10 14:13:56 +00:00
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;
2015-06-18 01:18:24 +01:00
}
catom = ap->NextOfAE;
READ_UNLOCK(ap->ARWLock);
}
}
LOCAL_search_atoms = NULL;
free(index);
return NULL;
}
2015-11-10 14:13:56 +00:00
static char *atom_generator(const char *prefix, int state) {
char *s = atom_enumerate(prefix, state);
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
if (s) {
char *copy = malloc(1 + strlen(s));
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
if (copy) /* else pretend no completion */
2015-06-18 01:18:24 +01:00
strcpy(copy, s);
s = copy;
}
return s;
}
2015-11-10 14:13:56 +00:00
static char **prolog_completion(const char *text, int start, int end) {
char **matches = NULL;
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
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);
2015-06-18 01:18:24 +01:00
else
2015-11-10 14:13:56 +00:00
matches = rl_completion_matches((char *)text, atom_generator);
2015-06-18 01:18:24 +01:00
return matches;
}
2015-11-10 14:13:56 +00:00
void Yap_ReadlineFlush(int sno) {
if (GLOBAL_Stream[sno].status & Tty_Stream_f &&
2015-06-18 01:18:24 +01:00
GLOBAL_Stream[sno].status & Output_Stream_f) {
2015-11-10 14:13:56 +00:00
rl_redisplay();
2015-06-18 01:18:24 +01:00
}
}
2015-11-10 14:13:56 +00:00
bool Yap_ReadlinePrompt(StreamDesc *s) {
2015-06-18 01:18:24 +01:00
if (s->status & Tty_Stream_f) {
s->stream_getc = ReadlineGetc;
if (GLOBAL_Stream[0].status & Tty_Stream_f &&
2015-11-10 14:13:56 +00:00
s->name == GLOBAL_Stream[0].name)
2015-06-18 01:18:24 +01:00
s->stream_putc = ReadlinePutc;
return true;
}
return false;
}
2015-11-10 14:13:56 +00:00
bool Yap_ReadlineOps(StreamDesc *s) {
2015-06-18 01:18:24 +01:00
if (s->status & Tty_Stream_f) {
if (GLOBAL_Stream[0].status & Tty_Stream_f &&
2015-11-10 14:13:56 +00:00
is_same_tty(s->file, GLOBAL_Stream[0].file))
2015-06-18 01:18:24 +01:00
s->stream_putc = ReadlinePutc;
s->stream_getc = ReadlineGetc;
return true;
}
return false;
}
2015-11-10 14:13:56 +00:00
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();
2015-06-18 01:18:24 +01:00
rl_complete(ignore, key);
2015-11-10 14:13:56 +00:00
if (rl_point > 0 && rl_line_buffer[rl_point - 1] == ' ') {
rl_delete_text(rl_point - 1, rl_point);
2015-06-18 01:18:24 +01:00
rl_point -= 1;
rl_delete(-1, key);
}
rl_end_undo_group();
#endif
} else
rl_complete(ignore, key);
return 0;
}
2015-11-10 14:13:56 +00:00
static void InitReadline(void) {
2015-06-18 01:18:24 +01:00
// don't call readline within emacs
2015-11-10 14:13:56 +00:00
// if (getenv("ËMACS"))
2015-07-06 12:03:16 +01:00
// return;
2015-06-18 01:18:24 +01:00
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();
2015-11-10 14:13:56 +00:00
char *s = Yap_AbsoluteFile("~/.YAP.history", NULL, true);
if (!read_history(s)) {
FILE *f = fopen(s, "w");
if (f) {
fclose(f);
read_history(s);
2015-06-18 01:18:24 +01:00
}
2015-11-10 14:13:56 +00:00
}
2015-06-18 01:18:24 +01:00
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
}
2015-11-10 14:13:56 +00:00
static bool getLine(int inp, int out) {
CACHE_REGS
2015-06-18 01:18:24 +01:00
rl_instream = GLOBAL_Stream[inp].file;
rl_outstream = GLOBAL_Stream[out].file;
const char *myrl_line;
2015-11-10 14:13:56 +00:00
StreamDesc *s = GLOBAL_Stream + inp;
2015-06-18 01:18:24 +01:00
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
2015-07-06 12:03:16 +01:00
fflush(NULL);
2015-11-10 14:13:56 +00:00
myrl_line = readline(LOCAL_Prompt);
2015-06-18 01:18:24 +01:00
} else {
LOCAL_PrologMode |= ConsoleGetcMode;
2015-11-10 14:13:56 +00:00
myrl_line = readline(NULL);
2015-06-18 01:18:24 +01:00
}
/* Do it the gnu way */
if (LOCAL_PrologMode & InterruptMode) {
2015-11-10 14:13:56 +00:00
Yap_external_signal(0, YAP_INT_SIGNAL);
2015-06-18 01:18:24 +01:00
LOCAL_PrologMode &= ~ConsoleGetcMode;
if (LOCAL_PrologMode & AbortMode) {
2015-09-25 10:57:26 +01:00
Yap_Error(ABORT_EVENT, TermNil, "");
2015-06-18 01:18:24 +01:00
LOCAL_ErrorMessage = "Abort";
return console_post_process_eof(s);
}
} else {
LOCAL_PrologMode &= ~ConsoleGetcMode;
}
2015-11-10 14:13:56 +00:00
strncpy(LOCAL_Prompt, RepAtom(LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT);
2015-06-18 01:18:24 +01:00
/* window of vulnerability closed */
if (myrl_line == NULL)
return false;
if (myrl_line[0] != '\0' && myrl_line[1] != '\0') {
2015-11-10 14:13:56 +00:00
add_history(myrl_line);
append_history(1, history_file);
2015-06-18 01:18:24 +01:00
}
2015-11-10 14:13:56 +00:00
s->u.irl.ptr = s->u.irl.buf = myrl_line;
return true;
}
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
static int ReadlinePutc(int sno, int ch) {
2015-06-18 01:18:24 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
#if MAC || _MSC_VER || defined(__MINGW32__)
2015-11-10 14:13:56 +00:00
if (ch == 10) {
putc('\n', s->file);
} else
2015-06-18 01:18:24 +01:00
#endif
2015-11-10 14:13:56 +00:00
putc(ch, s->file);
console_count_output_char(ch, s);
if (ch == 10) {
Yap_ReadlineFlush(sno);
2015-06-18 01:18:24 +01:00
}
2015-11-10 14:13:56 +00:00
return ((int)ch);
2015-06-18 01:18:24 +01:00
}
/*
reading from the console is complicated because we need to
know whether to prompt and so on...
*/
2015-11-10 14:13:56 +00:00
static int ReadlineGetc(int sno) {
2015-06-18 01:18:24 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
int ch;
bool fetch = (s->u.irl.buf == NULL);
2015-11-10 14:13:56 +00:00
if (!fetch || getLine(sno, StdErrStream)) {
const char *ttyptr = s->u.irl.ptr++, *myrl_line = s->u.irl.buf;
2015-06-18 01:18:24 +01:00
ch = *ttyptr;
if (ch == '\0') {
ch = '\n';
2015-11-10 14:13:56 +00:00
free((void *)myrl_line);
s->u.irl.ptr = s->u.irl.buf = NULL;
2015-06-18 01:18:24 +01:00
}
} else {
return EOF;
}
return console_post_process_read_char(ch, s);
}
2015-11-10 14:13:56 +00:00
int Yap_ReadlineForSIGINT(void) {
CACHE_REGS
2015-06-18 01:18:24 +01:00
int ch;
StreamDesc *s = &GLOBAL_Stream[StdInStream];
2015-11-10 14:13:56 +00:00
const char *myrl_line = s->u.irl.buf;
2015-06-18 01:18:24 +01:00
2015-11-10 14:13:56 +00:00
if ((LOCAL_PrologMode & ConsoleGetcMode) && myrl_line != (char *)NULL) {
2015-06-18 01:18:24 +01:00
ch = myrl_line[0];
free((void *)myrl_line);
myrl_line = NULL;
return ch;
} else {
2015-11-10 14:13:56 +00:00
myrl_line = readline("Action (h for help): ");
2015-06-18 01:18:24 +01:00
if (!myrl_line) {
ch = EOF;
return ch;
} else {
ch = myrl_line[0];
free((void *)myrl_line);
myrl_line = NULL;
return ch;
}
}
}
2015-11-10 14:13:56 +00:00
static Int has_readline(USES_REGS1) {
2015-11-09 18:22:43 +00:00
#if USE_READLINE
2015-06-18 01:18:24 +01:00
return true;
#else
return false;
#endif
}
void Yap_InitReadline(void) {
2015-11-10 14:13:56 +00:00
Yap_InitCPred("$has_readline", 0, has_readline,
SafePredFlag | HiddenPredFlag);
2015-06-18 01:18:24 +01:00
InitReadline();
}
#endif