diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index db33af1d..0fa68e78 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,11 +10,13 @@ GroupSources(example "/") add_executable (pretty + file.hpp pretty.cpp ) set_property(TARGET pretty PROPERTY FOLDER "example") add_executable (allocator + file.hpp allocator.cpp ) set_property(TARGET allocator PROPERTY FOLDER "example") diff --git a/example/file.hpp b/example/file.hpp new file mode 100644 index 00000000..a28540a6 --- /dev/null +++ b/example/file.hpp @@ -0,0 +1,111 @@ +// +// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/vinniefalco/json +// + +#ifndef BOOST_JSON_EXAMPLE_FILE_HPP +#define BOOST_JSON_EXAMPLE_FILE_HPP + +#include +#include + +class file +{ + FILE* f_ = nullptr; + +public: + ~file() + { + if(f_) + std::fclose(f_); + } + + file() = default; + + file( file&& other ) noexcept + : f_(other.f_) + { + other.f_ = nullptr; + } + + file( char const* path, char const* mode ) + { + open( path, mode ); + } + + file& + operator=(file&& other) noexcept + { + close(); + f_ = other.f_; + other.f_ = nullptr; + return *this; + } + + void + close() + { + if(f_) + { + std::fclose(f_); + f_ = nullptr; + } + } + + void + open( + char const* path, + char const* mode, + boost::json::error_code& ec) + { + close(); + f_ = std::fopen( path, mode ); + if( ! f_ ) + { + ec.assign( errno, boost::json::generic_category() ); + return; + } + } + + void + open( + char const* path, + char const* mode) + { + boost::json::error_code ec; + open(path, mode, ec); + if(ec) + throw boost::json::system_error(ec); + } + + bool + eof() const noexcept + { + return std::feof( f_ ) != 0; + } + + std::size_t + read( char* data, std::size_t size, boost::json::error_code& ec) + { + auto const nread = std::fread( data, 1, size, f_ ); + if( std::ferror(f_) ) + ec.assign( errno, boost::json::generic_category() ); + return nread; + } + + std::size_t + read( char* data, std::size_t size ) + { + boost::json::error_code ec; + auto const nread = read( data, size, ec ); + if(ec) + throw boost::json::system_error(ec); + return nread; + } +}; + +#endif diff --git a/example/pretty.cpp b/example/pretty.cpp index b2fb345d..3d13b53c 100644 --- a/example/pretty.cpp +++ b/example/pretty.cpp @@ -13,96 +13,115 @@ */ #include -#include +#include #include +#include "file.hpp" namespace json = boost::json; -class file -{ - FILE* f_ = nullptr; - -public: - ~file() - { - if(f_) - std::fclose(f_); - } - - file() = default; - - void - close() - { - if(f_) - { - std::fclose(f_); - f_ = nullptr; - } - } - - void - open( - char const* path, - char const* mode, - json::error_code& ec) - { - close(); - f_ = std::fopen( path, mode ); - if( ! f_ ) - { - ec.assign( errno, json::generic_category() ); - return; - } - } -}; - json::value parse_file( char const* filename ) { - json::error_code ec; - auto f = std::fopen( filename, "r" ); - if( ! f ) - { - ec.assign( errno, json::generic_category() ); - throw json::system_error(ec); - } + file f( filename, "r" ); json::parser p; p.start(); do { char buf[4096]; - - // Read from the file into our buffer. - auto const nread = fread( buf, 1, sizeof(buf), f ); - if( std::ferror(f) ) - { - ec.assign( errno, json::generic_category() ); - throw json::system_error(ec); - } - - auto nparsed = p.write_some( buf, nread, ec); - - // Make sure we use all the characters in the file. - if( ! ec && nparsed < nread ) - nparsed = p.write_some( buf + nparsed, sizeof(buf) - nparsed, ec ); - - if( ec ) - throw json::system_error(ec); + auto const nread = f.read( buf, sizeof(buf) ); + p.write( buf, nread ); } - while( ! std::feof(f) ); - - // Tell the parser there is no more serialized JSON. - p.finish(ec); - if( ec ) - throw json::system_error(ec); - + while( ! f.eof() ); + p.finish(); return p.release(); } void -pretty_print( std::ostream& os, json::value const& jv ) +pretty_print( std::ostream& os, json::value const& jv, std::string* indent = nullptr ) { + std::string indent_; + if(! indent) + indent = &indent_; + switch(jv.kind()) + { + case json::kind::object: + { + os << "{\n"; + indent->append(4, ' '); + auto const& obj = jv.get_object(); + if(! obj.empty()) + { + auto it = obj.begin(); + goto loop_obj; + while( ++it != obj.end() ) + { + os << ",\n"; + loop_obj: + os << *indent << json::to_string(it->key()) << " : "; + pretty_print( os, it->value(), indent); + } + } + os << "\n"; + indent->resize(indent->size() - 4); + os << *indent << "}"; + break; + } + + case json::kind::array: + { + os << "[\n"; + indent->append(4, ' '); + auto const& arr = jv.get_array(); + if(! arr.empty()) + { + auto it = arr.begin(); + goto loop_arr; + while( ++it != arr.end() ) + { + os << ",\n"; + loop_arr: + os << *indent; + pretty_print( os, *it, indent); + } + } + os << "\n"; + indent->resize(indent->size() - 4); + os << *indent << "]"; + break; + } + + case json::kind::string: + { + os << json::to_string(jv.get_string()); + break; + } + + case json::kind::uint64: + os << jv.get_uint64(); + break; + + case json::kind::int64: + os << jv.get_int64(); + break; + + case json::kind::double_: + os << jv.get_double(); + break; + + case json::kind::bool_: + if(jv.get_bool()) + os << "true"; + else + os << "false"; + break; + + case json::kind::null: + os << "null"; + break; + } + + if(indent->empty()) + os << "\n"; } int diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index a2ae8e85..7fcff9b8 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -63,7 +63,7 @@ enum class basic_parser::state : char esc1, esc2, esc3, esc4, sur1, sur2, sur3, num, - lit, + litt, litf, litn }; //---------------------------------------------------------- @@ -244,7 +244,7 @@ loop_val: ++p; lit_ = "rue"; ev_ = error::expected_true; - *st_ = state::lit; + *st_ = state::litt; goto loop; // false @@ -269,7 +269,7 @@ loop_val: ++p; lit_ = "alse"; ev_ = error::expected_false; - *st_ = state::lit; + *st_ = state::litf; goto loop; // null @@ -293,7 +293,7 @@ loop_val: ++p; lit_ = "ull"; ev_ = error::expected_null; - *st_ = state::lit; + *st_ = state::litn; goto loop; default: @@ -829,7 +829,9 @@ loop_num: // string literal (true, false, null) - case state::lit: + case state::litt: + case state::litf: + case state::litn: BOOST_JSON_ASSERT(lit_ != nullptr); while(p < p1) { @@ -841,6 +843,14 @@ loop_num: ++p; if(*++lit_ == 0) { + if(*st_ == state::litt) + this->on_bool(true, ec); + else if(*st_ == state::litf) + this->on_bool(false, ec); + else + this->on_null(ec); + if(ec) + goto yield; st_.pop(); goto loop; } @@ -980,7 +990,9 @@ finish(error_code& ec) break; } - case state::lit: + case state::litt: + case state::litf: + case state::litn: ec = ev_; return;