diff3.c

来自「unix v7是最后一个广泛发布的研究型UNIX版本」· C语言 代码 · 共 422 行

C
422
字号
#include <stdio.h>#/* diff3 - 3-way differential file comparison*//* diff3 [-e] d13 d23 f1 f2 f3  * * d13 = diff report on f1 vs f3 * d23 = diff report on f2 vs f3 * f1, f2, f3 the 3 files*/struct  range {int from,to; };	/* from is first in range of changed lines	 * to is last+1	 * from=to=line after point of insertion	* for added lines	*/struct diff {struct range old, new;};#define NC 200/* de is used to gather editing scripts, * that are later spewed out in reverse order. * its first element must be all zero * the "new" component of de contains line positions * or byte positions depending on when you look(!?)*/struct diff d13[NC];struct diff d23[NC];struct diff de[NC];char line[256];FILE *fp[3];int linct[3] = {0,0,0};/*	the number of the last-read line in each file *	is kept in cline[0-2]*/int cline[3];/*	the latest known correspondence between line *	numbers of the 3 files is stored in last[1-3]*/int last[4];int eflag;int debug  = 0;main(argc,argv)char **argv;{	register i,m,n;	if(*argv[1]=='-') {		switch(argv[1][1]) {		default:			eflag = 3;			break;		case '3':			eflag = 2;			break;		case 'x':			eflag = 1;		}		argv++;		argc--;	}	if(argc<6) {		fprintf(stderr,"diff3: arg count\n");		exit(1);	}	m = readin(argv[1],d13);	n = readin(argv[2],d23);	for(i=0;i<=2;i++)		if((fp[i] = fopen(argv[i+3],"r")) == NULL) {			printf("diff3: can't open %s\n",argv[i+3]);			exit(1);		}	merge(m,n);}/*pick up the line numbers of allcahnges from * one change file * (this puts the numbers in a vector, which is not * strictly necessary, since the vector is processed * in one sequential pass. The vector could be optimized * out of existence)*/readin(name,dd)char *name;struct diff *dd;{	register i;	int a,b,c,d;	char kind;	char *p;	fp[0] = fopen(name,"r");	for(i=0;getchange(fp[0]);i++) {		if(i>=NC) {			fprintf(stderr,"diff3: too many changes\n");			exit(0);		}		p = line;		a = b = number(&p);		if(*p==',') {			p++;			b = number(&p);		}		kind = *p++;		c = d = number(&p);		if(*p==',') {			p++;			d = number(&p);		}		if(kind=='a')			a++;		if(kind=='d')			c++;		b++;		d++;		dd[i].old.from = a;		dd[i].old.to = b;		dd[i].new.from = c;		dd[i].new.to = d;	}	dd[i].old.from = dd[i-1].old.to;	dd[i].new.from = dd[i-1].new.to;	fclose(fp[0]);	return(i);}number(lc)char **lc;{	register nn;	nn = 0;	while(digit(**lc))		nn = nn*10 + *(*lc)++ - '0';	return(nn);}digit(c){	return(c>='0'&&c<='9');}getchange(b)FILE *b;{	while(getline(b))		if(digit(line[0]))			return(1);	return(0);}getline(b)FILE *b;{	register i, c;	for(i=0;i<sizeof(line)-1;i++) {		c = getc(b);		if(c==EOF)			break;		line[i] = c;		if(c=='\n') {			line[++i] = 0;			return(i);		}	}	return(0);}merge(m1,m2){	register struct diff *d1, *d2, *d3;	int dup;	int j;	int t1,t2;	d1 = d13;	d2 = d23;	j = 0;	for(;(t1 = d1<d13+m1) | (t2 = d2<d23+m2);) {		if(debug) {			printf("%d,%d=%d,%d %d,%d=%d,%d\n",			d1->old.from,d1->old.to,			d1->new.from,d1->new.to,			d2->old.from,d2->old.to,			d2->new.from,d2->new.to);		}/*			first file is different from others*/		if(!t2||t1&&d1->new.to < d2->new.from) {/*			stuff peculiar to 1st file */			if(eflag==0) {				separate("1");				change(1,&d1->old,0);				keep(2,&d1->old,&d1->new);				change(3,&d1->new,0);			}			d1++;			continue;		}/*			second file is different from others*/		if(!t1||t2&&d2->new.to < d1->new.from) {			if(eflag==0) {				separate("2");				keep(1,&d2->old,&d2->new);				change(2,&d2->old,0);				change(3,&d2->new,0);			}			d2++;			continue;		}/*			merge overlapping changes in first file *			this happens after extension see below*/		if(d1+1<d13+m1 &&		   d1->new.to>=d1[1].new.from) {			d1[1].old.from = d1->old.from;			d1[1].new.from = d1->new.from;			d1++;			continue;		}/*			merge overlapping changes in second*/		if(d2+1<d23+m2 &&		   d2->new.to>=d2[1].new.from) {			d2[1].old.from = d2->old.from;			d2[1].new.from = d2->new.from;			d2++;			continue;		}/*			stuff peculiar to third file or different in all*/		if(d1->new.from==d2->new.from&&		   d1->new.to==d2->new.to) {			dup = duplicate(&d1->old,&d2->old);/*				dup=0 means all files differ *				dup =1 meands files 1&2 identical*/			if(eflag==0) {				separate(dup?"3":"");				change(1,&d1->old,dup);				change(2,&d2->old,0);				d3 = d1->old.to>d1->old.from?d1:d2;				change(3,&d3->new,0);			} else				j = edit(d1,dup,j);			d1++;			d2++;			continue;		}/*			overlapping changes from file1 & 2 *			extend changes appropriately to *			make them coincide*/		 if(d1->new.from<d2->new.from) {			d2->old.from -= d2->new.from-d1->new.from;			d2->new.from = d1->new.from;		}		else if(d2->new.from<d1->new.from) {			d1->old.from -= d1->new.from-d2->new.from;			d1->new.from = d2->new.from;		}		if(d1->new.to >d2->new.to) {			d2->old.to += d1->new.to - d2->new.to;			d2->new.to = d1->new.to;		}		else if(d2->new.to >d1->new.to) {			d1->old.to += d2->new.to - d1->new.to;			d1->new.to = d2->new.to;		}	}	if(eflag)		edscript(j);}separate(s)char *s;{	printf("====%s\n",s);}/*	the range of ines rold.from thru rold.to in file i *	is to be changed. it is to be printed only if *	it does not duplicate something to be printed later*/change(i,rold,dup)struct range *rold;{	printf("%d:",i);	last[i] = rold->to;	prange(rold);	if(dup)		return;	if(debug)		return;	i--;	skip(i,rold->from,(char *)0);	skip(i,rold->to,"  ");}/*	print the range of line numbers, rold.from  thru rold.to *	as n1,n2 or n1*/prange(rold)struct range *rold;{	if(rold->to<=rold->from)		printf("%da\n",rold->from-1);	else {		printf("%d",rold->from);		if(rold->to > rold->from+1)			printf(",%d",rold->to-1);		printf("c\n");	}}/*	no difference was reported by diff between file 1(or 2) *	and file 3, and an artificial dummy difference (trange) *	must be ginned up to correspond to the change reported *	in the other file*/keep(i,rold,rnew)struct range *rold, *rnew;{	register delta;	struct range trange;	delta = last[3] - last[i];	trange.from = rnew->from - delta;	trange.to = rnew->to - delta;	change(i,&trange,1);}/*	skip to just befor line number from in file i *	if "pr" is nonzero, print all skipped stuff * w	with string pr as a prefix*/skip(i,from,pr)char *pr;{	register j,n;	for(n=0;cline[i]<from-1;n+=j) {		if((j=getline(fp[i]))==0)			trouble();		if(pr)			printf("%s%s",pr,line);		cline[i]++;	}	return(n);}/*	return 1 or 0 according as the old range *	(in file 1) contains exactly the same data *	as the new range (in file 2)*/duplicate(r1,r2)struct range *r1, *r2;{	register c,d;	register nchar;	int nline;	if(r1->to-r1->from != r2->to-r2->from)		return(0);	skip(0,r1->from,(char *)0);	skip(1,r2->from,(char *)0);	nchar = 0;	for(nline=0;nline<r1->to-r1->from;nline++) {		do {			c = getc(fp[0]);			d = getc(fp[1]);			if(c== -1||d== -1)				trouble();			nchar++;			if(c!=d) {				repos(nchar);				return;			}		} while(c!= '\n');	}	repos(nchar);	return(1);}repos(nchar){	register i;	for(i=0;i<2;i++) 		fseek(fp[i], (long)-nchar, 1);}trouble(){	fprintf(stderr,"diff3: logic error\n");	abort();}/*	collect an editing script for later regurgitation*/edit(diff,dup,j)struct diff *diff;{	if(((dup+1)&eflag)==0)		return(j);	j++;	de[j].old.from = diff->old.from;	de[j].old.to = diff->old.to;	de[j].new.from = de[j-1].new.to	    +skip(2,diff->new.from,(char *)0);	de[j].new.to = de[j].new.from	    +skip(2,diff->new.to,(char *)0);	return(j);}/*		regurgitate */edscript(n){	register j,k;	char block[512];	for(n=n;n>0;n--) {		prange(&de[n].old);		fseek(fp[2], (long)de[n].new.from, 0);		for(k=de[n].new.to-de[n].new.from;k>0;k-= j) {			j = k>512?512:k;			if(fread(block,1,j,fp[2])!=j)				trouble();			fwrite(block, 1, j, stdout);		}		printf(".\n");	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?