137da2899SCharles.Forsythimplement Diff; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# diff - differential file comparison 437da2899SCharles.Forsyth# 537da2899SCharles.Forsyth# Uses an algorithm due to Harold Stone, which finds 637da2899SCharles.Forsyth# a pair of longest identical subsequences in the two 737da2899SCharles.Forsyth# files. 837da2899SCharles.Forsyth# 937da2899SCharles.Forsyth# The major goal is to generate the match vector J. 1037da2899SCharles.Forsyth# J[i] is the index of the line in file1 corresponding 1137da2899SCharles.Forsyth# to line i file0. J[i] = 0 if there is no 1237da2899SCharles.Forsyth# such line in file1. 1337da2899SCharles.Forsyth# 1437da2899SCharles.Forsyth# Lines are hashed so as to work in core. All potential 1537da2899SCharles.Forsyth# matches are located by sorting the lines of each file 1637da2899SCharles.Forsyth# on the hash (called value). In particular, this 1737da2899SCharles.Forsyth# collects the equivalence classes in file1 together. 1837da2899SCharles.Forsyth# Subroutine equiv replaces the value of each line in 1937da2899SCharles.Forsyth# file0 by the index of the first element of its 2037da2899SCharles.Forsyth# matching equivalence in (the reordered) file1. 2137da2899SCharles.Forsyth# To save space equiv squeezes file1 into a single 2237da2899SCharles.Forsyth# array member in which the equivalence classes 2337da2899SCharles.Forsyth# are simply concatenated, except that their first 2437da2899SCharles.Forsyth# members are flagged by changing sign. 2537da2899SCharles.Forsyth# 2637da2899SCharles.Forsyth# Next the indices that point into member are unsorted into 2737da2899SCharles.Forsyth# array class according to the original order of file0. 2837da2899SCharles.Forsyth# 2937da2899SCharles.Forsyth# The cleverness lies in routine stone. This marches 3037da2899SCharles.Forsyth# through the lines of file0, developing a vector klist 3137da2899SCharles.Forsyth# of "k-candidates". At step i a k-candidate is a matched 3237da2899SCharles.Forsyth# pair of lines x,y (x in file0 y in file1) such that 3337da2899SCharles.Forsyth# there is a common subsequence of lenght k 3437da2899SCharles.Forsyth# between the first i lines of file0 and the first y 3537da2899SCharles.Forsyth# lines of file1, but there is no such subsequence for 3637da2899SCharles.Forsyth# any smaller y. x is the earliest possible mate to y 3737da2899SCharles.Forsyth# that occurs in such a subsequence. 3837da2899SCharles.Forsyth# 3937da2899SCharles.Forsyth# Whenever any of the members of the equivalence class of 4037da2899SCharles.Forsyth# lines in file1 matable to a line in file0 has serial number 4137da2899SCharles.Forsyth# less than the y of some k-candidate, that k-candidate 4237da2899SCharles.Forsyth# with the smallest such y is replaced. The new 4337da2899SCharles.Forsyth# k-candidate is chained (via pred) to the current 4437da2899SCharles.Forsyth# k-1 candidate so that the actual subsequence can 4537da2899SCharles.Forsyth# be recovered. When a member has serial number greater 4637da2899SCharles.Forsyth# that the y of all k-candidates, the klist is extended. 4737da2899SCharles.Forsyth# At the end, the longest subsequence is pulled out 4837da2899SCharles.Forsyth# and placed in the array J by unravel. 4937da2899SCharles.Forsyth# 5037da2899SCharles.Forsyth# With J in hand, the matches there recorded are 5137da2899SCharles.Forsyth# check'ed against reality to assure that no spurious 5237da2899SCharles.Forsyth# matches have crept in due to hashing. If they have, 5337da2899SCharles.Forsyth# they are broken, and "jackpot " is recorded--a harmless 5437da2899SCharles.Forsyth# matter except that a true match for a spuriously 5537da2899SCharles.Forsyth# mated line may now be unnecessarily reported as a change. 5637da2899SCharles.Forsyth# 5737da2899SCharles.Forsyth# Much of the complexity of the program comes simply 5837da2899SCharles.Forsyth# from trying to minimize core utilization and 5937da2899SCharles.Forsyth# maximize the range of doable problems by dynamically 6037da2899SCharles.Forsyth# allocating what is needed and reusing what is not. 6137da2899SCharles.Forsyth# The core requirements for problems larger than somewhat 6237da2899SCharles.Forsyth# are (in words) 2*length(file0) + length(file1) + 6337da2899SCharles.Forsyth# 3*(number of k-candidates installed), typically about 6437da2899SCharles.Forsyth# 6n words for files of length n. 6537da2899SCharles.Forsyth# 6637da2899SCharles.Forsyth# 6737da2899SCharles.Forsyth 6837da2899SCharles.Forsythinclude "sys.m"; 6937da2899SCharles.Forsyth sys: Sys; 7037da2899SCharles.Forsyth 7137da2899SCharles.Forsythinclude "bufio.m"; 7237da2899SCharles.Forsyth bufio : Bufio; 7337da2899SCharles.ForsythIobuf : import bufio; 7437da2899SCharles.Forsyth 7537da2899SCharles.Forsythinclude "draw.m"; 7637da2899SCharles.Forsyth draw: Draw; 7737da2899SCharles.Forsythinclude "readdir.m"; 7837da2899SCharles.Forsyth readdir : Readdir; 7937da2899SCharles.Forsythinclude "string.m"; 8037da2899SCharles.Forsyth str : String; 8137da2899SCharles.Forsythinclude "arg.m"; 8237da2899SCharles.Forsyth 8337da2899SCharles.ForsythDiff : module 8437da2899SCharles.Forsyth{ 8537da2899SCharles.Forsyth init: fn(ctxt: ref Draw->Context, argv: list of string); 8637da2899SCharles.Forsyth}; 8737da2899SCharles.Forsyth 8837da2899SCharles.Forsythstderr: ref Sys->FD; 8937da2899SCharles.Forsyth 9037da2899SCharles.Forsythmode : int; # '\0', 'e', 'f', 'h' 9137da2899SCharles.Forsythbflag : int; # ignore multiple and trailing blanks 9237da2899SCharles.Forsythrflag : int; # recurse down directory trees 9337da2899SCharles.Forsythmflag : int; # pseudo flag: doing multiple files, one dir 9437da2899SCharles.Forsyth 9537da2899SCharles.ForsythREG, 9637da2899SCharles.ForsythBIN: con iota; 9737da2899SCharles.Forsyth 9837da2899SCharles.ForsythHALFINT : con 16; 9937da2899SCharles.ForsythUsage : con "usage: diff [ -efbwr ] file1 ... file2"; 10037da2899SCharles.Forsyth 10137da2899SCharles.Forsythcand : adt { 10237da2899SCharles.Forsyth x : int; 10337da2899SCharles.Forsyth y : int; 10437da2899SCharles.Forsyth pred : int; 10537da2899SCharles.Forsyth}; 10637da2899SCharles.Forsyth 10737da2899SCharles.Forsythline : adt { 10837da2899SCharles.Forsyth serial : int; 10937da2899SCharles.Forsyth value : int; 11037da2899SCharles.Forsyth}; 11137da2899SCharles.Forsyth 11237da2899SCharles.Forsythout : ref Iobuf; 11337da2899SCharles.Forsythfile := array[2] of array of line; 11437da2899SCharles.Forsythsfile := array[2] of array of line; # shortened by pruning common prefix and suffix 11537da2899SCharles.Forsythslen := array[2] of int; 11637da2899SCharles.Forsythilen := array[2] of int; 11737da2899SCharles.Forsythpref, suff, clen : int; # length of prefix and suffix 11837da2899SCharles.Forsythfirstchange : int; 11937da2899SCharles.Forsythclist : array of cand; # merely a free storage pot for candidates 12037da2899SCharles.ForsythJ : array of int; # will be overlaid on class 12137da2899SCharles.Forsythixold, ixnew : array of int; 12237da2899SCharles.Forsythinput := array[2] of ref Iobuf ; 12337da2899SCharles.Forsythfile1, file2 : string; 12437da2899SCharles.Forsythtmpname := array[] of {"/tmp/diff1", "/tmp/diff2"}; 12537da2899SCharles.Forsythwhichtmp : int; 12637da2899SCharles.Forsythanychange := 0; 12737da2899SCharles.Forsyth 12837da2899SCharles.Forsythinit(nil: ref Draw->Context, args: list of string) 12937da2899SCharles.Forsyth{ 13037da2899SCharles.Forsyth sys = load Sys Sys->PATH; 13137da2899SCharles.Forsyth stderr = sys->fildes(2); 13237da2899SCharles.Forsyth draw = load Draw Draw->PATH; 13337da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 13437da2899SCharles.Forsyth readdir = load Readdir Readdir->PATH; 13537da2899SCharles.Forsyth str = load String String->PATH; 13637da2899SCharles.Forsyth if (bufio==nil) 13737da2899SCharles.Forsyth fatal(sys->sprint("cannot load %s: %r", Bufio->PATH)); 13837da2899SCharles.Forsyth if (readdir==nil) 13937da2899SCharles.Forsyth fatal(sys->sprint("cannot load %s: %r", Readdir->PATH)); 14037da2899SCharles.Forsyth if (str==nil) 14137da2899SCharles.Forsyth fatal(sys->sprint("cannot load %s: %r", String->PATH)); 14237da2899SCharles.Forsyth arg := load Arg Arg->PATH; 14337da2899SCharles.Forsyth if (arg==nil) 14437da2899SCharles.Forsyth fatal(sys->sprint("cannot load %s: %r", Arg->PATH)); 14537da2899SCharles.Forsyth fsb, tsb : Sys->Dir; 14637da2899SCharles.Forsyth arg->init(args); 14737da2899SCharles.Forsyth while((o := arg->opt()) != 0) 14837da2899SCharles.Forsyth case o { 14937da2899SCharles.Forsyth 'e' or 'f' => 15037da2899SCharles.Forsyth mode = o; 15137da2899SCharles.Forsyth 'w' => 15237da2899SCharles.Forsyth bflag = 2; 15337da2899SCharles.Forsyth 'b' => 15437da2899SCharles.Forsyth bflag = 1; 15537da2899SCharles.Forsyth 'r' => 15637da2899SCharles.Forsyth rflag = 1; 15737da2899SCharles.Forsyth 'm' => 15837da2899SCharles.Forsyth mflag = 1; 15937da2899SCharles.Forsyth * => 16037da2899SCharles.Forsyth fatal(Usage); 16137da2899SCharles.Forsyth } 16237da2899SCharles.Forsyth tmp := arg->argv(); 16337da2899SCharles.Forsyth arg = nil; 16437da2899SCharles.Forsyth j := len tmp; 16537da2899SCharles.Forsyth if (j < 2) 16637da2899SCharles.Forsyth fatal(Usage); 16737da2899SCharles.Forsyth arr := array[j] of string; 16837da2899SCharles.Forsyth for(i:=0;i<j;i++){ 16937da2899SCharles.Forsyth arr[i]= hd tmp; 17037da2899SCharles.Forsyth tmp = tl tmp; 17137da2899SCharles.Forsyth } 17237da2899SCharles.Forsyth 17337da2899SCharles.Forsyth (i,tsb)=sys->stat(arr[j-1]); 17437da2899SCharles.Forsyth if (i == -1) 17537da2899SCharles.Forsyth fatal(sys->sprint("can't stat %s: %r", arr[j-1])); 17637da2899SCharles.Forsyth if (j > 2) { 17737da2899SCharles.Forsyth if (!(tsb.qid.qtype&Sys->QTDIR)) 17837da2899SCharles.Forsyth fatal(Usage); 17937da2899SCharles.Forsyth mflag = 1; 18037da2899SCharles.Forsyth } 18137da2899SCharles.Forsyth else { 18237da2899SCharles.Forsyth (i,fsb)=sys->stat(arr[0]); 18337da2899SCharles.Forsyth if (i == -1) 18437da2899SCharles.Forsyth fatal(sys->sprint("can't stat %s: %r", arr[0])); 18537da2899SCharles.Forsyth if ((fsb.qid.qtype&Sys->QTDIR) && (tsb.qid.qtype&Sys->QTDIR)) 18637da2899SCharles.Forsyth mflag = 1; 18737da2899SCharles.Forsyth } 18837da2899SCharles.Forsyth out=bufio->fopen(sys->fildes(1),Bufio->OWRITE); 18937da2899SCharles.Forsyth for (i = 0; i < j-1; i++) { 19037da2899SCharles.Forsyth diff(arr[i], arr[j-1], 0); 19137da2899SCharles.Forsyth rmtmpfiles(); 19237da2899SCharles.Forsyth } 19337da2899SCharles.Forsyth rmtmpfiles(); 19437da2899SCharles.Forsyth out.flush(); 19537da2899SCharles.Forsyth if (anychange) 19637da2899SCharles.Forsyth raise "fail:some"; 19737da2899SCharles.Forsyth} 19837da2899SCharles.Forsyth 19937da2899SCharles.Forsyth############################# diffreg from here .... 20037da2899SCharles.Forsyth 20137da2899SCharles.Forsyth# shellsort CACM #201 20237da2899SCharles.Forsyth 20337da2899SCharles.Forsythsort(a : array of line, n : int) 20437da2899SCharles.Forsyth{ 20537da2899SCharles.Forsyth w : line; 20637da2899SCharles.Forsyth m := 0; 20737da2899SCharles.Forsyth for (i := 1; i <= n; i *= 2) 20837da2899SCharles.Forsyth m = 2*i - 1; 20937da2899SCharles.Forsyth for (m /= 2; m != 0; m /= 2) { 21037da2899SCharles.Forsyth for (j := 1; j <= n-m ; j++) { 21137da2899SCharles.Forsyth ai:=j; 21237da2899SCharles.Forsyth aim:=j+m; 21337da2899SCharles.Forsyth do { 21437da2899SCharles.Forsyth if (a[aim].value > a[ai].value || 21537da2899SCharles.Forsyth a[aim].value == a[ai].value && 21637da2899SCharles.Forsyth a[aim].serial > a[ai].serial) 21737da2899SCharles.Forsyth break; 21837da2899SCharles.Forsyth w = a[ai]; 21937da2899SCharles.Forsyth a[ai] = a[aim]; 22037da2899SCharles.Forsyth a[aim] = w; 22137da2899SCharles.Forsyth aim=ai; 22237da2899SCharles.Forsyth ai-=m; 22337da2899SCharles.Forsyth } while (ai > 0 && aim >= ai); 22437da2899SCharles.Forsyth } 22537da2899SCharles.Forsyth } 22637da2899SCharles.Forsyth} 22737da2899SCharles.Forsyth 22837da2899SCharles.Forsythunsort(f : array of line, l : int) : array of int 22937da2899SCharles.Forsyth{ 23037da2899SCharles.Forsyth i : int; 23137da2899SCharles.Forsyth a := array[l+1] of int; 23237da2899SCharles.Forsyth for(i=1;i<=l;i++) 23337da2899SCharles.Forsyth a[f[i].serial] = f[i].value; 23437da2899SCharles.Forsyth return a; 23537da2899SCharles.Forsyth} 23637da2899SCharles.Forsyth 23737da2899SCharles.Forsythprune() 23837da2899SCharles.Forsyth{ 23937da2899SCharles.Forsyth for(pref=0;pref< ilen[0]&&pref< ilen[1]&& 24037da2899SCharles.Forsyth file[0][pref+1].value==file[1][pref+1].value; 24137da2899SCharles.Forsyth pref++ ) ; 24237da2899SCharles.Forsyth for(suff=0;suff< ilen[0]-pref&&suff< ilen[1]-pref&& 24337da2899SCharles.Forsyth file[0][ilen[0]-suff].value==file[1][ilen[1]-suff].value; 24437da2899SCharles.Forsyth suff++) ; 24537da2899SCharles.Forsyth for(j:=0;j<2;j++) { 24637da2899SCharles.Forsyth sfile[j] = file[j][pref:]; 24737da2899SCharles.Forsyth slen[j]= ilen[j]-pref-suff; 24837da2899SCharles.Forsyth for(i:=0;i<=slen[j];i++) 24937da2899SCharles.Forsyth sfile[j][i].serial = i; 25037da2899SCharles.Forsyth } 25137da2899SCharles.Forsyth} 25237da2899SCharles.Forsyth 25337da2899SCharles.Forsythequiv(a: array of line, n:int , b: array of line, m: int, c : array of int) 25437da2899SCharles.Forsyth{ 25537da2899SCharles.Forsyth i := 1; 25637da2899SCharles.Forsyth j := 1; 25737da2899SCharles.Forsyth while(i<=n && j<=m) { 25837da2899SCharles.Forsyth if(a[i].value < b[j].value) 25937da2899SCharles.Forsyth a[i++].value = 0; 26037da2899SCharles.Forsyth else if(a[i].value == b[j].value) 26137da2899SCharles.Forsyth a[i++].value = j; 26237da2899SCharles.Forsyth else 26337da2899SCharles.Forsyth j++; 26437da2899SCharles.Forsyth } 26537da2899SCharles.Forsyth while(i <= n) 26637da2899SCharles.Forsyth a[i++].value = 0; 26737da2899SCharles.Forsyth b[m+1].value = 0; # huh ? 26837da2899SCharles.Forsyth j = 1; 26937da2899SCharles.Forsyth while(j <= m) { 27037da2899SCharles.Forsyth c[j] = -b[j].serial; 27137da2899SCharles.Forsyth while(b[j+1].value == b[j].value) { 27237da2899SCharles.Forsyth j++; 27337da2899SCharles.Forsyth c[j] = b[j].serial; 27437da2899SCharles.Forsyth } 27537da2899SCharles.Forsyth j++; 27637da2899SCharles.Forsyth } 27737da2899SCharles.Forsyth c[j] = -1; 27837da2899SCharles.Forsyth} 27937da2899SCharles.Forsyth 28037da2899SCharles.Forsythnewcand(x, y, pred : int) : int 28137da2899SCharles.Forsyth{ 28237da2899SCharles.Forsyth if (clen==len clist){ 28337da2899SCharles.Forsyth q := array[clen*2] of cand; 28437da2899SCharles.Forsyth q[0:]=clist; 28537da2899SCharles.Forsyth clist= array[clen*2] of cand; 28637da2899SCharles.Forsyth clist[0:]=q; 28737da2899SCharles.Forsyth q=nil; 28837da2899SCharles.Forsyth } 28937da2899SCharles.Forsyth clist[clen].x=x; 29037da2899SCharles.Forsyth clist[clen].y=y; 29137da2899SCharles.Forsyth clist[clen].pred=pred; 29237da2899SCharles.Forsyth return clen++; 29337da2899SCharles.Forsyth} 29437da2899SCharles.Forsyth 29537da2899SCharles.Forsythsearch(c : array of int, k,y : int) : int 29637da2899SCharles.Forsyth{ 29737da2899SCharles.Forsyth if(clist[c[k]].y < y) # quick look for typical case 29837da2899SCharles.Forsyth return k+1; 29937da2899SCharles.Forsyth i := 0; 30037da2899SCharles.Forsyth j := k+1; 30137da2899SCharles.Forsyth while((l:=(i+j)/2) > i) { 30237da2899SCharles.Forsyth t := clist[c[l]].y; 30337da2899SCharles.Forsyth if(t > y) 30437da2899SCharles.Forsyth j = l; 30537da2899SCharles.Forsyth else if(t < y) 30637da2899SCharles.Forsyth i = l; 30737da2899SCharles.Forsyth else 30837da2899SCharles.Forsyth return l; 30937da2899SCharles.Forsyth } 31037da2899SCharles.Forsyth return l+1; 31137da2899SCharles.Forsyth} 31237da2899SCharles.Forsyth 31337da2899SCharles.Forsythstone(a : array of int ,n : int, b: array of int , c : array of int) : int 31437da2899SCharles.Forsyth{ 31537da2899SCharles.Forsyth oldc, oldl, tc, l ,y : int; 31637da2899SCharles.Forsyth k := 0; 31737da2899SCharles.Forsyth c[0] = newcand(0,0,0); 31837da2899SCharles.Forsyth for(i:=1; i<=n; i++) { 31937da2899SCharles.Forsyth j := a[i]; 32037da2899SCharles.Forsyth if(j==0) 32137da2899SCharles.Forsyth continue; 32237da2899SCharles.Forsyth y = -b[j]; 32337da2899SCharles.Forsyth oldl = 0; 32437da2899SCharles.Forsyth oldc = c[0]; 32537da2899SCharles.Forsyth do { 32637da2899SCharles.Forsyth if(y <= clist[oldc].y) 32737da2899SCharles.Forsyth continue; 32837da2899SCharles.Forsyth l = search(c, k, y); 32937da2899SCharles.Forsyth if(l!=oldl+1) 33037da2899SCharles.Forsyth oldc = c[l-1]; 33137da2899SCharles.Forsyth if(l<=k) { 33237da2899SCharles.Forsyth if(clist[c[l]].y <= y) 33337da2899SCharles.Forsyth continue; 33437da2899SCharles.Forsyth tc = c[l]; 33537da2899SCharles.Forsyth c[l] = newcand(i,y,oldc); 33637da2899SCharles.Forsyth oldc = tc; 33737da2899SCharles.Forsyth oldl = l; 33837da2899SCharles.Forsyth } else { 33937da2899SCharles.Forsyth c[l] = newcand(i,y,oldc); 34037da2899SCharles.Forsyth k++; 34137da2899SCharles.Forsyth break; 34237da2899SCharles.Forsyth } 34337da2899SCharles.Forsyth } while((y=b[j+=1]) > 0); 34437da2899SCharles.Forsyth } 34537da2899SCharles.Forsyth return k; 34637da2899SCharles.Forsyth} 34737da2899SCharles.Forsyth 34837da2899SCharles.Forsythunravel(p : int) 34937da2899SCharles.Forsyth{ 35037da2899SCharles.Forsyth for(i:=0; i<=ilen[0]; i++) { 35137da2899SCharles.Forsyth if (i <= pref) 35237da2899SCharles.Forsyth J[i] = i; 35337da2899SCharles.Forsyth else if (i > ilen[0]-suff) 35437da2899SCharles.Forsyth J[i] = i+ ilen[1]-ilen[0]; 35537da2899SCharles.Forsyth else 35637da2899SCharles.Forsyth J[i] = 0; 35737da2899SCharles.Forsyth } 35837da2899SCharles.Forsyth for(q:=clist[p];q.y!=0;q=clist[q.pred]) 35937da2899SCharles.Forsyth J[q.x+pref] = q.y+pref; 36037da2899SCharles.Forsyth} 36137da2899SCharles.Forsyth 36237da2899SCharles.Forsythoutput() 36337da2899SCharles.Forsyth{ 36437da2899SCharles.Forsyth i1: int; 36537da2899SCharles.Forsyth m := ilen[0]; 36637da2899SCharles.Forsyth J[0] = 0; 36737da2899SCharles.Forsyth J[m+1] = ilen[1]+1; 36837da2899SCharles.Forsyth if (mode != 'e') { 36937da2899SCharles.Forsyth for (i0 := 1; i0 <= m; i0 = i1+1) { 37037da2899SCharles.Forsyth while (i0 <= m && J[i0] == J[i0-1]+1) 37137da2899SCharles.Forsyth i0++; 37237da2899SCharles.Forsyth j0 := J[i0-1]+1; 37337da2899SCharles.Forsyth i1 = i0-1; 37437da2899SCharles.Forsyth while (i1 < m && J[i1+1] == 0) 37537da2899SCharles.Forsyth i1++; 37637da2899SCharles.Forsyth j1 := J[i1+1]-1; 37737da2899SCharles.Forsyth J[i1] = j1; 37837da2899SCharles.Forsyth change(i0, i1, j0, j1); 37937da2899SCharles.Forsyth } 38037da2899SCharles.Forsyth } 38137da2899SCharles.Forsyth else { 38237da2899SCharles.Forsyth for (i0 := m; i0 >= 1; i0 = i1-1) { 38337da2899SCharles.Forsyth while (i0 >= 1 && J[i0] == J[i0+1]-1 && J[i0]) 38437da2899SCharles.Forsyth i0--; 38537da2899SCharles.Forsyth j0 := J[i0+1]-1; 38637da2899SCharles.Forsyth i1 = i0+1; 38737da2899SCharles.Forsyth while (i1 > 1 && J[i1-1] == 0) 38837da2899SCharles.Forsyth i1--; 38937da2899SCharles.Forsyth j1 := J[i1-1]+1; 39037da2899SCharles.Forsyth J[i1] = j1; 39137da2899SCharles.Forsyth change(i1 , i0, j1, j0); 39237da2899SCharles.Forsyth } 39337da2899SCharles.Forsyth } 39437da2899SCharles.Forsyth if (m == 0) 39537da2899SCharles.Forsyth change(1, 0, 1, ilen[1]); 39637da2899SCharles.Forsyth out.flush(); 39737da2899SCharles.Forsyth} 39837da2899SCharles.Forsyth 39937da2899SCharles.Forsythdiffreg(f,t : string) 40037da2899SCharles.Forsyth{ 40137da2899SCharles.Forsyth k : int; 40237da2899SCharles.Forsyth 40337da2899SCharles.Forsyth (b0, b0type) := prepare(0, f); 40437da2899SCharles.Forsyth if (b0==nil) 40537da2899SCharles.Forsyth return; 40637da2899SCharles.Forsyth (b1, b1type) := prepare(1, t); 40737da2899SCharles.Forsyth if (b1==nil) { 40837da2899SCharles.Forsyth b0=nil; 40937da2899SCharles.Forsyth return; 41037da2899SCharles.Forsyth } 41137da2899SCharles.Forsyth if (b0type == BIN || b1type == BIN) { 41237da2899SCharles.Forsyth if (cmp(b0, b1)) { 41337da2899SCharles.Forsyth out.puts(sys->sprint("Binary files %s %s differ\n", f, t)); 41437da2899SCharles.Forsyth anychange = 1; 41537da2899SCharles.Forsyth } 41637da2899SCharles.Forsyth b0 = nil; 41737da2899SCharles.Forsyth b1 = nil; 41837da2899SCharles.Forsyth return; 41937da2899SCharles.Forsyth } 42037da2899SCharles.Forsyth clen=0; 42137da2899SCharles.Forsyth prune(); 42237da2899SCharles.Forsyth file[0]=nil; 42337da2899SCharles.Forsyth file[1]=nil; 42437da2899SCharles.Forsyth sort(sfile[0],slen[0]); 42537da2899SCharles.Forsyth sort(sfile[1],slen[1]); 42637da2899SCharles.Forsyth member := array[slen[1]+2] of int; 42737da2899SCharles.Forsyth equiv(sfile[0], slen[0],sfile[1],slen[1], member); 42837da2899SCharles.Forsyth class:=unsort(sfile[0],slen[0]); 42937da2899SCharles.Forsyth sfile[0]=nil; 43037da2899SCharles.Forsyth sfile[1]=nil; 43137da2899SCharles.Forsyth klist := array[slen[0]+2] of int; 43237da2899SCharles.Forsyth clist = array[1] of cand; 43337da2899SCharles.Forsyth k = stone(class, slen[0], member, klist); 43437da2899SCharles.Forsyth J = array[ilen[0]+2] of int; 43537da2899SCharles.Forsyth unravel(klist[k]); 43637da2899SCharles.Forsyth clist=nil; 43737da2899SCharles.Forsyth klist=nil; 43837da2899SCharles.Forsyth class=nil; 43937da2899SCharles.Forsyth member=nil; 44037da2899SCharles.Forsyth ixold = array[ilen[0]+2] of int; 44137da2899SCharles.Forsyth ixnew = array[ilen[1]+2] of int; 44237da2899SCharles.Forsyth 44337da2899SCharles.Forsyth b0.seek(big 0, 0); 44437da2899SCharles.Forsyth b1.seek(big 0, 0); 44537da2899SCharles.Forsyth check(b0, b1); 44637da2899SCharles.Forsyth output(); 44737da2899SCharles.Forsyth ixold=nil; 44837da2899SCharles.Forsyth ixnew=nil; 44937da2899SCharles.Forsyth b0=nil; 45037da2899SCharles.Forsyth b1=nil; 45137da2899SCharles.Forsyth} 45237da2899SCharles.Forsyth 45337da2899SCharles.Forsyth######################## diffio starts here... 45437da2899SCharles.Forsyth 45537da2899SCharles.Forsyth 45637da2899SCharles.Forsyth# hashing has the effect of 45737da2899SCharles.Forsyth# arranging line in 7-bit bytes and then 45837da2899SCharles.Forsyth# summing 1-s complement in 16-bit hunks 45937da2899SCharles.Forsyth 46037da2899SCharles.Forsythreadhash(bp : ref Iobuf) : int 46137da2899SCharles.Forsyth{ 46237da2899SCharles.Forsyth sum := 1; 46337da2899SCharles.Forsyth shift := 0; 46437da2899SCharles.Forsyth buf := bp.gets('\n'); 46537da2899SCharles.Forsyth if (buf == nil) 46637da2899SCharles.Forsyth return 0; 46737da2899SCharles.Forsyth buf = buf[0:len buf -1]; 46837da2899SCharles.Forsyth p := 0; 46937da2899SCharles.Forsyth case bflag { 47037da2899SCharles.Forsyth # various types of white space handling 47137da2899SCharles.Forsyth 0 => 47237da2899SCharles.Forsyth while (p< len buf) { 47337da2899SCharles.Forsyth sum += (buf[p] << (shift &= (HALFINT-1))); 47437da2899SCharles.Forsyth p++; 47537da2899SCharles.Forsyth shift += 7; 47637da2899SCharles.Forsyth } 47737da2899SCharles.Forsyth 1 => 47837da2899SCharles.Forsyth 47937da2899SCharles.Forsyth # coalesce multiple white-space 48037da2899SCharles.Forsyth 48137da2899SCharles.Forsyth for (space := 0; p< len buf; p++) { 48237da2899SCharles.Forsyth if (buf[p]==' ' || buf[p]=='\t') { 48337da2899SCharles.Forsyth space++; 48437da2899SCharles.Forsyth continue; 48537da2899SCharles.Forsyth } 48637da2899SCharles.Forsyth if (space) { 48737da2899SCharles.Forsyth shift += 7; 48837da2899SCharles.Forsyth space = 0; 48937da2899SCharles.Forsyth } 49037da2899SCharles.Forsyth sum += (buf[p] << (shift &= (HALFINT-1))); 49137da2899SCharles.Forsyth p++; 49237da2899SCharles.Forsyth shift += 7; 49337da2899SCharles.Forsyth } 49437da2899SCharles.Forsyth * => 49537da2899SCharles.Forsyth 49637da2899SCharles.Forsyth # strip all white-space 49737da2899SCharles.Forsyth 49837da2899SCharles.Forsyth while (p< len buf) { 49937da2899SCharles.Forsyth if (buf[p]==' ' || buf[p]=='\t') { 50037da2899SCharles.Forsyth p++; 50137da2899SCharles.Forsyth continue; 50237da2899SCharles.Forsyth } 50337da2899SCharles.Forsyth sum += (buf[p] << (shift &= (HALFINT-1))); 50437da2899SCharles.Forsyth p++; 50537da2899SCharles.Forsyth shift += 7; 50637da2899SCharles.Forsyth } 50737da2899SCharles.Forsyth } 50837da2899SCharles.Forsyth return sum; 50937da2899SCharles.Forsyth} 51037da2899SCharles.Forsyth 51137da2899SCharles.Forsythprepare(i : int, arg : string) : (ref Iobuf, int) 51237da2899SCharles.Forsyth{ 51337da2899SCharles.Forsyth h : int; 51437da2899SCharles.Forsyth bp := bufio->open(arg,Bufio->OREAD); 51537da2899SCharles.Forsyth if (bp==nil) { 51637da2899SCharles.Forsyth error(sys->sprint("cannot open %s: %r", arg)); 51737da2899SCharles.Forsyth return (nil, 0); 51837da2899SCharles.Forsyth } 51937da2899SCharles.Forsyth buf := array[1024] of byte; 52037da2899SCharles.Forsyth n :=bp.read(buf, len buf); 52137da2899SCharles.Forsyth str1 := string buf[0:n]; 52237da2899SCharles.Forsyth for (j:=0;j<len str1 -2;j++) 52337da2899SCharles.Forsyth if (str1[j] == Sys->UTFerror) 52437da2899SCharles.Forsyth return (bp, BIN); 52537da2899SCharles.Forsyth bp.seek(big 0, Sys->SEEKSTART); 52637da2899SCharles.Forsyth p := array[4] of line; 52737da2899SCharles.Forsyth for (j = 0; h = readhash(bp); p[j].value = h){ 52837da2899SCharles.Forsyth j++; 52937da2899SCharles.Forsyth if (j+3>=len p){ 53037da2899SCharles.Forsyth newp:=array[len p*2] of line; 53137da2899SCharles.Forsyth newp[0:]=p[0:]; 53237da2899SCharles.Forsyth p=array[len p*2] of line; 53337da2899SCharles.Forsyth p=newp; 53437da2899SCharles.Forsyth newp=nil; 53537da2899SCharles.Forsyth } 53637da2899SCharles.Forsyth } 53737da2899SCharles.Forsyth ilen[i]=j; 53837da2899SCharles.Forsyth file[i] = p; 53937da2899SCharles.Forsyth input[i] = bp; 54037da2899SCharles.Forsyth if (i == 0) { 54137da2899SCharles.Forsyth file1 = arg; 54237da2899SCharles.Forsyth firstchange = 0; 54337da2899SCharles.Forsyth } 54437da2899SCharles.Forsyth else 54537da2899SCharles.Forsyth file2 = arg; 54637da2899SCharles.Forsyth return (bp, REG); 54737da2899SCharles.Forsyth} 54837da2899SCharles.Forsyth 54937da2899SCharles.Forsythsquishspace(buf : string) : string 55037da2899SCharles.Forsyth{ 55137da2899SCharles.Forsyth q:=0; 55237da2899SCharles.Forsyth p:=0; 55337da2899SCharles.Forsyth for (space := 0; q<len buf; q++) { 55437da2899SCharles.Forsyth if (buf[q]==' ' || buf[q]=='\t') { 55537da2899SCharles.Forsyth space++; 55637da2899SCharles.Forsyth continue; 55737da2899SCharles.Forsyth } 55837da2899SCharles.Forsyth if (space && bflag == 1) { 55937da2899SCharles.Forsyth buf[p] = ' '; 56037da2899SCharles.Forsyth p++; 56137da2899SCharles.Forsyth space = 0; 56237da2899SCharles.Forsyth } 56337da2899SCharles.Forsyth buf[p]=buf[q]; 56437da2899SCharles.Forsyth p++; 56537da2899SCharles.Forsyth } 56637da2899SCharles.Forsyth buf=buf[0:p]; 56737da2899SCharles.Forsyth return buf; 56837da2899SCharles.Forsyth} 56937da2899SCharles.Forsyth 57037da2899SCharles.Forsyth 57137da2899SCharles.Forsyth# need to fix up for unexpected EOF's 57237da2899SCharles.Forsyth 57337da2899SCharles.Forsythftell(b: ref Iobuf): int 57437da2899SCharles.Forsyth{ 57537da2899SCharles.Forsyth return int b.offset(); 57637da2899SCharles.Forsyth} 57737da2899SCharles.Forsyth 57837da2899SCharles.Forsythcheck(bf, bt : ref Iobuf) 57937da2899SCharles.Forsyth{ 58037da2899SCharles.Forsyth fbuf, tbuf : string; 58137da2899SCharles.Forsyth f:=1; 58237da2899SCharles.Forsyth t:=1; 58337da2899SCharles.Forsyth ixold[0] = ixnew[0] = 0; 58437da2899SCharles.Forsyth for (; f < ilen[0]; f++) { 58537da2899SCharles.Forsyth fbuf = bf.gets('\n'); 58637da2899SCharles.Forsyth if (fbuf!=nil) 58737da2899SCharles.Forsyth fbuf=fbuf[0:len fbuf -1]; 58837da2899SCharles.Forsyth ixold[f] = ftell(bf); 58937da2899SCharles.Forsyth if (J[f] == 0) 59037da2899SCharles.Forsyth continue; 59137da2899SCharles.Forsyth tbuflen: int; 59237da2899SCharles.Forsyth do { 59337da2899SCharles.Forsyth tbuf = bt.gets('\n'); 59437da2899SCharles.Forsyth if (tbuf!=nil) 59537da2899SCharles.Forsyth tbuf=tbuf[0:len tbuf -1]; 59637da2899SCharles.Forsyth tbuflen = len array of byte tbuf; 59737da2899SCharles.Forsyth ixnew[t] = ftell(bt); 59837da2899SCharles.Forsyth } while (t++ < J[f]); 59937da2899SCharles.Forsyth if (bflag) { 60037da2899SCharles.Forsyth fbuf = squishspace(fbuf); 60137da2899SCharles.Forsyth tbuf = squishspace(tbuf); 60237da2899SCharles.Forsyth } 60337da2899SCharles.Forsyth if (len fbuf != len tbuf || fbuf!=tbuf) 60437da2899SCharles.Forsyth J[f] = 0; 60537da2899SCharles.Forsyth } 60637da2899SCharles.Forsyth while (t < ilen[1]) { 60737da2899SCharles.Forsyth tbuf = bt.gets('\n'); 60837da2899SCharles.Forsyth if (tbuf!=nil) 60937da2899SCharles.Forsyth tbuf=tbuf[0:len tbuf -1]; 61037da2899SCharles.Forsyth ixnew[t] = ftell(bt); 61137da2899SCharles.Forsyth t++; 61237da2899SCharles.Forsyth } 61337da2899SCharles.Forsyth} 61437da2899SCharles.Forsyth 61537da2899SCharles.Forsythrange(a, b : int, separator : string) 61637da2899SCharles.Forsyth{ 61737da2899SCharles.Forsyth if (a>b) 61837da2899SCharles.Forsyth out.puts(sys->sprint("%d", b)); 61937da2899SCharles.Forsyth else 62037da2899SCharles.Forsyth out.puts(sys->sprint("%d", a)); 62137da2899SCharles.Forsyth if (a < b) 62237da2899SCharles.Forsyth out.puts(sys->sprint("%s%d", separator, b)); 62337da2899SCharles.Forsyth} 62437da2899SCharles.Forsyth 62537da2899SCharles.Forsythfetch(f : array of int, a,b : int , bp : ref Iobuf, s : string) 62637da2899SCharles.Forsyth{ 62737da2899SCharles.Forsyth buf : string; 62837da2899SCharles.Forsyth bp.seek(big f[a-1], 0); 62937da2899SCharles.Forsyth while (a++ <= b) { 63037da2899SCharles.Forsyth buf=bp.gets('\n'); 63137da2899SCharles.Forsyth out.puts(s); 63237da2899SCharles.Forsyth out.puts(buf); 63337da2899SCharles.Forsyth } 63437da2899SCharles.Forsyth} 63537da2899SCharles.Forsyth 63637da2899SCharles.Forsythchange(a, b, c, d : int) 63737da2899SCharles.Forsyth{ 63837da2899SCharles.Forsyth if (a > b && c > d) 63937da2899SCharles.Forsyth return; 64037da2899SCharles.Forsyth anychange = 1; 64137da2899SCharles.Forsyth if (mflag && firstchange == 0) { 64237da2899SCharles.Forsyth out.puts(sys->sprint( "diff %s %s\n", file1, file2)); 64337da2899SCharles.Forsyth firstchange = 1; 64437da2899SCharles.Forsyth } 64537da2899SCharles.Forsyth if (mode != 'f') { 64637da2899SCharles.Forsyth range(a, b, ","); 64737da2899SCharles.Forsyth if (a>b) 64837da2899SCharles.Forsyth out.putc('a'); 64937da2899SCharles.Forsyth else if (c>d) 65037da2899SCharles.Forsyth out.putc('d'); 65137da2899SCharles.Forsyth else 65237da2899SCharles.Forsyth out.putc('c'); 65337da2899SCharles.Forsyth if (mode != 'e') 65437da2899SCharles.Forsyth range(c, d, ","); 65537da2899SCharles.Forsyth } 65637da2899SCharles.Forsyth else { 65737da2899SCharles.Forsyth if (a>b) 65837da2899SCharles.Forsyth out.putc('a'); 65937da2899SCharles.Forsyth else if (c>d) 66037da2899SCharles.Forsyth out.putc('d'); 66137da2899SCharles.Forsyth else 66237da2899SCharles.Forsyth out.putc('c'); 66337da2899SCharles.Forsyth range(a, b, " "); 66437da2899SCharles.Forsyth } 66537da2899SCharles.Forsyth out.putc('\n'); 66637da2899SCharles.Forsyth if (mode == 0) { 66737da2899SCharles.Forsyth fetch(ixold, a, b, input[0], "< "); 66837da2899SCharles.Forsyth if (a <= b && c <= d) 66937da2899SCharles.Forsyth out.puts("---\n"); 67037da2899SCharles.Forsyth } 67137da2899SCharles.Forsyth if (mode==0) 67237da2899SCharles.Forsyth fetch(ixnew, c, d, input[1], "> "); 67337da2899SCharles.Forsyth else 67437da2899SCharles.Forsyth fetch(ixnew, c, d, input[1], ""); 67537da2899SCharles.Forsyth 67637da2899SCharles.Forsyth if (mode != 0 && c <= d) 67737da2899SCharles.Forsyth out.puts(".\n"); 67837da2899SCharles.Forsyth} 67937da2899SCharles.Forsyth 68037da2899SCharles.Forsyth 68137da2899SCharles.Forsyth######################### diffdir starts here ...... 68237da2899SCharles.Forsyth 68337da2899SCharles.Forsythscandir(name : string) : array of string 68437da2899SCharles.Forsyth{ 68537da2899SCharles.Forsyth (db,nitems):= readdir->init(name,Readdir->NAME); 68637da2899SCharles.Forsyth cp := array[nitems] of string; 68737da2899SCharles.Forsyth for(i:=0;i<nitems;i++) 68837da2899SCharles.Forsyth cp[i]=db[i].name; 68937da2899SCharles.Forsyth return cp; 69037da2899SCharles.Forsyth} 69137da2899SCharles.Forsyth 69237da2899SCharles.Forsyth 69337da2899SCharles.Forsythdiffdir(f, t : string, level : int) 69437da2899SCharles.Forsyth{ 69537da2899SCharles.Forsyth df, dt : array of string; 69637da2899SCharles.Forsyth fb, tb : string; 69737da2899SCharles.Forsyth i:=0; 69837da2899SCharles.Forsyth j:=0; 69937da2899SCharles.Forsyth df = scandir(f); 70037da2899SCharles.Forsyth dt = scandir(t); 70137da2899SCharles.Forsyth while ((i<len df) || (j<len dt)) { 70237da2899SCharles.Forsyth if ((j==len dt) || (i<len df && df[i] < dt[j])) { 70337da2899SCharles.Forsyth if (mode == 0) 70437da2899SCharles.Forsyth out.puts(sys->sprint("Only in %s: %s\n", f, df[i])); 70537da2899SCharles.Forsyth i++; 70637da2899SCharles.Forsyth continue; 70737da2899SCharles.Forsyth } 70837da2899SCharles.Forsyth if ((i==len df) || (j<len dt && df[i] > dt[j])) { 70937da2899SCharles.Forsyth if (mode == 0) 71037da2899SCharles.Forsyth out.puts(sys->sprint("Only in %s: %s\n", t, dt[j])); 71137da2899SCharles.Forsyth j++; 71237da2899SCharles.Forsyth continue; 71337da2899SCharles.Forsyth } 71437da2899SCharles.Forsyth fb=sys->sprint("%s/%s", f, df[i]); 71537da2899SCharles.Forsyth tb=sys->sprint("%s/%s", t, dt[j]); 71637da2899SCharles.Forsyth diff(fb, tb, level+1); 71737da2899SCharles.Forsyth i++; j++; 71837da2899SCharles.Forsyth } 71937da2899SCharles.Forsyth} 72037da2899SCharles.Forsyth 72137da2899SCharles.Forsythcmp(b0, b1: ref Iobuf): int 72237da2899SCharles.Forsyth{ 72337da2899SCharles.Forsyth b0.seek(big 0, Sys->SEEKSTART); 72437da2899SCharles.Forsyth b1.seek(big 0, Sys->SEEKSTART); 72537da2899SCharles.Forsyth buf0 := array[1024] of byte; 72637da2899SCharles.Forsyth buf1 := array[1024] of byte; 72737da2899SCharles.Forsyth for (;;) { 72837da2899SCharles.Forsyth n0 := b0.read(buf0, len buf0); 72937da2899SCharles.Forsyth n1 := b1.read(buf1, len buf1); 73037da2899SCharles.Forsyth 73137da2899SCharles.Forsyth if (n0 != n1) 73237da2899SCharles.Forsyth return 1; 73337da2899SCharles.Forsyth 73437da2899SCharles.Forsyth if (n0 == 0) 73537da2899SCharles.Forsyth return 0; 73637da2899SCharles.Forsyth 73737da2899SCharles.Forsyth for (i := 0; i < n0; i++) 73837da2899SCharles.Forsyth if (buf0[i] != buf1[i]) 73937da2899SCharles.Forsyth return 1; 74037da2899SCharles.Forsyth } 74137da2899SCharles.Forsyth} 74237da2899SCharles.Forsyth 74337da2899SCharles.Forsyth################## main from here..... 74437da2899SCharles.Forsyth 74537da2899SCharles.ForsythREGULAR_FILE(s : Sys->Dir) : int 74637da2899SCharles.Forsyth{ 74737da2899SCharles.Forsyth # both pipes and networks contain non-zero-length files 74837da2899SCharles.Forsyth # which are not seekable. 74937da2899SCharles.Forsyth return (s.qid.qtype&Sys->QTDIR) == 0 && 75037da2899SCharles.Forsyth s.dtype != '|' && 75137da2899SCharles.Forsyth s.dtype != 'I'; 75237da2899SCharles.Forsyth# && s.length > 0; device files have zero length. 75337da2899SCharles.Forsyth} 75437da2899SCharles.Forsyth 75537da2899SCharles.Forsythrmtmpfiles() 75637da2899SCharles.Forsyth{ 75737da2899SCharles.Forsyth while (whichtmp > 0) { 75837da2899SCharles.Forsyth whichtmp--; 75937da2899SCharles.Forsyth sys->remove(tmpname[whichtmp]); 76037da2899SCharles.Forsyth } 76137da2899SCharles.Forsyth} 76237da2899SCharles.Forsyth 76337da2899SCharles.Forsythmktmpfile(inputf : ref Sys->FD) : (string, Sys->Dir) 76437da2899SCharles.Forsyth{ 76537da2899SCharles.Forsyth i, j : int; 76637da2899SCharles.Forsyth sb : Sys->Dir; 76737da2899SCharles.Forsyth p : string; 76837da2899SCharles.Forsyth buf := array[8192] of byte; 76937da2899SCharles.Forsyth 77037da2899SCharles.Forsyth p = tmpname[whichtmp++]; 77137da2899SCharles.Forsyth fd := sys->create(p, Sys->OWRITE, 8r600); 77237da2899SCharles.Forsyth if (fd == nil) { 77337da2899SCharles.Forsyth error(sys->sprint("cannot create %s: %r", p)); 77437da2899SCharles.Forsyth return (nil, sb); 77537da2899SCharles.Forsyth } 77637da2899SCharles.Forsyth while ((i = sys->read(inputf, buf, len buf)) > 0) { 77737da2899SCharles.Forsyth if ((i = sys->write(fd, buf, i)) < 0) 77837da2899SCharles.Forsyth break; 77937da2899SCharles.Forsyth } 78037da2899SCharles.Forsyth (j,sb)=sys->fstat(fd); 78137da2899SCharles.Forsyth if (i < 0 || j < 0) { 78237da2899SCharles.Forsyth error(sys->sprint("cannot read/write %s: %r", p)); 78337da2899SCharles.Forsyth return (nil, sb); 78437da2899SCharles.Forsyth } 78537da2899SCharles.Forsyth return (p, sb); 78637da2899SCharles.Forsyth} 78737da2899SCharles.Forsyth 78837da2899SCharles.Forsyth 78937da2899SCharles.Forsythstatfile(file : string) : (string,Sys->Dir) 79037da2899SCharles.Forsyth{ 79137da2899SCharles.Forsyth (ret,sb):=sys->stat(file); 79237da2899SCharles.Forsyth if (ret==-1) { 793*ca1042d3SCharles.Forsyth if (file != "-" || sys->fstat(sys->fildes(0)).t0 == -1){ 79437da2899SCharles.Forsyth error(sys->sprint("cannot stat %s: %r", file)); 79537da2899SCharles.Forsyth return (nil,sb); 79637da2899SCharles.Forsyth } 79737da2899SCharles.Forsyth (file, sb) = mktmpfile(sys->fildes(0)); 79837da2899SCharles.Forsyth } 79937da2899SCharles.Forsyth else if (!REGULAR_FILE(sb) && !(sb.qid.qtype&Sys->QTDIR)) { 80037da2899SCharles.Forsyth if ((i := sys->open(file, Sys->OREAD)) == nil) { 80137da2899SCharles.Forsyth error(sys->sprint("cannot open %s: %r", file)); 80237da2899SCharles.Forsyth return (nil, sb); 80337da2899SCharles.Forsyth } 80437da2899SCharles.Forsyth (file, sb) = mktmpfile(i); 80537da2899SCharles.Forsyth } 80637da2899SCharles.Forsyth return (file,sb); 80737da2899SCharles.Forsyth} 80837da2899SCharles.Forsyth 80937da2899SCharles.Forsythdiff(f, t : string, level : int) 81037da2899SCharles.Forsyth{ 81137da2899SCharles.Forsyth fp,tp,p,rest,fb,tb : string; 81237da2899SCharles.Forsyth fsb, tsb : Sys->Dir; 81337da2899SCharles.Forsyth (fp,fsb) = statfile(f); 81437da2899SCharles.Forsyth if (fp == nil) 81537da2899SCharles.Forsyth return; 81637da2899SCharles.Forsyth (tp,tsb) = statfile(t); 81737da2899SCharles.Forsyth if (tp == nil) 81837da2899SCharles.Forsyth return; 81937da2899SCharles.Forsyth if ((fsb.qid.qtype&Sys->QTDIR) && (tsb.qid.qtype&Sys->QTDIR)) { 82037da2899SCharles.Forsyth if (rflag || level == 0) 82137da2899SCharles.Forsyth diffdir(fp, tp, level); 82237da2899SCharles.Forsyth else 82337da2899SCharles.Forsyth out.puts(sys->sprint("Common subdirectories: %s and %s\n", fp, tp)); 82437da2899SCharles.Forsyth } 82537da2899SCharles.Forsyth else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb)){ 82637da2899SCharles.Forsyth diffreg(fp, tp); 82737da2899SCharles.Forsyth } else { 82837da2899SCharles.Forsyth if (!(fsb.qid.qtype&Sys->QTDIR)) { 82937da2899SCharles.Forsyth (p,rest)=str->splitr(f,"/"); 83037da2899SCharles.Forsyth if (rest!=nil) 83137da2899SCharles.Forsyth p = rest; 83237da2899SCharles.Forsyth tb=sys->sprint("%s/%s", tp, p); 83337da2899SCharles.Forsyth diffreg(fp, tb); 83437da2899SCharles.Forsyth } 83537da2899SCharles.Forsyth else { 83637da2899SCharles.Forsyth (p,rest)=str->splitr(t,"/"); 83737da2899SCharles.Forsyth if (rest!=nil) 83837da2899SCharles.Forsyth p = rest; 83937da2899SCharles.Forsyth fb=sys->sprint("%s/%s", fp, p); 84037da2899SCharles.Forsyth diffreg(fb, tp); 84137da2899SCharles.Forsyth } 84237da2899SCharles.Forsyth } 84337da2899SCharles.Forsyth} 84437da2899SCharles.Forsyth 84537da2899SCharles.Forsythfatal(s: string) 84637da2899SCharles.Forsyth{ 84737da2899SCharles.Forsyth sys->fprint(stderr, "diff: %s\n", s); 84837da2899SCharles.Forsyth raise "fail:error"; 84937da2899SCharles.Forsyth} 85037da2899SCharles.Forsyth 85137da2899SCharles.Forsytherror(s: string) 85237da2899SCharles.Forsyth{ 85337da2899SCharles.Forsyth sys->fprint(stderr, "diff: %s\n", s); 85437da2899SCharles.Forsyth} 855