From 7d663f4cd217b91809c6b279873520192383b614 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 29 Nov 2018 21:08:25 +0100 Subject: WIP: Use SerdWorld log in validator --- serd/serd.h | 13 +++++- src/reader.c | 4 +- src/serd_validate.c | 121 ++++++++++++++++++++++++++++++++++------------------ src/string.c | 1 + src/world.c | 2 +- 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; /** @@ -348,11 +349,21 @@ typedef struct { size_t len; /**< Size of buffer in bytes */ } 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 #include @@ -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; -- cgit v1.2.1