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/mem.c
Vítor Santos Costa b3cc23ce64 IO patches
simplify error handling
use get and inject
use wide support in OS
be stricter in checkin streams and arguments
2015-10-08 02:23:45 +01:00

411 lines
9.6 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: sockets.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 socket 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
#include "iopreds.h"
#if __APPLE__
#include "fmemopen.h"
#define HAVE_FMEMOPEN 1
#define HAVE_OPEN_MEMSTREAM 1
FILE * open_memstream (char **buf, size_t *len);
#endif
#if HAVE_FMEMOPEN
#define MAY_READ 1
#endif
#if HAVE_OPEN_MEMSTREAM
#define MAY_READ 1
#define MAY_WRITE 1
#endif
#if !MAY_READ
static int MemGetc( int);
/* read from memory */
static int
MemGetc (int sno)
{
register StreamDesc *s = &GLOBAL_Stream[sno];
Int ch;
int spos;
spos = s->u.mem_string.pos;
if (spos == s->u.mem_string.max_size) {
return post_process_eof(s);
} else {
ch = s->u.mem_string.buf[spos];
s->u.mem_string.pos = ++spos;
}
return post_process_read_char(ch, s);
}
#endif
#if !MAY_WRITE
static int MemPutc( int, int);
/* static */
static int
MemPutc(int sno, int ch)
{
StreamDesc *s = &GLOBAL_Stream[sno];
#if MAC || _MSC_VER
if (ch == 10)
{
ch = '\n';
}
#endif
s->u.mem_string.buf[s->u.mem_string.pos++] = ch;
if (s->u.mem_string.pos >= s->u.mem_string.max_size -8) {
int old_src = s->u.mem_string.src, new_src;
/* oops, we have reached an overflow */
Int new_max_size = s->u.mem_string.max_size + Yap_page_size;
char *newbuf;
if (old_src == MEM_BUF_CODE &&
(newbuf = Yap_AllocAtomSpace(new_max_size*sizeof(char))) != NULL) {
new_src = MEM_BUF_CODE;
#if HAVE_MEMMOVE
memmove((void *)newbuf, (void *)s->u.mem_string.buf, (size_t)((s->u.mem_string.pos)*sizeof(char)));
#else
{
Int n = s->u.mem_string.pos;
char *to = newbuf;
char *from = s->u.mem_string.buf;
while (n-- >= 0) {
*to++ = *from++;
}
}
#endif
Yap_FreeAtomSpace(s->u.mem_string.buf);
#if !HAVE_SYSTEM_MALLOC
} else if ((newbuf = (ADDR)realloc(s->u.mem_string.buf, new_max_size*sizeof(char))) != NULL) {
new_src = MEM_BUF_MALLOC;
#endif
} else {
if (GLOBAL_Stream[sno].u.mem_string.error_handler) {
CACHE_REGS
LOCAL_Error_Size = new_max_size*sizeof(char);
save_machine_regs();
longjmp(*(jmp_buf *)GLOBAL_Stream[sno].u.mem_string.error_handler,1);
} else {
Yap_Error(RESOURCE_ERROR_HEAP, TermNil, "YAP could not grow heap for writing to string");
}
return -1;
}
if (old_src == MEM_BUF_CODE) {
}
s->u.mem_string.buf = newbuf;
s->u.mem_string.max_size = new_max_size;
s->u.mem_string.src = new_src;
}
count_output_char(ch,s);
return ((int) ch);
}
#endif
int
Yap_open_buf_read_stream(const char *nbuf, size_t nchars, encoding_t *encp, memBufSource src)
{
CACHE_REGS
int sno;
StreamDesc *st;
sno = GetFreeStreamD();
if (sno < 0)
return (PlIOError (RESOURCE_ERROR_MAX_STREAMS,TermNil, "new stream not available for open_mem_read_stream/1"));
st = &GLOBAL_Stream[sno];
Yap_DefaultStreamOps( st );
#if MAY_READ
// like any file stream.
st->status = Input_Stream_f | InMemory_Stream_f | Seekable_Stream_f;
st->file = fmemopen( (void *)nbuf, nchars, "r");
#else
/* currently these streams are not seekable */
st->status = Input_Stream_f | InMemory_Stream_f;
st->u.mem_string.pos = 0;
st->u.mem_string.buf = (char *)nbuf;
st->u.mem_string.max_size = nchars;
st->u.mem_string.error_handler = NULL;
st->u.mem_string.src = src;
#endif
Yap_MemOps( st );
st->linepos = 0;
st->charcount = 0;
st->linecount = 1;
if (encp)
st->encoding = *encp;
else
st->encoding = LOCAL_encoding;
UNLOCK(st->streamlock);
return sno;
}
static Int
open_mem_read_stream (USES_REGS1) /* $open_mem_read_stream(+List,-Stream) */
{
Term t, ti;
int sno;
Int sl = 0, nchars = 0;
char *nbuf;
ti = Deref(ARG1);
while (ti != TermNil) {
if (IsVarTerm(ti)) {
Yap_Error(INSTANTIATION_ERROR, ti, "open_mem_read_stream");
return (FALSE);
} else if (!IsPairTerm(ti)) {
Yap_Error(TYPE_ERROR_LIST, ti, "open_mem_read_stream");
return (FALSE);
} else {
sl++;
ti = TailOfTerm(ti);
}
}
while ((nbuf = (char *)Yap_AllocAtomSpace((sl+1)*sizeof(char))) == NULL) {
if (!Yap_growheap(FALSE, (sl+1)*sizeof(char), NULL)) {
Yap_Error(RESOURCE_ERROR_HEAP, TermNil, LOCAL_ErrorMessage);
return(FALSE);
}
}
ti = Deref(ARG1);
while (ti != TermNil) {
Term ts = HeadOfTerm(ti);
if (IsVarTerm(ts)) {
Yap_Error(INSTANTIATION_ERROR, ARG1, "open_mem_read_stream");
return (FALSE);
} else if (!IsIntTerm(ts)) {
Yap_Error(TYPE_ERROR_INTEGER, ARG1, "open_mem_read_stream");
return (FALSE);
}
nbuf[nchars++] = IntOfTerm(ts);
ti = TailOfTerm(ti);
}
nbuf[nchars] = '\0';
sno = Yap_open_buf_read_stream(nbuf, nchars, &LOCAL_encoding, MEM_BUF_CODE);
t = Yap_MkStream (sno);
return (Yap_unify (ARG2, t));
}
int
Yap_open_buf_write_stream(char *buf, size_t nchars, encoding_t *encp, memBufSource sr)
{
CACHE_REGS
int sno;
StreamDesc *st;
sno = GetFreeStreamD();
if (sno < 0)
return -1;
if (!buf) {
if (!nchars) {
nchars = Yap_page_size;
}
buf = malloc( nchars );
}
st = GLOBAL_Stream+sno;
st->nbuf = buf;
if(!st->nbuf) {
return -1;
}
st->nsize = nchars;
/* currently these streams are not seekable */
st->linepos = 0;
st->charcount = 0;
st->linecount = 1;
if (encp)
st->encoding = *encp;
else
st->encoding = LOCAL_encoding;
Yap_DefaultStreamOps( st );
#if MAY_WRITE
st->file = open_memstream(&st->nbuf, &st->nsize);
st->status = Output_Stream_f | InMemory_Stream_f|Seekable_Stream_f;
#else
st->u.mem_string.pos = 0;
st->u.mem_string.buf = nbuf;
st->u.mem_string.max_size = nchars;
st->status = Output_Stream_f | InMemory_Stream_f;
#endif
Yap_MemOps( st );
UNLOCK(st->streamlock);
return sno;
}
int
Yap_OpenBufWriteStream( USES_REGS1 )
{
char *nbuf;
size_t sz = Yap_page_size;
while ((nbuf = (char *)Yap_AllocAtomSpace(Yap_page_size*sizeof(char))) == NULL) {
if (!Yap_growheap(FALSE, Yap_page_size*sizeof(char), NULL)) {
Yap_Error(RESOURCE_ERROR_HEAP, TermNil, LOCAL_ErrorMessage);
return -1;
}
}
return Yap_open_buf_write_stream(nbuf, sz, &GLOBAL_Stream[LOCAL_c_output_stream].encoding, 0);
}
static Int
open_mem_write_stream (USES_REGS1) /* $open_mem_write_stream(-Stream) */
{
Term t;
int sno;
sno = Yap_OpenBufWriteStream( PASS_REGS1 );
if (sno == -1)
return (PlIOError (SYSTEM_ERROR_INTERNAL,TermNil, "new stream not available for open_mem_read_stream/1"));
t = Yap_MkStream (sno);
return (Yap_unify (ARG1, t));
}
/**
* Yap_PeekMemwriteStream() shows the current buffer for a memory stream.
*
* @param sno, the in-memory stream
*
* @return temporary buffer, discarded by close and may be moved away
* by other writes..
*/
char *
Yap_MemExportStreamPtr( int sno )
{
char *s;
#if MAY_WRITE
if (fflush(GLOBAL_Stream[sno].file) == 0 &&
(s = GLOBAL_Stream[sno].nbuf)) {
s[ftell(GLOBAL_Stream[sno].file)] = '\0';
return s;
}
return NULL;
#else
return &GLOBAL_Stream[sno].u.mem_string;
#endif
}
static Int
peek_mem_write_stream ( USES_REGS1 )
{ /* '$peek_mem_write_stream'(+GLOBAL_Stream,?S0,?S) */
Int sno = Yap_CheckStream (ARG1, (Output_Stream_f | InMemory_Stream_f), "close/2");
Int i;
Term tf = ARG2;
CELL *HI;
const char *ptr;
if (sno < 0)
return (FALSE);
restart:
HI = HR;
#if MAY_WRITE
if (fflush(GLOBAL_Stream[sno].file) == 0) {
ptr = GLOBAL_Stream[sno].nbuf;
i = GLOBAL_Stream[sno].nsize;
}
#else
size_t pos;
ptr = GLOBAL_Stream[sno].u.mem_string.buf;
i = GLOBAL_Stream[sno].u.mem_string.pos;
#endif
while (i > 0) {
--i;
tf = MkPairTerm(MkIntTerm(ptr[i]),tf);
if (HR + 1024 >= ASP) {
UNLOCK(GLOBAL_Stream[sno].streamlock);
HR = HI;
if (!Yap_gcl((ASP-HI)*sizeof(CELL), 3, ENV, Yap_gcP()) ) {
UNLOCK(GLOBAL_Stream[sno].streamlock);
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return(FALSE);
}
i = GLOBAL_Stream[sno].u.mem_string.pos;
tf = ARG2;
LOCK(GLOBAL_Stream[sno].streamlock);
goto restart;
}
}
UNLOCK(GLOBAL_Stream[sno].streamlock);
return (Yap_unify(ARG3,tf));
}
void
Yap_MemOps( StreamDesc *st )
{
#if MAY_WRITE
st->stream_putc = FilePutc;
#else
st->stream_putc = MemPutc;
#endif
#if MAY_READ
st->stream_getc = PlGetc;
#else
st->stream_getc = MemGetc;
#endif
}
void
Yap_InitMems( void )
{
CACHE_REGS
Term cm = CurrentModule;
CurrentModule = CHARSIO_MODULE;
Yap_InitCPred ("open_mem_read_stream", 2, open_mem_read_stream, SyncPredFlag);
Yap_InitCPred ("open_mem_write_stream", 1, open_mem_write_stream, SyncPredFlag);
Yap_InitCPred ("peek_mem_write_stream", 3, peek_mem_write_stream, SyncPredFlag);
CurrentModule = cm;
}