diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..533e5d9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +project(yavl-cpp) +cmake_minimum_required(VERSION 2.8) + +find_package(PkgConfig REQUIRED) +pkg_check_modules (YAML REQUIRED yaml-cpp) + +include_directories( include/yavl-cpp /usr/include/yaml-cpp ) +link_libraries( yaml-cpp ) + +add_library(yavl-cpp SHARED src/yavl.cpp include/yavl-cpp/yavl.h) diff --git a/include/yavl-cpp/yavl.h b/include/yavl-cpp/yavl.h new file mode 100644 index 0000000..4ef3391 --- /dev/null +++ b/include/yavl-cpp/yavl.h @@ -0,0 +1,73 @@ +#ifndef _YAVL_H_ +#define _YAVL_H_ + +#include "yaml-cpp/yaml.h" +#include +#include +#include + +namespace YAVL { + +typedef std::vector Path; + +// really sucks that I have to do this sort of crap since I can't +// pass a type as an argument to a function. +template +std::string ctype2str() { + return "FAIL"; +} + +class Exception { +public: + std::string why; + Path gr_path; + Path doc_path; + Exception(const std::string _why, const Path& _gr_path, + const Path& _doc_path) : + why(_why), gr_path(_gr_path), doc_path(_doc_path) { + } + ; +}; + +typedef std::vector Errors; + +class Validator { + const YAML::Node& gr; + const YAML::Node& doc; + Path gr_path; + Path doc_path; + Errors errors; + + int num_keys(const YAML::Node& doc); + const std::string& type2str(const YAML::Node &doc); + bool validate_map(const YAML::Node &mapNode, const YAML::Node &doc); + bool validate_leaf(const YAML::Node &gr, const YAML::Node &doc); + bool validate_list(const YAML::Node &gr, const YAML::Node &doc); + bool validate_doc(const YAML::Node &gr, const YAML::Node &doc); + + void gen_error(const Exception& err) { + errors.push_back(err); + } + +public: + Validator(const YAML::Node& _gr, const YAML::Node& _doc) : + gr(_gr), doc(_doc) { + } + ; + + bool validate() { + return validate_doc(gr, doc); + } + + const Errors& get_errors() { + return errors; + } +}; +} + +std::ostream& operator <<(std::ostream& os, const YAVL::Path& path); +std::ostream& operator <<(std::ostream& os, const YAVL::Exception& v); +std::ostream& operator <<(std::ostream& os, const YAVL::Errors& v); + +#endif + diff --git a/scripts/generate-pkgconfig.sh b/scripts/generate-pkgconfig.sh new file mode 100755 index 0000000..3031ba4 --- /dev/null +++ b/scripts/generate-pkgconfig.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# This script create a pkg-config file for this clone of yavl-cpp +# It's fixed to reference to the ../build as the build directory. +# +set -e + +abspath=$(cd `dirname "${BASH_SOURCE[0]}"`/.. && pwd) +pkg_config_path="$1" + +if [ -z ${pkg_config_path} ]; then + echo Please specify your pkgconfig directory + exit 1 +fi + +mkdir -p ${pkg_config_path} +cat > ${pkg_config_path}/yavl-cpp.pc <= 0.5.1 +Libs: -L\${libdir} -lyavl-cpp +Cflags: -I\${includedir} +EOF diff --git a/src/yavl.cpp b/src/yavl.cpp index 5b0e8fb..208369f 100644 --- a/src/yavl.cpp +++ b/src/yavl.cpp @@ -1,212 +1,244 @@ #include #include -#include "yaml.h" #include "yavl.h" using namespace std; using namespace YAVL; namespace YAVL { - template <> - std::string ctype2str() - { - return "unsigned long long"; - } - - template <> - std::string ctype2str() - { - return "string"; - } - - template <> - std::string ctype2str() - { - return "long long"; - } - - template <> - std::string ctype2str() - { - return "unsigned int"; - } - - template <> - std::string ctype2str() - { - return "int"; - } +template<> +std::string ctype2str() { + return "unsigned long long"; +} + +template<> +std::string ctype2str() { + return "string"; +} + +template<> +std::string ctype2str() { + return "long long"; +} + +template<> +std::string ctype2str() { + return "unsigned int"; +} + +template<> +std::string ctype2str() { + return "int"; +} } -ostream& operator << (ostream& os, const Path& path) -{ - for (Path::const_iterator i = path.begin(); i != path.end(); ++i) { - // no dot before list indexes and before first element - if ((i != path.begin()) && ((*i)[0] != '[')) { - os << '.'; - } - os << *i; - } - return os; +ostream& operator <<(ostream& os, const Path& path) { + for (Path::const_iterator i = path.begin(); i != path.end(); ++i) { + // no dot before list indexes and before first element + if ((i != path.begin()) && ((*i)[0] != '[')) { + os << '.'; + } + os << *i; + } + return os; } -ostream& operator << (ostream& os, const Exception& v) -{ - os << "REASON: " << v.why << endl; - os << " doc path: " << v.doc_path << endl; - os << " treespec path: " << v.gr_path << endl; - os << endl; - return os; +ostream& operator <<(ostream& os, const Exception& v) { + os << "REASON: " << v.why << endl; + os << " doc path: " << v.doc_path << endl; + os << " treespec path: " << v.gr_path << endl; + os << endl; + return os; } -ostream& operator << (ostream& os, const Errors& v) -{ - for (Errors::const_iterator i = v.begin(); i != v.end(); ++i) { - os << *i; - } - return os; +ostream& operator <<(ostream& os, const Errors& v) { + for (Errors::const_iterator i = v.begin(); i != v.end(); ++i) { + os << *i; + } + return os; } -const string& Validator::type2str(YAML::CONTENT_TYPE t) -{ - static string nonestr = "none"; - static string scalarstr = "scalar"; - static string liststr = "list"; - static string mapstr = "map"; - - assert( (t >= YAML::CT_NONE) && (t <= YAML::CT_MAP) ); - - switch (t) { - case YAML::CT_NONE: - return nonestr; - case YAML::CT_SCALAR: - return scalarstr; - case YAML::CT_SEQUENCE: - return liststr; - case YAML::CT_MAP: - return mapstr; - } - assert(0); - return nonestr; +const string& Validator::type2str(const YAML::Node &doc) { + static string nonestr = "none"; + static string scalarstr = "scalar"; + static string liststr = "list"; + static string mapstr = "map"; + + if (doc.IsNull()) { + return nonestr; + } else if (doc.IsScalar()) { + return scalarstr; + } else if (doc.IsSequence()) { + return liststr; + } else if (doc.IsMap()) { + return mapstr; + } else { + assert(0); + return nonestr; + } + assert(0); + return nonestr; } -int Validator::num_keys(const YAML::Node& doc) -{ - if (doc.GetType() != YAML::CT_MAP) { - return 0; - } - int num = 0; - for (YAML::Iterator i = doc.begin(); i != doc.end(); ++i) { - num++; - } - return num; +int Validator::num_keys(const YAML::Node& doc) { + if (!doc.IsMap()) { + return 0; + } + int num = 0; + for (YAML::const_iterator i = doc.begin(); i != doc.end(); ++i) { + num++; + } + return num; } -bool Validator::validate_map(const YAML::Node &mapNode, const YAML::Node &doc) -{ - if (doc.GetType() != YAML::CT_MAP) { - string reason = "expected map, but found " + type2str(doc.GetType()); - gen_error(Exception(reason, gr_path, doc_path)); - return false; - } - - bool ok = true; - for (YAML::Iterator i = mapNode.begin(); i != mapNode.end(); ++i) { - string key = i.first(); - const YAML::Node &valueNode = i.second(); - const YAML::Node *docMapNode = 0; - if (!(docMapNode = doc.FindValue(key))) { - string reason = "key: " + key + " not found."; - gen_error(Exception(reason, gr_path, doc_path)); - ok = false; - } else { - doc_path.push_back(key); - gr_path.push_back(key); - - ok = validate_doc(valueNode, *docMapNode) && ok; - - gr_path.pop_back(); - doc_path.pop_back(); - } - } - return ok; +bool Validator::validate_map(const YAML::Node &mapNode, const YAML::Node &doc) { + if (!doc.IsMap()) { + string reason = "expected map, but found " + type2str(doc); + gen_error(Exception(reason, gr_path, doc_path)); + return false; + } + + bool ok = true; + for (YAML::const_iterator i = mapNode.begin(); i != mapNode.end(); ++i) { + const YAML::Node& first = i->first; + string key = first.as(); + + const YAML::Node& attributeNode = i->second; // document node to validate in next recursion + const YAML::Node docMapNode = doc[key]; + + if (!docMapNode.IsDefined()) { + string reason = "key: " + key + " not found."; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } else { + doc_path.push_back(key); + gr_path.push_back(key); + + ok = validate_doc(attributeNode, docMapNode) && ok; + + doc_path.pop_back(); + gr_path.pop_back(); + } + } + return ok; } -bool Validator::validate_leaf(const YAML::Node &gr, const YAML::Node &doc) -{ - assert( gr.GetType() == YAML::CT_SEQUENCE ); - - const YAML::Node& typespec_map = gr[0]; - assert( num_keys(typespec_map) == 1); - - string type = typespec_map.begin().first(); - const YAML::Node& type_specifics = typespec_map.begin().second(); - - bool ok = true; - if (type == "string") { - attempt_to_convert(doc, ok); - } else if (type == "uint64") { - attempt_to_convert(doc, ok); - } else if (type == "int64") { - attempt_to_convert(doc, ok); - } else if (type == "int") { - attempt_to_convert(doc, ok); - } else if (type == "uint") { - attempt_to_convert(doc, ok); - } else if (type == "enum") { - ok = false; - string docValue = doc; - for (YAML::Iterator i = type_specifics.begin(); i != type_specifics.end(); ++i) { - if (*i == docValue) { - ok = true; - break; - } - } - if (!ok) { - string reason = "enum string '" + docValue + "' is not allowed."; - gen_error(Exception(reason, gr_path, doc_path)); - } - } - return ok; +bool Validator::validate_leaf(const YAML::Node &gr, const YAML::Node &doc) { + assert(gr.IsSequence()); + + const YAML::Node& typespec_map = gr[0]; + assert(num_keys(typespec_map) == 1); + + string type = typespec_map.begin()->first.as(); + const YAML::Node& type_specifics = typespec_map.begin()->second; + + bool ok = true; + if (type == "string") { + string string_leaf = doc.as(); + if (string_leaf.empty()) + ok = false; + } else { + try { + if (type == "uint64") { + doc.as(); + } else if (type == "int64") { + doc.as(); + } else if (type == "int") { + doc.as(); + } else if (type == "uint") { + doc.as(); + } + else if (type == "double") { + doc.as(); + } + } catch (YAML::TypedBadConversion &tbc_e) { + // do something with tbc_e + string reason = "Expected unsigned long long leaf attribute value: " + + tbc_e.msg; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } catch (YAML::TypedBadConversion &tbc_e) { + // do something with tbc_e + string reason = "Expected long long leaf attribute value: " + + tbc_e.msg; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } catch (YAML::TypedBadConversion &tbc_e) { + // do something with tbc_e + string reason = "Expected int leaf attribute value: " + tbc_e.msg; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } catch (YAML::TypedBadConversion &tbc_e) { + // do something with tbc_e + string reason = "Expected unsigned unsigned int leaf attribute value: " + + tbc_e.msg; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } catch (YAML::TypedBadConversion &tbc_e) { + // do something with tbc_e + string reason = "Expected unsigned double leaf attribute value: " + + tbc_e.msg; + gen_error(Exception(reason, gr_path, doc_path)); + ok = false; + } + } + if (type == "enum") { + ok = false; + string docValue = doc.as(); + for (YAML::const_iterator i = type_specifics.begin(); + i != type_specifics.end(); ++i) { + string enumvalue_leaf = i->as(); + if (enumvalue_leaf == docValue) { + ok = true; + break; + } + } + if (!ok) { + string reason = "enum string '" + docValue + "' is not allowed."; + gen_error(Exception(reason, gr_path, doc_path)); + } + } + return ok; } -bool Validator::validate_list(const YAML::Node &gr, const YAML::Node &doc) -{ - if (doc.GetType() != YAML::CT_SEQUENCE) { - string reason = "expected list, but found " + type2str(doc.GetType()); - gen_error(Exception(reason, gr_path, doc_path)); - return false; - } - - bool ok = true; - int n = 0; - char buf[128]; - - for (YAML::Iterator i = doc.begin(); i != doc.end(); ++i, ++n) { - snprintf(buf, sizeof(buf), "[%d]", n); - doc_path.push_back(buf); - ok = validate_doc(gr, *i) && ok; - doc_path.pop_back(); - } - return ok; +bool Validator::validate_list(const YAML::Node &gr, const YAML::Node &doc) { + if (!doc.IsSequence()) { + string reason = "expected list, but found " + type2str(doc); + gen_error(Exception(reason, gr_path, doc_path)); + return false; + } + + bool ok = true; + int n = 0; + char buf[128]; + + for (YAML::const_iterator i = doc.begin(); i != doc.end(); ++i, ++n) { + snprintf(buf, sizeof(buf), "[%d]", n); + doc_path.push_back(buf); + + ok = validate_doc(gr, *i) && ok; // next recursion step for validating a document node + doc_path.pop_back(); + } + return ok; } -bool Validator::validate_doc(const YAML::Node &gr, const YAML::Node &doc) -{ - bool ok = true; - const YAML::Node *mapNode = 0; - const YAML::Node *listNode = 0; - if ((mapNode = gr.FindValue("map"))) { - gr_path.push_back("map"); - ok = validate_map(*mapNode, doc) && ok; - gr_path.pop_back(); - } else if ((listNode = gr.FindValue("list"))) { - gr_path.push_back("list"); - ok = validate_list(*listNode, doc) && ok; - gr_path.pop_back(); - } else { - ok = validate_leaf(gr, doc) && ok; - } - return ok; +bool Validator::validate_doc(const YAML::Node &gr, const YAML::Node &doc) { + bool ok = true; + + const YAML::Node mapNode = gr["map"]; + const YAML::Node listNode = gr["list"]; + + if (mapNode.IsDefined()) { + gr_path.push_back("map"); + ok = validate_map(mapNode, doc) && ok; + gr_path.pop_back(); + } else if (listNode.IsDefined()) { + gr_path.push_back("list"); + ok = validate_list(listNode, doc) && ok; + gr_path.pop_back(); + } else { + ok = validate_leaf(gr, doc) && ok; + } + return ok; } diff --git a/src/yavl.h b/src/yavl.h deleted file mode 100644 index 6be6a23..0000000 --- a/src/yavl.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _YAVL_H_ -#define _YAVL_H_ - -#include "yaml.h" -#include -#include -#include - -namespace YAVL -{ - - typedef std::vector Path; - - // really sucks that I have to do this sort of crap since I can't - // pass a type as an argument to a function. - template - std::string ctype2str() - { - return "FAIL"; - } - - class Exception { - public: - std::string why; - Path gr_path; - Path doc_path; - Exception(const std::string _why, - const Path& _gr_path, - const Path& _doc_path) : - why(_why), gr_path(_gr_path), doc_path(_doc_path) {}; - }; - - typedef std::vector Errors; - - class Validator { - const YAML::Node& gr; - const YAML::Node& doc; - Path gr_path; - Path doc_path; - Errors errors; - - int num_keys(const YAML::Node& doc); - const std::string& type2str(YAML::CONTENT_TYPE t); - bool validate_map(const YAML::Node &mapNode, const YAML::Node &doc); - bool validate_leaf(const YAML::Node &gr, const YAML::Node &doc); - bool validate_list(const YAML::Node &gr, const YAML::Node &doc); - bool validate_doc(const YAML::Node &gr, const YAML::Node &doc); - - void gen_error(const Exception& err) { - errors.push_back(err); - } - - template - void attempt_to_convert(const YAML::Node& scalar_node, bool& ok) { - try { - T tmp; - scalar_node >> tmp; - ok = true; - } catch (const YAML::InvalidScalar& e) { - std::string s = scalar_node; - std::string reason = "unable to convert '" + s + "' to '" + YAVL::ctype2str() + "'."; - gen_error(Exception(reason, gr_path, doc_path)); - ok = false; - } - } - - public: - Validator(const YAML::Node& _gr, const YAML::Node& _doc) : - gr(_gr), doc(_doc) {}; - bool validate() { - return validate_doc(gr, doc); - } - const Errors& get_errors() { - return errors; - } - }; -} - -std::ostream& operator << (std::ostream& os, const YAVL::Path& path); -std::ostream& operator << (std::ostream& os, const YAVL::Exception& v); -std::ostream& operator << (std::ostream& os, const YAVL::Errors& v); - -#endif -