2016-09-28 01:32:27 +01:00
|
|
|
/*************************************************************************
|
2017-09-23 02:17:55 +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 *
|
|
|
|
* *
|
|
|
|
**************************************************************************
|
|
|
|
* *
|
|
|
|
* File: mem.c *
|
|
|
|
* Last rev: 5/2/88 *
|
|
|
|
* mods: *
|
|
|
|
* comments: Input/Output C implemented predicates *
|
|
|
|
* *
|
|
|
|
*************************************************************************/
|
2016-09-28 01:32:27 +01:00
|
|
|
#ifdef SCCS
|
|
|
|
static char SccsId[] = "%W% %G%";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file includes the definition of a socket related IO.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-09-29 20:43:27 +01:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
|
|
|
|
2017-10-02 08:58:51 +01:00
|
|
|
#include "YapText.h"
|
2016-09-28 01:32:27 +01:00
|
|
|
#include "format.h"
|
2017-09-23 02:17:55 +01:00
|
|
|
#include "sysbits.h"
|
2016-09-28 01:32:27 +01:00
|
|
|
|
|
|
|
#if HAVE_FMEMOPEN
|
|
|
|
|
2017-09-23 02:17:55 +01:00
|
|
|
int format_synch(int sno, int sno0, format_info *fg) {
|
2016-09-28 01:32:27 +01:00
|
|
|
const char *s;
|
|
|
|
int n;
|
2016-09-28 15:08:22 +01:00
|
|
|
if (sno != sno0) {
|
2017-09-23 02:17:55 +01:00
|
|
|
fflush(GLOBAL_Stream[sno].file);
|
|
|
|
n = ftell(GLOBAL_Stream[sno].file);
|
|
|
|
s = GLOBAL_Stream[sno].nbuf;
|
|
|
|
if (GLOBAL_Stream[sno0].vfs) {
|
|
|
|
int ch;
|
|
|
|
int (*f)() = GLOBAL_Stream[sno0].vfs->put_char;
|
|
|
|
while ((ch = *s++)) {
|
|
|
|
f(sno0, ch);
|
2017-08-21 12:29:58 +01:00
|
|
|
}
|
2017-09-23 02:17:55 +01:00
|
|
|
} else {
|
|
|
|
fwrite(s, n, 1, GLOBAL_Stream[sno0].file);
|
|
|
|
}
|
2016-09-28 01:32:27 +01:00
|
|
|
rewind(GLOBAL_Stream[sno].file);
|
2016-09-28 15:08:22 +01:00
|
|
|
fg->lstart = 0;
|
|
|
|
fg->phys_start = 0;
|
|
|
|
fg->gapi = 0;
|
2016-09-28 01:32:27 +01:00
|
|
|
}
|
2017-08-21 12:29:58 +01:00
|
|
|
Yap_flush(sno0);
|
2016-09-28 15:08:22 +01:00
|
|
|
return sno;
|
2016-09-28 01:32:27 +01:00
|
|
|
}
|
|
|
|
|
2017-09-23 02:17:55 +01:00
|
|
|
bool fill_pads(int sno, int sno0, int total, format_info *fg USES_REGS)
|
2016-09-28 01:32:27 +01:00
|
|
|
// uses directly the buffer in the memory stream.
|
2017-09-23 02:17:55 +01:00
|
|
|
{
|
2016-09-28 01:32:27 +01:00
|
|
|
int nfillers, fill_space, lfill_space, nchars;
|
|
|
|
int (*f_putc)(int, int);
|
|
|
|
const char *buf;
|
|
|
|
int phys_end;
|
|
|
|
|
|
|
|
f_putc = GLOBAL_Stream[sno0].stream_putc;
|
|
|
|
if (fflush(GLOBAL_Stream[sno].file) == 0) {
|
|
|
|
buf = GLOBAL_Stream[sno].nbuf;
|
|
|
|
phys_end = ftell(GLOBAL_Stream[sno].file);
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
if (fg->gapi == 0) {
|
|
|
|
fg->gap[0].phys = phys_end;
|
|
|
|
fg->gap[0].filler = ' ';
|
|
|
|
fg->gapi = 1;
|
|
|
|
}
|
|
|
|
nchars = total - GLOBAL_Stream[sno].linepos;
|
|
|
|
if (nchars < 0)
|
|
|
|
nchars = 0; /* ignore */
|
|
|
|
nfillers = fg->gapi;
|
|
|
|
fill_space = nchars / nfillers;
|
|
|
|
lfill_space = nchars % nfillers;
|
|
|
|
|
|
|
|
int i = fg->phys_start;
|
|
|
|
gap_t *padi = fg->gap;
|
|
|
|
while (i < phys_end) {
|
|
|
|
if (i == padi->phys) {
|
|
|
|
int j;
|
|
|
|
for (j = 0; j < fill_space; j++)
|
|
|
|
f_putc(sno0, padi->filler);
|
|
|
|
padi++;
|
|
|
|
/* last gap??*/
|
|
|
|
if (padi - fg->gap == fg->gapi) {
|
|
|
|
for (j = 0; j < fill_space; j++)
|
|
|
|
f_putc(sno0, (padi - 1)->filler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f_putc(sno0, buf[i++]);
|
|
|
|
}
|
|
|
|
// final gap
|
|
|
|
if (i == padi->phys) {
|
|
|
|
int j;
|
|
|
|
for (j = 0; j < fill_space + lfill_space; j++)
|
|
|
|
f_putc(sno0, padi->filler);
|
|
|
|
};
|
|
|
|
|
|
|
|
rewind(GLOBAL_Stream[sno].file);
|
2017-08-21 12:29:58 +01:00
|
|
|
Yap_flush(sno0);
|
2016-09-28 01:32:27 +01:00
|
|
|
GLOBAL_Stream[sno].linecount = 1;
|
|
|
|
GLOBAL_Stream[sno].linepos += nchars;
|
|
|
|
GLOBAL_Stream[sno].charcount = 0;
|
2018-01-18 14:47:27 +00:00
|
|
|
GLOBAL_Stream[sno].buf.on = false;
|
2016-09-28 01:32:27 +01:00
|
|
|
fg->phys_start = 0;
|
|
|
|
fg->lstart = GLOBAL_Stream[sno].linepos;
|
|
|
|
fg->gapi = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-29 13:47:57 +00:00
|
|
|
bool Yap_set_stream_to_buf(StreamDesc *st, const char *buf,
|
|
|
|
size_t nchars USES_REGS) {
|
2016-09-28 01:32:27 +01:00
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
// like any file stream.
|
2017-12-01 10:42:10 +00:00
|
|
|
st->file = f = fmemopen((char *)buf, nchars, "r");
|
2017-11-29 13:47:57 +00:00
|
|
|
st->status = Input_Stream_f | Seekable_Stream_f | InMemory_Stream_f;
|
2017-06-05 13:06:12 +01:00
|
|
|
st->vfs = NULL;
|
2018-01-18 14:47:27 +00:00
|
|
|
st->buf.on = false;
|
2017-11-29 13:47:57 +00:00
|
|
|
st->encoding = LOCAL_encoding;
|
2016-09-28 01:32:27 +01:00
|
|
|
Yap_DefaultStreamOps(st);
|
2017-11-29 13:47:57 +00:00
|
|
|
st->linecount = 0;
|
|
|
|
st->linepos = st->charcount = 0;
|
2016-09-28 01:32:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-03 00:08:19 +01:00
|
|
|
|
|
|
|
char *Yap_StrPrefix( const char *buf, size_t n) {
|
|
|
|
char *b = (char*)malloc(n);
|
|
|
|
strncpy(b, buf, n - 1);
|
|
|
|
if (strlen(buf) > n - 1)
|
|
|
|
b[15] = '\0';
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Yap_open_buf_read_stream(const char *buf, size_t nchars,
|
|
|
|
encoding_t *encp, memBufSource src, Atom fname,
|
|
|
|
Term uname) {
|
2016-09-28 01:32:27 +01:00
|
|
|
CACHE_REGS
|
|
|
|
int sno;
|
|
|
|
StreamDesc *st;
|
|
|
|
FILE *f;
|
|
|
|
encoding_t encoding;
|
|
|
|
stream_flags_t flags;
|
|
|
|
|
|
|
|
sno = GetFreeStreamD();
|
|
|
|
if (sno < 0)
|
2017-09-23 02:17:55 +01:00
|
|
|
return (PlIOError(RESOURCE_ERROR_MAX_STREAMS, TermNil,
|
2016-09-28 01:32:27 +01:00
|
|
|
"new stream not available for open_mem_read_stream/1"));
|
|
|
|
st = GLOBAL_Stream + sno;
|
|
|
|
if (encp)
|
|
|
|
encoding = *encp;
|
|
|
|
else
|
|
|
|
encoding = LOCAL_encoding;
|
|
|
|
// like any file stream.
|
|
|
|
f = st->file = fmemopen((void *)buf, nchars, "r");
|
2018-05-27 00:47:03 +01:00
|
|
|
st->vfs = NULL;
|
2016-09-28 01:32:27 +01:00
|
|
|
flags = Input_Stream_f | InMemory_Stream_f | Seekable_Stream_f;
|
2018-09-29 20:43:27 +01:00
|
|
|
Yap_initStream(sno, f, fname, "r", uname, encoding, flags, NULL);
|
2017-09-23 02:17:55 +01:00
|
|
|
// like any file stream.
|
2016-09-28 01:32:27 +01:00
|
|
|
Yap_DefaultStreamOps(st);
|
|
|
|
UNLOCK(st->streamlock);
|
|
|
|
return sno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Int
|
|
|
|
open_mem_read_stream(USES_REGS1) /* $open_mem_read_stream(+List,-Stream) */
|
|
|
|
{
|
|
|
|
Term t, ti;
|
|
|
|
int sno;
|
|
|
|
const char *buf;
|
|
|
|
|
|
|
|
ti = Deref(ARG1);
|
2017-10-02 08:58:51 +01:00
|
|
|
int l = push_text_stack();
|
|
|
|
buf = Yap_TextTermToText(ti);
|
2016-09-28 01:32:27 +01:00
|
|
|
if (!buf) {
|
2018-06-03 12:07:38 +01:00
|
|
|
pop_text_stack(l);
|
2016-09-28 01:32:27 +01:00
|
|
|
return false;
|
|
|
|
}
|
2018-06-03 12:07:38 +01:00
|
|
|
buf = pop_output_text_stack(l, buf);
|
2016-09-28 01:32:27 +01:00
|
|
|
sno = Yap_open_buf_read_stream(buf, strlen(buf) + 1, &LOCAL_encoding,
|
2018-07-03 00:08:19 +01:00
|
|
|
MEM_BUF_MALLOC, Yap_LookupAtom(Yap_StrPrefix((char *)buf,16)), TermNone);
|
2016-09-28 01:32:27 +01:00
|
|
|
t = Yap_MkStream(sno);
|
|
|
|
return Yap_unify(ARG2, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
// open a buffer for writing, currently just ignores buf and nchars.
|
|
|
|
|
|
|
|
int Yap_open_buf_write_stream(encoding_t enc, memBufSource src) {
|
|
|
|
CACHE_REGS
|
|
|
|
int sno;
|
|
|
|
StreamDesc *st;
|
|
|
|
|
|
|
|
sno = GetFreeStreamD();
|
|
|
|
if (sno < 0)
|
|
|
|
return -1;
|
2018-06-14 11:27:43 +01:00
|
|
|
|
2016-09-28 01:32:27 +01:00
|
|
|
st = GLOBAL_Stream + sno;
|
2018-07-13 12:27:58 +01:00
|
|
|
st->status = Output_Stream_f | InMemory_Stream_f;
|
2016-09-28 01:32:27 +01:00
|
|
|
st->linepos = 0;
|
|
|
|
st->charcount = 0;
|
|
|
|
st->linecount = 1;
|
|
|
|
st->encoding = enc;
|
2017-06-05 13:06:12 +01:00
|
|
|
st->vfs = NULL;
|
2018-06-14 11:27:43 +01:00
|
|
|
st->buf.on = true;
|
|
|
|
st->nbuf = NULL;
|
2018-07-13 12:27:58 +01:00
|
|
|
st->status |= Seekable_Stream_f;
|
2016-09-28 01:32:27 +01:00
|
|
|
#if HAVE_OPEN_MEMSTREAM
|
|
|
|
st->file = open_memstream(&st->nbuf, &st->nsize);
|
|
|
|
// setbuf(st->file, NULL);
|
2018-07-13 12:27:58 +01:00
|
|
|
#else
|
|
|
|
st->file = fmemopen((void *)st->nbuf, st->nsize, "w+");
|
2016-09-28 01:32:27 +01:00
|
|
|
#endif
|
2018-01-05 16:57:38 +00:00
|
|
|
Yap_DefaultStreamOps(st);
|
2016-09-28 01:32:27 +01:00
|
|
|
UNLOCK(st->streamlock);
|
|
|
|
return sno;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Yap_OpenBufWriteStream(USES_REGS1) {
|
|
|
|
|
|
|
|
return Yap_open_buf_write_stream(
|
|
|
|
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);
|
|
|
|
GLOBAL_Stream[sno].status |= InMemory_Stream_f;
|
|
|
|
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) {
|
2018-07-14 11:49:42 +01:00
|
|
|
FILE *f = GLOBAL_Stream[sno].file;
|
|
|
|
if (fflush(f) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (fseek(f, 0, SEEK_END) < 0) {
|
2018-07-13 12:27:58 +01:00
|
|
|
return NULL;
|
2016-09-28 01:32:27 +01:00
|
|
|
}
|
2018-07-14 11:49:42 +01:00
|
|
|
size_t len = ftell(f);
|
2018-07-13 12:27:58 +01:00
|
|
|
char *buf = malloc(len+1);
|
|
|
|
#if HAVE_OPEN_MEMSTREAM
|
|
|
|
char *s = GLOBAL_Stream[sno].nbuf;
|
|
|
|
memcpy(buf, s, len);
|
|
|
|
// s[fseek(GLOBAL_Stream[sno].file, 0, SEEK_END)] = '\0';
|
|
|
|
#else
|
2018-09-14 11:28:24 +01:00
|
|
|
fread(buf, len, 1, GLOBAL_Stream[sno].file);
|
2018-07-13 12:27:58 +01:00
|
|
|
#endif
|
|
|
|
buf[len] = '\0';
|
|
|
|
return buf;
|
2016-09-28 01:32:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
Term tf = ARG2;
|
|
|
|
CELL *HI;
|
2018-07-13 12:27:58 +01:00
|
|
|
char *ptr;
|
|
|
|
int ch;
|
2016-09-28 01:32:27 +01:00
|
|
|
|
|
|
|
if (sno < 0)
|
|
|
|
return (FALSE);
|
2018-07-13 12:27:58 +01:00
|
|
|
char *p = ptr = Yap_MemExportStreamPtr(sno);
|
|
|
|
restart:
|
2016-09-28 01:32:27 +01:00
|
|
|
HI = HR;
|
2018-07-13 12:27:58 +01:00
|
|
|
while ((ch = *p++)) {
|
|
|
|
HR[0] = MkIntTerm(ch);
|
|
|
|
HR[1] = AbsPair(HR+2);
|
|
|
|
HR += 2;
|
2016-09-28 01:32:27 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
LOCK(GLOBAL_Stream[sno].streamlock);
|
|
|
|
goto restart;
|
|
|
|
}
|
|
|
|
}
|
2018-07-13 12:27:58 +01:00
|
|
|
HR[-1] = tf;
|
2016-09-28 01:32:27 +01:00
|
|
|
UNLOCK(GLOBAL_Stream[sno].streamlock);
|
2018-07-13 12:27:58 +01:00
|
|
|
free(ptr);
|
|
|
|
return (Yap_unify(ARG3, AbsPair(HI)));
|
2016-09-28 01:32:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Yap_MemOps(StreamDesc *st) {
|
|
|
|
st->stream_putc = FilePutc;
|
|
|
|
|
|
|
|
st->stream_getc = PlGetc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Yap_CloseMemoryStream(int sno) {
|
2017-12-20 00:29:15 +00:00
|
|
|
if ((GLOBAL_Stream[sno].status & Output_Stream_f) &&
|
|
|
|
GLOBAL_Stream[sno].file) {
|
2016-09-28 01:32:27 +01:00
|
|
|
fflush(GLOBAL_Stream[sno].file);
|
|
|
|
fclose(GLOBAL_Stream[sno].file);
|
|
|
|
if (GLOBAL_Stream[sno].status & FreeOnClose_Stream_f)
|
|
|
|
free(GLOBAL_Stream[sno].nbuf);
|
|
|
|
} else {
|
2017-12-01 10:42:10 +00:00
|
|
|
if (GLOBAL_Stream[sno].file)
|
2017-12-20 00:29:15 +00:00
|
|
|
fclose(GLOBAL_Stream[sno].file);
|
2016-09-28 01:32:27 +01:00
|
|
|
if (GLOBAL_Stream[sno].status & FreeOnClose_Stream_f)
|
|
|
|
free(GLOBAL_Stream[sno].nbuf);
|
|
|
|
}
|
2019-03-26 09:40:54 +00:00
|
|
|
GLOBAL_Stream[sno].status = Free_Stream_f;
|
2016-09-28 01:32:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Yap_InitMems(void) {
|
|
|
|
CACHE_REGS
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|