############################################################################ # # File: patchu.icn # # Subject: Program to implement UNIX-like patch # # Author: Rich Morin # # Date: June 18, 1990 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This program reads a source file and a diff file, producing an # updated file. The diff file may be generated by the UNIX diff(1) # utility, or by diffu.icn, which uses dif.icn for the hard work. # # The original patch(1) utility, written by Larry Wall, is widely # used in the UNIX community. # # The diff file contains edit lines, separators, and text lines. # Edit lines may take the forms: # # #a#[,#] <- add lines # #[,#]c#[,#] <- change lines # #[,#]d# <- delete lines # # Change lines contain only the string "---". All other lines are # text lines. See diff(1) in any UNIX manual for more details. # ############################################################################ # # Requires: co-expressions # ############################################################################ # # Links: options, patch # ############################################################################ link options, patch record diff_rec(pos, diffs) global n1, n2, n3, n4 procedure main(arg) local t, rev, source, dfile, diffs t := options(arg, "r") rev := t["r"] if *arg ~= 2 then zot("usage: patchu source diffs") source := open(arg[1]) | zot("cannot open " || arg[1]) dfile := open(arg[2]) | zot("cannot open " || arg[2]) # every write(patch(source, get_diff(dfile))) # ? shouldn't need diffs ? diffs := [] every put(diffs, get_diff(dfile)) every write(patch(source, diffs, rev)) end procedure get_diff(dfile) # get diff record local ef, i1, i2, l1, l2, i, line repeat { if ef := get_edit(dfile) then { # write(">>> ",n1,", ",n2,", ",ef,", ",n3,", ",n4) if ef == "a" then i1 := n1+1 else i1 := n1 if ef == "d" then i2 := n3+1 else i2 := n3 l1 := [] l2 := [] if ef == !"cd" then { every i := n1 to n2 do { line := !dfile | zot("unexpected end of edit data(1)") if line[1:3] ~== "< " then zot("bad edit data(1): " || line) put(l1, line[3:0]) } } if ef == "c" then { line := !dfile | zot("unexpected end of edit data(2)") if line ~== "---" then zot("bad edit data(2): " || line) } if ef == !"ac" then { every i := n3 to n4 do { line := !dfile | zot("unexpected end of edit data(3)") if line[1:3] ~== "> " then zot("bad edit data(3): " || line) put(l2, line[3:0]) } } suspend [diff_rec(i1,l1), diff_rec(i2,l2)] } else fail } end procedure get_edit(dfile) # get edit parameters local edit, i1, i2, ef, i3, i4 edit := !dfile | fail i1 := i2 := many(&digits, edit) | zot("bad edit spec(1): " || edit) n1 := n2 := edit[1:i1] if edit[i1] == "," then { i2 := many(&digits, edit, i1+1) | zot("bad edit spec(2): " || edit) n2 := edit[i1+1:i2] } if edit[i2] == !"acd" then { ef := edit[i2] i3 := i4 := many(&digits, edit, i2+1) | zot("bad edit spec(3): " || edit) n3 := n4 := edit[i2+1:i3] if edit[i3] == "," then { i4 := many(&digits, edit, i3+1) | zot("bad edit spec(4): " || edit) n4 := edit[i3+1:i4] } } else zot("bad edit spec(5): " || edit) if i4 ~= *edit+1 then zot("bad edit spec(6): " || edit) if not 0 <= n3 <= n4 then zot("bad edit spec(7): " || edit) if not 0 <= n1 <= n2 then zot("bad edit spec(8): " || edit) return ef end procedure zot(msg) # exit w/message write(&errout, "patchu: " || msg) exit(1) end