Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Utility to do an N-way diff and N-way merge, for N>2. Uses the patience diff algorithm.
C++ Shell C
branch: master

Document the --simple and --complex command-line options.

I'm not sure why I failed to document "--complex" originally.
Maybe just because it's not as polished as I would have liked
it to be?
latest commit 418586e738
@Quuxplusone authored

README

This is "Difdef", a program that performs a multi-way diff among
a set of source files.  Difdef is released under the MIT (Expat)
license; see LICENSE for details.


==Command-line use==

To build Difdef, run "make". This will produce an executable called
"difdef", with the following behavior:

    difdef [-D FOO ...] file1 [file2 file3 ...]

Invoked without any -D options, "difdef" produces output similar
to the standard "diff" program: a merged version of the given files,
with a prefix on each line indicating which files contain that line.
Where "diff" uses a one-character prefix from the set [+- ], "difdef"
uses an N-character prefix: "a" in the first column means the line
is present in file1, "b" in the second column means the line is
present in file2, and so on.

Invoked with -D options (of which there must be exactly as many
as there are filenames on the command line), "difdef" produces a
merged version of the given files where each difference is
surrounded by #ifdefs of the form
    #if defined(V1) || defined(V4) || defined(V5)
    <differing text>
    #endif /* V1 || V4 || V5 */
In other words, the output of "difdef -DV1 -DV2 A B" is similar to
the output of "diff -DV2 A B". However, blank lines are treated
specially; they can be coalesced and/or moved outside an #ifdef
range. Also, "difdef A B C D E" produces readable output similar
to the above example, where iterated application of "diff -D"
would produce an unintelligible stew.

Invoked with the -u option, "difdef" behaves as a drop-in replacement
for "diff -u", mostly just to prove that I could do it.

==Hacking==

Internally, the code aims for reusability. To create a merge,
your code should #include "difdef.h". The class Difdef manages
all the resources associated with a single N-way merge; the
Difdef constructor requires that you specify N.

Once you have a Difdef object, you can populate it by calling
mydifdef.replace_file(i, <file>) for 0 <= i < N. Then call
mydifdef.merge(), which returns a Diff object. The Diff object
(which perhaps would have been better called a Merge object)
is just a wrapper around a vector of Lines, where each Line
knows which of the N files it comes from and what its text is.

The full "public interface" for Difdef looks like this:

        class Difdef {
            static const int MAX_FILES = 32;
            typedef unsigned int mask_t;
            class Diff {
                class Line {
                    const std::string *text;
                    mask_t mask;
                    bool in_file(int fileid) const;
                };
                const int dimension;
                mask_t all_files_mask() const;
                bool includes_file(int fileid) const;
            };
            Difdef(int num_files);
            void replace_file(int fileid, std::istream &);
            Diff merge() const;
            Diff merge(int, int) const;
            Diff merge(const std::set<int> &) const;
            const int NUM_FILES;
        };

Something went wrong with that request. Please try again.