366 lines
7.5 KiB
C
366 lines
7.5 KiB
C
|
/* cdiff - context diff Author: Larry Wall */
|
||
|
|
||
|
/* Cdiff - turns a regular diff into a new-style context diff
|
||
|
*
|
||
|
* Usage: cdiff file1 file2
|
||
|
*/
|
||
|
|
||
|
#define PATCHLEVEL 2
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <ctype.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
#include <unistd.h>
|
||
|
#include <limits.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
char buff[512];
|
||
|
|
||
|
FILE *inputfp, *oldfp, *newfp;
|
||
|
|
||
|
int oldmin, oldmax, newmin, newmax;
|
||
|
int oldbeg, oldend, newbeg, newend;
|
||
|
int preoldmax, prenewmax;
|
||
|
int preoldbeg, preoldend, prenewbeg, prenewend;
|
||
|
int oldwanted, newwanted;
|
||
|
|
||
|
char *oldhunk, *newhunk;
|
||
|
char *progname;
|
||
|
size_t oldsize, oldalloc, newsize, newalloc;
|
||
|
|
||
|
_PROTOTYPE(int main, (int argc, char **argv));
|
||
|
_PROTOTYPE(void dumphunk, (void));
|
||
|
_PROTOTYPE(char *getold, (int targ));
|
||
|
_PROTOTYPE(char *getnew, (int targ));
|
||
|
_PROTOTYPE(void *xmalloc, (size_t size));
|
||
|
_PROTOTYPE(void *xrealloc, (void *ptr, size_t size));
|
||
|
|
||
|
#define Nullfp (FILE*)0
|
||
|
#define Nullch (char*)0
|
||
|
#define ENOUGH (NAME_MAX + PATH_MAX + 1)
|
||
|
#define CRC_END 12
|
||
|
|
||
|
int main(argc, argv)
|
||
|
int argc;
|
||
|
char **argv;
|
||
|
{
|
||
|
FILE *crcfp;
|
||
|
char *old, *new;
|
||
|
int context = 3;
|
||
|
struct stat statbuf;
|
||
|
register char *s;
|
||
|
char op;
|
||
|
char *newmark, *oldmark;
|
||
|
char sysbuf1[ENOUGH], sysbuf2[ENOUGH];
|
||
|
int len;
|
||
|
char *line;
|
||
|
int i;
|
||
|
int status;
|
||
|
|
||
|
progname = argv[0];
|
||
|
oldalloc = 512;
|
||
|
oldhunk = (char *) xmalloc(oldalloc);
|
||
|
newalloc = 512;
|
||
|
newhunk = (char *) xmalloc(newalloc);
|
||
|
|
||
|
for (argc--, argv++; argc; argc--, argv++) {
|
||
|
if (argv[0][0] != '-') break;
|
||
|
|
||
|
if (argv[0][1] == 'c') context = atoi(argv[0] + 2);
|
||
|
}
|
||
|
|
||
|
if (argc != 2) {
|
||
|
fprintf(stderr, "Usage: cdiff old new\n");
|
||
|
exit(2);
|
||
|
}
|
||
|
old = argv[0];
|
||
|
new = argv[1];
|
||
|
|
||
|
oldfp = fopen(old, "r");
|
||
|
if (!oldfp) {
|
||
|
fprintf(stderr, "Can't open %s\n", old);
|
||
|
exit(2);
|
||
|
}
|
||
|
newfp = fopen(new, "r");
|
||
|
if (!newfp) {
|
||
|
fprintf(stderr, "Can't open %s\n", new);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
/* Compute crcs by popen()ing crc and reading the output. Do this before
|
||
|
* popen()ing diff to do the work. popen() attempts to support multiple
|
||
|
* clients, but the 1.3-1.6.24b versions don't succeed.
|
||
|
*/
|
||
|
sprintf(sysbuf1, "crc %s", old);
|
||
|
crcfp = popen(sysbuf1, "r");
|
||
|
if (!crcfp) {
|
||
|
/* The only advantage of cdiff over diff is that it prints crcs, so
|
||
|
* give up easily if crc fails.
|
||
|
*/
|
||
|
fprintf(stderr, "Can't execute crc %s\n", old);
|
||
|
exit(2);
|
||
|
}
|
||
|
fgets(sysbuf1, sizeof(sysbuf1), crcfp);
|
||
|
sysbuf1[CRC_END] = '\0';
|
||
|
status = pclose(crcfp);
|
||
|
if (status != 0) {
|
||
|
fprintf(stderr, "crc %s returned bad status %d\n", old, status);
|
||
|
exit(2);
|
||
|
}
|
||
|
sprintf(sysbuf2, "crc %s", new);
|
||
|
crcfp = popen(sysbuf2, "r");
|
||
|
if (!crcfp) {
|
||
|
fprintf(stderr, "Can't execute crc %s\n", new);
|
||
|
exit(2);
|
||
|
}
|
||
|
fgets(sysbuf2, sizeof(sysbuf2), crcfp);
|
||
|
sysbuf2[CRC_END] = '\0';
|
||
|
status = pclose(crcfp);
|
||
|
if (status != 0) {
|
||
|
fprintf(stderr, "crc %s returned bad status %d\n", new, status);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
sprintf(buff, "diff %s %s 2>/dev/null", old, new);
|
||
|
inputfp = popen(buff, "r");
|
||
|
if (!inputfp) {
|
||
|
fprintf(stderr, "Can't execute diff %s %s\n", old, new);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
fstat(fileno(oldfp), &statbuf);
|
||
|
printf("*** %s crc=%s\t%s", old, sysbuf1, ctime(&statbuf.st_mtime));
|
||
|
fstat(fileno(newfp), &statbuf);
|
||
|
printf("--- %s crc=%s\t%s", new, sysbuf2, ctime(&statbuf.st_mtime));
|
||
|
|
||
|
preoldend = -1000;
|
||
|
|
||
|
while (fgets(buff, sizeof buff, inputfp) != Nullch) {
|
||
|
if (isdigit(*buff)) {
|
||
|
oldmin = atoi(buff);
|
||
|
for (s = buff; isdigit(*s); s++);
|
||
|
if (*s == ',') {
|
||
|
s++;
|
||
|
oldmax = atoi(s);
|
||
|
for (; isdigit(*s); s++);
|
||
|
} else {
|
||
|
oldmax = oldmin;
|
||
|
}
|
||
|
if (*s != 'a' && *s != 'd' && *s != 'c') {
|
||
|
fprintf(stderr, "Unparseable input: %s\n", s);
|
||
|
exit(2);
|
||
|
}
|
||
|
op = *s;
|
||
|
s++;
|
||
|
newmin = atoi(s);
|
||
|
for (; isdigit(*s); s++);
|
||
|
if (*s == ',') {
|
||
|
s++;
|
||
|
newmax = atoi(s);
|
||
|
for (; isdigit(*s); s++);
|
||
|
} else {
|
||
|
newmax = newmin;
|
||
|
}
|
||
|
if (*s != '\n' && *s != ' ') {
|
||
|
fprintf(stderr, "Unparseable input: %s\n", s);
|
||
|
exit(2);
|
||
|
}
|
||
|
newmark = oldmark = "! ";
|
||
|
if (op == 'a') {
|
||
|
oldmin++;
|
||
|
newmark = "+ ";
|
||
|
}
|
||
|
if (op == 'd') {
|
||
|
newmin++;
|
||
|
oldmark = "- ";
|
||
|
}
|
||
|
oldbeg = oldmin - context;
|
||
|
oldend = oldmax + context;
|
||
|
if (oldbeg < 1) oldbeg = 1;
|
||
|
newbeg = newmin - context;
|
||
|
newend = newmax + context;
|
||
|
if (newbeg < 1) newbeg = 1;
|
||
|
|
||
|
if (preoldend < oldbeg - 1) {
|
||
|
if (preoldend >= 0) {
|
||
|
dumphunk();
|
||
|
}
|
||
|
preoldbeg = oldbeg;
|
||
|
prenewbeg = newbeg;
|
||
|
oldwanted = newwanted = 0;
|
||
|
oldsize = newsize = 0;
|
||
|
} else { /* we want to append to previous hunk */
|
||
|
oldbeg = preoldmax + 1;
|
||
|
newbeg = prenewmax + 1;
|
||
|
}
|
||
|
|
||
|
for (i = oldbeg; i <= oldmax; i++) {
|
||
|
line = getold(i);
|
||
|
if (!line) {
|
||
|
oldend = oldmax = i - 1;
|
||
|
break;
|
||
|
}
|
||
|
len = strlen(line) + 2;
|
||
|
if (oldsize + len + 1 >= oldalloc) {
|
||
|
oldalloc *= 2;
|
||
|
oldhunk = (char *) xrealloc(oldhunk, oldalloc);
|
||
|
}
|
||
|
if (i >= oldmin) {
|
||
|
strcpy(oldhunk + oldsize, oldmark);
|
||
|
oldwanted++;
|
||
|
} else {
|
||
|
strcpy(oldhunk + oldsize, " ");
|
||
|
}
|
||
|
strcpy(oldhunk + oldsize + 2, line);
|
||
|
oldsize += len;
|
||
|
}
|
||
|
preoldmax = oldmax;
|
||
|
preoldend = oldend;
|
||
|
|
||
|
for (i = newbeg; i <= newmax; i++) {
|
||
|
line = getnew(i);
|
||
|
if (!line) {
|
||
|
newend = newmax = i - 1;
|
||
|
break;
|
||
|
}
|
||
|
len = strlen(line) + 2;
|
||
|
if (newsize + len + 1 >= newalloc) {
|
||
|
newalloc *= 2;
|
||
|
newhunk = (char *) xrealloc(newhunk, newalloc);
|
||
|
}
|
||
|
if (i >= newmin) {
|
||
|
strcpy(newhunk + newsize, newmark);
|
||
|
newwanted++;
|
||
|
} else {
|
||
|
strcpy(newhunk + newsize, " ");
|
||
|
}
|
||
|
strcpy(newhunk + newsize + 2, line);
|
||
|
newsize += len;
|
||
|
}
|
||
|
prenewmax = newmax;
|
||
|
prenewend = newend;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (preoldend >= 0) {
|
||
|
dumphunk();
|
||
|
}
|
||
|
status = pclose(inputfp);
|
||
|
if (!WIFEXITED(status)) exit(2);
|
||
|
status = WEXITSTATUS(status);
|
||
|
return(status == 0 || status == 1 ? status : 2);
|
||
|
}
|
||
|
|
||
|
void dumphunk()
|
||
|
{
|
||
|
int i;
|
||
|
char *line;
|
||
|
int len;
|
||
|
|
||
|
for (i = preoldmax + 1; i <= preoldend; i++) {
|
||
|
line = getold(i);
|
||
|
if (!line) {
|
||
|
preoldend = i - 1;
|
||
|
break;
|
||
|
}
|
||
|
len = strlen(line) + 2;
|
||
|
if (oldsize + len + 1 >= oldalloc) {
|
||
|
oldalloc *= 2;
|
||
|
oldhunk = (char *) xrealloc(oldhunk, oldalloc);
|
||
|
}
|
||
|
strcpy(oldhunk + oldsize, " ");
|
||
|
strcpy(oldhunk + oldsize + 2, line);
|
||
|
oldsize += len;
|
||
|
}
|
||
|
for (i = prenewmax + 1; i <= prenewend; i++) {
|
||
|
line = getnew(i);
|
||
|
if (!line) {
|
||
|
prenewend = i - 1;
|
||
|
break;
|
||
|
}
|
||
|
len = strlen(line) + 2;
|
||
|
if (newsize + len + 1 >= newalloc) {
|
||
|
newalloc *= 2;
|
||
|
newhunk = (char *) xrealloc(newhunk, newalloc);
|
||
|
}
|
||
|
strcpy(newhunk + newsize, " ");
|
||
|
strcpy(newhunk + newsize + 2, line);
|
||
|
newsize += len;
|
||
|
}
|
||
|
printf("***************\n");
|
||
|
if (preoldbeg >= preoldend) {
|
||
|
printf("*** %d ****\n", preoldend);
|
||
|
} else {
|
||
|
printf("*** %d,%d ****\n", preoldbeg, preoldend);
|
||
|
}
|
||
|
if (oldwanted) {
|
||
|
printf("%s", oldhunk);
|
||
|
}
|
||
|
oldsize = 0;
|
||
|
*oldhunk = '\0';
|
||
|
if (prenewbeg >= prenewend) {
|
||
|
printf("--- %d ----\n", prenewend);
|
||
|
} else {
|
||
|
printf("--- %d,%d ----\n", prenewbeg, prenewend);
|
||
|
}
|
||
|
if (newwanted) {
|
||
|
printf("%s", newhunk);
|
||
|
}
|
||
|
newsize = 0;
|
||
|
*newhunk = '\0';
|
||
|
}
|
||
|
|
||
|
char *getold(targ)
|
||
|
int targ;
|
||
|
{
|
||
|
static int oldline = 0;
|
||
|
|
||
|
while (fgets(buff, sizeof buff, oldfp) != Nullch) {
|
||
|
oldline++;
|
||
|
if (oldline == targ) return buff;
|
||
|
}
|
||
|
return Nullch;
|
||
|
}
|
||
|
|
||
|
char *getnew(targ)
|
||
|
int targ;
|
||
|
{
|
||
|
static int newline = 0;
|
||
|
|
||
|
while (fgets(buff, sizeof buff, newfp) != Nullch) {
|
||
|
newline++;
|
||
|
if (newline == targ) return buff;
|
||
|
}
|
||
|
return Nullch;
|
||
|
}
|
||
|
|
||
|
void *xmalloc(size)
|
||
|
size_t size;
|
||
|
{
|
||
|
void *ptr;
|
||
|
|
||
|
ptr = malloc(size);
|
||
|
if (ptr == NULL) {
|
||
|
fprintf(stderr, "%s: out of memory\n", progname);
|
||
|
exit(2);
|
||
|
}
|
||
|
return(ptr);
|
||
|
}
|
||
|
|
||
|
void *xrealloc(ptr, size)
|
||
|
void *ptr;
|
||
|
size_t size;
|
||
|
{
|
||
|
ptr = realloc(ptr, size);
|
||
|
if (ptr == NULL) {
|
||
|
fprintf(stderr, "%s: out of memory\n", progname);
|
||
|
exit(2);
|
||
|
}
|
||
|
return(ptr);
|
||
|
}
|