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/console.c

269 lines
6.9 KiB
C
Raw Normal View History

2015-06-18 01:35:39 +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 *
* *
**************************************************************************
* *
2016-04-05 08:12:16 +01:00
* File: readline.c *
2015-06-18 01:35:39 +01:00
* Last rev: 5/2/88 *
* mods: *
* comments: Input/Output C implemented predicates *
* *
*************************************************************************/
2016-01-20 22:18:17 +00:00
/**
* @file console.c
* @author VITOR SANTOS COSTA <vsc@VITORs-MBP.lan>
* @date Wed Jan 20 00:56:23 2016
2016-04-05 08:12:16 +01:00
*
* @brief
*
*
2016-01-20 22:18:17 +00:00
*/
2015-06-18 01:35:39 +01:00
/*
2016-04-05 08:12:16 +01:00
* This file includes the interface to the console IO, tty style. Refer also to
the readline library.
2016-01-20 22:18:17 +00:00
* @defgroup console Support for console-based interaction.
* @ingroup InputOutput
2016-04-05 08:12:16 +01:00
2015-06-18 01:35:39 +01:00
*/
2016-01-31 10:37:41 +00:00
#include "sysbits.h"
2015-06-18 01:35:39 +01:00
2016-04-05 08:12:16 +01:00
static Int prompt(USES_REGS1);
static Int prompt1(USES_REGS1);
2015-06-18 01:35:39 +01:00
2016-04-05 08:12:16 +01:00
static int ConsoleGetc(int);
static int ConsolePutc(int, int);
2015-06-18 01:35:39 +01:00
2016-06-17 17:12:08 +01:00
bool Yap_DoPrompt(StreamDesc *s) {
if (s->status & Tty_Stream_f) {
if (GLOBAL_Stream[0].status & Tty_Stream_f &&
s->name == GLOBAL_Stream[0].name)
return true;
if (GLOBAL_Stream[1].status & Tty_Stream_f &&
s->name == GLOBAL_Stream[1].name)
return true;
if (GLOBAL_Stream[2].status & Tty_Stream_f &&
s->name == GLOBAL_Stream[2].name)
return true;
}
return false;
}
2015-06-18 01:35:39 +01:00
/* check if we read a newline or an EOF */
2016-04-05 08:12:16 +01:00
int console_post_process_read_char(int ch, StreamDesc *s) {
2015-06-18 01:35:39 +01:00
/* the character is also going to be output by the console handler */
2016-04-05 08:12:16 +01:00
console_count_output_char(ch, GLOBAL_Stream + StdErrStream);
2015-06-18 01:35:39 +01:00
if (ch == '\n') {
2016-02-18 12:10:58 +00:00
CACHE_REGS
2015-06-18 01:35:39 +01:00
++s->linecount;
++s->charcount;
s->linepos = 0;
LOCAL_newline = true;
2015-06-18 01:35:39 +01:00
} else {
2016-02-18 12:10:58 +00:00
CACHE_REGS
2015-06-18 01:35:39 +01:00
++s->charcount;
++s->linepos;
LOCAL_newline = false;
2015-06-18 01:35:39 +01:00
}
return ch;
}
2016-04-05 08:12:16 +01:00
bool is_same_tty(FILE *f1, FILE *f2) {
2015-06-18 01:35:39 +01:00
#if HAVE_TTYNAME
2016-04-05 08:12:16 +01:00
return ttyname_r(fileno(f1), LOCAL_FileNameBuf, YAP_FILENAME_MAX - 1) ==
ttyname_r(fileno(f2), LOCAL_FileNameBuf, YAP_FILENAME_MAX - 1);
#endif
2016-01-31 10:37:41 +00:00
// assume a single console, for now
return true;
2015-06-18 01:35:39 +01:00
}
2016-04-05 08:12:16 +01:00
static Int is_same_tty2(USES_REGS1) { /* 'prompt(Atom) */
int sni = Yap_CheckStream(ARG1, Input_Stream_f, "put/2");
int sno = Yap_CheckStream(ARG2, Output_Stream_f, "put/2");
2015-06-18 01:35:39 +01:00
bool out = (GLOBAL_Stream[sni].status & Tty_Stream_f) &&
2016-04-05 08:12:16 +01:00
(GLOBAL_Stream[sno].status & Tty_Stream_f) &&
is_same_tty(GLOBAL_Stream[sno].file, GLOBAL_Stream[sni].file);
2015-06-18 01:35:39 +01:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
UNLOCK(GLOBAL_Stream[sni].streamlock);
return out;
}
2016-04-10 14:21:17 +01:00
void Yap_ConsoleOps(StreamDesc *s) {
2015-06-18 01:35:39 +01:00
/* the putc routine only has to check it is putting out a newline */
s->stream_putc = ConsolePutc;
2016-04-10 14:21:17 +01:00
s->stream_getc = ConsoleGetc;
2016-01-31 10:37:41 +00:00
#if USE_READLINE
2015-06-18 01:35:39 +01:00
/* if a tty have a special routine to call readline */
2016-04-05 08:12:16 +01:00
if ((s->status & Readline_Stream_f) && trueGlobalPrologFlag(READLINE_FLAG)) {
if (Yap_ReadlineOps(s))
return;
}
2016-01-31 10:37:41 +00:00
#endif
2015-06-18 01:35:39 +01:00
}
/* static */
2016-04-05 08:12:16 +01:00
static int ConsolePutc(int sno, int ch) {
2015-06-18 01:35:39 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
2016-04-05 08:12:16 +01:00
if (ch == 10) {
2016-04-18 01:09:10 +01:00
#if MAC || _WIN32
fputs("\n", s->file);
#else
2016-04-05 08:12:16 +01:00
putc('\n', s->file);
2016-04-18 01:09:10 +01:00
#endif
2016-04-05 08:12:16 +01:00
LOCAL_newline = true;
} else
putc(ch, s->file);
2016-04-18 01:09:10 +01:00
#if MAC || _WIN32
fflush( NULL );
#endif
2016-04-05 08:12:16 +01:00
console_count_output_char(ch, s);
return ((int)ch);
2015-06-18 01:35:39 +01:00
}
/* send a prompt, and use the system for internal buffering. Speed is
not of the essence here !!! */
2016-04-05 08:12:16 +01:00
static int ConsoleGetc(int sno) {
2015-06-18 01:35:39 +01:00
CACHE_REGS
register StreamDesc *s = &GLOBAL_Stream[sno];
int ch;
2016-04-05 08:12:16 +01:00
restart:
2015-06-18 01:35:39 +01:00
/* keep the prompt around, just in case, but don't actually
show it in silent mode */
2016-06-17 17:12:08 +01:00
if (Yap_DoPrompt(s)) {
2016-01-31 10:37:41 +00:00
if (!silentMode()) {
2015-06-18 01:35:39 +01:00
char *cptr = LOCAL_Prompt, ch;
2016-06-17 17:12:08 +01:00
/* use the default routine */
2015-06-18 01:35:39 +01:00
while ((ch = *cptr++) != '\0') {
2016-04-05 08:12:16 +01:00
GLOBAL_Stream[StdErrStream].stream_putc(StdErrStream, ch);
2015-06-18 01:35:39 +01:00
}
}
2016-04-05 08:12:16 +01:00
strncpy(LOCAL_Prompt, (char *)RepAtom(LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT);
2015-06-18 01:35:39 +01:00
LOCAL_newline = FALSE;
}
#if HAVE_SIGINTERRUPT
siginterrupt(SIGINT, TRUE);
#endif
LOCAL_PrologMode |= ConsoleGetcMode;
ch = fgetc(s->file);
#if HAVE_SIGINTERRUPT
siginterrupt(SIGINT, FALSE);
#endif
if (LOCAL_PrologMode & InterruptMode) {
2016-04-05 08:12:16 +01:00
Yap_external_signal(0, YAP_INT_SIGNAL);
2015-06-18 01:35:39 +01:00
LOCAL_PrologMode &= ~ConsoleGetcMode;
LOCAL_newline = TRUE;
if (LOCAL_PrologMode & AbortMode) {
2015-09-25 10:57:26 +01:00
Yap_Error(ABORT_EVENT, TermNil, "");
2015-06-18 01:35:39 +01:00
LOCAL_ErrorMessage = "Abort";
return EOF;
2015-06-18 01:35:39 +01:00
}
goto restart;
} else {
LOCAL_PrologMode &= ~ConsoleGetcMode;
}
if (ch == EOF)
2016-04-05 08:12:16 +01:00
return EOF;
return ch;
2015-06-18 01:35:39 +01:00
}
2016-01-20 22:18:17 +00:00
/** @pred prompt1(+ _A__)
Changes YAP input prompt for the .
*/
2015-06-18 01:35:39 +01:00
2016-04-05 08:12:16 +01:00
static Int prompt1(USES_REGS1) { /* prompt1(Atom) */
2015-06-18 01:35:39 +01:00
Term t = Deref(ARG1);
Atom a;
2016-04-05 08:12:16 +01:00
if (IsVarTerm(t) || !IsAtomTerm(t))
return (FALSE);
LOCAL_AtPrompt = a = AtomOfTerm(t);
if (strlen((char *)RepAtom(a)->StrOfAE) > MAX_PROMPT) {
Yap_Error(SYSTEM_ERROR_INTERNAL, t, "prompt %s is too long",
RepAtom(a)->StrOfAE);
2015-06-18 01:35:39 +01:00
return (FALSE);
}
2016-04-05 08:12:16 +01:00
strncpy(LOCAL_Prompt, (char *)RepAtom(a)->StrOfAE, MAX_PROMPT);
2015-06-18 01:35:39 +01:00
return (TRUE);
}
2016-01-20 22:18:17 +00:00
/** @pred prompt(- _A_,+ _B_)
2015-06-18 01:35:39 +01:00
2016-04-05 08:12:16 +01:00
Changes YAP input prompt from _A_ to _B_, active on *next* standard input
interaction.
2016-01-20 22:18:17 +00:00
*/
2016-04-05 08:12:16 +01:00
static Int prompt(USES_REGS1) { /* prompt(Old,New) */
Term t = Deref(ARG2);
2015-06-18 01:35:39 +01:00
Atom a;
2016-04-05 08:12:16 +01:00
if (!Yap_unify_constant(ARG1, MkAtomTerm(LOCAL_AtPrompt)))
2015-06-18 01:35:39 +01:00
return (FALSE);
2016-04-05 08:12:16 +01:00
if (IsVarTerm(t) || !IsAtomTerm(t))
2015-06-18 01:35:39 +01:00
return (FALSE);
2016-04-05 08:12:16 +01:00
a = AtomOfTerm(t);
if (strlen(RepAtom(a)->StrOfAE) > MAX_PROMPT) {
Yap_Error(SYSTEM_ERROR_INTERNAL, t, "prompt %s is too long",
RepAtom(a)->StrOfAE);
2016-01-20 22:18:17 +00:00
return false;
2015-06-18 01:35:39 +01:00
}
2016-04-05 08:12:16 +01:00
strncpy(LOCAL_Prompt, (char *)RepAtom(LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT);
2015-06-18 01:35:39 +01:00
LOCAL_AtPrompt = a;
return (TRUE);
}
/** @pred ensure_prompting
Make sure we have a prompt at this point, even if we have to
introduce a new line.
*/
2016-04-05 08:12:16 +01:00
static Int ensure_prompting(USES_REGS1) { /* prompt(Old,New) */
if (!LOCAL_newline) {
GLOBAL_Stream[2].stream_wputc(2, 10); // hack!
2016-04-05 08:12:16 +01:00
}
return true;
}
2016-04-05 08:12:16 +01:00
int Yap_GetCharForSIGINT(void) {
CACHE_REGS
2015-06-18 01:35:39 +01:00
int ch;
2016-01-31 10:37:41 +00:00
#if USE_READLINE
2016-04-05 08:12:16 +01:00
if (trueGlobalPrologFlag(READLINE_FLAG) ||
(ch = Yap_ReadlineForSIGINT()) == 0)
2016-01-31 10:37:41 +00:00
#endif
2016-04-05 08:12:16 +01:00
{ /* ask for a new line */
fprintf(stderr, "Action (h for help): ");
ch = getc(stdin);
/* first process up to end of line */
while ((fgetc(stdin)) != '\n')
;
}
2015-06-18 01:35:39 +01:00
LOCAL_newline = TRUE;
2016-05-16 11:21:54 +01:00
fflush(NULL);
2015-06-18 01:35:39 +01:00
return ch;
}
void Yap_InitConsole(void) {
2016-04-05 08:12:16 +01:00
CACHE_REGS
2016-01-31 10:37:41 +00:00
LOCAL_newline = true;
2016-04-05 08:12:16 +01:00
Yap_InitCPred("prompt", 1, prompt1, SafePredFlag | SyncPredFlag);
Yap_InitCPred("prompt1", 1, prompt1, SafePredFlag | SyncPredFlag);
Yap_InitCPred("$is_same_tty", 2, is_same_tty2,
SafePredFlag | SyncPredFlag | HiddenPredFlag);
Yap_InitCPred("prompt", 2, prompt, SafePredFlag | SyncPredFlag);
Yap_InitCPred("$ensure_prompting", 0, ensure_prompting,
SafePredFlag | SyncPredFlag);
2015-06-18 01:35:39 +01:00
}