[comp.unix.xenix] Context diffs, HELP

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (07/26/88)

In article <150@ispi.UUCP> jbayer@ispi.UUCP writes:
> 	I have Larry Wall's patch program (it works great), and have a
> need to create some diffs for use with it.  I have looked in several
> different manuals and books, but cannot find out how to create the diffs
> with the file names included.  According to the patch documentation
> context diffs create a header which specify the file names.  However, the
> normal diff command doesn't do that.  Is there a PD diff which creates
> diffs in the format that patch likes best?  Thanks.

Here's a little thing I whipped together a while back to do just what you want.
It runs your normal diff for you and then turns that into a context diff.

I apologize for posting source to d newsgroups, but this thing's so piddly
small it isn't worth waiting the month for it to get through the moderated
group.

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

#! /bin/sh

# Make a new directory for the cdiff sources, cd to it, and run kits 1
# thru 1 through sh.  When all 1 kits have been run, read README.

echo "This is cdiff 1.1 kit 1 (of 1).  If kit 1 is complete, the line"
echo '"'"End of kit 1 (of 1)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir  2>/dev/null
echo Extracting README
sed >README <<'!STUFFY!FUNK!' -e 's/X//'
XThis program runs a normal diff as input to a pipe, and transforms that into
Xa 4.3bsd-style context diff.
X
XTo compile, just type "cc -o cdiff cdiff.c".  You might want to throw in
Xa -Dvoid=int if your C compiler doesn't grok the void type.
X
XTo run, just say "cdiff file1 file2".  Cdiff will run a "diff file1 file2"
Xfor you, and modify that output to make the context diff.  If you don't have
Xa normal diff program, there is a PD version available from Erik Baalbergen
Xat erikb@cs.vu.nl.
!STUFFY!FUNK!
echo Extracting cdiff.c
sed >cdiff.c <<'!STUFFY!FUNK!' -e 's/X//'
Xstatic char rcsid[] = "$Header: cdiff.c,v 1.1.1.2 87/06/04 11:21:43 lwall Exp $";
X
X/* cdiff - turns a regular diff into a new-style context diff
X *
X * Usage: cdiff file1 file2
X *
X * $Log:	cdiff.c,v $
X * Revision 1.1.1.2  87/06/04  11:21:43  lwall
X * Didn't do diffs with less than 3 lines of leading context.
X * 
X * Revision 1.1.1.1  87/06/03  11:52:25  lwall
X * Wasn't concatenating overlapping hunks right.
X * 
X * Revision 1.1  87/06/01  16:05:57  lwall
X * Initial revision
X * 
X */
X
X#include "patchlevel.h"
X#include <stdio.h>
X#include <sys/types.h>
X#include <stat.h>
X#include <ctype.h>
X
Xchar buf[512];
X
XFILE *inputfp, *oldfp, *newfp;
X
Xint oldmin, oldmax, newmin, newmax;
Xint oldbeg, oldend, newbeg, newend;
Xint preoldmax, prenewmax;
Xint preoldbeg, preoldend, prenewbeg, prenewend;
Xint oldwanted, newwanted;
X
Xchar *oldhunk, *newhunk;
Xunsigned oldsize, oldalloc, newsize, newalloc;
X
Xvoid dumphunk();
Xchar *getold();
Xchar *getnew();
Xchar *malloc();
Xchar *realloc();
Xchar *fgets();
XFILE *popen();
X
X#define Nullfp (FILE*)0
X#define Nullch (char*)0
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X    char *old, *new;
X    int context = 3;
X    struct stat statbuf;
X    register char *s;
X    char op;
X    char *newmark, *oldmark;
X    int len;
X    char *line;
X    int i;
X
X    oldalloc = 512;
X    oldhunk = malloc(oldalloc);
X    newalloc = 512;
X    newhunk = malloc(newalloc);
X
X    for (argc--,argv++; argc; argc--,argv++) {
X	if (argv[0][0] != '-')
X	    break;
X	if (argv[0][1] == 'v') {
X	    printf("%s\n	Patch level: %d\n",rcsid,PATCHLEVEL);
X	    exit(0);
X	}
X	if (argv[0][1] == 'c')
X	    context = atoi(argv[0]+2);
X    }
X
X    if (argc != 2) {
X	fprintf(stderr,"cdiff old new\n");
X	exit(1);
X    }
X
X    old = argv[0];
X    new = argv[1];
X
X    sprintf(buf,"diff %s %s", old, new);
X    inputfp = popen(buf, "r");
X    if (!inputfp) {
X	fprintf(stderr, "Can't execute diff %s %s\n", old, new);
X	exit(1);
X    }
X
X    oldfp = fopen(old,"r");
X    if (!oldfp) {
X	fprintf(stderr, "Can't open %s\n", old);
X	exit(1);
X    }
X    newfp = fopen(new,"r");
X    if (!newfp) {
X	fprintf(stderr, "Can't open %s\n", new);
X	exit(1);
X    }
X
X    fstat(fileno(oldfp),&statbuf);
X    printf("*** %s\t%s", old, ctime(&statbuf.st_mtime));
X    fstat(fileno(newfp),&statbuf);
X    printf("--- %s\t%s", new, ctime(&statbuf.st_mtime));
X
X    preoldend = -1000;
X
X    while (fgets(buf, sizeof buf, inputfp) != Nullch) {
X	if (isdigit(*buf)) {
X	    oldmin = atoi(buf);
X	    for (s = buf; isdigit(*s); s++) ;
X	    if (*s == ',') {
X		s++;
X		oldmax = atoi(s);
X		for ( ; isdigit(*s); s++) ;
X	    }
X	    else {
X		oldmax = oldmin;
X	    }
X	    if (*s != 'a' && *s != 'd' && *s != 'c') {
X		fprintf(stderr, "Unparseable input: %s", s);
X		exit(1);
X	    }
X	    op = *s;
X	    s++;
X	    newmin = atoi(s);
X	    for ( ; isdigit(*s); s++) ;
X	    if (*s == ',') {
X		s++;
X		newmax = atoi(s);
X		for ( ; isdigit(*s); s++) ;
X	    }
X	    else {
X		newmax = newmin;
X	    }
X	    if (*s != '\n' && *s != ' ') {
X		fprintf(stderr, "Unparseable input: %s", s);
X		exit(1);
X	    }
X
X	    newmark = oldmark = "! ";
X	    if (op == 'a') {
X		oldmin++;
X		newmark = "+ ";
X	    }
X	    if (op == 'd') {
X		newmin++;
X		oldmark = "- ";
X	    }
X
X	    oldbeg = oldmin - context;
X	    oldend = oldmax + context;
X	    if (oldbeg < 1)
X		oldbeg = 1;
X	    newbeg = newmin - context;
X	    newend = newmax + context;
X	    if (newbeg < 1)
X		newbeg = 1;
X
X	    if (preoldend < oldbeg - 1) {
X		if (preoldend >= 0) {
X		    dumphunk();
X		}
X		preoldbeg = oldbeg;
X		prenewbeg = newbeg;
X		oldwanted = newwanted = 0;
X		oldsize = newsize = 0;
X	    } else {	/* we want to append to previous hunk */
X		oldbeg = preoldmax + 1;
X		newbeg = prenewmax + 1;
X	    }
X
X	    for (i = oldbeg; i <= oldmax; i++) {
X		line = getold(i);
X		if (!*line) {
X		    oldend = oldmax = i - 1;
X		    break;
X		}
X		len = strlen(line) + 2;
X		if (oldsize + len + 1 >= oldalloc) {
X		    oldalloc *= 2;
X		    oldhunk = realloc(oldhunk, oldalloc);
X		}
X		if (i >= oldmin) {
X		    strcpy(oldhunk+oldsize, oldmark);
X		    oldwanted++;
X		}
X		else {
X		    strcpy(oldhunk+oldsize, "  ");
X		}
X		strcpy(oldhunk+oldsize+2,line);
X		oldsize += len;
X	    }
X	    preoldmax = oldmax;
X	    preoldend = oldend;
X
X	    for (i = newbeg; i <= newmax; i++) {
X		line = getnew(i);
X		if (!*line) {
X		    newend = newmax = i - 1;
X		    break;
X		}
X		len = strlen(line) + 2;
X		if (newsize + len + 1 >= newalloc) {
X		    newalloc *= 2;
X		    newhunk = realloc(newhunk, newalloc);
X		}
X		if (i >= newmin) {
X		    strcpy(newhunk+newsize, newmark);
X		    newwanted++;
X		}
X		else {
X		    strcpy(newhunk+newsize, "  ");
X		}
X		strcpy(newhunk+newsize+2,line);
X		newsize += len;
X	    }
X	    prenewmax = newmax;
X	    prenewend = newend;
X	}
X    }
X
X    if (preoldend >= 0) {
X	dumphunk();
X    }
X}
X
Xvoid
Xdumphunk()
X{
X    int i;
X    char *line;
X    int len;
X
X    for (i = preoldmax + 1; i <= preoldend; i++) {
X	line = getold(i);
X	if (!line) {
X	    preoldend = i - 1;
X	    break;
X	}
X	len = strlen(line) + 2;
X	if (oldsize + len + 1 >= oldalloc) {
X	    oldalloc *= 2;
X	    oldhunk = realloc(oldhunk, oldalloc);
X	}
X	strcpy(oldhunk+oldsize, "  ");
X	strcpy(oldhunk+oldsize+2, line);
X	oldsize += len;
X    }
X    for (i = prenewmax + 1; i <= prenewend; i++) {
X	line = getnew(i);
X	if (!line) {
X	    prenewend = i - 1;
X	    break;
X	}
X	len = strlen(line) + 2;
X	if (newsize + len + 1 >= newalloc) {
X	    newalloc *= 2;
X	    newhunk = realloc(newhunk, newalloc);
X	}
X	strcpy(newhunk+newsize, "  ");
X	strcpy(newhunk+newsize+2, line);
X	newsize += len;
X    }
X    fputs("***************\n",stdout);
X    if (preoldbeg >= preoldend) {
X	printf("*** %d ****\n", preoldend);
X    } else {
X	printf("*** %d,%d ****\n", preoldbeg, preoldend);
X    }
X    if (oldwanted) {
X	fputs(oldhunk,stdout);
X    }
X    oldsize = 0;
X    *oldhunk = '\0';
X    if (prenewbeg >= prenewend) {
X	printf("--- %d ----\n", prenewend);
X    } else {
X	printf("--- %d,%d ----\n", prenewbeg, prenewend);
X    }
X    if (newwanted) {
X	fputs(newhunk,stdout);
X    }
X    newsize = 0;
X    *newhunk = '\0';
X}
X
Xchar *
Xgetold(targ)
Xint targ;
X{
X    static int oldline = 0;
X
X    while (fgets(buf, sizeof buf, oldfp) != Nullch) {
X	oldline++;
X	if (oldline == targ)
X	    return buf;
X    }
X    return Nullch;
X}
X
Xchar *
Xgetnew(targ)
Xint targ;
X{
X    static int newline = 0;
X
X    while (fgets(buf, sizeof buf, newfp) != Nullch) {
X	newline++;
X	if (newline == targ)
X	    return buf;
X    }
X    return Nullch;
X}
!STUFFY!FUNK!
echo Extracting MANIFEST
sed >MANIFEST <<'!STUFFY!FUNK!' -e 's/X//'
XAfter all the cdiff kits are run you should have the following files:
X
XFilename		Kit Description
X--------		--- -----------
XMANIFEST                 1 This file.
XREADME                   1 Instructions.
Xcdiff.c                  1 The program.
Xpatchlevel.h             1 The patch level of cdiff.
!STUFFY!FUNK!
echo Extracting patchlevel.h
sed >patchlevel.h <<'!STUFFY!FUNK!' -e 's/X//'
X#define PATCHLEVEL 2
!STUFFY!FUNK!
echo ""
echo "End of kit 1 (of 1)"
cat /dev/null >kit1isdone
run=''
config=''
for iskit in 1; do
    if test -f kit${iskit}isdone; then
	run="$run $iskit"
    else
	todo="$todo $iskit"
    fi
done
case $todo in
    '')
	echo "You have run all your kits.  Please read README."
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit