mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 07:14:45 +02:00
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ee8b58f82f | ||
![]() |
9132aa94b1 | ||
![]() |
76746b09fc | ||
![]() |
70b795bd45 | ||
![]() |
26842530f2 | ||
![]() |
e3f24286c1 | ||
![]() |
00b8ce81db | ||
![]() |
40810fe326 | ||
![]() |
59167d8627 | ||
![]() |
05c1b8344d | ||
![]() |
e893625e88 | ||
![]() |
e87e41cdb0 | ||
![]() |
9de2c2d84d | ||
![]() |
7956ccd61e | ||
![]() |
9454e687a3 | ||
![]() |
46a925ba4a | ||
![]() |
c407f1407f | ||
![]() |
ec251df6b7 | ||
![]() |
51c0afab22 | ||
![]() |
e39fb0083c | ||
![]() |
ec727e2f6b | ||
![]() |
4ce4bb8404 | ||
![]() |
2cd0f4ec21 | ||
![]() |
836f0fb863 | ||
![]() |
37644abd77 | ||
![]() |
66eb72f121 | ||
![]() |
94b0297dc5 | ||
![]() |
55db3c3cb2 | ||
![]() |
c07ef37904 | ||
![]() |
62ab94ddd3 | ||
![]() |
09d352ac13 | ||
![]() |
50753bb808 | ||
![]() |
8f3aa220db | ||
![]() |
73e127892e | ||
![]() |
4997dfb8af | ||
![]() |
c1441ef5e0 | ||
![]() |
e0bfb45000 | ||
![]() |
4bc311503c | ||
![]() |
cd140b5141 | ||
![]() |
01aee4a0dc | ||
![]() |
59a01652ab | ||
![]() |
8371a4337c | ||
![]() |
dc2e1c98b9 | ||
![]() |
d98b5f4230 | ||
![]() |
4ca9d25ccc |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,4 +10,4 @@
|
|||||||
/libs/
|
/libs/
|
||||||
/doc/doxyfile
|
/doc/doxyfile
|
||||||
/dist/
|
/dist/
|
||||||
/include/json/version.h
|
#/include/json/version.h
|
||||||
|
@@ -31,16 +31,6 @@ SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake
|
|||||||
CACHE PATH "Install dir for cmake package config files")
|
CACHE PATH "Install dir for cmake package config files")
|
||||||
MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PACKAGE_INSTALL_DIR )
|
MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PACKAGE_INSTALL_DIR )
|
||||||
|
|
||||||
# This ensures shared DLL are in the same dir as executable on Windows.
|
|
||||||
# Put all executables / libraries are in a project global directory.
|
|
||||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
|
||||||
CACHE PATH "Single directory for all static libraries.")
|
|
||||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
|
||||||
CACHE PATH "Single directory for all dynamic libraries on Unix.")
|
|
||||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
|
||||||
CACHE PATH "Single directory for all executable and dynamic libraries on Windows.")
|
|
||||||
MARK_AS_ADVANCED( CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY )
|
|
||||||
|
|
||||||
# Set variable named ${VAR_NAME} to value ${VALUE}
|
# Set variable named ${VAR_NAME} to value ${VALUE}
|
||||||
FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
|
FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
|
||||||
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
|
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
|
||||||
@@ -93,6 +83,14 @@ if ( MSVC )
|
|||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
|
||||||
endif( MSVC )
|
endif( MSVC )
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
# using regular Clang or AppleClang
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
# using GCC
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++0x")
|
||||||
|
endif()
|
||||||
|
|
||||||
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
IF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||||
UseCompilationWarningAsError()
|
UseCompilationWarningAsError()
|
||||||
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR)
|
ENDIF(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -16,26 +17,26 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#define JSON_ASSERT(condition) \
|
#define JSON_ASSERT(condition) \
|
||||||
assert(condition); // @todo <= change this into an exception throw
|
assert(condition); // @todo <= change this into an exception throw
|
||||||
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
|
#define JSON_FAIL_MESSAGE(message) do{std::ostringstream oss; oss << message; throw std::runtime_error(oss.str());}while(0)
|
||||||
|
//#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message)
|
||||||
#else // JSON_USE_EXCEPTION
|
#else // JSON_USE_EXCEPTION
|
||||||
#define JSON_ASSERT(condition) assert(condition);
|
#define JSON_ASSERT(condition) assert(condition);
|
||||||
|
|
||||||
// The call to assert() will show the failure message in debug builds. In
|
// The call to assert() will show the failure message in debug builds. In
|
||||||
// release bugs we write to invalid memory in order to crash hard, so that a
|
// release bugs we abort, for a core-dump or debugger.
|
||||||
// debugger or crash reporter gets the chance to take over. We still call exit()
|
|
||||||
// afterward in order to tell the compiler that this macro doesn't return.
|
|
||||||
#define JSON_FAIL_MESSAGE(message) \
|
#define JSON_FAIL_MESSAGE(message) \
|
||||||
{ \
|
{ \
|
||||||
assert(false&& message); \
|
std::ostringstream oss; oss << message; \
|
||||||
strcpy(reinterpret_cast<char*>(666), message); \
|
assert(false && oss.str().c_str()); \
|
||||||
exit(123); \
|
abort(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
JSON_FAIL_MESSAGE(message) \
|
JSON_FAIL_MESSAGE(message); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||||
|
@@ -187,7 +187,6 @@ private:
|
|||||||
|
|
||||||
typedef std::deque<ErrorInfo> Errors;
|
typedef std::deque<ErrorInfo> Errors;
|
||||||
|
|
||||||
bool expectToken(TokenType type, Token& token, const char* message);
|
|
||||||
bool readToken(Token& token);
|
bool readToken(Token& token);
|
||||||
void skipSpaces();
|
void skipSpaces();
|
||||||
bool match(Location pattern, int patternLength);
|
bool match(Location pattern, int patternLength);
|
||||||
|
@@ -235,25 +235,26 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
Value(const CppTL::ConstString& value);
|
Value(const CppTL::ConstString& value);
|
||||||
#endif
|
#endif
|
||||||
Value(bool value);
|
Value(bool value);
|
||||||
|
/// Deep copy.
|
||||||
Value(const Value& other);
|
Value(const Value& other);
|
||||||
~Value();
|
~Value();
|
||||||
|
|
||||||
|
// Deep copy, then swap(other).
|
||||||
Value& operator=(Value other);
|
Value& operator=(Value other);
|
||||||
/// Swap values.
|
/// Swap everything.
|
||||||
/// \note Currently, comments are intentionally not swapped, for
|
|
||||||
/// both logic and efficiency.
|
|
||||||
void swap(Value& other);
|
void swap(Value& other);
|
||||||
|
/// Swap values but leave comments and source offsets in place.
|
||||||
|
void swapPayload(Value& other);
|
||||||
|
|
||||||
ValueType type() const;
|
ValueType type() const;
|
||||||
|
|
||||||
|
/// Compare payload only, not comments etc.
|
||||||
bool operator<(const Value& other) const;
|
bool operator<(const Value& other) const;
|
||||||
bool operator<=(const Value& other) const;
|
bool operator<=(const Value& other) const;
|
||||||
bool operator>=(const Value& other) const;
|
bool operator>=(const Value& other) const;
|
||||||
bool operator>(const Value& other) const;
|
bool operator>(const Value& other) const;
|
||||||
|
|
||||||
bool operator==(const Value& other) const;
|
bool operator==(const Value& other) const;
|
||||||
bool operator!=(const Value& other) const;
|
bool operator!=(const Value& other) const;
|
||||||
|
|
||||||
int compare(const Value& other) const;
|
int compare(const Value& other) const;
|
||||||
|
|
||||||
const char* asCString() const;
|
const char* asCString() const;
|
||||||
@@ -391,9 +392,24 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
/// \return the removed Value, or null.
|
/// \return the removed Value, or null.
|
||||||
/// \pre type() is objectValue or nullValue
|
/// \pre type() is objectValue or nullValue
|
||||||
/// \post type() is unchanged
|
/// \post type() is unchanged
|
||||||
|
/// \deprecated
|
||||||
Value removeMember(const char* key);
|
Value removeMember(const char* key);
|
||||||
/// Same as removeMember(const char*)
|
/// Same as removeMember(const char*)
|
||||||
|
/// \deprecated
|
||||||
Value removeMember(const std::string& key);
|
Value removeMember(const std::string& key);
|
||||||
|
/** \brief Remove the named map member.
|
||||||
|
|
||||||
|
Update 'removed' iff removed.
|
||||||
|
\return true iff removed (no exceptions)
|
||||||
|
*/
|
||||||
|
bool removeMember(const char* key, Value* removed);
|
||||||
|
/** \brief Remove the indexed array element.
|
||||||
|
|
||||||
|
O(n) expensive operations.
|
||||||
|
Update 'removed' iff removed.
|
||||||
|
\return true iff removed (no exceptions)
|
||||||
|
*/
|
||||||
|
bool removeIndex(ArrayIndex i, Value* removed);
|
||||||
|
|
||||||
/// Return true if the object has a member named key.
|
/// Return true if the object has a member named key.
|
||||||
bool isMember(const char* key) const;
|
bool isMember(const char* key) const;
|
||||||
@@ -1081,6 +1097,14 @@ public:
|
|||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
/// Specialize std::swap() for Json::Value.
|
||||||
|
template<>
|
||||||
|
inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
@@ -4,9 +4,9 @@
|
|||||||
#ifndef JSON_VERSION_H_INCLUDED
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
# define JSON_VERSION_H_INCLUDED
|
# define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
# define JSONCPP_VERSION_STRING "1.1.0"
|
# define JSONCPP_VERSION_STRING "1.3.0"
|
||||||
# define JSONCPP_VERSION_MAJOR 1
|
# define JSONCPP_VERSION_MAJOR 1
|
||||||
# define JSONCPP_VERSION_MINOR 1
|
# define JSONCPP_VERSION_MINOR 3
|
||||||
# define JSONCPP_VERSION_PATCH 0
|
# define JSONCPP_VERSION_PATCH 0
|
||||||
# define JSONCPP_VERSION_QUALIFIER
|
# define JSONCPP_VERSION_QUALIFIER
|
||||||
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||||
|
@@ -47,23 +47,6 @@ Features Features::strictMode() {
|
|||||||
// Implementation of class Reader
|
// Implementation of class Reader
|
||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
static inline bool in(Reader::Char c,
|
|
||||||
Reader::Char c1,
|
|
||||||
Reader::Char c2,
|
|
||||||
Reader::Char c3,
|
|
||||||
Reader::Char c4) {
|
|
||||||
return c == c1 || c == c2 || c == c3 || c == c4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool in(Reader::Char c,
|
|
||||||
Reader::Char c1,
|
|
||||||
Reader::Char c2,
|
|
||||||
Reader::Char c3,
|
|
||||||
Reader::Char c4,
|
|
||||||
Reader::Char c5) {
|
|
||||||
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool containsNewLine(Reader::Location begin, Reader::Location end) {
|
static bool containsNewLine(Reader::Location begin, Reader::Location end) {
|
||||||
for (; begin < end; ++begin)
|
for (; begin < end; ++begin)
|
||||||
if (*begin == '\n' || *begin == '\r')
|
if (*begin == '\n' || *begin == '\r')
|
||||||
@@ -152,14 +135,9 @@ bool Reader::readValue() {
|
|||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
if (collectComments_ && !commentsBefore_.empty()) {
|
if (collectComments_ && !commentsBefore_.empty()) {
|
||||||
// Remove newline characters at the end of the comments
|
// Remove newline at the end of the comment
|
||||||
size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n");
|
if (commentsBefore_[commentsBefore_.size() - 1] == '\n')
|
||||||
if (lastNonNewline != std::string::npos) {
|
commentsBefore_.resize(commentsBefore_.size() - 1);
|
||||||
commentsBefore_.erase(lastNonNewline + 1);
|
|
||||||
} else {
|
|
||||||
commentsBefore_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
currentValue().setComment(commentsBefore_, commentBefore);
|
currentValue().setComment(commentsBefore_, commentBefore);
|
||||||
commentsBefore_ = "";
|
commentsBefore_ = "";
|
||||||
}
|
}
|
||||||
@@ -180,26 +158,36 @@ bool Reader::readValue() {
|
|||||||
successful = decodeString(token);
|
successful = decodeString(token);
|
||||||
break;
|
break;
|
||||||
case tokenTrue:
|
case tokenTrue:
|
||||||
currentValue() = true;
|
{
|
||||||
|
Value v(true);
|
||||||
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case tokenFalse:
|
case tokenFalse:
|
||||||
currentValue() = false;
|
{
|
||||||
|
Value v(false);
|
||||||
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case tokenNull:
|
case tokenNull:
|
||||||
currentValue() = Value();
|
{
|
||||||
|
Value v;
|
||||||
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case tokenArraySeparator:
|
case tokenArraySeparator:
|
||||||
if (features_.allowDroppedNullPlaceholders_) {
|
if (features_.allowDroppedNullPlaceholders_) {
|
||||||
// "Un-read" the current token and mark the current value as a null
|
// "Un-read" the current token and mark the current value as a null
|
||||||
// token.
|
// token.
|
||||||
current_--;
|
current_--;
|
||||||
currentValue() = Value();
|
Value v;
|
||||||
|
currentValue().swapPayload(v);
|
||||||
currentValue().setOffsetStart(current_ - begin_ - 1);
|
currentValue().setOffsetStart(current_ - begin_ - 1);
|
||||||
currentValue().setOffsetLimit(current_ - begin_);
|
currentValue().setOffsetLimit(current_ - begin_);
|
||||||
break;
|
break;
|
||||||
@@ -229,13 +217,6 @@ void Reader::skipCommentTokens(Token& token) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::expectToken(TokenType type, Token& token, const char* message) {
|
|
||||||
readToken(token);
|
|
||||||
if (token.type_ != type)
|
|
||||||
return addError(message, token);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reader::readToken(Token& token) {
|
bool Reader::readToken(Token& token) {
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
token.start_ = current_;
|
token.start_ = current_;
|
||||||
@@ -351,14 +332,34 @@ bool Reader::readComment() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
|
||||||
|
std::string normalized;
|
||||||
|
normalized.reserve(end - begin);
|
||||||
|
Reader::Location current = begin;
|
||||||
|
while (current != end) {
|
||||||
|
char c = *current++;
|
||||||
|
if (c == '\r') {
|
||||||
|
if (current != end && *current == '\n')
|
||||||
|
// convert dos EOL
|
||||||
|
++current;
|
||||||
|
// convert Mac EOL
|
||||||
|
normalized += '\n';
|
||||||
|
} else {
|
||||||
|
normalized += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Reader::addComment(Location begin, Location end, CommentPlacement placement) {
|
Reader::addComment(Location begin, Location end, CommentPlacement placement) {
|
||||||
assert(collectComments_);
|
assert(collectComments_);
|
||||||
|
const std::string& normalized = normalizeEOL(begin, end);
|
||||||
if (placement == commentAfterOnSameLine) {
|
if (placement == commentAfterOnSameLine) {
|
||||||
assert(lastValue_ != 0);
|
assert(lastValue_ != 0);
|
||||||
lastValue_->setComment(std::string(begin, end), placement);
|
lastValue_->setComment(normalized, placement);
|
||||||
} else {
|
} else {
|
||||||
commentsBefore_ += std::string(begin, end);
|
commentsBefore_ += normalized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,18 +375,38 @@ bool Reader::readCStyleComment() {
|
|||||||
bool Reader::readCppStyleComment() {
|
bool Reader::readCppStyleComment() {
|
||||||
while (current_ != end_) {
|
while (current_ != end_) {
|
||||||
Char c = getNextChar();
|
Char c = getNextChar();
|
||||||
if (c == '\r' || c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
if (c == '\r') {
|
||||||
|
// Consume DOS EOL. It will be normalized in addComment.
|
||||||
|
if (current_ != end_ && *current_ == '\n')
|
||||||
|
getNextChar();
|
||||||
|
// Break on Moc OS 9 EOL.
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reader::readNumber() {
|
void Reader::readNumber() {
|
||||||
while (current_ != end_) {
|
const char *p = current_;
|
||||||
if (!(*current_ >= '0' && *current_ <= '9') &&
|
char c = '0'; // stopgap for already consumed character
|
||||||
!in(*current_, '.', 'e', 'E', '+', '-'))
|
// integral part
|
||||||
break;
|
while (c >= '0' && c <= '9')
|
||||||
++current_;
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
|
// fractional part
|
||||||
|
if (c == '.') {
|
||||||
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
|
while (c >= '0' && c <= '9')
|
||||||
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
|
}
|
||||||
|
// exponential part
|
||||||
|
if (c == 'e' || c == 'E') {
|
||||||
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
|
if (c == '+' || c == '-')
|
||||||
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
|
while (c >= '0' && c <= '9')
|
||||||
|
c = (current_ = p) < end_ ? *p++ : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +425,8 @@ bool Reader::readString() {
|
|||||||
bool Reader::readObject(Token& tokenStart) {
|
bool Reader::readObject(Token& tokenStart) {
|
||||||
Token tokenName;
|
Token tokenName;
|
||||||
std::string name;
|
std::string name;
|
||||||
currentValue() = Value(objectValue);
|
Value init(objectValue);
|
||||||
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||||
while (readToken(tokenName)) {
|
while (readToken(tokenName)) {
|
||||||
bool initialTokenOk = true;
|
bool initialTokenOk = true;
|
||||||
@@ -457,7 +479,8 @@ bool Reader::readObject(Token& tokenStart) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::readArray(Token& tokenStart) {
|
bool Reader::readArray(Token& tokenStart) {
|
||||||
currentValue() = Value(arrayValue);
|
Value init(arrayValue);
|
||||||
|
currentValue().swapPayload(init);
|
||||||
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
if (*current_ == ']') // empty array
|
if (*current_ == ']') // empty array
|
||||||
@@ -497,20 +520,13 @@ bool Reader::decodeNumber(Token& token) {
|
|||||||
Value decoded;
|
Value decoded;
|
||||||
if (!decodeNumber(token, decoded))
|
if (!decodeNumber(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::decodeNumber(Token& token, Value& decoded) {
|
bool Reader::decodeNumber(Token& token, Value& decoded) {
|
||||||
bool isDouble = false;
|
|
||||||
for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
|
|
||||||
isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') ||
|
|
||||||
(*inspect == '-' && inspect != token.start_);
|
|
||||||
}
|
|
||||||
if (isDouble)
|
|
||||||
return decodeDouble(token, decoded);
|
|
||||||
// Attempts to parse the number as an integer. If the number is
|
// Attempts to parse the number as an integer. If the number is
|
||||||
// larger than the maximum supported value of an integer then
|
// larger than the maximum supported value of an integer then
|
||||||
// we decode the number as a double.
|
// we decode the number as a double.
|
||||||
@@ -518,6 +534,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
|
|||||||
bool isNegative = *current == '-';
|
bool isNegative = *current == '-';
|
||||||
if (isNegative)
|
if (isNegative)
|
||||||
++current;
|
++current;
|
||||||
|
// TODO: Help the compiler do the div and mod at compile time or get rid of them.
|
||||||
Value::LargestUInt maxIntegerValue =
|
Value::LargestUInt maxIntegerValue =
|
||||||
isNegative ? Value::LargestUInt(-Value::minLargestInt)
|
isNegative ? Value::LargestUInt(-Value::minLargestInt)
|
||||||
: Value::maxLargestUInt;
|
: Value::maxLargestUInt;
|
||||||
@@ -526,9 +543,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
|
|||||||
while (current < token.end_) {
|
while (current < token.end_) {
|
||||||
Char c = *current++;
|
Char c = *current++;
|
||||||
if (c < '0' || c > '9')
|
if (c < '0' || c > '9')
|
||||||
return addError("'" + std::string(token.start_, token.end_) +
|
return decodeDouble(token, decoded);
|
||||||
"' is not a number.",
|
|
||||||
token);
|
|
||||||
Value::UInt digit(c - '0');
|
Value::UInt digit(c - '0');
|
||||||
if (value >= threshold) {
|
if (value >= threshold) {
|
||||||
// We've hit or exceeded the max value divided by 10 (rounded down). If
|
// We've hit or exceeded the max value divided by 10 (rounded down). If
|
||||||
@@ -555,7 +570,7 @@ bool Reader::decodeDouble(Token& token) {
|
|||||||
Value decoded;
|
Value decoded;
|
||||||
if (!decodeDouble(token, decoded))
|
if (!decodeDouble(token, decoded))
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
@@ -598,10 +613,11 @@ bool Reader::decodeDouble(Token& token, Value& decoded) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::decodeString(Token& token) {
|
bool Reader::decodeString(Token& token) {
|
||||||
std::string decoded;
|
std::string decoded_string;
|
||||||
if (!decodeString(token, decoded))
|
if (!decodeString(token, decoded_string))
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
Value decoded(decoded_string);
|
||||||
|
currentValue().swapPayload(decoded);
|
||||||
currentValue().setOffsetStart(token.start_ - begin_);
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
currentValue().setOffsetLimit(token.end_ - begin_);
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
|
@@ -340,7 +340,7 @@ Value::Value(const Value& other)
|
|||||||
case stringValue:
|
case stringValue:
|
||||||
if (other.value_.string_) {
|
if (other.value_.string_) {
|
||||||
value_.string_ = duplicateStringValue(other.value_.string_);
|
value_.string_ = duplicateStringValue(other.value_.string_);
|
||||||
allocated_ = true;
|
allocated_ |= true;
|
||||||
} else {
|
} else {
|
||||||
value_.string_ = 0;
|
value_.string_ = 0;
|
||||||
allocated_ = false;
|
allocated_ = false;
|
||||||
@@ -410,7 +410,7 @@ Value& Value::operator=(Value other) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::swap(Value& other) {
|
void Value::swapPayload(Value& other) {
|
||||||
ValueType temp = type_;
|
ValueType temp = type_;
|
||||||
type_ = other.type_;
|
type_ = other.type_;
|
||||||
other.type_ = temp;
|
other.type_ = temp;
|
||||||
@@ -418,6 +418,11 @@ void Value::swap(Value& other) {
|
|||||||
int temp2 = allocated_;
|
int temp2 = allocated_;
|
||||||
allocated_ = other.allocated_;
|
allocated_ = other.allocated_;
|
||||||
other.allocated_ = temp2;
|
other.allocated_ = temp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::swap(Value& other) {
|
||||||
|
swapPayload(other);
|
||||||
|
std::swap(comments_, other.comments_);
|
||||||
std::swap(start_, other.start_);
|
std::swap(start_, other.start_);
|
||||||
std::swap(limit_, other.limit_);
|
std::swap(limit_, other.limit_);
|
||||||
}
|
}
|
||||||
@@ -984,35 +989,74 @@ Value Value::get(const std::string& key, const Value& defaultValue) const {
|
|||||||
return get(key.c_str(), defaultValue);
|
return get(key.c_str(), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Value::removeMember(const char* key, Value* removed) {
|
||||||
|
if (type_ != objectValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
|
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||||
|
if (it == value_.map_->end())
|
||||||
|
return false;
|
||||||
|
*removed = it->second;
|
||||||
|
value_.map_->erase(it);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
Value* value = value_.map_->find(key);
|
||||||
|
if (value) {
|
||||||
|
*removed = *value;
|
||||||
|
value_.map_.remove(key);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Value Value::removeMember(const char* key) {
|
Value Value::removeMember(const char* key) {
|
||||||
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
|
||||||
"in Json::Value::removeMember(): requires objectValue");
|
"in Json::Value::removeMember(): requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return null;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString actualKey(key, CZString::noDuplication);
|
Value removed; // null
|
||||||
ObjectValues::iterator it = value_.map_->find(actualKey);
|
removeMember(key, &removed);
|
||||||
if (it == value_.map_->end())
|
return removed; // still null if removeMember() did nothing
|
||||||
return null;
|
|
||||||
Value old(it->second);
|
|
||||||
value_.map_->erase(it);
|
|
||||||
return old;
|
|
||||||
#else
|
|
||||||
Value* value = value_.map_->find(key);
|
|
||||||
if (value) {
|
|
||||||
Value old(*value);
|
|
||||||
value_.map_.remove(key);
|
|
||||||
return old;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::removeMember(const std::string& key) {
|
Value Value::removeMember(const std::string& key) {
|
||||||
return removeMember(key.c_str());
|
return removeMember(key.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
||||||
|
if (type_ != arrayValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
JSON_FAIL_MESSAGE("removeIndex is not implemented for ValueInternalArray.");
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
CZString key(index);
|
||||||
|
ObjectValues::iterator it = value_.map_->find(key);
|
||||||
|
if (it == value_.map_->end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*removed = it->second;
|
||||||
|
ArrayIndex oldSize = size();
|
||||||
|
// shift left all items left, into the place of the "removed"
|
||||||
|
for (ArrayIndex i = index; i < (oldSize - 1); ++i){
|
||||||
|
CZString key(i);
|
||||||
|
(*value_.map_)[key] = (*this)[i + 1];
|
||||||
|
}
|
||||||
|
// erase the last one ("leftover")
|
||||||
|
CZString keyLast(oldSize - 1);
|
||||||
|
ObjectValues::iterator itLast = value_.map_->find(keyLast);
|
||||||
|
value_.map_->erase(itLast);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value Value::get(const CppTL::ConstString& key,
|
Value Value::get(const CppTL::ConstString& key,
|
||||||
const Value& defaultValue) const {
|
const Value& defaultValue) const {
|
||||||
|
@@ -421,26 +421,27 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) {
|
|||||||
|
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
writeIndent();
|
writeIndent();
|
||||||
std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
|
const std::string& comment = root.getComment(commentBefore);
|
||||||
std::string::const_iterator iter = normalizedComment.begin();
|
std::string::const_iterator iter = comment.begin();
|
||||||
while (iter != normalizedComment.end()) {
|
while (iter != comment.end()) {
|
||||||
document_ += *iter;
|
document_ += *iter;
|
||||||
if (*iter == '\n' && *(iter + 1) == '/')
|
if (*iter == '\n' &&
|
||||||
|
(iter != comment.end() && *(iter + 1) == '/'))
|
||||||
writeIndent();
|
writeIndent();
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comments are stripped of newlines, so add one here
|
// Comments are stripped of trailing newlines, so add one here
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
||||||
if (root.hasComment(commentAfterOnSameLine))
|
if (root.hasComment(commentAfterOnSameLine))
|
||||||
document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
document_ += " " + root.getComment(commentAfterOnSameLine);
|
||||||
|
|
||||||
if (root.hasComment(commentAfter)) {
|
if (root.hasComment(commentAfter)) {
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
document_ += normalizeEOL(root.getComment(commentAfter));
|
document_ += root.getComment(commentAfter);
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,25 +452,6 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
|
|||||||
value.hasComment(commentAfter);
|
value.hasComment(commentAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StyledWriter::normalizeEOL(const std::string& text) {
|
|
||||||
std::string normalized;
|
|
||||||
normalized.reserve(text.length());
|
|
||||||
const char* begin = text.c_str();
|
|
||||||
const char* end = begin + text.length();
|
|
||||||
const char* current = begin;
|
|
||||||
while (current != end) {
|
|
||||||
char c = *current++;
|
|
||||||
if (c == '\r') // mac or dos EOL
|
|
||||||
{
|
|
||||||
if (*current == '\n') // convert dos EOL
|
|
||||||
++current;
|
|
||||||
normalized += '\n';
|
|
||||||
} else // handle unix EOL & other char
|
|
||||||
normalized += c;
|
|
||||||
}
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class StyledStreamWriter
|
// Class StyledStreamWriter
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -646,17 +628,17 @@ void StyledStreamWriter::unindent() {
|
|||||||
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
|
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
|
||||||
if (!root.hasComment(commentBefore))
|
if (!root.hasComment(commentBefore))
|
||||||
return;
|
return;
|
||||||
*document_ << normalizeEOL(root.getComment(commentBefore));
|
*document_ << root.getComment(commentBefore);
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
||||||
if (root.hasComment(commentAfterOnSameLine))
|
if (root.hasComment(commentAfterOnSameLine))
|
||||||
*document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
*document_ << " " + root.getComment(commentAfterOnSameLine);
|
||||||
|
|
||||||
if (root.hasComment(commentAfter)) {
|
if (root.hasComment(commentAfter)) {
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
*document_ << normalizeEOL(root.getComment(commentAfter));
|
*document_ << root.getComment(commentAfter);
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -667,25 +649,6 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) {
|
|||||||
value.hasComment(commentAfter);
|
value.hasComment(commentAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
|
|
||||||
std::string normalized;
|
|
||||||
normalized.reserve(text.length());
|
|
||||||
const char* begin = text.c_str();
|
|
||||||
const char* end = begin + text.length();
|
|
||||||
const char* current = begin;
|
|
||||||
while (current != end) {
|
|
||||||
char c = *current++;
|
|
||||||
if (c == '\r') // mac or dos EOL
|
|
||||||
{
|
|
||||||
if (*current == '\n') // convert dos EOL
|
|
||||||
++current;
|
|
||||||
normalized += '\n';
|
|
||||||
} else // handle unix EOL & other char
|
|
||||||
normalized += c;
|
|
||||||
}
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& sout, const Value& root) {
|
std::ostream& operator<<(std::ostream& sout, const Value& root) {
|
||||||
Json::StyledStreamWriter writer;
|
Json::StyledStreamWriter writer;
|
||||||
writer.write(sout, root);
|
writer.write(sout, root);
|
||||||
|
@@ -17,8 +17,8 @@
|
|||||||
#define kint64min Json::Value::minInt64
|
#define kint64min Json::Value::minInt64
|
||||||
#define kuint64max Json::Value::maxUInt64
|
#define kuint64max Json::Value::maxUInt64
|
||||||
|
|
||||||
static const double kdint64max = double(kint64max);
|
//static const double kdint64max = double(kint64max);
|
||||||
static const float kfint64max = float(kint64max);
|
//static const float kfint64max = float(kint64max);
|
||||||
static const float kfint32max = float(kint32max);
|
static const float kfint32max = float(kint32max);
|
||||||
static const float kfuint32max = float(kuint32max);
|
static const float kfuint32max = float(kuint32max);
|
||||||
|
|
||||||
@@ -198,6 +198,18 @@ JSONTEST_FIXTURE(ValueTest, objects) {
|
|||||||
|
|
||||||
object1_["some other id"] = "foo";
|
object1_["some other id"] = "foo";
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
|
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
|
||||||
|
|
||||||
|
// Remove.
|
||||||
|
Json::Value got;
|
||||||
|
bool did;
|
||||||
|
did = object1_.removeMember("some other id", &got);
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), got);
|
||||||
|
JSONTEST_ASSERT_EQUAL(true, did);
|
||||||
|
got = Json::Value("bar");
|
||||||
|
did = object1_.removeMember("some other id", &got);
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value("bar"), got);
|
||||||
|
JSONTEST_ASSERT_EQUAL(false, did);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, arrays) {
|
JSONTEST_FIXTURE(ValueTest, arrays) {
|
||||||
@@ -240,6 +252,10 @@ JSONTEST_FIXTURE(ValueTest, arrays) {
|
|||||||
array1_[2] = Json::Value(17);
|
array1_[2] = Json::Value(17);
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]);
|
JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]);
|
||||||
JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]);
|
JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]);
|
||||||
|
Json::Value got;
|
||||||
|
JSONTEST_ASSERT_EQUAL(true, array1_.removeIndex(2, &got));
|
||||||
|
JSONTEST_ASSERT_EQUAL(Json::Value(17), got);
|
||||||
|
JSONTEST_ASSERT_EQUAL(false, array1_.removeIndex(2, &got)); // gone now
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ValueTest, null) {
|
JSONTEST_FIXTURE(ValueTest, null) {
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
.={}
|
.={}
|
||||||
|
// Comment for array
|
||||||
.test=[]
|
.test=[]
|
||||||
|
// Comment within array
|
||||||
.test[0]={}
|
.test[0]={}
|
||||||
.test[0].a="aaa"
|
.test[0].a="aaa"
|
||||||
.test[1]={}
|
.test[1]={}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"test":
|
"test":
|
||||||
|
// Comment for array
|
||||||
[
|
[
|
||||||
|
// Comment within array
|
||||||
{ "a" : "aaa" }, // Comment for a
|
{ "a" : "aaa" }, // Comment for a
|
||||||
{ "b" : "bbb" }, // Comment for b
|
{ "b" : "bbb" }, // Comment for b
|
||||||
{ "c" : "ccc" } // Comment for c
|
{ "c" : "ccc" } // Comment for c
|
||||||
|
@@ -11,4 +11,13 @@
|
|||||||
// Multiline comment cpp-style
|
// Multiline comment cpp-style
|
||||||
// Second line
|
// Second line
|
||||||
.cpp-test.c=3
|
.cpp-test.c=3
|
||||||
.cpp-test.d=4
|
// Comment before double
|
||||||
|
.cpp-test.d=4.1
|
||||||
|
// Comment before string
|
||||||
|
.cpp-test.e="e-string"
|
||||||
|
// Comment before true
|
||||||
|
.cpp-test.f=true
|
||||||
|
// Comment before false
|
||||||
|
.cpp-test.g=false
|
||||||
|
// Comment before null
|
||||||
|
.cpp-test.h=null
|
||||||
|
@@ -12,6 +12,15 @@
|
|||||||
// Multiline comment cpp-style
|
// Multiline comment cpp-style
|
||||||
// Second line
|
// Second line
|
||||||
"c" : 3,
|
"c" : 3,
|
||||||
"d" : 4
|
// Comment before double
|
||||||
|
"d" : 4.1,
|
||||||
|
// Comment before string
|
||||||
|
"e" : "e-string",
|
||||||
|
// Comment before true
|
||||||
|
"f" : true,
|
||||||
|
// Comment before false
|
||||||
|
"g" : false,
|
||||||
|
// Comment before null
|
||||||
|
"h" : null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,30 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from io import open
|
||||||
from glob import glob
|
from glob import glob
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import pipes
|
import os.path
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes '
|
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes '
|
||||||
|
|
||||||
|
def getStatusOutput(cmd):
|
||||||
|
"""
|
||||||
|
Return int, unicode (for both Python 2 and 3).
|
||||||
|
Note: os.popen().close() would return None for 0.
|
||||||
|
"""
|
||||||
|
pipe = os.popen(cmd)
|
||||||
|
process_output = pipe.read()
|
||||||
|
try:
|
||||||
|
# We have been using os.popen(). When we read() the result
|
||||||
|
# we get 'str' (bytes) in py2, and 'str' (unicode) in py3.
|
||||||
|
# Ugh! There must be a better way to handle this.
|
||||||
|
process_output = process_output.decode('utf-8')
|
||||||
|
except AttributeError:
|
||||||
|
pass # python3
|
||||||
|
status = pipe.close()
|
||||||
|
return status, process_output
|
||||||
def compareOutputs( expected, actual, message ):
|
def compareOutputs( expected, actual, message ):
|
||||||
expected = expected.strip().replace('\r','').split('\n')
|
expected = expected.strip().replace('\r','').split('\n')
|
||||||
actual = actual.strip().replace('\r','').split('\n')
|
actual = actual.strip().replace('\r','').split('\n')
|
||||||
@@ -34,7 +52,7 @@ def compareOutputs( expected, actual, message ):
|
|||||||
|
|
||||||
def safeReadFile( path ):
|
def safeReadFile( path ):
|
||||||
try:
|
try:
|
||||||
return file( path, 'rt' ).read()
|
return open( path, 'rt', encoding = 'utf-8' ).read()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
return '<File "%s" is missing: %s>' % (path,e)
|
return '<File "%s" is missing: %s>' % (path,e)
|
||||||
|
|
||||||
@@ -54,21 +72,20 @@ def runAllTests( jsontest_executable_path, input_dir = None,
|
|||||||
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
||||||
print('TESTING:', input_path, end=' ')
|
print('TESTING:', input_path, end=' ')
|
||||||
options = is_json_checker_test and '--json-checker' or ''
|
options = is_json_checker_test and '--json-checker' or ''
|
||||||
pipe = os.popen( "%s%s %s %s" % (
|
cmd = '%s%s %s "%s"' % (
|
||||||
valgrind_path, jsontest_executable_path, options,
|
valgrind_path, jsontest_executable_path, options,
|
||||||
pipes.quote(input_path)))
|
input_path)
|
||||||
process_output = pipe.read()
|
status, process_output = getStatusOutput(cmd)
|
||||||
status = pipe.close()
|
|
||||||
if is_json_checker_test:
|
if is_json_checker_test:
|
||||||
if expect_failure:
|
if expect_failure:
|
||||||
if status is None:
|
if not status:
|
||||||
print('FAILED')
|
print('FAILED')
|
||||||
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
|
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
|
||||||
safeReadFile(input_path)) )
|
safeReadFile(input_path)) )
|
||||||
else:
|
else:
|
||||||
print('OK')
|
print('OK')
|
||||||
else:
|
else:
|
||||||
if status is not None:
|
if status:
|
||||||
print('FAILED')
|
print('FAILED')
|
||||||
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
||||||
else:
|
else:
|
||||||
@@ -77,13 +94,13 @@ def runAllTests( jsontest_executable_path, input_dir = None,
|
|||||||
base_path = os.path.splitext(input_path)[0]
|
base_path = os.path.splitext(input_path)[0]
|
||||||
actual_output = safeReadFile( base_path + '.actual' )
|
actual_output = safeReadFile( base_path + '.actual' )
|
||||||
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
|
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
|
||||||
file(base_path + '.process-output','wt').write( process_output )
|
open(base_path + '.process-output', 'wt', encoding = 'utf-8').write( process_output )
|
||||||
if status:
|
if status:
|
||||||
print('parsing failed')
|
print('parsing failed')
|
||||||
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
|
||||||
else:
|
else:
|
||||||
expected_output_path = os.path.splitext(input_path)[0] + '.expected'
|
expected_output_path = os.path.splitext(input_path)[0] + '.expected'
|
||||||
expected_output = file( expected_output_path, 'rt' ).read()
|
expected_output = open( expected_output_path, 'rt', encoding = 'utf-8' ).read()
|
||||||
detail = ( compareOutputs( expected_output, actual_output, 'input' )
|
detail = ( compareOutputs( expected_output, actual_output, 'input' )
|
||||||
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
|
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
|
||||||
if detail:
|
if detail:
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from io import open
|
||||||
from glob import glob
|
from glob import glob
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@@ -19,7 +21,11 @@ class TestProxy(object):
|
|||||||
else:
|
else:
|
||||||
cmd = []
|
cmd = []
|
||||||
cmd.extend( [self.test_exe_path, '--test-auto'] + options )
|
cmd.extend( [self.test_exe_path, '--test-auto'] + options )
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
try:
|
||||||
|
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
||||||
|
except:
|
||||||
|
print(cmd)
|
||||||
|
raise
|
||||||
stdout = process.communicate()[0]
|
stdout = process.communicate()[0]
|
||||||
if process.returncode:
|
if process.returncode:
|
||||||
return False, stdout
|
return False, stdout
|
||||||
@@ -31,7 +37,7 @@ def runAllTests( exe_path, use_valgrind=False ):
|
|||||||
if not status:
|
if not status:
|
||||||
print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
|
print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
test_names = [name.strip() for name in test_names.strip().split('\n')]
|
test_names = [name.strip() for name in test_names.decode('utf-8').strip().split('\n')]
|
||||||
failures = []
|
failures = []
|
||||||
for name in test_names:
|
for name in test_names:
|
||||||
print('TESTING %s:' % name, end=' ')
|
print('TESTING %s:' % name, end=' ')
|
||||||
|
Reference in New Issue
Block a user