cyclone/mstreams.c
2024-01-17 19:43:47 -08:00

140 lines
3.8 KiB
C

/**
* Cyclone Scheme
* https://github.com/justinethier/cyclone
*
* Copyright (c) 2014-2016, Justin Ethier
* All rights reserved.
*
* This file contains platform-specific code for memory streams.
*/
#include "cyclone/types.h"
#include "cyclone/runtime.h"
#include <errno.h>
/* These macros are hardcoded here to support functions in this module. */
#define closcall1(td, clo, buf) \
if (obj_is_not_closure(clo)) { \
Cyc_apply(td, clo, 1, buf ); \
} else { \
((clo)->fn)(td, clo, 1, buf); \
;\
}
#define return_closcall1(td, clo,a1) { \
char top; \
object buf[1]; buf[0] = a1;\
if (stack_overflow(&top, (((gc_thread_data *)data)->stack_limit))) { \
GC(td, clo, buf, 1); \
return; \
} else {\
closcall1(td, (closure) (clo), buf); \
return;\
} \
}
int Cyc_have_mstreams()
{
#if CYC_HAVE_FMEMOPEN && CYC_HAVE_OPEN_MEMSTREAM
return 1;
#else
return 0;
#endif
}
object Cyc_heap_alloc_port(void *data, port_type * p);
port_type *Cyc_io_open_input_string(void *data, object str)
{
// Allocate port on the heap so the location of mem_buf does not change
port_type *p;
make_input_port(sp, NULL, CYC_IO_BUF_LEN);
Cyc_check_str(data, str);
p = (port_type *) Cyc_heap_alloc_port(data, &sp);
errno = 0;
#if CYC_HAVE_FMEMOPEN
p->str_bv_in_mem_buf = malloc(sizeof(char) * (string_len(str) + 1));
p->str_bv_in_mem_buf_len = string_len(str);
memcpy(p->str_bv_in_mem_buf, string_str(str), string_len(str));
p->fp = fmemopen(p->str_bv_in_mem_buf, string_len(str), "r");
#endif
if (p->fp == NULL) {
Cyc_rt_raise2(data, "Unable to open input memory stream",
obj_int2obj(errno));
}
return p;
}
port_type *Cyc_io_open_input_bytevector(void *data, object bv)
{
// Allocate port on the heap so the location of mem_buf does not change
port_type *p;
make_input_port(sp, NULL, CYC_IO_BUF_LEN);
Cyc_check_bvec(data, bv);
p = (port_type *) Cyc_heap_alloc_port(data, &sp);
errno = 0;
#if CYC_HAVE_FMEMOPEN
p->str_bv_in_mem_buf = malloc(sizeof(char) * ((bytevector) bv)->len);
p->str_bv_in_mem_buf_len = ((bytevector) bv)->len;
memcpy(p->str_bv_in_mem_buf, ((bytevector) bv)->data, ((bytevector) bv)->len);
p->fp = fmemopen(p->str_bv_in_mem_buf, ((bytevector) bv)->len, "r");
#endif
if (p->fp == NULL) {
Cyc_rt_raise2(data, "Unable to open input memory stream",
obj_int2obj(errno));
}
return p;
}
port_type *Cyc_io_open_output_string(void *data)
{
// Allocate port on the heap so the location of mem_buf does not change
port_type *p;
make_port(sp, NULL, 0);
p = (port_type *) Cyc_heap_alloc_port(data, &sp);
errno = 0;
#if CYC_HAVE_OPEN_MEMSTREAM
p->fp = open_memstream(&(p->str_bv_in_mem_buf), &(p->str_bv_in_mem_buf_len));
#endif
if (p->fp == NULL) {
Cyc_rt_raise2(data, "Unable to open output memory stream",
obj_int2obj(errno));
}
return p;
}
void Cyc_io_get_output_string(void *data, object cont, object port)
{
port_type *p = (port_type *) port;
Cyc_check_port(data, port);
if (p->fp) {
fflush(p->fp);
}
if (p->str_bv_in_mem_buf == NULL) {
Cyc_rt_raise2(data, "Not an in-memory port", port);
}
{
make_string_with_len(s, p->str_bv_in_mem_buf, p->str_bv_in_mem_buf_len);
s.num_cp = Cyc_utf8_count_code_points((uint8_t *) string_str(&s));
return_closcall1(data, cont, &s);
}
}
void Cyc_io_get_output_bytevector(void *data, object cont, object port)
{
port_type *p = (port_type *) port;
Cyc_check_port(data, port);
if (p->fp) {
fflush(p->fp);
}
if (p->str_bv_in_mem_buf == NULL) {
Cyc_rt_raise2(data, "Not an in-memory port", port);
}
{
object bv;
alloc_bytevector(data, bv, p->str_bv_in_mem_buf_len);
memcpy(((bytevector) bv)->data, p->str_bv_in_mem_buf,
p->str_bv_in_mem_buf_len);
return_closcall1(data, cont, bv);
}
}