aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--serd/serd.h13
-rw-r--r--src/reader.c4
-rw-r--r--src/serd_validate.c121
-rw-r--r--src/string.c1
-rw-r--r--src/world.c2
5 files changed, 96 insertions, 45 deletions
diff --git a/serd/serd.h b/serd/serd.h
index 8aa22f7a..4f8d40c5 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -159,7 +159,8 @@ typedef enum {
SERD_ERR_ID_CLASH, /**< Encountered clashing blank node IDs */
SERD_ERR_BAD_CURIE, /**< Invalid CURIE (e.g. prefix does not exist) */
SERD_ERR_INTERNAL, /**< Unexpected internal error (should not happen) */
- SERD_ERR_OVERFLOW /**< Stack overflow */
+ SERD_ERR_OVERFLOW, /**< Stack overflow */
+ SERD_ERR_INVALID /**< Invalid data */
} SerdStatus;
/**
@@ -349,10 +350,20 @@ typedef struct {
} SerdBuffer;
/**
+ Log message level.
+*/
+typedef enum {
+ SERD_LOG_LEVEL_INFO = 0, /**< Normal informative message */
+ SERD_LOG_LEVEL_WARNING = 1, /**< Warning */
+ SERD_LOG_LEVEL_ERROR = 2, /**< Error */
+} SerdLogLevel;
+
+/**
A message description.
*/
typedef struct {
SerdStatus status; /**< Status code */
+ SerdLogLevel level; /**< Log level */
const SerdCursor* cursor; /**< Origin of message, or NULL */
const char* fmt; /**< Message format string (printf style) */
va_list* args; /**< Arguments for fmt */
diff --git a/src/reader.c b/src/reader.c
index 0b0c2360..7d82d8ca 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -37,7 +37,9 @@ r_err(SerdReader* reader, SerdStatus st, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- const SerdMessage msg = { st, &reader->source.cur, fmt, &args };
+ const SerdMessage msg = {
+ st, SERD_LOG_LEVEL_ERROR, &reader->source.cur, fmt, &args
+ };
serd_world_error(reader->world, &msg);
va_end(args);
return st;
diff --git a/src/serd_validate.c b/src/serd_validate.c
index b852a3fa..f84344b1 100644
--- a/src/serd_validate.c
+++ b/src/serd_validate.c
@@ -19,7 +19,9 @@
#include "serd_config.h"
+#include "model.h"
#include "serd/serd.h"
+#include "world.h"
#include <assert.h>
#include <limits.h>
@@ -42,14 +44,15 @@
#define CERRORF(fmt, ...) fprintf(stderr, "serd_validate: " fmt, __VA_ARGS__);
-#define VERRORF(statement, fmt, ...) \
- report(statement, "error", fmt, __VA_ARGS__);
+#define VERRORF(model, statement, fmt, ...) \
+ report(model, statement, "error", fmt, __VA_ARGS__);
-#define VERROR(statement, fmt) report(statement, "error", fmt);
+#define VERROR(model, statement, fmt) report(model, statement, "error", fmt);
-#define VNOTEF(statement, fmt, ...) report(statement, "note", fmt, __VA_ARGS__);
+#define VNOTEF(model, statement, fmt, ...) \
+ report(model, statement, "note", fmt, __VA_ARGS__);
-#define VNOTE(statement, fmt) report(statement, "note", fmt);
+#define VNOTE(model, statement, fmt) report(model, statement, "note", fmt);
#define SERD_FOREACH(name, range) \
for (const SerdStatement* name = NULL; \
@@ -153,12 +156,16 @@ absolute_path(const char* path)
}
static int
-report(const SerdStatement* statement, const char* type, const char* fmt, ...)
+report(const SerdModel* model,
+ const SerdStatement* statement,
+ const char* type,
+ const char* fmt,
+ ...)
{
va_list args;
va_start(args, fmt);
- fprintf(stderr, "%s: ", type);
+ serd_world_errorf(model->world, SERD_ERR_INVALID, "%s: ", type);
const SerdCursor* cursor = serd_statement_get_cursor(statement);
if (cursor) {
@@ -237,7 +244,10 @@ is_subdatatype(SerdModel* model,
}
static bool
-regexp_match(const SerdStatement* pat_statement, const char* pat, const char* str)
+regexp_match(const SerdModel* model,
+ const SerdStatement* pat_statement,
+ const char* pat,
+ const char* str)
{
#ifdef HAVE_PCRE
// Append a $ to the pattern so we only match if the entire string matches
@@ -252,7 +262,8 @@ regexp_match(const SerdStatement* pat_statement, const char* pat, const char* st
pcre* re = pcre_compile(regx, PCRE_ANCHORED, &err, &erroffset, NULL);
free(regx);
if (!re) {
- VERRORF(pat_statement,
+ VERRORF(model,
+ pat_statement,
"Error in pattern \"%s\" at offset %d (%s)\n",
pat,
erroffset,
@@ -305,8 +316,9 @@ check_literal_restriction(SerdModel* model,
if (pat_statement) {
const SerdNode* pat_node = serd_statement_get_object(pat_statement);
const char* pat = serd_node_get_string(pat_node);
- if (check(!regexp_match(pat_statement, pat, str))) {
- VERRORF(statement,
+ if (check(!regexp_match(model, pat_statement, pat, str))) {
+ VERRORF(model,
+ statement,
"Value \"%s\" does not match pattern \"%s\"\n",
serd_node_get_string(literal),
pat);
@@ -319,7 +331,8 @@ check_literal_restriction(SerdModel* model,
serd_model_get(model, restriction, uris->xsd_minInclusive, 0, 0);
if (lower) {
if (check(bound_cmp(model, uris, literal, type, lower) < 0)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Value \"%s\" < minimum \"%s\"\n",
serd_node_get_string(literal),
serd_node_get_string(lower));
@@ -332,7 +345,8 @@ check_literal_restriction(SerdModel* model,
serd_model_get(model, restriction, uris->xsd_maxInclusive, 0, 0);
if (upper) {
if (check(bound_cmp(model, uris, literal, type, upper) > 0)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Value \"%s\" > than maximum \"%s\"\n",
serd_node_get_string(literal),
serd_node_get_string(upper));
@@ -345,7 +359,8 @@ check_literal_restriction(SerdModel* model,
serd_model_get(model, restriction, uris->xsd_minExclusive, 0, 0);
if (elower) {
if (check(bound_cmp(model, uris, literal, type, elower) <= 0)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Value \"%s\" <= exclusive minimum \"%s\"\n",
serd_node_get_string(literal),
serd_node_get_string(elower));
@@ -358,7 +373,8 @@ check_literal_restriction(SerdModel* model,
serd_model_get(model, restriction, uris->xsd_maxExclusive, 0, 0);
if (eupper) {
if (check(bound_cmp(model, uris, literal, type, eupper) >= 0)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Value \"%s\" >= exclusive maximum \"%s\"\n",
serd_node_get_string(literal),
serd_node_get_string(eupper));
@@ -398,7 +414,8 @@ literal_is_valid(SerdModel* model,
// Check that datatype is defined
const SerdNode* datatype = serd_node_get_datatype(literal);
if (datatype && !is_datatype(model, uris, datatype)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Datatype <%s> is not defined\n",
serd_node_get_string(datatype));
return false;
@@ -420,7 +437,8 @@ literal_is_valid(SerdModel* model,
// Check this restriction
if (!check_literal_restriction(
model, uris, statement, literal, type, first)) {
- VNOTEF(serd_iter_get(f),
+ VNOTEF(model,
+ serd_iter_get(f),
"Restriction on <%s>\n",
serd_node_get_string(type));
return false;
@@ -488,7 +506,9 @@ check_instance_type(SerdModel* model,
{
if (is_subclass(model, uris, klass, uris->rdfs_Literal) ||
serd_model_ask(model, klass, uris->rdf_type, uris->rdfs_Datatype, 0)) {
- VERROR(statement, "Class instance found where literal expected\n");
+ VERROR(model,
+ statement,
+ "Class instance found where literal expected\n");
return false;
}
@@ -511,7 +531,8 @@ check_instance_type(SerdModel* model,
}
if (!is_instance_of(model, uris, statement, node, klass)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Node %s is not an instance of %s\n",
serd_node_get_string(node),
serd_node_get_string(klass));
@@ -538,7 +559,8 @@ check_type(SerdModel* model,
return true; // Trivially true for a literal
} else if (serd_node_equals(type, uris->rdf_PlainLiteral)) {
if (serd_node_get_datatype(node)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Literal \"%s\" should be plain, but has datatype "
"<%s>\n",
serd_node_get_string(node),
@@ -551,7 +573,8 @@ check_type(SerdModel* model,
uris->rdf_type,
uris->rdfs_Datatype,
NULL)) {
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Literal \"%s\" where instance of <%s> expected\n",
serd_node_get_string(node),
serd_node_get_string(type));
@@ -571,7 +594,8 @@ check_type(SerdModel* model,
return check_instance_type(model, uris, statement, node, type);
}
- VERRORF(statement,
+ VERRORF(model,
+ statement,
"Unhandled case checking if %s is of type %s\n",
serd_node_get_string(node),
serd_node_get_string(type));
@@ -616,7 +640,7 @@ check_statement(SerdModel* model,
serd_range_free(t);
if (!is_property) {
- st = VERROR(statement, "Use of undefined property\n");
+ st = VERROR(model, statement, "Use of undefined property\n");
}
if (serd_node_equals(pred, uris->rdf_type)) {
@@ -638,24 +662,29 @@ check_statement(SerdModel* model,
model, pred, uris->rdf_type, uris->owl_DatatypeProperty, 0);
if (!serd_model_ask(model, pred, uris->rdfs_label, NULL, NULL)) {
- st = VERRORF(statement,
+ st = VERRORF(model,
+ statement,
"Property <%s> has no label\n",
serd_node_get_string(pred));
}
if (is_DatatypeProperty && serd_node_get_type(obj) != SERD_LITERAL) {
- st = VERROR(statement, "Datatype property with non-literal value\n");
+ st = VERROR(
+ model, statement, "Datatype property with non-literal value\n");
}
if (is_ObjectProperty && serd_node_get_type(obj) == SERD_LITERAL) {
- st = VERROR(statement, "Object property with literal value\n");
+ st = VERROR(model, statement, "Object property with literal value\n");
}
if (is_FunctionalProperty) {
SerdRange* o = serd_model_range(model, subj, pred, NULL, NULL);
const uint64_t n = count_non_blanks(o, SERD_OBJECT);
if (n > 1) {
- st = VERRORF(statement, "Functional property with %u objects\n", n);
+ st = VERRORF(model,
+ statement,
+ "Functional property with %u objects\n",
+ n);
}
serd_range_free(o);
}
@@ -664,7 +693,8 @@ check_statement(SerdModel* model,
SerdRange* s = serd_model_range(model, NULL, pred, obj, NULL);
const unsigned n = count_non_blanks(s, SERD_SUBJECT);
if (n > 1) {
- st = VERRORF(statement,
+ st = VERRORF(model,
+ statement,
"Inverse functional property with %u subjects\n",
n);
}
@@ -674,7 +704,8 @@ check_statement(SerdModel* model,
if (serd_node_get_type(obj) == SERD_LITERAL &&
!literal_is_valid(
model, uris, statement, obj, serd_node_get_datatype(obj))) {
- /* st = VERRORF(statement, "Literal does not match datatype\n"); */
+ /* st = VERRORF(model,
+statement, "Literal does not match datatype\n"); */
}
// Check range
@@ -686,7 +717,8 @@ check_statement(SerdModel* model,
}
if (!check_type(model, uris, statement, obj, range)) {
- VNOTEF(serd_range_front(r),
+ VNOTEF(model,
+ serd_range_front(r),
"Range of <%s> defined here\n",
serd_node_get_string(pred));
}
@@ -702,7 +734,8 @@ check_statement(SerdModel* model,
}
if (!check_type(model, uris, statement, subj, domain)) {
- VNOTEF(serd_range_front(d),
+ VNOTEF(model,
+ serd_range_front(d),
"Domain of <%s> defined here\n",
serd_node_get_string(pred));
}
@@ -726,7 +759,8 @@ check_properties(SerdModel* model, URIs* uris)
}
static int
-cardinality_error(const SerdStatement* statement,
+cardinality_error(const SerdModel* model,
+ const SerdStatement* statement,
const SerdStatement* restriction_statement,
const SerdNode* property,
const SerdNode* instance,
@@ -734,13 +768,14 @@ cardinality_error(const SerdStatement* statement,
const char* comparison,
const unsigned expected_values)
{
- const int st = VERRORF(statement,
+ const int st = VERRORF(model,
+ statement,
"Property <%s> has %u %s %u values\n",
serd_node_get_string(property),
actual_values,
comparison,
expected_values);
- VNOTE(restriction_statement, "Restriction here\n");
+ VNOTE(model, restriction_statement, "Restriction here\n");
return st;
}
@@ -768,7 +803,7 @@ check_class_restriction(SerdModel* model,
const unsigned count = atoi(serd_node_get_string(card));
if (check(values != count)) {
st = cardinality_error(
- statement, c, prop, instance, values, "!=", count);
+ model, statement, c, prop, instance, values, "!=", count);
}
}
@@ -780,7 +815,7 @@ check_class_restriction(SerdModel* model,
const unsigned count = atoi(serd_node_get_string(card));
if (check(values < count)) {
st = cardinality_error(
- statement, l, prop, instance, values, "<", count);
+ model, statement, l, prop, instance, values, "<", count);
}
}
@@ -792,13 +827,13 @@ check_class_restriction(SerdModel* model,
const unsigned count = atoi(serd_node_get_string(card));
if (check(values > count)) {
st = cardinality_error(
- statement, u, prop, instance, values, ">", count);
+ model, statement, u, prop, instance, values, ">", count);
}
}
// Check someValuesFrom
const SerdStatement* s = serd_model_get_statement(
- model, restriction, uris->owl_someValuesFrom, 0, 0);
+ model, restriction, uris->owl_someValuesFrom, 0, 0);
if (s) {
const SerdNode* some = serd_statement_get_object(s);
@@ -812,12 +847,13 @@ check_class_restriction(SerdModel* model,
}
}
if (check(!found)) {
- st = VERRORF(statement,
+ st = VERRORF(model,
+ statement,
"%s has no <%s> values of type <%s>\n",
serd_node_get_string(instance),
serd_node_get_string(prop),
serd_node_get_string(some));
- VNOTE(s, "Restriction here\n");
+ VNOTE(model, s, "Restriction here\n");
}
serd_range_free(v);
}
@@ -833,11 +869,12 @@ check_class_restriction(SerdModel* model,
SERD_FOREACH (i, v) {
const SerdNode* value = serd_statement_get_object(i);
if (!check_type(model, uris, statement, value, all)) {
- st = VERRORF(i,
+ st = VERRORF(model,
+ i,
"<%s> value not of type <%s>\n",
serd_node_get_string(prop),
serd_node_get_string(all));
- VNOTE(a, "Restriction here\n");
+ VNOTE(model, a, "Restriction here\n");
break;
}
}
diff --git a/src/string.c b/src/string.c
index a1d3a0b5..29b21cb7 100644
--- a/src/string.c
+++ b/src/string.c
@@ -44,6 +44,7 @@ serd_strerror(SerdStatus status)
case SERD_ERR_BAD_CURIE: return "Invalid CURIE";
case SERD_ERR_INTERNAL: return "Internal error";
case SERD_ERR_OVERFLOW: return "Stack overflow";
+ case SERD_ERR_INVALID: return "Invalid data";
}
return "Unknown error"; // never reached
}
diff --git a/src/world.c b/src/world.c
index 01a86dc5..3140066e 100644
--- a/src/world.c
+++ b/src/world.c
@@ -74,7 +74,7 @@ serd_world_errorf(const SerdWorld* world, SerdStatus st, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- const SerdMessage msg = { st, NULL, fmt, &args };
+ const SerdMessage msg = { st, SERD_LOG_LEVEL_ERROR, NULL, fmt, &args };
serd_world_error(world, &msg);
va_end(args);
return st;