1*44844408SAndroid Build Coastguard Worker // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2*44844408SAndroid Build Coastguard Worker // Distributed under MIT license, or public domain if desired and
3*44844408SAndroid Build Coastguard Worker // recognized in your jurisdiction.
4*44844408SAndroid Build Coastguard Worker // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5*44844408SAndroid Build Coastguard Worker
6*44844408SAndroid Build Coastguard Worker #if defined(__GNUC__)
7*44844408SAndroid Build Coastguard Worker #pragma GCC diagnostic push
8*44844408SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
9*44844408SAndroid Build Coastguard Worker #elif defined(_MSC_VER)
10*44844408SAndroid Build Coastguard Worker #pragma warning(disable : 4996)
11*44844408SAndroid Build Coastguard Worker #endif
12*44844408SAndroid Build Coastguard Worker
13*44844408SAndroid Build Coastguard Worker /* This executable is used for testing parser/writer using real JSON files.
14*44844408SAndroid Build Coastguard Worker */
15*44844408SAndroid Build Coastguard Worker
16*44844408SAndroid Build Coastguard Worker #include <algorithm> // sort
17*44844408SAndroid Build Coastguard Worker #include <cstdio>
18*44844408SAndroid Build Coastguard Worker #include <iostream>
19*44844408SAndroid Build Coastguard Worker #include <json/json.h>
20*44844408SAndroid Build Coastguard Worker #include <memory>
21*44844408SAndroid Build Coastguard Worker #include <sstream>
22*44844408SAndroid Build Coastguard Worker
23*44844408SAndroid Build Coastguard Worker struct Options {
24*44844408SAndroid Build Coastguard Worker Json::String path;
25*44844408SAndroid Build Coastguard Worker Json::Features features;
26*44844408SAndroid Build Coastguard Worker bool parseOnly;
27*44844408SAndroid Build Coastguard Worker using writeFuncType = Json::String (*)(Json::Value const&);
28*44844408SAndroid Build Coastguard Worker writeFuncType write;
29*44844408SAndroid Build Coastguard Worker };
30*44844408SAndroid Build Coastguard Worker
normalizeFloatingPointStr(double value)31*44844408SAndroid Build Coastguard Worker static Json::String normalizeFloatingPointStr(double value) {
32*44844408SAndroid Build Coastguard Worker char buffer[32];
33*44844408SAndroid Build Coastguard Worker jsoncpp_snprintf(buffer, sizeof(buffer), "%.16g", value);
34*44844408SAndroid Build Coastguard Worker buffer[sizeof(buffer) - 1] = 0;
35*44844408SAndroid Build Coastguard Worker Json::String s(buffer);
36*44844408SAndroid Build Coastguard Worker Json::String::size_type index = s.find_last_of("eE");
37*44844408SAndroid Build Coastguard Worker if (index != Json::String::npos) {
38*44844408SAndroid Build Coastguard Worker Json::String::size_type hasSign =
39*44844408SAndroid Build Coastguard Worker (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
40*44844408SAndroid Build Coastguard Worker Json::String::size_type exponentStartIndex = index + 1 + hasSign;
41*44844408SAndroid Build Coastguard Worker Json::String normalized = s.substr(0, exponentStartIndex);
42*44844408SAndroid Build Coastguard Worker Json::String::size_type indexDigit =
43*44844408SAndroid Build Coastguard Worker s.find_first_not_of('0', exponentStartIndex);
44*44844408SAndroid Build Coastguard Worker Json::String exponent = "0";
45*44844408SAndroid Build Coastguard Worker if (indexDigit != Json::String::npos) // There is an exponent different
46*44844408SAndroid Build Coastguard Worker // from 0
47*44844408SAndroid Build Coastguard Worker {
48*44844408SAndroid Build Coastguard Worker exponent = s.substr(indexDigit);
49*44844408SAndroid Build Coastguard Worker }
50*44844408SAndroid Build Coastguard Worker return normalized + exponent;
51*44844408SAndroid Build Coastguard Worker }
52*44844408SAndroid Build Coastguard Worker return s;
53*44844408SAndroid Build Coastguard Worker }
54*44844408SAndroid Build Coastguard Worker
readInputTestFile(const char * path)55*44844408SAndroid Build Coastguard Worker static Json::String readInputTestFile(const char* path) {
56*44844408SAndroid Build Coastguard Worker FILE* file = fopen(path, "rb");
57*44844408SAndroid Build Coastguard Worker if (!file)
58*44844408SAndroid Build Coastguard Worker return "";
59*44844408SAndroid Build Coastguard Worker fseek(file, 0, SEEK_END);
60*44844408SAndroid Build Coastguard Worker auto const size = ftell(file);
61*44844408SAndroid Build Coastguard Worker auto const usize = static_cast<size_t>(size);
62*44844408SAndroid Build Coastguard Worker fseek(file, 0, SEEK_SET);
63*44844408SAndroid Build Coastguard Worker auto buffer = new char[size + 1];
64*44844408SAndroid Build Coastguard Worker buffer[size] = 0;
65*44844408SAndroid Build Coastguard Worker Json::String text;
66*44844408SAndroid Build Coastguard Worker if (fread(buffer, 1, usize, file) == usize)
67*44844408SAndroid Build Coastguard Worker text = buffer;
68*44844408SAndroid Build Coastguard Worker fclose(file);
69*44844408SAndroid Build Coastguard Worker delete[] buffer;
70*44844408SAndroid Build Coastguard Worker return text;
71*44844408SAndroid Build Coastguard Worker }
72*44844408SAndroid Build Coastguard Worker
printValueTree(FILE * fout,Json::Value & value,const Json::String & path=".")73*44844408SAndroid Build Coastguard Worker static void printValueTree(FILE* fout, Json::Value& value,
74*44844408SAndroid Build Coastguard Worker const Json::String& path = ".") {
75*44844408SAndroid Build Coastguard Worker if (value.hasComment(Json::commentBefore)) {
76*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s\n", value.getComment(Json::commentBefore).c_str());
77*44844408SAndroid Build Coastguard Worker }
78*44844408SAndroid Build Coastguard Worker switch (value.type()) {
79*44844408SAndroid Build Coastguard Worker case Json::nullValue:
80*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=null\n", path.c_str());
81*44844408SAndroid Build Coastguard Worker break;
82*44844408SAndroid Build Coastguard Worker case Json::intValue:
83*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=%s\n", path.c_str(),
84*44844408SAndroid Build Coastguard Worker Json::valueToString(value.asLargestInt()).c_str());
85*44844408SAndroid Build Coastguard Worker break;
86*44844408SAndroid Build Coastguard Worker case Json::uintValue:
87*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=%s\n", path.c_str(),
88*44844408SAndroid Build Coastguard Worker Json::valueToString(value.asLargestUInt()).c_str());
89*44844408SAndroid Build Coastguard Worker break;
90*44844408SAndroid Build Coastguard Worker case Json::realValue:
91*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=%s\n", path.c_str(),
92*44844408SAndroid Build Coastguard Worker normalizeFloatingPointStr(value.asDouble()).c_str());
93*44844408SAndroid Build Coastguard Worker break;
94*44844408SAndroid Build Coastguard Worker case Json::stringValue:
95*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str());
96*44844408SAndroid Build Coastguard Worker break;
97*44844408SAndroid Build Coastguard Worker case Json::booleanValue:
98*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false");
99*44844408SAndroid Build Coastguard Worker break;
100*44844408SAndroid Build Coastguard Worker case Json::arrayValue: {
101*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s=[]\n", path.c_str());
102*44844408SAndroid Build Coastguard Worker Json::ArrayIndex size = value.size();
103*44844408SAndroid Build Coastguard Worker for (Json::ArrayIndex index = 0; index < size; ++index) {
104*44844408SAndroid Build Coastguard Worker static char buffer[16];
105*44844408SAndroid Build Coastguard Worker jsoncpp_snprintf(buffer, sizeof(buffer), "[%u]", index);
106*44844408SAndroid Build Coastguard Worker printValueTree(fout, value[index], path + buffer);
107*44844408SAndroid Build Coastguard Worker }
108*44844408SAndroid Build Coastguard Worker } break;
109*44844408SAndroid Build Coastguard Worker case Json::objectValue: {
110*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s={}\n", path.c_str());
111*44844408SAndroid Build Coastguard Worker Json::Value::Members members(value.getMemberNames());
112*44844408SAndroid Build Coastguard Worker std::sort(members.begin(), members.end());
113*44844408SAndroid Build Coastguard Worker Json::String suffix = *(path.end() - 1) == '.' ? "" : ".";
114*44844408SAndroid Build Coastguard Worker for (const auto& name : members) {
115*44844408SAndroid Build Coastguard Worker printValueTree(fout, value[name], path + suffix + name);
116*44844408SAndroid Build Coastguard Worker }
117*44844408SAndroid Build Coastguard Worker } break;
118*44844408SAndroid Build Coastguard Worker default:
119*44844408SAndroid Build Coastguard Worker break;
120*44844408SAndroid Build Coastguard Worker }
121*44844408SAndroid Build Coastguard Worker
122*44844408SAndroid Build Coastguard Worker if (value.hasComment(Json::commentAfter)) {
123*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s\n", value.getComment(Json::commentAfter).c_str());
124*44844408SAndroid Build Coastguard Worker }
125*44844408SAndroid Build Coastguard Worker }
126*44844408SAndroid Build Coastguard Worker
parseAndSaveValueTree(const Json::String & input,const Json::String & actual,const Json::String & kind,const Json::Features & features,bool parseOnly,Json::Value * root,bool use_legacy)127*44844408SAndroid Build Coastguard Worker static int parseAndSaveValueTree(const Json::String& input,
128*44844408SAndroid Build Coastguard Worker const Json::String& actual,
129*44844408SAndroid Build Coastguard Worker const Json::String& kind,
130*44844408SAndroid Build Coastguard Worker const Json::Features& features, bool parseOnly,
131*44844408SAndroid Build Coastguard Worker Json::Value* root, bool use_legacy) {
132*44844408SAndroid Build Coastguard Worker if (!use_legacy) {
133*44844408SAndroid Build Coastguard Worker Json::CharReaderBuilder builder;
134*44844408SAndroid Build Coastguard Worker
135*44844408SAndroid Build Coastguard Worker builder.settings_["allowComments"] = features.allowComments_;
136*44844408SAndroid Build Coastguard Worker builder.settings_["strictRoot"] = features.strictRoot_;
137*44844408SAndroid Build Coastguard Worker builder.settings_["allowDroppedNullPlaceholders"] =
138*44844408SAndroid Build Coastguard Worker features.allowDroppedNullPlaceholders_;
139*44844408SAndroid Build Coastguard Worker builder.settings_["allowNumericKeys"] = features.allowNumericKeys_;
140*44844408SAndroid Build Coastguard Worker
141*44844408SAndroid Build Coastguard Worker std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
142*44844408SAndroid Build Coastguard Worker Json::String errors;
143*44844408SAndroid Build Coastguard Worker const bool parsingSuccessful =
144*44844408SAndroid Build Coastguard Worker reader->parse(input.data(), input.data() + input.size(), root, &errors);
145*44844408SAndroid Build Coastguard Worker
146*44844408SAndroid Build Coastguard Worker if (!parsingSuccessful) {
147*44844408SAndroid Build Coastguard Worker std::cerr << "Failed to parse " << kind << " file: " << std::endl
148*44844408SAndroid Build Coastguard Worker << errors << std::endl;
149*44844408SAndroid Build Coastguard Worker return 1;
150*44844408SAndroid Build Coastguard Worker }
151*44844408SAndroid Build Coastguard Worker
152*44844408SAndroid Build Coastguard Worker // We may instead check the legacy implementation (to ensure it doesn't
153*44844408SAndroid Build Coastguard Worker // randomly get broken).
154*44844408SAndroid Build Coastguard Worker } else {
155*44844408SAndroid Build Coastguard Worker Json::Reader reader(features);
156*44844408SAndroid Build Coastguard Worker const bool parsingSuccessful =
157*44844408SAndroid Build Coastguard Worker reader.parse(input.data(), input.data() + input.size(), *root);
158*44844408SAndroid Build Coastguard Worker if (!parsingSuccessful) {
159*44844408SAndroid Build Coastguard Worker std::cerr << "Failed to parse " << kind << " file: " << std::endl
160*44844408SAndroid Build Coastguard Worker << reader.getFormatedErrorMessages() << std::endl;
161*44844408SAndroid Build Coastguard Worker return 1;
162*44844408SAndroid Build Coastguard Worker }
163*44844408SAndroid Build Coastguard Worker }
164*44844408SAndroid Build Coastguard Worker
165*44844408SAndroid Build Coastguard Worker if (!parseOnly) {
166*44844408SAndroid Build Coastguard Worker FILE* factual = fopen(actual.c_str(), "wt");
167*44844408SAndroid Build Coastguard Worker if (!factual) {
168*44844408SAndroid Build Coastguard Worker std::cerr << "Failed to create '" << kind << "' actual file."
169*44844408SAndroid Build Coastguard Worker << std::endl;
170*44844408SAndroid Build Coastguard Worker return 2;
171*44844408SAndroid Build Coastguard Worker }
172*44844408SAndroid Build Coastguard Worker printValueTree(factual, *root);
173*44844408SAndroid Build Coastguard Worker fclose(factual);
174*44844408SAndroid Build Coastguard Worker }
175*44844408SAndroid Build Coastguard Worker return 0;
176*44844408SAndroid Build Coastguard Worker }
177*44844408SAndroid Build Coastguard Worker // static Json::String useFastWriter(Json::Value const& root) {
178*44844408SAndroid Build Coastguard Worker // Json::FastWriter writer;
179*44844408SAndroid Build Coastguard Worker // writer.enableYAMLCompatibility();
180*44844408SAndroid Build Coastguard Worker // return writer.write(root);
181*44844408SAndroid Build Coastguard Worker // }
useStyledWriter(Json::Value const & root)182*44844408SAndroid Build Coastguard Worker static Json::String useStyledWriter(Json::Value const& root) {
183*44844408SAndroid Build Coastguard Worker Json::StyledWriter writer;
184*44844408SAndroid Build Coastguard Worker return writer.write(root);
185*44844408SAndroid Build Coastguard Worker }
useStyledStreamWriter(Json::Value const & root)186*44844408SAndroid Build Coastguard Worker static Json::String useStyledStreamWriter(Json::Value const& root) {
187*44844408SAndroid Build Coastguard Worker Json::StyledStreamWriter writer;
188*44844408SAndroid Build Coastguard Worker Json::OStringStream sout;
189*44844408SAndroid Build Coastguard Worker writer.write(sout, root);
190*44844408SAndroid Build Coastguard Worker return sout.str();
191*44844408SAndroid Build Coastguard Worker }
useBuiltStyledStreamWriter(Json::Value const & root)192*44844408SAndroid Build Coastguard Worker static Json::String useBuiltStyledStreamWriter(Json::Value const& root) {
193*44844408SAndroid Build Coastguard Worker Json::StreamWriterBuilder builder;
194*44844408SAndroid Build Coastguard Worker return Json::writeString(builder, root);
195*44844408SAndroid Build Coastguard Worker }
rewriteValueTree(const Json::String & rewritePath,const Json::Value & root,Options::writeFuncType write,Json::String * rewrite)196*44844408SAndroid Build Coastguard Worker static int rewriteValueTree(const Json::String& rewritePath,
197*44844408SAndroid Build Coastguard Worker const Json::Value& root,
198*44844408SAndroid Build Coastguard Worker Options::writeFuncType write,
199*44844408SAndroid Build Coastguard Worker Json::String* rewrite) {
200*44844408SAndroid Build Coastguard Worker *rewrite = write(root);
201*44844408SAndroid Build Coastguard Worker FILE* fout = fopen(rewritePath.c_str(), "wt");
202*44844408SAndroid Build Coastguard Worker if (!fout) {
203*44844408SAndroid Build Coastguard Worker std::cerr << "Failed to create rewrite file: " << rewritePath << std::endl;
204*44844408SAndroid Build Coastguard Worker return 2;
205*44844408SAndroid Build Coastguard Worker }
206*44844408SAndroid Build Coastguard Worker fprintf(fout, "%s\n", rewrite->c_str());
207*44844408SAndroid Build Coastguard Worker fclose(fout);
208*44844408SAndroid Build Coastguard Worker return 0;
209*44844408SAndroid Build Coastguard Worker }
210*44844408SAndroid Build Coastguard Worker
removeSuffix(const Json::String & path,const Json::String & extension)211*44844408SAndroid Build Coastguard Worker static Json::String removeSuffix(const Json::String& path,
212*44844408SAndroid Build Coastguard Worker const Json::String& extension) {
213*44844408SAndroid Build Coastguard Worker if (extension.length() >= path.length())
214*44844408SAndroid Build Coastguard Worker return Json::String("");
215*44844408SAndroid Build Coastguard Worker Json::String suffix = path.substr(path.length() - extension.length());
216*44844408SAndroid Build Coastguard Worker if (suffix != extension)
217*44844408SAndroid Build Coastguard Worker return Json::String("");
218*44844408SAndroid Build Coastguard Worker return path.substr(0, path.length() - extension.length());
219*44844408SAndroid Build Coastguard Worker }
220*44844408SAndroid Build Coastguard Worker
printConfig()221*44844408SAndroid Build Coastguard Worker static void printConfig() {
222*44844408SAndroid Build Coastguard Worker // Print the configuration used to compile JsonCpp
223*44844408SAndroid Build Coastguard Worker #if defined(JSON_NO_INT64)
224*44844408SAndroid Build Coastguard Worker std::cout << "JSON_NO_INT64=1" << std::endl;
225*44844408SAndroid Build Coastguard Worker #else
226*44844408SAndroid Build Coastguard Worker std::cout << "JSON_NO_INT64=0" << std::endl;
227*44844408SAndroid Build Coastguard Worker #endif
228*44844408SAndroid Build Coastguard Worker }
229*44844408SAndroid Build Coastguard Worker
printUsage(const char * argv[])230*44844408SAndroid Build Coastguard Worker static int printUsage(const char* argv[]) {
231*44844408SAndroid Build Coastguard Worker std::cout << "Usage: " << argv[0] << " [--strict] input-json-file"
232*44844408SAndroid Build Coastguard Worker << std::endl;
233*44844408SAndroid Build Coastguard Worker return 3;
234*44844408SAndroid Build Coastguard Worker }
235*44844408SAndroid Build Coastguard Worker
parseCommandLine(int argc,const char * argv[],Options * opts)236*44844408SAndroid Build Coastguard Worker static int parseCommandLine(int argc, const char* argv[], Options* opts) {
237*44844408SAndroid Build Coastguard Worker opts->parseOnly = false;
238*44844408SAndroid Build Coastguard Worker opts->write = &useStyledWriter;
239*44844408SAndroid Build Coastguard Worker if (argc < 2) {
240*44844408SAndroid Build Coastguard Worker return printUsage(argv);
241*44844408SAndroid Build Coastguard Worker }
242*44844408SAndroid Build Coastguard Worker int index = 1;
243*44844408SAndroid Build Coastguard Worker if (Json::String(argv[index]) == "--json-checker") {
244*44844408SAndroid Build Coastguard Worker opts->features = Json::Features::strictMode();
245*44844408SAndroid Build Coastguard Worker opts->parseOnly = true;
246*44844408SAndroid Build Coastguard Worker ++index;
247*44844408SAndroid Build Coastguard Worker }
248*44844408SAndroid Build Coastguard Worker if (Json::String(argv[index]) == "--json-config") {
249*44844408SAndroid Build Coastguard Worker printConfig();
250*44844408SAndroid Build Coastguard Worker return 3;
251*44844408SAndroid Build Coastguard Worker }
252*44844408SAndroid Build Coastguard Worker if (Json::String(argv[index]) == "--json-writer") {
253*44844408SAndroid Build Coastguard Worker ++index;
254*44844408SAndroid Build Coastguard Worker Json::String const writerName(argv[index++]);
255*44844408SAndroid Build Coastguard Worker if (writerName == "StyledWriter") {
256*44844408SAndroid Build Coastguard Worker opts->write = &useStyledWriter;
257*44844408SAndroid Build Coastguard Worker } else if (writerName == "StyledStreamWriter") {
258*44844408SAndroid Build Coastguard Worker opts->write = &useStyledStreamWriter;
259*44844408SAndroid Build Coastguard Worker } else if (writerName == "BuiltStyledStreamWriter") {
260*44844408SAndroid Build Coastguard Worker opts->write = &useBuiltStyledStreamWriter;
261*44844408SAndroid Build Coastguard Worker } else {
262*44844408SAndroid Build Coastguard Worker std::cerr << "Unknown '--json-writer' " << writerName << std::endl;
263*44844408SAndroid Build Coastguard Worker return 4;
264*44844408SAndroid Build Coastguard Worker }
265*44844408SAndroid Build Coastguard Worker }
266*44844408SAndroid Build Coastguard Worker if (index == argc || index + 1 < argc) {
267*44844408SAndroid Build Coastguard Worker return printUsage(argv);
268*44844408SAndroid Build Coastguard Worker }
269*44844408SAndroid Build Coastguard Worker opts->path = argv[index];
270*44844408SAndroid Build Coastguard Worker return 0;
271*44844408SAndroid Build Coastguard Worker }
272*44844408SAndroid Build Coastguard Worker
runTest(Options const & opts,bool use_legacy)273*44844408SAndroid Build Coastguard Worker static int runTest(Options const& opts, bool use_legacy) {
274*44844408SAndroid Build Coastguard Worker int exitCode = 0;
275*44844408SAndroid Build Coastguard Worker
276*44844408SAndroid Build Coastguard Worker Json::String input = readInputTestFile(opts.path.c_str());
277*44844408SAndroid Build Coastguard Worker if (input.empty()) {
278*44844408SAndroid Build Coastguard Worker std::cerr << "Invalid input file: " << opts.path << std::endl;
279*44844408SAndroid Build Coastguard Worker return 3;
280*44844408SAndroid Build Coastguard Worker }
281*44844408SAndroid Build Coastguard Worker
282*44844408SAndroid Build Coastguard Worker Json::String basePath = removeSuffix(opts.path, ".json");
283*44844408SAndroid Build Coastguard Worker if (!opts.parseOnly && basePath.empty()) {
284*44844408SAndroid Build Coastguard Worker std::cerr << "Bad input path '" << opts.path
285*44844408SAndroid Build Coastguard Worker << "'. Must end with '.expected'" << std::endl;
286*44844408SAndroid Build Coastguard Worker return 3;
287*44844408SAndroid Build Coastguard Worker }
288*44844408SAndroid Build Coastguard Worker
289*44844408SAndroid Build Coastguard Worker Json::String const actualPath = basePath + ".actual";
290*44844408SAndroid Build Coastguard Worker Json::String const rewritePath = basePath + ".rewrite";
291*44844408SAndroid Build Coastguard Worker Json::String const rewriteActualPath = basePath + ".actual-rewrite";
292*44844408SAndroid Build Coastguard Worker
293*44844408SAndroid Build Coastguard Worker Json::Value root;
294*44844408SAndroid Build Coastguard Worker exitCode = parseAndSaveValueTree(input, actualPath, "input", opts.features,
295*44844408SAndroid Build Coastguard Worker opts.parseOnly, &root, use_legacy);
296*44844408SAndroid Build Coastguard Worker if (exitCode || opts.parseOnly) {
297*44844408SAndroid Build Coastguard Worker return exitCode;
298*44844408SAndroid Build Coastguard Worker }
299*44844408SAndroid Build Coastguard Worker
300*44844408SAndroid Build Coastguard Worker Json::String rewrite;
301*44844408SAndroid Build Coastguard Worker exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite);
302*44844408SAndroid Build Coastguard Worker if (exitCode) {
303*44844408SAndroid Build Coastguard Worker return exitCode;
304*44844408SAndroid Build Coastguard Worker }
305*44844408SAndroid Build Coastguard Worker
306*44844408SAndroid Build Coastguard Worker Json::Value rewriteRoot;
307*44844408SAndroid Build Coastguard Worker exitCode = parseAndSaveValueTree(rewrite, rewriteActualPath, "rewrite",
308*44844408SAndroid Build Coastguard Worker opts.features, opts.parseOnly, &rewriteRoot,
309*44844408SAndroid Build Coastguard Worker use_legacy);
310*44844408SAndroid Build Coastguard Worker
311*44844408SAndroid Build Coastguard Worker return exitCode;
312*44844408SAndroid Build Coastguard Worker }
313*44844408SAndroid Build Coastguard Worker
main(int argc,const char * argv[])314*44844408SAndroid Build Coastguard Worker int main(int argc, const char* argv[]) {
315*44844408SAndroid Build Coastguard Worker Options opts;
316*44844408SAndroid Build Coastguard Worker try {
317*44844408SAndroid Build Coastguard Worker int exitCode = parseCommandLine(argc, argv, &opts);
318*44844408SAndroid Build Coastguard Worker if (exitCode != 0) {
319*44844408SAndroid Build Coastguard Worker std::cerr << "Failed to parse command-line." << std::endl;
320*44844408SAndroid Build Coastguard Worker return exitCode;
321*44844408SAndroid Build Coastguard Worker }
322*44844408SAndroid Build Coastguard Worker
323*44844408SAndroid Build Coastguard Worker const int modern_return_code = runTest(opts, false);
324*44844408SAndroid Build Coastguard Worker if (modern_return_code) {
325*44844408SAndroid Build Coastguard Worker return modern_return_code;
326*44844408SAndroid Build Coastguard Worker }
327*44844408SAndroid Build Coastguard Worker
328*44844408SAndroid Build Coastguard Worker const std::string filename =
329*44844408SAndroid Build Coastguard Worker opts.path.substr(opts.path.find_last_of("\\/") + 1);
330*44844408SAndroid Build Coastguard Worker const bool should_run_legacy = (filename.rfind("legacy_", 0) == 0);
331*44844408SAndroid Build Coastguard Worker if (should_run_legacy) {
332*44844408SAndroid Build Coastguard Worker return runTest(opts, true);
333*44844408SAndroid Build Coastguard Worker }
334*44844408SAndroid Build Coastguard Worker } catch (const std::exception& e) {
335*44844408SAndroid Build Coastguard Worker std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl;
336*44844408SAndroid Build Coastguard Worker return 1;
337*44844408SAndroid Build Coastguard Worker }
338*44844408SAndroid Build Coastguard Worker return 0;
339*44844408SAndroid Build Coastguard Worker }
340*44844408SAndroid Build Coastguard Worker
341*44844408SAndroid Build Coastguard Worker #if defined(__GNUC__)
342*44844408SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
343*44844408SAndroid Build Coastguard Worker #endif
344