77#include " StringUtil.h"
88#include " TextFile.h"
99
10+ #include < nlohmann/json.hpp>
11+
1012#include < algorithm>
1113#include < cmath>
1214#include < cstring>
1315#include < ctime>
1416#include < fstream>
17+ #include < optional>
1518#include < sstream>
1619#include < tuple>
1720#include < unordered_map>
2023typedef std::tuple<unsigned , std::string> FileLength;
2124typedef const std::string* StringPtr;
2225typedef std::unordered_map<unsigned long , std::vector<StringPtr>> HashToFiles;
26+ using json = nlohmann::json;
2327
2428class ProcessResult {
2529 unsigned m_blocks;
@@ -159,14 +163,36 @@ namespace {
159163 return std::tuple (std::move (sourceFiles), matrix, files, locsTotal);
160164 }
161165
166+ void ReportSeqJSON (
167+ int begin,
168+ int end,
169+ int src_begin1,
170+ int src_end1,
171+ int src_begin2,
172+ int src_end2,
173+ const SourceFile& source1,
174+ const SourceFile& source2,
175+ json& json_out) {
176+ json_out.emplace_back (json{
177+ { " LineCount" , end - begin },
178+ { " SourceFile1" , source1.GetFilename () },
179+ { " StartLineNumber1" , src_begin1 },
180+ { " EndLineNumber1" , src_end1 },
181+ { " SourceFile2" , source2.GetFilename () },
182+ { " StartLineNumber2" , src_begin2 },
183+ { " EndLineNumber2" , src_end2 },
184+ { " Lines" , source1.GetLines (begin, end) } });
185+ }
186+
162187 void ReportSeq (
163188 int line1,
164189 int line2,
165190 int count,
166191 bool xml,
167192 const SourceFile& source1,
168193 const SourceFile& source2,
169- std::ostream& out) {
194+ std::ostream& out,
195+ std::optional<json>& json_out) {
170196 if (xml) {
171197 out
172198 << " <set LineCount=\" " << count << " \" >"
@@ -209,6 +235,17 @@ namespace {
209235
210236 out << " </lines>" << std::endl;
211237 out << " </set>" << std::endl;
238+ } else if (json_out) {
239+ ReportSeqJSON (
240+ line1,
241+ line1 + count,
242+ source1.GetLine (line1).GetLineNumber (),
243+ source1.GetLine (line1 + count).GetLineNumber (),
244+ source2.GetLine (line2).GetLineNumber (),
245+ source2.GetLine (line2 + count).GetLineNumber (),
246+ source1,
247+ source2,
248+ json_out.value ());
212249 } else {
213250 out
214251 << source1.GetFilename ()
@@ -231,7 +268,8 @@ namespace {
231268 const SourceFile& source2,
232269 std::vector<bool >& matrix,
233270 const Options& options,
234- std::ostream& outFile) {
271+ std::ostream& outFile,
272+ std::optional<json>& json_out) {
235273 size_t m = source1.GetNumOfLines ();
236274 size_t n = source2.GetNumOfLines ();
237275
@@ -279,7 +317,8 @@ namespace {
279317 options.GetOutputXml (),
280318 source1,
281319 source2,
282- outFile);
320+ outFile,
321+ json_out);
283322 duplicateLines += seqLen;
284323 blocks++;
285324 }
@@ -300,7 +339,8 @@ namespace {
300339 options.GetOutputXml (),
301340 source1,
302341 source2,
303- outFile);
342+ outFile,
343+ json_out);
304344 duplicateLines += seqLen;
305345 blocks++;
306346 }
@@ -324,7 +364,8 @@ namespace {
324364 options.GetOutputXml (),
325365 source1,
326366 source2,
327- outFile);
367+ outFile,
368+ json_out);
328369 duplicateLines += seqLen;
329370 blocks++;
330371 }
@@ -340,7 +381,8 @@ namespace {
340381 options.GetOutputXml (),
341382 source1,
342383 source2,
343- outFile);
384+ outFile,
385+ json_out);
344386 duplicateLines += seqLen;
345387 blocks++;
346388 }
@@ -357,7 +399,7 @@ int Duplo::Run(const Options& options) {
357399 std::ofstream of;
358400 if (options.GetOutputFilename () == " -" ) {
359401 buf = std::cout.rdbuf ();
360- if (options.GetOutputXml () == false ) {
402+ if (! options.GetOutputXml () && !options. GetOutputJSON () ) {
361403 logbuf = std::cout.rdbuf ();
362404 }
363405 else {
@@ -391,6 +433,8 @@ int Duplo::Run(const Options& options) {
391433 << std::endl;
392434 }
393435
436+ auto json_out = options.GetOutputJSON () ? std::optional (json ()) : std::nullopt ;
437+
394438 auto lines = LoadFileList (options.GetListFilename ());
395439 auto [sourceFiles, matrix, files, locsTotal] = LoadSourceFiles (
396440 lines,
@@ -429,7 +473,8 @@ int Duplo::Run(const Options& options) {
429473 left,
430474 matrix,
431475 options,
432- out);
476+ out,
477+ json_out);
433478
434479 // files to compare are those that have matching lines
435480 for (unsigned j = i + 1 ; j < sourceFiles.size (); j++) {
@@ -442,11 +487,12 @@ int Duplo::Run(const Options& options) {
442487 right,
443488 matrix,
444489 options,
445- out);
490+ out,
491+ json_out);
446492 }
447493 }
448494
449- if (options.GetOutputXml () == false ) {
495+ if (! options.GetOutputXml () && !options. GetOutputJSON () ) {
450496 if (processResult.Blocks () > 0 ) {
451497 log
452498 << left.GetFilename ()
@@ -465,6 +511,8 @@ int Duplo::Run(const Options& options) {
465511 out
466512 << " </duplo>"
467513 << std::endl;
514+ } else if (json_out) {
515+ out << json_out->dump (2 );
468516 } else {
469517 out
470518 << " Configuration:"
0 commit comments