version 1.57, 2005/10/07 21:47:32 |
version 1.58, 2005/10/07 23:59:56 |
|
|
} *file[2]; |
} *file[2]; |
|
|
/* |
/* |
* The following struct is used to record change information when |
* The following struct is used to record change in formation when |
* doing a "context" or "unified" diff. (see routine "change" to |
* doing a "context" or "unified" diff. (see routine "change" to |
* understand the highly mnemonic field names) |
* understand the highly mnemonic field names) |
*/ |
*/ |
|
|
static int cvs_diff_cleanup(void); |
static int cvs_diff_cleanup(void); |
#endif |
#endif |
|
|
|
static void diff_output(const char *, ...); |
static void output(const char *, FILE *, const char *, FILE *); |
static void output(const char *, FILE *, const char *, FILE *); |
static void check(FILE *, FILE *); |
static void check(FILE *, FILE *); |
static void range(int, int, char *); |
static void range(int, int, char *); |
|
|
#endif |
#endif |
static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; |
static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; |
static int context; |
static int context; |
static int format = D_NORMAL; |
int diff_format = D_NORMAL; |
static struct stat stb1, stb2; |
static struct stat stb1, stb2; |
static char *ifdefname, *ignore_pats; |
static char *ifdefname, *ignore_pats; |
static const char *diff_file; |
static const char *diff_file; |
|
|
static char lastbuf[FUNCTION_CONTEXT_SIZE]; |
static char lastbuf[FUNCTION_CONTEXT_SIZE]; |
static int lastline; |
static int lastline; |
static int lastmatchline; |
static int lastmatchline; |
|
static BUF *diffbuf = NULL; |
|
|
/* |
/* |
* chrtran points to one of 2 translation tables: cup2low if folding upper to |
* chrtran points to one of 2 translation tables: cup2low if folding upper to |
* lower case clow2low if not folding case |
* lower case clow2low if not folding case |
|
|
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
strlcat(diffargs, " -c", sizeof(diffargs)); |
strlcat(diffargs, " -c", sizeof(diffargs)); |
format = D_CONTEXT; |
diff_format = D_CONTEXT; |
break; |
break; |
case 'D': |
case 'D': |
if (dap->date1 == NULL && dap->rev1 == NULL) { |
if (dap->date1 == NULL && dap->rev1 == NULL) { |
|
|
break; |
break; |
case 'n': |
case 'n': |
strlcat(diffargs, " -n", sizeof(diffargs)); |
strlcat(diffargs, " -n", sizeof(diffargs)); |
format = D_RCSDIFF; |
diff_format = D_RCSDIFF; |
break; |
break; |
case 'p': |
case 'p': |
strlcat(diffargs, " -p", sizeof(diffargs)); |
strlcat(diffargs, " -p", sizeof(diffargs)); |
|
|
break; |
break; |
case 'u': |
case 'u': |
strlcat(diffargs, " -u", sizeof(diffargs)); |
strlcat(diffargs, " -u", sizeof(diffargs)); |
format = D_UNIFIED; |
diff_format = D_UNIFIED; |
break; |
break; |
default: |
default: |
return (CVS_EX_USAGE); |
return (CVS_EX_USAGE); |
|
|
if (pflag && (cvs_sendarg(root, "-p", 0) < 0)) |
if (pflag && (cvs_sendarg(root, "-p", 0) < 0)) |
return (CVS_EX_PROTO); |
return (CVS_EX_PROTO); |
|
|
if (format == D_CONTEXT) { |
if (diff_format == D_CONTEXT) { |
if (cvs_sendarg(root, "-c", 0) < 0) |
if (cvs_sendarg(root, "-c", 0) < 0) |
return (CVS_EX_PROTO); |
return (CVS_EX_PROTO); |
} else if (format == D_UNIFIED) { |
} else if (diff_format == D_UNIFIED) { |
if (cvs_sendarg(root, "-u", 0) < 0) |
if (cvs_sendarg(root, "-u", 0) < 0) |
return (CVS_EX_PROTO); |
return (CVS_EX_PROTO); |
} |
} |
|
|
} |
} |
cvs_buf_free(b2); |
cvs_buf_free(b2); |
|
|
cvs_diffreg(path_tmp1, path_tmp2); |
cvs_diffreg(path_tmp1, path_tmp2, NULL); |
(void)unlink(path_tmp1); |
(void)unlink(path_tmp1); |
(void)unlink(path_tmp2); |
(void)unlink(path_tmp2); |
|
|
|
|
|
|
|
|
int |
int |
cvs_diffreg(const char *file1, const char *file2) |
cvs_diffreg(const char *file1, const char *file2, BUF *out) |
{ |
{ |
FILE *f1, *f2; |
FILE *f1, *f2; |
int i, rval; |
int i, rval; |
|
|
lastmatchline = 0; |
lastmatchline = 0; |
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
chrtran = (iflag ? cup2low : clow2low); |
chrtran = (iflag ? cup2low : clow2low); |
|
if (out != NULL) |
|
diffbuf = out; |
|
|
f1 = fopen(file1, "r"); |
f1 = fopen(file1, "r"); |
if (f1 == NULL) { |
if (f1 == NULL) { |
|
|
} |
} |
if (m == 0) |
if (m == 0) |
change(file1, f1, file2, f2, 1, 0, 1, diff_len[1]); |
change(file1, f1, file2, f2, 1, 0, 1, diff_len[1]); |
if (format == D_IFDEF) { |
if (diff_format == D_IFDEF) { |
for (;;) { |
for (;;) { |
#define c i0 |
#define c i0 |
if ((c = getc(f1)) == EOF) |
if ((c = getc(f1)) == EOF) |
return; |
return; |
cvs_putchar(c); |
diff_output("%c", c); |
} |
} |
#undef c |
#undef c |
} |
} |
if (anychange != 0) { |
if (anychange != 0) { |
if (format == D_CONTEXT) |
if (diff_format == D_CONTEXT) |
dump_context_vec(f1, f2); |
dump_context_vec(f1, f2); |
else if (format == D_UNIFIED) |
else if (diff_format == D_UNIFIED) |
dump_unified_vec(f1, f2); |
dump_unified_vec(f1, f2); |
} |
} |
} |
} |
|
|
static __inline void |
static __inline void |
range(int a, int b, char *separator) |
range(int a, int b, char *separator) |
{ |
{ |
cvs_printf("%d", a > b ? b : a); |
diff_output("%d", a > b ? b : a); |
if (a < b) |
if (a < b) |
cvs_printf("%s%d", separator, b); |
diff_output("%s%d", separator, b); |
} |
} |
|
|
static __inline void |
static __inline void |
uni_range(int a, int b) |
uni_range(int a, int b) |
{ |
{ |
if (a < b) |
if (a < b) |
cvs_printf("%d,%d", a, b - a + 1); |
diff_output("%d,%d", a, b - a + 1); |
else if (a == b) |
else if (a == b) |
cvs_printf("%d", b); |
diff_output("%d", b); |
else |
else |
cvs_printf("%d,0", b); |
diff_output("%d,0", b); |
} |
} |
|
|
static char * |
static char * |
|
|
static size_t max_context = 64; |
static size_t max_context = 64; |
int i; |
int i; |
|
|
if (format != D_IFDEF && a > b && c > d) |
if (diff_format != D_IFDEF && a > b && c > d) |
return; |
return; |
if (ignore_pats != NULL) { |
if (ignore_pats != NULL) { |
char *line; |
char *line; |
|
|
return; |
return; |
} |
} |
proceed: |
proceed: |
if (format == D_CONTEXT || format == D_UNIFIED) { |
if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { |
/* |
/* |
* Allocate change records as needed. |
* Allocate change records as needed. |
*/ |
*/ |
|
|
/* |
/* |
* Print the context/unidiff header first time through. |
* Print the context/unidiff header first time through. |
*/ |
*/ |
cvs_printf("%s %s %s", |
diff_output("%s %s %s", |
format == D_CONTEXT ? "***" : "---", diff_file, |
diff_format == D_CONTEXT ? "***" : "---", diff_file, |
ctime(&stb1.st_mtime)); |
ctime(&stb1.st_mtime)); |
cvs_printf("%s %s %s", |
diff_output("%s %s %s", |
format == D_CONTEXT ? "---" : "+++", diff_file, |
diff_format == D_CONTEXT ? "---" : "+++", diff_file, |
ctime(&stb2.st_mtime)); |
ctime(&stb2.st_mtime)); |
anychange = 1; |
anychange = 1; |
} else if (a > context_vec_ptr->b + (2 * context) + 1 && |
} else if (a > context_vec_ptr->b + (2 * context) + 1 && |
|
|
* If this change is more than 'context' lines from the |
* If this change is more than 'context' lines from the |
* previous change, dump the record and reset it. |
* previous change, dump the record and reset it. |
*/ |
*/ |
if (format == D_CONTEXT) |
if (diff_format == D_CONTEXT) |
dump_context_vec(f1, f2); |
dump_context_vec(f1, f2); |
else |
else |
dump_unified_vec(f1, f2); |
dump_unified_vec(f1, f2); |
|
|
} |
} |
if (anychange == 0) |
if (anychange == 0) |
anychange = 1; |
anychange = 1; |
switch (format) { |
switch (diff_format) { |
case D_BRIEF: |
case D_BRIEF: |
return; |
return; |
case D_NORMAL: |
case D_NORMAL: |
range(a, b, ","); |
range(a, b, ","); |
cvs_putchar(a > b ? 'a' : c > d ? 'd' : 'c'); |
diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); |
if (format == D_NORMAL) |
if (diff_format == D_NORMAL) |
range(c, d, ","); |
range(c, d, ","); |
cvs_putchar('\n'); |
diff_output("\n"); |
break; |
break; |
case D_RCSDIFF: |
case D_RCSDIFF: |
if (a > b) |
if (a > b) |
cvs_printf("a%d %d\n", b, d - c + 1); |
diff_output("a%d %d\n", b, d - c + 1); |
else { |
else { |
cvs_printf("d%d %d\n", a, b - a + 1); |
diff_output("d%d %d\n", a, b - a + 1); |
|
|
if (!(c > d)) /* add changed lines */ |
if (!(c > d)) /* add changed lines */ |
cvs_printf("a%d %d\n", b, d - c + 1); |
diff_output("a%d %d\n", b, d - c + 1); |
} |
} |
break; |
break; |
} |
} |
if (format == D_NORMAL || format == D_IFDEF) { |
if (diff_format == D_NORMAL || diff_format == D_IFDEF) { |
fetch(ixold, a, b, f1, '<', 1); |
fetch(ixold, a, b, f1, '<', 1); |
if (a <= b && c <= d && format == D_NORMAL) |
if (a <= b && c <= d && diff_format == D_NORMAL) |
puts("---"); |
diff_output("---"); |
} |
} |
i = fetch(ixnew, c, d, f2, format == D_NORMAL ? '>' : '\0', 0); |
i = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); |
if (inifdef) { |
if (inifdef) { |
cvs_printf("#endif /* %s */\n", ifdefname); |
diff_output("#endif /* %s */\n", ifdefname); |
inifdef = 0; |
inifdef = 0; |
} |
} |
} |
} |
|
|
* When doing #ifdef's, copy down to current line |
* When doing #ifdef's, copy down to current line |
* if this is the first file, so that stuff makes it to output. |
* if this is the first file, so that stuff makes it to output. |
*/ |
*/ |
if (format == D_IFDEF && oldfile) { |
if (diff_format == D_IFDEF && oldfile) { |
long curpos = ftell(lb); |
long curpos = ftell(lb); |
/* print through if append (a>b), else to (nb: 0 vs 1 orig) */ |
/* print through if append (a>b), else to (nb: 0 vs 1 orig) */ |
nc = f[a > b ? b : a - 1] - curpos; |
nc = f[a > b ? b : a - 1] - curpos; |
for (i = 0; i < nc; i++) |
for (i = 0; i < nc; i++) |
cvs_putchar(getc(lb)); |
diff_output("%c", getc(lb)); |
} |
} |
if (a > b) |
if (a > b) |
return (0); |
return (0); |
if (format == D_IFDEF) { |
if (diff_format == D_IFDEF) { |
if (inifdef) { |
if (inifdef) { |
cvs_printf("#else /* %s%s */\n", |
diff_output("#else /* %s%s */\n", |
oldfile == 1 ? "!" : "", ifdefname); |
oldfile == 1 ? "!" : "", ifdefname); |
} else { |
} else { |
if (oldfile) |
if (oldfile) |
cvs_printf("#ifndef %s\n", ifdefname); |
diff_output("#ifndef %s\n", ifdefname); |
else |
else |
cvs_printf("#ifdef %s\n", ifdefname); |
diff_output("#ifdef %s\n", ifdefname); |
} |
} |
inifdef = 1 + oldfile; |
inifdef = 1 + oldfile; |
} |
} |
for (i = a; i <= b; i++) { |
for (i = a; i <= b; i++) { |
fseek(lb, f[i - 1], SEEK_SET); |
fseek(lb, f[i - 1], SEEK_SET); |
nc = f[i] - f[i - 1]; |
nc = f[i] - f[i - 1]; |
if (format != D_IFDEF && ch != '\0') { |
if (diff_format != D_IFDEF && ch != '\0') { |
cvs_putchar(ch); |
diff_output("%c", ch); |
if (Tflag && (format == D_NORMAL || format == D_CONTEXT |
if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT |
|| format == D_UNIFIED)) |
|| diff_format == D_UNIFIED)) |
cvs_putchar('\t'); |
diff_output("\t"); |
else if (format != D_UNIFIED) |
else if (diff_format != D_UNIFIED) |
cvs_putchar(' '); |
diff_output(" "); |
} |
} |
col = 0; |
col = 0; |
for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { |
for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { |
if ((c = getc(lb)) == EOF) { |
if ((c = getc(lb)) == EOF) { |
if (format == D_RCSDIFF) |
if (diff_format == D_RCSDIFF) |
warnx("No newline at end of file"); |
warnx("No newline at end of file"); |
else |
else |
puts("\n\\ No newline at end of file"); |
diff_output("\n\\ No newline at end of file"); |
return (0); |
return (0); |
} |
} |
if (c == '\t' && tflag) { |
if (c == '\t' && tflag) { |
do { |
do { |
cvs_putchar(' '); |
diff_output(" "); |
} while (++col & 7); |
} while (++col & 7); |
} else { |
} else { |
cvs_putchar(c); |
diff_output("%c", c); |
col++; |
col++; |
} |
} |
} |
} |
|
|
lowc = MAX(1, cvp->c - context); |
lowc = MAX(1, cvp->c - context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
|
|
cvs_printf("***************"); |
diff_output("***************"); |
if (pflag) { |
if (pflag) { |
f = match_function(ixold, lowa - 1, f1); |
f = match_function(ixold, lowa - 1, f1); |
if (f != NULL) { |
if (f != NULL) { |
cvs_putchar(' '); |
diff_output(" "); |
cvs_printf("%s", f); |
diff_output("%s", f); |
} |
} |
} |
} |
cvs_printf("\n*** "); |
diff_output("\n*** "); |
range(lowa, upb, ","); |
range(lowa, upb, ","); |
cvs_printf(" ****\n"); |
diff_output(" ****\n"); |
|
|
/* |
/* |
* Output changes to the "old" file. The first loop suppresses |
* Output changes to the "old" file. The first loop suppresses |
|
|
fetch(ixold, b + 1, upb, f1, ' ', 0); |
fetch(ixold, b + 1, upb, f1, ' ', 0); |
} |
} |
/* output changes to the "new" file */ |
/* output changes to the "new" file */ |
cvs_printf("--- "); |
diff_output("--- "); |
range(lowc, upd, ","); |
range(lowc, upd, ","); |
cvs_printf(" ----\n"); |
diff_output(" ----\n"); |
|
|
do_output = 0; |
do_output = 0; |
for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) |
for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) |
|
|
lowc = MAX(1, cvp->c - context); |
lowc = MAX(1, cvp->c - context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
upd = MIN(diff_len[1], context_vec_ptr->d + context); |
|
|
cvs_printf("@@ -"); |
diff_output("@@ -"); |
uni_range(lowa, upb); |
uni_range(lowa, upb); |
cvs_printf(" +"); |
diff_output(" +"); |
uni_range(lowc, upd); |
uni_range(lowc, upd); |
cvs_printf(" @@"); |
diff_output(" @@"); |
if (pflag) { |
if (pflag) { |
f = match_function(ixold, lowa - 1, f1); |
f = match_function(ixold, lowa - 1, f1); |
if (f != NULL) { |
if (f != NULL) { |
cvs_putchar(' '); |
diff_output(" "); |
cvs_printf("%s", f); |
diff_output("%s", f); |
} |
} |
} |
} |
cvs_putchar('\n'); |
diff_output("\n"); |
|
|
/* |
/* |
* Output changes in "unified" diff format--the old and new lines |
* Output changes in "unified" diff format--the old and new lines |
|
|
fetch(ixnew, d + 1, upd, f2, ' ', 0); |
fetch(ixnew, d + 1, upd, f2, ' ', 0); |
|
|
context_vec_ptr = context_vec_start - 1; |
context_vec_ptr = context_vec_start - 1; |
|
} |
|
|
|
static void |
|
diff_output(const char *fmt, ...) |
|
{ |
|
va_list vap; |
|
char *str; |
|
|
|
va_start(vap, fmt); |
|
vasprintf(&str, fmt, vap); |
|
if (diffbuf != NULL) |
|
cvs_buf_append(diffbuf, str, strlen(str)); |
|
else |
|
cvs_printf("%s", str); |
|
free(str); |
|
va_end(vap); |
} |
} |