aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-06-15 09:26:17 -0400
committerDavid Robillard <d@drobilla.net>2022-01-13 23:03:27 -0500
commit6df8ef0e9b360f8d1a37723d0492bacc4a49f957 (patch)
tree90a5faa1c5cacebff10cd9b19245816c2e60ff92
parent7a171498eca31ddedb0de1f372c982eca00d3d50 (diff)
downloadserd-6df8ef0e9b360f8d1a37723d0492bacc4a49f957.tar.gz
serd-6df8ef0e9b360f8d1a37723d0492bacc4a49f957.tar.bz2
serd-6df8ef0e9b360f8d1a37723d0492bacc4a49f957.zip
Bring read/write interface closer to C standard
-rw-r--r--NEWS1
-rw-r--r--include/serd/serd.h65
-rw-r--r--src/byte_sink.h18
-rw-r--r--src/byte_source.c2
-rw-r--r--src/byte_source.h4
-rw-r--r--src/node.c20
-rw-r--r--src/reader.c8
-rw-r--r--src/serdi.c4
-rw-r--r--src/uri.c33
-rw-r--r--src/writer.c31
-rw-r--r--test/test_reader_writer.c5
11 files changed, 99 insertions, 92 deletions
diff --git a/NEWS b/NEWS
index f66ebd6c..bfc786fe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
serd (1.0.1) unstable;
* Add SerdBuffer for mutable buffers to keep SerdChunk const-correct
+ * Bring read/write interface closer to C standard
* Make nodes opaque
* Remove serd_uri_to_path()
* Remove support for Turtle named inline nodes extension
diff --git a/include/serd/serd.h b/include/serd/serd.h
index 6b455878..8b51e947 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -283,17 +283,29 @@ typedef int (*SerdStreamErrorFunc)(void* SERD_NONNULL stream);
@param size Size of a single element of data in bytes (always 1).
@param nmemb Number of elements to read.
@param stream Stream to read from (FILE* for fread).
- @return Number of elements (bytes) read.
+ @return Number of elements (bytes) read, which is short on error.
*/
-typedef size_t (*SerdSource)(void* SERD_NONNULL buf,
- size_t size,
- size_t nmemb,
- void* SERD_NONNULL stream);
+typedef size_t (*SerdReadFunc)(void* SERD_NONNULL buf,
+ size_t size,
+ size_t nmemb,
+ void* SERD_NONNULL stream);
-/// Sink function for raw string output
-typedef size_t (*SerdSink)(const void* SERD_NONNULL buf,
- size_t len,
- void* SERD_NONNULL stream);
+/**
+ Sink function for raw string output.
+
+ Identical semantics to `fwrite`, but may set errno for more informative
+ error reporting than supported by SerdStreamErrorFunc.
+
+ @param buf Input buffer.
+ @param size Size of a single element of data in bytes (always 1).
+ @param nmemb Number of elements to read.
+ @param stream Stream to write to (FILE* for fread).
+ @return Number of elements (bytes) written, which is short on error.
+*/
+typedef size_t (*SerdWriteFunc)(const void* SERD_NONNULL buf,
+ size_t size,
+ size_t nmemb,
+ void* SERD_NONNULL stream);
/**
@}
@@ -422,9 +434,9 @@ serd_uri_is_within(SerdURIView r, SerdURIView base);
*/
SERD_API
size_t
-serd_write_uri(SerdURIView uri,
- SerdSink SERD_NONNULL sink,
- void* SERD_NONNULL stream);
+serd_write_uri(SerdURIView uri,
+ SerdWriteFunc SERD_NONNULL sink,
+ void* SERD_NONNULL stream);
/**
@}
@@ -927,7 +939,7 @@ serd_reader_start_stream(SerdReader* SERD_NONNULL reader,
SERD_API
SerdStatus
serd_reader_start_source_stream(SerdReader* SERD_NONNULL reader,
- SerdSource SERD_NONNULL read_func,
+ SerdReadFunc SERD_NONNULL read_func,
SerdStreamErrorFunc SERD_NONNULL error_func,
void* SERD_NONNULL stream,
const char* SERD_NULLABLE name,
@@ -961,7 +973,7 @@ serd_reader_read_file_handle(SerdReader* SERD_NONNULL reader,
SERD_API
SerdStatus
serd_reader_read_source(SerdReader* SERD_NONNULL reader,
- SerdSource SERD_NONNULL source,
+ SerdReadFunc SERD_NONNULL source,
SerdStreamErrorFunc SERD_NONNULL error,
void* SERD_NONNULL stream,
const char* SERD_NULLABLE name,
@@ -1008,11 +1020,11 @@ typedef uint32_t SerdWriterFlags;
/// Create a new RDF writer
SERD_API
SerdWriter* SERD_ALLOCATED
-serd_writer_new(SerdSyntax syntax,
- SerdWriterFlags flags,
- SerdEnv* SERD_NONNULL env,
- SerdSink SERD_NONNULL ssink,
- void* SERD_NULLABLE stream);
+serd_writer_new(SerdSyntax syntax,
+ SerdWriterFlags flags,
+ SerdEnv* SERD_NONNULL env,
+ SerdWriteFunc SERD_NONNULL ssink,
+ void* SERD_NULLABLE stream);
/// Free `writer`
SERD_API
@@ -1025,18 +1037,6 @@ SerdEnv* SERD_NONNULL
serd_writer_env(SerdWriter* SERD_NONNULL writer);
/**
- A convenience sink function for writing to a FILE*.
-
- This function can be used as a SerdSink when writing to a FILE*. The
- `stream` parameter must be a FILE* opened for writing.
-*/
-SERD_API
-size_t
-serd_file_sink(const void* SERD_NONNULL buf,
- size_t len,
- void* SERD_NONNULL stream);
-
-/**
A convenience sink function for writing to a string.
This function can be used as a SerdSink to write to a SerdBuffer which is
@@ -1047,7 +1047,8 @@ serd_file_sink(const void* SERD_NONNULL buf,
SERD_API
size_t
serd_buffer_sink(const void* SERD_NONNULL buf,
- size_t len,
+ size_t size,
+ size_t nmemb,
void* SERD_NONNULL stream);
/**
diff --git a/src/byte_sink.h b/src/byte_sink.h
index d5222843..576f9c2e 100644
--- a/src/byte_sink.h
+++ b/src/byte_sink.h
@@ -26,15 +26,15 @@
#include <string.h>
typedef struct SerdByteSinkImpl {
- SerdSink sink;
- void* stream;
- char* buf;
- size_t size;
- size_t block_size;
+ SerdWriteFunc sink;
+ void* stream;
+ char* buf;
+ size_t size;
+ size_t block_size;
} SerdByteSink;
static inline SerdByteSink
-serd_byte_sink_new(SerdSink sink, void* stream, size_t block_size)
+serd_byte_sink_new(SerdWriteFunc sink, void* stream, size_t block_size)
{
SerdByteSink bsink;
bsink.sink = sink;
@@ -50,7 +50,7 @@ static inline void
serd_byte_sink_flush(SerdByteSink* bsink)
{
if (bsink->block_size > 1 && bsink->size > 0) {
- bsink->sink(bsink->buf, bsink->size, bsink->stream);
+ bsink->sink(bsink->buf, 1, bsink->size, bsink->stream);
bsink->size = 0;
}
}
@@ -71,7 +71,7 @@ serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
}
if (bsink->block_size == 1) {
- return bsink->sink(buf, len, bsink->stream);
+ return bsink->sink(buf, 1, len, bsink->stream);
}
const size_t orig_len = len;
@@ -87,7 +87,7 @@ serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
// Flush page if buffer is full
if (bsink->size == bsink->block_size) {
- bsink->sink(bsink->buf, bsink->block_size, bsink->stream);
+ bsink->sink(bsink->buf, 1, bsink->block_size, bsink->stream);
bsink->size = 0;
}
}
diff --git a/src/byte_source.c b/src/byte_source.c
index dac5d049..275133b9 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -48,7 +48,7 @@ serd_byte_source_page(SerdByteSource* const source)
SerdStatus
serd_byte_source_open_source(SerdByteSource* const source,
- const SerdSource read_func,
+ const SerdReadFunc read_func,
const SerdStreamErrorFunc error_func,
void* const stream,
const char* const name,
diff --git a/src/byte_source.h b/src/byte_source.h
index 63cc1b51..a5c98ef6 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -32,7 +32,7 @@ typedef struct {
} Cursor;
typedef struct {
- SerdSource read_func; ///< Read function (e.g. fread)
+ SerdReadFunc read_func; ///< Read function (e.g. fread)
SerdStreamErrorFunc error_func; ///< Error function (e.g. ferror)
void* stream; ///< Stream (e.g. FILE)
size_t page_size; ///< Number of bytes to read at a time
@@ -55,7 +55,7 @@ serd_byte_source_open_string(SerdByteSource* source, const char* utf8);
SerdStatus
serd_byte_source_open_source(SerdByteSource* source,
- SerdSource read_func,
+ SerdReadFunc read_func,
SerdStreamErrorFunc error_func,
void* stream,
const char* name,
diff --git a/src/node.c b/src/node.c
index 8f981856..8485c144 100644
--- a/src/node.c
+++ b/src/node.c
@@ -48,7 +48,6 @@ static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
static SerdNode*
serd_new_from_uri(SerdURIView uri, SerdURIView base);
-SERD_PURE_FUNC
static size_t
serd_uri_string_length(const SerdURIView* const uri)
{
@@ -69,12 +68,15 @@ serd_uri_string_length(const SerdURIView* const uri)
}
static size_t
-string_sink(const void* const buf, const size_t len, void* const stream)
+string_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
char** ptr = (char**)stream;
- memcpy(*ptr, buf, len);
- *ptr += len;
- return len;
+ memcpy(*ptr, buf, size * nmemb);
+ *ptr += size * nmemb;
+ return nmemb;
}
static size_t
@@ -390,16 +392,16 @@ serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
SerdBuffer buffer = {uri, uri_len};
for (size_t i = 0; i < path.len; ++i) {
if (is_windows && path.buf[i] == '\\') {
- serd_buffer_sink("/", 1, &buffer);
+ serd_buffer_sink("/", 1, 1, &buffer);
} else if (path.buf[i] == '%') {
- serd_buffer_sink("%%", 2, &buffer);
+ serd_buffer_sink("%%", 1, 2, &buffer);
} else if (is_uri_path_char(path.buf[i])) {
- serd_buffer_sink(path.buf + i, 1, &buffer);
+ serd_buffer_sink(path.buf + i, 1, 1, &buffer);
} else {
char escape_str[10] = {'%', 0, 0, 0, 0, 0, 0, 0, 0, 0};
snprintf(
escape_str + 1, sizeof(escape_str) - 1, "%X", (unsigned)path.buf[i]);
- serd_buffer_sink(escape_str, 3, &buffer);
+ serd_buffer_sink(escape_str, 1, 3, &buffer);
}
}
serd_buffer_sink_finish(&buffer);
diff --git a/src/reader.c b/src/reader.c
index d0cc8a97..6bd458d4 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -319,7 +319,7 @@ serd_reader_start_stream(SerdReader* const reader,
const bool bulk)
{
return serd_reader_start_source_stream(reader,
- bulk ? (SerdSource)fread
+ bulk ? (SerdReadFunc)fread
: serd_file_read_byte,
(SerdStreamErrorFunc)ferror,
file,
@@ -329,7 +329,7 @@ serd_reader_start_stream(SerdReader* const reader,
SerdStatus
serd_reader_start_source_stream(SerdReader* const reader,
- const SerdSource read_func,
+ const SerdReadFunc read_func,
const SerdStreamErrorFunc error_func,
void* const stream,
const char* const name,
@@ -383,7 +383,7 @@ serd_reader_read_file_handle(SerdReader* const reader,
const char* const name)
{
return serd_reader_read_source(reader,
- (SerdSource)fread,
+ (SerdReadFunc)fread,
(SerdStreamErrorFunc)ferror,
file,
name,
@@ -392,7 +392,7 @@ serd_reader_read_file_handle(SerdReader* const reader,
SerdStatus
serd_reader_read_source(SerdReader* const reader,
- const SerdSource source,
+ const SerdReadFunc source,
const SerdStreamErrorFunc error,
void* const stream,
const char* const name,
diff --git a/src/serdi.c b/src/serdi.c
index ed34b0fb..a62083af 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -327,8 +327,8 @@ main(int argc, char** argv)
SerdEnv* const env =
serd_env_new(base ? serd_node_string_view(base) : SERD_EMPTY_STRING());
- SerdWriter* const writer =
- serd_writer_new(output_syntax, writer_flags, env, serd_file_sink, out_fd);
+ SerdWriter* writer = serd_writer_new(
+ output_syntax, writer_flags, env, (SerdWriteFunc)fwrite, out_fd);
SerdReader* const reader =
serd_reader_new(input_syntax,
diff --git a/src/uri.c b/src/uri.c
index 2c9c6db2..2b7aef17 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -57,18 +57,18 @@ serd_parse_file_uri(const char* const uri, char** const hostname)
for (const char* s = path; *s; ++s) {
if (*s == '%') {
if (*(s + 1) == '%') {
- serd_buffer_sink("%", 1, &buffer);
+ serd_buffer_sink("%", 1, 1, &buffer);
++s;
} else if (is_hexdig(*(s + 1)) && is_hexdig(*(s + 2))) {
const char code[3] = {*(s + 1), *(s + 2), 0};
const char c = (char)strtoul(code, NULL, 16);
- serd_buffer_sink(&c, 1, &buffer);
+ serd_buffer_sink(&c, 1, 1, &buffer);
s += 2;
} else {
s += 2; // Junk escape, ignore
}
} else {
- serd_buffer_sink(s, 1, &buffer);
+ serd_buffer_sink(s, 1, 1, &buffer);
}
}
@@ -411,48 +411,49 @@ serd_uri_is_within(const SerdURIView uri, const SerdURIView base)
/// See http://tools.ietf.org/html/rfc3986#section-5.3
size_t
-serd_write_uri(const SerdURIView uri, SerdSink sink, void* const stream)
+serd_write_uri(const SerdURIView uri,
+ const SerdWriteFunc sink,
+ void* const stream)
{
size_t len = 0;
if (uri.scheme.buf) {
- len += sink(uri.scheme.buf, uri.scheme.len, stream);
- len += sink(":", 1, stream);
+ len += sink(uri.scheme.buf, 1, uri.scheme.len, stream);
+ len += sink(":", 1, 1, stream);
}
if (uri.authority.buf) {
- len += sink("//", 2, stream);
- len += sink(uri.authority.buf, uri.authority.len, stream);
+ len += sink("//", 1, 2, stream);
+ len += sink(uri.authority.buf, 1, uri.authority.len, stream);
if (uri.authority.len > 0 && uri_path_len(&uri) > 0 &&
uri_path_at(&uri, 0) != '/') {
// Special case: ensure path begins with a slash
// https://tools.ietf.org/html/rfc3986#section-3.2
- len += sink("/", 1, stream);
+ len += sink("/", 1, 1, stream);
}
}
if (uri.path_prefix.buf) {
- len += sink(uri.path_prefix.buf, uri.path_prefix.len, stream);
+ len += sink(uri.path_prefix.buf, 1, uri.path_prefix.len, stream);
} else if (uri.path_prefix.len) {
for (size_t i = 0; i < uri.path_prefix.len; ++i) {
- len += sink("../", 3, stream);
+ len += sink("../", 1, 3, stream);
}
}
if (uri.path.buf) {
- len += sink(uri.path.buf, uri.path.len, stream);
+ len += sink(uri.path.buf, 1, uri.path.len, stream);
}
if (uri.query.buf) {
- len += sink("?", 1, stream);
- len += sink(uri.query.buf, uri.query.len, stream);
+ len += sink("?", 1, 1, stream);
+ len += sink(uri.query.buf, 1, uri.query.len, stream);
}
if (uri.fragment.buf) {
// Note that uri.fragment.buf includes the leading `#'
- len += sink(uri.fragment.buf, uri.fragment.len, stream);
+ len += sink(uri.fragment.buf, 1, uri.fragment.len, stream);
}
-
return len;
}
diff --git a/src/writer.c b/src/writer.c
index 227d516c..7c3cb563 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -438,9 +438,11 @@ write_text(SerdWriter* writer,
}
static size_t
-uri_sink(const void* buf, size_t len, void* stream)
+uri_sink(const void* buf, size_t size, size_t nmemb, void* stream)
{
- return write_uri((SerdWriter*)stream, (const char*)buf, len);
+ (void)size;
+ assert(size == 1);
+ return write_uri((SerdWriter*)stream, (const char*)buf, nmemb);
}
static void
@@ -938,7 +940,7 @@ SerdWriter*
serd_writer_new(SerdSyntax syntax,
SerdWriterFlags flags,
SerdEnv* env,
- SerdSink ssink,
+ SerdWriteFunc ssink,
void* stream)
{
const WriteContext context = WRITE_CONTEXT_NULL;
@@ -1076,25 +1078,24 @@ serd_writer_env(SerdWriter* writer)
}
size_t
-serd_file_sink(const void* buf, size_t len, void* stream)
+serd_buffer_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
- return fwrite(buf, 1, len, (FILE*)stream);
-}
+ assert(size == 1);
+ (void)size;
-size_t
-serd_buffer_sink(const void* const buf, const size_t len, void* const stream)
-{
SerdBuffer* buffer = (SerdBuffer*)stream;
-
- buffer->buf = (char*)realloc(buffer->buf, buffer->len + len);
- memcpy((uint8_t*)buffer->buf + buffer->len, buf, len);
- buffer->len += len;
- return len;
+ buffer->buf = (char*)realloc(buffer->buf, buffer->len + nmemb);
+ memcpy((uint8_t*)buffer->buf + buffer->len, buf, nmemb);
+ buffer->len += nmemb;
+ return nmemb;
}
char*
serd_buffer_sink_finish(SerdBuffer* const stream)
{
- serd_buffer_sink("", 1, stream);
+ serd_buffer_sink("", 1, 1, stream);
return (char*)stream->buf;
}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 3a78889c..76ba87b7 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -180,7 +180,8 @@ test_writer(const char* const path)
SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
assert(fd);
- SerdWriter* writer = serd_writer_new(SERD_TURTLE, 0, env, serd_file_sink, fd);
+ SerdWriter* writer =
+ serd_writer_new(SERD_TURTLE, 0, env, (SerdWriteFunc)fwrite, fd);
assert(writer);
serd_writer_chop_blank_prefix(writer, "tmp");
@@ -322,7 +323,7 @@ test_reader(const char* path)
{
size_t n_reads = 0;
serd_reader_start_source_stream(reader,
- (SerdSource)eof_test_read,
+ (SerdReadFunc)eof_test_read,
(SerdStreamErrorFunc)eof_test_error,
&n_reads,
NULL,