The following steps are required to define a new stream in C:
SP_create_stream()
.
The following sample makes it possible to create read-only binary
streams that use the C FILE*
API.
#include <sicstus/sicstus.h> #include <stdio.h> #include <string.h> #include <errno.h> struct stdio_t_stream { FILE *f; }; typedef struct stdio_t_stream stdio_t_stream; static spio_t_error_code SPCDECL stdio_read(void *user_data, void *buf, size_t *pbuf_size, spio_t_bits read_options) { spio_t_error_code ecode = SPIO_E_ERROR; stdio_t_stream *s; size_t res; if (read_options & SPIO_DEVICE_READ_OPTION_NONBLOCKING) { ecode = SPIO_E_NOT_SUPPORTED; goto barf; } s = (stdio_t_stream *)user_data; res = fread(buf, 1, *pbuf_size, s->f); if (res == 0) /* error */ { if (feof(s->f)) { ecode = SPIO_E_END_OF_FILE; } else /* some other error */ { ecode = SPIO_E_OS_ERROR; } goto barf; } *pbuf_size = res; /* number of bytes read */ return SPIO_S_NOERR; barf: return ecode; }
static spio_t_error_code SPCDECL stdio_close(void **puser_data, spio_t_bits close_options) { stdio_t_stream *s; s = (stdio_t_stream *)*puser_data; /* we can ignore SPIO_DEVICE_CLOSE_OPTION_FORCE */ if (close_options & SPIO_DEVICE_CLOSE_OPTION_READ) { *puser_data = NULL; /* tell caller we are gone */ if (fclose(s->f) != 0) { ; /* ignore errors */ } } return SPIO_S_NOERR; }
/* Identify our streams with (an arbitrary) pointer that is unique to us */ #define STDIO_STREAM_CLASS ((void*)&stdio_open_c) int stdio_open_c(char const *path, char const *direction, SP_stream **pstream) { spio_t_error_code ecode = SPIO_E_ERROR; stdio_t_stream *s = NULL; SP_stream *stream = NULL; if (strcmp(direction, "read") != 0) { goto not_supported; } /* read */ s = (stdio_t_stream*)SP_malloc(sizeof *s); if (s == NULL) goto out_of_memory; /* open binary */ s->f = fopen(path, "rb"); if (s->f == NULL) { ecode = SPIO_E_OPEN_ERROR; goto barf; } ecode = SP_create_stream((void*)s, STDIO_STREAM_CLASS, stdio_read, NULL, /* write */ NULL, /* flush_output */ NULL, /* seek */ stdio_close, NULL, /* interrupt */ NULL, /* ioctl */ NULL, /* args */ SP_CREATE_STREAM_OPTION_BINARY, &stream); if (SPIO_FAILED(ecode)) goto barf; *pstream = stream; return 0; /* success */ barf: if (s != NULL) { if (s->f != NULL) fclose(s->f); SP_free(s); } return ecode; out_of_memory: ecode = SPIO_E_OUT_OF_MEMORY; goto barf; not_supported: ecode = SPIO_E_NOT_IMPLEMENTED; goto barf; }
Calling stdio_open_c("foo", "read", &stream)
will open the file
foo as binary stream that can be read by all SICStus stream
operations.
There are several stream implementions in the SICStus Prolog library
that can serve as sample, e.g. library(codesio)
and
library(tcltk)
.
See cpg-ref-SP_create_stream for details.