Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!rutgers!seismo!ll-xn!cit-vax!oberon!sdcrdcf!lwall From: lwall@sdcrdcf.UUCP Newsgroups: comp.os.minix Subject: Making context diffs - cdiff Message-ID: <4663@sdcrdcf.UUCP> Date: Mon, 1-Jun-87 19:17:17 EDT Article-I.D.: sdcrdcf.4663 Posted: Mon Jun 1 19:17:17 1987 Date-Received: Thu, 4-Jun-87 01:20:19 EDT Reply-To: lwall@sdcrdcf.UUCP (Larry Wall) Distribution: world Organization: Unisys - System Development Group, Santa Monica Lines: 374 If you use the following program to produce your patches, people will be able to apply your patches using the patch program even if their line numbers don't match your line numbers. This program produces 4.3bsd-style context diffs, which are considerably more compact than old-style context diffs, yet are much less error-prone to apply than normal diffs, since patch has more information to decide if it is putting the patch in the right place. In the worst case (that is, an append), a normal diff applied by patch can insert lines in the wrong place in your program and never tell you about it because all it has to go on is the line number. Note that cdiff uses a normal diff as a back end, so you'll still need Erik Baalbergen's diff program that he just posted if you want to run this under MINIX. Don't be confused, however, between his patch program and mine. His will only apply normal diffs, and only if you haven't modified your file. By the way, this is an unobfuscated version of a program I entered in the Obfuscated C Code Contest. Exercise #1: How would you go about shrinking this to under 1K of source? It's currently over 5K. Enjoy. Larry Wall {allegra,burdvax,cbosgd,hplabs,ihnp4,sdcsvax}!sdcrdcf!lwall #! /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 $$) 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 87/06/01 16:05:57 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 87/06/01 16:05:57 lwall X * Initial revision X * X */ X X#include "patchlevel.h" X#include X#include X#include X#include 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 newbeg = newmin - context; X newend = newmax + context; X X if (preoldend < newbeg - 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 0 !STUFFY!FUNK! echo "" echo "End of kit 1 (of 1)" : Someone might mail this, so... exit