17db96d56Sopenharmony_ci#! /usr/bin/env python3
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci# Module ndiff version 1.7.0
47db96d56Sopenharmony_ci# Released to the public domain 08-Dec-2000,
57db96d56Sopenharmony_ci# by Tim Peters (tim.one@home.com).
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci# ndiff.py is now simply a front-end to the difflib.ndiff() function.
107db96d56Sopenharmony_ci# Originally, it contained the difflib.SequenceMatcher class as well.
117db96d56Sopenharmony_ci# This completes the raiding of reusable code from this formerly
127db96d56Sopenharmony_ci# self-contained script.
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci"""ndiff [-q] file1 file2
157db96d56Sopenharmony_ci    or
167db96d56Sopenharmony_cindiff (-r1 | -r2) < ndiff_output > file1_or_file2
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ciPrint a human-friendly file difference report to stdout.  Both inter-
197db96d56Sopenharmony_ciand intra-line differences are noted.  In the second form, recreate file1
207db96d56Sopenharmony_ci(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ciIn the first form, if -q ("quiet") is not specified, the first two lines
237db96d56Sopenharmony_ciof output are
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci-: file1
267db96d56Sopenharmony_ci+: file2
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ciEach remaining line begins with a two-letter code:
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci    "- "    line unique to file1
317db96d56Sopenharmony_ci    "+ "    line unique to file2
327db96d56Sopenharmony_ci    "  "    line common to both files
337db96d56Sopenharmony_ci    "? "    line not present in either input file
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ciLines beginning with "? " attempt to guide the eye to intraline
367db96d56Sopenharmony_cidifferences, and were not present in either input file.  These lines can be
377db96d56Sopenharmony_ciconfusing if the source files contain tab characters.
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ciThe first file can be recovered by retaining only lines that begin with
407db96d56Sopenharmony_ci"  " or "- ", and deleting those 2-character prefixes; use ndiff with -r1.
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ciThe second file can be recovered similarly, but by retaining only "  " and
437db96d56Sopenharmony_ci"+ " lines; use ndiff with -r2; or, on Unix, the second file can be
447db96d56Sopenharmony_cirecovered by piping the output through
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci    sed -n '/^[+ ] /s/^..//p'
477db96d56Sopenharmony_ci"""
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci__version__ = 1, 7, 0
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ciimport difflib, sys
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_cidef fail(msg):
547db96d56Sopenharmony_ci    out = sys.stderr.write
557db96d56Sopenharmony_ci    out(msg + "\n\n")
567db96d56Sopenharmony_ci    out(__doc__)
577db96d56Sopenharmony_ci    return 0
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci# open a file & return the file object; gripe and return 0 if it
607db96d56Sopenharmony_ci# couldn't be opened
617db96d56Sopenharmony_cidef fopen(fname):
627db96d56Sopenharmony_ci    try:
637db96d56Sopenharmony_ci        return open(fname)
647db96d56Sopenharmony_ci    except IOError as detail:
657db96d56Sopenharmony_ci        return fail("couldn't open " + fname + ": " + str(detail))
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci# open two files & spray the diff to stdout; return false iff a problem
687db96d56Sopenharmony_cidef fcompare(f1name, f2name):
697db96d56Sopenharmony_ci    f1 = fopen(f1name)
707db96d56Sopenharmony_ci    f2 = fopen(f2name)
717db96d56Sopenharmony_ci    if not f1 or not f2:
727db96d56Sopenharmony_ci        return 0
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    a = f1.readlines(); f1.close()
757db96d56Sopenharmony_ci    b = f2.readlines(); f2.close()
767db96d56Sopenharmony_ci    for line in difflib.ndiff(a, b):
777db96d56Sopenharmony_ci        print(line, end=' ')
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci    return 1
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci# crack args (sys.argv[1:] is normal) & compare;
827db96d56Sopenharmony_ci# return false iff a problem
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_cidef main(args):
857db96d56Sopenharmony_ci    import getopt
867db96d56Sopenharmony_ci    try:
877db96d56Sopenharmony_ci        opts, args = getopt.getopt(args, "qr:")
887db96d56Sopenharmony_ci    except getopt.error as detail:
897db96d56Sopenharmony_ci        return fail(str(detail))
907db96d56Sopenharmony_ci    noisy = 1
917db96d56Sopenharmony_ci    qseen = rseen = 0
927db96d56Sopenharmony_ci    for opt, val in opts:
937db96d56Sopenharmony_ci        if opt == "-q":
947db96d56Sopenharmony_ci            qseen = 1
957db96d56Sopenharmony_ci            noisy = 0
967db96d56Sopenharmony_ci        elif opt == "-r":
977db96d56Sopenharmony_ci            rseen = 1
987db96d56Sopenharmony_ci            whichfile = val
997db96d56Sopenharmony_ci    if qseen and rseen:
1007db96d56Sopenharmony_ci        return fail("can't specify both -q and -r")
1017db96d56Sopenharmony_ci    if rseen:
1027db96d56Sopenharmony_ci        if args:
1037db96d56Sopenharmony_ci            return fail("no args allowed with -r option")
1047db96d56Sopenharmony_ci        if whichfile in ("1", "2"):
1057db96d56Sopenharmony_ci            restore(whichfile)
1067db96d56Sopenharmony_ci            return 1
1077db96d56Sopenharmony_ci        return fail("-r value must be 1 or 2")
1087db96d56Sopenharmony_ci    if len(args) != 2:
1097db96d56Sopenharmony_ci        return fail("need 2 filename args")
1107db96d56Sopenharmony_ci    f1name, f2name = args
1117db96d56Sopenharmony_ci    if noisy:
1127db96d56Sopenharmony_ci        print('-:', f1name)
1137db96d56Sopenharmony_ci        print('+:', f2name)
1147db96d56Sopenharmony_ci    return fcompare(f1name, f2name)
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci# read ndiff output from stdin, and print file1 (which=='1') or
1177db96d56Sopenharmony_ci# file2 (which=='2') to stdout
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_cidef restore(which):
1207db96d56Sopenharmony_ci    restored = difflib.restore(sys.stdin.readlines(), which)
1217db96d56Sopenharmony_ci    sys.stdout.writelines(restored)
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciif __name__ == '__main__':
1247db96d56Sopenharmony_ci    args = sys.argv[1:]
1257db96d56Sopenharmony_ci    if "-profile" in args:
1267db96d56Sopenharmony_ci        import profile, pstats
1277db96d56Sopenharmony_ci        args.remove("-profile")
1287db96d56Sopenharmony_ci        statf = "ndiff.pro"
1297db96d56Sopenharmony_ci        profile.run("main(args)", statf)
1307db96d56Sopenharmony_ci        stats = pstats.Stats(statf)
1317db96d56Sopenharmony_ci        stats.strip_dirs().sort_stats('time').print_stats()
1327db96d56Sopenharmony_ci    else:
1337db96d56Sopenharmony_ci        main(args)
134