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

1847 lines
54 KiB
C
Raw Normal View History

2015-06-18 01:39:03 +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-12-15 09:14:15 +00:00
* File: iopreds.c *
2015-06-18 01:39:03 +01:00
* Last rev: 5/2/88 *
2015-12-15 09:14:15 +00:00
* mods: *
2015-06-18 01:39:03 +01:00
* comments: Input/Output C implemented predicates *
* *
*************************************************************************/
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#endif
/*
* This file includes the definition of a miscellania of standard predicates
2015-10-05 10:33:52 +01:00
* for yap refering to: Files and GLOBAL_Streams, Simple Input/Output,
2015-06-18 01:39:03 +01:00
*
*/
#include "Yap.h"
#include "Yatom.h"
#include "YapHeap.h"
#include "yapio.h"
#include "eval.h"
#include "YapText.h"
#include <stdlib.h>
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_WCTYPE_H
#include <wctype.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
2015-10-05 10:33:52 +01:00
#if HAVE_SYS_SELECT_H && !_MSC_VER && !defined(__MINGW32__)
2015-06-18 01:39:03 +01:00
#include <sys/select.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_FCNTL_H
/* for O_BINARY and O_TEXT in WIN32 */
#include <fcntl.h>
#endif
#ifdef _WIN32
#if HAVE_IO_H
/* Windows */
#include <io.h>
#endif
#endif
#if !HAVE_STRNCAT
2015-12-15 09:14:15 +00:00
#define strncat(X, Y, Z) strcat(X, Y)
2015-06-18 01:39:03 +01:00
#endif
#if !HAVE_STRNCPY
2015-12-15 09:14:15 +00:00
#define strncpy(X, Y, Z) strcpy(X, Y)
2015-06-18 01:39:03 +01:00
#endif
2015-10-05 10:33:52 +01:00
#if _MSC_VER || defined(__MINGW32__)
2015-06-18 01:39:03 +01:00
#if HAVE_SOCKET
#include <winsock2.h>
#endif
#include <windows.h>
#ifndef S_ISDIR
2015-12-15 09:14:15 +00:00
#define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
2015-06-18 01:39:03 +01:00
#endif
#endif
#include "iopreds.h"
2015-12-15 09:14:15 +00:00
static int get_wchar(int);
static int get_wchar_from_file(int);
2015-06-18 01:39:03 +01:00
FILE *Yap_stdin;
FILE *Yap_stdout;
FILE *Yap_stderr;
2015-12-15 09:14:15 +00:00
static bool issolutions(Term t) {
if (t == TermFirst || t == TermAll)
2015-09-21 23:05:36 +01:00
return true;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
if (IsVarTerm(t)) {
2015-09-21 23:05:36 +01:00
Yap_Error(INSTANTIATION_ERROR, t, "solutions in {first, all}.");
return false;
}
if (IsAtomTerm(t)) {
Yap_Error(DOMAIN_ERROR_SOLUTIONS, t, "solutions in {first, all}");
return false;
}
Yap_Error(TYPE_ERROR_ATOM, t, "solutions in {first, all}}");
return false;
}
2015-12-15 09:14:15 +00:00
static bool is_file_type(Term t) {
if (t == TermTxt || t == TermProlog || t == TermSource ||
t == TermExecutable || t == TermQly || t == TermDirectory)
2015-09-21 23:05:36 +01:00
return true;
2015-12-15 09:14:15 +00:00
2015-09-21 23:05:36 +01:00
if (IsVarTerm(t)) {
2015-12-15 09:14:15 +00:00
Yap_Error(INSTANTIATION_ERROR, t,
"file_type in {txt,prolog,exe,directory...}");
2015-09-21 23:05:36 +01:00
return false;
}
if (IsAtomTerm(t)) {
2015-12-15 09:14:15 +00:00
Yap_Error(DOMAIN_ERROR_FILE_TYPE, t,
"file_type in {txt,prolog,exe,directory...}");
2015-09-21 23:05:36 +01:00
return false;
}
Yap_Error(TYPE_ERROR_ATOM, t, "file_type in {txt,prolog,exe,directory...}");
return false;
}
2015-12-15 09:14:15 +00:00
static bool is_file_errors(Term t) {
if (t == TermFail || t == TermError)
2015-09-21 23:05:36 +01:00
return true;
2015-12-15 09:14:15 +00:00
2015-09-21 23:05:36 +01:00
if (IsVarTerm(t)) {
2015-10-05 10:33:52 +01:00
Yap_Error(INSTANTIATION_ERROR, t, "file_error in {fail,error}.");
return false;
2015-09-21 23:05:36 +01:00
}
if (IsAtomTerm(t)) {
Yap_Error(DOMAIN_ERROR_FILE_ERRORS, t, "file_error in {fail,error}.");
return false;
}
Yap_Error(TYPE_ERROR_ATOM, t, "file_error in {fail,error}.");
return false;
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
void Yap_DefaultStreamOps(StreamDesc *st) {
2015-06-18 01:39:03 +01:00
st->stream_wputc = put_wchar;
2015-12-15 09:14:15 +00:00
if (!(st->status & (Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f)))
st->stream_wgetc = get_wchar_from_file;
else
st->stream_wgetc = get_wchar;
2015-06-18 01:39:03 +01:00
if (GLOBAL_CharConversionTable != NULL)
st->stream_wgetc_for_read = ISOWGetc;
else
2015-10-05 10:33:52 +01:00
st->stream_wgetc_for_read = st->stream_wgetc;
2015-12-15 09:14:15 +00:00
if (st->encoding == ENC_ISO_UTF8)
2015-09-21 23:05:36 +01:00
st->stream_getc_for_utf8 = st->stream_getc;
else
st->stream_getc_for_utf8 = GetUTF8;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
static void unix_upd_stream_info(StreamDesc *s) {
2015-06-18 01:39:03 +01:00
if (s->status & InMemory_Stream_f) {
s->status |= Seekable_Stream_f;
return;
}
2015-12-15 09:14:15 +00:00
Yap_socketStream(s);
#if _MSC_VER || defined(__MINGW32__)
2015-06-18 01:39:03 +01:00
{
2015-12-15 09:14:15 +00:00
if (_isatty(_fileno(s->u.file.file))) {
s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
2015-06-18 01:39:03 +01:00
/* make all console descriptors unbuffered */
setvbuf(s->u.file.file, NULL, _IONBF, 0);
return;
}
#if _MSC_VER
/* standard error stream should never be buffered */
2015-12-15 09:14:15 +00:00
else if (StdErrStream == s - Stream) {
2015-10-05 10:33:52 +01:00
setvbuf(s->u.file.file, NULL, _IONBF, 0);
2015-06-18 01:39:03 +01:00
}
#endif
s->status |= Seekable_Stream_f;
return;
}
#else
#if HAVE_ISATTY
#if __simplescalar__
/* isatty does not seem to work with simplescar. I'll assume the first
2015-10-05 10:33:52 +01:00
three streams will probably be ttys (pipes are not thatg different) */
2015-12-15 09:14:15 +00:00
if (s - Stream < 3) {
2015-06-18 01:39:03 +01:00
s->name = AtomTty;
2015-12-15 09:14:15 +00:00
s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
#else
2015-06-18 01:39:03 +01:00
{
int filedes; /* visualc */
2015-12-15 09:14:15 +00:00
if (!s->file) {
2015-10-05 10:33:52 +01:00
s->name = AtomNil;
return;
}
2015-12-15 09:14:15 +00:00
filedes = fileno(s->file);
if (isatty(filedes)) {
2015-10-05 10:33:52 +01:00
#if HAVE_TTYNAME
2015-06-18 01:39:03 +01:00
char *ttys = ttyname(filedes);
if (ttys == NULL)
2015-10-05 10:33:52 +01:00
s->name = AtomTty;
2015-06-18 01:39:03 +01:00
else
2015-10-05 10:33:52 +01:00
s->name = AtomTtys;
2015-06-18 01:39:03 +01:00
#else
s->name = AtomTty;
#endif
2015-12-15 09:14:15 +00:00
s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
2015-06-18 01:39:03 +01:00
return;
}
}
#endif
#endif /* HAVE_ISATTY */
#endif /* _MSC_VER */
s->status |= Seekable_Stream_f;
}
2015-12-15 09:14:15 +00:00
GetsFunc PlGetsFunc(void) {
2015-06-18 01:39:03 +01:00
if (GLOBAL_CharConversionTable)
return DefaultGets;
else
return PlGets;
}
2015-12-15 09:14:15 +00:00
static void InitFileIO(StreamDesc *s) {
2015-06-18 01:39:03 +01:00
s->stream_gets = PlGetsFunc();
if (s->status & Socket_Stream_f) {
/* Console is a socket and socket will prompt */
2015-12-15 09:14:15 +00:00
Yap_ConsoleSocketOps(s);
2015-06-18 01:39:03 +01:00
s->stream_wputc = put_wchar;
2015-12-15 09:14:15 +00:00
} else if (s->status & Pipe_Stream_f) {
2015-06-18 01:39:03 +01:00
/* Console is a socket and socket will prompt */
Yap_ConsolePipeOps(s);
s->stream_wputc = put_wchar;
} else if (s->status & InMemory_Stream_f) {
2015-12-15 09:14:15 +00:00
Yap_MemOps(s);
2015-06-18 01:39:03 +01:00
s->stream_wputc = put_wchar;
} else {
/* check if our console is promptable: may be tty or pipe */
if (s->status & (Promptable_Stream_f)) {
2015-12-15 09:14:15 +00:00
Yap_ConsoleOps(s);
2015-06-18 01:39:03 +01:00
} else {
/* we are reading from a file, no need to check for prompts */
s->stream_putc = FilePutc;
s->stream_wputc = put_wchar;
s->stream_getc = PlGetc;
s->stream_gets = PlGetsFunc();
s->stream_wgetc = get_wchar_from_file;
2015-12-15 09:14:15 +00:00
}
2015-06-18 01:39:03 +01:00
}
s->stream_wputc = put_wchar;
s->stream_wgetc = get_wchar;
}
2015-12-15 09:14:15 +00:00
static void InitStdStream(int sno, SMALLUNSGN flags, FILE *file) {
2015-10-05 10:33:52 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
s->file = file;
2015-06-18 01:39:03 +01:00
s->status = flags;
s->linepos = 0;
s->linecount = 1;
2015-08-07 22:57:53 +01:00
s->charcount = 0.;
2015-09-21 23:05:36 +01:00
s->encoding = ENC_ISO_UTF8;
2015-06-18 01:39:03 +01:00
INIT_LOCK(s->streamlock);
unix_upd_stream_info(s);
/* Getting streams to prompt is a mess because we need for cooperation
2015-10-05 10:33:52 +01:00
between readers and writers to the stream :-(
*/
2015-06-18 01:39:03 +01:00
InitFileIO(s);
2015-12-15 09:14:15 +00:00
switch (sno) {
case 0:
s->name = AtomUserIn;
break;
case 1:
s->name = AtomUserOut;
break;
default:
s->name = AtomUserErr;
break;
}
s->user_name = MkAtomTerm(s->name);
Yap_DefaultStreamOps(s);
2015-06-18 01:39:03 +01:00
#if LIGHT
2015-12-15 09:14:15 +00:00
s->status |= Tty_Stream_f | Promptable_Stream_f;
2015-06-18 01:39:03 +01:00
#endif
#if HAVE_SETBUF
2015-12-15 09:14:15 +00:00
if (s->status & Tty_Stream_f && sno == 0) {
2015-06-18 01:39:03 +01:00
/* make sure input is unbuffered if it comes from stdin, this
2015-10-05 10:33:52 +01:00
makes life simpler for interrupt handling */
2015-12-15 09:14:15 +00:00
setbuf(stdin, NULL);
2015-06-18 01:39:03 +01:00
// fprintf(stderr,"here I am\n");
}
#endif /* HAVE_SETBUF */
}
2015-12-15 09:14:15 +00:00
Term Yap_StreamUserName(int sno) {
2015-10-05 10:33:52 +01:00
Term atname;
StreamDesc *s = &GLOBAL_Stream[sno];
if (s->user_name != 0L) {
return (s->user_name);
}
if ((atname = StreamName(sno)))
return atname;
return TermNil;
2015-07-06 12:03:16 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static void InitStdStreams(void) {
2015-06-18 01:39:03 +01:00
CACHE_REGS
2015-10-05 10:33:52 +01:00
if (LOCAL_sockets_io) {
2015-12-15 09:14:15 +00:00
InitStdStream(StdInStream, Input_Stream_f, NULL);
InitStdStream(StdOutStream, Output_Stream_f, NULL);
InitStdStream(StdErrStream, Output_Stream_f, NULL);
2015-10-05 10:33:52 +01:00
} else {
2015-12-15 09:14:15 +00:00
InitStdStream(StdInStream, Input_Stream_f, stdin);
InitStdStream(StdOutStream, Output_Stream_f, stdout);
InitStdStream(StdErrStream, Output_Stream_f, stderr);
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
GLOBAL_Stream[StdInStream].name = Yap_LookupAtom("user_input");
GLOBAL_Stream[StdOutStream].name = Yap_LookupAtom("user_output");
2015-12-15 09:14:15 +00:00
GLOBAL_Stream[StdErrStream].name = Yap_LookupAtom("user_error");
2015-06-18 01:39:03 +01:00
LOCAL_c_input_stream = StdInStream;
LOCAL_c_output_stream = StdOutStream;
LOCAL_c_error_stream = StdErrStream;
}
2015-12-15 09:14:15 +00:00
void Yap_InitStdStreams(void) { InitStdStreams(); }
2015-09-29 23:44:11 +01:00
2015-12-15 09:14:15 +00:00
Int PlIOError__(const char *file, const char *function, int lineno,
yap_error_number type, Term culprit, ...) {
if (trueLocalPrologFlag(FILEERRORS_FLAG) ||
2015-06-18 01:39:03 +01:00
type == RESOURCE_ERROR_MAX_STREAMS /* do not catch resource errors */) {
2015-10-05 10:33:52 +01:00
va_list args;
2015-09-29 23:44:11 +01:00
const char *format;
char who[1024];
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
va_start(args, culprit);
2015-09-29 23:44:11 +01:00
format = va_arg(args, char *);
2015-10-18 11:49:18 +01:00
if (format) {
vsnprintf(who, 1023, format, args);
} else {
2015-12-15 09:14:15 +00:00
who[0] = '\0';
2015-10-18 11:49:18 +01:00
}
2015-12-15 09:14:15 +00:00
va_end(args);
2015-10-05 10:33:52 +01:00
Yap_Error__(file, function, lineno, type, culprit, who);
/* and fail */
2015-11-05 17:16:10 +00:00
return false;
2015-06-18 01:39:03 +01:00
} else {
2015-11-05 17:16:10 +00:00
return false;
2015-06-18 01:39:03 +01:00
}
}
2015-12-15 09:14:15 +00:00
static int eolflg = 1;
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static char my_line[200] = {0};
static char *lp = my_line;
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
FILE *curfile, *Yap_logfile;
2015-06-18 01:39:03 +01:00
bool Yap_Option[256];
#ifdef MACC
2015-12-15 09:14:15 +00:00
static void InTTYLine(char *line) {
char *p = line;
char ch;
2015-06-18 01:39:03 +01:00
while ((ch = InKey()) != '\n' && ch != '\r')
if (ch == 8) {
if (line < p)
2015-10-05 10:33:52 +01:00
BackupTTY(*--p);
2015-06-18 01:39:03 +01:00
} else
TTYChar(*p++ = ch);
TTYChar('\n');
*p = 0;
}
#endif
2015-12-15 09:14:15 +00:00
void Yap_DebugSetIFile(char *fname) {
2015-06-18 01:39:03 +01:00
if (curfile)
fclose(curfile);
curfile = fopen(fname, "r");
if (curfile == NULL) {
curfile = stdin;
2015-11-05 17:16:10 +00:00
Yap_Warning("%% YAP open %s for input\n", fname);
2015-06-18 01:39:03 +01:00
}
}
2015-12-15 09:14:15 +00:00
void Yap_DebugEndline() { *lp = 0; }
2015-11-05 17:16:10 +00:00
2015-12-15 09:14:15 +00:00
int Yap_DebugGetc() {
int ch;
2015-06-18 01:39:03 +01:00
if (eolflg) {
if (curfile != NULL) {
if (fgets(my_line, 200, curfile) == 0)
2015-10-05 10:33:52 +01:00
curfile = NULL;
2015-06-18 01:39:03 +01:00
}
if (curfile == NULL)
if (fgets(my_line, 200, stdin) == NULL) {
2015-10-05 10:33:52 +01:00
return EOF;
2015-06-18 01:39:03 +01:00
}
eolflg = 0;
lp = my_line;
}
if ((ch = *lp++) == 0)
ch = '\n', eolflg = 1;
if (Yap_Option['l' - 96])
putc(ch, Yap_logfile);
return (ch);
}
2015-12-15 09:14:15 +00:00
int Yap_DebugPutc(FILE *s, wchar_t ch) {
2015-06-18 01:39:03 +01:00
if (Yap_Option['l' - 96])
2015-12-15 09:14:15 +00:00
(void)putc(ch, Yap_logfile);
2015-06-18 01:39:03 +01:00
return (putc(ch, s));
}
2015-12-15 09:14:15 +00:00
int Yap_DebugPuts(FILE *s, const char *sch) {
2015-06-18 01:39:03 +01:00
if (Yap_Option['l' - 96])
2015-12-15 09:14:15 +00:00
(void)fputs(sch, Yap_logfile);
return fputs(sch, s);
}
2015-12-15 09:14:15 +00:00
void Yap_DebugErrorPuts(const char *s) { Yap_DebugPuts(stderr, s); }
2015-12-15 09:14:15 +00:00
void Yap_DebugPlWrite(Term t) {
2015-06-18 01:39:03 +01:00
if (t != 0)
2015-12-15 09:14:15 +00:00
Yap_plwrite(t, GLOBAL_Stream + 2, 0, 0, GLOBAL_MaxPriority);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
void Yap_DebugPlWriteln(Term t) {
2015-11-05 17:16:10 +00:00
CACHE_REGS
2015-12-15 09:14:15 +00:00
Yap_plwrite(t, NULL, 15, 0, GLOBAL_MaxPriority);
Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, '.');
Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, 10);
2015-11-05 17:16:10 +00:00
}
2015-12-15 09:14:15 +00:00
void Yap_DebugErrorPutc(int c) {
2015-11-05 17:16:10 +00:00
CACHE_REGS
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(GLOBAL_Stream[LOCAL_c_error_stream].file, c);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
void Yap_DebugWriteIndicator(PredEntry *ap) {
2015-09-29 23:44:11 +01:00
CACHE_REGS
2015-09-25 10:57:26 +01:00
Term tmod = ap->ModuleOfPred;
2015-12-15 09:14:15 +00:00
if (!tmod)
tmod = TermProlog;
2015-09-25 10:57:26 +01:00
#if THREADS
Yap_DebugPlWrite(MkIntegerTerm(worker_id));
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, ' ');
2015-09-25 10:57:26 +01:00
#endif
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, '>');
Yap_DebugPutc(stderr, '\t');
2015-09-25 10:57:26 +01:00
Yap_DebugPlWrite(tmod);
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, ':');
2015-09-25 10:57:26 +01:00
if (ap->ModuleOfPred == IDB_MODULE) {
2015-10-05 10:33:52 +01:00
Term t = Deref(ARG1);
if (IsAtomTerm(t)) {
Yap_DebugPlWrite(t);
} else if (IsIntegerTerm(t)) {
Yap_DebugPlWrite(t);
2015-09-25 10:57:26 +01:00
} else {
2015-10-05 10:33:52 +01:00
Functor f = FunctorOfTerm(t);
Atom At = NameOfFunctor(f);
Yap_DebugPlWrite(MkAtomTerm(At));
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, '/');
2015-10-05 10:33:52 +01:00
Yap_DebugPlWrite(MkIntegerTerm(ArityOfFunctor(f)));
2015-09-25 10:57:26 +01:00
}
2015-10-05 10:33:52 +01:00
} else {
if (ap->ArityOfPE == 0) {
Atom At = (Atom)ap->FunctorOfPred;
Yap_DebugPlWrite(MkAtomTerm(At));
} else {
Functor f = ap->FunctorOfPred;
Atom At = NameOfFunctor(f);
Yap_DebugPlWrite(MkAtomTerm(At));
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, '/');
2015-10-05 10:33:52 +01:00
Yap_DebugPlWrite(MkIntegerTerm(ArityOfFunctor(f)));
}
}
2015-09-25 10:57:26 +01:00
2015-12-15 09:14:15 +00:00
Yap_DebugPutc(stderr, '\n');
}
2015-09-25 10:57:26 +01:00
2015-06-18 01:39:03 +01:00
/* static */
2015-12-15 09:14:15 +00:00
int FilePutc(int sno, int ch) {
2015-06-18 01:39:03 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
#if MAC || _MSC_VER
2015-12-15 09:14:15 +00:00
if (ch == 10) {
2015-10-05 10:33:52 +01:00
ch = '\n';
}
2015-06-18 01:39:03 +01:00
#endif
putc(ch, s->file);
#if MAC || _MSC_VER
2015-12-15 09:14:15 +00:00
if (ch == 10) {
2015-10-05 10:33:52 +01:00
fflush(s->file);
}
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
count_output_char(ch, s);
return ((int)ch);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
static int NullPutc(int sno, int ch) {
2015-06-18 01:39:03 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
#if MAC || _MSC_VER
2015-12-15 09:14:15 +00:00
if (ch == 10) {
2015-10-05 10:33:52 +01:00
ch = '\n';
}
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
count_output_char(ch, s);
return ((int)ch);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
int ResetEOF(StreamDesc *s) {
s->status &= ~Push_Eof_Stream_f;
2015-06-18 01:39:03 +01:00
if (s->status & Eof_Error_Stream_f) {
2015-12-15 09:14:15 +00:00
Yap_Error(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM, MkAtomTerm(s->name),
2015-10-05 10:33:52 +01:00
"GetC");
2015-06-18 01:39:03 +01:00
return FALSE;
} else if (s->status & Reset_Eof_Stream_f) {
/* reset the eof indicator on file */
2015-12-15 09:14:15 +00:00
if (feof(s->file))
clearerr(s->file);
/* reset our function for reading input */
2015-06-18 01:39:03 +01:00
#if HAVE_SOCKET
if (s->status & Socket_Stream_f) {
if (s->status & Promptable_Stream_f)
2015-12-15 09:14:15 +00:00
Yap_ConsoleSocketOps(s);
2015-10-05 10:33:52 +01:00
else
2015-12-15 09:14:15 +00:00
Yap_SocketOps(s);
2015-06-18 01:39:03 +01:00
s->stream_wputc = put_wchar;
2015-10-05 10:33:52 +01:00
} else
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
if (s->status & Pipe_Stream_f) {
if (s->status & Promptable_Stream_f)
Yap_ConsolePipeOps(s);
else
Yap_PipeOps(s);
} else if (s->status & InMemory_Stream_f) {
Yap_MemOps(s);
} else if (s->status & Promptable_Stream_f) {
Yap_ConsoleOps(s);
} else {
s->stream_getc = PlGetc;
Yap_DefaultStreamOps(s);
s->stream_gets = PlGetsFunc();
}
2015-10-05 10:33:52 +01:00
/* next, reset our own error indicator */
2015-06-18 01:39:03 +01:00
s->status &= ~Eof_Stream_f;
/* try reading again */
return TRUE;
} else {
s->status |= Past_Eof_Stream_f;
return FALSE;
}
}
/* handle reading from a stream after having found an EOF */
2015-12-15 09:14:15 +00:00
static int EOFWGetc(int sno) {
register StreamDesc *s = &GLOBAL_Stream[sno];
2015-12-15 09:14:15 +00:00
if (s->status & Push_Eof_Stream_f) {
/* ok, we have pushed an EOF, send it away */
s->status &= ~Push_Eof_Stream_f;
return EOF;
}
if (ResetEOF(s)) {
2016-01-03 02:06:09 +00:00
Yap_ConsoleOps(s);
2015-12-15 09:14:15 +00:00
return (s->stream_wgetc(sno));
}
return EOF;
}
2015-12-15 09:14:15 +00:00
static int EOFGetc(int sno) {
2015-06-18 01:39:03 +01:00
register StreamDesc *s = &GLOBAL_Stream[sno];
2015-12-15 09:14:15 +00:00
2015-06-18 01:39:03 +01:00
if (s->status & Push_Eof_Stream_f) {
/* ok, we have pushed an EOF, send it away */
s->status &= ~Push_Eof_Stream_f;
2015-12-15 09:14:15 +00:00
ResetEOF(s);
2015-06-18 01:39:03 +01:00
return EOF;
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
if (ResetEOF(s)) {
2016-01-03 02:06:09 +00:00
Yap_ConsoleOps(s);
2015-12-15 09:14:15 +00:00
return s->stream_getc(sno);
2015-06-18 01:39:03 +01:00
}
return EOF;
}
/* check if we read a LOCAL_newline or an EOF */
2015-12-15 09:14:15 +00:00
int console_post_process_eof(StreamDesc *s) {
2015-06-18 01:39:03 +01:00
CACHE_REGS
2015-12-15 09:14:15 +00:00
if (!ResetEOF(s)) {
s->status |= Eof_Stream_f;
s->stream_getc = EOFGetc;
s->stream_wgetc = EOFWGetc;
s->stream_wgetc_for_read = EOFWGetc;
s->stream_getc_for_utf8 = EOFGetc;
LOCAL_newline = true;
}
2015-06-18 01:39:03 +01:00
return EOFCHAR;
}
/* check if we read a newline or an EOF */
2015-12-15 09:14:15 +00:00
int post_process_read_char(int ch, StreamDesc *s) {
2015-06-18 01:39:03 +01:00
++s->charcount;
++s->linepos;
if (ch == '\n') {
++s->linecount;
s->linepos = 0;
/* don't convert if the stream is binary */
if (!(s->status & Binary_Stream_f))
ch = 10;
}
return ch;
}
/* check if we read a newline or an EOF */
2015-12-15 09:14:15 +00:00
int post_process_eof(StreamDesc *s) {
if (!ResetEOF(s)) {
s->status |= Eof_Stream_f;
s->stream_wgetc = EOFWGetc;
s->stream_getc = EOFGetc;
s->stream_wgetc_for_read = EOFWGetc;
s->stream_getc_for_utf8 = EOFGetc;
}
2015-10-05 10:33:52 +01:00
return EOFCHAR;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
int post_process_weof(StreamDesc *s) {
if (!ResetEOF(s)) {
s->status |= Eof_Stream_f;
s->stream_wgetc = EOFWGetc;
s->stream_wgetc = EOFWGetc;
s->stream_wgetc_for_read = EOFWGetc;
s->stream_getc_for_utf8 = EOFGetc;
}
return EOFCHAR;
}
2016-01-03 02:06:09 +00:00
/**
* caled after EOF found a peek, it just calls console_post_process to conclude
*the job.
*
* @param sno
*
2015-12-15 09:14:15 +00:00
* @return EOF
*/
2016-01-03 02:06:09 +00:00
int EOFPeek(int sno) { return EOFGetc(sno); }
2015-12-15 09:14:15 +00:00
2016-01-03 02:06:09 +00:00
int EOFWPeek(int sno) { return EOFWGetc(sno); }
2015-06-18 01:39:03 +01:00
/* standard routine, it should read from anything pointed by a FILE *.
2015-10-05 10:33:52 +01:00
It could be made more efficient by doing our own buffering and avoiding
post_process_read_char, something to think about */
2015-12-15 09:14:15 +00:00
int PlGetc(int sno) {
2015-06-18 01:39:03 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
Int ch;
2015-12-15 09:14:15 +00:00
ch = getc(s->file);
2015-06-18 01:39:03 +01:00
if (ch == EOF) {
2015-10-05 10:33:52 +01:00
return post_process_eof(s);
2015-06-18 01:39:03 +01:00
}
return post_process_read_char(ch, s);
}
/* standard routine, it should read from anything pointed by a FILE *.
2015-09-21 23:05:36 +01:00
It could be made more efficient by doing our own buffering and avoiding
2015-12-15 09:14:15 +00:00
post_process_read_char, something to think about. It assumes codification in 8
bits. */
int PlGets(int sno, UInt size, char *buf) {
2015-06-18 01:39:03 +01:00
register StreamDesc *s = &GLOBAL_Stream[sno];
UInt len;
2015-12-15 09:14:15 +00:00
if (fgets(buf, size, s->file) == NULL) {
2015-09-21 23:05:36 +01:00
return post_process_eof(s);
2015-06-18 01:39:03 +01:00
}
len = strlen(buf);
2015-12-15 09:14:15 +00:00
s->charcount += len - 1;
post_process_read_char(buf[len - 2], s);
2015-06-18 01:39:03 +01:00
return strlen(buf);
}
/* standard routine, it should read from anything pointed by a FILE *.
2015-10-05 10:33:52 +01:00
It could be made more efficient by doing our own buffering and avoiding
post_process_read_char, something to think about */
2015-12-15 09:14:15 +00:00
int DefaultGets(int sno, UInt size, char *buf) {
2015-06-18 01:39:03 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
char ch;
char *pt = buf;
2015-12-15 09:14:15 +00:00
2015-06-18 01:39:03 +01:00
if (!size)
return 0;
2015-12-15 09:14:15 +00:00
while ((ch = *buf++ = s->stream_getc(sno)) != -1 && ch != 10 && --size)
;
2015-06-18 01:39:03 +01:00
*buf++ = '\0';
2015-12-15 09:14:15 +00:00
return (buf - pt) - 1;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
int GetUTF8(int sno) {
2015-09-21 23:05:36 +01:00
StreamDesc *s = &GLOBAL_Stream[sno];
uint64_t bufi = s->utf8_buf;
unsigned char *buf = (unsigned char *)&bufi;
2015-12-15 09:14:15 +00:00
2015-09-21 23:05:36 +01:00
if (!bufi) {
2015-10-05 10:33:52 +01:00
int32_t ch = get_wchar(sno);
2015-12-15 09:14:15 +00:00
if (ch < 128)
return ch;
2015-10-05 10:33:52 +01:00
put_utf8((unsigned char *)&bufi, ch);
2015-09-21 23:05:36 +01:00
} else {
2015-12-15 09:14:15 +00:00
while (*buf++ == '\0')
;
2015-09-21 23:05:36 +01:00
}
unsigned char c = *buf;
buf[0] = '\0';
return c;
}
2015-12-15 09:14:15 +00:00
static int utf8_nof(char ch) {
2015-06-18 01:39:03 +01:00
if (!(ch & 0x20))
return 1;
if (!(ch & 0x10))
return 2;
if (!(ch & 0x08))
return 3;
if (!(ch & 0x04))
return 4;
return 5;
}
2015-12-15 09:14:15 +00:00
#define wide_char() \
switch (GLOBAL_Stream[sno].encoding) { \
case ENC_OCTET: \
return ch; \
case ENC_ISO_LATIN1: \
return ch; \
case ENC_ISO_ASCII: \
if (ch & 0x80) { \
/* error */ \
} \
return ch; \
case ENC_ISO_ANSI: { \
char buf[1]; \
int out; \
\
if (!how_many) { \
memset((void *)&(GLOBAL_Stream[sno].mbstate), 0, sizeof(mbstate_t)); \
} \
buf[0] = ch; \
if ((out = mbrtowc(&wch, buf, 1, &(GLOBAL_Stream[sno].mbstate))) == 1) \
return wch; \
if (out == -1) { \
/* error */ \
} \
how_many++; \
break; \
} \
case ENC_ISO_UTF8: { \
if (!how_many) { \
if (ch & 0x80) { \
how_many = utf8_nof(ch); \
/* \
keep a backup of the start character in case we meet an error, \
useful if we are scanning ISO files. \
*/ \
GLOBAL_Stream[sno].och = ch; \
wch = (ch & ((1 << (6 - how_many)) - 1)) << (6 * how_many); \
} else { \
return ch; \
} \
} else { \
how_many--; \
if ((ch & 0xc0) == 0x80) { \
wch += (ch & ~0xc0) << (how_many * 6); \
} else { \
/* error */ \
/* try to recover character, assume this is our first character */ \
wchar_t och = GLOBAL_Stream[sno].och; \
return och; \
} \
if (!how_many) { \
return wch; \
} \
} \
} break; \
case ENC_UTF16_BE: \
if (how_many) { \
return wch + ch; \
} \
how_many = 1; \
wch = ch << 8; \
break; \
case ENC_UTF16_LE: \
if (how_many) { \
return wch + (ch << 8); \
} \
how_many = 1; \
wch = ch; \
break; \
case ENC_ISO_UTF32_LE: \
if (!how_many) { \
how_many = 4; \
wch = 0; \
} \
how_many--; \
wch += ((unsigned char)(ch & 0xff)) << (how_many * 8); \
if (how_many == 0) \
return wch; \
break; \
case ENC_ISO_UTF32_BE: \
if (!how_many) { \
how_many = 4; \
wch = 0; \
} \
how_many--; \
wch += ((unsigned char)(ch & 0xff)) << ((3 - how_many) * 8); \
if (how_many == 0) \
return wch; \
break; \
}
static int get_wchar(int sno) {
int ch;
wchar_t wch;
int how_many = 0;
2015-12-15 09:14:15 +00:00
while (true) {
ch = GLOBAL_Stream[sno].stream_getc(sno);
if (ch == -1) {
if (how_many) {
2015-12-15 09:14:15 +00:00
/* error */
}
2016-01-03 02:06:09 +00:00
return post_process_weof(GLOBAL_Stream + sno);
}
wide_char();
}
return EOF;
}
// layered version
2015-12-15 09:14:15 +00:00
static int get_wchar__(int sno) {
2015-06-18 01:39:03 +01:00
int ch;
wchar_t wch;
int how_many = 0;
2015-12-15 09:14:15 +00:00
StreamDesc *s = GLOBAL_Stream + sno;
2015-06-18 01:39:03 +01:00
while (TRUE) {
ch = getc(GLOBAL_Stream[sno].file);
2015-06-18 01:39:03 +01:00
if (ch == -1) {
if (how_many) {
2015-10-05 10:33:52 +01:00
/* error */
2015-06-18 01:39:03 +01:00
}
return post_process_weof(s);
2015-06-18 01:39:03 +01:00
}
wide_char();
2015-06-18 01:39:03 +01:00
}
return EOF;
}
2015-12-15 09:14:15 +00:00
static int get_wchar_from_file(int sno) {
return post_process_read_char(get_wchar__(sno), GLOBAL_Stream + sno);
}
2015-06-18 01:39:03 +01:00
#ifndef MB_LEN_MAX
#define MB_LEN_MAX 6
#endif
2015-12-15 09:14:15 +00:00
static int handle_write_encoding_error(int sno, wchar_t ch) {
2015-06-18 01:39:03 +01:00
if (GLOBAL_Stream[sno].status & RepError_Xml_f) {
/* use HTML/XML encoding in ASCII */
int i = ch, digits = 1;
GLOBAL_Stream[sno].stream_putc(sno, '&');
GLOBAL_Stream[sno].stream_putc(sno, '#');
while (digits < i)
digits *= 10;
if (digits > i)
digits /= 10;
while (i) {
2015-12-15 09:14:15 +00:00
GLOBAL_Stream[sno].stream_putc(sno, i / digits);
2015-06-18 01:39:03 +01:00
i %= 10;
digits /= 10;
}
GLOBAL_Stream[sno].stream_putc(sno, ';');
return ch;
} else if (GLOBAL_Stream[sno].status & RepError_Prolog_f) {
/* write quoted */
GLOBAL_Stream[sno].stream_putc(sno, '\\');
GLOBAL_Stream[sno].stream_putc(sno, 'u');
2015-12-15 09:14:15 +00:00
GLOBAL_Stream[sno].stream_putc(sno, ch >> 24);
GLOBAL_Stream[sno].stream_putc(sno, 256 & (ch >> 16));
GLOBAL_Stream[sno].stream_putc(sno, 256 & (ch >> 8));
GLOBAL_Stream[sno].stream_putc(sno, 256 & ch);
2015-06-18 01:39:03 +01:00
return ch;
} else {
CACHE_REGS
2015-12-15 09:14:15 +00:00
Yap_Error(REPRESENTATION_ERROR_CHARACTER, MkIntegerTerm(ch),
"charater %ld cannot be encoded in stream %d",
(unsigned long int)ch, sno);
2015-06-18 01:39:03 +01:00
return -1;
}
}
2015-12-15 09:14:15 +00:00
int put_wchar(int sno, wchar_t ch) {
/* pass the bucck if we can */
2015-06-18 01:39:03 +01:00
switch (GLOBAL_Stream[sno].encoding) {
2015-12-15 09:14:15 +00:00
case ENC_OCTET:
return GLOBAL_Stream[sno].stream_putc(sno, ch);
case ENC_ISO_LATIN1:
if (ch >= 0xff) {
return handle_write_encoding_error(sno, ch);
}
return GLOBAL_Stream[sno].stream_putc(sno, ch);
case ENC_ISO_ASCII:
if (ch >= 0x80) {
return handle_write_encoding_error(sno, ch);
}
return GLOBAL_Stream[sno].stream_putc(sno, ch);
case ENC_ISO_ANSI: {
char buf[MB_LEN_MAX];
int n;
memset((void *)&(GLOBAL_Stream[sno].mbstate), 0, sizeof(mbstate_t));
if ((n = wcrtomb(buf, ch, &(GLOBAL_Stream[sno].mbstate))) < 0) {
/* error */
GLOBAL_Stream[sno].stream_putc(sno, ch);
return -1;
} else {
int i;
for (i = 0; i < n; i++) {
GLOBAL_Stream[sno].stream_putc(sno, buf[i]);
2015-10-05 10:33:52 +01:00
}
2015-12-15 09:14:15 +00:00
return ch;
}
case ENC_ISO_UTF8:
if (ch < 0x80) {
2015-10-05 10:33:52 +01:00
return GLOBAL_Stream[sno].stream_putc(sno, ch);
2015-12-15 09:14:15 +00:00
} else if (ch < 0x800) {
GLOBAL_Stream[sno].stream_putc(sno, 0xC0 | ch >> 6);
return GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
} else if (ch < 0x10000) {
GLOBAL_Stream[sno].stream_putc(sno, 0xE0 | ch >> 12);
GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 6 & 0x3F));
return GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
} else if (ch < 0x200000) {
GLOBAL_Stream[sno].stream_putc(sno, 0xF0 | ch >> 18);
GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 12 & 0x3F));
GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch >> 6 & 0x3F));
return GLOBAL_Stream[sno].stream_putc(sno, 0x80 | (ch & 0x3F));
} else {
/* should never happen */
return -1;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
break;
case ENC_UTF16_BE:
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
return GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
case ENC_UTF16_LE:
GLOBAL_Stream[sno].stream_putc(sno, (ch & 0xff));
return GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8));
case ENC_ISO_UTF32_BE:
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 24) & 0xff);
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 16) & 0xff);
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8) & 0xff);
return GLOBAL_Stream[sno].stream_putc(sno, ch & 0xff);
case ENC_ISO_UTF32_LE:
GLOBAL_Stream[sno].stream_putc(sno, ch & 0xff);
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 8) & 0xff);
GLOBAL_Stream[sno].stream_putc(sno, (ch >> 16) & 0xff);
return GLOBAL_Stream[sno].stream_putc(sno, (ch >> 24) & 0xff);
}
2015-06-18 01:39:03 +01:00
}
return -1;
}
/* used by user-code to read characters from the current input stream */
2015-12-15 09:14:15 +00:00
int Yap_PlGetchar(void) {
2015-06-18 01:39:03 +01:00
CACHE_REGS
2015-12-15 09:14:15 +00:00
return (
GLOBAL_Stream[LOCAL_c_input_stream].stream_getc(LOCAL_c_input_stream));
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
int Yap_PlGetWchar(void) {
2015-06-18 01:39:03 +01:00
CACHE_REGS
2015-10-05 10:33:52 +01:00
return get_wchar(LOCAL_c_input_stream);
2015-06-18 01:39:03 +01:00
}
/* avoid using a variable to call a function */
2015-12-15 09:14:15 +00:00
int Yap_PlFGetchar(void) {
2015-06-18 01:39:03 +01:00
CACHE_REGS
2015-12-15 09:14:15 +00:00
return (PlGetc(LOCAL_c_input_stream));
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
Term Yap_MkStream(int n) {
2015-06-18 01:39:03 +01:00
Term t[1];
2015-12-15 09:14:15 +00:00
t[0] = MkIntTerm(n);
return (Yap_MkApplTerm(FunctorStream, 1, t));
2015-06-18 01:39:03 +01:00
}
/* given a stream index, get the corresponding fd */
2015-12-15 09:14:15 +00:00
Int GetStreamFd(int sno) {
2015-06-18 01:39:03 +01:00
#if HAVE_SOCKET
if (GLOBAL_Stream[sno].status & Socket_Stream_f) {
2015-12-15 09:14:15 +00:00
return (GLOBAL_Stream[sno].u.socket.fd);
2015-06-18 01:39:03 +01:00
} else
#endif
2015-12-15 09:14:15 +00:00
if (GLOBAL_Stream[sno].status & Pipe_Stream_f) {
2015-10-05 10:33:52 +01:00
#if _MSC_VER || defined(__MINGW32__)
2015-12-15 09:14:15 +00:00
return ((Int)(GLOBAL_Stream[sno].u.pipe.hdl));
2015-06-18 01:39:03 +01:00
#else
2015-12-15 09:14:15 +00:00
return (GLOBAL_Stream[sno].u.pipe.fd);
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
} else if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
return (-1);
}
return (fileno(GLOBAL_Stream[sno].file));
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
Int Yap_GetStreamFd(int sno) { return GetStreamFd(sno); }
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static int binary_file(char *file_name) {
2015-06-18 01:39:03 +01:00
#if HAVE_STAT
2015-10-05 10:33:52 +01:00
#if _MSC_VER || defined(__MINGW32__)
2015-06-18 01:39:03 +01:00
struct _stat ss;
2015-10-05 10:33:52 +01:00
if (_stat(file_name, &ss) != 0)
2015-06-18 01:39:03 +01:00
#else
2015-12-15 09:14:15 +00:00
struct stat ss;
2015-10-05 10:33:52 +01:00
if (stat(file_name, &ss) != 0)
2015-06-18 01:39:03 +01:00
#endif
2015-10-05 10:33:52 +01:00
{
/* ignore errors while checking a file */
2015-12-15 09:14:15 +00:00
return (FALSE);
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
return (S_ISDIR(ss.st_mode));
#else
2015-12-15 09:14:15 +00:00
return (FALSE);
2015-10-05 10:33:52 +01:00
#endif
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static int write_bom(int sno, StreamDesc *st) {
2015-10-05 10:33:52 +01:00
/* dump encoding */
switch (st->encoding) {
2015-12-15 09:14:15 +00:00
case ENC_ISO_UTF8:
if (st->stream_putc(sno, 0xEF) < 0)
return FALSE;
if (st->stream_putc(sno, 0xBB) < 0)
return FALSE;
if (st->stream_putc(sno, 0xBF) < 0)
return FALSE;
st->status |= HAS_BOM_f;
return TRUE;
case ENC_UTF16_BE:
if (st->stream_putc(sno, 0xFE) < 0)
return FALSE;
if (st->stream_putc(sno, 0xFF) < 0)
return FALSE;
st->status |= HAS_BOM_f;
return TRUE;
case ENC_UTF16_LE:
if (st->stream_putc(sno, 0xFF) < 0)
return FALSE;
if (st->stream_putc(sno, 0xFE) < 0)
return FALSE;
case ENC_ISO_UTF32_BE:
if (st->stream_putc(sno, 0x00) < 0)
return FALSE;
if (st->stream_putc(sno, 0x00) < 0)
return FALSE;
if (st->stream_putc(sno, 0xFE) < 0)
return FALSE;
if (st->stream_putc(sno, 0xFF) < 0)
return FALSE;
case ENC_ISO_UTF32_LE:
if (st->stream_putc(sno, 0xFF) < 0)
return FALSE;
if (st->stream_putc(sno, 0xFE) < 0)
return FALSE;
if (st->stream_putc(sno, 0x00) < 0)
return FALSE;
if (st->stream_putc(sno, 0x00) < 0)
return FALSE;
default:
return TRUE;
}
}
static void check_bom(int sno, StreamDesc *st) {
int ch1, ch2, ch3, ch4;
2015-12-15 09:14:15 +00:00
ch1 = st->stream_getc(sno);
2015-12-15 09:14:15 +00:00
switch (ch1) {
case 0x00: {
ch2 = st->stream_getc(sno);
if (ch2 != 0x00) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
return;
} else {
ch3 = st->stream_getc(sno);
if (ch3 == EOFCHAR || ch3 != 0xFE) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
ungetc(ch3, st->file);
2015-10-05 10:33:52 +01:00
return;
} else {
2015-12-15 09:14:15 +00:00
ch4 = st->stream_getc(sno);
if (ch4 == EOFCHAR || ch3 != 0xFF) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
ungetc(ch3, st->file);
ungetc(ch4, st->file);
2015-10-05 10:33:52 +01:00
return;
} else {
2015-12-15 09:14:15 +00:00
st->status |= HAS_BOM_f;
st->encoding = ENC_ISO_UTF32_BE;
return;
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
}
2015-12-15 09:14:15 +00:00
}
case 0xFE: {
ch2 = st->stream_getc(sno);
if (ch2 != 0xFF) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
return;
} else {
st->status |= HAS_BOM_f;
st->encoding = ENC_UTF16_BE;
return;
2015-10-05 10:33:52 +01:00
}
2015-12-15 09:14:15 +00:00
}
case 0xFF: {
ch2 = st->stream_getc(sno);
if (ch2 != 0xFE) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
return;
} else {
ch3 = st->stream_getc(sno);
if (ch3 != 0x00) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
ungetc(ch3, st->file);
2015-10-05 10:33:52 +01:00
return;
} else {
2015-12-15 09:14:15 +00:00
ch4 = st->stream_getc(sno);
if (ch4 != 0x00) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
ungetc(ch3, st->file);
ungetc(ch4, st->file);
return;
2015-10-05 10:33:52 +01:00
} else {
2015-12-15 09:14:15 +00:00
st->status |= HAS_BOM_f;
st->encoding = ENC_ISO_UTF32_LE;
return;
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
st->status |= HAS_BOM_f;
st->encoding = ENC_UTF16_LE;
return;
2015-10-05 10:33:52 +01:00
}
2015-12-15 09:14:15 +00:00
}
case 0xEF:
ch2 = st->stream_getc(sno);
if (ch2 != 0xBB) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
return;
} else {
ch3 = st->stream_getc(sno);
if (ch3 != 0xBF) {
ungetc(ch1, st->file);
ungetc(ch2, st->file);
ungetc(ch3, st->file);
return;
2015-06-18 01:39:03 +01:00
} else {
2015-12-15 09:14:15 +00:00
st->status |= HAS_BOM_f;
st->encoding = ENC_ISO_UTF8;
return;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
}
default:
2015-12-15 09:14:15 +00:00
ungetc(ch1, st->file);
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
bool Yap_initStream(int sno, FILE *fd, const char *name, Term file_name,
2015-12-15 09:14:15 +00:00
encoding_t encoding, stream_flags_t flags,
Atom open_mode) {
2015-10-05 10:33:52 +01:00
StreamDesc *st = &GLOBAL_Stream[sno];
st->status = flags;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
st->charcount = 0;
st->linecount = 1;
if (flags & Binary_Stream_f) {
2015-09-21 23:05:36 +01:00
st->encoding = ENC_OCTET;
} else {
st->encoding = encoding;
}
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
if (name == NULL) {
2015-12-15 09:14:15 +00:00
char buf[YAP_FILENAME_MAX + 1];
2015-10-05 10:33:52 +01:00
name = Yap_guessFileName(fileno(fd), sno, buf, YAP_FILENAME_MAX);
2016-01-04 15:12:44 +00:00
if (name)
2015-10-05 10:33:52 +01:00
st->name = Yap_LookupAtom(name);
}
st->user_name = file_name;
2015-12-15 09:14:15 +00:00
st->file = fd;
2015-10-05 10:33:52 +01:00
st->linepos = 0;
if (flags & Pipe_Stream_f) {
2015-12-15 09:14:15 +00:00
Yap_PipeOps(st);
Yap_DefaultStreamOps(st);
2015-10-05 10:33:52 +01:00
} else if (flags & Tty_Stream_f) {
2015-12-15 09:14:15 +00:00
Yap_ConsoleOps(st);
Yap_DefaultStreamOps(st);
2015-10-05 10:33:52 +01:00
} else {
st->stream_putc = FilePutc;
st->stream_getc = PlGetc;
2015-12-15 09:14:15 +00:00
unix_upd_stream_info(st);
Yap_DefaultStreamOps(st);
2015-10-05 10:33:52 +01:00
}
st->stream_gets = PlGetsFunc();
2015-09-21 23:05:36 +01:00
return true;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
#define OPEN_DEFS() \
PAR("alias", isatom, OPEN_ALIAS), PAR("bom", boolean, OPEN_BOM), \
PAR("buffer", isatom, OPEN_BUFFER), \
PAR("close_on_abort", boolean, OPEN_CLOSE_ON_ABORT), \
PAR("create", isatom, OPEN_CREATE), \
PAR("encoding", isatom, OPEN_ENCODING), \
PAR("eof_action", isatom, OPEN_EOF_ACTION), \
PAR("expand_filename", boolean, OPEN_EXPAND_FILENAME), \
PAR("file_name", isatom, OPEN_FILE_NAME), PAR("input", ok, OPEN_INPUT), \
PAR("locale", isatom, OPEN_LOCALE), PAR("lock", isatom, OPEN_LOCK), \
PAR("mode", isatom, OPEN_MODE), PAR("output", ok, OPEN_OUTPUT), \
PAR("representation_errors", boolean, OPEN_REPRESENTATION_ERRORS), \
PAR("reposition", boolean, OPEN_REPOSITION), \
PAR("type", isatom, OPEN_TYPE), PAR("wait", boolean, OPEN_WAIT), \
PAR(NULL, ok, OPEN_END)
#define PAR(x, y, z) z
typedef enum open_enum_choices { OPEN_DEFS() } open_choices_t;
2015-06-18 01:39:03 +01:00
#undef PAR
2015-12-15 09:14:15 +00:00
#define PAR(x, y, z) \
{ x, y, z }
2015-10-05 10:33:52 +01:00
2015-12-15 09:14:15 +00:00
static const param_t open_defs[] = {OPEN_DEFS()};
2015-06-18 01:39:03 +01:00
#undef PAR
2016-01-08 20:04:31 +00:00
2015-10-05 10:33:52 +01:00
static Int
2015-12-15 09:14:15 +00:00
do_open(Term file_name, Term t2,
Term tlist USES_REGS) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
2015-10-05 10:33:52 +01:00
Atom open_mode;
int sno;
SMALLUNSGN s;
char io_mode[8];
StreamDesc *st;
2016-01-08 20:04:31 +00:00
bool avoid_bom = false, needs_bom = false;
2015-10-05 10:33:52 +01:00
char *fname;
stream_flags_t flags;
FILE *fd;
encoding_t encoding;
Term tenc;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
// original file name
2015-12-15 09:14:15 +00:00
if (IsVarTerm(file_name)) {
Yap_Error(INSTANTIATION_ERROR, file_name, "open/3");
2015-10-05 10:33:52 +01:00
return FALSE;
}
2015-12-15 09:14:15 +00:00
if (!IsAtomTerm(file_name)) {
if (IsStringTerm(file_name)) {
fname = (char *)StringOfTerm(file_name);
2015-06-18 01:39:03 +01:00
} else {
2015-12-15 09:14:15 +00:00
Yap_Error(DOMAIN_ERROR_SOURCE_SINK, file_name, "open/3");
2015-06-18 01:39:03 +01:00
return FALSE;
}
2015-10-05 10:33:52 +01:00
} else {
2015-12-15 09:14:15 +00:00
fname = RepAtom(AtomOfTerm(file_name))->StrOfAE;
2015-10-05 10:33:52 +01:00
}
// open mode
2015-12-15 09:14:15 +00:00
if (IsVarTerm(t2)) {
Yap_Error(INSTANTIATION_ERROR, t2, "open/3");
2015-10-05 10:33:52 +01:00
return FALSE;
}
2015-12-15 09:14:15 +00:00
if (!IsAtomTerm(t2)) {
if (IsStringTerm(t2)) {
open_mode = Yap_LookupAtom(StringOfTerm(t2));
2015-06-18 01:39:03 +01:00
} else {
2015-12-15 09:14:15 +00:00
Yap_Error(TYPE_ERROR_ATOM, t2, "open/3");
return (FALSE);
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
} else {
2015-12-15 09:14:15 +00:00
open_mode = AtomOfTerm(t2);
2015-10-05 10:33:52 +01:00
}
// read, write, append
if (open_mode == AtomRead) {
2015-12-15 09:14:15 +00:00
strncpy(io_mode, "rb", 8);
2015-10-05 10:33:52 +01:00
s = Input_Stream_f;
} else if (open_mode == AtomWrite) {
2015-12-15 09:14:15 +00:00
strncpy(io_mode, "w", 8);
2015-10-05 10:33:52 +01:00
s = Output_Stream_f;
} else if (open_mode == AtomAppend) {
2015-12-15 09:14:15 +00:00
strncpy(io_mode, "a", 8);
2015-10-05 10:33:52 +01:00
s = Append_Stream_f | Output_Stream_f;
} else {
Yap_Error(DOMAIN_ERROR_IO_MODE, t2, "open/3");
2015-12-15 09:14:15 +00:00
return (FALSE);
2015-10-05 10:33:52 +01:00
}
/* get options */
2015-12-15 09:14:15 +00:00
xarg *args = Yap_ArgListToVector(tlist, open_defs, OPEN_END);
if (args == NULL) {
2015-12-15 09:14:15 +00:00
if (LOCAL_Error_TYPE)
Yap_Error(LOCAL_Error_TYPE, LOCAL_Error_Term,
"option handling in open/3");
2015-10-05 10:33:52 +01:00
return FALSE;
2015-12-15 09:14:15 +00:00
}
2015-10-05 10:33:52 +01:00
/* done */
sno = GetFreeStreamD();
if (sno < 0)
2015-12-15 09:14:15 +00:00
return PlIOError(RESOURCE_ERROR_MAX_STREAMS, TermNil, "open/3");
2015-10-05 10:33:52 +01:00
st = &GLOBAL_Stream[sno];
st->user_name = file_name;
flags = s;
// user requested encoding?
if (args[OPEN_ALIAS].used) {
Atom al = AtomOfTerm(args[OPEN_ALIAS].tvalue);
2015-12-15 09:14:15 +00:00
if (!Yap_AddAlias(al, sno))
2015-10-05 10:33:52 +01:00
return false;
}
if (args[OPEN_ENCODING].used) {
tenc = args[OPEN_ENCODING].tvalue;
2015-12-15 09:14:15 +00:00
encoding = enc_id(RepAtom(AtomOfTerm(tenc))->StrOfAE);
2015-10-05 10:33:52 +01:00
} else {
encoding = LOCAL_encoding;
}
2015-12-15 09:14:15 +00:00
bool ok = (args[OPEN_EXPAND_FILENAME].used
? args[OPEN_EXPAND_FILENAME].tvalue == TermTrue
: false) ||
trueGlobalPrologFlag(OPEN_EXPANDS_FILENAME_FLAG);
2015-10-05 10:33:52 +01:00
// expand file name?
2015-12-15 09:14:15 +00:00
fname = Yap_AbsoluteFile(fname, LOCAL_FileNameBuf, ok);
st->name = Yap_LookupAtom(fname);
2015-10-05 10:33:52 +01:00
// binary type
if (args[OPEN_TYPE].used) {
2015-10-05 10:33:52 +01:00
Term t = args[OPEN_TYPE].tvalue;
2015-12-15 09:14:15 +00:00
bool bin = (t == TermBinary);
2015-10-05 10:33:52 +01:00
if (bin) {
#ifdef _WIN32
strncat(io_mode, "b", 8);
2015-06-18 01:39:03 +01:00
#endif
2015-10-05 10:33:52 +01:00
flags |= Binary_Stream_f;
encoding = ENC_OCTET;
avoid_bom = true;
2016-01-08 20:04:31 +00:00
needs_bom = false;
2015-12-15 09:14:15 +00:00
} else if (t == TermText) {
2015-10-05 10:33:52 +01:00
#ifdef _WIN32
strncat(io_mode, "t", 8);
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
/* note that this matters for UNICODE style conversions */
2015-10-05 10:33:52 +01:00
} else {
2015-12-15 09:14:15 +00:00
Yap_Error(DOMAIN_ERROR_STREAM, tlist,
"type is ~a, must be one of binary or text", t);
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
}
// BOM mess
2016-01-08 20:04:31 +00:00
if (encoding == ENC_UTF16_BE || encoding == ENC_UTF16_LE ||
encoding == ENC_ISO_UTF32_BE || encoding == ENC_ISO_UTF32_LE ) {
needs_bom = true;
2015-10-05 10:33:52 +01:00
}
if (args[OPEN_BOM].used) {
if (args[OPEN_BOM].tvalue == TermTrue) {
2016-01-08 20:04:31 +00:00
avoid_bom = false;
2015-10-05 10:33:52 +01:00
needs_bom = true;
2015-12-15 09:14:15 +00:00
} else if (args[OPEN_BOM].tvalue == TermFalse) {
2015-10-05 10:33:52 +01:00
avoid_bom = true;
2016-01-08 20:04:31 +00:00
needs_bom = false;
2015-06-18 01:39:03 +01:00
}
2016-01-08 20:04:31 +00:00
}
if (st - GLOBAL_Stream < 3) {
2015-10-05 10:33:52 +01:00
flags |= RepError_Prolog_f;
}
2015-12-15 09:14:15 +00:00
if ((fd = fopen(fname, io_mode)) == NULL ||
(!(flags & Binary_Stream_f) && binary_file(fname))) {
2015-10-05 10:33:52 +01:00
UNLOCK(st->streamlock);
if (errno == ENOENT)
2015-12-15 09:14:15 +00:00
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, ARG6, "%s: %s", fname,
strerror(errno)));
else {
2015-12-15 09:14:15 +00:00
return (PlIOError(PERMISSION_ERROR_OPEN_SOURCE_SINK, file_name, "%s: %s",
fname, strerror(errno)));
}
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
#if MAC
2015-12-15 09:14:15 +00:00
if (open_mode == AtomWrite) {
Yap_SetTextFile(RepAtom(AtomOfTerm(file_name))->StrOfAE);
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
#endif
flags &= ~(Free_Stream_f);
if (!Yap_initStream(sno, fd, fname, file_name, encoding, flags, open_mode))
2015-06-18 01:39:03 +01:00
return false;
2015-12-15 09:14:15 +00:00
if (open_mode == AtomWrite) {
if (needs_bom && !write_bom(sno, st))
2016-01-08 20:04:31 +00:00
return false;
} else if ( open_mode == AtomRead && !avoid_bom ) {
2015-10-05 10:33:52 +01:00
check_bom(sno, st); // can change encoding
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
UNLOCK(st->streamlock);
{
2015-12-15 09:14:15 +00:00
Term t = Yap_MkStream(sno);
return (Yap_unify(ARG3, t));
2015-10-05 10:33:52 +01:00
}
}
2015-12-15 09:14:15 +00:00
static Int open3(USES_REGS1) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
return do_open(Deref(ARG1), Deref(ARG2), TermNil PASS_REGS);
2015-07-06 12:03:16 +01:00
}
2015-12-15 09:14:15 +00:00
static Int open4(USES_REGS1) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
return do_open(Deref(ARG1), Deref(ARG2), Deref(ARG4) PASS_REGS);
2015-07-06 12:03:16 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static Int p_file_expansion(USES_REGS1) { /* '$file_expansion'(+File,-Name) */
2015-10-05 10:33:52 +01:00
Term file_name = Deref(ARG1);
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
/* we know file_name is bound */
2015-12-15 09:14:15 +00:00
if (!IsAtomTerm(file_name)) {
2015-10-05 10:33:52 +01:00
PlIOError(TYPE_ERROR_ATOM, file_name, "absolute_file_name/3");
2015-12-15 09:14:15 +00:00
return (FALSE);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
if (!Yap_TrueFileName(RepAtom(AtomOfTerm(file_name))->StrOfAE,
LOCAL_FileNameBuf, FALSE))
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, file_name,
"absolute_file_name/3"));
return (Yap_unify(ARG2, MkAtomTerm(Yap_LookupAtom(LOCAL_FileNameBuf))));
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static Int p_open_null_stream(USES_REGS1) {
2015-10-05 10:33:52 +01:00
Term t;
StreamDesc *st;
int sno = GetFreeStreamD();
if (sno < 0)
2015-12-15 09:14:15 +00:00
return (PlIOError(SYSTEM_ERROR_INTERNAL, TermNil,
"new stream not available for open_null_stream/1"));
2015-10-05 10:33:52 +01:00
st = &GLOBAL_Stream[sno];
st->status = Append_Stream_f | Output_Stream_f | Null_Stream_f;
2015-06-18 01:39:03 +01:00
#if _WIN32
2015-12-15 09:14:15 +00:00
st->file = fopen("NUL", "w");
2015-06-18 01:39:03 +01:00
#else
2015-12-15 09:14:15 +00:00
st->file = fopen("/dev/null", "w");
2015-10-05 10:33:52 +01:00
#endif
if (st->file == NULL) {
2015-12-15 09:14:15 +00:00
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
"Could not open NULL stream (/dev/null,NUL)");
2015-10-05 10:33:52 +01:00
return false;
}
st->linepos = 0;
st->charcount = 0;
st->linecount = 1;
st->stream_putc = NullPutc;
st->stream_wputc = put_wchar;
st->stream_getc = PlGetc;
st->stream_gets = PlGets;
2015-10-05 10:33:52 +01:00
st->stream_wgetc = get_wchar;
st->stream_wgetc_for_read = get_wchar;
2015-12-15 09:14:15 +00:00
if (st->encoding == ENC_ISO_UTF8)
2015-09-21 23:05:36 +01:00
st->stream_getc_for_utf8 = st->stream_getc;
else
st->stream_getc_for_utf8 = GetUTF8;
2015-12-15 09:14:15 +00:00
st->user_name = MkAtomTerm(st->name = AtomDevNull);
2015-10-05 10:33:52 +01:00
UNLOCK(st->streamlock);
2015-12-15 09:14:15 +00:00
t = Yap_MkStream(sno);
return (Yap_unify(ARG1, t));
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
int Yap_OpenStream(FILE *fd, char *name, Term file_name, int flags) {
2015-10-05 10:33:52 +01:00
CACHE_REGS
int sno;
Atom at;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
sno = GetFreeStreamD();
2015-12-15 09:14:15 +00:00
if (sno < 0)
return (PlIOError(RESOURCE_ERROR_MAX_STREAMS, file_name,
"new stream not available for opening"));
2015-10-05 10:33:52 +01:00
if (flags & Output_Stream_f) {
if (flags & Append_Stream_f)
at = AtomAppend;
else
at = AtomWrite;
} else
at = AtomRead;
Yap_initStream(sno, fd, name, file_name, LOCAL_encoding, flags, at);
2015-10-05 10:33:52 +01:00
return sno;
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
#define CheckStream(arg, kind, msg) \
CheckStream__(__FILE__, __FUNCTION__, __LINE__, arg, kind, msg)
2015-10-18 11:49:18 +01:00
2015-12-15 09:14:15 +00:00
static int CheckStream__(const char *file, const char *f, int line, Term arg,
int kind, const char *msg) {
2015-10-05 10:33:52 +01:00
int sno = -1;
2015-12-15 09:14:15 +00:00
arg = Deref(arg);
if (IsVarTerm(arg)) {
2015-10-05 10:33:52 +01:00
Yap_Error(INSTANTIATION_ERROR, arg, msg);
return -1;
2015-12-15 09:14:15 +00:00
} else if (IsAtomTerm(arg)) {
Atom sname = AtomOfTerm(arg);
2015-10-05 10:33:52 +01:00
if (sname == AtomUser) {
if (kind & Input_Stream_f) {
2015-12-15 09:14:15 +00:00
if (kind & (Output_Stream_f | Append_Stream_f)) {
2016-01-03 02:06:09 +00:00
PlIOError__(file, f, line, PERMISSION_ERROR_OUTPUT_STREAM, arg,
2015-12-15 09:14:15 +00:00
"ambiguous use of 'user' as a stream");
2015-10-05 10:33:52 +01:00
return (-1);
}
sname = AtomUserIn;
} else {
sname = AtomUserOut;
2015-06-18 01:39:03 +01:00
}
}
2015-10-05 10:33:52 +01:00
if ((sno = Yap_CheckAlias(sname)) < 0) {
UNLOCK(GLOBAL_Stream[sno].streamlock);
2015-12-15 09:14:15 +00:00
PlIOError__(file, f, line, EXISTENCE_ERROR_STREAM, arg, msg);
2015-10-05 10:33:52 +01:00
return -1;
} else {
LOCK(GLOBAL_Stream[sno].streamlock);
return sno;
}
2015-12-15 09:14:15 +00:00
} else if (IsApplTerm(arg) && FunctorOfTerm(arg) == FunctorStream) {
arg = ArgOfTerm(1, arg);
if (!IsVarTerm(arg) && IsIntegerTerm(arg)) {
2015-10-05 10:33:52 +01:00
sno = IntegerOfTerm(arg);
}
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
if (sno < 0) {
2015-10-05 10:33:52 +01:00
Yap_Error(DOMAIN_ERROR_STREAM_OR_ALIAS, arg, msg);
return (-1);
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
if (GLOBAL_Stream[sno].status & Free_Stream_f) {
PlIOError__(file, f, line, EXISTENCE_ERROR_STREAM, arg, msg);
2015-10-05 10:33:52 +01:00
return (-1);
}
LOCK(GLOBAL_Stream[sno].streamlock);
2015-12-15 09:14:15 +00:00
if ((GLOBAL_Stream[sno].status & Input_Stream_f) &&
!(kind & Input_Stream_f)) {
UNLOCK(GLOBAL_Stream[sno].streamlock);
2016-01-03 02:06:09 +00:00
PlIOError__(file, f, line, PERMISSION_ERROR_OUTPUT_STREAM, arg, msg);
2015-12-15 09:14:15 +00:00
}
if ((GLOBAL_Stream[sno].status & (Append_Stream_f | Output_Stream_f)) &&
!(kind & Output_Stream_f)) {
2015-10-05 10:33:52 +01:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
2016-01-03 02:06:09 +00:00
PlIOError__(file, f, line, PERMISSION_ERROR_INPUT_STREAM, arg, msg);
2015-10-05 10:33:52 +01:00
}
return (sno);
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
int Yap_CheckStream__(const char *file, const char *f, int line, Term arg,
int kind, const char *msg) {
2015-10-18 11:49:18 +01:00
return CheckStream__(file, f, line, arg, kind, msg);
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
int Yap_CheckTextStream__(const char *file, const char *f, int line, Term arg,
int kind, const char *msg) {
int sno;
2015-12-15 09:14:15 +00:00
if ((sno = CheckStream__(file, f, line, arg, kind, msg)) < 0)
return -1;
if ((GLOBAL_Stream[sno].status & Binary_Stream_f)) {
2016-01-03 02:06:09 +00:00
if (kind == Input_Stream_f)
PlIOError__(file, f, line, PERMISSION_ERROR_INPUT_BINARY_STREAM, arg,
msg);
else
PlIOError__(file, f, line, PERMISSION_ERROR_OUTPUT_BINARY_STREAM, arg,
msg);
UNLOCK(GLOBAL_Stream[sno].streamlock);
return -1;
}
return sno;
}
/* used from C-interface */
int Yap_GetFreeStreamDForReading(void) {
int sno = GetFreeStreamD();
StreamDesc *s;
2015-06-18 01:39:03 +01:00
if (sno < 0)
return sno;
s = GLOBAL_Stream + sno;
s->status |= User_Stream_f | Input_Stream_f;
s->charcount = 0;
s->linecount = 1;
s->linepos = 0;
2015-12-15 09:14:15 +00:00
Yap_DefaultStreamOps(s);
UNLOCK(s->streamlock);
return sno;
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static Int always_prompt_user(USES_REGS1) {
StreamDesc *s = GLOBAL_Stream + StdInStream;
2015-10-05 10:33:52 +01:00
s->status |= Promptable_Stream_f;
2015-06-18 01:39:03 +01:00
#if USE_SOCKET
2015-10-05 10:33:52 +01:00
if (s->status & Socket_Stream_f) {
2015-12-15 09:14:15 +00:00
Yap_ConsoleSocketOps(s);
2015-10-05 10:33:52 +01:00
} else
2015-06-18 01:39:03 +01:00
#endif
2015-12-15 09:14:15 +00:00
if (s->status & Pipe_Stream_f) {
Yap_ConsolePipeOps(s);
} else
Yap_ConsoleOps(s);
return (TRUE);
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
static Int close1(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
Int sno = CheckStream(
ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
2015-10-05 10:33:52 +01:00
if (sno < 0)
return (FALSE);
if (sno <= StdErrStream) {
2015-06-18 01:39:03 +01:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
2015-10-05 10:33:52 +01:00
return TRUE;
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
Yap_CloseStream(sno);
UNLOCK(GLOBAL_Stream[sno].streamlock);
return (TRUE);
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
#define CLOSE_DEFS() \
PAR("force", boolean, CLOSE_FORCE), PAR(NULL, ok, CLOSE_END)
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
#define PAR(x, y, z) z
2015-10-05 10:33:52 +01:00
2015-12-15 09:14:15 +00:00
typedef enum close_enum_choices { CLOSE_DEFS() } close_choices_t;
2015-06-18 01:39:03 +01:00
#undef PAR
2015-12-15 09:14:15 +00:00
#define PAR(x, y, z) \
{ x, y, z }
2015-10-05 10:33:52 +01:00
2015-12-15 09:14:15 +00:00
static const param_t close_defs[] = {CLOSE_DEFS()};
2015-06-18 01:39:03 +01:00
#undef PAR
2015-12-15 09:14:15 +00:00
static Int close2(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
Int sno = CheckStream(
ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
2015-10-05 10:33:52 +01:00
Term tlist;
if (sno < 0)
return (FALSE);
if (sno <= StdErrStream) {
2015-06-18 01:39:03 +01:00
UNLOCK(GLOBAL_Stream[sno].streamlock);
2015-10-05 10:33:52 +01:00
return TRUE;
2015-06-18 01:39:03 +01:00
}
2015-12-15 09:14:15 +00:00
xarg *args =
Yap_ArgListToVector((tlist = Deref(ARG2)), close_defs, CLOSE_END);
2015-10-05 10:33:52 +01:00
if (args == NULL)
return FALSE;
// if (args[CLOSE_FORCE].used) {
// }
Yap_CloseStream(sno);
UNLOCK(GLOBAL_Stream[sno].streamlock);
return (TRUE);
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
Term read_line(int sno) {
2015-10-05 10:33:52 +01:00
CACHE_REGS
Term tail;
Int ch;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
if ((ch = GLOBAL_Stream[sno].stream_wgetc(sno)) == 10) {
2015-12-15 09:14:15 +00:00
return (TermNil);
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
tail = read_line(sno);
2015-12-15 09:14:15 +00:00
return (MkPairTerm(MkIntTerm(ch), tail));
2015-10-05 10:33:52 +01:00
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
#define ABSOLUTE_FILE_NAME_DEFS() \
PAR("access", isatom, ABSOLUTE_FILE_NAME_ACCESS), \
PAR("expand", boolean, ABSOLUTE_FILE_NAME_EXPAND), \
PAR("extensions", ok, ABSOLUTE_FILE_NAME_EXTENSIONS), \
PAR("file_type", is_file_type, ABSOLUTE_FILE_NAME_FILE_TYPE), \
PAR("file_errors", is_file_errors, ABSOLUTE_FILE_NAME_FILE_ERRORS), \
PAR("glob", ok, ABSOLUTE_FILE_NAME_GLOB), \
PAR("relative_to", isatom, ABSOLUTE_FILE_NAME_RELATIVE_TO), \
PAR("solutions", issolutions, ABSOLUTE_FILE_NAME_SOLUTIONS), \
PAR("verbose_file_search", boolean, \
ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH), \
PAR(NULL, ok, ABSOLUTE_FILE_NAME_END)
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
#define PAR(x, y, z) z
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
typedef enum ABSOLUTE_FILE_NAME_enum_ {
2015-10-05 10:33:52 +01:00
ABSOLUTE_FILE_NAME_DEFS()
} absolute_file_name_choices_t;
2015-09-21 23:05:36 +01:00
#undef PAR
2015-12-15 09:14:15 +00:00
#define PAR(x, y, z) \
{ x, y, z }
2015-10-05 10:33:52 +01:00
2015-12-15 09:14:15 +00:00
static const param_t absolute_file_name_search_defs[] = {
ABSOLUTE_FILE_NAME_DEFS()};
2015-09-21 23:05:36 +01:00
#undef PAR
2015-12-15 09:14:15 +00:00
static Int abs_file_parameters(USES_REGS1) {
2015-10-05 10:33:52 +01:00
Term t[ABSOLUTE_FILE_NAME_END];
Term tlist = Deref(ARG1), tf;
/* get options */
2015-12-15 09:14:15 +00:00
xarg *args = Yap_ArgListToVector(tlist, absolute_file_name_search_defs,
ABSOLUTE_FILE_NAME_END);
2015-10-05 10:33:52 +01:00
if (args == NULL)
return FALSE;
/* done */
if (args[ABSOLUTE_FILE_NAME_EXTENSIONS].used)
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_EXTENSIONS] =
args[ABSOLUTE_FILE_NAME_EXTENSIONS].tvalue;
2015-10-05 10:33:52 +01:00
else
t[ABSOLUTE_FILE_NAME_EXTENSIONS] = TermNil;
if (args[ABSOLUTE_FILE_NAME_RELATIVE_TO].used)
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_RELATIVE_TO] =
args[ABSOLUTE_FILE_NAME_RELATIVE_TO].tvalue;
2015-10-05 10:33:52 +01:00
else
t[ABSOLUTE_FILE_NAME_RELATIVE_TO] = TermEmptyAtom;
2015-10-05 10:33:52 +01:00
if (args[ABSOLUTE_FILE_NAME_FILE_TYPE].used)
t[ABSOLUTE_FILE_NAME_FILE_TYPE] = args[ABSOLUTE_FILE_NAME_FILE_TYPE].tvalue;
else
t[ABSOLUTE_FILE_NAME_FILE_TYPE] = TermTxt;
if (args[ABSOLUTE_FILE_NAME_ACCESS].used)
t[ABSOLUTE_FILE_NAME_ACCESS] = args[ABSOLUTE_FILE_NAME_ACCESS].tvalue;
else
t[ABSOLUTE_FILE_NAME_ACCESS] = TermNone;
if (args[ABSOLUTE_FILE_NAME_FILE_ERRORS].used)
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_FILE_ERRORS] =
args[ABSOLUTE_FILE_NAME_FILE_ERRORS].tvalue;
2015-10-05 10:33:52 +01:00
else
t[ABSOLUTE_FILE_NAME_FILE_ERRORS] = TermError;
if (args[ABSOLUTE_FILE_NAME_SOLUTIONS].used)
t[ABSOLUTE_FILE_NAME_SOLUTIONS] = args[ABSOLUTE_FILE_NAME_SOLUTIONS].tvalue;
else
t[ABSOLUTE_FILE_NAME_SOLUTIONS] = TermFirst;
if (args[ABSOLUTE_FILE_NAME_EXPAND].used)
t[ABSOLUTE_FILE_NAME_EXPAND] = args[ABSOLUTE_FILE_NAME_EXPAND].tvalue;
else
t[ABSOLUTE_FILE_NAME_EXPAND] = TermFalse;
if (args[ABSOLUTE_FILE_NAME_GLOB].used)
t[ABSOLUTE_FILE_NAME_GLOB] = args[ABSOLUTE_FILE_NAME_GLOB].tvalue;
else
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_GLOB] = TermEmptyAtom;
2015-10-05 10:33:52 +01:00
if (args[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH].used)
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH] =
args[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH].tvalue;
2015-10-05 10:33:52 +01:00
else
2015-12-15 09:14:15 +00:00
t[ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH] =
(trueGlobalPrologFlag(VERBOSE_FILE_SEARCH_FLAG) ? TermTrue : TermFalse);
tf = Yap_MkApplTerm(Yap_MkFunctor(AtomOpt, ABSOLUTE_FILE_NAME_END),
ABSOLUTE_FILE_NAME_END, t);
return (Yap_unify(ARG2, tf));
2015-09-21 23:05:36 +01:00
}
2015-12-15 09:14:15 +00:00
static Int get_abs_file_parameter(USES_REGS1) {
2015-10-05 10:33:52 +01:00
Term t = Deref(ARG1), topts = ARG2;
/* get options */
/* done */
if (t == TermExtensions)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_EXTENSIONS + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermRelativeTo)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3,
ArgOfTerm(ABSOLUTE_FILE_NAME_RELATIVE_TO + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermFileType)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_FILE_TYPE + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermAccess)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_ACCESS + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermFileErrors)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3,
ArgOfTerm(ABSOLUTE_FILE_NAME_FILE_ERRORS + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermSolutions)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_SOLUTIONS + 1, topts));
if (t == TermGlob)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_GLOB + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermExpand)
2015-12-15 09:14:15 +00:00
return Yap_unify(ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_EXPAND + 1, topts));
2015-10-05 10:33:52 +01:00
if (t == TermVerboseFileSearch)
2015-12-15 09:14:15 +00:00
return Yap_unify(
ARG3, ArgOfTerm(ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH + 1, topts));
Yap_Error(DOMAIN_ERROR_ABSOLUTE_FILE_NAME_OPTION, ARG2, NULL);
2015-10-05 10:33:52 +01:00
return false;
2015-09-21 23:05:36 +01:00
}
2015-12-15 09:14:15 +00:00
void Yap_InitPlIO(void) {
2015-10-05 10:33:52 +01:00
Int i;
2015-12-15 09:14:15 +00:00
2015-10-05 10:33:52 +01:00
Yap_stdin = stdin;
Yap_stdout = stdout;
Yap_stderr = stderr;
2015-12-15 09:14:15 +00:00
GLOBAL_Stream =
(StreamDesc *)Yap_AllocCodeSpace(sizeof(StreamDesc) * MaxStreams);
2015-10-05 10:33:52 +01:00
for (i = 0; i < MaxStreams; ++i) {
INIT_LOCK(GLOBAL_Stream[i].streamlock);
GLOBAL_Stream[i].status = Free_Stream_f;
2015-06-18 01:39:03 +01:00
}
2015-10-05 10:33:52 +01:00
InitStdStreams();
}
2015-06-18 01:39:03 +01:00
2015-12-15 09:14:15 +00:00
void Yap_InitIOPreds(void) {
2015-10-05 10:33:52 +01:00
/* here the Input/Output predicates */
2015-12-15 09:14:15 +00:00
Yap_InitCPred("always_prompt_user", 0, always_prompt_user,
SafePredFlag | SyncPredFlag);
Yap_InitCPred("close", 1, close1, SafePredFlag | SyncPredFlag);
Yap_InitCPred("close", 2, close2, SafePredFlag | SyncPredFlag);
Yap_InitCPred("open", 4, open4, SyncPredFlag);
Yap_InitCPred("open", 3, open3, SyncPredFlag);
Yap_InitCPred("abs_file_parameters", 2, abs_file_parameters,
SyncPredFlag | HiddenPredFlag);
Yap_InitCPred("get_abs_file_parameter", 3, get_abs_file_parameter,
SafePredFlag | SyncPredFlag | HiddenPredFlag);
Yap_InitCPred("$file_expansion", 2, p_file_expansion,
SafePredFlag | SyncPredFlag | HiddenPredFlag);
Yap_InitCPred("$open_null_stream", 1, p_open_null_stream,
SafePredFlag | SyncPredFlag | HiddenPredFlag);
2015-10-05 10:33:52 +01:00
Yap_InitIOStreams();
Yap_InitCharsio();
Yap_InitChtypes();
Yap_InitConsole();
2015-12-15 09:14:15 +00:00
Yap_InitReadUtil();
2015-10-05 10:33:52 +01:00
Yap_InitMems();
2015-12-15 09:14:15 +00:00
Yap_InitPipes();
2015-10-05 10:33:52 +01:00
Yap_InitFiles();
Yap_InitWriteTPreds();
Yap_InitReadTPreds();
Yap_InitFormat();
2015-11-05 17:16:10 +00:00
Yap_InitRandomPreds();
2015-10-05 10:33:52 +01:00
Yap_InitReadline();
Yap_InitSockets();
2015-11-05 17:16:10 +00:00
Yap_InitSignalPreds();
2015-10-05 10:33:52 +01:00
Yap_InitSysPreds();
2015-11-05 17:16:10 +00:00
Yap_InitTimePreds();
2015-10-05 10:33:52 +01:00
}