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/pipes.c
Vítor Santos Costa f7d23f9deb Simplify Input/Output
get rid of string I/O, did not add much
getc is never actually used by Prolog
try to use system I/O, even if it may be slower, at least for now.
extend IO C-interface to allow reading clauses
2016-02-21 19:06:25 +00:00

262 lines
5.7 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: pipes.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 pipe related IO.
*
*/
#include "Yap.h"
#include "Yatom.h"
#include "YapHeap.h"
#include "yapio.h"
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef _WIN32
#if HAVE_IO_H
/* Windows */
#include <io.h>
#endif
#if HAVE_SOCKET
#include <winsock2.h>
#endif
#include <windows.h>
#ifndef S_ISDIR
#define S_ISDIR(x) (((x)&_S_IFDIR)==_S_IFDIR)
#endif
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "iopreds.h"
static int PipePutc( int, int);
static int ConsolePipePutc( int, int);
static int PipeGetc( int);
static int ConsolePipeGetc( int);
/* static */
static int
ConsolePipePutc (int sno, int ch)
{
StreamDesc *s = &GLOBAL_Stream[sno];
char c = ch;
#if MAC || _MSC_VER
if (ch == 10)
{
ch = '\n';
}
#endif
{
int out = 0;
while (!out) {
out = write(s->u.pipe.fd, &c, sizeof(c));
if (out <0) {
#if HAVE_STRERROR
Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream pipe: %s", strerror(errno));
#else
Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream pipe");
#endif
}
}
}
count_output_char(ch,s);
return ((int) ch);
}
static int
PipePutc (int sno, int ch)
{
StreamDesc *s = &GLOBAL_Stream[sno];
char c = ch;
#if MAC || _MSC_VER
if (ch == 10)
{
ch = '\n';
}
#endif
{
int out = 0;
while (!out) {
out = write(s->u.pipe.fd, &c, sizeof(c));
if (out <0) {
#if HAVE_STRERROR
Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream pipe: %s", strerror(errno));
#else
Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream pipe");
#endif
}
}
}
console_count_output_char(ch,s);
return ((int) ch);
}
/*
Basically, the same as console but also sends a prompt and takes care of
finding out whether we are at the start of a LOCAL_newline.
*/
static int
ConsolePipeGetc(int sno)
{
CACHE_REGS
StreamDesc *s = &GLOBAL_Stream[sno];
int ch;
char c;
#if _MSC_VER || defined(__MINGW32__)
DWORD count;
#else
int count;
#endif
/* send the prompt away */
if (LOCAL_newline) {
char *cptr = LOCAL_Prompt, ch;
/* use the default routine */
while ((ch = *cptr++) != '\0') {
GLOBAL_Stream[StdErrStream].stream_putc(StdErrStream, ch);
}
strncpy(LOCAL_Prompt, RepAtom (LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT);
LOCAL_newline = false;
}
/* should be able to use a buffer */
LOCAL_PrologMode |= ConsoleGetcMode;
count = read(s->u.pipe.fd, &c, sizeof(char));
LOCAL_PrologMode &= ~ConsoleGetcMode;
if (count == 0) {
return console_post_process_eof(s);
} else if (count > 0) {
ch = c;
} else {
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "read");
return console_post_process_eof(s);
}
return console_post_process_read_char(ch, s);
}
static int
PipeGetc(int sno)
{
StreamDesc *s = &GLOBAL_Stream[sno];
Int ch;
char c;
/* should be able to use a buffer */
int count;
count = read(s->u.pipe.fd, &c, sizeof(char));
if (count == 0) {
return EOF;
} else if (count > 0) {
ch = c;
} else {
#if HAVE_STRERROR
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "at pipe getc: %s", strerror(errno));
#else
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "at pipe getc");
#endif
return EOF;
}
return ch;
}
void
Yap_PipeOps( StreamDesc *st )
{
st->stream_putc = PipePutc;
st->stream_getc = PipeGetc;
}
void
Yap_ConsolePipeOps( StreamDesc *st )
{
st->stream_putc = ConsolePipePutc;
st->stream_getc = ConsolePipeGetc;
}
static Int
open_pipe_stream (USES_REGS1)
{
Term t1, t2;
StreamDesc *st;
int sno;
int filedes[2];
if (
#if _MSC_VER || defined(__MINGW32__)
// assume for now only text streams...
_pipe(filedes, 1024, O_TEXT)
#else
pipe(filedes)
#endif
!= 0)
{
return (PlIOError (SYSTEM_ERROR_INTERNAL,TermNil, "error %s", strerror(errno)) );
}
sno = GetFreeStreamD();
if (sno < 0)
return (PlIOError (RESOURCE_ERROR_MAX_STREAMS,TermNil, "new stream not available for open_pipe_stream/2"));
t1 = Yap_MkStream (sno);
st = &GLOBAL_Stream[sno];
st->status = Input_Stream_f | Pipe_Stream_f;
st->linepos = 0;
st->charcount = 0;
st->linecount = 1;
st->stream_putc = PipePutc;
st->stream_getc = PipeGetc;
Yap_DefaultStreamOps( st );
st->u.pipe.fd = filedes[0];
st->file = fdopen( filedes[0], "r");
UNLOCK(st->streamlock);
sno = GetFreeStreamD();
if (sno < 0)
return (PlIOError (RESOURCE_ERROR_MAX_STREAMS,TermNil, "new stream not available for open_pipe_stream/2"));
st = &GLOBAL_Stream[sno];
st->status = Output_Stream_f | Pipe_Stream_f;
st->linepos = 0;
st->charcount = 0;
st->linecount = 1;
st->stream_putc = PipePutc;
st->stream_getc = PipeGetc;
Yap_DefaultStreamOps( st );
st->u.pipe.fd = filedes[1];
st->file = fdopen( filedes[1], "w");
UNLOCK(st->streamlock);
t2 = Yap_MkStream (sno);
return
Yap_unify (ARG1, t1) &&
Yap_unify (ARG2, t2);
}
void
Yap_InitPipes( void )
{
Yap_InitCPred ("open_pipe_stream", 2, open_pipe_stream, SafePredFlag);
}