contextual diff on Bell systems

sources at genrad.UUCP sources at genrad.UUCP
Thu Jan 24 06:43:03 AEST 1985


This is a program for all those poor slobs that have to deal with UNIX systems
that don't have a -c option on their diff.  This program eliminates the last
excuse for bug fixes to be in standard diff format (especially since "patch"
works so much more reliably on diffc format).

Send bug reports to:  John Nelson  (decvax!genrad!john).

------------------- cut here -------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
echo 'x - diffc.1'
sed 's/^X//' <<'//go.sysin dd *' >diffc.1
X.TH DIFFC l  "22 January 1985"
X.UC 4
X.SH NAME
diffc \- context diff for systems whose diff has no \-c option
X.SH SYNOPSIS
X.B diff
[
X.B \-options
] [
X.B \-r
] [
\fB\-c#
] file1 file2
X.SH DESCRIPTION
X.I Diffc
is a front end for
X.IR diff (1)
which outputs contextual diff format like Berkeley system's "diff -c".
X.I Diffc
will actually run
X.I diff
as a subprocess, and will merge the "standard" diff format with lines from
both files.
As far as I can tell, the output is exactly the same as that of a diff with
the -c option.
X.PP
The -c# option allows the amount of context to be specified.
The default is 3 lines above and below the change.
I find that -c1 works well for updates intended for use with patch(1).
Any other options specified on the command line are passed along to
X.IR diff .
Note that most options to
X.I diff
should NOT be specified when using 
X.IR diffc ,
but the capability is there, nevertheless.
X.PP
The output format begins with identification of the files involved and
their creation dates and then each change is separated
by a line with a dozen *'s.
The lines removed from
X.I file1
are marked with `\(mi'; those added to
X.I file2
are marked `+'.  Lines which are changed from one
file to the other are marked in both files with `!'.
X.PP
No claim is made that the algoritm used is either fast or bulletproof.
It was only intended for standard text files with lines shorter than
BUFSIZ.
XFseek is used extensively to move around in the files, precluding the
use of standard input as one of the files to be diff'ed.
X.SH "SEE ALSO"
cmp(1), diff(1), comm(1), patch(1)
X.SH DIAGNOSTICS
Exit status is nonzero to indicate problems.
X.SH BUGS
This program is a hack, and should really be incorporated as part of "diff"
by Bell.
X.SH AUTHOR
John P. Nelson
//go.sysin dd *
echo 'x - diffc.c'
sed 's/^X//' <<'//go.sysin dd *' >diffc.c
X/* diffc.c - provide diff -c output on non-berkeley systems
**
** cc -o diffc diffc.c
**
**  or for V7 type systems
**
** cc -o diffc -DV7 diffc.c
*/

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>

#ifdef V7
#define strchr index
#include <string.h>		/* BEZERKELY 4.2 is strings.h */
#else
#include <string.h>
#endif

#define WIDTH 3
#define SEPERATE "***************"
#define max(_a,_b) (((_a)>(_b))?(_a):(_b))

XFILE *diff, *fd1, *fd2;
int line1 = 1, line2 = 1;
long off1, off2;
char buffer[BUFSIZ];
int width = WIDTH;

char *ctime();
XFILE *popen();

main(argc, argv)
int argc;
char **argv;
    {
    int i;
    struct stat statbuf;

    strcpy(buffer, "diff");
    /* skip over minus args - they must be for diff */
    for (i = 1; i < argc; ++i)
	{
	if (argv[i][0] != '-')
	    break;
	else if (!strncmp(argv[i], "-c", 2))
	    {
	    width = atoi(argv[i]+2);
	    if (width < 1 || width > 20)
		width = WIDTH;
	    }
	else
	    {
	    strcat(buffer, " ");
	    strcat(buffer, argv[i]);
	    }
	}
    if (argc - i != 2)
	{
	fprintf(stderr, "Usage: %s [-minusargs] file1 file2\n", argv[0]);
	exit(1);
	}
    strcat(buffer, " ");
    strcat(buffer, argv[i]);
    strcat(buffer, " ");
    strcat(buffer, argv[i+1]);

    fd1 = fopen(argv[i], "r");
    fd2 = fopen(argv[i+1], "r");

    if (!fd1 || !fd2)
	{
	fprintf(stderr, "%s: File not accessible\n", argv[0]);
	exit(1);
	}

    if ((diff = popen(buffer, "r")) == NULL)
	{
	fprintf(stderr, "%s: Cant find diff\n", argv[0]);
	exit(1);
	}

    stat(argv[i], &statbuf);
    printf("*** %s\t%s", argv[i], ctime(&(statbuf.st_mtime)));
    stat(argv[i+1], &statbuf);
    printf("--- %s\t%s", argv[i+1], ctime(&(statbuf.st_mtime)));

    dodiffs();
    }

dodiffs()
    {
    char line[BUFSIZ];
    char type, disp;
    int from1, to1, from2, to2;
    int dfrom1, dto1, dfrom2, dto2;
    int i;
    int skip;

    while (fgets(line, sizeof(line), diff))
	{
	parse(line, &from1, &from2, &to1, &to2, &type);

	dfrom1 = max(from1 - width, 1);
	dfrom2 = max(from2 - width, 1);

	line1 = toline(fd1, line1, dfrom1);
	line2 = toline(fd2, line2, dfrom2);

	off1 = ftell(fd1);
	off2 = ftell(fd2);

	dto1 = checkline(fd1, line1, to1 + width);
	dto2 = checkline(fd2, line2, to2 + width);

	/* checkline moved the position, so seek back to last point */
	fseek(fd1, off1, 0);
	fseek(fd2, off2, 0);

	printf("*** %d,%d\n", dfrom1, dto1);
	for (i = dfrom1; i <= dto1; ++i)
	    {
	    if (!fgets(buffer, sizeof(buffer), fd1))
		break;
	    disp = ' ';
	    if (i >= from1 && i <= to1)
		disp = (type == 'c') ? '!': '-';
	    printf("%c %s", disp, buffer);
	    }
	printf("\n--- %d,%d -----\n", dfrom2, dto2);
	for (i = dfrom2; i <= dto2; ++i)
	    {
	    if (!fgets(buffer, sizeof(buffer), fd2))
		break;
	    disp = ' ';
	    if (i >= from2 && i <= to2)
		disp = (type == 'c') ? '!': '+';
	    printf("%c %s", disp, buffer);
	    }

	/* seek back because next diff may overlap */
	fseek(fd1, off1, 0);
	fseek(fd2, off2, 0);

	/* calculate the number of display lines generated by diff */
	skip = to1 - from1 + to2 - from2 + 2;
	if (type == 'c')
	    skip++;		/* add one for the seperator */
	toline(diff, 0, skip);
	}
    }

parse(line, from1, from2, to1, to2, type)
char *line, *type;
int *from1, *from2, *to1, *to2;
    {
    char *part2, *ptr;

    /* expect a line range type range */
    if(!isdigit(line[0]))
	{
	fprintf(stderr, "Unknown junk from diff: %s\n", line);
	exit(2);
	}
    if ((part2 = strchr(line, 'a')) || (part2 = strchr(line, 'c')) || (part2 = strchr(line, 'd')))
	{
	*type = *part2;
	*part2++ = '\0';
	printf("%s\n", SEPERATE);
	}
    else
	{
	fprintf(stderr, "Unknown junk from diff: %s\n", line);
	exit(2);
	}
X/* file 1 */
    *from1 = atoi(line);
    if (ptr = strchr(line, ','))
	*to1 = atoi(++ptr);
    else
	*to1 = *from1;
X/* file 2 */
    *from2 = atoi(part2);
    if (ptr = strchr(part2, ','))
	*to2 = atoi(++ptr);
    else
	*to2 = *from2;

    if (*type == 'a')
	++*from1;

    if (*type == 'd')
	++*from2;
    }


toline(fd, lineis, linenum)
XFILE *fd;
int lineis, linenum;
    {
    /* note: toline can seek to one more line than there actually is (EOF) */
    while (lineis < linenum)
	{
	if (fgets(buffer, sizeof(buffer), fd))
	    ++lineis;
	else
	    break;
	}
    return lineis;
    }

checkline(fd, lineis, linenum)
XFILE *fd;
int lineis, linenum;
    {
    lineis = toline(fd, lineis, linenum);
    if (!fgets(buffer, sizeof(buffer), fd))
	--lineis;
    return lineis;
    }
//go.sysin dd *



More information about the Mod.sources mailing list