Interactive Diff

July 12, 2019

Kernighan and Pike implemented idiff in about three pages of C; we use awk:

#! /usr/local/bin/gawk -f

BEGIN {

    ed = ENVIRON["EDITOR"]; if (ed == "") { ed = "ed" }
    outfile = "idiff.out"; tempfile = "idiff.tmp"; diffile = "idiff.dif"
    file1 = ARGV[1]; file2 = ARGV[2]; ARGV[1] = ARGV[2] = ""
    system("diff " file1 " " file2 " > " diffile)
    nf1 = nf2 = 0

    while (getline difline < diffile > 0) {

        cmd = substr(difline, match(difline, /[acd]/), 1)
        split(difline, linenums, cmd)
        split(linenums[1], ones, ","); split(linenums[2], twos, ",")
        from1 = ones[1]; to1 = ones[2] > 0 ? ones[2] : ones[1]
        from2 = twos[1]; to2 = twos[2] > 0 ? twos[2] : twos[1]
        nlines = to1-from1 + to2-from2 + 1
        if      (cmd == "a") { from1++ }
        else if (cmd == "c") { nlines += 2 }
        else if (cmd == "d") { from2++ }

        print difline
        while (nlines-- > 0) { getline difline < diffile; print difline }         do {             printf("? "); getline buf             if (substr(buf, 1, 1) == ">") {                 nskip(file1, to1-nf1); ncopy(file2, to2-nf2, outfile) }             else if (substr(buf, 1, 1) == "<") {                 nskip(file2, to2-nf2); ncopy(file1, to1-nf1, outfile) }             else if (substr(buf, 1, 1) == "e") {                 ncopy(file1, from1-1-nf1, outfile)                 nskip(file2, from2-1-nf2)                 ncopy(file1, to1+1-from1, tempfile)                 print "---" > tempfile                 ncopy(file2, to2+1-from2, tempfile)                 close(tempfile)                 system(ed " " tempfile)                 ncopy(tempfile, -1, outfile)                 close(tempfile) }             else if (substr(buf, 1, 1) == "!") {                 system(substr(buf, 2)); print "!" }             else { print "Enter < or > or e or !cmd" }         } while (substr(buf, 1, 1) !~ /[><e]/)
        nf1 = to1; nf2 = to2
    }
    system("rm " tempfile " " diffile)
}

function nskip(fin, n,    junk) {
    while (n-- != 0) { getline junk < fin } }
function ncopy(fin, n, fout,    line) {
    while ((n-- != 0) && (getline line < fin > 0)) { print line > fout } }

Every time I use awk I am amazed at how it fits such a neat “sweet spot” in language design. It’s a small language, but very expressive. Automatic initialization of variables, field splitting, associative arrays, implicit conversion between strings and numbers, and the pattern/action paradigm combine to make a highly productive programming environment.

You can run the program at https://ideone.com/nI9CNB.

Advertisement

Pages: 1 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: