1515
1616#include < algorithm> // sort
1717#include < cstdio>
18+ #include < iostream>
1819#include < json/json.h>
20+ #include < memory>
1921#include < sstream>
2022
2123struct Options {
@@ -126,19 +128,45 @@ static int parseAndSaveValueTree(const Json::String& input,
126128 const Json::String& actual,
127129 const Json::String& kind,
128130 const Json::Features& features, bool parseOnly,
129- Json::Value* root) {
130- Json::Reader reader (features);
131- bool parsingSuccessful =
132- reader.parse (input.data (), input.data () + input.size (), *root);
133- if (!parsingSuccessful) {
134- printf (" Failed to parse %s file: \n %s\n " , kind.c_str (),
135- reader.getFormattedErrorMessages ().c_str ());
136- return 1 ;
131+ Json::Value* root, bool use_legacy) {
132+ if (!use_legacy) {
133+ Json::CharReaderBuilder builder;
134+
135+ builder.settings_ [" allowComments" ] = features.allowComments_ ;
136+ builder.settings_ [" strictRoot" ] = features.strictRoot_ ;
137+ builder.settings_ [" allowDroppedNullPlaceholders" ] =
138+ features.allowDroppedNullPlaceholders_ ;
139+ builder.settings_ [" allowNumericKeys" ] = features.allowNumericKeys_ ;
140+
141+ std::unique_ptr<Json::CharReader> reader (builder.newCharReader ());
142+ Json::String errors;
143+ const bool parsingSuccessful =
144+ reader->parse (input.data (), input.data () + input.size (), root, &errors);
145+
146+ if (!parsingSuccessful) {
147+ std::cerr << " Failed to parse " << kind << " file: " << std::endl
148+ << errors << std::endl;
149+ return 1 ;
150+ }
151+
152+ // We may instead check the legacy implementation (to ensure it doesn't
153+ // randomly get broken).
154+ } else {
155+ Json::Reader reader (features);
156+ const bool parsingSuccessful =
157+ reader.parse (input.data (), input.data () + input.size (), *root);
158+ if (!parsingSuccessful) {
159+ std::cerr << " Failed to parse " << kind << " file: " << std::endl
160+ << reader.getFormatedErrorMessages () << std::endl;
161+ return 1 ;
162+ }
137163 }
164+
138165 if (!parseOnly) {
139166 FILE* factual = fopen (actual.c_str (), " wt" );
140167 if (!factual) {
141- printf (" Failed to create %s actual file.\n " , kind.c_str ());
168+ std::cerr << " Failed to create '" << kind << " ' actual file."
169+ << std::endl;
142170 return 2 ;
143171 }
144172 printValueTree (factual, *root);
@@ -172,7 +200,7 @@ static int rewriteValueTree(const Json::String& rewritePath,
172200 *rewrite = write (root);
173201 FILE* fout = fopen (rewritePath.c_str (), " wt" );
174202 if (!fout) {
175- printf ( " Failed to create rewrite file: %s \n " , rewritePath. c_str ()) ;
203+ std::cerr << " Failed to create rewrite file: " << rewritePath << std::endl ;
176204 return 2 ;
177205 }
178206 fprintf (fout, " %s\n " , rewrite->c_str ());
@@ -193,14 +221,15 @@ static Json::String removeSuffix(const Json::String& path,
193221static void printConfig () {
194222// Print the configuration used to compile JsonCpp
195223#if defined(JSON_NO_INT64)
196- printf ( " JSON_NO_INT64=1\n " ) ;
224+ std::cout << " JSON_NO_INT64=1" << std::endl ;
197225#else
198- printf ( " JSON_NO_INT64=0\n " ) ;
226+ std::cout << " JSON_NO_INT64=0" << std::endl ;
199227#endif
200228}
201229
202230static int printUsage (const char * argv[]) {
203- printf (" Usage: %s [--strict] input-json-file" , argv[0 ]);
231+ std::cout << " Usage: " << argv[0 ] << " [--strict] input-json-file"
232+ << std::endl;
204233 return 3 ;
205234}
206235
@@ -230,7 +259,7 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
230259 } else if (writerName == " BuiltStyledStreamWriter" ) {
231260 opts->write = &useBuiltStyledStreamWriter;
232261 } else {
233- printf ( " Unknown '--json-writer %s' \n " , writerName. c_str ()) ;
262+ std::cerr << " Unknown '--json-writer' " << writerName << std::endl ;
234263 return 4 ;
235264 }
236265 }
@@ -240,19 +269,20 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
240269 opts->path = argv[index];
241270 return 0 ;
242271}
243- static int runTest (Options const & opts) {
272+
273+ static int runTest (Options const & opts, bool use_legacy) {
244274 int exitCode = 0 ;
245275
246276 Json::String input = readInputTestFile (opts.path .c_str ());
247277 if (input.empty ()) {
248- printf ( " Failed to read input or empty input: %s \n " , opts.path . c_str ()) ;
278+ std::cerr << " Invalid input file: " << opts.path << std::endl ;
249279 return 3 ;
250280 }
251281
252282 Json::String basePath = removeSuffix (opts.path , " .json" );
253283 if (!opts.parseOnly && basePath.empty ()) {
254- printf ( " Bad input path. Path does not end with '.expected': \n %s \n " ,
255- opts. path . c_str ()) ;
284+ std::cerr << " Bad input path ' " << opts. path
285+ << " '. Must end with '.expected' " << std::endl ;
256286 return 3 ;
257287 }
258288
@@ -262,34 +292,47 @@ static int runTest(Options const& opts) {
262292
263293 Json::Value root;
264294 exitCode = parseAndSaveValueTree (input, actualPath, " input" , opts.features ,
265- opts.parseOnly , &root);
295+ opts.parseOnly , &root, use_legacy );
266296 if (exitCode || opts.parseOnly ) {
267297 return exitCode;
268298 }
299+
269300 Json::String rewrite;
270301 exitCode = rewriteValueTree (rewritePath, root, opts.write , &rewrite);
271302 if (exitCode) {
272303 return exitCode;
273304 }
305+
274306 Json::Value rewriteRoot;
275307 exitCode = parseAndSaveValueTree (rewrite, rewriteActualPath, " rewrite" ,
276- opts.features , opts.parseOnly , &rewriteRoot);
277- if (exitCode) {
278- return exitCode;
279- }
280- return 0 ;
308+ opts.features , opts.parseOnly , &rewriteRoot,
309+ use_legacy);
310+
311+ return exitCode;
281312}
313+
282314int main (int argc, const char * argv[]) {
283315 Options opts;
284316 try {
285317 int exitCode = parseCommandLine (argc, argv, &opts);
286318 if (exitCode != 0 ) {
287- printf ( " Failed to parse command-line." ) ;
319+ std::cerr << " Failed to parse command-line." << std::endl ;
288320 return exitCode;
289321 }
290- return runTest (opts);
322+
323+ const int modern_return_code = runTest (opts, false );
324+ if (modern_return_code) {
325+ return modern_return_code;
326+ }
327+
328+ const std::string filename =
329+ opts.path .substr (opts.path .find_last_of (" \\ /" ) + 1 );
330+ const bool should_run_legacy = (filename.rfind (" legacy_" , 0 ) == 0 );
331+ if (should_run_legacy) {
332+ return runTest (opts, true );
333+ }
291334 } catch (const std::exception& e) {
292- printf ( " Unhandled exception:\n %s \n " , e.what ()) ;
335+ std::cerr << " Unhandled exception:" << std::endl << e.what () << std::endl ;
293336 return 1 ;
294337 }
295338}
0 commit comments