/************************************************************************* * * * 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 * * * *************************************************************************/ /** * @file console.c * @author VITOR SANTOS COSTA * @date Wed Jan 20 00:56:23 2016 * * @brief * * */ /* * This file includes the interface to the console IO, tty style. Refer also to the readline library. * @defgroup console Support for console-based interaction. * @ingroup InputOutput */ #include "sysbits.h" static Int prompt(USES_REGS1); static Int prompt1(USES_REGS1); static int ConsoleGetc(int); static int ConsolePutc(int, int); bool Yap_DoPrompt(StreamDesc *s) { if (s->status & Tty_Stream_f) { if (GLOBAL_Stream[LOCAL_c_input_stream].status & Tty_Stream_f && GLOBAL_Stream[LOCAL_c_error_stream].status & Tty_Stream_f) { return LOCAL_newline; } } return false; } /* check if we read a newline or an EOF */ int console_post_process_read_char(int ch, StreamDesc *s) { /* the character is also going to be output by the console handler */ console_count_output_char(ch, GLOBAL_Stream + LOCAL_c_error_stream); if (ch == '\r') { s->linepos = 0; LOCAL_newline = true; } else if (ch == '\n') { CACHE_REGS ++s->linecount; ++s->charcount; s->linepos = 0; LOCAL_newline = true; } else { CACHE_REGS ++s->charcount; ++s->linepos; LOCAL_newline = false; } return ch; } bool is_same_tty(FILE *f1, FILE *f2) { #if HAVE_TTYNAME return ttyname_r(fileno(f1), LOCAL_FileNameBuf, YAP_FILENAME_MAX - 1) == ttyname_r(fileno(f2), LOCAL_FileNameBuf, YAP_FILENAME_MAX - 1); #endif // assume a single console, for now return true; } 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"); bool out = (GLOBAL_Stream[sni].status & Tty_Stream_f) && (GLOBAL_Stream[sno].status & Tty_Stream_f) && is_same_tty(GLOBAL_Stream[sno].file, GLOBAL_Stream[sni].file); UNLOCK(GLOBAL_Stream[sno].streamlock); UNLOCK(GLOBAL_Stream[sni].streamlock); return out; } void Yap_ConsoleOps(StreamDesc *s) { /* the putc routine only has to check it is putting out a newline */ s->stream_putc = ConsolePutc; s->stream_getc = ConsoleGetc; #if USE_READLINE /* if a tty have a special routine to call readline */ if ((s->status & Readline_Stream_f) && trueGlobalPrologFlag(READLINE_FLAG)) { if (Yap_ReadlineOps(s)) return; } #endif } /* static */ static int ConsolePutc(int sno, int ch) { StreamDesc *s = &GLOBAL_Stream[sno]; if (ch == 10) { #if MAC || _WIN32 fputs("\n", s->file); #else putc('\n', s->file); #endif LOCAL_newline = true; } else putc(ch, s->file); #if MAC || _WIN32 fflush( NULL ); #endif console_count_output_char(ch, s); return ((int)ch); } /* send a prompt, and use the system for internal buffering. Speed is not of the essence here !!! */ static int ConsoleGetc(int sno) { CACHE_REGS register StreamDesc *s = &GLOBAL_Stream[sno]; int ch; restart: /* keep the prompt around, just in case, but don't actually show it in silent mode */ if (Yap_DoPrompt(s)) { if (!silentMode()) { char *cptr = LOCAL_Prompt, ch; /* use the default routine */ while ((ch = *cptr++) != '\0') { GLOBAL_Stream[StdErrStream].stream_putc(StdErrStream, ch); } } Yap_clearInput(LOCAL_c_error_stream); strncpy(LOCAL_Prompt, (char *)RepAtom(LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT); 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) { Yap_external_signal(0, YAP_INT_SIGNAL); LOCAL_PrologMode &= ~ConsoleGetcMode; LOCAL_newline = TRUE; if (LOCAL_PrologMode & AbortMode) { Yap_Error(ABORT_EVENT, TermNil, ""); LOCAL_ErrorMessage = "Abort"; return EOF; } goto restart; } else { LOCAL_PrologMode &= ~ConsoleGetcMode; } if (ch == EOF) return EOF; return ch; } /** @pred prompt1(+ _A__) Changes YAP input prompt for the . */ static Int prompt1(USES_REGS1) { /* prompt1(Atom) */ Term t = Deref(ARG1); Atom a; 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); return (FALSE); } strncpy(LOCAL_Prompt, (char *)RepAtom(a)->StrOfAE, MAX_PROMPT); return (TRUE); } /** @pred prompt(- _A_,+ _B_) Changes YAP input prompt from _A_ to _B_, active on *next* standard input interaction. */ static Int prompt(USES_REGS1) { /* prompt(Old,New) */ Term t = Deref(ARG2); Atom a; if (!Yap_unify_constant(ARG1, MkAtomTerm(LOCAL_AtPrompt))) return (FALSE); if (IsVarTerm(t) || !IsAtomTerm(t)) return (FALSE); a = AtomOfTerm(t); if (strlen(RepAtom(a)->StrOfAE) > MAX_PROMPT) { Yap_Error(SYSTEM_ERROR_INTERNAL, t, "prompt %s is too long", RepAtom(a)->StrOfAE); return false; } strncpy(LOCAL_Prompt, (char *)RepAtom(LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT); 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. */ static Int ensure_prompting(USES_REGS1) { /* prompt(Old,New) */ if (!LOCAL_newline) { GLOBAL_Stream[2].stream_wputc(2, 10); // hack! } return true; } int Yap_GetCharForSIGINT(void) { CACHE_REGS int ch; #if USE_READLINE if (trueGlobalPrologFlag(READLINE_FLAG) || (ch = Yap_ReadlineForSIGINT()) == 0) #endif { /* 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') ; } LOCAL_newline = TRUE; fflush(NULL); return ch; } void Yap_InitConsole(void) { CACHE_REGS LOCAL_newline = true; 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); }