mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 15:16:47 +02:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
15949af098 | ||
![]() |
8dc52b3cca | ||
![]() |
add941c1a9 |
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
|
||||||
|
@@ -7,11 +7,12 @@ language: cpp
|
|||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
script: cmake -DJSONCPP_WITH_CMAKE_PACKAGE=$CMAKE_PKG -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIB -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
|
script: cmake -DJSONCPP_LIB_BUILD_SHARED=$SHARED_LIBRARY -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE=$VERBOSE_MAKE . && make
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
- SHARED_LIBRARY=ON BUILD_TYPE=release VERBOSE_MAKE=false
|
||||||
- SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
|
- SHARED_LIBRARY=OFF BUILD_TYPE=release VERBOSE_MAKE=false
|
||||||
|
- SHARED_LIBRARY=OFF BUILD_TYPE=debug VERBOSE VERBOSE_MAKE=true
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
- aaronjjacobs@gmail.com
|
- aaronjjacobs@gmail.com
|
||||||
|
@@ -17,20 +17,28 @@ IF(NOT WIN32)
|
|||||||
ENDIF(NOT CMAKE_BUILD_TYPE)
|
ENDIF(NOT CMAKE_BUILD_TYPE)
|
||||||
ENDIF(NOT WIN32)
|
ENDIF(NOT WIN32)
|
||||||
|
|
||||||
SET(LIB_SUFFIX "" CACHE STRING "Optional arch-dependent suffix for the library installation directory")
|
|
||||||
|
|
||||||
SET(RUNTIME_INSTALL_DIR bin
|
SET(RUNTIME_INSTALL_DIR bin
|
||||||
CACHE PATH "Install dir for executables and dlls")
|
CACHE PATH "Install dir for executables and dlls")
|
||||||
SET(ARCHIVE_INSTALL_DIR lib${LIB_SUFFIX}
|
SET(ARCHIVE_INSTALL_DIR lib
|
||||||
CACHE PATH "Install dir for static libraries")
|
CACHE PATH "Install dir for static libraries")
|
||||||
SET(LIBRARY_INSTALL_DIR lib${LIB_SUFFIX}
|
SET(LIBRARY_INSTALL_DIR lib
|
||||||
CACHE PATH "Install dir for shared libraries")
|
CACHE PATH "Install dir for shared libraries")
|
||||||
SET(INCLUDE_INSTALL_DIR include
|
SET(INCLUDE_INSTALL_DIR include
|
||||||
CACHE PATH "Install dir for headers")
|
CACHE PATH "Install dir for headers")
|
||||||
SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake
|
SET(PACKAGE_INSTALL_DIR lib/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)
|
||||||
@@ -83,14 +91,6 @@ 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} -std=c++11 -Wall")
|
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
|
||||||
# using GCC
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -pedantic")
|
|
||||||
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)
|
||||||
@@ -101,7 +101,7 @@ IF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
|
|||||||
"pkg-config/jsoncpp.pc"
|
"pkg-config/jsoncpp.pc"
|
||||||
@ONLY)
|
@ONLY)
|
||||||
INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc"
|
INSTALL(FILES "${CMAKE_BINARY_DIR}/pkg-config/jsoncpp.pc"
|
||||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig")
|
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||||
ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
|
ENDIF(JSONCPP_WITH_PKGCONFIG_SUPPORT)
|
||||||
|
|
||||||
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||||
|
2
NEWS.txt
2
NEWS.txt
@@ -80,7 +80,7 @@ New in SVN
|
|||||||
(e.g. MSVC 2008 command prompt in start menu) before running scons.
|
(e.g. MSVC 2008 command prompt in start menu) before running scons.
|
||||||
|
|
||||||
- Added support for amalgamated source and header generation (a la sqlite).
|
- Added support for amalgamated source and header generation (a la sqlite).
|
||||||
Refer to README.md section "Generating amalgamated source and header"
|
Refer to README.txt section "Generating amalgamated source and header"
|
||||||
for detail.
|
for detail.
|
||||||
|
|
||||||
* Value
|
* Value
|
||||||
|
@@ -66,7 +66,7 @@ Alternatively, from the command-line on Unix in the source directory:
|
|||||||
|
|
||||||
mkdir -p build/debug
|
mkdir -p build/debug
|
||||||
cd build/debug
|
cd build/debug
|
||||||
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_STATIC=ON -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
|
cmake -DCMAKE_BUILD_TYPE=debug -DJSONCPP_LIB_BUILD_SHARED=OFF -G "Unix Makefiles" ../..
|
||||||
make
|
make
|
||||||
|
|
||||||
Running `cmake -`" will display the list of available generators (passed using
|
Running `cmake -`" will display the list of available generators (passed using
|
||||||
|
@@ -237,7 +237,7 @@ RunUnitTests = ActionFactory(runUnitTests_action, runUnitTests_string )
|
|||||||
env.Alias( 'check' )
|
env.Alias( 'check' )
|
||||||
|
|
||||||
srcdist_cmd = env['SRCDIST_ADD']( source = """
|
srcdist_cmd = env['SRCDIST_ADD']( source = """
|
||||||
AUTHORS README.md SConstruct
|
AUTHORS README.txt SConstruct
|
||||||
""".split() )
|
""".split() )
|
||||||
env.Alias( 'src-dist', srcdist_cmd )
|
env.Alias( 'src-dist', srcdist_cmd )
|
||||||
|
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
# Baptiste Lepilleur, 2009
|
# Baptiste Lepilleur, 2009
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from dircache import listdir
|
from dircache import listdir
|
||||||
import re
|
import re
|
||||||
import fnmatch
|
import fnmatch
|
||||||
@@ -191,12 +190,12 @@ if __name__ == "__main__":
|
|||||||
test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) )
|
test_cases.append( (ant_pattern, local_path(accepted_matches), local_path( rejected_matches )) )
|
||||||
for ant_pattern, accepted_matches, rejected_matches in test_cases:
|
for ant_pattern, accepted_matches, rejected_matches in test_cases:
|
||||||
rex = ant_pattern_to_re( ant_pattern )
|
rex = ant_pattern_to_re( ant_pattern )
|
||||||
print('ant_pattern:', ant_pattern, ' => ', rex.pattern)
|
print 'ant_pattern:', ant_pattern, ' => ', rex.pattern
|
||||||
for accepted_match in accepted_matches:
|
for accepted_match in accepted_matches:
|
||||||
print('Accepted?:', accepted_match)
|
print 'Accepted?:', accepted_match
|
||||||
self.assertTrue(rex.match(accepted_match) is not None)
|
self.assert_( rex.match( accepted_match ) is not None )
|
||||||
for rejected_match in rejected_matches:
|
for rejected_match in rejected_matches:
|
||||||
print('Rejected?:', rejected_match)
|
print 'Rejected?:', rejected_match
|
||||||
self.assertTrue(rex.match(rejected_match) is None)
|
self.assert_( rex.match( rejected_match ) is None )
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import collections
|
import collections
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
@@ -30,7 +29,7 @@ class BuildDesc:
|
|||||||
def env( self ):
|
def env( self ):
|
||||||
environ = os.environ.copy()
|
environ = os.environ.copy()
|
||||||
for values_by_name in self.prepend_envs:
|
for values_by_name in self.prepend_envs:
|
||||||
for var, value in list(values_by_name.items()):
|
for var, value in values_by_name.items():
|
||||||
var = var.upper()
|
var = var.upper()
|
||||||
if type(value) is unicode:
|
if type(value) is unicode:
|
||||||
value = value.encode( sys.getdefaultencoding() )
|
value = value.encode( sys.getdefaultencoding() )
|
||||||
@@ -63,7 +62,7 @@ class BuildData:
|
|||||||
self.build_succeeded = False
|
self.build_succeeded = False
|
||||||
|
|
||||||
def execute_build(self):
|
def execute_build(self):
|
||||||
print('Build %s' % self.desc)
|
print 'Build %s' % self.desc
|
||||||
self._make_new_work_dir( )
|
self._make_new_work_dir( )
|
||||||
self.cmake_succeeded = self._generate_makefiles( )
|
self.cmake_succeeded = self._generate_makefiles( )
|
||||||
if self.cmake_succeeded:
|
if self.cmake_succeeded:
|
||||||
@@ -71,19 +70,19 @@ class BuildData:
|
|||||||
return self.build_succeeded
|
return self.build_succeeded
|
||||||
|
|
||||||
def _generate_makefiles(self):
|
def _generate_makefiles(self):
|
||||||
print(' Generating makefiles: ', end=' ')
|
print ' Generating makefiles: ',
|
||||||
cmd = ['cmake'] + self.desc.cmake_args( ) + [os.path.abspath( self.source_dir )]
|
cmd = ['cmake'] + self.desc.cmake_args( ) + [os.path.abspath( self.source_dir )]
|
||||||
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.cmake_log_path )
|
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.cmake_log_path )
|
||||||
print('done' if succeeded else 'FAILED')
|
print 'done' if succeeded else 'FAILED'
|
||||||
return succeeded
|
return succeeded
|
||||||
|
|
||||||
def _build_using_makefiles(self):
|
def _build_using_makefiles(self):
|
||||||
print(' Building:', end=' ')
|
print ' Building:',
|
||||||
cmd = ['cmake', '--build', self.work_dir]
|
cmd = ['cmake', '--build', self.work_dir]
|
||||||
if self.desc.build_type:
|
if self.desc.build_type:
|
||||||
cmd += ['--config', self.desc.build_type]
|
cmd += ['--config', self.desc.build_type]
|
||||||
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.build_log_path )
|
succeeded = self._execute_build_subprocess( cmd, self.desc.env(), self.build_log_path )
|
||||||
print('done' if succeeded else 'FAILED')
|
print 'done' if succeeded else 'FAILED'
|
||||||
return succeeded
|
return succeeded
|
||||||
|
|
||||||
def _execute_build_subprocess(self, cmd, env, log_path):
|
def _execute_build_subprocess(self, cmd, env, log_path):
|
||||||
@@ -98,7 +97,7 @@ class BuildData:
|
|||||||
|
|
||||||
def _make_new_work_dir(self):
|
def _make_new_work_dir(self):
|
||||||
if os.path.isdir( self.work_dir ):
|
if os.path.isdir( self.work_dir ):
|
||||||
print(' Removing work directory', self.work_dir)
|
print ' Removing work directory', self.work_dir
|
||||||
shutil.rmtree( self.work_dir, ignore_errors=True )
|
shutil.rmtree( self.work_dir, ignore_errors=True )
|
||||||
if not os.path.isdir( self.work_dir ):
|
if not os.path.isdir( self.work_dir ):
|
||||||
os.makedirs( self.work_dir )
|
os.makedirs( self.work_dir )
|
||||||
@@ -135,9 +134,9 @@ def load_build_variants_from_config(config_path):
|
|||||||
|
|
||||||
def generate_build_variants( build_descs_by_axis ):
|
def generate_build_variants( build_descs_by_axis ):
|
||||||
"""Returns a list of BuildDesc generated for the partial BuildDesc for each axis."""
|
"""Returns a list of BuildDesc generated for the partial BuildDesc for each axis."""
|
||||||
axis_names = list(build_descs_by_axis.keys())
|
axis_names = build_descs_by_axis.keys()
|
||||||
build_descs = []
|
build_descs = []
|
||||||
for axis_name, axis_build_descs in list(build_descs_by_axis.items()):
|
for axis_name, axis_build_descs in build_descs_by_axis.items():
|
||||||
if len(build_descs):
|
if len(build_descs):
|
||||||
# for each existing build_desc and each axis build desc, create a new build_desc
|
# for each existing build_desc and each axis build desc, create a new build_desc
|
||||||
new_build_descs = []
|
new_build_descs = []
|
||||||
@@ -211,21 +210,24 @@ def generate_html_report(html_report_path, builds):
|
|||||||
build_status = 'ok' if build.build_succeeded else 'FAILED'
|
build_status = 'ok' if build.build_succeeded else 'FAILED'
|
||||||
cmake_log_url = os.path.relpath( build.cmake_log_path, report_dir )
|
cmake_log_url = os.path.relpath( build.cmake_log_path, report_dir )
|
||||||
build_log_url = os.path.relpath( build.build_log_path, report_dir )
|
build_log_url = os.path.relpath( build.build_log_path, report_dir )
|
||||||
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % ( build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
|
td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % (
|
||||||
|
build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status)
|
||||||
if build.cmake_succeeded:
|
if build.cmake_succeeded:
|
||||||
td += '<br><a href="%s" class="%s">Build: %s</a>' % ( build_log_url, build_status.lower(), build_status)
|
td += '<br><a href="%s" class="%s">Build: %s</a>' % (
|
||||||
|
build_log_url, build_status.lower(), build_status)
|
||||||
td += '</td>'
|
td += '</td>'
|
||||||
else:
|
else:
|
||||||
td = '<td></td>'
|
td = '<td></td>'
|
||||||
tds.append( td )
|
tds.append( td )
|
||||||
tr_builds.append( '<tr>%s</tr>' % '\n'.join( tds ) )
|
tr_builds.append( '<tr>%s</tr>' % '\n'.join( tds ) )
|
||||||
html = HTML_TEMPLATE.substitute( title='Batch build report',
|
html = HTML_TEMPLATE.substitute(
|
||||||
|
title='Batch build report',
|
||||||
th_vars=' '.join(th_vars),
|
th_vars=' '.join(th_vars),
|
||||||
th_build_types=' '.join( th_build_types),
|
th_build_types=' '.join( th_build_types),
|
||||||
tr_builds='\n'.join( tr_builds ) )
|
tr_builds='\n'.join( tr_builds ) )
|
||||||
with open( html_report_path, 'wt' ) as fhtml:
|
with open( html_report_path, 'wt' ) as fhtml:
|
||||||
fhtml.write( html )
|
fhtml.write( html )
|
||||||
print('HTML report generated in:', html_report_path)
|
print 'HTML report generated in:', html_report_path
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...]
|
usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...]
|
||||||
@@ -256,7 +258,7 @@ python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.j
|
|||||||
for config_path in config_paths:
|
for config_path in config_paths:
|
||||||
build_descs_by_axis = load_build_variants_from_config( config_path )
|
build_descs_by_axis = load_build_variants_from_config( config_path )
|
||||||
build_descs.extend( generate_build_variants( build_descs_by_axis ) )
|
build_descs.extend( generate_build_variants( build_descs_by_axis ) )
|
||||||
print('Build variants (%d):' % len(build_descs))
|
print 'Build variants (%d):' % len(build_descs)
|
||||||
# assign build directory for each variant
|
# assign build directory for each variant
|
||||||
if not os.path.isdir( work_dir ):
|
if not os.path.isdir( work_dir ):
|
||||||
os.makedirs( work_dir )
|
os.makedirs( work_dir )
|
||||||
@@ -270,7 +272,7 @@ python devtools\batchbuild.py e:\buildbots\jsoncpp\build . devtools\agent_vmw7.j
|
|||||||
build.execute_build()
|
build.execute_build()
|
||||||
html_report_path = os.path.join( work_dir, 'batchbuild-report.html' )
|
html_report_path = os.path.join( work_dir, 'batchbuild-report.html' )
|
||||||
generate_html_report( html_report_path, builds )
|
generate_html_report( html_report_path, builds )
|
||||||
print('Done')
|
print 'Done'
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
def fix_source_eol( path, is_dry_run = True, verbose = True, eol = '\n' ):
|
||||||
@@ -7,8 +6,8 @@ def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'):
|
|||||||
raise ValueError( 'Path "%s" is not a file' % path )
|
raise ValueError( 'Path "%s" is not a file' % path )
|
||||||
try:
|
try:
|
||||||
f = open(path, 'rb')
|
f = open(path, 'rb')
|
||||||
except IOError as msg:
|
except IOError, msg:
|
||||||
print("%s: I/O Error: %s" % (file, str(msg)), file=sys.stderr)
|
print >> sys.stderr, "%s: I/O Error: %s" % (file, str(msg))
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
raw_lines = f.readlines()
|
raw_lines = f.readlines()
|
||||||
@@ -16,7 +15,7 @@ def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'):
|
|||||||
f.close()
|
f.close()
|
||||||
fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines]
|
fixed_lines = [line.rstrip('\r\n') + eol for line in raw_lines]
|
||||||
if raw_lines != fixed_lines:
|
if raw_lines != fixed_lines:
|
||||||
print('%s =>' % path, end=' ')
|
print '%s =>' % path,
|
||||||
if not is_dry_run:
|
if not is_dry_run:
|
||||||
f = open(path, "wb")
|
f = open(path, "wb")
|
||||||
try:
|
try:
|
||||||
@@ -24,7 +23,7 @@ def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'):
|
|||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
if verbose:
|
if verbose:
|
||||||
print(is_dry_run and ' NEED FIX' or ' FIXED')
|
print is_dry_run and ' NEED FIX' or ' FIXED'
|
||||||
return True
|
return True
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
"""Updates the license text in source file.
|
"""Updates the license text in source file.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# An existing license is found if the file starts with the string below,
|
# An existing license is found if the file starts with the string below,
|
||||||
# and ends with the first blank line.
|
# and ends with the first blank line.
|
||||||
@@ -35,11 +34,11 @@ def update_license(path, dry_run, show_diff):
|
|||||||
if not dry_run:
|
if not dry_run:
|
||||||
with open( path, 'wb' ) as fout:
|
with open( path, 'wb' ) as fout:
|
||||||
fout.write( new_text.replace('\n', newline ) )
|
fout.write( new_text.replace('\n', newline ) )
|
||||||
print('Updated', path)
|
print 'Updated', path
|
||||||
if show_diff:
|
if show_diff:
|
||||||
import difflib
|
import difflib
|
||||||
print('\n'.join(difflib.unified_diff(original_text.split('\n'),
|
print '\n'.join( difflib.unified_diff( original_text.split('\n'),
|
||||||
new_text.split('\n'))))
|
new_text.split('\n') ) )
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ python devtools\licenseupdater.py include src
|
|||||||
parser.enable_interspersed_args()
|
parser.enable_interspersed_args()
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
update_license_in_source_directories( args, options.dry_run, options.show_diff )
|
update_license_in_source_directories( args, options.dry_run, options.show_diff )
|
||||||
print('Done')
|
print 'Done'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
from contextlib import closing
|
import os.path
|
||||||
import os
|
import gzip
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
TARGZ_DEFAULT_COMPRESSION_LEVEL = 9
|
TARGZ_DEFAULT_COMPRESSION_LEVEL = 9
|
||||||
@@ -29,19 +29,25 @@ def make_tarball(tarball_path, sources, base_dir, prefix_dir=''):
|
|||||||
path_in_tar = archive_name(path)
|
path_in_tar = archive_name(path)
|
||||||
tar.add(path, path_in_tar )
|
tar.add(path, path_in_tar )
|
||||||
compression = TARGZ_DEFAULT_COMPRESSION_LEVEL
|
compression = TARGZ_DEFAULT_COMPRESSION_LEVEL
|
||||||
with closing(tarfile.TarFile.open(tarball_path, 'w:gz',
|
tar = tarfile.TarFile.gzopen( tarball_path, 'w', compresslevel=compression )
|
||||||
compresslevel=compression)) as tar:
|
try:
|
||||||
for source in sources:
|
for source in sources:
|
||||||
source_path = source
|
source_path = source
|
||||||
if os.path.isdir( source ):
|
if os.path.isdir( source ):
|
||||||
for dirpath, dirnames, filenames in os.walk(source_path):
|
os.path.walk(source_path, visit, tar)
|
||||||
visit(tar, dirpath, filenames)
|
|
||||||
else:
|
else:
|
||||||
path_in_tar = archive_name(source_path)
|
path_in_tar = archive_name(source_path)
|
||||||
tar.add(source_path, path_in_tar ) # filename, arcname
|
tar.add(source_path, path_in_tar ) # filename, arcname
|
||||||
|
finally:
|
||||||
|
tar.close()
|
||||||
|
|
||||||
def decompress( tarball_path, base_dir ):
|
def decompress( tarball_path, base_dir ):
|
||||||
"""Decompress the gzipped tarball into directory base_dir.
|
"""Decompress the gzipped tarball into directory base_dir.
|
||||||
"""
|
"""
|
||||||
with closing(tarfile.TarFile.open(tarball_path)) as tar:
|
# !!! This class method is not documented in the online doc
|
||||||
|
# nor is bz2open!
|
||||||
|
tar = tarfile.TarFile.gzopen(tarball_path, mode='r')
|
||||||
|
try:
|
||||||
tar.extractall( base_dir )
|
tar.extractall( base_dir )
|
||||||
|
finally:
|
||||||
|
tar.close()
|
||||||
|
@@ -819,7 +819,7 @@ EXCLUDE_SYMBOLS =
|
|||||||
# that contain example code fragments that are included (see the \include
|
# that contain example code fragments that are included (see the \include
|
||||||
# command).
|
# command).
|
||||||
|
|
||||||
EXAMPLE_PATH = ..
|
EXAMPLE_PATH =
|
||||||
|
|
||||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
|
||||||
|
@@ -16,7 +16,7 @@ JsonCpp - JSON data format manipulation library
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td width="40%" align="right" valign="center">
|
<td width="40%" align="right" valign="center">
|
||||||
<a href="http://open-source-parsers.github.io/jsoncpp-docs/doxygen/">JsonCpp home page</a>
|
<a href="https://github.com/open-source-parsers/jsoncpp">JsonCpp home page</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
108
doc/jsoncpp.dox
108
doc/jsoncpp.dox
@@ -4,21 +4,11 @@
|
|||||||
|
|
||||||
<a HREF="http://www.json.org/">JSON (JavaScript Object Notation)</a>
|
<a HREF="http://www.json.org/">JSON (JavaScript Object Notation)</a>
|
||||||
is a lightweight data-interchange format.
|
is a lightweight data-interchange format.
|
||||||
|
It can represent integer, real number, string, an ordered sequence of value, and
|
||||||
|
a collection of name/value pairs.
|
||||||
|
|
||||||
Here is an example of JSON data:
|
Here is an example of JSON data:
|
||||||
\verbatim
|
\verbatim
|
||||||
{
|
|
||||||
"encoding" : "UTF-8",
|
|
||||||
"plug-ins" : [
|
|
||||||
"python",
|
|
||||||
"c++",
|
|
||||||
"ruby"
|
|
||||||
],
|
|
||||||
"indent" : { "length" : 3, "use_space": true }
|
|
||||||
}
|
|
||||||
\endverbatim
|
|
||||||
<b>JsonCpp</b> supports comments as <i>meta-data</i>:
|
|
||||||
\code
|
|
||||||
// Configuration options
|
// Configuration options
|
||||||
{
|
{
|
||||||
// Default encoding for text
|
// Default encoding for text
|
||||||
@@ -27,22 +17,22 @@ Here is an example of JSON data:
|
|||||||
// Plug-ins loaded at start-up
|
// Plug-ins loaded at start-up
|
||||||
"plug-ins" : [
|
"plug-ins" : [
|
||||||
"python",
|
"python",
|
||||||
"c++", // trailing comment
|
"c++",
|
||||||
"ruby"
|
"ruby"
|
||||||
],
|
],
|
||||||
|
|
||||||
// Tab indent size
|
// Tab indent size
|
||||||
// (multi-line comment)
|
"indent" : { "length" : 3, "use_space": true }
|
||||||
"indent" : { /*embedded comment*/ "length" : 3, "use_space": true }
|
|
||||||
}
|
}
|
||||||
\endcode
|
\endverbatim
|
||||||
|
<code>jsoncpp</code> supports comments as <i>meta-data</i>.
|
||||||
|
|
||||||
\section _features Features
|
\section _features Features
|
||||||
- read and write JSON document
|
- read and write JSON document
|
||||||
- attach C++ style comments to element during parsing
|
- attach C++ style comments to element during parsing
|
||||||
- rewrite JSON document preserving original comments
|
- rewrite JSON document preserving original comments
|
||||||
|
|
||||||
Notes: Comments used to be supported in JSON but were removed for
|
Notes: Comments used to be supported in JSON but where removed for
|
||||||
portability (C like comments are not supported in Python). Since
|
portability (C like comments are not supported in Python). Since
|
||||||
comments are useful in configuration/input file, this feature was
|
comments are useful in configuration/input file, this feature was
|
||||||
preserved.
|
preserved.
|
||||||
@@ -50,73 +40,47 @@ preserved.
|
|||||||
\section _example Code example
|
\section _example Code example
|
||||||
|
|
||||||
\code
|
\code
|
||||||
Json::Value root; // 'root' will contain the root value after parsing.
|
Json::Value root; // will contains the root value after parsing.
|
||||||
std::cin >> root;
|
Json::Reader reader;
|
||||||
|
bool parsingSuccessful = reader.parse( config_doc, root );
|
||||||
// You can also read into a particular sub-value.
|
if ( !parsingSuccessful )
|
||||||
std::cin >> root["subtree"];
|
{
|
||||||
|
// report to the user the failure and their locations in the document.
|
||||||
|
std::cout << "Failed to parse configuration\n"
|
||||||
|
<< reader.getFormattedErrorMessages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
|
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
|
||||||
// such member.
|
// such member.
|
||||||
std::string encoding = root.get("encoding", "UTF-8" ).asString();
|
std::string encoding = root.get("encoding", "UTF-8" ).asString();
|
||||||
// Get the value of the member of root named 'encoding'; return a 'null' value if
|
// Get the value of the member of root named 'encoding', return a 'null' value if
|
||||||
// there is no such member.
|
// there is no such member.
|
||||||
const Json::Value plugins = root["plug-ins"];
|
const Json::Value plugins = root["plug-ins"];
|
||||||
for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements.
|
for ( int index = 0; index < plugins.size(); ++index ) // Iterates over the sequence elements.
|
||||||
loadPlugIn( plugins[index].asString() );
|
loadPlugIn( plugins[index].asString() );
|
||||||
|
|
||||||
foo::setIndentLength( root["indent"].get("length", 3).asInt() );
|
setIndentLength( root["indent"].get("length", 3).asInt() );
|
||||||
foo::setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
|
setIndentUseSpace( root["indent"].get("use_space", true).asBool() );
|
||||||
|
|
||||||
|
// ...
|
||||||
|
// At application shutdown to make the new configuration document:
|
||||||
// Since Json::Value has implicit constructor for all value types, it is not
|
// Since Json::Value has implicit constructor for all value types, it is not
|
||||||
// necessary to explicitly construct the Json::Value object:
|
// necessary to explicitly construct the Json::Value object:
|
||||||
root["encoding"] = foo::getCurrentEncoding();
|
root["encoding"] = getCurrentEncoding();
|
||||||
root["indent"]["length"] = foo::getCurrentIndentLength();
|
root["indent"]["length"] = getCurrentIndentLength();
|
||||||
root["indent"]["use_space"] = foo::getCurrentIndentUseSpace();
|
root["indent"]["use_space"] = getCurrentIndentUseSpace();
|
||||||
|
|
||||||
// If you like the defaults, you can insert directly into a stream.
|
Json::StyledWriter writer;
|
||||||
|
// Make a new JSON document for the configuration. Preserve original comments.
|
||||||
|
std::string outputConfig = writer.write( root );
|
||||||
|
|
||||||
|
// You can also use streams. This will put the contents of any JSON
|
||||||
|
// stream at a particular sub-value, if you'd like.
|
||||||
|
std::cin >> root["subtree"];
|
||||||
|
|
||||||
|
// And you can write to a stream, using the StyledWriter automatically.
|
||||||
std::cout << root;
|
std::cout << root;
|
||||||
// Of course, you can write to `std::ostringstream` if you prefer.
|
|
||||||
|
|
||||||
// If desired, remember to add a linefeed and flush.
|
|
||||||
std::cout << std::endl;
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
\section _advanced Advanced usage
|
|
||||||
|
|
||||||
Configure *builders* to create *readers* and *writers*. For
|
|
||||||
configuration, we use our own `Json::Value` (rather than
|
|
||||||
standard setters/getters) so that we can add
|
|
||||||
features without losing binary-compatibility.
|
|
||||||
|
|
||||||
\code
|
|
||||||
// For convenience, use `writeString()` with a specialized builder.
|
|
||||||
Json::StreamWriterBuilder wbuilder;
|
|
||||||
wbuilder.settings_["indentation"] = "\t"; // simple Json::Value
|
|
||||||
std::string document = Json::writeString(wbuilder, root);
|
|
||||||
|
|
||||||
// Here, using a specialized Builder, we discard comments and
|
|
||||||
// record errors as we parse.
|
|
||||||
Json::CharReaderBuilder rbuilder;
|
|
||||||
rbuilder.settings_["collectComments"] = false; // simple Json::Value
|
|
||||||
std::string errs;
|
|
||||||
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
Yes, compile-time configuration-checking would be helpful,
|
|
||||||
but `Json::Value` lets you
|
|
||||||
write and read the builder configuration, which is better! In other words,
|
|
||||||
you can configure your JSON parser using JSON.
|
|
||||||
|
|
||||||
CharReaders and StreamWriters are not thread-safe, but they are re-usable.
|
|
||||||
\code
|
|
||||||
Json::CharReaderBuilder rbuilder;
|
|
||||||
cfg >> rbuilder.settings_;
|
|
||||||
std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
|
|
||||||
reader->parse(start, stop, &value1, &errs);
|
|
||||||
// ...
|
|
||||||
reader->parse(start, stop, &value2, &errs);
|
|
||||||
// etc.
|
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
\section _pbuild Build instructions
|
\section _pbuild Build instructions
|
||||||
@@ -152,8 +116,4 @@ Basically JsonCpp is licensed under MIT license, or public domain if desired
|
|||||||
and recognized in your jurisdiction.
|
and recognized in your jurisdiction.
|
||||||
|
|
||||||
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
\author Baptiste Lepilleur <blep@users.sourceforge.net> (originator)
|
||||||
\version \include version
|
|
||||||
We make strong guarantees about binary-compatibility, consistent with
|
|
||||||
<a href="http://apr.apache.org/versioning.html">the Apache versioning scheme</a>.
|
|
||||||
\sa version.h
|
|
||||||
*/
|
*/
|
||||||
|
2302
doc/web_doxyfile.in
2302
doc/web_doxyfile.in
File diff suppressed because it is too large
Load Diff
114
doxybuild.py
114
doxybuild.py
@@ -1,27 +1,12 @@
|
|||||||
"""Script to generate doxygen documentation.
|
"""Script to generate doxygen documentation.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from devtools import tarball
|
|
||||||
from contextlib import contextmanager
|
|
||||||
import subprocess
|
|
||||||
import traceback
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
|
from devtools import tarball
|
||||||
@contextmanager
|
|
||||||
def cd(newdir):
|
|
||||||
"""
|
|
||||||
http://stackoverflow.com/questions/431684/how-do-i-cd-in-python
|
|
||||||
"""
|
|
||||||
prevdir = os.getcwd()
|
|
||||||
os.chdir(newdir)
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
os.chdir(prevdir)
|
|
||||||
|
|
||||||
def find_program(*filenames):
|
def find_program(*filenames):
|
||||||
"""find a program in folders path_lst, and sets env[var]
|
"""find a program in folders path_lst, and sets env[var]
|
||||||
@@ -43,54 +28,51 @@ def do_subst_in_file(targetfile, sourcefile, dict):
|
|||||||
For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
|
For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
|
||||||
then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
|
then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
|
||||||
"""
|
"""
|
||||||
with open(sourcefile, 'r') as f:
|
try:
|
||||||
|
f = open(sourcefile, 'rb')
|
||||||
contents = f.read()
|
contents = f.read()
|
||||||
for (k,v) in list(dict.items()):
|
f.close()
|
||||||
|
except:
|
||||||
|
print "Can't read source file %s"%sourcefile
|
||||||
|
raise
|
||||||
|
for (k,v) in dict.items():
|
||||||
v = v.replace('\\','\\\\')
|
v = v.replace('\\','\\\\')
|
||||||
contents = re.sub(k, v, contents)
|
contents = re.sub(k, v, contents)
|
||||||
with open(targetfile, 'w') as f:
|
|
||||||
f.write(contents)
|
|
||||||
|
|
||||||
def getstatusoutput(cmd):
|
|
||||||
"""cmd is a list.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
f = open(targetfile, 'wb')
|
||||||
output, _ = process.communicate()
|
f.write(contents)
|
||||||
status = process.returncode
|
f.close()
|
||||||
except:
|
except:
|
||||||
status = -1
|
print "Can't write target file %s"%targetfile
|
||||||
output = traceback.format_exc()
|
raise
|
||||||
return status, output
|
|
||||||
|
|
||||||
def run_cmd(cmd, silent=False):
|
|
||||||
"""Raise exception on failure.
|
|
||||||
"""
|
|
||||||
info = 'Running: %r in %r' %(' '.join(cmd), os.getcwd())
|
|
||||||
print(info)
|
|
||||||
sys.stdout.flush()
|
|
||||||
if silent:
|
|
||||||
status, output = getstatusoutput(cmd)
|
|
||||||
else:
|
|
||||||
status, output = os.system(' '.join(cmd)), ''
|
|
||||||
if status:
|
|
||||||
msg = 'Error while %s ...\n\terror=%d, output="""%s"""' %(info, status, output)
|
|
||||||
raise Exception(msg)
|
|
||||||
|
|
||||||
def assert_is_exe(path):
|
|
||||||
if not path:
|
|
||||||
raise Exception('path is empty.')
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
raise Exception('%r is not a file.' %path)
|
|
||||||
if not os.access(path, os.X_OK):
|
|
||||||
raise Exception('%r is not executable by this user.' %path)
|
|
||||||
|
|
||||||
def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
def run_doxygen(doxygen_path, config_file, working_dir, is_silent):
|
||||||
assert_is_exe(doxygen_path)
|
|
||||||
config_file = os.path.abspath( config_file )
|
config_file = os.path.abspath( config_file )
|
||||||
with cd(working_dir):
|
doxygen_path = doxygen_path
|
||||||
|
old_cwd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir( working_dir )
|
||||||
cmd = [doxygen_path, config_file]
|
cmd = [doxygen_path, config_file]
|
||||||
run_cmd(cmd, is_silent)
|
print 'Running:', ' '.join( cmd )
|
||||||
|
try:
|
||||||
|
import subprocess
|
||||||
|
except:
|
||||||
|
if os.system( ' '.join( cmd ) ) != 0:
|
||||||
|
print 'Documentation generation failed'
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if is_silent:
|
||||||
|
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
||||||
|
else:
|
||||||
|
process = subprocess.Popen( cmd )
|
||||||
|
stdout, _ = process.communicate()
|
||||||
|
if process.returncode:
|
||||||
|
print 'Documentation generation failed:'
|
||||||
|
print stdout
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
finally:
|
||||||
|
os.chdir( old_cwd )
|
||||||
|
|
||||||
def build_doc( options, make_release=False ):
|
def build_doc( options, make_release=False ):
|
||||||
if make_release:
|
if make_release:
|
||||||
@@ -125,26 +107,26 @@ def build_doc(options, make_release=False):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if os.path.isdir( output_dir ):
|
if os.path.isdir( output_dir ):
|
||||||
print('Deleting directory:', output_dir)
|
print 'Deleting directory:', output_dir
|
||||||
shutil.rmtree( output_dir )
|
shutil.rmtree( output_dir )
|
||||||
if not os.path.isdir( output_dir ):
|
if not os.path.isdir( output_dir ):
|
||||||
os.makedirs( output_dir )
|
os.makedirs( output_dir )
|
||||||
|
|
||||||
do_subst_in_file('doc/doxyfile', options.doxyfile_input_path, subst_keys)
|
do_subst_in_file( 'doc/doxyfile', 'doc/doxyfile.in', subst_keys )
|
||||||
run_doxygen(options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent)
|
ok = run_doxygen( options.doxygen_path, 'doc/doxyfile', 'doc', is_silent=options.silent )
|
||||||
if not options.silent:
|
if not options.silent:
|
||||||
print(open(warning_log_path, 'r').read())
|
print open(warning_log_path, 'rb').read()
|
||||||
index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
index_path = os.path.abspath(os.path.join('doc', subst_keys['%HTML_OUTPUT%'], 'index.html'))
|
||||||
print('Generated documentation can be found in:')
|
print 'Generated documentation can be found in:'
|
||||||
print(index_path)
|
print index_path
|
||||||
if options.open:
|
if options.open:
|
||||||
import webbrowser
|
import webbrowser
|
||||||
webbrowser.open( 'file://' + index_path )
|
webbrowser.open( 'file://' + index_path )
|
||||||
if options.make_tarball:
|
if options.make_tarball:
|
||||||
print('Generating doc tarball to', tarball_path)
|
print 'Generating doc tarball to', tarball_path
|
||||||
tarball_sources = [
|
tarball_sources = [
|
||||||
output_dir,
|
output_dir,
|
||||||
'README.md',
|
'README.txt',
|
||||||
'LICENSE',
|
'LICENSE',
|
||||||
'NEWS.txt',
|
'NEWS.txt',
|
||||||
'version'
|
'version'
|
||||||
@@ -169,8 +151,6 @@ def main():
|
|||||||
help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
|
help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
|
||||||
parser.add_option('--doxygen', dest="doxygen_path", action='store', default=find_program('doxygen'),
|
parser.add_option('--doxygen', dest="doxygen_path", action='store', default=find_program('doxygen'),
|
||||||
help="""Path to Doxygen tool. [Default: %default]""")
|
help="""Path to Doxygen tool. [Default: %default]""")
|
||||||
parser.add_option('--in', dest="doxyfile_input_path", action='store', default='doc/doxyfile.in',
|
|
||||||
help="""Path to doxygen inputs. [Default: %default]""")
|
|
||||||
parser.add_option('--with-html-help', dest="with_html_help", action='store_true', default=False,
|
parser.add_option('--with-html-help', dest="with_html_help", action='store_true', default=False,
|
||||||
help="""Enable generation of Microsoft HTML HELP""")
|
help="""Enable generation of Microsoft HTML HELP""")
|
||||||
parser.add_option('--no-uml-look', dest="with_uml_look", action='store_false', default=True,
|
parser.add_option('--no-uml-look', dest="with_uml_look", action='store_false', default=True,
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
#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"
|
||||||
@@ -17,26 +16,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) do{std::ostringstream oss; oss << message; throw std::runtime_error(oss.str());}while(0)
|
#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
|
||||||
//#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 abort, for a core-dump or debugger.
|
// release bugs we write to invalid memory in order to crash hard, so that a
|
||||||
|
// 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) \
|
||||||
{ \
|
{ \
|
||||||
std::ostringstream oss; oss << message; \
|
assert(false&& message); \
|
||||||
assert(false && oss.str().c_str()); \
|
strcpy(reinterpret_cast<char*>(666), message); \
|
||||||
abort(); \
|
exit(123); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#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
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <istream>
|
|
||||||
|
|
||||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
// be used by...
|
// be used by...
|
||||||
@@ -28,7 +27,6 @@ namespace Json {
|
|||||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
||||||
*Value.
|
*Value.
|
||||||
*
|
*
|
||||||
* \deprecated Use CharReader and CharReaderBuilder.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API Reader {
|
class JSON_API Reader {
|
||||||
public:
|
public:
|
||||||
@@ -80,7 +78,7 @@ public:
|
|||||||
document to read.
|
document to read.
|
||||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||||
document to read.
|
document to read.
|
||||||
* Must be >= beginDoc.
|
\ Must be >= beginDoc.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them
|
* \param collectComments \c true to collect comment and allow writing them
|
||||||
@@ -189,6 +187,7 @@ 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);
|
||||||
@@ -240,119 +239,8 @@ private:
|
|||||||
std::string commentsBefore_;
|
std::string commentsBefore_;
|
||||||
Features features_;
|
Features features_;
|
||||||
bool collectComments_;
|
bool collectComments_;
|
||||||
}; // Reader
|
|
||||||
|
|
||||||
/** Interface for reading JSON from a char array.
|
|
||||||
*/
|
|
||||||
class JSON_API CharReader {
|
|
||||||
public:
|
|
||||||
virtual ~CharReader() {}
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
|
||||||
document.
|
|
||||||
* The document must be a UTF-8 encoded string containing the document to read.
|
|
||||||
*
|
|
||||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
|
||||||
document to read.
|
|
||||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
|
||||||
document to read.
|
|
||||||
* Must be >= beginDoc.
|
|
||||||
* \param root [out] Contains the root value of the document if it was
|
|
||||||
* successfully parsed.
|
|
||||||
* \param errs [out] Formatted error messages (if not NULL)
|
|
||||||
* a user friendly string that lists errors in the parsed
|
|
||||||
* document.
|
|
||||||
* \return \c true if the document was successfully parsed, \c false if an
|
|
||||||
error occurred.
|
|
||||||
*/
|
|
||||||
virtual bool parse(
|
|
||||||
char const* beginDoc, char const* endDoc,
|
|
||||||
Value* root, std::string* errs) = 0;
|
|
||||||
|
|
||||||
class Factory {
|
|
||||||
public:
|
|
||||||
/** \brief Allocate a CharReader via operator new().
|
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
|
||||||
*/
|
|
||||||
virtual CharReader* newCharReader() const = 0;
|
|
||||||
}; // Factory
|
|
||||||
}; // CharReader
|
|
||||||
|
|
||||||
/** \brief Build a CharReader implementation.
|
|
||||||
|
|
||||||
\deprecated This is experimental and will be altered before the next release.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
\code
|
|
||||||
using namespace Json;
|
|
||||||
CharReaderBuilder builder;
|
|
||||||
builder.settings_["collectComments"] = false;
|
|
||||||
Value value;
|
|
||||||
std::string errs;
|
|
||||||
bool ok = parseFromStream(builder, std::cin, &value, &errs);
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
class JSON_API CharReaderBuilder : public CharReader::Factory {
|
|
||||||
public:
|
|
||||||
// Note: We use a Json::Value so that we can add data-members to this class
|
|
||||||
// without a major version bump.
|
|
||||||
/** Configuration of this builder.
|
|
||||||
These are case-sensitive.
|
|
||||||
Available settings (case-sensitive):
|
|
||||||
- "collectComments": false or true
|
|
||||||
- true to collect comment and allow writing them
|
|
||||||
back during serialization, false to discard comments.
|
|
||||||
This parameter is ignored if allowComments is false.
|
|
||||||
- "allowComments": false or true
|
|
||||||
- true if comments are allowed.
|
|
||||||
- "strictRoot": false or true
|
|
||||||
- true if root must be either an array or an object value
|
|
||||||
- "allowDroppedNullPlaceholders": false or true
|
|
||||||
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
|
|
||||||
- "allowNumericKeys": false or true
|
|
||||||
- true if numeric object keys are allowed.
|
|
||||||
- "stackLimit": integer
|
|
||||||
- This is a security issue (seg-faults caused by deeply nested JSON),
|
|
||||||
so the default is low.
|
|
||||||
|
|
||||||
You can examine 'settings_` yourself
|
|
||||||
to see the defaults. You can also write and read them just like any
|
|
||||||
JSON Value.
|
|
||||||
\sa setDefaults()
|
|
||||||
*/
|
|
||||||
Json::Value settings_;
|
|
||||||
|
|
||||||
CharReaderBuilder();
|
|
||||||
virtual ~CharReaderBuilder();
|
|
||||||
|
|
||||||
virtual CharReader* newCharReader() const;
|
|
||||||
|
|
||||||
/** \return true if 'settings' are legal and consistent;
|
|
||||||
* otherwise, indicate bad settings via 'invalid'.
|
|
||||||
*/
|
|
||||||
bool validate(Json::Value* invalid) const;
|
|
||||||
/** Called by ctor, but you can use this to reset settings_.
|
|
||||||
* \pre 'settings' != NULL (but Json::null is fine)
|
|
||||||
* \remark Defaults:
|
|
||||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
|
||||||
*/
|
|
||||||
static void setDefaults(Json::Value* settings);
|
|
||||||
/** Same as old Features::strictMode().
|
|
||||||
* \pre 'settings' != NULL (but Json::null is fine)
|
|
||||||
* \remark Defaults:
|
|
||||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
|
|
||||||
*/
|
|
||||||
static void strictMode(Json::Value* settings);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Consume entire stream and use its begin/end.
|
|
||||||
* Someday we might have a real StreamReader, but for now this
|
|
||||||
* is convenient.
|
|
||||||
*/
|
|
||||||
bool parseFromStream(
|
|
||||||
CharReader::Factory const&,
|
|
||||||
std::istream&,
|
|
||||||
Value* root, std::string* errs);
|
|
||||||
|
|
||||||
/** \brief Read from 'sin' into 'root'.
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|
||||||
Always keep comments from the input JSON.
|
Always keep comments from the input JSON.
|
||||||
|
@@ -133,8 +133,7 @@ public:
|
|||||||
typedef Json::LargestUInt LargestUInt;
|
typedef Json::LargestUInt LargestUInt;
|
||||||
typedef Json::ArrayIndex ArrayIndex;
|
typedef Json::ArrayIndex ArrayIndex;
|
||||||
|
|
||||||
static const Value& null; ///! We regret this reference to a global instance; prefer the simpler Value().
|
static const Value& null;
|
||||||
static const Value& nullRef; ///! just a kludge for binary-compatibility; same as null
|
|
||||||
/// Minimum signed integer value that can be stored in a Json::Value.
|
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||||
static const LargestInt minLargestInt;
|
static const LargestInt minLargestInt;
|
||||||
/// Maximum signed integer value that can be stored in a Json::Value.
|
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||||
@@ -172,7 +171,7 @@ private:
|
|||||||
CZString(const char* cstr, DuplicationPolicy allocate);
|
CZString(const char* cstr, DuplicationPolicy allocate);
|
||||||
CZString(const CZString& other);
|
CZString(const CZString& other);
|
||||||
~CZString();
|
~CZString();
|
||||||
CZString& operator=(CZString other);
|
CZString &operator=(const CZString &other);
|
||||||
bool operator<(const CZString& other) const;
|
bool operator<(const CZString& other) const;
|
||||||
bool operator==(const CZString& other) const;
|
bool operator==(const CZString& other) const;
|
||||||
ArrayIndex index() const;
|
ArrayIndex index() const;
|
||||||
@@ -236,26 +235,25 @@ 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=(const 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;
|
||||||
@@ -393,24 +391,9 @@ 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;
|
||||||
@@ -433,10 +416,8 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
// EnumValues enumValues() const;
|
// EnumValues enumValues() const;
|
||||||
//# endif
|
//# endif
|
||||||
|
|
||||||
/// \deprecated Always pass len.
|
|
||||||
void setComment(const char* comment, CommentPlacement placement);
|
|
||||||
/// Comments must be //... or /* ... */
|
/// Comments must be //... or /* ... */
|
||||||
void setComment(const char* comment, size_t len, CommentPlacement placement);
|
void setComment(const char* comment, CommentPlacement placement);
|
||||||
/// Comments must be //... or /* ... */
|
/// Comments must be //... or /* ... */
|
||||||
void setComment(const std::string& comment, CommentPlacement placement);
|
void setComment(const std::string& comment, CommentPlacement placement);
|
||||||
bool hasComment(CommentPlacement placement) const;
|
bool hasComment(CommentPlacement placement) const;
|
||||||
@@ -459,8 +440,6 @@ Json::Value obj_value(Json::objectValue); // {}
|
|||||||
size_t getOffsetLimit() const;
|
size_t getOffsetLimit() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initBasic(ValueType type, bool allocated = false);
|
|
||||||
|
|
||||||
Value& resolveReference(const char* key, bool isStatic);
|
Value& resolveReference(const char* key, bool isStatic);
|
||||||
|
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
@@ -480,7 +459,7 @@ private:
|
|||||||
CommentInfo();
|
CommentInfo();
|
||||||
~CommentInfo();
|
~CommentInfo();
|
||||||
|
|
||||||
void setComment(const char* text, size_t len);
|
void setComment(const char* text);
|
||||||
|
|
||||||
char* comment_;
|
char* comment_;
|
||||||
};
|
};
|
||||||
@@ -508,10 +487,10 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
} value_;
|
} value_;
|
||||||
ValueType type_ : 8;
|
ValueType type_ : 8;
|
||||||
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
|
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
|
||||||
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
||||||
#endif
|
#endif
|
||||||
CommentInfo* comments_;
|
CommentInfo* comments_;
|
||||||
|
|
||||||
@@ -1100,14 +1079,6 @@ 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.4.0"
|
# define JSONCPP_VERSION_STRING "0.7.0"
|
||||||
# define JSONCPP_VERSION_MAJOR 1
|
# define JSONCPP_VERSION_MAJOR 0
|
||||||
# define JSONCPP_VERSION_MINOR 4
|
# define JSONCPP_VERSION_MINOR 7
|
||||||
# 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))
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
// be used by...
|
// be used by...
|
||||||
@@ -24,111 +23,7 @@ namespace Json {
|
|||||||
|
|
||||||
class Value;
|
class Value;
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
\code
|
|
||||||
using namespace Json;
|
|
||||||
void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
|
|
||||||
std::unique_ptr<StreamWriter> const writer(
|
|
||||||
factory.newStreamWriter());
|
|
||||||
writer->write(value, &std::cout);
|
|
||||||
std::cout << std::endl; // add lf and flush
|
|
||||||
}
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
class JSON_API StreamWriter {
|
|
||||||
protected:
|
|
||||||
std::ostream* sout_; // not owned; will not delete
|
|
||||||
public:
|
|
||||||
StreamWriter();
|
|
||||||
virtual ~StreamWriter();
|
|
||||||
/** Write Value into document as configured in sub-class.
|
|
||||||
Do not take ownership of sout, but maintain a reference during function.
|
|
||||||
\pre sout != NULL
|
|
||||||
\return zero on success
|
|
||||||
\throw std::exception possibly, depending on configuration
|
|
||||||
*/
|
|
||||||
virtual int write(Value const& root, std::ostream* sout) = 0;
|
|
||||||
|
|
||||||
/** \brief A simple abstract factory.
|
|
||||||
*/
|
|
||||||
class JSON_API Factory {
|
|
||||||
public:
|
|
||||||
virtual ~Factory();
|
|
||||||
/** \brief Allocate a CharReader via operator new().
|
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
|
||||||
*/
|
|
||||||
virtual StreamWriter* newStreamWriter() const = 0;
|
|
||||||
}; // Factory
|
|
||||||
}; // StreamWriter
|
|
||||||
|
|
||||||
/** \brief Write into stringstream, then return string, for convenience.
|
|
||||||
* A StreamWriter will be created from the factory, used, and then deleted.
|
|
||||||
*/
|
|
||||||
std::string writeString(StreamWriter::Factory const& factory, Value const& root);
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Build a StreamWriter implementation.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
\code
|
|
||||||
using namespace Json;
|
|
||||||
Value value = ...;
|
|
||||||
StreamWriterBuilder builder;
|
|
||||||
builder.settings_["commentStyle"] = "None";
|
|
||||||
builder.settings_["indentation"] = " "; // or whatever you like
|
|
||||||
std::unique_ptr<Json::StreamWriter> writer(
|
|
||||||
builder.newStreamWriter());
|
|
||||||
writer->write(value, &std::cout);
|
|
||||||
std::cout << std::endl; // add lf and flush
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
|
|
||||||
public:
|
|
||||||
// Note: We use a Json::Value so that we can add data-members to this class
|
|
||||||
// without a major version bump.
|
|
||||||
/** Configuration of this builder.
|
|
||||||
Available settings (case-sensitive):
|
|
||||||
- "commentStyle": "None" or "All"
|
|
||||||
- "indentation": "<anything>"
|
|
||||||
- "enableYAMLCompatibility": false or true
|
|
||||||
- slightly change the whitespace around colons
|
|
||||||
- "dropNullPlaceholders": false or true
|
|
||||||
- Drop the "null" string from the writer's output for nullValues.
|
|
||||||
Strictly speaking, this is not valid JSON. But when the output is being
|
|
||||||
fed to a browser's Javascript, it makes for smaller output and the
|
|
||||||
browser can handle the output just fine.
|
|
||||||
|
|
||||||
You can examine 'settings_` yourself
|
|
||||||
to see the defaults. You can also write and read them just like any
|
|
||||||
JSON Value.
|
|
||||||
\sa setDefaults()
|
|
||||||
*/
|
|
||||||
Json::Value settings_;
|
|
||||||
|
|
||||||
StreamWriterBuilder();
|
|
||||||
virtual ~StreamWriterBuilder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
|
||||||
*/
|
|
||||||
virtual StreamWriter* newStreamWriter() const;
|
|
||||||
|
|
||||||
/** \return true if 'settings' are legal and consistent;
|
|
||||||
* otherwise, indicate bad settings via 'invalid'.
|
|
||||||
*/
|
|
||||||
bool validate(Json::Value* invalid) const;
|
|
||||||
/** Called by ctor, but you can use this to reset settings_.
|
|
||||||
* \pre 'settings' != NULL (but Json::null is fine)
|
|
||||||
* \remark Defaults:
|
|
||||||
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
|
|
||||||
*/
|
|
||||||
static void setDefaults(Json::Value* settings);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
* \deprecated Use StreamWriter.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API Writer {
|
class JSON_API Writer {
|
||||||
public:
|
public:
|
||||||
@@ -144,7 +39,6 @@ public:
|
|||||||
*consumption,
|
*consumption,
|
||||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||||
* \sa Reader, Value
|
* \sa Reader, Value
|
||||||
* \deprecated Use StreamWriterBuilder.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API FastWriter : public Writer {
|
class JSON_API FastWriter : public Writer {
|
||||||
public:
|
public:
|
||||||
@@ -196,7 +90,6 @@ private:
|
|||||||
*#CommentPlacement.
|
*#CommentPlacement.
|
||||||
*
|
*
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
* \deprecated Use StreamWriterBuilder.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledWriter : public Writer {
|
class JSON_API StyledWriter : public Writer {
|
||||||
public:
|
public:
|
||||||
@@ -258,7 +151,6 @@ private:
|
|||||||
*
|
*
|
||||||
* \param indentation Each level will be indented by this amount extra.
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
* \deprecated Use StreamWriterBuilder.
|
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledStreamWriter {
|
class JSON_API StyledStreamWriter {
|
||||||
public:
|
public:
|
||||||
@@ -295,8 +187,7 @@ private:
|
|||||||
std::string indentString_;
|
std::string indentString_;
|
||||||
int rightMargin_;
|
int rightMargin_;
|
||||||
std::string indentation_;
|
std::string indentation_;
|
||||||
bool addChildValues_ : 1;
|
bool addChildValues_;
|
||||||
bool indented_ : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(JSON_HAS_INT64)
|
#if defined(JSON_HAS_INT64)
|
||||||
|
@@ -14,7 +14,6 @@ python makerelease.py 0.5.0 0.6.0-dev
|
|||||||
Note: This was for Subversion. Now that we are in GitHub, we do not
|
Note: This was for Subversion. Now that we are in GitHub, we do not
|
||||||
need to build versioned tarballs anymore, so makerelease.py is defunct.
|
need to build versioned tarballs anymore, so makerelease.py is defunct.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -47,7 +46,7 @@ class SVNError(Exception):
|
|||||||
|
|
||||||
def svn_command( command, *args ):
|
def svn_command( command, *args ):
|
||||||
cmd = ['svn', '--non-interactive', command] + list(args)
|
cmd = ['svn', '--non-interactive', command] + list(args)
|
||||||
print('Running:', ' '.join(cmd))
|
print 'Running:', ' '.join( cmd )
|
||||||
process = subprocess.Popen( cmd,
|
process = subprocess.Popen( cmd,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT )
|
stderr=subprocess.STDOUT )
|
||||||
@@ -85,7 +84,7 @@ def svn_check_if_tag_exist(tag_url):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
list_stdout = svn_command( 'list', tag_url )
|
list_stdout = svn_command( 'list', tag_url )
|
||||||
except SVNError as e:
|
except SVNError, e:
|
||||||
if e.returncode != 1 or not str(e).find('tag_url'):
|
if e.returncode != 1 or not str(e).find('tag_url'):
|
||||||
raise e
|
raise e
|
||||||
# otherwise ignore error, meaning tag does not exist
|
# otherwise ignore error, meaning tag does not exist
|
||||||
@@ -118,7 +117,7 @@ def svn_export(tag_url, export_dir):
|
|||||||
def fix_sources_eol( dist_dir ):
|
def fix_sources_eol( dist_dir ):
|
||||||
"""Set file EOL for tarball distribution.
|
"""Set file EOL for tarball distribution.
|
||||||
"""
|
"""
|
||||||
print('Preparing exported source file EOL for distribution...')
|
print 'Preparing exported source file EOL for distribution...'
|
||||||
prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
|
prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
|
||||||
win_sources = antglob.glob( dist_dir,
|
win_sources = antglob.glob( dist_dir,
|
||||||
includes = '**/*.sln **/*.vcproj',
|
includes = '**/*.sln **/*.vcproj',
|
||||||
@@ -149,7 +148,7 @@ def download(url, target_path):
|
|||||||
|
|
||||||
def check_compile( distcheck_top_dir, platform ):
|
def check_compile( distcheck_top_dir, platform ):
|
||||||
cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
|
cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
|
||||||
print('Running:', ' '.join(cmd))
|
print 'Running:', ' '.join( cmd )
|
||||||
log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
|
log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
|
||||||
flog = open( log_path, 'wb' )
|
flog = open( log_path, 'wb' )
|
||||||
try:
|
try:
|
||||||
@@ -180,9 +179,9 @@ def run_sftp_batch(userhost, sftp, batch, retry=0):
|
|||||||
# psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
|
# psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
|
||||||
cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
|
cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
|
||||||
error = None
|
error = None
|
||||||
for retry_index in range(0, max(1,retry)):
|
for retry_index in xrange(0, max(1,retry)):
|
||||||
heading = retry_index == 0 and 'Running:' or 'Retrying:'
|
heading = retry_index == 0 and 'Running:' or 'Retrying:'
|
||||||
print(heading, ' '.join(cmd))
|
print heading, ' '.join( cmd )
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
||||||
stdout = process.communicate()[0]
|
stdout = process.communicate()[0]
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
@@ -220,21 +219,21 @@ exit
|
|||||||
upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
|
upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
|
||||||
paths_to_remove = existing_paths - upload_paths
|
paths_to_remove = existing_paths - upload_paths
|
||||||
if paths_to_remove:
|
if paths_to_remove:
|
||||||
print('Removing the following file from web:')
|
print 'Removing the following file from web:'
|
||||||
print('\n'.join(paths_to_remove))
|
print '\n'.join( paths_to_remove )
|
||||||
stdout = run_sftp_batch( userhost, sftp, """cd htdocs
|
stdout = run_sftp_batch( userhost, sftp, """cd htdocs
|
||||||
rm %s
|
rm %s
|
||||||
exit""" % ' '.join(paths_to_remove) )
|
exit""" % ' '.join(paths_to_remove) )
|
||||||
print('Uploading %d files:' % len(upload_paths))
|
print 'Uploading %d files:' % len(upload_paths)
|
||||||
batch_size = 10
|
batch_size = 10
|
||||||
upload_paths = list(upload_paths)
|
upload_paths = list(upload_paths)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
for index in range(0,len(upload_paths),batch_size):
|
for index in xrange(0,len(upload_paths),batch_size):
|
||||||
paths = upload_paths[index:index+batch_size]
|
paths = upload_paths[index:index+batch_size]
|
||||||
file_per_sec = (time.time() - start_time) / (index+1)
|
file_per_sec = (time.time() - start_time) / (index+1)
|
||||||
remaining_files = len(upload_paths) - index
|
remaining_files = len(upload_paths) - index
|
||||||
remaining_sec = file_per_sec * remaining_files
|
remaining_sec = file_per_sec * remaining_files
|
||||||
print('%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec))
|
print '%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec)
|
||||||
run_sftp_batch( userhost, sftp, """cd htdocs
|
run_sftp_batch( userhost, sftp, """cd htdocs
|
||||||
lcd %s
|
lcd %s
|
||||||
mput %s
|
mput %s
|
||||||
@@ -298,7 +297,7 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
else:
|
else:
|
||||||
msg = check_no_pending_commit()
|
msg = check_no_pending_commit()
|
||||||
if not msg:
|
if not msg:
|
||||||
print('Setting version to', release_version)
|
print 'Setting version to', release_version
|
||||||
set_version( release_version )
|
set_version( release_version )
|
||||||
svn_commit( 'Release ' + release_version )
|
svn_commit( 'Release ' + release_version )
|
||||||
tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
|
tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
|
||||||
@@ -306,11 +305,11 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
if options.retag_release:
|
if options.retag_release:
|
||||||
svn_remove_tag( tag_url, 'Overwriting previous tag' )
|
svn_remove_tag( tag_url, 'Overwriting previous tag' )
|
||||||
else:
|
else:
|
||||||
print('Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url)
|
print 'Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url
|
||||||
sys.exit( 1 )
|
sys.exit( 1 )
|
||||||
svn_tag_sandbox( tag_url, 'Release ' + release_version )
|
svn_tag_sandbox( tag_url, 'Release ' + release_version )
|
||||||
|
|
||||||
print('Generated doxygen document...')
|
print 'Generated doxygen document...'
|
||||||
## doc_dirname = r'jsoncpp-api-html-0.5.0'
|
## doc_dirname = r'jsoncpp-api-html-0.5.0'
|
||||||
## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
|
## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
|
||||||
doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
|
doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
|
||||||
@@ -324,11 +323,11 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
|
|
||||||
source_dir = 'jsoncpp-src-' + release_version
|
source_dir = 'jsoncpp-src-' + release_version
|
||||||
source_tarball_path = 'dist/%s.tar.gz' % source_dir
|
source_tarball_path = 'dist/%s.tar.gz' % source_dir
|
||||||
print('Generating source tarball to', source_tarball_path)
|
print 'Generating source tarball to', source_tarball_path
|
||||||
tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
|
tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
|
||||||
|
|
||||||
amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir
|
amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir
|
||||||
print('Generating amalgamation source tarball to', amalgamation_tarball_path)
|
print 'Generating amalgamation source tarball to', amalgamation_tarball_path
|
||||||
amalgamation_dir = 'dist/amalgamation'
|
amalgamation_dir = 'dist/amalgamation'
|
||||||
amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' )
|
amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' )
|
||||||
amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version
|
amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version
|
||||||
@@ -338,41 +337,41 @@ Warning: --force should only be used when developping/testing the release script
|
|||||||
# Decompress source tarball, download and install scons-local
|
# Decompress source tarball, download and install scons-local
|
||||||
distcheck_dir = 'dist/distcheck'
|
distcheck_dir = 'dist/distcheck'
|
||||||
distcheck_top_dir = distcheck_dir + '/' + source_dir
|
distcheck_top_dir = distcheck_dir + '/' + source_dir
|
||||||
print('Decompressing source tarball to', distcheck_dir)
|
print 'Decompressing source tarball to', distcheck_dir
|
||||||
rmdir_if_exist( distcheck_dir )
|
rmdir_if_exist( distcheck_dir )
|
||||||
tarball.decompress( source_tarball_path, distcheck_dir )
|
tarball.decompress( source_tarball_path, distcheck_dir )
|
||||||
scons_local_path = 'dist/scons-local.tar.gz'
|
scons_local_path = 'dist/scons-local.tar.gz'
|
||||||
print('Downloading scons-local to', scons_local_path)
|
print 'Downloading scons-local to', scons_local_path
|
||||||
download( SCONS_LOCAL_URL, scons_local_path )
|
download( SCONS_LOCAL_URL, scons_local_path )
|
||||||
print('Decompressing scons-local to', distcheck_top_dir)
|
print 'Decompressing scons-local to', distcheck_top_dir
|
||||||
tarball.decompress( scons_local_path, distcheck_top_dir )
|
tarball.decompress( scons_local_path, distcheck_top_dir )
|
||||||
|
|
||||||
# Run compilation
|
# Run compilation
|
||||||
print('Compiling decompressed tarball')
|
print 'Compiling decompressed tarball'
|
||||||
all_build_status = True
|
all_build_status = True
|
||||||
for platform in options.platforms.split(','):
|
for platform in options.platforms.split(','):
|
||||||
print('Testing platform:', platform)
|
print 'Testing platform:', platform
|
||||||
build_status, log_path = check_compile( distcheck_top_dir, platform )
|
build_status, log_path = check_compile( distcheck_top_dir, platform )
|
||||||
print('see build log:', log_path)
|
print 'see build log:', log_path
|
||||||
print(build_status and '=> ok' or '=> FAILED')
|
print build_status and '=> ok' or '=> FAILED'
|
||||||
all_build_status = all_build_status and build_status
|
all_build_status = all_build_status and build_status
|
||||||
if not build_status:
|
if not build_status:
|
||||||
print('Testing failed on at least one platform, aborting...')
|
print 'Testing failed on at least one platform, aborting...'
|
||||||
svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
|
svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if options.user:
|
if options.user:
|
||||||
if not options.no_web:
|
if not options.no_web:
|
||||||
print('Uploading documentation using user', options.user)
|
print 'Uploading documentation using user', options.user
|
||||||
sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
|
sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
|
||||||
print('Completed documentation upload')
|
print 'Completed documentation upload'
|
||||||
print('Uploading source and documentation tarballs for release using user', options.user)
|
print 'Uploading source and documentation tarballs for release using user', options.user
|
||||||
sourceforge_release_tarball( SOURCEFORGE_PROJECT,
|
sourceforge_release_tarball( SOURCEFORGE_PROJECT,
|
||||||
[source_tarball_path, doc_tarball_path],
|
[source_tarball_path, doc_tarball_path],
|
||||||
user=options.user, sftp=options.sftp )
|
user=options.user, sftp=options.sftp )
|
||||||
print('Source and doc release tarballs uploaded')
|
print 'Source and doc release tarballs uploaded'
|
||||||
else:
|
else:
|
||||||
print('No upload user specified. Web site and download tarbal were not uploaded.')
|
print 'No upload user specified. Web site and download tarbal were not uploaded.'
|
||||||
print('Tarball can be found at:', doc_tarball_path)
|
print 'Tarball can be found at:', doc_tarball_path
|
||||||
|
|
||||||
# Set next version number and commit
|
# Set next version number and commit
|
||||||
set_version( next_version )
|
set_version( next_version )
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
exec_prefix=${prefix}
|
exec_prefix=${prefix}
|
||||||
libdir=${exec_prefix}/@LIBRARY_INSTALL_DIR@
|
libdir=${exec_prefix}/lib
|
||||||
includedir=${prefix}/@INCLUDE_INSTALL_DIR@
|
includedir=${prefix}/include
|
||||||
|
|
||||||
Name: jsoncpp
|
Name: jsoncpp
|
||||||
Description: A C++ library for interacting with JSON
|
Description: A C++ library for interacting with JSON
|
||||||
|
@@ -161,7 +161,8 @@ def generate(env):
|
|||||||
Add builders and construction variables for the
|
Add builders and construction variables for the
|
||||||
SrcDist tool.
|
SrcDist tool.
|
||||||
"""
|
"""
|
||||||
## doxyfile_scanner = env.Scanner(## DoxySourceScan,
|
## doxyfile_scanner = env.Scanner(
|
||||||
|
## DoxySourceScan,
|
||||||
## "DoxySourceScan",
|
## "DoxySourceScan",
|
||||||
## scan_check = DoxySourceScanCheck,
|
## scan_check = DoxySourceScanCheck,
|
||||||
## )
|
## )
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
from SCons.Script import * # the usual scons stuff you get in a SConscript
|
from SCons.Script import * # the usual scons stuff you get in a SConscript
|
||||||
import collections
|
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
"""
|
"""
|
||||||
@@ -26,28 +25,28 @@ def generate(env):
|
|||||||
contents = f.read()
|
contents = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
raise SCons.Errors.UserError("Can't read source file %s"%sourcefile)
|
raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
|
||||||
for (k,v) in list(dict.items()):
|
for (k,v) in dict.items():
|
||||||
contents = re.sub(k, v, contents)
|
contents = re.sub(k, v, contents)
|
||||||
try:
|
try:
|
||||||
f = open(targetfile, 'wb')
|
f = open(targetfile, 'wb')
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
f.close()
|
f.close()
|
||||||
except:
|
except:
|
||||||
raise SCons.Errors.UserError("Can't write target file %s"%targetfile)
|
raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
|
||||||
return 0 # success
|
return 0 # success
|
||||||
|
|
||||||
def subst_in_file(target, source, env):
|
def subst_in_file(target, source, env):
|
||||||
if 'SUBST_DICT' not in env:
|
if not env.has_key('SUBST_DICT'):
|
||||||
raise SCons.Errors.UserError("SubstInFile requires SUBST_DICT to be set.")
|
raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
|
||||||
d = dict(env['SUBST_DICT']) # copy it
|
d = dict(env['SUBST_DICT']) # copy it
|
||||||
for (k,v) in list(d.items()):
|
for (k,v) in d.items():
|
||||||
if isinstance(v, collections.Callable):
|
if callable(v):
|
||||||
d[k] = env.subst(v()).replace('\\','\\\\')
|
d[k] = env.subst(v()).replace('\\','\\\\')
|
||||||
elif SCons.Util.is_String(v):
|
elif SCons.Util.is_String(v):
|
||||||
d[k] = env.subst(v).replace('\\','\\\\')
|
d[k] = env.subst(v).replace('\\','\\\\')
|
||||||
else:
|
else:
|
||||||
raise SCons.Errors.UserError("SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)))
|
raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
|
||||||
for (t,s) in zip(target, source):
|
for (t,s) in zip(target, source):
|
||||||
return do_subst_in_file(str(t), str(s), d)
|
return do_subst_in_file(str(t), str(s), d)
|
||||||
|
|
||||||
@@ -61,8 +60,8 @@ def generate(env):
|
|||||||
Returns original target, source tuple unchanged.
|
Returns original target, source tuple unchanged.
|
||||||
"""
|
"""
|
||||||
d = env['SUBST_DICT'].copy() # copy it
|
d = env['SUBST_DICT'].copy() # copy it
|
||||||
for (k,v) in list(d.items()):
|
for (k,v) in d.items():
|
||||||
if isinstance(v, collections.Callable):
|
if callable(v):
|
||||||
d[k] = env.subst(v())
|
d[k] = env.subst(v())
|
||||||
elif SCons.Util.is_String(v):
|
elif SCons.Util.is_String(v):
|
||||||
d[k]=env.subst(v)
|
d[k]=env.subst(v)
|
||||||
|
@@ -7,13 +7,7 @@ ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|||||||
ADD_EXECUTABLE(jsontestrunner_exe
|
ADD_EXECUTABLE(jsontestrunner_exe
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
|
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib)
|
||||||
ELSE(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
TARGET_LINK_LIBRARIES(jsontestrunner_exe jsoncpp_lib_static)
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
|
SET_TARGET_PROPERTIES(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
|
||||||
|
|
||||||
IF(PYTHONINTERP_FOUND)
|
IF(PYTHONINTERP_FOUND)
|
||||||
|
@@ -8,22 +8,12 @@
|
|||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <algorithm> // sort
|
#include <algorithm> // sort
|
||||||
#include <sstream>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||||
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Options
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
Json::Features features;
|
|
||||||
bool parseOnly;
|
|
||||||
typedef std::string (*writeFuncType)(Json::Value const&);
|
|
||||||
writeFuncType write;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::string normalizeFloatingPointStr(double value) {
|
static std::string normalizeFloatingPointStr(double value) {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||||
@@ -139,67 +129,43 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
|
|||||||
static int parseAndSaveValueTree(const std::string& input,
|
static int parseAndSaveValueTree(const std::string& input,
|
||||||
const std::string& actual,
|
const std::string& actual,
|
||||||
const std::string& kind,
|
const std::string& kind,
|
||||||
|
Json::Value& root,
|
||||||
const Json::Features& features,
|
const Json::Features& features,
|
||||||
bool parseOnly,
|
bool parseOnly) {
|
||||||
Json::Value* root)
|
|
||||||
{
|
|
||||||
Json::Reader reader(features);
|
Json::Reader reader(features);
|
||||||
bool parsingSuccessful = reader.parse(input, *root);
|
bool parsingSuccessful = reader.parse(input, root);
|
||||||
if (!parsingSuccessful) {
|
if (!parsingSuccessful) {
|
||||||
printf("Failed to parse %s file: \n%s\n",
|
printf("Failed to parse %s file: \n%s\n",
|
||||||
kind.c_str(),
|
kind.c_str(),
|
||||||
reader.getFormattedErrorMessages().c_str());
|
reader.getFormattedErrorMessages().c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseOnly) {
|
if (!parseOnly) {
|
||||||
FILE* factual = fopen(actual.c_str(), "wt");
|
FILE* factual = fopen(actual.c_str(), "wt");
|
||||||
if (!factual) {
|
if (!factual) {
|
||||||
printf("Failed to create %s actual file.\n", kind.c_str());
|
printf("Failed to create %s actual file.\n", kind.c_str());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
printValueTree(factual, *root);
|
printValueTree(factual, root);
|
||||||
fclose(factual);
|
fclose(factual);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// static std::string useFastWriter(Json::Value const& root) {
|
|
||||||
|
static int rewriteValueTree(const std::string& rewritePath,
|
||||||
|
const Json::Value& root,
|
||||||
|
std::string& rewrite) {
|
||||||
// Json::FastWriter writer;
|
// Json::FastWriter writer;
|
||||||
// writer.enableYAMLCompatibility();
|
// writer.enableYAMLCompatibility();
|
||||||
// return writer.write(root);
|
|
||||||
// }
|
|
||||||
static std::string useStyledWriter(
|
|
||||||
Json::Value const& root)
|
|
||||||
{
|
|
||||||
Json::StyledWriter writer;
|
Json::StyledWriter writer;
|
||||||
return writer.write(root);
|
rewrite = writer.write(root);
|
||||||
}
|
|
||||||
static std::string useStyledStreamWriter(
|
|
||||||
Json::Value const& root)
|
|
||||||
{
|
|
||||||
Json::StyledStreamWriter writer;
|
|
||||||
std::ostringstream sout;
|
|
||||||
writer.write(sout, root);
|
|
||||||
return sout.str();
|
|
||||||
}
|
|
||||||
static std::string useBuiltStyledStreamWriter(
|
|
||||||
Json::Value const& root)
|
|
||||||
{
|
|
||||||
Json::StreamWriterBuilder builder;
|
|
||||||
return Json::writeString(builder, root);
|
|
||||||
}
|
|
||||||
static int rewriteValueTree(
|
|
||||||
const std::string& rewritePath,
|
|
||||||
const Json::Value& root,
|
|
||||||
Options::writeFuncType write,
|
|
||||||
std::string* rewrite)
|
|
||||||
{
|
|
||||||
*rewrite = write(root);
|
|
||||||
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
||||||
if (!fout) {
|
if (!fout) {
|
||||||
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
fprintf(fout, "%s\n", rewrite->c_str());
|
fprintf(fout, "%s\n", rewrite.c_str());
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -228,98 +194,84 @@ static int printUsage(const char* argv[]) {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parseCommandLine(
|
int parseCommandLine(int argc,
|
||||||
int argc, const char* argv[], Options* opts)
|
const char* argv[],
|
||||||
{
|
Json::Features& features,
|
||||||
opts->parseOnly = false;
|
std::string& path,
|
||||||
opts->write = &useStyledWriter;
|
bool& parseOnly) {
|
||||||
|
parseOnly = false;
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
return printUsage(argv);
|
return printUsage(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
if (std::string(argv[index]) == "--json-checker") {
|
if (std::string(argv[1]) == "--json-checker") {
|
||||||
opts->features = Json::Features::strictMode();
|
features = Json::Features::strictMode();
|
||||||
opts->parseOnly = true;
|
parseOnly = true;
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
if (std::string(argv[index]) == "--json-config") {
|
|
||||||
|
if (std::string(argv[1]) == "--json-config") {
|
||||||
printConfig();
|
printConfig();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
if (std::string(argv[index]) == "--json-writer") {
|
|
||||||
++index;
|
|
||||||
std::string const writerName(argv[index++]);
|
|
||||||
if (writerName == "StyledWriter") {
|
|
||||||
opts->write = &useStyledWriter;
|
|
||||||
} else if (writerName == "StyledStreamWriter") {
|
|
||||||
opts->write = &useStyledStreamWriter;
|
|
||||||
} else if (writerName == "BuiltStyledStreamWriter") {
|
|
||||||
opts->write = &useBuiltStyledStreamWriter;
|
|
||||||
} else {
|
|
||||||
printf("Unknown '--json-writer %s'\n", writerName.c_str());
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index == argc || index + 1 < argc) {
|
if (index == argc || index + 1 < argc) {
|
||||||
return printUsage(argv);
|
return printUsage(argv);
|
||||||
}
|
}
|
||||||
opts->path = argv[index];
|
|
||||||
|
path = argv[index];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int runTest(Options const& opts)
|
|
||||||
{
|
|
||||||
int exitCode = 0;
|
|
||||||
|
|
||||||
std::string input = readInputTestFile(opts.path.c_str());
|
int main(int argc, const char* argv[]) {
|
||||||
|
std::string path;
|
||||||
|
Json::Features features;
|
||||||
|
bool parseOnly;
|
||||||
|
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::string input = readInputTestFile(path.c_str());
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
printf("Failed to read input or empty input: %s\n", opts.path.c_str());
|
printf("Failed to read input or empty input: %s\n", path.c_str());
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string basePath = removeSuffix(opts.path, ".json");
|
std::string basePath = removeSuffix(argv[1], ".json");
|
||||||
if (!opts.parseOnly && basePath.empty()) {
|
if (!parseOnly && basePath.empty()) {
|
||||||
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
||||||
opts.path.c_str());
|
path.c_str());
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const actualPath = basePath + ".actual";
|
std::string actualPath = basePath + ".actual";
|
||||||
std::string const rewritePath = basePath + ".rewrite";
|
std::string rewritePath = basePath + ".rewrite";
|
||||||
std::string const rewriteActualPath = basePath + ".actual-rewrite";
|
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
exitCode = parseAndSaveValueTree(
|
exitCode = parseAndSaveValueTree(
|
||||||
input, actualPath, "input",
|
input, actualPath, "input", root, features, parseOnly);
|
||||||
opts.features, opts.parseOnly, &root);
|
if (exitCode == 0 && !parseOnly) {
|
||||||
if (exitCode || opts.parseOnly) {
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
std::string rewrite;
|
std::string rewrite;
|
||||||
exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite);
|
exitCode = rewriteValueTree(rewritePath, root, rewrite);
|
||||||
if (exitCode) {
|
if (exitCode == 0) {
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
Json::Value rewriteRoot;
|
Json::Value rewriteRoot;
|
||||||
exitCode = parseAndSaveValueTree(
|
exitCode = parseAndSaveValueTree(rewrite,
|
||||||
rewrite, rewriteActualPath, "rewrite",
|
rewriteActualPath,
|
||||||
opts.features, opts.parseOnly, &rewriteRoot);
|
"rewrite",
|
||||||
if (exitCode) {
|
rewriteRoot,
|
||||||
return exitCode;
|
features,
|
||||||
|
parseOnly);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
int main(int argc, const char* argv[]) {
|
|
||||||
Options opts;
|
|
||||||
int exitCode = parseCommandLine(argc, argv, &opts);
|
|
||||||
if (exitCode != 0) {
|
|
||||||
printf("Failed to parse command-line.");
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return runTest(opts);
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
printf("Unhandled exception:\n%s\n", e.what());
|
printf("Unhandled exception:\n%s\n", e.what());
|
||||||
return 1;
|
exitCode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,14 @@
|
|||||||
OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF)
|
OPTION(JSONCPP_LIB_BUILD_SHARED "Build jsoncpp_lib as a shared library." OFF)
|
||||||
OPTION(JSONCPP_LIB_BUILD_STATIC "Build jsoncpp_lib static library." ON)
|
IF(JSONCPP_LIB_BUILD_SHARED)
|
||||||
|
SET(JSONCPP_LIB_TYPE SHARED)
|
||||||
|
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
|
||||||
|
ELSE(JSONCPP_LIB_BUILD_SHARED)
|
||||||
|
SET(JSONCPP_LIB_TYPE STATIC)
|
||||||
|
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
||||||
|
|
||||||
IF(BUILD_SHARED_LIBS)
|
|
||||||
SET(JSONCPP_LIB_BUILD_SHARED ON)
|
|
||||||
ENDIF(BUILD_SHARED_LIBS)
|
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
#Get compiler version.
|
|
||||||
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
|
|
||||||
OUTPUT_VARIABLE GNUCXX_VERSION )
|
|
||||||
|
|
||||||
#-Werror=* was introduced -after- GCC 4.1.2
|
|
||||||
if( GNUCXX_VERSION VERSION_GREATER 4.1.2 )
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
|
||||||
endif()
|
|
||||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
|
|
||||||
SET( JSONCPP_INCLUDE_DIR ../../include )
|
SET( JSONCPP_INCLUDE_DIR ../../include )
|
||||||
@@ -31,56 +26,32 @@ SET( PUBLIC_HEADERS
|
|||||||
|
|
||||||
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
|
SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
|
||||||
|
|
||||||
SET(jsoncpp_sources
|
ADD_LIBRARY( jsoncpp_lib ${JSONCPP_LIB_TYPE}
|
||||||
|
${PUBLIC_HEADERS}
|
||||||
json_tool.h
|
json_tool.h
|
||||||
json_reader.cpp
|
json_reader.cpp
|
||||||
json_batchallocator.h
|
json_batchallocator.h
|
||||||
json_valueiterator.inl
|
json_valueiterator.inl
|
||||||
json_value.cpp
|
json_value.cpp
|
||||||
json_writer.cpp
|
json_writer.cpp
|
||||||
version.h.in)
|
version.h.in
|
||||||
|
)
|
||||||
|
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
|
||||||
|
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR} )
|
||||||
|
|
||||||
# Install instructions for this target
|
# Install instructions for this target
|
||||||
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
IF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||||
|
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib
|
||||||
|
PUBLIC $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSON_INCLUDE_DIR}>
|
||||||
|
)
|
||||||
SET(INSTALL_EXPORT EXPORT jsoncpp)
|
SET(INSTALL_EXPORT EXPORT jsoncpp)
|
||||||
ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
|
ELSE(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||||
SET(INSTALL_EXPORT)
|
SET(INSTALL_EXPORT)
|
||||||
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
|
ENDIF(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
ADD_DEFINITIONS( -DJSON_DLL_BUILD )
|
|
||||||
ADD_LIBRARY(jsoncpp_lib SHARED ${PUBLIC_HEADERS} ${jsoncpp_sources})
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp )
|
|
||||||
|
|
||||||
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
|
INSTALL( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
|
||||||
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
||||||
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
|
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
|
||||||
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR})
|
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR}
|
||||||
|
|
||||||
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib PUBLIC
|
|
||||||
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>)
|
|
||||||
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_STATIC)
|
|
||||||
ADD_LIBRARY(jsoncpp_lib_static STATIC ${PUBLIC_HEADERS} ${jsoncpp_sources})
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_VERSION_MAJOR})
|
|
||||||
SET_TARGET_PROPERTIES( jsoncpp_lib_static PROPERTIES OUTPUT_NAME jsoncpp )
|
|
||||||
|
|
||||||
INSTALL( TARGETS jsoncpp_lib_static ${INSTALL_EXPORT}
|
|
||||||
RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR}
|
|
||||||
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
|
|
||||||
ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR})
|
|
||||||
|
|
||||||
IF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
TARGET_INCLUDE_DIRECTORIES( jsoncpp_lib_static PUBLIC
|
|
||||||
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
|
||||||
)
|
)
|
||||||
ENDIF(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
|
||||||
|
|
||||||
ENDIF()
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,6 @@ namespace Json {
|
|||||||
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
||||||
const unsigned char& kNullRef = kNull[0];
|
const unsigned char& kNullRef = kNull[0];
|
||||||
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
|
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
|
||||||
const Value& Value::nullRef = null;
|
|
||||||
|
|
||||||
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
||||||
const Int Value::maxInt = Int(UInt(-1) / 2);
|
const Int Value::maxInt = Int(UInt(-1) / 2);
|
||||||
@@ -142,17 +141,15 @@ Value::CommentInfo::~CommentInfo() {
|
|||||||
releaseStringValue(comment_);
|
releaseStringValue(comment_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::CommentInfo::setComment(const char* text, size_t len) {
|
void Value::CommentInfo::setComment(const char* text) {
|
||||||
if (comment_) {
|
if (comment_)
|
||||||
releaseStringValue(comment_);
|
releaseStringValue(comment_);
|
||||||
comment_ = 0;
|
|
||||||
}
|
|
||||||
JSON_ASSERT(text != 0);
|
JSON_ASSERT(text != 0);
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE(
|
||||||
text[0] == '\0' || text[0] == '/',
|
text[0] == '\0' || text[0] == '/',
|
||||||
"in Json::Value::setComment(): Comments must start with /");
|
"in Json::Value::setComment(): Comments must start with /");
|
||||||
// It seems that /**/ style comments are acceptable as well.
|
// It seems that /**/ style comments are acceptable as well.
|
||||||
comment_ = duplicateStringValue(text, len);
|
comment_ = duplicateStringValue(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@@ -178,8 +175,7 @@ Value::CZString::CZString(const CZString& other)
|
|||||||
? duplicateStringValue(other.cstr_)
|
? duplicateStringValue(other.cstr_)
|
||||||
: other.cstr_),
|
: other.cstr_),
|
||||||
index_(other.cstr_
|
index_(other.cstr_
|
||||||
? static_cast<ArrayIndex>(other.index_ == noDuplication
|
? (other.index_ == noDuplication ? noDuplication : duplicate)
|
||||||
? noDuplication : duplicate)
|
|
||||||
: other.index_) {}
|
: other.index_) {}
|
||||||
|
|
||||||
Value::CZString::~CZString() {
|
Value::CZString::~CZString() {
|
||||||
@@ -192,8 +188,9 @@ void Value::CZString::swap(CZString& other) {
|
|||||||
std::swap(index_, other.index_);
|
std::swap(index_, other.index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::CZString& Value::CZString::operator=(CZString other) {
|
Value::CZString &Value::CZString::operator=(const CZString &other) {
|
||||||
swap(other);
|
CZString temp(other);
|
||||||
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +226,14 @@ bool Value::CZString::isStaticString() const { return index_ == noDuplication; }
|
|||||||
* memset( this, 0, sizeof(Value) )
|
* memset( this, 0, sizeof(Value) )
|
||||||
* This optimization is used in ValueInternalMap fast allocator.
|
* This optimization is used in ValueInternalMap fast allocator.
|
||||||
*/
|
*/
|
||||||
Value::Value(ValueType type) {
|
Value::Value(ValueType type)
|
||||||
initBasic(type);
|
: type_(type), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case nullValue:
|
case nullValue:
|
||||||
break;
|
break;
|
||||||
@@ -265,62 +268,130 @@ Value::Value(ValueType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(Int value) {
|
Value::Value(UInt value)
|
||||||
initBasic(intValue);
|
: type_(uintValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
|
value_.uint_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Value(Int value)
|
||||||
|
: type_(intValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.int_ = value;
|
value_.int_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(UInt value) {
|
|
||||||
initBasic(uintValue);
|
|
||||||
value_.uint_ = value;
|
|
||||||
}
|
|
||||||
#if defined(JSON_HAS_INT64)
|
#if defined(JSON_HAS_INT64)
|
||||||
Value::Value(Int64 value) {
|
Value::Value(Int64 value)
|
||||||
initBasic(intValue);
|
: type_(intValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.int_ = value;
|
value_.int_ = value;
|
||||||
}
|
}
|
||||||
Value::Value(UInt64 value) {
|
|
||||||
initBasic(uintValue);
|
Value::Value(UInt64 value)
|
||||||
|
: type_(uintValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.uint_ = value;
|
value_.uint_ = value;
|
||||||
}
|
}
|
||||||
#endif // defined(JSON_HAS_INT64)
|
#endif // defined(JSON_HAS_INT64)
|
||||||
|
|
||||||
Value::Value(double value) {
|
Value::Value(double value)
|
||||||
initBasic(realValue);
|
: type_(realValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.real_ = value;
|
value_.real_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const char* value) {
|
Value::Value(const char* value)
|
||||||
initBasic(stringValue, true);
|
: type_(stringValue), allocated_(true)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.string_ = duplicateStringValue(value);
|
value_.string_ = duplicateStringValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const char* beginValue, const char* endValue) {
|
Value::Value(const char* beginValue, const char* endValue)
|
||||||
initBasic(stringValue, true);
|
: type_(stringValue), allocated_(true)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.string_ =
|
value_.string_ =
|
||||||
duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue));
|
duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const std::string& value) {
|
Value::Value(const std::string& value)
|
||||||
initBasic(stringValue, true);
|
: type_(stringValue), allocated_(true)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.string_ =
|
value_.string_ =
|
||||||
duplicateStringValue(value.c_str(), (unsigned int)value.length());
|
duplicateStringValue(value.c_str(), (unsigned int)value.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(const StaticString& value) {
|
Value::Value(const StaticString& value)
|
||||||
initBasic(stringValue);
|
: type_(stringValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.string_ = const_cast<char*>(value.c_str());
|
value_.string_ = const_cast<char*>(value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
Value::Value(const CppTL::ConstString& value) {
|
Value::Value(const CppTL::ConstString& value)
|
||||||
initBasic(stringValue, true);
|
: type_(stringValue), allocated_(true)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.string_ = duplicateStringValue(value, value.length());
|
value_.string_ = duplicateStringValue(value, value.length());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Value::Value(bool value) {
|
Value::Value(bool value)
|
||||||
initBasic(booleanValue);
|
: type_(booleanValue), allocated_(false)
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
,
|
||||||
|
itemIsUsed_(0)
|
||||||
|
#endif
|
||||||
|
,
|
||||||
|
comments_(0), start_(0), limit_(0) {
|
||||||
value_.bool_ = value;
|
value_.bool_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,8 +441,7 @@ Value::Value(const Value& other)
|
|||||||
for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
|
for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
|
||||||
const CommentInfo& otherComment = other.comments_[comment];
|
const CommentInfo& otherComment = other.comments_[comment];
|
||||||
if (otherComment.comment_)
|
if (otherComment.comment_)
|
||||||
comments_[comment].setComment(
|
comments_[comment].setComment(otherComment.comment_);
|
||||||
otherComment.comment_, strlen(otherComment.comment_));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,12 +479,13 @@ Value::~Value() {
|
|||||||
delete[] comments_;
|
delete[] comments_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator=(Value other) {
|
Value &Value::operator=(const Value &other) {
|
||||||
swap(other);
|
Value temp(other);
|
||||||
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::swapPayload(Value& other) {
|
void Value::swap(Value& other) {
|
||||||
ValueType temp = type_;
|
ValueType temp = type_;
|
||||||
type_ = other.type_;
|
type_ = other.type_;
|
||||||
other.type_ = temp;
|
other.type_ = temp;
|
||||||
@@ -422,11 +493,6 @@ void Value::swapPayload(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_);
|
||||||
}
|
}
|
||||||
@@ -902,17 +968,6 @@ Value& Value::operator[](const char* key) {
|
|||||||
return resolveReference(key, false);
|
return resolveReference(key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::initBasic(ValueType type, bool allocated) {
|
|
||||||
type_ = type;
|
|
||||||
allocated_ = allocated;
|
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
itemIsUsed_ = 0;
|
|
||||||
#endif
|
|
||||||
comments_ = 0;
|
|
||||||
start_ = 0;
|
|
||||||
limit_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& Value::resolveReference(const char* key, bool isStatic) {
|
Value& Value::resolveReference(const char* key, bool isStatic) {
|
||||||
JSON_ASSERT_MESSAGE(
|
JSON_ASSERT_MESSAGE(
|
||||||
type_ == nullValue || type_ == objectValue,
|
type_ == nullValue || type_ == objectValue,
|
||||||
@@ -993,74 +1048,35 @@ 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
|
||||||
Value removed; // null
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
removeMember(key, &removed);
|
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||||
return removed; // still null if removeMember() did nothing
|
if (it == value_.map_->end())
|
||||||
|
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 {
|
||||||
@@ -1229,22 +1245,14 @@ bool Value::isArray() const { return type_ == arrayValue; }
|
|||||||
|
|
||||||
bool Value::isObject() const { return type_ == objectValue; }
|
bool Value::isObject() const { return type_ == objectValue; }
|
||||||
|
|
||||||
void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
|
void Value::setComment(const char* comment, CommentPlacement placement) {
|
||||||
if (!comments_)
|
if (!comments_)
|
||||||
comments_ = new CommentInfo[numberOfCommentPlacement];
|
comments_ = new CommentInfo[numberOfCommentPlacement];
|
||||||
if ((len > 0) && (comment[len-1] == '\n')) {
|
comments_[placement].setComment(comment);
|
||||||
// Always discard trailing newline, to aid indentation.
|
|
||||||
len -= 1;
|
|
||||||
}
|
|
||||||
comments_[placement].setComment(comment, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Value::setComment(const char* comment, CommentPlacement placement) {
|
|
||||||
setComment(comment, strlen(comment), placement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setComment(const std::string& comment, CommentPlacement placement) {
|
void Value::setComment(const std::string& comment, CommentPlacement placement) {
|
||||||
setComment(comment.c_str(), comment.length(), placement);
|
setComment(comment.c_str(), placement);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::hasComment(CommentPlacement placement) const {
|
bool Value::hasComment(CommentPlacement placement) const {
|
||||||
|
@@ -7,16 +7,13 @@
|
|||||||
#include <json/writer.h>
|
#include <json/writer.h>
|
||||||
#include "json_tool.h"
|
#include "json_tool.h"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <iomanip>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <set>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@@ -29,19 +26,8 @@
|
|||||||
#pragma warning(disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__sun) && defined(__SVR4) //Solaris
|
|
||||||
#include <ieeefp.h>
|
|
||||||
#define isfinite finite
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
|
||||||
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
|
|
||||||
#else
|
|
||||||
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool containsControlCharacter(const char* str) {
|
static bool containsControlCharacter(const char* str) {
|
||||||
while (*str) {
|
while (*str) {
|
||||||
if (isControlCharacter(*(str++)))
|
if (isControlCharacter(*(str++)))
|
||||||
@@ -96,13 +82,13 @@ std::string valueToString(double value) {
|
|||||||
// visual studio 2005 to
|
// visual studio 2005 to
|
||||||
// avoid warning.
|
// avoid warning.
|
||||||
#if defined(WINCE)
|
#if defined(WINCE)
|
||||||
len = _snprintf(buffer, sizeof(buffer), "%.17g", value);
|
len = _snprintf(buffer, sizeof(buffer), "%.16g", value);
|
||||||
#else
|
#else
|
||||||
len = sprintf_s(buffer, sizeof(buffer), "%.17g", value);
|
len = sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
if (isfinite(value)) {
|
if (isfinite(value)) {
|
||||||
len = snprintf(buffer, sizeof(buffer), "%.17g", value);
|
len = snprintf(buffer, sizeof(buffer), "%.16g", value);
|
||||||
} else {
|
} else {
|
||||||
// IEEE standard states that NaN values will not compare to themselves
|
// IEEE standard states that NaN values will not compare to themselves
|
||||||
if (value != value) {
|
if (value != value) {
|
||||||
@@ -231,28 +217,28 @@ void FastWriter::writeValue(const Value& value) {
|
|||||||
document_ += valueToString(value.asBool());
|
document_ += valueToString(value.asBool());
|
||||||
break;
|
break;
|
||||||
case arrayValue: {
|
case arrayValue: {
|
||||||
document_ += '[';
|
document_ += "[";
|
||||||
int size = value.size();
|
int size = value.size();
|
||||||
for (int index = 0; index < size; ++index) {
|
for (int index = 0; index < size; ++index) {
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
document_ += ',';
|
document_ += ",";
|
||||||
writeValue(value[index]);
|
writeValue(value[index]);
|
||||||
}
|
}
|
||||||
document_ += ']';
|
document_ += "]";
|
||||||
} break;
|
} break;
|
||||||
case objectValue: {
|
case objectValue: {
|
||||||
Value::Members members(value.getMemberNames());
|
Value::Members members(value.getMemberNames());
|
||||||
document_ += '{';
|
document_ += "{";
|
||||||
for (Value::Members::iterator it = members.begin(); it != members.end();
|
for (Value::Members::iterator it = members.begin(); it != members.end();
|
||||||
++it) {
|
++it) {
|
||||||
const std::string& name = *it;
|
const std::string& name = *it;
|
||||||
if (it != members.begin())
|
if (it != members.begin())
|
||||||
document_ += ',';
|
document_ += ",";
|
||||||
document_ += valueToQuotedString(name.c_str());
|
document_ += valueToQuotedString(name.c_str());
|
||||||
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
document_ += yamlCompatiblityEnabled_ ? ": " : ":";
|
||||||
writeValue(value[name]);
|
writeValue(value[name]);
|
||||||
}
|
}
|
||||||
document_ += '}';
|
document_ += "}";
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +302,7 @@ void StyledWriter::writeValue(const Value& value) {
|
|||||||
writeCommentAfterValueOnSameLine(childValue);
|
writeCommentAfterValueOnSameLine(childValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
document_ += ',';
|
document_ += ",";
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
writeCommentAfterValueOnSameLine(childValue);
|
||||||
}
|
}
|
||||||
unindent();
|
unindent();
|
||||||
@@ -350,7 +336,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
|||||||
writeCommentAfterValueOnSameLine(childValue);
|
writeCommentAfterValueOnSameLine(childValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
document_ += ',';
|
document_ += ",";
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
writeCommentAfterValueOnSameLine(childValue);
|
||||||
}
|
}
|
||||||
unindent();
|
unindent();
|
||||||
@@ -385,9 +371,6 @@ bool StyledWriter::isMultineArray(const Value& value) {
|
|||||||
addChildValues_ = true;
|
addChildValues_ = true;
|
||||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||||
for (int index = 0; index < size; ++index) {
|
for (int index = 0; index < size; ++index) {
|
||||||
if (hasCommentForValue(value[index])) {
|
|
||||||
isMultiLine = true;
|
|
||||||
}
|
|
||||||
writeValue(value[index]);
|
writeValue(value[index]);
|
||||||
lineLength += int(childValues_[index].length());
|
lineLength += int(childValues_[index].length());
|
||||||
}
|
}
|
||||||
@@ -433,27 +416,26 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) {
|
|||||||
|
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
writeIndent();
|
writeIndent();
|
||||||
const std::string& comment = root.getComment(commentBefore);
|
std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
|
||||||
std::string::const_iterator iter = comment.begin();
|
std::string::const_iterator iter = normalizedComment.begin();
|
||||||
while (iter != comment.end()) {
|
while (iter != normalizedComment.end()) {
|
||||||
document_ += *iter;
|
document_ += *iter;
|
||||||
if (*iter == '\n' &&
|
if (*iter == '\n' && *(iter + 1) == '/')
|
||||||
(iter != comment.end() && *(iter + 1) == '/'))
|
|
||||||
writeIndent();
|
writeIndent();
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comments are stripped of trailing newlines, so add one here
|
// Comments are stripped of 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_ += " " + root.getComment(commentAfterOnSameLine);
|
document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
||||||
|
|
||||||
if (root.hasComment(commentAfter)) {
|
if (root.hasComment(commentAfter)) {
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
document_ += root.getComment(commentAfter);
|
document_ += normalizeEOL(root.getComment(commentAfter));
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,6 +446,25 @@ 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
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -475,10 +476,7 @@ void StyledStreamWriter::write(std::ostream& out, const Value& root) {
|
|||||||
document_ = &out;
|
document_ = &out;
|
||||||
addChildValues_ = false;
|
addChildValues_ = false;
|
||||||
indentString_ = "";
|
indentString_ = "";
|
||||||
indented_ = true;
|
|
||||||
writeCommentBeforeValue(root);
|
writeCommentBeforeValue(root);
|
||||||
if (!indented_) writeIndent();
|
|
||||||
indented_ = true;
|
|
||||||
writeValue(root);
|
writeValue(root);
|
||||||
writeCommentAfterValueOnSameLine(root);
|
writeCommentAfterValueOnSameLine(root);
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
@@ -554,10 +552,8 @@ void StyledStreamWriter::writeArrayValue(const Value& value) {
|
|||||||
if (hasChildValue)
|
if (hasChildValue)
|
||||||
writeWithIndent(childValues_[index]);
|
writeWithIndent(childValues_[index]);
|
||||||
else {
|
else {
|
||||||
if (!indented_) writeIndent();
|
writeIndent();
|
||||||
indented_ = true;
|
|
||||||
writeValue(childValue);
|
writeValue(childValue);
|
||||||
indented_ = false;
|
|
||||||
}
|
}
|
||||||
if (++index == size) {
|
if (++index == size) {
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
writeCommentAfterValueOnSameLine(childValue);
|
||||||
@@ -598,9 +594,6 @@ bool StyledStreamWriter::isMultineArray(const Value& value) {
|
|||||||
addChildValues_ = true;
|
addChildValues_ = true;
|
||||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||||
for (int index = 0; index < size; ++index) {
|
for (int index = 0; index < size; ++index) {
|
||||||
if (hasCommentForValue(value[index])) {
|
|
||||||
isMultiLine = true;
|
|
||||||
}
|
|
||||||
writeValue(value[index]);
|
writeValue(value[index]);
|
||||||
lineLength += int(childValues_[index].length());
|
lineLength += int(childValues_[index].length());
|
||||||
}
|
}
|
||||||
@@ -618,17 +611,24 @@ void StyledStreamWriter::pushValue(const std::string& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StyledStreamWriter::writeIndent() {
|
void StyledStreamWriter::writeIndent() {
|
||||||
// blep intended this to look at the so-far-written string
|
/*
|
||||||
// to determine whether we are already indented, but
|
Some comments in this method would have been nice. ;-)
|
||||||
// with a stream we cannot do that. So we rely on some saved state.
|
|
||||||
// The caller checks indented_.
|
if ( !document_.empty() )
|
||||||
|
{
|
||||||
|
char last = document_[document_.length()-1];
|
||||||
|
if ( last == ' ' ) // already indented
|
||||||
|
return;
|
||||||
|
if ( last != '\n' ) // Comments may add new-line
|
||||||
|
*document_ << '\n';
|
||||||
|
}
|
||||||
|
*/
|
||||||
*document_ << '\n' << indentString_;
|
*document_ << '\n' << indentString_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyledStreamWriter::writeWithIndent(const std::string& value) {
|
void StyledStreamWriter::writeWithIndent(const std::string& value) {
|
||||||
if (!indented_) writeIndent();
|
writeIndent();
|
||||||
*document_ << value;
|
*document_ << value;
|
||||||
indented_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyledStreamWriter::indent() { indentString_ += indentation_; }
|
void StyledStreamWriter::indent() { indentString_ += indentation_; }
|
||||||
@@ -641,30 +641,19 @@ 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));
|
||||||
if (!indented_) writeIndent();
|
*document_ << "\n";
|
||||||
const std::string& comment = root.getComment(commentBefore);
|
|
||||||
std::string::const_iterator iter = comment.begin();
|
|
||||||
while (iter != comment.end()) {
|
|
||||||
*document_ << *iter;
|
|
||||||
if (*iter == '\n' &&
|
|
||||||
(iter != comment.end() && *(iter + 1) == '/'))
|
|
||||||
// writeIndent(); // would include newline
|
|
||||||
*document_ << indentString_;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
indented_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
||||||
if (root.hasComment(commentAfterOnSameLine))
|
if (root.hasComment(commentAfterOnSameLine))
|
||||||
*document_ << ' ' << root.getComment(commentAfterOnSameLine);
|
*document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
|
||||||
|
|
||||||
if (root.hasComment(commentAfter)) {
|
if (root.hasComment(commentAfter)) {
|
||||||
writeIndent();
|
*document_ << "\n";
|
||||||
*document_ << root.getComment(commentAfter);
|
*document_ << normalizeEOL(root.getComment(commentAfter));
|
||||||
|
*document_ << "\n";
|
||||||
}
|
}
|
||||||
indented_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyledStreamWriter::hasCommentForValue(const Value& value) {
|
bool StyledStreamWriter::hasCommentForValue(const Value& value) {
|
||||||
@@ -673,376 +662,28 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) {
|
|||||||
value.hasComment(commentAfter);
|
value.hasComment(commentAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////
|
std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
|
||||||
// BuiltStyledStreamWriter
|
std::string normalized;
|
||||||
|
normalized.reserve(text.length());
|
||||||
/// Scoped enums are not available until C++11.
|
const char* begin = text.c_str();
|
||||||
struct CommentStyle {
|
const char* end = begin + text.length();
|
||||||
/// Decide whether to write comments.
|
const char* current = begin;
|
||||||
enum Enum {
|
while (current != end) {
|
||||||
None, ///< Drop all comments.
|
char c = *current++;
|
||||||
Most, ///< Recover odd behavior of previous versions (not implemented yet).
|
if (c == '\r') // mac or dos EOL
|
||||||
All ///< Keep all comments.
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BuiltStyledStreamWriter : public StreamWriter
|
|
||||||
{
|
|
||||||
BuiltStyledStreamWriter(
|
|
||||||
std::string const& indentation,
|
|
||||||
CommentStyle::Enum cs,
|
|
||||||
std::string const& colonSymbol,
|
|
||||||
std::string const& nullSymbol,
|
|
||||||
std::string const& endingLineFeedSymbol);
|
|
||||||
virtual int write(Value const& root, std::ostream* sout);
|
|
||||||
private:
|
|
||||||
void writeValue(Value const& value);
|
|
||||||
void writeArrayValue(Value const& value);
|
|
||||||
bool isMultineArray(Value const& value);
|
|
||||||
void pushValue(std::string const& value);
|
|
||||||
void writeIndent();
|
|
||||||
void writeWithIndent(std::string const& value);
|
|
||||||
void indent();
|
|
||||||
void unindent();
|
|
||||||
void writeCommentBeforeValue(Value const& root);
|
|
||||||
void writeCommentAfterValueOnSameLine(Value const& root);
|
|
||||||
static bool hasCommentForValue(const Value& value);
|
|
||||||
|
|
||||||
typedef std::vector<std::string> ChildValues;
|
|
||||||
|
|
||||||
ChildValues childValues_;
|
|
||||||
std::string indentString_;
|
|
||||||
int rightMargin_;
|
|
||||||
std::string indentation_;
|
|
||||||
CommentStyle::Enum cs_;
|
|
||||||
std::string colonSymbol_;
|
|
||||||
std::string nullSymbol_;
|
|
||||||
std::string endingLineFeedSymbol_;
|
|
||||||
bool addChildValues_ : 1;
|
|
||||||
bool indented_ : 1;
|
|
||||||
};
|
|
||||||
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
|
||||||
std::string const& indentation,
|
|
||||||
CommentStyle::Enum cs,
|
|
||||||
std::string const& colonSymbol,
|
|
||||||
std::string const& nullSymbol,
|
|
||||||
std::string const& endingLineFeedSymbol)
|
|
||||||
: rightMargin_(74)
|
|
||||||
, indentation_(indentation)
|
|
||||||
, cs_(cs)
|
|
||||||
, colonSymbol_(colonSymbol)
|
|
||||||
, nullSymbol_(nullSymbol)
|
|
||||||
, endingLineFeedSymbol_(endingLineFeedSymbol)
|
|
||||||
, addChildValues_(false)
|
|
||||||
, indented_(false)
|
|
||||||
{
|
{
|
||||||
|
if (*current == '\n') // convert dos EOL
|
||||||
|
++current;
|
||||||
|
normalized += '\n';
|
||||||
|
} else // handle unix EOL & other char
|
||||||
|
normalized += c;
|
||||||
}
|
}
|
||||||
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
|
return normalized;
|
||||||
{
|
|
||||||
sout_ = sout;
|
|
||||||
addChildValues_ = false;
|
|
||||||
indented_ = true;
|
|
||||||
indentString_ = "";
|
|
||||||
writeCommentBeforeValue(root);
|
|
||||||
if (!indented_) writeIndent();
|
|
||||||
indented_ = true;
|
|
||||||
writeValue(root);
|
|
||||||
writeCommentAfterValueOnSameLine(root);
|
|
||||||
*sout_ << endingLineFeedSymbol_;
|
|
||||||
sout_ = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|
||||||
switch (value.type()) {
|
|
||||||
case nullValue:
|
|
||||||
pushValue(nullSymbol_);
|
|
||||||
break;
|
|
||||||
case intValue:
|
|
||||||
pushValue(valueToString(value.asLargestInt()));
|
|
||||||
break;
|
|
||||||
case uintValue:
|
|
||||||
pushValue(valueToString(value.asLargestUInt()));
|
|
||||||
break;
|
|
||||||
case realValue:
|
|
||||||
pushValue(valueToString(value.asDouble()));
|
|
||||||
break;
|
|
||||||
case stringValue:
|
|
||||||
pushValue(valueToQuotedString(value.asCString()));
|
|
||||||
break;
|
|
||||||
case booleanValue:
|
|
||||||
pushValue(valueToString(value.asBool()));
|
|
||||||
break;
|
|
||||||
case arrayValue:
|
|
||||||
writeArrayValue(value);
|
|
||||||
break;
|
|
||||||
case objectValue: {
|
|
||||||
Value::Members members(value.getMemberNames());
|
|
||||||
if (members.empty())
|
|
||||||
pushValue("{}");
|
|
||||||
else {
|
|
||||||
writeWithIndent("{");
|
|
||||||
indent();
|
|
||||||
Value::Members::iterator it = members.begin();
|
|
||||||
for (;;) {
|
|
||||||
std::string const& name = *it;
|
|
||||||
Value const& childValue = value[name];
|
|
||||||
writeCommentBeforeValue(childValue);
|
|
||||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
|
||||||
*sout_ << colonSymbol_;
|
|
||||||
writeValue(childValue);
|
|
||||||
if (++it == members.end()) {
|
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*sout_ << ",";
|
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
|
||||||
}
|
|
||||||
unindent();
|
|
||||||
writeWithIndent("}");
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
|
std::ostream& operator<<(std::ostream& sout, const Value& root) {
|
||||||
unsigned size = value.size();
|
Json::StyledStreamWriter writer;
|
||||||
if (size == 0)
|
writer.write(sout, root);
|
||||||
pushValue("[]");
|
|
||||||
else {
|
|
||||||
bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
|
|
||||||
if (isMultiLine) {
|
|
||||||
writeWithIndent("[");
|
|
||||||
indent();
|
|
||||||
bool hasChildValue = !childValues_.empty();
|
|
||||||
unsigned index = 0;
|
|
||||||
for (;;) {
|
|
||||||
Value const& childValue = value[index];
|
|
||||||
writeCommentBeforeValue(childValue);
|
|
||||||
if (hasChildValue)
|
|
||||||
writeWithIndent(childValues_[index]);
|
|
||||||
else {
|
|
||||||
if (!indented_) writeIndent();
|
|
||||||
indented_ = true;
|
|
||||||
writeValue(childValue);
|
|
||||||
indented_ = false;
|
|
||||||
}
|
|
||||||
if (++index == size) {
|
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*sout_ << ",";
|
|
||||||
writeCommentAfterValueOnSameLine(childValue);
|
|
||||||
}
|
|
||||||
unindent();
|
|
||||||
writeWithIndent("]");
|
|
||||||
} else // output on a single line
|
|
||||||
{
|
|
||||||
assert(childValues_.size() == size);
|
|
||||||
*sout_ << "[";
|
|
||||||
if (!indentation_.empty()) *sout_ << " ";
|
|
||||||
for (unsigned index = 0; index < size; ++index) {
|
|
||||||
if (index > 0)
|
|
||||||
*sout_ << ", ";
|
|
||||||
*sout_ << childValues_[index];
|
|
||||||
}
|
|
||||||
if (!indentation_.empty()) *sout_ << " ";
|
|
||||||
*sout_ << "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
|
|
||||||
int size = value.size();
|
|
||||||
bool isMultiLine = size * 3 >= rightMargin_;
|
|
||||||
childValues_.clear();
|
|
||||||
for (int index = 0; index < size && !isMultiLine; ++index) {
|
|
||||||
Value const& childValue = value[index];
|
|
||||||
isMultiLine =
|
|
||||||
isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
|
|
||||||
childValue.size() > 0);
|
|
||||||
}
|
|
||||||
if (!isMultiLine) // check if line length > max line length
|
|
||||||
{
|
|
||||||
childValues_.reserve(size);
|
|
||||||
addChildValues_ = true;
|
|
||||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
|
||||||
for (int index = 0; index < size; ++index) {
|
|
||||||
if (hasCommentForValue(value[index])) {
|
|
||||||
isMultiLine = true;
|
|
||||||
}
|
|
||||||
writeValue(value[index]);
|
|
||||||
lineLength += int(childValues_[index].length());
|
|
||||||
}
|
|
||||||
addChildValues_ = false;
|
|
||||||
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
|
||||||
}
|
|
||||||
return isMultiLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::pushValue(std::string const& value) {
|
|
||||||
if (addChildValues_)
|
|
||||||
childValues_.push_back(value);
|
|
||||||
else
|
|
||||||
*sout_ << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::writeIndent() {
|
|
||||||
// blep intended this to look at the so-far-written string
|
|
||||||
// to determine whether we are already indented, but
|
|
||||||
// with a stream we cannot do that. So we rely on some saved state.
|
|
||||||
// The caller checks indented_.
|
|
||||||
|
|
||||||
if (!indentation_.empty()) {
|
|
||||||
// In this case, drop newlines too.
|
|
||||||
*sout_ << '\n' << indentString_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
|
|
||||||
if (!indented_) writeIndent();
|
|
||||||
*sout_ << value;
|
|
||||||
indented_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::unindent() {
|
|
||||||
assert(indentString_.size() >= indentation_.size());
|
|
||||||
indentString_.resize(indentString_.size() - indentation_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
|
|
||||||
if (cs_ == CommentStyle::None) return;
|
|
||||||
if (!root.hasComment(commentBefore))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!indented_) writeIndent();
|
|
||||||
const std::string& comment = root.getComment(commentBefore);
|
|
||||||
std::string::const_iterator iter = comment.begin();
|
|
||||||
while (iter != comment.end()) {
|
|
||||||
*sout_ << *iter;
|
|
||||||
if (*iter == '\n' &&
|
|
||||||
(iter != comment.end() && *(iter + 1) == '/'))
|
|
||||||
// writeIndent(); // would write extra newline
|
|
||||||
*sout_ << indentString_;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
indented_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
|
|
||||||
if (cs_ == CommentStyle::None) return;
|
|
||||||
if (root.hasComment(commentAfterOnSameLine))
|
|
||||||
*sout_ << " " + root.getComment(commentAfterOnSameLine);
|
|
||||||
|
|
||||||
if (root.hasComment(commentAfter)) {
|
|
||||||
writeIndent();
|
|
||||||
*sout_ << root.getComment(commentAfter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
|
|
||||||
return value.hasComment(commentBefore) ||
|
|
||||||
value.hasComment(commentAfterOnSameLine) ||
|
|
||||||
value.hasComment(commentAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////
|
|
||||||
// StreamWriter
|
|
||||||
|
|
||||||
StreamWriter::StreamWriter()
|
|
||||||
: sout_(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
StreamWriter::~StreamWriter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
StreamWriter::Factory::~Factory()
|
|
||||||
{}
|
|
||||||
StreamWriterBuilder::StreamWriterBuilder()
|
|
||||||
{
|
|
||||||
setDefaults(&settings_);
|
|
||||||
}
|
|
||||||
StreamWriterBuilder::~StreamWriterBuilder()
|
|
||||||
{}
|
|
||||||
StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|
||||||
{
|
|
||||||
std::string indentation = settings_["indentation"].asString();
|
|
||||||
std::string cs_str = settings_["commentStyle"].asString();
|
|
||||||
bool eyc = settings_["enableYAMLCompatibility"].asBool();
|
|
||||||
bool dnp = settings_["dropNullPlaceholders"].asBool();
|
|
||||||
CommentStyle::Enum cs = CommentStyle::All;
|
|
||||||
if (cs_str == "All") {
|
|
||||||
cs = CommentStyle::All;
|
|
||||||
} else if (cs_str == "None") {
|
|
||||||
cs = CommentStyle::None;
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("commentStyle must be 'All' or 'None'");
|
|
||||||
}
|
|
||||||
std::string colonSymbol = " : ";
|
|
||||||
if (eyc) {
|
|
||||||
colonSymbol = ": ";
|
|
||||||
} else if (indentation.empty()) {
|
|
||||||
colonSymbol = ":";
|
|
||||||
}
|
|
||||||
std::string nullSymbol = "null";
|
|
||||||
if (dnp) {
|
|
||||||
nullSymbol = "";
|
|
||||||
}
|
|
||||||
std::string endingLineFeedSymbol = "";
|
|
||||||
return new BuiltStyledStreamWriter(
|
|
||||||
indentation, cs,
|
|
||||||
colonSymbol, nullSymbol, endingLineFeedSymbol);
|
|
||||||
}
|
|
||||||
static void getValidWriterKeys(std::set<std::string>* valid_keys)
|
|
||||||
{
|
|
||||||
valid_keys->clear();
|
|
||||||
valid_keys->insert("indentation");
|
|
||||||
valid_keys->insert("commentStyle");
|
|
||||||
valid_keys->insert("enableYAMLCompatibility");
|
|
||||||
valid_keys->insert("dropNullPlaceholders");
|
|
||||||
}
|
|
||||||
bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
|
||||||
{
|
|
||||||
Json::Value my_invalid;
|
|
||||||
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
|
|
||||||
Json::Value& inv = *invalid;
|
|
||||||
bool valid = true;
|
|
||||||
std::set<std::string> valid_keys;
|
|
||||||
getValidWriterKeys(&valid_keys);
|
|
||||||
Value::Members keys = settings_.getMemberNames();
|
|
||||||
size_t n = keys.size();
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
std::string const& key = keys[i];
|
|
||||||
if (valid_keys.find(key) == valid_keys.end()) {
|
|
||||||
inv[key] = settings_[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
// static
|
|
||||||
void StreamWriterBuilder::setDefaults(Json::Value* settings)
|
|
||||||
{
|
|
||||||
//! [StreamWriterBuilderDefaults]
|
|
||||||
(*settings)["commentStyle"] = "All";
|
|
||||||
(*settings)["indentation"] = "\t";
|
|
||||||
(*settings)["enableYAMLCompatibility"] = false;
|
|
||||||
(*settings)["dropNullPlaceholders"] = false;
|
|
||||||
//! [StreamWriterBuilderDefaults]
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
|
|
||||||
std::ostringstream sout;
|
|
||||||
StreamWriterPtr const writer(builder.newStreamWriter());
|
|
||||||
writer->write(root, &sout);
|
|
||||||
return sout.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& sout, Value const& root) {
|
|
||||||
StreamWriterBuilder builder;
|
|
||||||
StreamWriterPtr const writer(builder.newStreamWriter());
|
|
||||||
writer->write(root, &sout);
|
|
||||||
return sout;
|
return sout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,15 +9,7 @@ ADD_EXECUTABLE( jsoncpp_test
|
|||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
IF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
|
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib)
|
||||||
ELSE(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
TARGET_LINK_LIBRARIES(jsoncpp_test jsoncpp_lib_static)
|
|
||||||
ENDIF(JSONCPP_LIB_BUILD_SHARED)
|
|
||||||
|
|
||||||
# another way to solve issue #90
|
|
||||||
#set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store)
|
|
||||||
|
|
||||||
# Run unit tests in post-build
|
# Run unit tests in post-build
|
||||||
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
|
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
|
||||||
|
@@ -323,7 +323,7 @@ void Runner::listTests() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Runner::runCommandLine(int argc, const char* argv[]) const {
|
int Runner::runCommandLine(int argc, const char* argv[]) const {
|
||||||
// typedef std::deque<std::string> TestNames;
|
typedef std::deque<std::string> TestNames;
|
||||||
Runner subrunner;
|
Runner subrunner;
|
||||||
for (int index = 1; index < argc; ++index) {
|
for (int index = 1; index < argc; ++index) {
|
||||||
std::string opt = argv[index];
|
std::string opt = argv[index];
|
||||||
|
@@ -178,8 +178,8 @@ private:
|
|||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
TestResult& checkEqual(TestResult& result,
|
TestResult& checkEqual(TestResult& result,
|
||||||
T expected,
|
const T& expected,
|
||||||
U actual,
|
const U& actual,
|
||||||
const char* file,
|
const char* file,
|
||||||
unsigned int line,
|
unsigned int line,
|
||||||
const char* expr) {
|
const char* expr) {
|
||||||
@@ -214,7 +214,7 @@ TestResult& checkStringEqual(TestResult& result,
|
|||||||
#define JSONTEST_ASSERT_PRED(expr) \
|
#define JSONTEST_ASSERT_PRED(expr) \
|
||||||
{ \
|
{ \
|
||||||
JsonTest::PredicateContext _minitest_Context = { \
|
JsonTest::PredicateContext _minitest_Context = { \
|
||||||
result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL \
|
result_->predicateId_, __FILE__, __LINE__, #expr \
|
||||||
}; \
|
}; \
|
||||||
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
result_->predicateStackTail_->next_ = &_minitest_Context; \
|
||||||
result_->predicateId_ += 1; \
|
result_->predicateId_ += 1; \
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
#include <json/config.h>
|
#include <json/config.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
// Make numeric limits more convenient to talk about.
|
// Make numeric limits more convenient to talk about.
|
||||||
// Assumes int type in 32 bits.
|
// Assumes int type in 32 bits.
|
||||||
@@ -18,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);
|
||||||
|
|
||||||
@@ -199,18 +198,6 @@ 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) {
|
||||||
@@ -253,10 +240,6 @@ 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) {
|
||||||
@@ -943,7 +926,7 @@ JSONTEST_FIXTURE(ValueTest, integers) {
|
|||||||
JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)),
|
JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)),
|
||||||
val.asFloat());
|
val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("9.2233720368547758e+18",
|
JSONTEST_ASSERT_STRING_EQUAL("9.223372036854776e+18",
|
||||||
normalizeFloatingPointStr(val.asString()));
|
normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// int64 min
|
// int64 min
|
||||||
@@ -991,7 +974,7 @@ JSONTEST_FIXTURE(ValueTest, integers) {
|
|||||||
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble());
|
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat());
|
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("-9.2233720368547758e+18",
|
JSONTEST_ASSERT_STRING_EQUAL("-9.223372036854776e+18",
|
||||||
normalizeFloatingPointStr(val.asString()));
|
normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// 10^19
|
// 10^19
|
||||||
@@ -1082,7 +1065,7 @@ JSONTEST_FIXTURE(ValueTest, integers) {
|
|||||||
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble());
|
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat());
|
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1.8446744073709552e+19",
|
JSONTEST_ASSERT_STRING_EQUAL("1.844674407370955e+19",
|
||||||
normalizeFloatingPointStr(val.asString()));
|
normalizeFloatingPointStr(val.asString()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1234,7 +1217,7 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
|
|||||||
normalizeFloatingPointStr(val.asString()));
|
normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
val = Json::Value(1.2345678901234);
|
val = Json::Value(1.2345678901234);
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1.2345678901234001",
|
JSONTEST_ASSERT_STRING_EQUAL("1.2345678901234",
|
||||||
normalizeFloatingPointStr(val.asString()));
|
normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// A 16-digit floating point number.
|
// A 16-digit floating point number.
|
||||||
@@ -1527,17 +1510,6 @@ JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
|
|||||||
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
|
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StreamWriterTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
|
|
||||||
Json::StreamWriterBuilder b;
|
|
||||||
Json::Value nullValue;
|
|
||||||
b.settings_["dropNullPlaceholders"] = false;
|
|
||||||
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "null");
|
|
||||||
b.settings_["dropNullPlaceholders"] = true;
|
|
||||||
JSONTEST_ASSERT(Json::writeString(b, nullValue) == "");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReaderTest : JsonTest::TestCase {};
|
struct ReaderTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
|
||||||
@@ -1629,118 +1601,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
|||||||
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CharReaderTest : JsonTest::TestCase {};
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrors) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] = "{ \"property\" : \"value\" }";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs.size() == 0);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrorsTestingOffsets) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
|
|
||||||
"{ \"nested\" : 123, \"bool\" : true}, \"null\" : "
|
|
||||||
"null, \"false\" : false }";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs.size() == 0);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseWithOneError) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" :: \"value\" }";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT(errs ==
|
|
||||||
"* Line 1, Column 15\n Syntax error: value, object or array "
|
|
||||||
"expected.\n");
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseChineseWithOneError) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"pr佐藤erty\" :: \"value\" }";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT(errs ==
|
|
||||||
"* Line 1, Column 19\n Syntax error: value, object or array "
|
|
||||||
"expected.\n");
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseWithDetailError) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" : \"v\\alue\" }";
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(!ok);
|
|
||||||
JSONTEST_ASSERT(errs ==
|
|
||||||
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
|
|
||||||
"Line 1, Column 20 for detail.\n");
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
|
|
||||||
Json::CharReaderBuilder b;
|
|
||||||
Json::Value root;
|
|
||||||
char const doc[] =
|
|
||||||
"{ \"property\" : \"value\" }";
|
|
||||||
{
|
|
||||||
b.settings_["stackLimit"] = 2;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
bool ok = reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs);
|
|
||||||
JSONTEST_ASSERT(ok);
|
|
||||||
JSONTEST_ASSERT(errs == "");
|
|
||||||
JSONTEST_ASSERT_EQUAL("value", root["property"]);
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
b.settings_["stackLimit"] = 1;
|
|
||||||
Json::CharReader* reader(b.newCharReader());
|
|
||||||
std::string errs;
|
|
||||||
JSONTEST_ASSERT_THROWS(reader->parse(
|
|
||||||
doc, doc + std::strlen(doc),
|
|
||||||
&root, &errs));
|
|
||||||
delete reader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
JsonTest::Runner runner;
|
JsonTest::Runner runner;
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
||||||
@@ -1771,16 +1631,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
|
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
|
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithNoErrors);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(
|
|
||||||
runner, CharReaderTest, parseWithNoErrorsTestingOffsets);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithOneError);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseChineseWithOneError);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
|
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
|
|
||||||
|
|
||||||
return runner.runCommandLine(argc, argv);
|
return runner.runCommandLine(argc, argv);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
// Comment for array
|
|
||||||
.=[]
|
|
||||||
// Comment within array
|
|
||||||
.[0]="one-element"
|
|
@@ -1,5 +0,0 @@
|
|||||||
// Comment for array
|
|
||||||
[
|
|
||||||
// Comment within array
|
|
||||||
"one-element"
|
|
||||||
]
|
|
@@ -1,7 +1,5 @@
|
|||||||
.={}
|
.={}
|
||||||
// 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,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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,13 +11,4 @@
|
|||||||
// Multiline comment cpp-style
|
// Multiline comment cpp-style
|
||||||
// Second line
|
// Second line
|
||||||
.cpp-test.c=3
|
.cpp-test.c=3
|
||||||
// Comment before double
|
.cpp-test.d=4
|
||||||
.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,15 +12,6 @@
|
|||||||
// Multiline comment cpp-style
|
// Multiline comment cpp-style
|
||||||
// Second line
|
// Second line
|
||||||
"c" : 3,
|
"c" : 3,
|
||||||
// Comment before double
|
"d" : 4
|
||||||
"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,11 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import glob
|
import glob
|
||||||
import os.path
|
import os.path
|
||||||
for path in glob.glob( '*.json' ):
|
for path in glob.glob( '*.json' ):
|
||||||
text = file(path,'rt').read()
|
text = file(path,'rt').read()
|
||||||
target = os.path.splitext(path)[0] + '.expected'
|
target = os.path.splitext(path)[0] + '.expected'
|
||||||
if os.path.exists( target ):
|
if os.path.exists( target ):
|
||||||
print('skipping:', target)
|
print 'skipping:', target
|
||||||
else:
|
else:
|
||||||
print('creating:', target)
|
print 'creating:', target
|
||||||
file(target,'wt').write(text)
|
file(target,'wt').write(text)
|
||||||
|
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
# Simple implementation of a json test runner to run the test against json-py.
|
# Simple implementation of a json test runner to run the test against json-py.
|
||||||
from __future__ import print_function
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import json
|
import json
|
||||||
import types
|
import types
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Usage: %s input-json-file", sys.argv[0])
|
print "Usage: %s input-json-file", sys.argv[0]
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
input_path = sys.argv[1]
|
input_path = sys.argv[1]
|
||||||
|
@@ -1,37 +1,17 @@
|
|||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from io import open
|
|
||||||
from glob import glob
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
from glob import glob
|
||||||
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.
|
|
||||||
"""
|
|
||||||
print(cmd, file=sys.stderr)
|
|
||||||
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')
|
||||||
diff_line = 0
|
diff_line = 0
|
||||||
max_line_to_compare = min( len(expected), len(actual) )
|
max_line_to_compare = min( len(expected), len(actual) )
|
||||||
for index in range(0,max_line_to_compare):
|
for index in xrange(0,max_line_to_compare):
|
||||||
if expected[index].strip() != actual[index].strip():
|
if expected[index].strip() != actual[index].strip():
|
||||||
diff_line = index + 1
|
diff_line = index + 1
|
||||||
break
|
break
|
||||||
@@ -53,13 +33,12 @@ def compareOutputs(expected, actual, message):
|
|||||||
|
|
||||||
def safeReadFile( path ):
|
def safeReadFile( path ):
|
||||||
try:
|
try:
|
||||||
return open(path, 'rt', encoding = 'utf-8').read()
|
return file( path, 'rt' ).read()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
return '<File "%s" is missing: %s>' % (path,e)
|
return '<File "%s" is missing: %s>' % (path,e)
|
||||||
|
|
||||||
def runAllTests( jsontest_executable_path, input_dir = None,
|
def runAllTests( jsontest_executable_path, input_dir = None,
|
||||||
use_valgrind=False, with_json_checker=False,
|
use_valgrind=False, with_json_checker=False ):
|
||||||
writerClass='StyledWriter'):
|
|
||||||
if not input_dir:
|
if not input_dir:
|
||||||
input_dir = os.path.join( os.getcwd(), 'data' )
|
input_dir = os.path.join( os.getcwd(), 'data' )
|
||||||
tests = glob( os.path.join( input_dir, '*.json' ) )
|
tests = glob( os.path.join( input_dir, '*.json' ) )
|
||||||
@@ -72,57 +51,58 @@ def runAllTests(jsontest_executable_path, input_dir = None,
|
|||||||
for input_path in tests + test_jsonchecker:
|
for input_path in tests + test_jsonchecker:
|
||||||
expect_failure = os.path.basename( input_path ).startswith( 'fail' )
|
expect_failure = os.path.basename( input_path ).startswith( 'fail' )
|
||||||
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,
|
||||||
options = is_json_checker_test and '--json-checker' or ''
|
options = is_json_checker_test and '--json-checker' or ''
|
||||||
options += ' --json-writer %s'%writerClass
|
pipe = os.popen( "%s%s %s %s" % (
|
||||||
cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options,
|
valgrind_path, jsontest_executable_path, options,
|
||||||
input_path)
|
input_path) )
|
||||||
status, process_output = getStatusOutput(cmd)
|
process_output = pipe.read()
|
||||||
|
status = pipe.close()
|
||||||
if is_json_checker_test:
|
if is_json_checker_test:
|
||||||
if expect_failure:
|
if expect_failure:
|
||||||
if not status:
|
if status is None:
|
||||||
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:
|
if status is not None:
|
||||||
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:
|
||||||
print('OK')
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
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' )
|
||||||
open(base_path + '.process-output', 'wt', encoding = 'utf-8').write(process_output)
|
file(base_path + '.process-output','wt').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 = open(expected_output_path, 'rt', encoding = 'utf-8').read()
|
expected_output = file( expected_output_path, 'rt' ).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:
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_tests.append( (input_path, detail) )
|
failed_tests.append( (input_path, detail) )
|
||||||
else:
|
else:
|
||||||
print('OK')
|
print 'OK'
|
||||||
|
|
||||||
if failed_tests:
|
if failed_tests:
|
||||||
print()
|
print
|
||||||
print('Failure details:')
|
print 'Failure details:'
|
||||||
for failed_test in failed_tests:
|
for failed_test in failed_tests:
|
||||||
print('* Test', failed_test[0])
|
print '* Test', failed_test[0]
|
||||||
print(failed_test[1])
|
print failed_test[1]
|
||||||
print()
|
print
|
||||||
print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
|
print 'Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
|
||||||
len(failed_tests)))
|
len(failed_tests) )
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
print('All %d tests passed.' % len(tests))
|
print 'All %d tests passed.' % len(tests)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -147,22 +127,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
input_path = None
|
input_path = None
|
||||||
status = runAllTests( jsontest_executable_path, input_path,
|
status = runAllTests( jsontest_executable_path, input_path,
|
||||||
use_valgrind=options.valgrind,
|
use_valgrind=options.valgrind, with_json_checker=options.with_json_checker )
|
||||||
with_json_checker=options.with_json_checker,
|
|
||||||
writerClass='StyledWriter')
|
|
||||||
if status:
|
|
||||||
sys.exit(status)
|
|
||||||
status = runAllTests(jsontest_executable_path, input_path,
|
|
||||||
use_valgrind=options.valgrind,
|
|
||||||
with_json_checker=options.with_json_checker,
|
|
||||||
writerClass='StyledStreamWriter')
|
|
||||||
if status:
|
|
||||||
sys.exit(status)
|
|
||||||
status = runAllTests(jsontest_executable_path, input_path,
|
|
||||||
use_valgrind=options.valgrind,
|
|
||||||
with_json_checker=options.with_json_checker,
|
|
||||||
writerClass='BuiltStyledStreamWriter')
|
|
||||||
if status:
|
|
||||||
sys.exit( status )
|
sys.exit( status )
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from io import open
|
|
||||||
from glob import glob
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from glob import glob
|
||||||
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'
|
||||||
@@ -21,11 +18,7 @@ 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 )
|
||||||
try:
|
|
||||||
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
|
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
|
||||||
@@ -35,28 +28,29 @@ def runAllTests(exe_path, use_valgrind=False):
|
|||||||
test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
|
test_proxy = TestProxy( exe_path, use_valgrind=use_valgrind )
|
||||||
status, test_names = test_proxy.run( ['--list-tests'] )
|
status, test_names = test_proxy.run( ['--list-tests'] )
|
||||||
if not status:
|
if not status:
|
||||||
print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
|
print >> sys.stderr, "Failed to obtain unit tests list:\n" + test_names
|
||||||
return 1
|
return 1
|
||||||
test_names = [name.strip() for name in test_names.decode('utf-8').strip().split('\n')]
|
test_names = [name.strip() for name in test_names.strip().split('\n')]
|
||||||
failures = []
|
failures = []
|
||||||
for name in test_names:
|
for name in test_names:
|
||||||
print('TESTING %s:' % name, end=' ')
|
print 'TESTING %s:' % name,
|
||||||
succeed, result = test_proxy.run( ['--test', name] )
|
succeed, result = test_proxy.run( ['--test', name] )
|
||||||
if succeed:
|
if succeed:
|
||||||
print('OK')
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
failures.append( (name, result) )
|
failures.append( (name, result) )
|
||||||
print('FAILED')
|
print 'FAILED'
|
||||||
failed_count = len(failures)
|
failed_count = len(failures)
|
||||||
pass_count = len(test_names) - failed_count
|
pass_count = len(test_names) - failed_count
|
||||||
if failed_count:
|
if failed_count:
|
||||||
print()
|
print
|
||||||
for name, result in failures:
|
for name, result in failures:
|
||||||
print(result)
|
print result
|
||||||
print('%d/%d tests passed (%d failure(s))' % ( pass_count, len(test_names), failed_count))
|
print '%d/%d tests passed (%d failure(s))' % (
|
||||||
|
pass_count, len(test_names), failed_count)
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
print('All %d tests passed' % len(test_names))
|
print 'All %d tests passed' % len(test_names)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
Reference in New Issue
Block a user