# frozen_string_literal: truerequire'optparse'require'ostruct'require'diff/lcs/hunk'moduleDiff::LCS::Ldiff#:nodoc:BANNER=<<-COPYRIGHT
ldiff #{Diff::LCS::VERSION}
Copyright 2004-2019 Austin Ziegler
Part of Diff::LCS.
https://github.com/halostatue/diff-lcs
This program is free software. It may be redistributed and/or modified under
the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
MIT licence.
COPYRIGHTendclass<<Diff::LCS::Ldiffattr_reader:format,:lines#:nodoc:attr_reader:file_old,:file_new#:nodoc:attr_reader:data_old,:data_new#:nodoc:defrun(args,_input=$stdin,output=$stdout,error=$stderr)#:nodoc:@binary=nilargs.optionsdo|o|o.banner="Usage: #{File.basename($0)} [options] oldfile newfile"o.separator''o.on('-c','-C','--context [LINES]',Integer,'Displays a context diff with LINES lines','of context. Default 3 lines.')do|ctx|@format=:context@lines=ctx||3endo.on('-u','-U','--unified [LINES]',Integer,'Displays a unified diff with LINES lines','of context. Default 3 lines.')do|ctx|@format=:unified@lines=ctx||3endo.on('-e','Creates an \'ed\' script to change','oldfile to newfile.')do|_ctx|@format=:edendo.on('-f','Creates an \'ed\' script to change','oldfile to newfile in reverse order.')do|_ctx|@format=:reverse_edendo.on('-a','--text','Treat the files as text and compare them','line-by-line, even if they do not seem','to be text.')do|_txt|@binary=falseendo.on('--binary','Treats the files as binary.')do|_bin|@binary=trueendo.on('-q','--brief','Report only whether or not the files','differ, not the details.')do|_ctx|@format=:reportendo.on_tail('--help','Shows this text.')doerror<<oreturn0endo.on_tail('--version','Shows the version of Diff::LCS.')doerror<<Diff::LCS::Ldiff::BANNERreturn0endo.on_tail''o.on_tail'By default, runs produces an "old-style" diff, with output like UNIX diff.'o.parse!endunlessargs.size==2error<<args.optionsreturn127end# Defaults are for old-style diff@format||=:old@lines||=0file_old,file_new=*ARGVcase@formatwhen:contextchar_old='*'*3char_new='-'*3when:unifiedchar_old='-'*3char_new='+'*3end# After we've read up to a certain point in each file, the number of# items we've read from each file will differ by FLD (could be 0).file_length_difference=0if@binary.nil?or@binarydata_old=IO.read(file_old)data_new=IO.read(file_new)# Test binary statusif@binary.nil?old_txt=data_old[0,4096].scan(/\0/).empty?new_txt=data_new[0,4096].scan(/\0/).empty?@binary=!old_txtor!new_txtendunless@binarydata_old=data_old.split($/).map{|e|e.chomp}data_new=data_new.split($/).map{|e|e.chomp}endelsedata_old=IO.readlines(file_old).map{|e|e.chomp}data_new=IO.readlines(file_new).map{|e|e.chomp}end# diff yields lots of pieces, each of which is basically a Block objectif@binarydiffs=(data_old==data_new)elsediffs=Diff::LCS.diff(data_old,data_new)diffs=nilifdiffs.empty?endreturn0unlessdiffsif@format==:reportoutput<<"Files #{file_old} and #{file_new} differ\n"return1endif(@format==:unified)or(@format==:context)ft=File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')output<<"#{char_old}#{file_old}\t#{ft}\n"ft=File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.000000000 %z')output<<"#{char_new}#{file_new}\t#{ft}\n"end# Loop over hunks. If a hunk overlaps with the last hunk, join them.# Otherwise, print out the old one.oldhunk=hunk=nilif@format==:edreal_output=outputoutput=[]enddiffs.eachdo|piece|beginhunk=Diff::LCS::Hunk.new(data_old,data_new,piece,@lines,file_length_difference)file_length_difference=hunk.file_length_differencenextunlessoldhunknextif@lines.positive?andhunk.merge(oldhunk)output<<oldhunk.diff(@format)<<"\n"ensureoldhunk=hunkendendlast=oldhunk.diff(@format)last<<"\n"iflast.respond_to?(:end_with?)&&!last.end_with?("\n")output<<lastoutput.reverse_each{|e|real_output<<e.diff(:ed_finish)}if@format==:ed1endend