1450 lines
45 KiB
C
1450 lines
45 KiB
C
/*************************************************************************
|
|
* *
|
|
* YAP Prolog *
|
|
* *
|
|
* Yap Prolog was developed at NCCUP - Universidade do Porto *
|
|
* *
|
|
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
|
|
* *
|
|
**************************************************************************
|
|
* *
|
|
* File: iopreds.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 definition of a miscellania of standard predicates
|
|
* for yap refering to: Files and GLOBAL_Streams, Simple Input/Output,
|
|
*
|
|
*/
|
|
|
|
#include "Yap.h"
|
|
#if HAVE_FCNTL_H
|
|
/* for O_BINARY and O_TEXT in WIN32 */
|
|
#include <fcntl.h>
|
|
#endif
|
|
#include "YapHeap.h"
|
|
#include "YapText.h"
|
|
#include "Yatom.h"
|
|
#include "eval.h"
|
|
#include "yapio.h"
|
|
#include <stdlib.h>
|
|
#if HAVE_STDARG_H
|
|
#include <stdarg.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_CTYPE_H
|
|
#include <ctype.h>
|
|
#endif
|
|
#if HAVE_WCTYPE_H
|
|
#include <wctype.h>
|
|
#endif
|
|
#if HAVE_SYS_PARAM_H
|
|
#include <sys/param.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
|
|
#if HAVE_SYS_SELECT_H && !_MSC_VER && !defined(__MINGW32__)
|
|
#include <sys/select.h>
|
|
#endif
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#if HAVE_SIGNAL_H
|
|
#include <signal.h>
|
|
#endif
|
|
#ifdef _WIN32
|
|
#if HAVE_IO_H
|
|
/* Windows */
|
|
#include <io.h>
|
|
#endif
|
|
#endif
|
|
#if !HAVE_STRNCAT
|
|
#define strncat(X, Y, Z) strcat(X, Y)
|
|
#endif
|
|
#if !HAVE_STRNCPY
|
|
#define strncpy(X, Y, Z) strcpy(X, Y)
|
|
#endif
|
|
#if _MSC_VER || defined(__MINGW32__)
|
|
#if HAVE_SOCKET
|
|
#include <winsock2.h>
|
|
#endif
|
|
#include <windows.h>
|
|
#ifndef S_ISDIR
|
|
#define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
|
|
#endif
|
|
#endif
|
|
#include "iopreds.h"
|
|
|
|
#if _MSC_VER || defined(__MINGW32__)
|
|
#define SYSTEM_STAT _stat
|
|
//#include <winbase.h>
|
|
#else
|
|
#define SYSTEM_STAT stat
|
|
#endif
|
|
|
|
static void CloseStream(int sno);
|
|
|
|
FILE *Yap_GetInputStream(Term t, const char *msg) {
|
|
int sno = Yap_CheckStream(t, Input_Stream_f, msg);
|
|
FILE *rc;
|
|
|
|
if (!(GLOBAL_Stream[sno].status &
|
|
(Tty_Stream_f | Socket_Stream_f | Pipe_Stream_f)))
|
|
rc = GLOBAL_Stream[sno].file;
|
|
else
|
|
rc = NULL;
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return rc;
|
|
}
|
|
|
|
FILE *Yap_GetOutputStream(Term t, const char *msg) {
|
|
int sno = Yap_CheckStream(t, Output_Stream_f, msg);
|
|
FILE *rc;
|
|
|
|
if (!(GLOBAL_Stream[sno].status & (Tty_Stream_f | Socket_Stream_f)))
|
|
rc = GLOBAL_Stream[sno].file;
|
|
else
|
|
rc = NULL;
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return rc;
|
|
}
|
|
|
|
int GetFreeStreamD(void) {
|
|
CACHE_REGS
|
|
LOCK(GLOBAL_StreamDescLock);
|
|
int sno;
|
|
for (sno = 0; sno < MaxStreams; ++sno) {
|
|
if (GLOBAL_Stream[sno].status & Free_Stream_f) {
|
|
break;
|
|
}
|
|
}
|
|
if (sno == MaxStreams) {
|
|
UNLOCK(GLOBAL_StreamDescLock);
|
|
return -1;
|
|
}
|
|
LOCK(GLOBAL_Stream[sno].streamlock);
|
|
UNLOCK(GLOBAL_StreamDescLock);
|
|
GLOBAL_Stream[sno].encoding = LOCAL_encoding;
|
|
return sno;
|
|
}
|
|
|
|
int Yap_GetFreeStreamD(void) { return GetFreeStreamD(); }
|
|
|
|
static Term lineCount(int sno) {
|
|
Term tout;
|
|
/* one has to be somewhat more careful because of terminals */
|
|
if (GLOBAL_Stream[sno].status & Tty_Stream_f) {
|
|
Int no = 1;
|
|
int i;
|
|
Atom my_stream;
|
|
#if HAVE_SOCKET
|
|
if (GLOBAL_Stream[sno].status & Socket_Stream_f)
|
|
my_stream = AtomSocket;
|
|
else
|
|
#endif
|
|
if (GLOBAL_Stream[sno].status & Pipe_Stream_f)
|
|
my_stream = AtomPipe;
|
|
else if (GLOBAL_Stream[sno].status & InMemory_Stream_f)
|
|
my_stream = AtomCharsio;
|
|
else
|
|
my_stream = GLOBAL_Stream[sno].name;
|
|
for (i = 0; i < MaxStreams; i++) {
|
|
if ((GLOBAL_Stream[i].status &
|
|
(Socket_Stream_f | Pipe_Stream_f | InMemory_Stream_f)) &&
|
|
!(GLOBAL_Stream[i].status & (Free_Stream_f)) &&
|
|
GLOBAL_Stream[i].name == my_stream)
|
|
no += GLOBAL_Stream[i].linecount - 1;
|
|
}
|
|
tout = MkIntTerm(no);
|
|
} else
|
|
tout = MkIntTerm(GLOBAL_Stream[sno].linecount);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return tout;
|
|
}
|
|
|
|
static Int stream_flags(USES_REGS1) { /* '$stream_flags'(+N,-Flags) */
|
|
Term trm;
|
|
trm = Deref(ARG1);
|
|
if (IsVarTerm(trm) || !IsIntTerm(trm))
|
|
return (FALSE);
|
|
return (Yap_unify_constant(ARG2,
|
|
MkIntTerm(GLOBAL_Stream[IntOfTerm(trm)].status)));
|
|
}
|
|
|
|
static Int p_check_stream(USES_REGS1) { /* '$check_stream'(Stream,Mode) */
|
|
Term mode = Deref(ARG2);
|
|
int sno = Yap_CheckStream(
|
|
ARG1, AtomOfTerm(mode) == AtomRead ? Input_Stream_f : Output_Stream_f,
|
|
"check_stream/2");
|
|
if (sno != -1)
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return sno != -1;
|
|
}
|
|
|
|
static Int p_check_if_stream(USES_REGS1) { /* '$check_stream'(Stream) */
|
|
int sno = Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f |
|
|
Append_Stream_f | Socket_Stream_f,
|
|
"check_stream/1");
|
|
if (sno != -1)
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return sno != -1;
|
|
}
|
|
|
|
static Int
|
|
is_input(int sno USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
bool rc = GLOBAL_Stream[sno].status & Input_Stream_f;
|
|
return rc;
|
|
}
|
|
|
|
static Int
|
|
is_output(int sno USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
bool rc = GLOBAL_Stream[sno].status & (Output_Stream_f | Append_Stream_f);
|
|
return rc;
|
|
}
|
|
|
|
static Int
|
|
has_bom(int sno, Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
bool rc = GLOBAL_Stream[sno].status & HAS_BOM_f;
|
|
if (!IsVarTerm(t2) && !booleanFlag(t2)) {
|
|
// Yap_Error( DOMAIN_ERROR_BOOLEAN, t2, " stream_property/2");
|
|
return false;
|
|
}
|
|
if (rc) {
|
|
return Yap_unify_constant(t2, TermTrue);
|
|
} else {
|
|
return Yap_unify_constant(t2, TermFalse);
|
|
}
|
|
}
|
|
|
|
static Int
|
|
has_reposition(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
bool rc = GLOBAL_Stream[sno].status & Seekable_Stream_f;
|
|
if (!IsVarTerm(t2) && !booleanFlag(t2)) {
|
|
// Yap_Error( DOMAIN_ERROR_BOOLEAN, t2, " stream_property/2");
|
|
return false;
|
|
}
|
|
if (rc) {
|
|
return Yap_unify_constant(t2, TermTrue);
|
|
} else {
|
|
return Yap_unify_constant(t2, TermFalse);
|
|
}
|
|
}
|
|
|
|
char *Yap_guessFileName(FILE *file, int sno, char *nameb, size_t max) {
|
|
size_t maxs = max(255, max);
|
|
if (!nameb) {
|
|
nameb = malloc(maxs + 1);
|
|
}
|
|
if (!file) {
|
|
strncpy(nameb, "memory buffer", maxs);
|
|
return nameb;
|
|
}
|
|
int f = fileno(file);
|
|
if (f < 0) {
|
|
strcpy(nameb, "???");
|
|
return nameb;
|
|
}
|
|
|
|
#if __linux__
|
|
char path[256];
|
|
if (snprintf(path, 255, "/proc/self/fd/%d", f) && readlink(path, nameb, max))
|
|
return nameb;
|
|
#elif __APPLE__
|
|
if (fcntl(f, F_GETPATH, nameb) != -1) {
|
|
return nameb;
|
|
}
|
|
#else
|
|
TCHAR path[MAX_PATH + 1];
|
|
if (!GetFullPathName(path, MAX_PATH, path, NULL))
|
|
return NULL;
|
|
else {
|
|
int i;
|
|
unsigned char *ptr = (unsigned char *)nameb;
|
|
for (i = 0; i < strlen(path); i++)
|
|
ptr += put_utf8(ptr, path[i]);
|
|
*ptr = '\0';
|
|
return nameb;
|
|
}
|
|
#endif
|
|
if (!StreamName(sno)) {
|
|
return NULL;
|
|
}
|
|
return RepAtom(AtomOfTerm(StreamName(sno)))->StrOfAE;
|
|
}
|
|
|
|
static Int representation_error(int sno, Term t2 USES_REGS) {
|
|
stream_flags_t flags =
|
|
GLOBAL_Stream[sno].status & (RepError_Xml_f | RepError_Prolog_f);
|
|
/* '$representation_error'(+Stream,-ErrorMessage) */
|
|
if (!IsVarTerm(t2) && isatom(t2)) {
|
|
return false;
|
|
}
|
|
if (flags & RepError_Xml_f) {
|
|
return Yap_unify(t2, TermXml);
|
|
}
|
|
if (flags & RepError_Prolog_f) {
|
|
return Yap_unify(t2, TermProlog);
|
|
}
|
|
return Yap_unify(t2, TermError);
|
|
}
|
|
|
|
static Int file_name(int sno, Term t2 USES_REGS) {
|
|
return Yap_unify_constant(t2, MkAtomTerm(GLOBAL_Stream[sno].name));
|
|
}
|
|
|
|
static Int file_no(int sno, Term t2 USES_REGS) {
|
|
int f = Yap_GetStreamFd(sno);
|
|
Term rc = MkIntTerm(f);
|
|
if (!IsVarTerm(t2) && !IsIntTerm(t2)) {
|
|
return false;
|
|
}
|
|
return Yap_unify_constant(t2, rc);
|
|
}
|
|
|
|
static bool SetCloseOnAbort(int sno, bool close) {
|
|
if (close) {
|
|
GLOBAL_Stream[sno].status |= DoNotCloseOnAbort_Stream_f;
|
|
} else {
|
|
GLOBAL_Stream[sno].status &= ~DoNotCloseOnAbort_Stream_f;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static Int has_close_on_abort(
|
|
int sno, Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
bool rc = GLOBAL_Stream[sno].status & DoNotCloseOnAbort_Stream_f;
|
|
if (!IsVarTerm(t2)) {
|
|
return t2 == (rc ? TermTrue : TermFalse);
|
|
}
|
|
if (rc) {
|
|
return Yap_unify_constant(t2, TermTrue);
|
|
} else {
|
|
return Yap_unify_constant(t2, TermFalse);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
has_encoding(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
const char *s = enc_name(GLOBAL_Stream[sno].encoding);
|
|
return Yap_unify(t2, MkAtomTerm(Yap_LookupAtom(s)));
|
|
}
|
|
|
|
static bool
|
|
found_eof(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
stream_flags_t flags =
|
|
GLOBAL_Stream[sno].status & (Past_Eof_Stream_f | Eof_Stream_f);
|
|
if (!IsVarTerm(t2) && !(isatom(t2))) {
|
|
return FALSE;
|
|
}
|
|
if (flags & Past_Eof_Stream_f)
|
|
return Yap_unify(t2, MkAtomTerm(AtomPast));
|
|
if (flags & Eof_Stream_f)
|
|
return Yap_unify(t2, MkAtomTerm(AtomAt));
|
|
return Yap_unify(t2, MkAtomTerm(AtomAltNot));
|
|
}
|
|
|
|
static bool
|
|
stream_mode(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
stream_flags_t flags = GLOBAL_Stream[sno].status &
|
|
(Input_Stream_f | Output_Stream_f | Append_Stream_f);
|
|
if (!IsVarTerm(t2) && !(isatom(t2))) {
|
|
return FALSE;
|
|
}
|
|
if (flags & Input_Stream_f)
|
|
return Yap_unify(t2, TermRead);
|
|
if (flags & Output_Stream_f)
|
|
return Yap_unify(t2, TermWrite);
|
|
if (flags & Append_Stream_f)
|
|
return Yap_unify(t2, TermAppend);
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
stream_tty(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
stream_flags_t flags = GLOBAL_Stream[sno].status & (Tty_Stream_f);
|
|
if (!IsVarTerm(t2) && !(isatom(t2))) {
|
|
return FALSE;
|
|
}
|
|
if (flags & Tty_Stream_f)
|
|
return Yap_unify(t2, TermTrue);
|
|
return Yap_unify(t2, TermFalse);
|
|
}
|
|
|
|
static bool
|
|
stream_type(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
stream_flags_t flags = GLOBAL_Stream[sno].status & (Binary_Stream_f);
|
|
if (!IsVarTerm(t2) && !(isatom(t2))) {
|
|
return FALSE;
|
|
}
|
|
if (flags & Binary_Stream_f)
|
|
return Yap_unify(t2, TermBinary);
|
|
return Yap_unify(t2, TermText);
|
|
}
|
|
|
|
static bool
|
|
stream_position(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
Term tout = StreamPosition(sno);
|
|
return Yap_unify(t2, tout);
|
|
}
|
|
|
|
static bool stream_line_count(
|
|
int sno, Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
Term tout = lineCount(sno);
|
|
return Yap_unify(t2, tout);
|
|
}
|
|
|
|
static bool stream_line_number(
|
|
int sno, Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
Term tout = MkIntegerTerm(GLOBAL_Stream[sno].linecount);
|
|
return Yap_unify(t2, tout);
|
|
}
|
|
|
|
static bool
|
|
SetBuffering(int sno, Atom at) { /* '$set_bufferingt'(+Stream,-ErrorMessage) */
|
|
if (at == AtomFull) {
|
|
if (setvbuf(GLOBAL_Stream[sno].file, NULL, _IOFBF, 0) < 0)
|
|
return PlIOError(SYSTEM_ERROR_INTERNAL, Yap_MkStream(sno),
|
|
"could not set buffer");
|
|
} else if (at == AtomLine) {
|
|
if (setvbuf(GLOBAL_Stream[sno].file, NULL, _IOLBF, 0) < 0)
|
|
return PlIOError(SYSTEM_ERROR_INTERNAL, Yap_MkStream(sno),
|
|
"could not set line buffering");
|
|
} else if (at == AtomFalse) {
|
|
if (setvbuf(GLOBAL_Stream[sno].file, NULL, _IONBF, 0) < 0)
|
|
return PlIOError(SYSTEM_ERROR_INTERNAL, Yap_MkStream(sno),
|
|
"could not set disable buffering");
|
|
} else {
|
|
CACHE_REGS
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_OUT_OF_RANGE;
|
|
LOCAL_ErrorMessage = "in set_stream/2:buffer";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool SetBuffer(int sno,
|
|
Int sz) { /* '$set_bufferingt'(+Stream,-ErrorMessage) */
|
|
if (setvbuf(GLOBAL_Stream[sno].file, NULL, _IOFBF, sz) < 0) {
|
|
return PlIOError(SYSTEM_ERROR_INTERNAL, Yap_MkStream(sno),
|
|
"could not set buffer");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
eof_action(int sno,
|
|
Term t2 USES_REGS) { /* '$set_output'(+Stream,-ErrorMessage) */
|
|
stream_flags_t flags =
|
|
GLOBAL_Stream[sno].status &
|
|
(Eof_Error_Stream_f | Reset_Eof_Stream_f | Push_Eof_Stream_f);
|
|
if (!IsVarTerm(t2) && !(isatom(t2))) {
|
|
return FALSE;
|
|
}
|
|
if (flags & Eof_Error_Stream_f) {
|
|
return Yap_unify(t2, TermError);
|
|
}
|
|
if (flags & Reset_Eof_Stream_f) {
|
|
return Yap_unify(t2, TermReset);
|
|
}
|
|
return Yap_unify(t2, TermEOfCode);
|
|
}
|
|
|
|
#define STREAM_PROPERTY_DEFS() \
|
|
PAR("alias", filler, STREAM_PROPERTY_ALIAS) \
|
|
, PAR("bom", filler, STREAM_PROPERTY_BOM), \
|
|
PAR("close_on_abort", filler, STREAM_PROPERTY_CLOSE_ON_ABORT), \
|
|
PAR("encoding", filler, STREAM_PROPERTY_ENCODING), \
|
|
PAR("end_of_stream", filler, STREAM_PROPERTY_END_OF_STREAM), \
|
|
PAR("eof_action", filler, STREAM_PROPERTY_EOF_ACTION), \
|
|
PAR("file_name", filler, STREAM_PROPERTY_FILE_NAME), \
|
|
PAR("file_no", filler, STREAM_PROPERTY_FILE_NO), \
|
|
PAR("input", ok, STREAM_PROPERTY_INPUT), \
|
|
PAR("line_count", ok, STREAM_PROPERTY_LINE_COUNT), \
|
|
PAR("line_number", ok, STREAM_PROPERTY_LINE_NUMBER), \
|
|
PAR("mode", filler, STREAM_PROPERTY_MODE), \
|
|
PAR("output", filler, STREAM_PROPERTY_OUTPUT), \
|
|
PAR("position", isatom, STREAM_PROPERTY_POSITION), \
|
|
PAR("reposition", filler, STREAM_PROPERTY_REPOSITION), \
|
|
PAR("representation_errors", filler, \
|
|
STREAM_PROPERTY_REPRESENTATION_ERRORS), \
|
|
PAR("type", filler, STREAM_PROPERTY_TYPE), \
|
|
PAR("tty", filler, STREAM_PROPERTY_TTY), \
|
|
PAR(NULL, ok, STREAM_PROPERTY_END)
|
|
|
|
#define PAR(x, y, z) z
|
|
|
|
typedef enum stream_property_enum_choices {
|
|
STREAM_PROPERTY_DEFS()
|
|
} stream_property_choices_t;
|
|
|
|
#undef PAR
|
|
|
|
#define PAR(x, y, z) \
|
|
{ x, y, z }
|
|
|
|
static const param_t stream_property_defs[] = {STREAM_PROPERTY_DEFS()};
|
|
#undef PAR
|
|
|
|
static bool do_stream_property(int sno,
|
|
xarg *args USES_REGS) { /* Init current_stream */
|
|
stream_property_choices_t i;
|
|
bool rc = true;
|
|
|
|
for (i = 0; i < STREAM_PROPERTY_END; i++) {
|
|
if (args[i].used) {
|
|
switch (i) {
|
|
case STREAM_PROPERTY_ALIAS: {
|
|
Term ta = args[STREAM_PROPERTY_ALIAS].tvalue;
|
|
rc = rc & Yap_FetchStreamAlias(sno, ta PASS_REGS);
|
|
} break;
|
|
case STREAM_PROPERTY_BOM:
|
|
rc = rc && has_bom(sno, args[STREAM_PROPERTY_BOM].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_CLOSE_ON_ABORT:
|
|
rc = rc &&
|
|
has_close_on_abort(
|
|
sno, args[STREAM_PROPERTY_CLOSE_ON_ABORT].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_ENCODING:
|
|
rc = rc &&
|
|
has_encoding(sno, args[STREAM_PROPERTY_ENCODING].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_END_OF_STREAM:
|
|
rc = rc &&
|
|
found_eof(sno,
|
|
args[STREAM_PROPERTY_END_OF_STREAM].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_EOF_ACTION:
|
|
rc = rc &&
|
|
eof_action(sno, args[STREAM_PROPERTY_EOF_ACTION].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_FILE_NAME:
|
|
rc = rc &&
|
|
file_name(sno, args[STREAM_PROPERTY_FILE_NAME].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_FILE_NO:
|
|
rc = rc && file_no(sno, args[STREAM_PROPERTY_FILE_NO].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_INPUT:
|
|
rc = rc && is_input(sno PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_LINE_NUMBER:
|
|
rc = rc && stream_line_number(
|
|
sno, args[STREAM_PROPERTY_LINE_NUMBER].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_LINE_COUNT:
|
|
rc = rc && stream_line_count(
|
|
sno, args[STREAM_PROPERTY_LINE_COUNT].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_MODE:
|
|
rc =
|
|
rc && stream_mode(sno, args[STREAM_PROPERTY_MODE].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_OUTPUT:
|
|
rc = rc && is_output(sno PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_POSITION:
|
|
rc = rc && stream_position(
|
|
sno, args[STREAM_PROPERTY_POSITION].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_REPOSITION:
|
|
rc = rc && has_reposition(
|
|
sno, args[STREAM_PROPERTY_REPOSITION].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_REPRESENTATION_ERRORS:
|
|
rc = rc &&
|
|
representation_error(
|
|
sno,
|
|
args[STREAM_PROPERTY_REPRESENTATION_ERRORS].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_TYPE:
|
|
rc =
|
|
rc && stream_type(sno, args[STREAM_PROPERTY_TYPE].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_TTY:
|
|
rc = rc && stream_tty(sno, args[STREAM_PROPERTY_TTY].tvalue PASS_REGS);
|
|
break;
|
|
case STREAM_PROPERTY_END:
|
|
rc = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static xarg *generate_property(int sno, Term t2,
|
|
stream_property_choices_t p USES_REGS) {
|
|
if (p == STREAM_PROPERTY_INPUT)
|
|
Yap_unify(t2, MkAtomTerm(AtomInput));
|
|
else if (p == STREAM_PROPERTY_OUTPUT)
|
|
Yap_unify(t2, MkAtomTerm(AtomOutput));
|
|
else {
|
|
Functor f = Yap_MkFunctor(Yap_LookupAtom(stream_property_defs[p].name), 1);
|
|
Yap_unify(t2, Yap_MkNewApplTerm(f, 1));
|
|
}
|
|
return Yap_ArgListToVector(t2, stream_property_defs, STREAM_PROPERTY_END);
|
|
}
|
|
|
|
static Int cont_stream_property(USES_REGS1) { /* current_stream */
|
|
bool det;
|
|
xarg *args;
|
|
int i = IntOfTerm(EXTRA_CBACK_ARG(2, 1));
|
|
stream_property_choices_t p = STREAM_PROPERTY_END;
|
|
bool rc;
|
|
Term t2 = Deref(ARG2);
|
|
Term t1 = Deref(ARG1);
|
|
|
|
if (IsVarTerm(t2)) {
|
|
p = IntOfTerm(EXTRA_CBACK_ARG(2, 2));
|
|
args = generate_property(i, t2, p++ PASS_REGS);
|
|
|
|
EXTRA_CBACK_ARG(2, 2) = MkIntTerm(p % STREAM_PROPERTY_END);
|
|
// otherwise, just drop through
|
|
} else {
|
|
args = Yap_ArgListToVector(t2, stream_property_defs, STREAM_PROPERTY_END);
|
|
}
|
|
if (args == NULL) {
|
|
if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
|
|
if (LOCAL_Error_TYPE == DOMAIN_ERROR_GENERIC_ARGUMENT)
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_STREAM_PROPERTY_OPTION;
|
|
Yap_Error(LOCAL_Error_TYPE, LOCAL_Error_Term, NULL);
|
|
return false;
|
|
}
|
|
cut_fail();
|
|
}
|
|
LOCK(GLOBAL_Stream[i].streamlock);
|
|
if (IsAtomTerm(args[STREAM_PROPERTY_ALIAS].tvalue)) {
|
|
// one solution only
|
|
i = Yap_CheckAlias(AtomOfTerm(args[STREAM_PROPERTY_ALIAS].tvalue));
|
|
free(args) UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
if (i < 0 || !Yap_unify(ARG1, Yap_MkStream(i))) {
|
|
cut_fail();
|
|
}
|
|
cut_succeed();
|
|
}
|
|
LOCK(GLOBAL_Stream[i].streamlock);
|
|
rc = do_stream_property(i, args PASS_REGS);
|
|
UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
if (IsVarTerm(t1)) {
|
|
if (rc)
|
|
rc = Yap_unify(ARG1, Yap_MkStream(i));
|
|
if (p == STREAM_PROPERTY_END) {
|
|
// move to next existing stream
|
|
LOCK(GLOBAL_StreamDescLock);
|
|
while (++i < MaxStreams && GLOBAL_Stream[i].status & Free_Stream_f) {
|
|
}
|
|
UNLOCK(GLOBAL_StreamDescLock);
|
|
if (i < MaxStreams) {
|
|
EXTRA_CBACK_ARG(2, 1) = MkIntTerm(i);
|
|
det = false;
|
|
} else {
|
|
det = true;
|
|
}
|
|
} else {
|
|
det = false;
|
|
}
|
|
} else {
|
|
// done
|
|
det = (p == STREAM_PROPERTY_END);
|
|
}
|
|
free(args);
|
|
if (rc) {
|
|
if (det)
|
|
cut_succeed();
|
|
else {
|
|
return true;
|
|
}
|
|
} else if (det) {
|
|
cut_fail();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Int stream_property(USES_REGS1) { /* Init current_stream */
|
|
Term t1 = Deref(ARG1);
|
|
Term t2 = Deref(ARG2);
|
|
// Yap_DebugPlWrite(ARG1);fprintf(stderr,", ");
|
|
// Yap_DebugPlWrite(ARG2);fprintf(stderr,"\n");
|
|
|
|
/* make valgrind happy by always filling in memory */
|
|
EXTRA_CBACK_ARG(2, 1) = MkIntTerm(0);
|
|
EXTRA_CBACK_ARG(2, 2) = MkIntTerm(0);
|
|
if (!IsVarTerm(t1)) {
|
|
Int i;
|
|
xarg *args;
|
|
|
|
i = Yap_CheckStream(t1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"current_stream/3");
|
|
if (i < 0) {
|
|
UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
return false; // error...
|
|
}
|
|
EXTRA_CBACK_ARG(2, 1) = MkIntTerm(i);
|
|
if (IsVarTerm(t2)) {
|
|
return cont_stream_property(PASS_REGS1);
|
|
}
|
|
args = Yap_ArgListToVector(Deref(ARG2), stream_property_defs,
|
|
STREAM_PROPERTY_END);
|
|
if (args == NULL) {
|
|
if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
|
|
if (LOCAL_Error_TYPE == DOMAIN_ERROR_PROLOG_FLAG)
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_STREAM_PROPERTY_OPTION;
|
|
Yap_Error(LOCAL_Error_TYPE, LOCAL_Error_Term, NULL);
|
|
return false;
|
|
}
|
|
UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
cut_fail();
|
|
}
|
|
if (do_stream_property(i, args PASS_REGS)) {
|
|
UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
free(args);
|
|
cut_succeed();
|
|
} else {
|
|
UNLOCK(GLOBAL_Stream[i].streamlock);
|
|
free(args);
|
|
cut_fail();
|
|
}
|
|
} else {
|
|
return cont_stream_property(PASS_REGS1);
|
|
}
|
|
}
|
|
|
|
#define SET_STREAM_DEFS() \
|
|
PAR("alias", isatom, SET_STREAM_ALIAS) \
|
|
, PAR("buffer", booleanFlag, SET_STREAM_BUFFER), \
|
|
PAR("buffer_size", nat, SET_STREAM_BUFFER_SIZE), \
|
|
PAR("close_on_abort", booleanFlag, SET_STREAM_CLOSE_ON_ABORT), \
|
|
PAR("encoding", isatom, SET_STREAM_ENCODING), \
|
|
PAR("eof_action", isatom, SET_STREAM_EOF_ACTION), \
|
|
PAR("file_name", isatom, SET_STREAM_FILE_NAME), \
|
|
PAR("line_position", nat, SET_STREAM_LINE_POSITION), \
|
|
PAR("newline", filler, SET_STREAM_NEWLINE), \
|
|
PAR("record_position", isatom, SET_STREAM_RECORD_POSITION), \
|
|
PAR("representation_errors", isatom, SET_STREAM_REPRESENTATION_ERRORS), \
|
|
PAR("type", isatom, SET_STREAM_TYPE), \
|
|
PAR("tty", filler, SET_STREAM_TTY), PAR(NULL, ok, SET_STREAM_END)
|
|
|
|
#define PAR(x, y, z) z
|
|
|
|
typedef enum set_stream_enum_choices {
|
|
SET_STREAM_DEFS()
|
|
} set_stream_enum_choices_t;
|
|
|
|
#undef PAR
|
|
|
|
#define PAR(x, y, z) \
|
|
{ x, y, z }
|
|
|
|
static const param_t set_stream_defs[] = {SET_STREAM_DEFS()};
|
|
#undef PAR
|
|
|
|
static bool do_set_stream(int sno,
|
|
Term opts USES_REGS) { /* Init current_stream */
|
|
xarg *args;
|
|
set_stream_enum_choices_t i;
|
|
bool rc = true;
|
|
|
|
args = Yap_ArgListToVector(opts, set_stream_defs, SET_STREAM_END);
|
|
if (args == NULL) {
|
|
if (LOCAL_Error_TYPE != YAP_NO_ERROR) {
|
|
if (LOCAL_Error_TYPE == DOMAIN_ERROR_GENERIC_ARGUMENT)
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_SET_STREAM_OPTION;
|
|
Yap_Error(LOCAL_Error_TYPE, LOCAL_Error_Term, NULL);
|
|
}
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return false;
|
|
}
|
|
for (i = 0; i < SET_STREAM_END; i++) {
|
|
if (args[i].used) {
|
|
Term t = args[i].tvalue;
|
|
switch (i) {
|
|
case SET_STREAM_ALIAS:
|
|
rc = rc && Yap_AddAlias(AtomOfTerm(t), sno);
|
|
break;
|
|
case SET_STREAM_BUFFER:
|
|
rc = rc && SetBuffering(sno, AtomOfTerm(t));
|
|
break;
|
|
case SET_STREAM_BUFFER_SIZE:
|
|
rc = rc && SetBuffer(sno, IntegerOfTerm(t));
|
|
break;
|
|
case SET_STREAM_CLOSE_ON_ABORT:
|
|
rc = rc &&
|
|
SetCloseOnAbort(
|
|
sno, (args[SET_STREAM_CLOSE_ON_ABORT].tvalue == TermTrue));
|
|
break;
|
|
case SET_STREAM_ENCODING: {
|
|
Term t2 = args[SET_STREAM_ENCODING].tvalue;
|
|
Atom atEnc = AtomOfTerm(t2);
|
|
GLOBAL_Stream[sno].encoding =
|
|
enc_id(atEnc->StrOfAE, (GLOBAL_Stream[sno].status & HAS_BOM_f
|
|
? GLOBAL_Stream[sno].encoding
|
|
: ENC_OCTET));
|
|
Yap_DefaultStreamOps(GLOBAL_Stream + sno);
|
|
} break;
|
|
case SET_STREAM_EOF_ACTION: {
|
|
Term t2 = args[SET_STREAM_EOF_ACTION].tvalue;
|
|
if (t2 == TermError) {
|
|
GLOBAL_Stream[sno].status |= Eof_Error_Stream_f;
|
|
GLOBAL_Stream[sno].status &= ~Reset_Eof_Stream_f;
|
|
} else if (t2 == TermReset) {
|
|
GLOBAL_Stream[sno].status &= ~Eof_Error_Stream_f;
|
|
GLOBAL_Stream[sno].status |= Reset_Eof_Stream_f;
|
|
} else if (t2 == TermEOfCode) {
|
|
GLOBAL_Stream[sno].status &= ~Eof_Error_Stream_f;
|
|
GLOBAL_Stream[sno].status &= ~Reset_Eof_Stream_f;
|
|
} else {
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_OUT_OF_RANGE;
|
|
LOCAL_ErrorMessage = "in set_stream/2:eof_action";
|
|
rc = false;
|
|
}
|
|
break;
|
|
case SET_STREAM_FILE_NAME:
|
|
GLOBAL_Stream[sno].user_name = args[SET_STREAM_FILE_NAME].tvalue;
|
|
break;
|
|
case SET_STREAM_LINE_POSITION:
|
|
GLOBAL_Stream[sno].linepos =
|
|
IntegerOfTerm(args[SET_STREAM_FILE_NAME].tvalue);
|
|
break;
|
|
case SET_STREAM_NEWLINE:
|
|
printf("not yet\n");
|
|
break;
|
|
case SET_STREAM_RECORD_POSITION:
|
|
if (args[SET_STREAM_RECORD_POSITION].tvalue == TermTrue)
|
|
GLOBAL_Stream[sno].status |= Seekable_Stream_f;
|
|
else
|
|
GLOBAL_Stream[sno].status &= ~Seekable_Stream_f;
|
|
break;
|
|
case SET_STREAM_REPRESENTATION_ERRORS: {
|
|
Term t2 = args[SET_STREAM_EOF_ACTION].tvalue;
|
|
if (t2 == TermXml) {
|
|
GLOBAL_Stream[sno].status |= RepError_Xml_f;
|
|
GLOBAL_Stream[sno].status &= ~RepError_Prolog_f;
|
|
} else if (t2 == TermError) {
|
|
GLOBAL_Stream[sno].status &= ~RepError_Xml_f;
|
|
GLOBAL_Stream[sno].status |= RepError_Prolog_f;
|
|
} else if (t2 == TermEOfCode) {
|
|
GLOBAL_Stream[sno].status &= ~RepError_Xml_f;
|
|
GLOBAL_Stream[sno].status |= RepError_Prolog_f;
|
|
} else {
|
|
LOCAL_Error_TYPE = DOMAIN_ERROR_OUT_OF_RANGE;
|
|
LOCAL_ErrorMessage = "in set_stream/2:eof_action";
|
|
rc = false;
|
|
}
|
|
} break;
|
|
case SET_STREAM_TYPE:
|
|
rc &= stream_type(sno, args[SET_STREAM_TYPE].tvalue PASS_REGS);
|
|
break;
|
|
case SET_STREAM_TTY:
|
|
rc &= stream_tty(sno, args[SET_STREAM_TTY].tvalue PASS_REGS);
|
|
break;
|
|
case SET_STREAM_END:
|
|
rc = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return rc;
|
|
}
|
|
|
|
static Int set_stream(USES_REGS1) { /* Init current_stream */
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"set_stream_position/2");
|
|
if (sno < 0) {
|
|
return false;
|
|
}
|
|
return do_set_stream(sno, Deref(ARG2) PASS_REGS);
|
|
}
|
|
|
|
/*
|
|
* Called when you want to close all open streams, except for stdin, stdout
|
|
* and stderr
|
|
*/
|
|
void Yap_CloseStreams(int loud) {
|
|
CACHE_REGS
|
|
int sno;
|
|
fflush(NULL);
|
|
for (sno = 3; sno < MaxStreams; ++sno) {
|
|
if (GLOBAL_Stream[sno].status & Free_Stream_f)
|
|
continue;
|
|
CloseStream(sno);
|
|
}
|
|
}
|
|
|
|
static void CloseStream(int sno) {
|
|
CACHE_REGS
|
|
|
|
fflush(NULL);
|
|
if (!(GLOBAL_Stream[sno].status &
|
|
(Null_Stream_f | Socket_Stream_f | InMemory_Stream_f | Pipe_Stream_f)))
|
|
fclose(GLOBAL_Stream[sno].file);
|
|
#if HAVE_SOCKET
|
|
else if (GLOBAL_Stream[sno].status & (Socket_Stream_f)) {
|
|
Yap_CloseSocket(GLOBAL_Stream[sno].u.socket.fd,
|
|
GLOBAL_Stream[sno].u.socket.flags,
|
|
GLOBAL_Stream[sno].u.socket.domain);
|
|
}
|
|
#endif
|
|
else if (GLOBAL_Stream[sno].status & Pipe_Stream_f) {
|
|
close(GLOBAL_Stream[sno].u.pipe.fd);
|
|
} else if (GLOBAL_Stream[sno].status & (InMemory_Stream_f)) {
|
|
Yap_CloseMemoryStream(sno);
|
|
}
|
|
GLOBAL_Stream[sno].status = Free_Stream_f;
|
|
Yap_DeleteAliases(sno);
|
|
if (LOCAL_c_input_stream == sno) {
|
|
LOCAL_c_input_stream = StdInStream;
|
|
} else if (LOCAL_c_output_stream == sno) {
|
|
LOCAL_c_output_stream = StdOutStream;
|
|
} else if (LOCAL_c_error_stream == sno) {
|
|
LOCAL_c_error_stream = StdErrStream;
|
|
}
|
|
/* if (st->status == Socket_Stream_f|Input_Stream_f|Output_Stream_f) {
|
|
Yap_CloseSocket();
|
|
}
|
|
*/
|
|
}
|
|
|
|
void Yap_CloseStream(int sno) { CloseStream(sno); }
|
|
|
|
void Yap_ReleaseStream(int sno) {
|
|
CACHE_REGS
|
|
GLOBAL_Stream[sno].status = Free_Stream_f;
|
|
GLOBAL_Stream[sno].user_name = 0;
|
|
Yap_DeleteAliases(sno);
|
|
if (LOCAL_c_input_stream == sno) {
|
|
LOCAL_c_input_stream = StdInStream;
|
|
} else if (LOCAL_c_output_stream == sno) {
|
|
LOCAL_c_output_stream = StdOutStream;
|
|
} else if (LOCAL_c_error_stream == sno) {
|
|
LOCAL_c_error_stream = StdErrStream;
|
|
}
|
|
/* if (st->status == Socket_Stream_f|Input_Stream_f|Output_Stream_f) {
|
|
Yap_CloseSocket();
|
|
}
|
|
*/
|
|
}
|
|
|
|
static Int current_input(USES_REGS1) { /* current_input(?Stream) */
|
|
Term t1 = Deref(ARG1);
|
|
if (IsVarTerm(t1)) {
|
|
Term t = Yap_MkStream(LOCAL_c_input_stream);
|
|
YapBind(VarOfTerm(t1), t);
|
|
return TRUE;
|
|
} else if (!IsApplTerm(t1) || FunctorOfTerm(t1) != FunctorStream ||
|
|
!IsIntTerm((t1 = ArgOfTerm(1, t1)))) {
|
|
Yap_Error(DOMAIN_ERROR_STREAM, t1, "current_input/1");
|
|
return FALSE;
|
|
} else {
|
|
return LOCAL_c_input_stream == IntOfTerm(t1);
|
|
}
|
|
}
|
|
|
|
/** @pred set_input(+ _S_) is iso
|
|
* Set stream _S_ as the current input stream. Predicates like read/1
|
|
* and get/1 will start using stream _S_ by default.
|
|
*
|
|
*
|
|
* @param Input-mode stream
|
|
*
|
|
*/
|
|
static Int set_input(USES_REGS1) { /* '$show_stream_position'(+Stream,Pos) */
|
|
int sno = Yap_CheckStream(ARG1, Input_Stream_f, "set_input/1");
|
|
if (sno < 0)
|
|
return false;
|
|
LOCAL_c_input_stream = sno;
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return true;
|
|
}
|
|
|
|
static Int current_output(USES_REGS1) { /* current_output(?Stream) */
|
|
Term t1 = Deref(ARG1);
|
|
if (IsVarTerm(t1)) {
|
|
Term t = Yap_MkStream(LOCAL_c_output_stream);
|
|
YapBind(VarOfTerm(t1), t);
|
|
return TRUE;
|
|
} else if (!IsApplTerm(t1) || FunctorOfTerm(t1) != FunctorStream ||
|
|
!IsIntTerm((t1 = ArgOfTerm(1, t1)))) {
|
|
Yap_Error(DOMAIN_ERROR_STREAM, t1, "current_output/1");
|
|
return FALSE;
|
|
} else {
|
|
return (LOCAL_c_output_stream == IntOfTerm(t1));
|
|
}
|
|
}
|
|
|
|
/** @pred set_input(+ _S_) is iso
|
|
* Set stream _S_ as the current input stream. Predicates like read/1
|
|
* and get/1 will start using stream _S_ by default.
|
|
*
|
|
*
|
|
* @param Output-mode stream
|
|
*
|
|
*/
|
|
static Int set_output(USES_REGS1) { /* '$show_stream_position'(+Stream,Pos) */
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Output_Stream_f | Append_Stream_f, "set_output/2");
|
|
if (sno < 0)
|
|
return false;
|
|
LOCAL_c_output_stream = sno;
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return true;
|
|
}
|
|
|
|
static Int p_user_file_name(USES_REGS1) {
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"user_file_name/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
tout = Yap_StreamUserName(sno);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (Yap_unify_constant(ARG2, tout));
|
|
}
|
|
|
|
static Int p_file_name(USES_REGS1) {
|
|
Term tout;
|
|
int sno = Yap_CheckStream(
|
|
ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f, "file_name/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
#if HAVE_SOCKET
|
|
if (GLOBAL_Stream[sno].status & Socket_Stream_f)
|
|
tout = MkAtomTerm(AtomSocket);
|
|
else
|
|
#endif
|
|
if (GLOBAL_Stream[sno].status & Pipe_Stream_f)
|
|
tout = MkAtomTerm(AtomPipe);
|
|
else if (GLOBAL_Stream[sno].status & InMemory_Stream_f)
|
|
tout = MkAtomTerm(AtomCharsio);
|
|
else
|
|
tout = MkAtomTerm(GLOBAL_Stream[sno].name);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return Yap_unify_constant(ARG2, tout);
|
|
}
|
|
|
|
static Int line_count(USES_REGS1) { /* '$current_line_number'(+Stream,-N) */
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"current_line_number/2");
|
|
if (sno < 0)
|
|
return (false);
|
|
tout = lineCount(sno);
|
|
return (Yap_unify_constant(ARG2, tout));
|
|
}
|
|
|
|
static Int p_line_position(USES_REGS1) { /* '$line_position'(+Stream,-N) */
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"line_position/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
if (GLOBAL_Stream[sno].status & Tty_Stream_f) {
|
|
Int no = 0;
|
|
int i;
|
|
Atom my_stream = GLOBAL_Stream[sno].name;
|
|
for (i = 0; i < MaxStreams; i++) {
|
|
if (!(GLOBAL_Stream[i].status & Free_Stream_f) &&
|
|
GLOBAL_Stream[i].name == my_stream)
|
|
no += GLOBAL_Stream[i].linepos;
|
|
}
|
|
tout = MkIntTerm(no);
|
|
} else
|
|
tout = MkIntTerm(GLOBAL_Stream[sno].linepos);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (Yap_unify_constant(ARG2, tout));
|
|
}
|
|
|
|
static Int p_character_count(USES_REGS1) { /* '$character_count'(+Stream,-N) */
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"character_count/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
if (GLOBAL_Stream[sno].status & Tty_Stream_f) {
|
|
Int no = 0;
|
|
int i;
|
|
Atom my_stream = GLOBAL_Stream[sno].name;
|
|
for (i = 0; i < MaxStreams; i++) {
|
|
if (!(GLOBAL_Stream[i].status & Free_Stream_f) &&
|
|
GLOBAL_Stream[i].name == my_stream)
|
|
no += GLOBAL_Stream[i].charcount;
|
|
}
|
|
tout = MkIntTerm(no);
|
|
} else if (GLOBAL_Stream[sno].status & Null_Stream_f)
|
|
tout = MkIntTerm(GLOBAL_Stream[sno].charcount);
|
|
else
|
|
tout = MkIntTerm(ftell(GLOBAL_Stream[sno].file));
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (Yap_unify_constant(ARG2, tout));
|
|
}
|
|
|
|
static Int
|
|
p_show_stream_flags(USES_REGS1) { /* '$show_stream_flags'(+Stream,Pos) */
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"stream_property/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
tout = MkIntTerm(GLOBAL_Stream[sno].status);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (Yap_unify(ARG2, tout));
|
|
}
|
|
|
|
Term Yap_StreamPosition(int sno) { return StreamPosition(sno); }
|
|
|
|
static Int p_show_stream_position(
|
|
USES_REGS1) { /* '$show_stream_position'(+Stream,Pos) */
|
|
Term tout;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"stream_position/2");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
tout = StreamPosition(sno);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return Yap_unify(ARG2, tout);
|
|
}
|
|
|
|
static Int
|
|
set_stream_position(USES_REGS1) { /* '$set_stream_position'(+Stream,Pos) */
|
|
Term tin, tp;
|
|
Int char_pos;
|
|
int sno =
|
|
Yap_CheckStream(ARG1, Input_Stream_f | Output_Stream_f | Append_Stream_f,
|
|
"set_stream_position/2");
|
|
if (sno < 0) {
|
|
return false;
|
|
}
|
|
tin = Deref(ARG2);
|
|
if (IsVarTerm(tin)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(INSTANTIATION_ERROR, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
} else if (!(IsApplTerm(tin))) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(DOMAIN_ERROR_STREAM_POSITION, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
if (FunctorOfTerm(tin) == FunctorStreamPos) {
|
|
if (IsVarTerm(tp = ArgOfTerm(1, tin))) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(INSTANTIATION_ERROR, tp, "set_stream_position/2");
|
|
return (FALSE);
|
|
} else if (!IsIntTerm(tp)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(DOMAIN_ERROR_STREAM_POSITION, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
if (!(GLOBAL_Stream[sno].status & Seekable_Stream_f)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(PERMISSION_ERROR_REPOSITION_STREAM, ARG1,
|
|
"set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
char_pos = IntOfTerm(tp);
|
|
if (IsVarTerm(tp = ArgOfTerm(2, tin))) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(INSTANTIATION_ERROR, tp, "set_stream_position/2");
|
|
return (FALSE);
|
|
} else if (!IsIntTerm(tp)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(DOMAIN_ERROR_STREAM_POSITION, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
GLOBAL_Stream[sno].charcount = char_pos;
|
|
GLOBAL_Stream[sno].linecount = IntOfTerm(tp);
|
|
if (IsVarTerm(tp = ArgOfTerm(3, tin))) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(INSTANTIATION_ERROR, tp, "set_stream_position/2");
|
|
return (FALSE);
|
|
} else if (!IsIntTerm(tp)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(DOMAIN_ERROR_STREAM_POSITION, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
GLOBAL_Stream[sno].linepos = IntOfTerm(tp);
|
|
if (fseek(GLOBAL_Stream[sno].file, (long)(char_pos), 0) == -1) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, tp,
|
|
"fseek failed for set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
GLOBAL_Stream[sno].stream_getc = PlGetc;
|
|
} else if (FunctorOfTerm(tin) == FunctorStreamEOS) {
|
|
if (IsVarTerm(tp = ArgOfTerm(1, tin))) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(INSTANTIATION_ERROR, tp, "set_stream_position/2");
|
|
return (FALSE);
|
|
} else if (tp != MkAtomTerm(AtomAt)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
Yap_Error(DOMAIN_ERROR_STREAM_POSITION, tin, "set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
if (!(GLOBAL_Stream[sno].status & Seekable_Stream_f)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
PlIOError(PERMISSION_ERROR_REPOSITION_STREAM, ARG1,
|
|
"set_stream_position/2");
|
|
return (FALSE);
|
|
}
|
|
if (fseek(GLOBAL_Stream[sno].file, 0L, SEEK_END) == -1) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
PlIOError(SYSTEM_ERROR_INTERNAL, tp,
|
|
"fseek failed for set_stream_position/2: %s", strerror(errno));
|
|
return (FALSE);
|
|
}
|
|
GLOBAL_Stream[sno].stream_getc = PlGetc;
|
|
/* reset the counters */
|
|
GLOBAL_Stream[sno].linepos = 0;
|
|
GLOBAL_Stream[sno].linecount = 1;
|
|
GLOBAL_Stream[sno].charcount = 0;
|
|
}
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (TRUE);
|
|
}
|
|
|
|
#if HAVE_SELECT
|
|
/* stream_select(+Streams,+TimeOut,-Result) */
|
|
static Int p_stream_select(USES_REGS1) {
|
|
Term t1 = Deref(ARG1), t2;
|
|
fd_set readfds, writefds, exceptfds;
|
|
struct timeval timeout, *ptime;
|
|
|
|
#if _MSC_VER
|
|
u_int fdmax = 0;
|
|
#else
|
|
int fdmax = 0;
|
|
#endif
|
|
Term tout = TermNil, ti, Head;
|
|
|
|
if (IsVarTerm(t1)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t1, "stream_select/3");
|
|
return FALSE;
|
|
}
|
|
if (!IsPairTerm(t1)) {
|
|
Yap_Error(TYPE_ERROR_LIST, t1, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
FD_ZERO(&readfds);
|
|
FD_ZERO(&writefds);
|
|
FD_ZERO(&exceptfds);
|
|
ti = t1;
|
|
while (ti != TermNil) {
|
|
#if _MSC_VER
|
|
u_int fd;
|
|
#else
|
|
int fd;
|
|
#endif
|
|
int sno;
|
|
|
|
Head = HeadOfTerm(ti);
|
|
sno = Yap_CheckStream(Head, Input_Stream_f, "stream_select/3");
|
|
if (sno < 0)
|
|
return (FALSE);
|
|
fd = GetStreamFd(sno);
|
|
FD_SET(fd, &readfds);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
if (fd > fdmax)
|
|
fdmax = fd;
|
|
ti = TailOfTerm(ti);
|
|
}
|
|
t2 = Deref(ARG2);
|
|
if (IsVarTerm(t2)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
if (IsAtomTerm(t2)) {
|
|
if (t2 == MkAtomTerm(AtomOff)) {
|
|
/* wait indefinitely */
|
|
ptime = NULL;
|
|
} else {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t1, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
} else {
|
|
Term t21, t22;
|
|
|
|
if (!IsApplTerm(t2) || FunctorOfTerm(t2) != FunctorModule) {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
t21 = ArgOfTerm(1, t2);
|
|
if (IsVarTerm(t21)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
if (!IsIntegerTerm(t21)) {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
timeout.tv_sec = IntegerOfTerm(t21);
|
|
if (timeout.tv_sec < 0) {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
t22 = ArgOfTerm(2, t2);
|
|
if (IsVarTerm(t22)) {
|
|
Yap_Error(INSTANTIATION_ERROR, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
if (!IsIntegerTerm(t22)) {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
timeout.tv_usec = IntegerOfTerm(t22);
|
|
if (timeout.tv_usec < 0) {
|
|
Yap_Error(DOMAIN_ERROR_TIMEOUT_SPEC, t2, "stream_select/3");
|
|
return (FALSE);
|
|
}
|
|
ptime = &timeout;
|
|
}
|
|
/* do the real work */
|
|
if (select(fdmax + 1, &readfds, &writefds, &exceptfds, ptime) < 0) {
|
|
#if HAVE_STRERROR
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "stream_select/3 (select: %s)",
|
|
strerror(errno));
|
|
#else
|
|
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "stream_select/3 (select)");
|
|
#endif
|
|
}
|
|
while (t1 != TermNil) {
|
|
int fd;
|
|
int sno;
|
|
|
|
Head = HeadOfTerm(t1);
|
|
sno = Yap_CheckStream(Head, Input_Stream_f, "stream_select/3");
|
|
fd = GetStreamFd(sno);
|
|
if (FD_ISSET(fd, &readfds))
|
|
tout = MkPairTerm(Head, tout);
|
|
else
|
|
tout = MkPairTerm(TermNil, tout);
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
t1 = TailOfTerm(t1);
|
|
}
|
|
/* we're done, just pass the info back */
|
|
return (Yap_unify(ARG3, tout));
|
|
}
|
|
#endif
|
|
|
|
Int Yap_StreamToFileNo(Term t) {
|
|
int sno =
|
|
Yap_CheckStream(t, (Input_Stream_f | Output_Stream_f), "StreamToFileNo");
|
|
if (GLOBAL_Stream[sno].status & Pipe_Stream_f) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (GLOBAL_Stream[sno].u.pipe.fd);
|
|
#if HAVE_SOCKET
|
|
} else if (GLOBAL_Stream[sno].status & Socket_Stream_f) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (GLOBAL_Stream[sno].u.socket.fd);
|
|
#endif
|
|
} else if (GLOBAL_Stream[sno].status & (Null_Stream_f)) {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (-1);
|
|
} else {
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return (fileno(GLOBAL_Stream[sno].file));
|
|
}
|
|
}
|
|
|
|
static Int p_stream(USES_REGS1) {
|
|
Term in = Deref(ARG1);
|
|
if (IsVarTerm(in))
|
|
return (FALSE);
|
|
if (IsAtomTerm(in))
|
|
return (Yap_CheckAlias(AtomOfTerm(in)) >= 0);
|
|
if (IsApplTerm(in))
|
|
return (FunctorOfTerm(in) == FunctorStream);
|
|
return (FALSE);
|
|
}
|
|
|
|
FILE *Yap_FileDescriptorFromStream(Term t) {
|
|
int sno = Yap_CheckStream(t, Input_Stream_f | Output_Stream_f,
|
|
"FileDescriptorFromStream");
|
|
FILE *rc;
|
|
if (sno < 0)
|
|
return NULL;
|
|
if (GLOBAL_Stream[sno].status &
|
|
(Null_Stream_f | Socket_Stream_f | Pipe_Stream_f | Free_Stream_f))
|
|
rc = NULL;
|
|
else
|
|
rc = GLOBAL_Stream[sno].file;
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
|
|
Yap_InitBackIO (
|
|
|
|
void)
|
|
{
|
|
Yap_InitCPredBack("stream_property", 2, 2, stream_property,
|
|
cont_stream_property, SafePredFlag | SyncPredFlag);
|
|
}
|
|
|
|
void Yap_InitIOStreams(void) {
|
|
Yap_InitCPred("$stream_flags", 2, stream_flags,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$check_stream", 2, p_check_stream,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$check_stream", 1, p_check_if_stream,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$line_position", 2, p_line_position,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$character_count", 2, p_character_count,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$show_stream_flags", 2, p_show_stream_flags,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("$user_file_name", 2, p_user_file_name,
|
|
SafePredFlag | SyncPredFlag),
|
|
Yap_InitCPred("$file_name", 2, p_file_name, SafePredFlag | SyncPredFlag),
|
|
Yap_InitCPred("current_input", 1, current_input,
|
|
SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("current_output", 1, current_output,
|
|
SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("set_input", 1, set_input, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("set_output", 1, set_output, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$stream", 1, p_stream, SafePredFlag | TestPredFlag);
|
|
#if HAVE_SELECT
|
|
Yap_InitCPred("stream_select", 3, p_stream_select,
|
|
SafePredFlag | SyncPredFlag);
|
|
#endif
|
|
Yap_InitCPred("line_count", 2, line_count, SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("$show_stream_position", 2, p_show_stream_position,
|
|
SafePredFlag | SyncPredFlag | HiddenPredFlag);
|
|
Yap_InitCPred("set_stream_position", 2, set_stream_position,
|
|
SafePredFlag | SyncPredFlag);
|
|
Yap_InitCPred("set_stream", 2, set_stream, SafePredFlag | SyncPredFlag);
|
|
}
|