aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-06-15 09:26:17 -0400
committerDavid Robillard <d@drobilla.net>2019-04-13 19:15:32 +0200
commit19b358a447cf62da8aff1f4ef0235b04f39499eb (patch)
tree966fe0e98a7caf157f5ef4031475b92c552f153c
parent116d82115163a41541db28882d1614574b789f85 (diff)
downloadserd-19b358a447cf62da8aff1f4ef0235b04f39499eb.tar.gz
serd-19b358a447cf62da8aff1f4ef0235b04f39499eb.tar.bz2
serd-19b358a447cf62da8aff1f4ef0235b04f39499eb.zip
Bring read/write interface closer to C standard
-rw-r--r--NEWS1
-rw-r--r--serd/serd.h44
-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.c16
-rw-r--r--src/reader.c4
-rw-r--r--src/serdi.c11
-rw-r--r--src/uri.c40
-rw-r--r--src/writer.c27
-rw-r--r--tests/serd_test.c2
11 files changed, 87 insertions, 82 deletions
diff --git a/NEWS b/NEWS
index d57791bb..f7e72ea3 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ serd (1.0.0) unstable;
* Make serd_strtod API const-correct
* Make nodes opaque
* Remove half-baked serd_uri_to_path()
+ * Bring read/write interface closer to C standard
-- David Robillard <d@drobilla.net> Sat, 19 Jan 2019 13:31:12 +0100
diff --git a/serd/serd.h b/serd/serd.h
index 031d84c0..3698d30c 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -362,17 +362,29 @@ typedef int (*SerdStreamErrorFunc)(void* 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* buf,
- size_t size,
- size_t nmemb,
- void* stream);
+typedef size_t (*SerdReadFunc)(void* buf,
+ size_t size,
+ size_t nmemb,
+ void* 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 (*SerdSink)(const void* buf, size_t len, void* stream);
+typedef size_t (*SerdWriteFunc)(const void* buf,
+ size_t size,
+ size_t nmemb,
+ void* stream);
/**
@}
@@ -424,7 +436,7 @@ serd_uri_resolve(const SerdURI* r, const SerdURI* base, SerdURI* t);
*/
SERD_API
size_t
-serd_uri_serialise(const SerdURI* uri, SerdSink sink, void* stream);
+serd_uri_serialise(const SerdURI* uri, SerdWriteFunc sink, void* stream);
/**
Serialise `uri` relative to `base` with a series of calls to `sink`.
@@ -438,7 +450,7 @@ size_t
serd_uri_serialise_relative(const SerdURI* uri,
const SerdURI* base,
const SerdURI* root,
- SerdSink sink,
+ SerdWriteFunc sink,
void* stream);
/**
@@ -886,7 +898,7 @@ serd_reader_read_file(SerdReader* reader,
SERD_API
SerdStatus
serd_reader_start_stream(SerdReader* reader,
- SerdSource read_func,
+ SerdReadFunc read_func,
SerdStreamErrorFunc error_func,
void* stream,
const char* name,
@@ -958,7 +970,7 @@ serd_writer_new(SerdSyntax syntax,
SerdStyle style,
SerdEnv* env,
const SerdURI* base_uri,
- SerdSink ssink,
+ SerdWriteFunc ssink,
void* stream);
/**
@@ -976,16 +988,6 @@ SerdEnv*
serd_writer_get_env(SerdWriter* 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* buf, size_t len, void* 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
@@ -995,7 +997,7 @@ serd_file_sink(const void* buf, size_t len, void* stream);
*/
SERD_API
size_t
-serd_buffer_sink(const void* buf, size_t len, void* stream);
+serd_buffer_sink(const void* buf, size_t size, size_t nmemb, void* stream);
/**
Finish a serialisation to a buffer with serd_buffer_sink().
diff --git a/src/byte_sink.h b/src/byte_sink.h
index dca08825..cd9cbce6 100644
--- a/src/byte_sink.h
+++ b/src/byte_sink.h
@@ -23,15 +23,15 @@
#include "serd/serd.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;
@@ -48,7 +48,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;
}
}
@@ -67,7 +67,7 @@ serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink)
if (len == 0) {
return 0;
} else 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;
@@ -83,7 +83,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 7cd613a0..5c38e53c 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -37,7 +37,7 @@ serd_byte_source_page(SerdByteSource* source)
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/byte_source.h b/src/byte_source.h
index 0ef8f9a6..fc5947fa 100644
--- a/src/byte_source.h
+++ b/src/byte_source.h
@@ -30,7 +30,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
@@ -54,7 +54,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 8a490a45..3f2fd90f 100644
--- a/src/node.c
+++ b/src/node.c
@@ -204,12 +204,12 @@ serd_uri_string_length(const SerdURI* uri)
}
static size_t
-string_sink(const void* buf, size_t len, void* stream)
+string_sink(const void* buf, size_t size, size_t nmemb, void* stream)
{
char** ptr = (char**)stream;
- memcpy(*ptr, buf, len);
- *ptr += len;
- return len;
+ memcpy(*ptr, buf, size * nmemb);
+ *ptr += size * nmemb;
+ return nmemb;
}
SerdNode*
@@ -279,15 +279,15 @@ serd_node_new_file_uri(const char* path,
SerdBuffer buffer = { uri, uri_len };
for (size_t i = 0; i < path_len; ++i) {
if (evil && path[i] == '\\') {
- serd_buffer_sink("/", 1, &buffer);
+ serd_buffer_sink("/", 1, 1, &buffer);
} else if (path[i] == '%') {
- serd_buffer_sink("%%", 2, &buffer);
+ serd_buffer_sink("%%", 1, 2, &buffer);
} else if (!escape || is_uri_path_char(path[i])) {
- serd_buffer_sink(path + i, 1, &buffer);
+ serd_buffer_sink(path + i, 1, 1, &buffer);
} else {
char escape_str[4] = { '%', 0, 0, 0 };
snprintf(escape_str + 1, sizeof(escape_str) - 1, "%X", path[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 7d831bbe..63e45070 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -261,7 +261,7 @@ serd_reader_read_file(SerdReader* reader,
}
SerdStatus st = serd_reader_start_stream(
- reader, (SerdSource)fread, (SerdStreamErrorFunc)ferror,
+ reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror,
fd, path, SERD_PAGE_SIZE);
if (!st) {
@@ -295,7 +295,7 @@ skip_bom(SerdReader* me)
SerdStatus
serd_reader_start_stream(SerdReader* reader,
- SerdSource read_func,
+ SerdReadFunc read_func,
SerdStreamErrorFunc error_func,
void* stream,
const char* name,
diff --git a/src/serdi.c b/src/serdi.c
index 692ec56c..29c78b7f 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -287,9 +287,12 @@ main(int argc, char** argv)
output_style |= SERD_STYLE_BULK;
}
- SerdWriter* writer = serd_writer_new(
- output_syntax, (SerdStyle)output_style,
- env, &base_uri, serd_file_sink, out_fd);
+ SerdWriter* writer = serd_writer_new(output_syntax,
+ (SerdStyle)output_style,
+ env,
+ &base_uri,
+ (SerdWriteFunc)fwrite,
+ out_fd);
SerdReader* reader = serd_reader_new(
input_syntax, writer, NULL,
@@ -316,7 +319,7 @@ main(int argc, char** argv)
} else {
status = serd_reader_start_stream(
reader,
- bulk_read ? (SerdSource)fread : serd_file_read_byte,
+ bulk_read ? (SerdReadFunc)fread : serd_file_read_byte,
(SerdStreamErrorFunc)ferror,
in_fd,
in_name,
diff --git a/src/uri.c b/src/uri.c
index 138ef55c..9881f43a 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -51,18 +51,18 @@ serd_file_uri_parse(const char* uri, char** 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((const char*)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);
}
}
return serd_buffer_sink_finish(&buffer);
@@ -327,18 +327,18 @@ serd_uri_resolve(const SerdURI* r, const SerdURI* base, SerdURI* t)
/** Write the path of `uri` starting at index `i` */
static size_t
-write_path_tail(SerdSink sink, void* stream, const SerdURI* uri, size_t i)
+write_path_tail(SerdWriteFunc sink, void* stream, const SerdURI* uri, size_t i)
{
size_t len = 0;
if (i < uri->path_base.len) {
- len += sink(uri->path_base.buf + i, uri->path_base.len - i, stream);
+ len += sink(uri->path_base.buf + i, 1, uri->path_base.len - i, stream);
}
if (uri->path.buf) {
if (i < uri->path_base.len) {
- len += sink(uri->path.buf, uri->path.len, stream);
+ len += sink(uri->path.buf, 1, uri->path.len, stream);
} else {
const size_t j = (i - uri->path_base.len);
- len += sink(uri->path.buf + j, uri->path.len - j, stream);
+ len += sink(uri->path.buf + j, 1, uri->path.len - j, stream);
}
}
return len;
@@ -346,7 +346,7 @@ write_path_tail(SerdSink sink, void* stream, const SerdURI* uri, size_t i)
/** Write the path of `uri` relative to the path of `base`. */
static size_t
-write_rel_path(SerdSink sink,
+write_rel_path(SerdWriteFunc sink,
void* stream,
const SerdURI* uri,
const SerdURI* base)
@@ -379,11 +379,11 @@ write_rel_path(SerdSink sink,
// Write up references
size_t len = 0;
for (size_t u = 0; u < up; ++u) {
- len += sink("../", 3, stream);
+ len += sink("../", 1, 3, stream);
}
if (last_shared_sep == 0 && up == 0) {
- len += sink("/", 1, stream);
+ len += sink("/", 1, 1, stream);
}
// Write suffix
@@ -403,7 +403,7 @@ size_t
serd_uri_serialise_relative(const SerdURI* uri,
const SerdURI* base,
const SerdURI* root,
- SerdSink sink,
+ SerdWriteFunc sink,
void* stream)
{
size_t len = 0;
@@ -415,35 +415,35 @@ serd_uri_serialise_relative(const SerdURI* uri,
}
if (!relative || (!len && base->query.buf)) {
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.buf[uri->authority.len - 1] != '/' &&
serd_uri_path_starts_without_slash(uri)) {
// 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);
}
}
len += write_path_tail(sink, stream, uri, 0);
}
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 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;
}
/// See http://tools.ietf.org/html/rfc3986#section-5.3
size_t
-serd_uri_serialise(const SerdURI* uri, SerdSink sink, void* stream)
+serd_uri_serialise(const SerdURI* uri, SerdWriteFunc sink, void* stream)
{
return serd_uri_serialise_relative(uri, NULL, NULL, sink, stream);
}
diff --git a/src/writer.c b/src/writer.c
index 174d331a..13dd62a6 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -370,9 +370,11 @@ write_text(SerdWriter* writer, TextContext ctx,
}
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
@@ -870,7 +872,7 @@ serd_writer_new(SerdSyntax syntax,
SerdStyle style,
SerdEnv* env,
const SerdURI* base_uri,
- SerdSink ssink,
+ SerdWriteFunc ssink,
void* stream)
{
const WriteContext context = WRITE_CONTEXT_NULL;
@@ -992,24 +994,21 @@ serd_writer_get_env(SerdWriter* writer)
}
size_t
-serd_file_sink(const void* buf, size_t len, void* stream)
+serd_buffer_sink(const void* buf, size_t size, size_t nmemb, void* stream)
{
- return fwrite(buf, 1, len, (FILE*)stream);
-}
+ assert(size == 1);
+ (void)size;
-size_t
-serd_buffer_sink(const void* buf, size_t len, void* 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* stream)
{
- serd_buffer_sink("", 1, stream);
+ serd_buffer_sink("", 1, 1, stream);
return (char*)stream->buf;
}
diff --git a/tests/serd_test.c b/tests/serd_test.c
index 6c47d5e3..90a01f03 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -419,7 +419,7 @@ main(void)
assert(fd);
SerdWriter* writer = serd_writer_new(
- SERD_TURTLE, (SerdStyle)0, env, NULL, serd_file_sink, fd);
+ SERD_TURTLE, (SerdStyle)0, env, NULL, (SerdWriteFunc)fwrite, fd);
assert(writer);
serd_writer_chop_blank_prefix(writer, "tmp");