Updated to GNU diffutils 2.6
This commit is contained in:
parent
fbc38b4bc3
commit
54a379a8a7
@ -1,11 +1,8 @@
|
||||
|
||||
PROG= diff
|
||||
SRCS= diff.c analyze.c io.c context.c ed.c normal.c ifdef.c util.c dir.c \
|
||||
version.c regex.c getopt.c getopt1.c side.c
|
||||
CFLAGS+=-DDIRENT=1 -DHAVE_UNISTD_H=1 -DHAVE_DUP2=1 -DHAVE_MEMCHR=1 \
|
||||
-DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_FCNTL_H=1 \
|
||||
-DHAVE_STRING_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_TIME_H=1 \
|
||||
-DHAVE_ST_BLKSIZE=1
|
||||
version.c regex.c getopt.c getopt1.c side.c cmpbuf.c
|
||||
CFLAGS+=-DHAVE_CONFIG_H
|
||||
MAN= diff.1
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Analyze file differences for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -17,72 +17,98 @@ You should have received a copy of the GNU General Public License
|
||||
along with GNU DIFF; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* The basic algorithm is described in:
|
||||
/* The basic algorithm is described in:
|
||||
"An O(ND) Difference Algorithm and its Variations", Eugene Myers,
|
||||
Algorithmica Vol. 1 No. 2, 1986, p 251. */
|
||||
Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;
|
||||
see especially section 4.2, which describes the variation used below.
|
||||
Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE
|
||||
heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N)
|
||||
at the price of producing suboptimal output for large inputs with
|
||||
many differences.
|
||||
|
||||
The basic algorithm was independently discovered as described in:
|
||||
"Algorithms for Approximate String Matching", E. Ukkonen,
|
||||
Information and Control Vol. 64, 1985, pp. 100-118. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
int read_files ();
|
||||
void finish_output ();
|
||||
void print_context_script ();
|
||||
void print_ed_script ();
|
||||
void print_ifdef_script ();
|
||||
void print_sdiff_script ();
|
||||
void print_normal_script ();
|
||||
void print_rcs_script ();
|
||||
void pr_forward_ed_script ();
|
||||
void setup_output ();
|
||||
#include "cmpbuf.h"
|
||||
|
||||
extern int no_discards;
|
||||
|
||||
static int *xvec, *yvec; /* Vectors being compared. */
|
||||
static int *fdiag; /* Vector, indexed by diagonal, containing
|
||||
the X coordinate of the point furthest
|
||||
1 + the X coordinate of the point furthest
|
||||
along the given diagonal in the forward
|
||||
search of the edit matrix. */
|
||||
static int *bdiag; /* Vector, indexed by diagonal, containing
|
||||
the X coordinate of the point furthest
|
||||
along the given diagonal in the backward
|
||||
search of the edit matrix. */
|
||||
static int too_expensive; /* Edit scripts longer than this are too
|
||||
expensive to compute. */
|
||||
|
||||
#define SNAKE_LIMIT 20 /* Snakes bigger than this are considered `big'. */
|
||||
|
||||
struct partition
|
||||
{
|
||||
int xmid, ymid; /* Midpoints of this partition. */
|
||||
int lo_minimal; /* Nonzero if low half will be analyzed minimally. */
|
||||
int hi_minimal; /* Likewise for high half. */
|
||||
};
|
||||
|
||||
static int diag PARAMS((int, int, int, int, int, struct partition *));
|
||||
static struct change *add_change PARAMS((int, int, int, int, struct change *));
|
||||
static struct change *build_reverse_script PARAMS((struct file_data const[]));
|
||||
static struct change *build_script PARAMS((struct file_data const[]));
|
||||
static void briefly_report PARAMS((int, struct file_data const[]));
|
||||
static void compareseq PARAMS((int, int, int, int, int));
|
||||
static void discard_confusing_lines PARAMS((struct file_data[]));
|
||||
static void shift_boundaries PARAMS((struct file_data[]));
|
||||
|
||||
/* Find the midpoint of the shortest edit script for a specified
|
||||
portion of the two files.
|
||||
|
||||
We scan from the beginnings of the files, and simultaneously from the ends,
|
||||
Scan from the beginnings of the files, and simultaneously from the ends,
|
||||
doing a breadth-first search through the space of edit-sequence.
|
||||
When the two searches meet, we have found the midpoint of the shortest
|
||||
edit sequence.
|
||||
|
||||
The value returned is the number of the diagonal on which the midpoint lies.
|
||||
The diagonal number equals the number of inserted lines minus the number
|
||||
If MINIMAL is nonzero, find the minimal edit script regardless
|
||||
of expense. Otherwise, if the search is too expensive, use
|
||||
heuristics to stop the search and report a suboptimal answer.
|
||||
|
||||
Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal number
|
||||
XMID - YMID equals the number of inserted lines minus the number
|
||||
of deleted lines (counting only lines before the midpoint).
|
||||
The edit cost is stored into *COST; this is the total number of
|
||||
lines inserted or deleted (counting only lines before the midpoint).
|
||||
Return the approximate edit cost; this is the total number of
|
||||
lines inserted or deleted (counting only lines before the midpoint),
|
||||
unless a heuristic is used to terminate the search prematurely.
|
||||
|
||||
Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script for the
|
||||
left half of the partition is known; similarly for PART->RIGHT_MINIMAL.
|
||||
|
||||
This function assumes that the first lines of the specified portions
|
||||
of the two files do not match, and likewise that the last lines do not
|
||||
match. The caller must trim matching lines from the beginning and end
|
||||
of the portions it is going to specify.
|
||||
|
||||
Note that if we return the "wrong" diagonal value, or if
|
||||
the value of bdiag at that diagonal is "wrong",
|
||||
If we return the "wrong" partitions,
|
||||
the worst this can do is cause suboptimal diff output.
|
||||
It cannot cause incorrect diff output. */
|
||||
|
||||
static int
|
||||
diag (xoff, xlim, yoff, ylim, cost)
|
||||
int xoff, xlim, yoff, ylim;
|
||||
int *cost;
|
||||
diag (xoff, xlim, yoff, ylim, minimal, part)
|
||||
int xoff, xlim, yoff, ylim, minimal;
|
||||
struct partition *part;
|
||||
{
|
||||
int *const fd = fdiag; /* Give the compiler a chance. */
|
||||
int *const bd = bdiag; /* Additional help for the compiler. */
|
||||
int *const xv = xvec; /* Still more help for the compiler. */
|
||||
int *const yv = yvec; /* And more and more . . . */
|
||||
const int dmin = xoff - ylim; /* Minimum valid diagonal. */
|
||||
const int dmax = xlim - yoff; /* Maximum valid diagonal. */
|
||||
const int fmid = xoff - yoff; /* Center diagonal of top-down search. */
|
||||
const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
|
||||
int const *const xv = xvec; /* Still more help for the compiler. */
|
||||
int const *const yv = yvec; /* And more and more . . . */
|
||||
int const dmin = xoff - ylim; /* Minimum valid diagonal. */
|
||||
int const dmax = xlim - yoff; /* Maximum valid diagonal. */
|
||||
int const fmid = xoff - yoff; /* Center diagonal of top-down search. */
|
||||
int const bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
|
||||
int fmin = fmid, fmax = fmid; /* Limits of top-down search. */
|
||||
int bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */
|
||||
int c; /* Cost. */
|
||||
@ -112,17 +138,19 @@ diag (xoff, xlim, yoff, ylim, cost)
|
||||
y = x - d;
|
||||
while (x < xlim && y < ylim && xv[x] == yv[y])
|
||||
++x, ++y;
|
||||
if (x - oldx > 20)
|
||||
if (x - oldx > SNAKE_LIMIT)
|
||||
big_snake = 1;
|
||||
fd[d] = x;
|
||||
if (odd && bmin <= d && d <= bmax && bd[d] <= fd[d])
|
||||
if (odd && bmin <= d && d <= bmax && bd[d] <= x)
|
||||
{
|
||||
*cost = 2 * c - 1;
|
||||
return d;
|
||||
part->xmid = x;
|
||||
part->ymid = y;
|
||||
part->lo_minimal = part->hi_minimal = 1;
|
||||
return 2 * c - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Similar extend the bottom-up search. */
|
||||
/* Similarly extend the bottom-up search. */
|
||||
bmin > dmin ? bd[--bmin - 1] = INT_MAX : ++bmin;
|
||||
bmax < dmax ? bd[++bmax + 1] = INT_MAX : --bmax;
|
||||
for (d = bmax; d >= bmin; d -= 2)
|
||||
@ -137,16 +165,21 @@ diag (xoff, xlim, yoff, ylim, cost)
|
||||
y = x - d;
|
||||
while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
|
||||
--x, --y;
|
||||
if (oldx - x > 20)
|
||||
if (oldx - x > SNAKE_LIMIT)
|
||||
big_snake = 1;
|
||||
bd[d] = x;
|
||||
if (!odd && fmin <= d && d <= fmax && bd[d] <= fd[d])
|
||||
if (!odd && fmin <= d && d <= fmax && x <= fd[d])
|
||||
{
|
||||
*cost = 2 * c;
|
||||
return d;
|
||||
part->xmid = x;
|
||||
part->ymid = y;
|
||||
part->lo_minimal = part->hi_minimal = 1;
|
||||
return 2 * c;
|
||||
}
|
||||
}
|
||||
|
||||
if (minimal)
|
||||
continue;
|
||||
|
||||
/* Heuristic: check occasionally for a diagonal that has made
|
||||
lots of progress compared with the edit distance.
|
||||
If we have any such, find the one that has made the most
|
||||
@ -158,73 +191,134 @@ diag (xoff, xlim, yoff, ylim, cost)
|
||||
if (c > 200 && big_snake && heuristic)
|
||||
{
|
||||
int best;
|
||||
int bestpos;
|
||||
|
||||
best = 0;
|
||||
for (d = fmax; d >= fmin; d -= 2)
|
||||
{
|
||||
int dd = d - fmid;
|
||||
if ((fd[d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
|
||||
int x = fd[d];
|
||||
int y = x - d;
|
||||
int v = (x - xoff) * 2 - dd;
|
||||
if (v > 12 * (c + (dd < 0 ? -dd : dd)))
|
||||
{
|
||||
if (fd[d] * 2 - dd > best
|
||||
&& fd[d] - xoff > 20
|
||||
&& fd[d] - d - yoff > 20)
|
||||
if (v > best
|
||||
&& xoff + SNAKE_LIMIT <= x && x < xlim
|
||||
&& yoff + SNAKE_LIMIT <= y && y < ylim)
|
||||
{
|
||||
int k;
|
||||
int x = fd[d];
|
||||
|
||||
/* We have a good enough best diagonal;
|
||||
now insist that it end with a significant snake. */
|
||||
for (k = 1; k <= 20; k++)
|
||||
if (xvec[x - k] != yvec[x - d - k])
|
||||
break;
|
||||
int k;
|
||||
|
||||
if (k == 21)
|
||||
{
|
||||
best = fd[d] * 2 - dd;
|
||||
bestpos = d;
|
||||
}
|
||||
for (k = 1; xv[x - k] == yv[y - k]; k++)
|
||||
if (k == SNAKE_LIMIT)
|
||||
{
|
||||
best = v;
|
||||
part->xmid = x;
|
||||
part->ymid = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best > 0)
|
||||
{
|
||||
*cost = 2 * c - 1;
|
||||
return bestpos;
|
||||
part->lo_minimal = 1;
|
||||
part->hi_minimal = 0;
|
||||
return 2 * c - 1;
|
||||
}
|
||||
|
||||
best = 0;
|
||||
for (d = bmax; d >= bmin; d -= 2)
|
||||
{
|
||||
int dd = d - bmid;
|
||||
if ((xlim - bd[d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
|
||||
int x = bd[d];
|
||||
int y = x - d;
|
||||
int v = (xlim - x) * 2 + dd;
|
||||
if (v > 12 * (c + (dd < 0 ? -dd : dd)))
|
||||
{
|
||||
if ((xlim - bd[d]) * 2 + dd > best
|
||||
&& xlim - bd[d] > 20
|
||||
&& ylim - (bd[d] - d) > 20)
|
||||
if (v > best
|
||||
&& xoff < x && x <= xlim - SNAKE_LIMIT
|
||||
&& yoff < y && y <= ylim - SNAKE_LIMIT)
|
||||
{
|
||||
/* We have a good enough best diagonal;
|
||||
now insist that it end with a significant snake. */
|
||||
int k;
|
||||
int x = bd[d];
|
||||
|
||||
for (k = 0; k < 20; k++)
|
||||
if (xvec[x + k] != yvec[x - d + k])
|
||||
break;
|
||||
if (k == 20)
|
||||
{
|
||||
best = (xlim - bd[d]) * 2 + dd;
|
||||
bestpos = d;
|
||||
}
|
||||
for (k = 0; xv[x + k] == yv[y + k]; k++)
|
||||
if (k == SNAKE_LIMIT - 1)
|
||||
{
|
||||
best = v;
|
||||
part->xmid = x;
|
||||
part->ymid = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best > 0)
|
||||
{
|
||||
*cost = 2 * c - 1;
|
||||
return bestpos;
|
||||
part->lo_minimal = 0;
|
||||
part->hi_minimal = 1;
|
||||
return 2 * c - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heuristic: if we've gone well beyond the call of duty,
|
||||
give up and report halfway between our best results so far. */
|
||||
if (c >= too_expensive)
|
||||
{
|
||||
int fxybest, fxbest;
|
||||
int bxybest, bxbest;
|
||||
|
||||
fxbest = bxbest = 0; /* Pacify `gcc -Wall'. */
|
||||
|
||||
/* Find forward diagonal that maximizes X + Y. */
|
||||
fxybest = -1;
|
||||
for (d = fmax; d >= fmin; d -= 2)
|
||||
{
|
||||
int x = min (fd[d], xlim);
|
||||
int y = x - d;
|
||||
if (ylim < y)
|
||||
x = ylim + d, y = ylim;
|
||||
if (fxybest < x + y)
|
||||
{
|
||||
fxybest = x + y;
|
||||
fxbest = x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find backward diagonal that minimizes X + Y. */
|
||||
bxybest = INT_MAX;
|
||||
for (d = bmax; d >= bmin; d -= 2)
|
||||
{
|
||||
int x = max (xoff, bd[d]);
|
||||
int y = x - d;
|
||||
if (y < yoff)
|
||||
x = yoff + d, y = yoff;
|
||||
if (x + y < bxybest)
|
||||
{
|
||||
bxybest = x + y;
|
||||
bxbest = x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the better of the two diagonals. */
|
||||
if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
|
||||
{
|
||||
part->xmid = fxbest;
|
||||
part->ymid = fxybest - fxbest;
|
||||
part->lo_minimal = 1;
|
||||
part->hi_minimal = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
part->xmid = bxbest;
|
||||
part->ymid = bxybest - bxbest;
|
||||
part->lo_minimal = 0;
|
||||
part->hi_minimal = 1;
|
||||
}
|
||||
return 2 * c - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,19 +331,25 @@ diag (xoff, xlim, yoff, ylim, cost)
|
||||
The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
|
||||
|
||||
Note that XLIM, YLIM are exclusive bounds.
|
||||
All line numbers are origin-0 and discarded lines are not counted. */
|
||||
All line numbers are origin-0 and discarded lines are not counted.
|
||||
|
||||
If MINIMAL is nonzero, find a minimal difference no matter how
|
||||
expensive it is. */
|
||||
|
||||
static void
|
||||
compareseq (xoff, xlim, yoff, ylim)
|
||||
int xoff, xlim, yoff, ylim;
|
||||
compareseq (xoff, xlim, yoff, ylim, minimal)
|
||||
int xoff, xlim, yoff, ylim, minimal;
|
||||
{
|
||||
int * const xv = xvec; /* Help the compiler. */
|
||||
int * const yv = yvec;
|
||||
|
||||
/* Slide down the bottom initial diagonal. */
|
||||
while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff])
|
||||
while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff])
|
||||
++xoff, ++yoff;
|
||||
/* Slide up the top initial diagonal. */
|
||||
while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1])
|
||||
while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1])
|
||||
--xlim, --ylim;
|
||||
|
||||
|
||||
/* Handle simple cases. */
|
||||
if (xoff == xlim)
|
||||
while (yoff < ylim)
|
||||
@ -259,13 +359,12 @@ compareseq (xoff, xlim, yoff, ylim)
|
||||
files[0].changed_flag[files[0].realindexes[xoff++]] = 1;
|
||||
else
|
||||
{
|
||||
int c, d, f, b;
|
||||
int c;
|
||||
struct partition part;
|
||||
|
||||
/* Find a point of correspondence in the middle of the files. */
|
||||
|
||||
d = diag (xoff, xlim, yoff, ylim, &c);
|
||||
f = fdiag[d];
|
||||
b = bdiag[d];
|
||||
c = diag (xoff, xlim, yoff, ylim, minimal, &part);
|
||||
|
||||
if (c == 1)
|
||||
{
|
||||
@ -277,21 +376,17 @@ compareseq (xoff, xlim, yoff, ylim)
|
||||
#if 0
|
||||
/* The two subsequences differ by a single insert or delete;
|
||||
record it and we are done. */
|
||||
if (d < xoff - yoff)
|
||||
files[1].changed_flag[files[1].realindexes[b - d - 1]] = 1;
|
||||
if (part.xmid - part.ymid < xoff - yoff)
|
||||
files[1].changed_flag[files[1].realindexes[part.ymid - 1]] = 1;
|
||||
else
|
||||
files[0].changed_flag[files[0].realindexes[b]] = 1;
|
||||
files[0].changed_flag[files[0].realindexes[part.xmid]] = 1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use that point to split this problem into two subproblems. */
|
||||
compareseq (xoff, b, yoff, b - d);
|
||||
/* This used to use f instead of b,
|
||||
but that is incorrect!
|
||||
It is not necessarily the case that diagonal d
|
||||
has a snake from b to f. */
|
||||
compareseq (b, xlim, b - d, ylim);
|
||||
/* Use the partitions to split this problem into subproblems. */
|
||||
compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal);
|
||||
compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,7 +403,7 @@ compareseq (xoff, xlim, yoff, ylim)
|
||||
When we discard a line, we also mark it as a deletion or insertion
|
||||
so that it will be printed in the output. */
|
||||
|
||||
void
|
||||
static void
|
||||
discard_confusing_lines (filevec)
|
||||
struct file_data filevec[];
|
||||
{
|
||||
@ -341,10 +436,12 @@ discard_confusing_lines (filevec)
|
||||
|
||||
/* Set up tables of which lines are going to be discarded. */
|
||||
|
||||
discarded[0] = (char *) xmalloc (filevec[0].buffered_lines
|
||||
+ filevec[1].buffered_lines);
|
||||
discarded[0] = xmalloc (sizeof (char)
|
||||
* (filevec[0].buffered_lines
|
||||
+ filevec[1].buffered_lines));
|
||||
discarded[1] = discarded[0] + filevec[0].buffered_lines;
|
||||
bzero (discarded[0], filevec[0].buffered_lines + filevec[1].buffered_lines);
|
||||
bzero (discarded[0], sizeof (char) * (filevec[0].buffered_lines
|
||||
+ filevec[1].buffered_lines));
|
||||
|
||||
/* Mark to be discarded each line that matches no line of the other file.
|
||||
If a line matches many lines, mark it as provisionally discardable. */
|
||||
@ -509,16 +606,15 @@ discard_confusing_lines (filevec)
|
||||
free (equiv_count[0]);
|
||||
}
|
||||
|
||||
/* Adjust inserts/deletes of blank lines to join changes
|
||||
/* Adjust inserts/deletes of identical lines to join changes
|
||||
as much as possible.
|
||||
|
||||
We do something when a run of changed lines include a blank
|
||||
line at one end and have an excluded blank line at the other.
|
||||
We are free to choose which blank line is included.
|
||||
`compareseq' always chooses the one at the beginning,
|
||||
but usually it is cleaner to consider the following blank line
|
||||
to be the "change". The only exception is if the preceding blank line
|
||||
would join this change to other changes. */
|
||||
We do something when a run of changed lines include a
|
||||
line at one end and have an excluded, identical line at the other.
|
||||
We are free to choose which identical line is included.
|
||||
`compareseq' usually chooses the one at the beginning,
|
||||
but usually it is cleaner to consider the following identical line
|
||||
to be the "change". */
|
||||
|
||||
int inhibit;
|
||||
|
||||
@ -534,16 +630,15 @@ shift_boundaries (filevec)
|
||||
for (f = 0; f < 2; f++)
|
||||
{
|
||||
char *changed = filevec[f].changed_flag;
|
||||
char *other_changed = filevec[1-f].changed_flag;
|
||||
char const *other_changed = filevec[1-f].changed_flag;
|
||||
int const *equivs = filevec[f].equivs;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int i_end = filevec[f].buffered_lines;
|
||||
int preceding = -1;
|
||||
int other_preceding = -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int start, other_start;
|
||||
int runlength, start, corresponding;
|
||||
|
||||
/* Scan forwards to find beginning of another run of changes.
|
||||
Also keep track of the corresponding point in the other file. */
|
||||
@ -551,9 +646,7 @@ shift_boundaries (filevec)
|
||||
while (i < i_end && changed[i] == 0)
|
||||
{
|
||||
while (other_changed[j++])
|
||||
/* Non-corresponding lines in the other file
|
||||
will count as the preceding batch of changes. */
|
||||
other_preceding = j;
|
||||
continue;
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -561,42 +654,67 @@ shift_boundaries (filevec)
|
||||
break;
|
||||
|
||||
start = i;
|
||||
other_start = j;
|
||||
|
||||
while (1)
|
||||
/* Find the end of this run of changes. */
|
||||
|
||||
while (changed[++i])
|
||||
continue;
|
||||
while (other_changed[j])
|
||||
j++;
|
||||
|
||||
do
|
||||
{
|
||||
/* Now find the end of this run of changes. */
|
||||
/* Record the length of this run of changes, so that
|
||||
we can later determine whether the run has grown. */
|
||||
runlength = i - start;
|
||||
|
||||
while (changed[++i] != 0)
|
||||
;
|
||||
/* Move the changed region back, so long as the
|
||||
previous unchanged line matches the last changed one.
|
||||
This merges with previous changed regions. */
|
||||
|
||||
/* If the first changed line matches the following unchanged one,
|
||||
and this run does not follow right after a previous run,
|
||||
and there are no lines deleted from the other file here,
|
||||
then classify the first changed line as unchanged
|
||||
and the following line as changed in its place. */
|
||||
while (start && equivs[start - 1] == equivs[i - 1])
|
||||
{
|
||||
changed[--start] = 1;
|
||||
changed[--i] = 0;
|
||||
while (changed[start - 1])
|
||||
start--;
|
||||
while (other_changed[--j])
|
||||
continue;
|
||||
}
|
||||
|
||||
/* You might ask, how could this run follow right after another?
|
||||
Only because the previous run was shifted here. */
|
||||
/* Set CORRESPONDING to the end of the changed run, at the last
|
||||
point where it corresponds to a changed run in the other file.
|
||||
CORRESPONDING == I_END means no such point has been found. */
|
||||
corresponding = other_changed[j - 1] ? i : i_end;
|
||||
|
||||
if (i != i_end
|
||||
&& files[f].equivs[start] == files[f].equivs[i]
|
||||
&& !other_changed[j]
|
||||
&& !(start == preceding || other_start == other_preceding))
|
||||
/* Move the changed region forward, so long as the
|
||||
first changed line matches the following unchanged one.
|
||||
This merges with following changed regions.
|
||||
Do this second, so that if there are no merges,
|
||||
the changed region is moved forward as far as possible. */
|
||||
|
||||
while (i != i_end && equivs[start] == equivs[i])
|
||||
{
|
||||
changed[start++] = 0;
|
||||
changed[i] = 1;
|
||||
/* Since one line-that-matches is now before this run
|
||||
instead of after, we must advance in the other file
|
||||
to keep in synch. */
|
||||
++j;
|
||||
changed[i++] = 1;
|
||||
while (changed[i])
|
||||
i++;
|
||||
while (other_changed[++j])
|
||||
corresponding = i;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (runlength != i - start);
|
||||
|
||||
preceding = i;
|
||||
other_preceding = j;
|
||||
/* If possible, move the fully-merged run of changes
|
||||
back to a corresponding run in the other file. */
|
||||
|
||||
while (corresponding < i)
|
||||
{
|
||||
changed[--start] = 1;
|
||||
changed[--i] = 0;
|
||||
while (other_changed[--j])
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -629,7 +747,7 @@ add_change (line0, line1, deleted, inserted, old)
|
||||
|
||||
static struct change *
|
||||
build_reverse_script (filevec)
|
||||
struct file_data filevec[];
|
||||
struct file_data const filevec[];
|
||||
{
|
||||
struct change *script = 0;
|
||||
char *changed0 = filevec[0].changed_flag;
|
||||
@ -667,7 +785,7 @@ build_reverse_script (filevec)
|
||||
|
||||
static struct change *
|
||||
build_script (filevec)
|
||||
struct file_data filevec[];
|
||||
struct file_data const filevec[];
|
||||
{
|
||||
struct change *script = 0;
|
||||
char *changed0 = filevec[0].changed_flag;
|
||||
@ -697,6 +815,18 @@ build_script (filevec)
|
||||
return script;
|
||||
}
|
||||
|
||||
/* If CHANGES, briefly report that two files differed. */
|
||||
static void
|
||||
briefly_report (changes, filevec)
|
||||
int changes;
|
||||
struct file_data const filevec[];
|
||||
{
|
||||
if (changes)
|
||||
message (no_details_flag ? "Files %s and %s differ\n"
|
||||
: "Binary files %s and %s differ\n",
|
||||
filevec[0].name, filevec[1].name);
|
||||
}
|
||||
|
||||
/* Report the differences of two files. DEPTH is the current directory
|
||||
depth. */
|
||||
int
|
||||
@ -714,9 +844,10 @@ diff_2_files (filevec, depth)
|
||||
/* If we have detected that either file is binary,
|
||||
compare the two files as binary. This can happen
|
||||
only when the first chunk is read.
|
||||
Also, -q means treat all files as binary. */
|
||||
Also, --brief without any --ignore-* options means
|
||||
we can speed things up by treating the files as binary. */
|
||||
|
||||
if (read_files (filevec))
|
||||
if (read_files (filevec, no_details_flag & ~ignore_some_changes))
|
||||
{
|
||||
/* Files with different lengths must be different. */
|
||||
if (filevec[0].stat.st_size != filevec[1].stat.st_size
|
||||
@ -732,8 +863,8 @@ diff_2_files (filevec, depth)
|
||||
/* Scan both files, a buffer at a time, looking for a difference. */
|
||||
{
|
||||
/* Allocate same-sized buffers for both files. */
|
||||
int buffer_size = max (STAT_BLOCKSIZE (filevec[0].stat),
|
||||
STAT_BLOCKSIZE (filevec[1].stat));
|
||||
size_t buffer_size = buffer_lcm (STAT_BLOCKSIZE (filevec[0].stat),
|
||||
STAT_BLOCKSIZE (filevec[1].stat));
|
||||
for (i = 0; i < 2; i++)
|
||||
filevec[i].buffer = xrealloc (filevec[i].buffer, buffer_size);
|
||||
|
||||
@ -757,9 +888,10 @@ diff_2_files (filevec, depth)
|
||||
|
||||
/* If the buffers differ, the files differ. */
|
||||
if (filevec[0].buffered_chars != filevec[1].buffered_chars
|
||||
|| bcmp (filevec[0].buffer,
|
||||
filevec[1].buffer,
|
||||
filevec[0].buffered_chars) != 0)
|
||||
|| (filevec[0].buffered_chars != 0
|
||||
&& memcmp (filevec[0].buffer,
|
||||
filevec[1].buffer,
|
||||
filevec[0].buffered_chars) != 0))
|
||||
{
|
||||
changes = 1;
|
||||
break;
|
||||
@ -774,10 +906,7 @@ diff_2_files (filevec, depth)
|
||||
}
|
||||
}
|
||||
|
||||
if (changes)
|
||||
message (no_details_flag ? "Files %s and %s differ\n"
|
||||
: "Binary files %s and %s differ\n",
|
||||
filevec[0].name, filevec[1].name);
|
||||
briefly_report (changes, filevec);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -786,11 +915,9 @@ diff_2_files (filevec, depth)
|
||||
is an insertion or deletion.
|
||||
Allocate an extra element, always zero, at each end of each vector. */
|
||||
|
||||
filevec[0].changed_flag = (char *) xmalloc (filevec[0].buffered_lines
|
||||
+ filevec[1].buffered_lines
|
||||
+ 4);
|
||||
bzero (filevec[0].changed_flag, filevec[0].buffered_lines
|
||||
+ filevec[1].buffered_lines + 4);
|
||||
size_t s = filevec[0].buffered_lines + filevec[1].buffered_lines + 4;
|
||||
filevec[0].changed_flag = xmalloc (s);
|
||||
bzero (filevec[0].changed_flag, s);
|
||||
filevec[0].changed_flag++;
|
||||
filevec[1].changed_flag = filevec[0].changed_flag
|
||||
+ filevec[0].buffered_lines + 2;
|
||||
@ -812,11 +939,19 @@ diff_2_files (filevec, depth)
|
||||
fdiag += filevec[1].nondiscarded_lines + 1;
|
||||
bdiag += filevec[1].nondiscarded_lines + 1;
|
||||
|
||||
/* Set TOO_EXPENSIVE to be approximate square root of input size,
|
||||
bounded below by 256. */
|
||||
too_expensive = 1;
|
||||
for (i = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines;
|
||||
i != 0; i >>= 2)
|
||||
too_expensive <<= 1;
|
||||
too_expensive = max (256, too_expensive);
|
||||
|
||||
files[0] = filevec[0];
|
||||
files[1] = filevec[1];
|
||||
|
||||
compareseq (0, filevec[0].nondiscarded_lines,
|
||||
0, filevec[1].nondiscarded_lines);
|
||||
0, filevec[1].nondiscarded_lines, no_discards);
|
||||
|
||||
free (fdiag - (filevec[1].nondiscarded_lines + 1));
|
||||
|
||||
@ -833,50 +968,7 @@ diff_2_files (filevec, depth)
|
||||
else
|
||||
script = build_script (filevec);
|
||||
|
||||
if (script || ! no_diff_means_no_output)
|
||||
{
|
||||
/* Record info for starting up output,
|
||||
to be used if and when we have some output to print. */
|
||||
setup_output (files[0].name, files[1].name, depth);
|
||||
|
||||
switch (output_style)
|
||||
{
|
||||
case OUTPUT_CONTEXT:
|
||||
print_context_script (script, 0);
|
||||
break;
|
||||
|
||||
case OUTPUT_UNIFIED:
|
||||
print_context_script (script, 1);
|
||||
break;
|
||||
|
||||
case OUTPUT_ED:
|
||||
print_ed_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_FORWARD_ED:
|
||||
pr_forward_ed_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_RCS:
|
||||
print_rcs_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_NORMAL:
|
||||
print_normal_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_IFDEF:
|
||||
print_ifdef_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_SDIFF:
|
||||
print_sdiff_script (script);
|
||||
}
|
||||
|
||||
finish_output ();
|
||||
}
|
||||
|
||||
/* Set CHANGES if we had any diffs that were printed.
|
||||
/* Set CHANGES if we had any diffs.
|
||||
If some changes are ignored, we must scan the script to decide. */
|
||||
if (ignore_blank_lines_flag || ignore_regexp_list)
|
||||
{
|
||||
@ -895,9 +987,9 @@ diff_2_files (filevec, depth)
|
||||
/* Disconnect them from the rest of the changes, making them
|
||||
a hunk, and remember the rest for next iteration. */
|
||||
next = end->link;
|
||||
end->link = NULL;
|
||||
end->link = 0;
|
||||
|
||||
/* Determine whether this hunk was printed. */
|
||||
/* Determine whether this hunk is really a difference. */
|
||||
analyze_hunk (this, &first0, &last0, &first1, &last1,
|
||||
&deletes, &inserts);
|
||||
|
||||
@ -911,6 +1003,54 @@ diff_2_files (filevec, depth)
|
||||
else
|
||||
changes = (script != 0);
|
||||
|
||||
if (no_details_flag)
|
||||
briefly_report (changes, filevec);
|
||||
else
|
||||
{
|
||||
if (changes || ! no_diff_means_no_output)
|
||||
{
|
||||
/* Record info for starting up output,
|
||||
to be used if and when we have some output to print. */
|
||||
setup_output (files[0].name, files[1].name, depth);
|
||||
|
||||
switch (output_style)
|
||||
{
|
||||
case OUTPUT_CONTEXT:
|
||||
print_context_script (script, 0);
|
||||
break;
|
||||
|
||||
case OUTPUT_UNIFIED:
|
||||
print_context_script (script, 1);
|
||||
break;
|
||||
|
||||
case OUTPUT_ED:
|
||||
print_ed_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_FORWARD_ED:
|
||||
pr_forward_ed_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_RCS:
|
||||
print_rcs_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_NORMAL:
|
||||
print_normal_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_IFDEF:
|
||||
print_ifdef_script (script);
|
||||
break;
|
||||
|
||||
case OUTPUT_SDIFF:
|
||||
print_sdiff_script (script);
|
||||
}
|
||||
|
||||
finish_output ();
|
||||
}
|
||||
}
|
||||
|
||||
free (filevec[0].undiscarded);
|
||||
|
||||
free (filevec[0].changed_flag - 1);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Context-format output routines for GNU DIFF.
|
||||
Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -19,11 +19,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
static void pr_context_hunk ();
|
||||
static void pr_unidiff_hunk ();
|
||||
static struct change *find_hunk ();
|
||||
static void mark_ignorable ();
|
||||
static void find_function ();
|
||||
static struct change *find_hunk PARAMS((struct change *));
|
||||
static void find_function PARAMS((struct file_data const *, int, char const **, size_t *));
|
||||
static void mark_ignorable PARAMS((struct change *));
|
||||
static void pr_context_hunk PARAMS((struct change *));
|
||||
static void pr_unidiff_hunk PARAMS((struct change *));
|
||||
static void print_context_label PARAMS ((char const *, struct file_data *, char const *));
|
||||
static void print_context_number_range PARAMS((struct file_data const *, int, int));
|
||||
static void print_unidiff_number_range PARAMS((struct file_data const *, int, int));
|
||||
|
||||
/* Last place find_function started searching from. */
|
||||
static int find_function_last_search;
|
||||
@ -35,24 +38,23 @@ static int find_function_last_match;
|
||||
|
||||
static void
|
||||
print_context_label (mark, inf, label)
|
||||
const char *mark;
|
||||
char const *mark;
|
||||
struct file_data *inf;
|
||||
const char *label;
|
||||
char const *label;
|
||||
{
|
||||
if (label)
|
||||
fprintf (outfile, "%s %s\n", mark, label);
|
||||
else if (inf->stat.st_mtime)
|
||||
fprintf (outfile, "%s %s\t%s", mark, inf->name, ctime(&inf->stat.st_mtime));
|
||||
else
|
||||
/* Don't pretend that standard input is ancient. */
|
||||
fprintf (outfile, "%s %s\n", mark, inf->name);
|
||||
/* See Posix.2 section 4.17.6.1.4 for this format. */
|
||||
fprintf (outfile, "%s %s\t%s",
|
||||
mark, inf->name, ctime (&inf->stat.st_mtime));
|
||||
}
|
||||
|
||||
/* Print a header for a context diff, with the file names and dates. */
|
||||
|
||||
void
|
||||
print_context_header (inf, unidiff_flag)
|
||||
struct file_data *inf;
|
||||
struct file_data inf[];
|
||||
int unidiff_flag;
|
||||
{
|
||||
if (unidiff_flag)
|
||||
@ -100,7 +102,7 @@ print_context_script (script, unidiff_flag)
|
||||
|
||||
static void
|
||||
print_context_number_range (file, a, b)
|
||||
struct file_data *file;
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
{
|
||||
int trans_a, trans_b;
|
||||
@ -128,9 +130,9 @@ pr_context_hunk (hunk)
|
||||
{
|
||||
int first0, last0, first1, last1, show_from, show_to, i;
|
||||
struct change *next;
|
||||
char *prefix;
|
||||
const char *function;
|
||||
int function_length;
|
||||
char const *prefix;
|
||||
char const *function;
|
||||
size_t function_length;
|
||||
FILE *out;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
@ -234,7 +236,7 @@ pr_context_hunk (hunk)
|
||||
|
||||
static void
|
||||
print_unidiff_number_range (file, a, b)
|
||||
struct file_data *file;
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
{
|
||||
int trans_a, trans_b;
|
||||
@ -262,8 +264,8 @@ pr_unidiff_hunk (hunk)
|
||||
{
|
||||
int first0, last0, first1, last1, show_from, show_to, i, j, k;
|
||||
struct change *next;
|
||||
char *function;
|
||||
int function_length;
|
||||
char const *function;
|
||||
size_t function_length;
|
||||
FILE *out;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
@ -317,7 +319,7 @@ pr_unidiff_hunk (hunk)
|
||||
if (!next || i < next->line0)
|
||||
{
|
||||
putc (tab_align_flag ? '\t' : ' ', out);
|
||||
print_1_line ((char *)0, &files[0].linbuf[i++]);
|
||||
print_1_line (0, &files[0].linbuf[i++]);
|
||||
j++;
|
||||
}
|
||||
else
|
||||
@ -330,7 +332,7 @@ pr_unidiff_hunk (hunk)
|
||||
putc ('-', out);
|
||||
if (tab_align_flag)
|
||||
putc ('\t', out);
|
||||
print_1_line ((char *)0, &files[0].linbuf[i++]);
|
||||
print_1_line (0, &files[0].linbuf[i++]);
|
||||
}
|
||||
|
||||
/* Then output the inserted part. */
|
||||
@ -341,7 +343,7 @@ pr_unidiff_hunk (hunk)
|
||||
putc ('+', out);
|
||||
if (tab_align_flag)
|
||||
putc ('\t', out);
|
||||
print_1_line ((char *)0, &files[1].linbuf[j++]);
|
||||
print_1_line (0, &files[1].linbuf[j++]);
|
||||
}
|
||||
|
||||
/* We're done with this hunk, so on to the next! */
|
||||
@ -424,10 +426,10 @@ mark_ignorable (script)
|
||||
|
||||
static void
|
||||
find_function (file, linenum, linep, lenp)
|
||||
struct file_data *file;
|
||||
struct file_data const *file;
|
||||
int linenum;
|
||||
const char **linep;
|
||||
int *lenp;
|
||||
char const **linep;
|
||||
size_t *lenp;
|
||||
{
|
||||
int i = linenum;
|
||||
int last = find_function_last_search;
|
||||
@ -437,8 +439,8 @@ find_function (file, linenum, linep, lenp)
|
||||
{
|
||||
/* See if this line is what we want. */
|
||||
struct regexp_list *r;
|
||||
const char *line = file->linbuf[i];
|
||||
int len = file->linbuf[i + 1] - line;
|
||||
char const *line = file->linbuf[i];
|
||||
size_t len = file->linbuf[i + 1] - line;
|
||||
|
||||
for (r = function_regexp_list; r; r = r->next)
|
||||
if (0 <= re_search (&r->buf, line, len, 0, len, 0))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* GNU DIFF main routine.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -33,14 +33,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#define GUTTER_WIDTH_MINIMUM 3
|
||||
#endif
|
||||
|
||||
int diff_dirs ();
|
||||
int diff_2_files ();
|
||||
|
||||
static int compare_files ();
|
||||
static int specify_format ();
|
||||
static void add_regexp();
|
||||
static void specify_style ();
|
||||
static void usage ();
|
||||
static char const *filetype PARAMS((struct stat const *));
|
||||
static char *option_list PARAMS((char **, int));
|
||||
static int add_exclude_file PARAMS((char const *));
|
||||
static int ck_atoi PARAMS((char const *, int *));
|
||||
static int compare_files PARAMS((char const *, char const *, char const *, char const *, int));
|
||||
static int specify_format PARAMS((char **, char *));
|
||||
static void add_exclude PARAMS((char const *));
|
||||
static void add_regexp PARAMS((struct regexp_list **, char const *));
|
||||
static void specify_style PARAMS((enum output_style));
|
||||
static void usage PARAMS((char const *));
|
||||
|
||||
/* Nonzero for -r: if comparing two directories,
|
||||
compare their common subdirectories recursively. */
|
||||
@ -65,13 +67,13 @@ option_list (optionvec, count)
|
||||
int count;
|
||||
{
|
||||
int i;
|
||||
int length = 0;
|
||||
size_t length = 0;
|
||||
char *result;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
length += strlen (optionvec[i]) + 1;
|
||||
|
||||
result = (char *) xmalloc (length + 1);
|
||||
result = xmalloc (length + 1);
|
||||
result[0] = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
@ -83,14 +85,14 @@ option_list (optionvec, count)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Convert STR to a positive integer, storing the result in *OUT.
|
||||
/* Convert STR to a positive integer, storing the result in *OUT.
|
||||
If STR is not a valid integer, return -1 (otherwise 0). */
|
||||
static int
|
||||
ck_atoi (str, out)
|
||||
char *str;
|
||||
char const *str;
|
||||
int *out;
|
||||
{
|
||||
char *p;
|
||||
char const *p;
|
||||
for (p = str; *p; p++)
|
||||
if (*p < '0' || *p > '9')
|
||||
return -1;
|
||||
@ -101,12 +103,12 @@ ck_atoi (str, out)
|
||||
|
||||
/* Keep track of excluded file name patterns. */
|
||||
|
||||
static const char **exclude;
|
||||
static char const **exclude;
|
||||
static int exclude_alloc, exclude_count;
|
||||
|
||||
int
|
||||
excluded_filename (f)
|
||||
const char *f;
|
||||
char const *f;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < exclude_count; i++)
|
||||
@ -117,10 +119,10 @@ excluded_filename (f)
|
||||
|
||||
static void
|
||||
add_exclude (pattern)
|
||||
const char *pattern;
|
||||
char const *pattern;
|
||||
{
|
||||
if (exclude_alloc <= exclude_count)
|
||||
exclude = (const char **)
|
||||
exclude = (char const **)
|
||||
(exclude_alloc == 0
|
||||
? xmalloc ((exclude_alloc = 64) * sizeof (*exclude))
|
||||
: xrealloc (exclude, (exclude_alloc *= 2) * sizeof (*exclude)));
|
||||
@ -130,13 +132,15 @@ add_exclude (pattern)
|
||||
|
||||
static int
|
||||
add_exclude_file (name)
|
||||
const char *name;
|
||||
char const *name;
|
||||
{
|
||||
struct file_data f;
|
||||
char *p, *q, *lim;
|
||||
|
||||
f.name = optarg;
|
||||
f.desc = strcmp (optarg, "-") == 0 ? 0 : open (optarg, O_RDONLY, 0);
|
||||
f.desc = (strcmp (optarg, "-") == 0
|
||||
? STDIN_FILENO
|
||||
: open (optarg, O_RDONLY, 0));
|
||||
if (f.desc < 0 || fstat (f.desc, &f.stat) != 0)
|
||||
return -1;
|
||||
|
||||
@ -145,7 +149,7 @@ add_exclude_file (name)
|
||||
|
||||
for (p = f.buffer, lim = p + f.buffered_chars; p < lim; p = q)
|
||||
{
|
||||
q = memchr (p, '\n', lim - p);
|
||||
q = (char *) memchr (p, '\n', lim - p);
|
||||
if (!q)
|
||||
q = lim;
|
||||
*q++ = 0;
|
||||
@ -158,7 +162,7 @@ add_exclude_file (name)
|
||||
/* The numbers 129- that appear in the fourth element of some entries
|
||||
tell the big switch in `main' how to process those options. */
|
||||
|
||||
static struct option longopts[] =
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"ignore-blank-lines", 0, 0, 'B'},
|
||||
{"context", 2, 0, 'C'},
|
||||
@ -202,11 +206,13 @@ static struct option longopts[] =
|
||||
{"old-line-format", 1, 0, 132},
|
||||
{"new-line-format", 1, 0, 133},
|
||||
{"unchanged-line-format", 1, 0, 134},
|
||||
{"old-group-format", 1, 0, 135},
|
||||
{"new-group-format", 1, 0, 136},
|
||||
{"unchanged-group-format", 1, 0, 137},
|
||||
{"changed-group-format", 1, 0, 138},
|
||||
{"horizon-lines", 1, 0, 139},
|
||||
{"line-format", 1, 0, 135},
|
||||
{"old-group-format", 1, 0, 136},
|
||||
{"new-group-format", 1, 0, 137},
|
||||
{"unchanged-group-format", 1, 0, 138},
|
||||
{"changed-group-format", 1, 0, 139},
|
||||
{"horizon-lines", 1, 0, 140},
|
||||
{"help", 0, 0, 141},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@ -218,42 +224,19 @@ main (argc, argv)
|
||||
int val;
|
||||
int c;
|
||||
int prev = -1;
|
||||
extern char *version_string;
|
||||
int width = DEFAULT_WIDTH;
|
||||
|
||||
/* Do our initializations. */
|
||||
program = argv[0];
|
||||
|
||||
/* Do our initializations. */
|
||||
output_style = OUTPUT_NORMAL;
|
||||
always_text_flag = FALSE;
|
||||
ignore_space_change_flag = FALSE;
|
||||
ignore_all_space_flag = FALSE;
|
||||
length_varies = FALSE;
|
||||
ignore_case_flag = FALSE;
|
||||
ignore_blank_lines_flag = FALSE;
|
||||
ignore_regexp_list = NULL;
|
||||
function_regexp_list = NULL;
|
||||
print_file_same_flag = FALSE;
|
||||
entire_new_file_flag = FALSE;
|
||||
unidirectional_new_file_flag = FALSE;
|
||||
no_details_flag = FALSE;
|
||||
context = -1;
|
||||
line_end_char = '\n';
|
||||
tab_align_flag = FALSE;
|
||||
tab_expand_flag = FALSE;
|
||||
recursive = FALSE;
|
||||
paginate_flag = FALSE;
|
||||
heuristic = FALSE;
|
||||
dir_start_file = NULL;
|
||||
msg_chain = NULL;
|
||||
msg_chain_end = NULL;
|
||||
no_discards = 0;
|
||||
|
||||
/* Decode the options. */
|
||||
|
||||
while ((c = getopt_long (argc, argv,
|
||||
"0123456789abBcC:dD:efF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y",
|
||||
longopts, (int *)0)) != EOF)
|
||||
longopts, 0)) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -285,14 +268,16 @@ main (argc, argv)
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
/* Ignore changes in amount of whitespace. */
|
||||
/* Ignore changes in amount of white space. */
|
||||
ignore_space_change_flag = 1;
|
||||
length_varies = 1;
|
||||
ignore_some_changes = 1;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
/* Ignore changes affecting only blank lines. */
|
||||
ignore_blank_lines_flag = 1;
|
||||
ignore_some_changes = 1;
|
||||
break;
|
||||
|
||||
case 'C': /* +context[=lines] */
|
||||
@ -323,7 +308,7 @@ main (argc, argv)
|
||||
specify_style (OUTPUT_IFDEF);
|
||||
{
|
||||
int i, err = 0;
|
||||
static const char C_ifdef_group_formats[] =
|
||||
static char const C_ifdef_group_formats[] =
|
||||
"#ifndef %s\n%%<#endif /* not %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c%%=%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n";
|
||||
char *b = xmalloc (sizeof (C_ifdef_group_formats)
|
||||
+ 7 * strlen(optarg) - 14 /* 7*"%s" */
|
||||
@ -376,12 +361,14 @@ main (argc, argv)
|
||||
case 'i':
|
||||
/* Ignore changes in case. */
|
||||
ignore_case_flag = 1;
|
||||
ignore_some_changes = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
/* Ignore changes affecting only lines that match the
|
||||
specified regexp. */
|
||||
add_regexp (&ignore_regexp_list, optarg);
|
||||
ignore_some_changes = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
@ -398,7 +385,7 @@ main (argc, argv)
|
||||
else
|
||||
fatal ("too many file label options");
|
||||
break;
|
||||
|
||||
|
||||
case 'n':
|
||||
/* Output RCS-style diffs, like `-f' except that each command
|
||||
specifies the number of lines affected. */
|
||||
@ -429,7 +416,7 @@ main (argc, argv)
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
/* When comparing directories,
|
||||
/* When comparing directories,
|
||||
recursively compare any subdirectories found. */
|
||||
recursive = 1;
|
||||
break;
|
||||
@ -464,12 +451,13 @@ main (argc, argv)
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
fprintf (stderr, "GNU diff version %s\n", version_string);
|
||||
break;
|
||||
printf ("GNU diff version %s\n", version_string);
|
||||
exit (0);
|
||||
|
||||
case 'w':
|
||||
/* Ignore horizontal whitespace when comparing lines. */
|
||||
/* Ignore horizontal white space when comparing lines. */
|
||||
ignore_all_space_flag = 1;
|
||||
ignore_some_changes = 1;
|
||||
length_varies = 1;
|
||||
break;
|
||||
|
||||
@ -492,15 +480,15 @@ main (argc, argv)
|
||||
if (ck_atoi (optarg, &width) || width <= 0)
|
||||
fatal ("column width must be a positive integer");
|
||||
break;
|
||||
|
||||
|
||||
case 129:
|
||||
sdiff_left_only = 1;
|
||||
break;
|
||||
|
||||
|
||||
case 130:
|
||||
sdiff_skip_common_lines = 1;
|
||||
break;
|
||||
|
||||
|
||||
case 131:
|
||||
/* sdiff-style columns output. */
|
||||
specify_style (OUTPUT_SDIFF);
|
||||
@ -511,40 +499,46 @@ main (argc, argv)
|
||||
case 133:
|
||||
case 134:
|
||||
specify_style (OUTPUT_IFDEF);
|
||||
{
|
||||
const char **form = &line_format[c - 132];
|
||||
if (*form && strcmp (*form, optarg) != 0)
|
||||
error ("conflicting line format", 0, 0);
|
||||
*form = optarg;
|
||||
}
|
||||
if (specify_format (&line_format[c - 132], optarg) != 0)
|
||||
error ("conflicting line format", 0, 0);
|
||||
break;
|
||||
|
||||
case 135:
|
||||
case 136:
|
||||
case 137:
|
||||
case 138:
|
||||
specify_style (OUTPUT_IFDEF);
|
||||
{
|
||||
const char **form = &group_format[c - 135];
|
||||
if (*form && strcmp (*form, optarg) != 0)
|
||||
error ("conflicting group format", 0, 0);
|
||||
*form = optarg;
|
||||
int i, err = 0;
|
||||
for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++)
|
||||
err |= specify_format (&line_format[i], optarg);
|
||||
if (err)
|
||||
error ("conflicting line format", 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 136:
|
||||
case 137:
|
||||
case 138:
|
||||
case 139:
|
||||
specify_style (OUTPUT_IFDEF);
|
||||
if (specify_format (&group_format[c - 136], optarg) != 0)
|
||||
error ("conflicting group format", 0, 0);
|
||||
break;
|
||||
|
||||
case 140:
|
||||
if (ck_atoi (optarg, &horizon_lines) || horizon_lines < 0)
|
||||
fatal ("horizon must be a nonnegative integer");
|
||||
break;
|
||||
|
||||
case 141:
|
||||
usage (0);
|
||||
|
||||
default:
|
||||
usage ();
|
||||
usage ("");
|
||||
}
|
||||
prev = c;
|
||||
}
|
||||
|
||||
if (optind != argc - 2)
|
||||
usage ();
|
||||
usage (optind < argc - 2 ? "extra operand" : "missing operand");
|
||||
|
||||
|
||||
{
|
||||
@ -569,7 +563,7 @@ main (argc, argv)
|
||||
else if (context == -1)
|
||||
/* Default amount of context for -c. */
|
||||
context = 3;
|
||||
|
||||
|
||||
if (output_style == OUTPUT_IFDEF)
|
||||
{
|
||||
int i;
|
||||
@ -598,7 +592,7 @@ main (argc, argv)
|
||||
|
||||
switch_string = option_list (argv + 1, optind - 1);
|
||||
|
||||
val = compare_files (NULL, argv[optind], NULL, argv[optind + 1], 0);
|
||||
val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
|
||||
|
||||
/* Print any messages that were saved up for last. */
|
||||
print_message_queue ();
|
||||
@ -614,14 +608,14 @@ main (argc, argv)
|
||||
static void
|
||||
add_regexp (reglist, pattern)
|
||||
struct regexp_list **reglist;
|
||||
char *pattern;
|
||||
char const *pattern;
|
||||
{
|
||||
struct regexp_list *r;
|
||||
const char *m;
|
||||
char const *m;
|
||||
|
||||
r = (struct regexp_list *) xmalloc (sizeof (*r));
|
||||
bzero (r, sizeof (*r));
|
||||
r->buf.fastmap = (char *) xmalloc (256);
|
||||
r->buf.fastmap = xmalloc (256);
|
||||
m = re_compile_pattern (pattern, strlen (pattern), &r->buf);
|
||||
if (m != 0)
|
||||
error ("%s: %s", pattern, m);
|
||||
@ -632,37 +626,43 @@ add_regexp (reglist, pattern)
|
||||
}
|
||||
|
||||
static void
|
||||
usage ()
|
||||
usage (reason)
|
||||
char const *reason;
|
||||
{
|
||||
fprintf (stderr, "Usage: %s [options] from-file to-file\n", program);
|
||||
fprintf (stderr, "Options:\n\
|
||||
[-abBcdefhHilnNpPqrstTuvwy] [-C lines] [-D name] [-F regexp]\n\
|
||||
[-I regexp] [-L from-label [-L to-label]] [-S starting-file] [-U lines]\n\
|
||||
[-W columns] [-x pattern] [-X pattern-file] [--exclude=pattern]\n\
|
||||
[--exclude-from=pattern-file] [--ignore-blank-lines] [--context[=lines]]\n\
|
||||
[--ifdef=name] [--show-function-line=regexp] [--speed-large-files]\n\
|
||||
[--label=from-label [--label=to-label]] [--new-file]\n");
|
||||
fprintf (stderr, "\
|
||||
[--ignore-matching-lines=regexp] [--unidirectional-new-file]\n\
|
||||
[--starting-file=starting-file] [--initial-tab] [--width=columns]\n\
|
||||
[--text] [--ignore-space-change] [--minimal] [--ed] [--forward-ed]\n\
|
||||
[--ignore-case] [--paginate] [--rcs] [--show-c-function] [--brief]\n\
|
||||
[--recursive] [--report-identical-files] [--expand-tabs] [--version]\n");
|
||||
fprintf (stderr, "\
|
||||
[--ignore-all-space] [--side-by-side] [--unified[=lines]]\n\
|
||||
[--left-column] [--suppress-common-lines] [--sdiff-merge-assist]\n\
|
||||
[--old-line-format=format] [--new-line-format=format]\n\
|
||||
[--unchanged-line-format=format]\n\
|
||||
[--old-group-format=format] [--new-group-format=format]\n\
|
||||
[--unchanged-group-format=format] [--changed-group-format=format]\n\
|
||||
[--horizon-lines=lines]\n");
|
||||
exit (2);
|
||||
}
|
||||
if (reason && *reason)
|
||||
fprintf (stderr, "%s: %s\n", program, reason);
|
||||
fflush (stderr);
|
||||
printf ("Usage: %s [options] from-file to-file\n", program);
|
||||
printf ("Options:\n\
|
||||
[-abBcdefhHilnNpPqrstTuvwy] [-C lines] [-D name] [-F regexp]\n\
|
||||
[-I regexp] [-L from-label [-L to-label]] [-S starting-file] [-U lines]\n\
|
||||
[-W columns] [-x pattern] [-X pattern-file]\n");
|
||||
printf ("\
|
||||
[--brief] [--changed-group-format=format] [--context[=lines]] [--ed]\n\
|
||||
[--exclude=pattern] [--exclude-from=pattern-file] [--expand-tabs]\n\
|
||||
[--forward-ed] [--help] [--horizon-lines=lines] [--ifdef=name]\n\
|
||||
[--ignore-all-space] [--ignore-blank-lines] [--ignore-case]\n");
|
||||
printf ("\
|
||||
[--ignore-matching-lines=regexp] [--ignore-space-change]\n\
|
||||
[--initial-tab] [--label=from-label [--label=to-label]]\n\
|
||||
[--left-column] [--minimal] [--new-file] [--new-group-format=format]\n\
|
||||
[--new-line-format=format] [--old-group-format=format]\n");
|
||||
printf ("\
|
||||
[--old-line-format=format] [--paginate] [--rcs] [--recursive]\n\
|
||||
[--report-identical-files] [--sdiff-merge-assist] [--show-c-function]\n\
|
||||
[--show-function-line=regexp] [--side-by-side] [--speed-large-files]\n\
|
||||
[--starting-file=starting-file] [--suppress-common-lines] [--text]\n");
|
||||
printf ("\
|
||||
[--unchanged-group-format=format] [--unchanged-line-format=format]\n\
|
||||
[--unidirectional-new-file] [--unified[=lines]] [--version]\n\
|
||||
[--width=columns]\n");
|
||||
exit (reason ? 2 : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
specify_format (var, value)
|
||||
const char **var;
|
||||
const char *value;
|
||||
char **var;
|
||||
char *value;
|
||||
{
|
||||
int err = *var ? strcmp (*var, value) : 0;
|
||||
*var = value;
|
||||
@ -679,6 +679,46 @@ specify_style (style)
|
||||
output_style = style;
|
||||
}
|
||||
|
||||
static char const *
|
||||
filetype (st)
|
||||
struct stat const *st;
|
||||
{
|
||||
/* See Posix.2 section 4.17.6.1.1 and Table 5-1 for these formats.
|
||||
To keep diagnostics grammatical, the returned string must start
|
||||
with a consonant. */
|
||||
|
||||
if (S_ISREG (st->st_mode))
|
||||
{
|
||||
if (st->st_size == 0)
|
||||
return "regular empty file";
|
||||
/* Posix.2 section 5.14.2 seems to suggest that we must read the file
|
||||
and guess whether it's C, Fortran, etc., but this is somewhat useless
|
||||
and doesn't reflect historical practice. We're allowed to guess
|
||||
wrong, so we don't bother to read the file. */
|
||||
return "regular file";
|
||||
}
|
||||
if (S_ISDIR (st->st_mode)) return "directory";
|
||||
|
||||
/* other Posix.1 file types */
|
||||
#ifdef S_ISBLK
|
||||
if (S_ISBLK (st->st_mode)) return "block special file";
|
||||
#endif
|
||||
#ifdef S_ISCHR
|
||||
if (S_ISCHR (st->st_mode)) return "character special file";
|
||||
#endif
|
||||
#ifdef S_ISFIFO
|
||||
if (S_ISFIFO (st->st_mode)) return "fifo";
|
||||
#endif
|
||||
|
||||
/* other popular file types */
|
||||
/* S_ISLNK is impossible with `stat'. */
|
||||
#ifdef S_ISSOCK
|
||||
if (S_ISSOCK (st->st_mode)) return "socket";
|
||||
#endif
|
||||
|
||||
return "weird file";
|
||||
}
|
||||
|
||||
/* Compare two files (or dirs) with specified names
|
||||
DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
|
||||
(if DIR0 is 0, then the name is just NAME0, etc.)
|
||||
@ -689,15 +729,16 @@ specify_style (style)
|
||||
|
||||
static int
|
||||
compare_files (dir0, name0, dir1, name1, depth)
|
||||
char *dir0, *dir1;
|
||||
char *name0, *name1;
|
||||
char const *dir0, *dir1;
|
||||
char const *name0, *name1;
|
||||
int depth;
|
||||
{
|
||||
struct file_data inf[2];
|
||||
register int i;
|
||||
int val;
|
||||
int same_files;
|
||||
int errorcount = 0;
|
||||
int failed = 0;
|
||||
char *free0 = 0, *free1 = 0;
|
||||
|
||||
/* If this is directory comparison, perhaps we have a file
|
||||
that exists only in one of the directories.
|
||||
@ -707,15 +748,17 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
|| (unidirectional_new_file_flag && name1 != 0)
|
||||
|| entire_new_file_flag))
|
||||
{
|
||||
char *name = name0 == 0 ? name1 : name0;
|
||||
char *dir = name0 == 0 ? dir1 : dir0;
|
||||
char const *name = name0 == 0 ? name1 : name0;
|
||||
char const *dir = name0 == 0 ? dir1 : dir0;
|
||||
message ("Only in %s: %s\n", dir, name);
|
||||
/* Return 1 so that diff_dirs will return 1 ("some files differ"). */
|
||||
return 1;
|
||||
}
|
||||
|
||||
bzero (inf, sizeof (inf));
|
||||
|
||||
/* Mark any nonexistent file with -1 in the desc field. */
|
||||
/* Mark unopened files (i.e. directories) with -2. */
|
||||
/* Mark unopened files (e.g. directories) with -2. */
|
||||
|
||||
inf[0].desc = name0 == 0 ? -1 : -2;
|
||||
inf[1].desc = name1 == 0 ? -1 : -2;
|
||||
@ -727,25 +770,41 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
if (name1 == 0)
|
||||
name1 = name0;
|
||||
|
||||
inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
|
||||
inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
|
||||
inf[0].name = dir0 == 0 ? name0 : (free0 = dir_file_pathname (dir0, name0));
|
||||
inf[1].name = dir1 == 0 ? name1 : (free1 = dir_file_pathname (dir1, name1));
|
||||
|
||||
/* Stat the files. Record whether they are directories. */
|
||||
|
||||
for (i = 0; i <= 1; i++)
|
||||
{
|
||||
bzero (&inf[i].stat, sizeof (struct stat));
|
||||
inf[i].dir_p = 0;
|
||||
|
||||
if (inf[i].desc != -1)
|
||||
{
|
||||
int stat_result;
|
||||
|
||||
if (strcmp (inf[i].name, "-") == 0)
|
||||
if (i && strcmp (inf[i].name, inf[0].name) == 0)
|
||||
{
|
||||
inf[i].desc = 0;
|
||||
inf[i].name = "Standard Input";
|
||||
stat_result = fstat (0, &inf[i].stat);
|
||||
inf[i].stat = inf[0].stat;
|
||||
stat_result = 0;
|
||||
}
|
||||
else if (strcmp (inf[i].name, "-") == 0)
|
||||
{
|
||||
inf[i].desc = STDIN_FILENO;
|
||||
stat_result = fstat (STDIN_FILENO, &inf[i].stat);
|
||||
if (stat_result == 0 && S_ISREG (inf[i].stat.st_mode))
|
||||
{
|
||||
off_t pos = lseek (STDIN_FILENO, (off_t) 0, SEEK_CUR);
|
||||
if (pos == -1)
|
||||
stat_result = -1;
|
||||
else
|
||||
{
|
||||
if (pos <= inf[i].stat.st_size)
|
||||
inf[i].stat.st_size -= pos;
|
||||
else
|
||||
inf[i].stat.st_size = 0;
|
||||
/* Posix.2 4.17.6.1.4 requires current time for stdin. */
|
||||
time (&inf[i].stat.st_mtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
stat_result = stat (inf[i].name, &inf[i].stat);
|
||||
@ -753,42 +812,46 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
if (stat_result != 0)
|
||||
{
|
||||
perror_with_name (inf[i].name);
|
||||
errorcount = 1;
|
||||
failed = 1;
|
||||
}
|
||||
else
|
||||
inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0;
|
||||
{
|
||||
inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0;
|
||||
if (inf[1 - i].desc == -1)
|
||||
{
|
||||
inf[1 - i].dir_p = inf[i].dir_p;
|
||||
inf[1 - i].stat.st_mode = inf[i].stat.st_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name0 == 0)
|
||||
inf[0].dir_p = inf[1].dir_p;
|
||||
if (name1 == 0)
|
||||
inf[1].dir_p = inf[0].dir_p;
|
||||
|
||||
if (errorcount == 0 && depth == 0 && inf[0].dir_p != inf[1].dir_p)
|
||||
if (! failed && depth == 0 && inf[0].dir_p != inf[1].dir_p)
|
||||
{
|
||||
/* If one is a directory, and it was specified in the command line,
|
||||
use the file in that dir with the other file's basename. */
|
||||
|
||||
int fnm_arg = inf[0].dir_p;
|
||||
int dir_arg = 1 - fnm_arg;
|
||||
char *p = rindex (inf[fnm_arg].name, '/');
|
||||
char *filename = inf[dir_arg].name
|
||||
= concat (inf[dir_arg].name, "/", (p ? p+1 : inf[fnm_arg].name));
|
||||
char const *fnm = inf[fnm_arg].name;
|
||||
char const *dir = inf[dir_arg].name;
|
||||
char const *p = strrchr (fnm, '/');
|
||||
char const *filename = inf[dir_arg].name
|
||||
= dir_file_pathname (dir, p ? p + 1 : fnm);
|
||||
|
||||
if (inf[fnm_arg].desc == 0)
|
||||
if (strcmp (fnm, "-") == 0)
|
||||
fatal ("can't compare - to a directory");
|
||||
|
||||
if (stat (filename, &inf[dir_arg].stat) != 0)
|
||||
{
|
||||
perror_with_name (filename);
|
||||
errorcount = 1;
|
||||
failed = 1;
|
||||
}
|
||||
else
|
||||
inf[dir_arg].dir_p = S_ISDIR (inf[dir_arg].stat.st_mode);
|
||||
}
|
||||
|
||||
if (errorcount)
|
||||
if (failed)
|
||||
{
|
||||
|
||||
/* If either file should exist but does not, return 2. */
|
||||
@ -798,6 +861,7 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
}
|
||||
else if ((same_files = inf[0].stat.st_ino == inf[1].stat.st_ino
|
||||
&& inf[0].stat.st_dev == inf[1].stat.st_dev
|
||||
&& inf[0].stat.st_size == inf[1].stat.st_size
|
||||
&& inf[0].desc != -1
|
||||
&& inf[1].desc != -1)
|
||||
&& no_diff_means_no_output)
|
||||
@ -828,37 +892,43 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
}
|
||||
|
||||
}
|
||||
else if (inf[0].dir_p | inf[1].dir_p)
|
||||
else if ((inf[0].dir_p | inf[1].dir_p)
|
||||
|| (depth > 0
|
||||
&& (! S_ISREG (inf[0].stat.st_mode)
|
||||
|| ! S_ISREG (inf[1].stat.st_mode))))
|
||||
{
|
||||
/* Perhaps we have a subdirectory that exists only in one directory.
|
||||
If so, just print a message to that effect. */
|
||||
|
||||
if (inf[0].desc == -1 || inf[1].desc == -1)
|
||||
{
|
||||
if (recursive
|
||||
if ((inf[0].dir_p | inf[1].dir_p)
|
||||
&& recursive
|
||||
&& (entire_new_file_flag
|
||||
|| (unidirectional_new_file_flag && inf[0].desc == -1)))
|
||||
val = diff_dirs (inf, compare_files, depth);
|
||||
else
|
||||
{
|
||||
char *dir = (inf[0].desc == -1) ? dir1 : dir0;
|
||||
char const *dir = (inf[0].desc == -1) ? dir1 : dir0;
|
||||
/* See Posix.2 section 4.17.6.1.1 for this format. */
|
||||
message ("Only in %s: %s\n", dir, name0);
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have a subdirectory in one directory
|
||||
and a file in the other. */
|
||||
/* We have two files that are not to be compared. */
|
||||
|
||||
message ("%s is a directory but %s is not\n",
|
||||
inf[1 - inf[0].dir_p].name, inf[inf[0].dir_p].name);
|
||||
/* See Posix.2 section 4.17.6.1.1 for this format. */
|
||||
message5 ("File %s is a %s while file %s is a %s\n",
|
||||
inf[0].name, filetype (&inf[0].stat),
|
||||
inf[1].name, filetype (&inf[1].stat));
|
||||
|
||||
/* This is a difference. */
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
else if (no_details_flag
|
||||
else if ((no_details_flag & ~ignore_some_changes)
|
||||
&& inf[0].stat.st_size != inf[1].stat.st_size
|
||||
&& (inf[0].desc == -1 || S_ISREG (inf[0].stat.st_mode))
|
||||
&& (inf[1].desc == -1 || S_ISREG (inf[1].stat.st_mode)))
|
||||
@ -876,7 +946,7 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
if ((inf[0].desc = open (inf[0].name, O_RDONLY, 0)) < 0)
|
||||
{
|
||||
perror_with_name (inf[0].name);
|
||||
errorcount = 1;
|
||||
failed = 1;
|
||||
}
|
||||
if (inf[1].desc == -2)
|
||||
if (same_files)
|
||||
@ -884,12 +954,12 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
else if ((inf[1].desc = open (inf[1].name, O_RDONLY, 0)) < 0)
|
||||
{
|
||||
perror_with_name (inf[1].name);
|
||||
errorcount = 1;
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Compare the files, if no error was found. */
|
||||
|
||||
val = errorcount ? 2 : diff_2_files (inf, depth);
|
||||
val = failed ? 2 : diff_2_files (inf, depth);
|
||||
|
||||
/* Close the file descriptors. */
|
||||
|
||||
@ -918,10 +988,10 @@ compare_files (dir0, name0, dir1, name1, depth)
|
||||
else
|
||||
fflush (stdout);
|
||||
|
||||
if (dir0 != 0)
|
||||
free (inf[0].name);
|
||||
if (dir1 != 0)
|
||||
free (inf[1].name);
|
||||
if (free0)
|
||||
free (free0);
|
||||
if (free1)
|
||||
free (free1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Shared definitions for GNU DIFF
|
||||
Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -17,22 +17,15 @@ You should have received a copy of the GNU General Public License
|
||||
along with GNU DIFF; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "system.h"
|
||||
#include "regex.h"
|
||||
|
||||
#ifndef PR_FILE_NAME
|
||||
#define PR_FILE_NAME "/bin/pr"
|
||||
#endif
|
||||
|
||||
/* Character classes. */
|
||||
extern const char textchar[];
|
||||
|
||||
/* Is_space is a little broader than ctype.h's isspace,
|
||||
because it also includes backspace and no-break space. */
|
||||
#define Is_space(c) (textchar[c] & 2)
|
||||
|
||||
#define TAB_WIDTH 8
|
||||
|
||||
/* Variables for command line options */
|
||||
@ -82,10 +75,10 @@ EXTERN int always_text_flag;
|
||||
/* Number of lines to keep in identical prefix and suffix. */
|
||||
EXTERN int horizon_lines;
|
||||
|
||||
/* Ignore changes in horizontal whitespace (-b). */
|
||||
/* Ignore changes in horizontal white space (-b). */
|
||||
EXTERN int ignore_space_change_flag;
|
||||
|
||||
/* Ignore all horizontal whitespace (-w). */
|
||||
/* Ignore all horizontal white space (-w). */
|
||||
EXTERN int ignore_all_space_flag;
|
||||
|
||||
/* Ignore changes that affect only blank lines (-B). */
|
||||
@ -95,6 +88,10 @@ EXTERN int ignore_blank_lines_flag;
|
||||
This depends on various options. */
|
||||
EXTERN int length_varies;
|
||||
|
||||
/* 1 if files may match even if their contents are not byte-for-byte identical.
|
||||
This depends on various options. */
|
||||
EXTERN int ignore_some_changes;
|
||||
|
||||
/* Ignore differences in case of letters (-i). */
|
||||
EXTERN int ignore_case_flag;
|
||||
|
||||
@ -160,13 +157,13 @@ enum line_class {
|
||||
};
|
||||
|
||||
/* Line group formats for old, new, unchanged, and changed groups. */
|
||||
EXTERN const char *group_format[CHANGED + 1];
|
||||
EXTERN char *group_format[CHANGED + 1];
|
||||
|
||||
/* Line formats for old, new, and unchanged lines. */
|
||||
EXTERN const char *line_format[UNCHANGED + 1];
|
||||
EXTERN char *line_format[UNCHANGED + 1];
|
||||
|
||||
/* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */
|
||||
EXTERN int sdiff_help_sdiff;
|
||||
EXTERN int sdiff_help_sdiff;
|
||||
|
||||
/* Tell OUTPUT_SDIFF to show only the left version of common lines. */
|
||||
EXTERN int sdiff_left_only;
|
||||
@ -192,7 +189,7 @@ EXTERN char * program;
|
||||
/* The result of comparison is an "edit script": a chain of `struct change'.
|
||||
Each `struct change' represents one place where some lines are deleted
|
||||
and some are inserted.
|
||||
|
||||
|
||||
LINE0 and LINE1 are the first affected lines in the two files (origin 0).
|
||||
DELETED is the number of lines deleted here from file 0.
|
||||
INSERTED is the number of lines inserted here in file 1.
|
||||
@ -216,19 +213,19 @@ struct change
|
||||
|
||||
struct file_data {
|
||||
int desc; /* File descriptor */
|
||||
char *name; /* File name */
|
||||
char const *name; /* File name */
|
||||
struct stat stat; /* File status from fstat() */
|
||||
int dir_p; /* nonzero if file is a directory */
|
||||
|
||||
/* Buffer in which text of file is read. */
|
||||
char * buffer;
|
||||
/* Allocated size of buffer. */
|
||||
int bufsize;
|
||||
size_t bufsize;
|
||||
/* Number of valid characters now in the buffer. */
|
||||
int buffered_chars;
|
||||
size_t buffered_chars;
|
||||
|
||||
/* Array of pointers to lines in the file. */
|
||||
const char **linbuf;
|
||||
char const **linbuf;
|
||||
|
||||
/* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines.
|
||||
linebuf[linbuf_base ... buffered_lines - 1] are possibly differing.
|
||||
@ -237,14 +234,14 @@ struct file_data {
|
||||
int linbuf_base, buffered_lines, valid_lines, alloc_lines;
|
||||
|
||||
/* Pointer to end of prefix of this file to ignore when hashing. */
|
||||
const char *prefix_end;
|
||||
char const *prefix_end;
|
||||
|
||||
/* Count of lines in the prefix.
|
||||
There are this many lines in the file before linbuf[0]. */
|
||||
int prefix_lines;
|
||||
|
||||
/* Pointer to start of suffix of this file to ignore when hashing. */
|
||||
const char *suffix_begin;
|
||||
char const *suffix_begin;
|
||||
|
||||
/* Vector, indexed by line number, containing an equivalence code for
|
||||
each line. It is this vector that is actually compared with that
|
||||
@ -279,57 +276,73 @@ struct file_data {
|
||||
|
||||
EXTERN struct file_data files[2];
|
||||
|
||||
/* Queue up one-line messages to be printed at the end,
|
||||
when -l is specified. Each message is recorded with a `struct msg'. */
|
||||
|
||||
struct msg
|
||||
{
|
||||
struct msg *next;
|
||||
char *format;
|
||||
char *arg1;
|
||||
char *arg2;
|
||||
};
|
||||
|
||||
/* Head of the chain of queues messages. */
|
||||
|
||||
EXTERN struct msg *msg_chain;
|
||||
|
||||
/* Tail of the chain of queues messages. */
|
||||
|
||||
EXTERN struct msg *msg_chain_end;
|
||||
|
||||
/* Stdio stream to output diffs to. */
|
||||
|
||||
EXTERN FILE *outfile;
|
||||
|
||||
/* Declare various functions. */
|
||||
|
||||
#if __STDC__
|
||||
#define VOID void
|
||||
#else
|
||||
#define VOID char
|
||||
#endif
|
||||
VOID *xmalloc ();
|
||||
VOID *xrealloc ();
|
||||
char *concat ();
|
||||
/* analyze.c */
|
||||
int diff_2_files PARAMS((struct file_data[], int));
|
||||
|
||||
int excluded_filename ();
|
||||
int sip ();
|
||||
/* context.c */
|
||||
void print_context_header PARAMS((struct file_data[], int));
|
||||
void print_context_script PARAMS((struct change *, int));
|
||||
|
||||
struct change *find_change ();
|
||||
/* diff.c */
|
||||
int excluded_filename PARAMS((char const *));
|
||||
|
||||
void analyze_hunk ();
|
||||
void begin_output ();
|
||||
void error ();
|
||||
void fatal ();
|
||||
void message ();
|
||||
void output_1_line ();
|
||||
void perror_with_name ();
|
||||
void pfatal_with_name ();
|
||||
void print_1_line ();
|
||||
void print_context_header ();
|
||||
void print_message_queue ();
|
||||
void print_number_range ();
|
||||
void print_script ();
|
||||
void slurp ();
|
||||
void translate_range ();
|
||||
/* dir.c */
|
||||
int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int));
|
||||
|
||||
/* ed.c */
|
||||
void print_ed_script PARAMS((struct change *));
|
||||
void pr_forward_ed_script PARAMS((struct change *));
|
||||
|
||||
/* ifdef.c */
|
||||
void print_ifdef_script PARAMS((struct change *));
|
||||
|
||||
/* io.c */
|
||||
int read_files PARAMS((struct file_data[], int));
|
||||
int sip PARAMS((struct file_data *, int));
|
||||
void slurp PARAMS((struct file_data *));
|
||||
|
||||
/* normal.c */
|
||||
void print_normal_script PARAMS((struct change *));
|
||||
|
||||
/* rcs.c */
|
||||
void print_rcs_script PARAMS((struct change *));
|
||||
|
||||
/* side.c */
|
||||
void print_sdiff_script PARAMS((struct change *));
|
||||
|
||||
/* util.c */
|
||||
VOID *xmalloc PARAMS((size_t));
|
||||
VOID *xrealloc PARAMS((VOID *, size_t));
|
||||
char *concat PARAMS((char const *, char const *, char const *));
|
||||
char *dir_file_pathname PARAMS((char const *, char const *));
|
||||
int change_letter PARAMS((int, int));
|
||||
int line_cmp PARAMS((char const *, size_t, char const *, size_t));
|
||||
int translate_line_number PARAMS((struct file_data const *, int));
|
||||
struct change *find_change PARAMS((struct change *));
|
||||
struct change *find_reverse_change PARAMS((struct change *));
|
||||
void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *));
|
||||
void begin_output PARAMS((void));
|
||||
void debug_script PARAMS((struct change *));
|
||||
void error PARAMS((char const *, char const *, char const *));
|
||||
void fatal PARAMS((char const *));
|
||||
void finish_output PARAMS((void));
|
||||
void message PARAMS((char const *, char const *, char const *));
|
||||
void message5 PARAMS((char const *, char const *, char const *, char const *, char const *));
|
||||
void output_1_line PARAMS((char const *, char const *, char const *, char const *));
|
||||
void perror_with_name PARAMS((char const *));
|
||||
void pfatal_with_name PARAMS((char const *));
|
||||
void print_1_line PARAMS((char const *, char const * const *));
|
||||
void print_message_queue PARAMS((void));
|
||||
void print_number_range PARAMS((int, struct file_data *, int, int));
|
||||
void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *))));
|
||||
void setup_output PARAMS((char const *, char const *, int));
|
||||
void translate_range PARAMS((struct file_data const *, int, int, int *, int *));
|
||||
|
||||
/* version.c */
|
||||
extern char const version_string[];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Three way file comparison program (diff3) for Project GNU.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -17,16 +17,12 @@
|
||||
|
||||
/* Written by Randy Smith */
|
||||
|
||||
#if __STDC__
|
||||
#define VOID void
|
||||
#else
|
||||
#define VOID char
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "getopt.h"
|
||||
#include "system.h"
|
||||
|
||||
extern char const version_string[];
|
||||
|
||||
/*
|
||||
* Internal data structures and macros for the diff3 program; includes
|
||||
@ -70,7 +66,7 @@ enum diff_type {
|
||||
struct diff_block {
|
||||
int ranges[2][2]; /* Ranges are inclusive */
|
||||
char **lines[2]; /* The actual lines (may contain nulls) */
|
||||
int *lengths[2]; /* Line lengths (including newlines, if any) */
|
||||
size_t *lengths[2]; /* Line lengths (including newlines, if any) */
|
||||
struct diff_block *next;
|
||||
};
|
||||
|
||||
@ -80,7 +76,7 @@ struct diff3_block {
|
||||
enum diff_type correspond; /* Type of diff */
|
||||
int ranges[3][2]; /* Ranges are inclusive */
|
||||
char **lines[3]; /* The actual lines (may contain nulls) */
|
||||
int *lengths[3]; /* Line lengths (including newlines, if any) */
|
||||
size_t *lengths[3]; /* Line lengths (including newlines, if any) */
|
||||
struct diff3_block *next;
|
||||
};
|
||||
|
||||
@ -158,6 +154,9 @@ static int flagging;
|
||||
/* Number of lines to keep in identical prefix and suffix. */
|
||||
static int horizon_lines = 10;
|
||||
|
||||
/* Use a tab to align output lines (-T). */
|
||||
static int tab_align_flag;
|
||||
|
||||
/* If nonzero, do not output information for overlapping diffs. */
|
||||
static int simple_only;
|
||||
|
||||
@ -176,46 +175,44 @@ static int merge;
|
||||
|
||||
static char *argv0;
|
||||
|
||||
/*
|
||||
* Forward function declarations.
|
||||
*/
|
||||
static int myread ();
|
||||
static void fatal ();
|
||||
static void perror_with_exit ();
|
||||
static struct diff_block *process_diff ();
|
||||
static struct diff3_block *make_3way_diff ();
|
||||
static void output_diff3 ();
|
||||
static int output_diff3_edscript ();
|
||||
static int output_diff3_merge ();
|
||||
static void usage ();
|
||||
static VOID *xmalloc PARAMS((size_t));
|
||||
static VOID *xrealloc PARAMS((VOID *, size_t));
|
||||
|
||||
static struct diff3_block *using_to_diff3_block ();
|
||||
static int copy_stringlist ();
|
||||
static struct diff3_block *create_diff3_block ();
|
||||
static int compare_line_list ();
|
||||
static char *read_diff PARAMS((char const *, char const *, char **));
|
||||
static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int));
|
||||
static enum diff_type process_diff_control PARAMS((char **, struct diff_block *));
|
||||
static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int));
|
||||
static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int));
|
||||
static int dotlines PARAMS((FILE *, struct diff3_block *, int));
|
||||
static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
|
||||
static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *));
|
||||
static size_t myread PARAMS((int, char *, size_t));
|
||||
static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int));
|
||||
static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *));
|
||||
static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *));
|
||||
static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *));
|
||||
static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **));
|
||||
static void fatal PARAMS((char const *));
|
||||
static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3]));
|
||||
static void perror_with_exit PARAMS((char const *));
|
||||
static void undotlines PARAMS((FILE *, int, int, int));
|
||||
static void usage PARAMS((int));
|
||||
|
||||
static char *read_diff ();
|
||||
static enum diff_type process_diff_control ();
|
||||
static char *scan_diff_line ();
|
||||
static char const diff_program[] = DIFF_PROGRAM;
|
||||
|
||||
static struct diff3_block *reverse_diff3_blocklist ();
|
||||
|
||||
VOID *xmalloc ();
|
||||
static VOID *xrealloc ();
|
||||
|
||||
static char diff_program[] = DIFF_PROGRAM;
|
||||
|
||||
static struct option longopts[] =
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"text", 0, NULL, 'a'},
|
||||
{"show-all", 0, NULL, 'A'},
|
||||
{"ed", 0, NULL, 'e'},
|
||||
{"show-overlap", 0, NULL, 'E'},
|
||||
{"label", 1, NULL, 'L'},
|
||||
{"merge", 0, NULL, 'm'},
|
||||
{"overlap-only", 0, NULL, 'x'},
|
||||
{"easy-only", 0, NULL, '3'},
|
||||
{"version", 0, NULL, 'v'},
|
||||
{"text", 0, 0, 'a'},
|
||||
{"show-all", 0, 0, 'A'},
|
||||
{"ed", 0, 0, 'e'},
|
||||
{"show-overlap", 0, 0, 'E'},
|
||||
{"label", 1, 0, 'L'},
|
||||
{"merge", 0, 0, 'm'},
|
||||
{"initial-tab", 0, 0, 'T'},
|
||||
{"overlap-only", 0, 0, 'x'},
|
||||
{"easy-only", 0, 0, '3'},
|
||||
{"version", 0, 0, 'v'},
|
||||
{"help", 0, 0, 129},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@ -228,7 +225,6 @@ main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
extern char *version_string;
|
||||
int c, i;
|
||||
int mapping[3];
|
||||
int rev_mapping[3];
|
||||
@ -238,7 +234,6 @@ main (argc, argv)
|
||||
struct diff3_block *diff3;
|
||||
int tag_count = 0;
|
||||
char *tag_strings[3];
|
||||
extern char *optarg;
|
||||
char *commonname;
|
||||
char **file;
|
||||
struct stat statb;
|
||||
@ -247,8 +242,7 @@ main (argc, argv)
|
||||
|
||||
argv0 = argv[0];
|
||||
|
||||
while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -283,9 +277,14 @@ main (argc, argv)
|
||||
case 'e':
|
||||
incompat++;
|
||||
break;
|
||||
case 'v':
|
||||
fprintf (stderr, "GNU diff3 version %s\n", version_string);
|
||||
case 'T':
|
||||
tab_align_flag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
printf ("GNU diff3 version %s\n", version_string);
|
||||
exit (0);
|
||||
case 129:
|
||||
usage (0);
|
||||
case 'L':
|
||||
/* Handle up to three -L options. */
|
||||
if (tag_count < 3)
|
||||
@ -295,8 +294,7 @@ main (argc, argv)
|
||||
}
|
||||
/* Falls through */
|
||||
default:
|
||||
usage ();
|
||||
/* NOTREACHED */
|
||||
usage (2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +306,7 @@ main (argc, argv)
|
||||
|| finalwrite & merge /* -i -m would rewrite input file. */
|
||||
|| (tag_count && ! flagging) /* -L requires one of -AEX. */
|
||||
|| argc - optind != 3)
|
||||
usage ();
|
||||
usage (2);
|
||||
|
||||
file = &argv[optind];
|
||||
|
||||
@ -346,14 +344,15 @@ main (argc, argv)
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (strcmp (file[i], "-") != 0)
|
||||
if (stat (file[i], &statb) < 0)
|
||||
perror_with_exit (file[i]);
|
||||
else if (S_ISDIR(statb.st_mode))
|
||||
{
|
||||
fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]);
|
||||
exit (2);
|
||||
}
|
||||
|
||||
{
|
||||
if (stat (file[i], &statb) < 0)
|
||||
perror_with_exit (file[i]);
|
||||
else if (S_ISDIR(statb.st_mode))
|
||||
{
|
||||
fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]);
|
||||
exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
commonname = file[rev_mapping[FILEC]];
|
||||
thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block);
|
||||
@ -395,16 +394,19 @@ main (argc, argv)
|
||||
* Explain, patiently and kindly, how to use this program. Then exit.
|
||||
*/
|
||||
static void
|
||||
usage ()
|
||||
usage (status)
|
||||
int status;
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
fflush (stderr);
|
||||
printf ("\
|
||||
Usage: %s [options] my-file older-file your-file\n\
|
||||
Options:\n\
|
||||
[-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\
|
||||
[--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\
|
||||
[--label=label1 [--label=label2 [--label=label3]]] [--version]\n\
|
||||
Only one of [exAEX3] is allowed\n", argv0);
|
||||
exit (2);
|
||||
[-exAEX3aTv] [-i|-m] [-L label1 [-L label2 [-L label3]]]\n\
|
||||
[--easy-only] [--ed] [--help] [--initial-tab]\n\
|
||||
[--label=label1 [--label=label2 [--label=label3]]] [--merge]\n\
|
||||
[--overlap-only] [--show-all] [--show-overlap] [--text] [--version]\n\
|
||||
Only one of [exAEX3] is allowed\n", argv0);
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -436,7 +438,7 @@ Options:\n\
|
||||
* Create a diff3_block, reserving space as indicated by the ranges.
|
||||
*
|
||||
* 3) Copy all of the pointers for file2 in. At least for now,
|
||||
* do bcmp's between corresponding strings in the two diffs.
|
||||
* do memcmp's between corresponding strings in the two diffs.
|
||||
*
|
||||
* 4) Copy all of the pointers for file0 and 1 in. Get what you
|
||||
* need from file2 (when there isn't a diff block, it's
|
||||
@ -447,8 +449,8 @@ Options:\n\
|
||||
* the common file in that diff) is the odd person out. If you used
|
||||
* diff blocks from both sets, check to see if files 0 and 1 match:
|
||||
*
|
||||
* Same number of lines? If so, do a set of bcmp's (if a
|
||||
* bcmp matches; copy the pointer over; it'll be easier later
|
||||
* Same number of lines? If so, do a set of memcmp's (if a
|
||||
* memcmp matches; copy the pointer over; it'll be easier later
|
||||
* if you have to do any compares). If they match, 0 & 1 are
|
||||
* the same. If not, all three different.
|
||||
*
|
||||
@ -518,16 +520,11 @@ make_3way_diff (thread0, thread1)
|
||||
struct diff3_block
|
||||
*result,
|
||||
*tmpblock,
|
||||
**result_end,
|
||||
*last_diff3;
|
||||
**result_end;
|
||||
|
||||
static struct diff3_block zero_diff3 = {
|
||||
ERROR,
|
||||
{ {0, 0}, {0, 0}, {0, 0} },
|
||||
{ (char **) 0, (char **) 0, (char **) 0 },
|
||||
{ (int *) 0, (int *) 0, (int *) 0 },
|
||||
(struct diff3_block *) 0
|
||||
};
|
||||
struct diff3_block const *last_diff3;
|
||||
|
||||
static struct diff3_block const zero_diff3;
|
||||
|
||||
/* Initialization */
|
||||
result = 0;
|
||||
@ -539,8 +536,7 @@ make_3way_diff (thread0, thread1)
|
||||
|
||||
while (current[0] || current[1])
|
||||
{
|
||||
using[0] = using[1] = last_using[0] = last_using[1] =
|
||||
(struct diff_block *) 0;
|
||||
using[0] = using[1] = last_using[0] = last_using[1] = 0;
|
||||
|
||||
/* Setup low and high water threads, diffs, and marks. */
|
||||
if (!current[0])
|
||||
@ -567,8 +563,7 @@ make_3way_diff (thread0, thread1)
|
||||
= last_using[high_water_thread]
|
||||
= high_water_diff;
|
||||
current[high_water_thread] = high_water_diff->next;
|
||||
last_using[high_water_thread]->next
|
||||
= (struct diff_block *) 0;
|
||||
last_using[high_water_thread]->next = 0;
|
||||
|
||||
/* And mark the other diff */
|
||||
other_thread = high_water_thread ^ 0x1;
|
||||
@ -591,10 +586,8 @@ make_3way_diff (thread0, thread1)
|
||||
/* Take it off the current list. Note that this following
|
||||
code assumes that other_diff enters it equal to
|
||||
current[high_water_thread ^ 0x1] */
|
||||
current[other_thread]
|
||||
= current[other_thread]->next;
|
||||
other_diff->next
|
||||
= (struct diff_block *) 0;
|
||||
current[other_thread] = current[other_thread]->next;
|
||||
other_diff->next = 0;
|
||||
|
||||
/* Set the high_water stuff
|
||||
If this comparison is equal, then this is the last pass
|
||||
@ -660,7 +653,7 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
|
||||
*using[2],
|
||||
*last_using[2];
|
||||
int low_thread, high_thread;
|
||||
struct diff3_block *last_diff3;
|
||||
struct diff3_block const *last_diff3;
|
||||
{
|
||||
int low[2], high[2];
|
||||
struct diff3_block *result;
|
||||
@ -780,21 +773,21 @@ using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3)
|
||||
*/
|
||||
static int
|
||||
copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
|
||||
char *fromptrs[], *toptrs[];
|
||||
int *fromlengths, *tolengths;
|
||||
char * const fromptrs[];
|
||||
char *toptrs[];
|
||||
size_t const fromlengths[];
|
||||
size_t tolengths[];
|
||||
int copynum;
|
||||
{
|
||||
register char
|
||||
**f = fromptrs,
|
||||
**t = toptrs;
|
||||
register int
|
||||
*fl = fromlengths,
|
||||
*tl = tolengths;
|
||||
register char * const *f = fromptrs;
|
||||
register char **t = toptrs;
|
||||
register size_t const *fl = fromlengths;
|
||||
register size_t *tl = tolengths;
|
||||
|
||||
while (copynum--)
|
||||
{
|
||||
if (*t)
|
||||
{ if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; }
|
||||
{ if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; }
|
||||
else
|
||||
{ *t = *f ; *tl = *fl; }
|
||||
|
||||
@ -831,42 +824,42 @@ create_diff3_block (low0, high0, low1, high1, low2, high2)
|
||||
if (numlines)
|
||||
{
|
||||
D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
|
||||
D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
|
||||
D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t);
|
||||
bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
|
||||
bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
|
||||
bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t)));
|
||||
}
|
||||
else
|
||||
{
|
||||
D_LINEARRAY (result, FILE0) = (char **) 0;
|
||||
D_LENARRAY (result, FILE0) = (int *) 0;
|
||||
D_LINEARRAY (result, FILE0) = 0;
|
||||
D_LENARRAY (result, FILE0) = 0;
|
||||
}
|
||||
|
||||
numlines = D_NUMLINES (result, FILE1);
|
||||
if (numlines)
|
||||
{
|
||||
D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
|
||||
D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
|
||||
D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t);
|
||||
bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
|
||||
bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
|
||||
bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t)));
|
||||
}
|
||||
else
|
||||
{
|
||||
D_LINEARRAY (result, FILE1) = (char **) 0;
|
||||
D_LENARRAY (result, FILE1) = (int *) 0;
|
||||
D_LINEARRAY (result, FILE1) = 0;
|
||||
D_LENARRAY (result, FILE1) = 0;
|
||||
}
|
||||
|
||||
numlines = D_NUMLINES (result, FILE2);
|
||||
if (numlines)
|
||||
{
|
||||
D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
|
||||
D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
|
||||
D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t);
|
||||
bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
|
||||
bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
|
||||
bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t)));
|
||||
}
|
||||
else
|
||||
{
|
||||
D_LINEARRAY (result, FILE2) = (char **) 0;
|
||||
D_LENARRAY (result, FILE2) = (int *) 0;
|
||||
D_LINEARRAY (result, FILE2) = 0;
|
||||
D_LENARRAY (result, FILE2) = 0;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
@ -879,20 +872,20 @@ create_diff3_block (low0, high0, low1, high1, low2, high2)
|
||||
*/
|
||||
static int
|
||||
compare_line_list (list1, lengths1, list2, lengths2, nl)
|
||||
char *list1[], *list2[];
|
||||
int *lengths1, *lengths2;
|
||||
char * const list1[], * const list2[];
|
||||
size_t const lengths1[], lengths2[];
|
||||
int nl;
|
||||
{
|
||||
char
|
||||
**l1 = list1,
|
||||
**l2 = list2;
|
||||
int
|
||||
* const *l1 = list1,
|
||||
* const *l2 = list2;
|
||||
size_t const
|
||||
*lgths1 = lengths1,
|
||||
*lgths2 = lengths2;
|
||||
|
||||
while (nl--)
|
||||
if (!*l1 || !*l2 || *lgths1 != *lgths2++
|
||||
|| bcmp (*l1++, *l2++, *lgths1++))
|
||||
|| memcmp (*l1++, *l2++, *lgths1++))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -907,7 +900,7 @@ extern char **environ;
|
||||
|
||||
static struct diff_block *
|
||||
process_diff (filea, fileb, last_block)
|
||||
char *filea, *fileb;
|
||||
char const *filea, *fileb;
|
||||
struct diff_block **last_block;
|
||||
{
|
||||
char *diff_contents;
|
||||
@ -920,12 +913,13 @@ process_diff (filea, fileb, last_block)
|
||||
diff_limit = read_diff (filea, fileb, &diff_contents);
|
||||
scan_diff = diff_contents;
|
||||
block_list_end = &block_list;
|
||||
bptr = 0; /* Pacify `gcc -W'. */
|
||||
|
||||
while (scan_diff < diff_limit)
|
||||
{
|
||||
bptr = ALLOCATE (1, struct diff_block);
|
||||
bptr->lines[0] = bptr->lines[1] = (char **) 0;
|
||||
bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
|
||||
bptr->lines[0] = bptr->lines[1] = 0;
|
||||
bptr->lengths[0] = bptr->lengths[1] = 0;
|
||||
|
||||
dt = process_diff_control (&scan_diff, bptr);
|
||||
if (dt == ERROR || *scan_diff != '\n')
|
||||
@ -962,7 +956,7 @@ process_diff (filea, fileb, last_block)
|
||||
{
|
||||
int numlines = D_NUMLINES (bptr, 0);
|
||||
bptr->lines[0] = ALLOCATE (numlines, char *);
|
||||
bptr->lengths[0] = ALLOCATE (numlines, int);
|
||||
bptr->lengths[0] = ALLOCATE (numlines, size_t);
|
||||
for (i = 0; i < numlines; i++)
|
||||
scan_diff = scan_diff_line (scan_diff,
|
||||
&(bptr->lines[0][i]),
|
||||
@ -985,7 +979,7 @@ process_diff (filea, fileb, last_block)
|
||||
{
|
||||
int numlines = D_NUMLINES (bptr, 1);
|
||||
bptr->lines[1] = ALLOCATE (numlines, char *);
|
||||
bptr->lengths[1] = ALLOCATE (numlines, int);
|
||||
bptr->lengths[1] = ALLOCATE (numlines, size_t);
|
||||
for (i = 0; i < numlines; i++)
|
||||
scan_diff = scan_diff_line (scan_diff,
|
||||
&(bptr->lines[1][i]),
|
||||
@ -1038,9 +1032,9 @@ process_diff_control (string, db)
|
||||
|
||||
#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
|
||||
#define READNUM(s, num) \
|
||||
{ if (!isdigit (*s)) return ERROR; holdnum = 0; \
|
||||
do { holdnum = (*s++ - '0' + holdnum * 10); } \
|
||||
while (isdigit (*s)); (num) = holdnum; }
|
||||
{ unsigned char c = *s; if (!isdigit (c)) return ERROR; holdnum = 0; \
|
||||
do { holdnum = (c - '0' + holdnum * 10); } \
|
||||
while (isdigit (c = *++s)); (num) = holdnum; }
|
||||
|
||||
/* Read first set of digits */
|
||||
SKIPWHITE (s);
|
||||
@ -1097,18 +1091,16 @@ process_diff_control (string, db)
|
||||
|
||||
static char *
|
||||
read_diff (filea, fileb, output_placement)
|
||||
char *filea, *fileb;
|
||||
char const *filea, *fileb;
|
||||
char **output_placement;
|
||||
{
|
||||
char *argv[7];
|
||||
char horizon_arg[256];
|
||||
char **ap;
|
||||
int fds[2];
|
||||
char *diff_result;
|
||||
int current_chunk_size;
|
||||
int bytes;
|
||||
int total;
|
||||
int pid, w;
|
||||
size_t bytes, current_chunk_size, total;
|
||||
char const *argv[7];
|
||||
char horizon_arg[256];
|
||||
char const **ap;
|
||||
int fds[2];
|
||||
pid_t pid;
|
||||
int wstatus;
|
||||
|
||||
ap = argv;
|
||||
@ -1120,7 +1112,7 @@ read_diff (filea, fileb, output_placement)
|
||||
*ap++ = "--";
|
||||
*ap++ = filea;
|
||||
*ap++ = fileb;
|
||||
*ap = (char *) 0;
|
||||
*ap = 0;
|
||||
|
||||
if (pipe (fds) < 0)
|
||||
perror_with_exit ("pipe failed");
|
||||
@ -1130,15 +1122,15 @@ read_diff (filea, fileb, output_placement)
|
||||
{
|
||||
/* Child */
|
||||
close (fds[0]);
|
||||
if (fds[1] != fileno (stdout))
|
||||
if (fds[1] != STDOUT_FILENO)
|
||||
{
|
||||
dup2 (fds[1], fileno (stdout));
|
||||
dup2 (fds[1], STDOUT_FILENO);
|
||||
close (fds[1]);
|
||||
}
|
||||
execve (diff_program, argv, environ);
|
||||
execve (diff_program, (char **) argv, environ);
|
||||
/* Avoid stdio, because the parent process's buffers are inherited. */
|
||||
write (fileno (stderr), diff_program, strlen (diff_program));
|
||||
write (fileno (stderr), ": not found\n", 12);
|
||||
write (STDERR_FILENO, diff_program, strlen (diff_program));
|
||||
write (STDERR_FILENO, ": not found\n", 12);
|
||||
_exit (2);
|
||||
}
|
||||
|
||||
@ -1147,7 +1139,7 @@ read_diff (filea, fileb, output_placement)
|
||||
|
||||
close (fds[1]); /* Prevent erroneous lack of EOF */
|
||||
current_chunk_size = DIFF_CHUNK_SIZE;
|
||||
diff_result = (char *) xmalloc (current_chunk_size);
|
||||
diff_result = xmalloc (current_chunk_size);
|
||||
total = 0;
|
||||
do {
|
||||
bytes = myread (fds[0],
|
||||
@ -1155,7 +1147,15 @@ read_diff (filea, fileb, output_placement)
|
||||
current_chunk_size - total);
|
||||
total += bytes;
|
||||
if (total == current_chunk_size)
|
||||
diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
|
||||
{
|
||||
if (current_chunk_size < 2 * current_chunk_size)
|
||||
current_chunk_size = 2 * current_chunk_size;
|
||||
else if (current_chunk_size < (size_t) -1)
|
||||
current_chunk_size = (size_t) -1;
|
||||
else
|
||||
fatal ("files are too large to fit into memory");
|
||||
diff_result = xrealloc (diff_result, (current_chunk_size *= 2));
|
||||
}
|
||||
} while (bytes);
|
||||
|
||||
if (total != 0 && diff_result[total-1] != '\n')
|
||||
@ -1163,10 +1163,18 @@ read_diff (filea, fileb, output_placement)
|
||||
|
||||
*output_placement = diff_result;
|
||||
|
||||
do
|
||||
if ((w = wait (&wstatus)) == -1)
|
||||
#if HAVE_WAITPID
|
||||
if (waitpid (pid, &wstatus, 0) < 0)
|
||||
perror_with_exit ("waitpid failed");
|
||||
#else
|
||||
for (;;) {
|
||||
pid_t w = wait (&wstatus);
|
||||
if (w < 0)
|
||||
perror_with_exit ("wait failed");
|
||||
while (w != pid);
|
||||
if (w == pid)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
|
||||
fatal ("subsidiary diff failed");
|
||||
@ -1185,7 +1193,7 @@ read_diff (filea, fileb, output_placement)
|
||||
static char *
|
||||
scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
|
||||
char *scan_ptr, **set_start;
|
||||
int *set_length;
|
||||
size_t *set_length;
|
||||
char *limit;
|
||||
char firstchar;
|
||||
{
|
||||
@ -1238,16 +1246,17 @@ static void
|
||||
output_diff3 (outputfile, diff, mapping, rev_mapping)
|
||||
FILE *outputfile;
|
||||
struct diff3_block *diff;
|
||||
int mapping[3], rev_mapping[3];
|
||||
int const mapping[3], rev_mapping[3];
|
||||
{
|
||||
int i;
|
||||
int oddoneout;
|
||||
char *cp;
|
||||
struct diff3_block *ptr;
|
||||
int line;
|
||||
int length;
|
||||
size_t length;
|
||||
int dontprint;
|
||||
static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
|
||||
char const *line_prefix = tab_align_flag ? "\t" : " ";
|
||||
|
||||
for (ptr = diff; ptr; ptr = D_NEXT (ptr))
|
||||
{
|
||||
@ -1299,15 +1308,20 @@ output_diff3 (outputfile, diff, mapping, rev_mapping)
|
||||
|
||||
if (i == dontprint) continue;
|
||||
|
||||
for (line = 0; line < hight - lowt + 1; line++)
|
||||
if (lowt <= hight)
|
||||
{
|
||||
fprintf (outputfile, " ");
|
||||
cp = D_RELNUM (ptr, realfile, line);
|
||||
length = D_RELLEN (ptr, realfile, line);
|
||||
fwrite (cp, sizeof (char), length, outputfile);
|
||||
line = 0;
|
||||
do
|
||||
{
|
||||
fprintf (outputfile, line_prefix);
|
||||
cp = D_RELNUM (ptr, realfile, line);
|
||||
length = D_RELLEN (ptr, realfile, line);
|
||||
fwrite (cp, sizeof (char), length, outputfile);
|
||||
}
|
||||
while (++line < hight - lowt + 1);
|
||||
if (cp[length - 1] != '\n')
|
||||
fprintf (outputfile, "\n\\ No newline at end of file\n");
|
||||
}
|
||||
if (line != 0 && cp[length - 1] != '\n')
|
||||
fprintf (outputfile, "\n\\ No newline at end of file\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1388,8 +1402,8 @@ output_diff3_edscript (outputfile, diff, mapping, rev_mapping,
|
||||
file0, file1, file2)
|
||||
FILE *outputfile;
|
||||
struct diff3_block *diff;
|
||||
int mapping[3], rev_mapping[3];
|
||||
char *file0, *file1, *file2;
|
||||
int const mapping[3], rev_mapping[3];
|
||||
char const *file0, *file1, *file2;
|
||||
{
|
||||
int leading_dot;
|
||||
int conflicts_found = 0, conflict;
|
||||
@ -1515,8 +1529,8 @@ output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping,
|
||||
file0, file1, file2)
|
||||
FILE *infile, *outputfile;
|
||||
struct diff3_block *diff;
|
||||
int mapping[3], rev_mapping[3];
|
||||
char *file0, *file1, *file2;
|
||||
int const mapping[3], rev_mapping[3];
|
||||
char const *file0, *file1, *file2;
|
||||
{
|
||||
int c, i;
|
||||
int conflicts_found = 0, conflict;
|
||||
@ -1532,7 +1546,7 @@ output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping,
|
||||
((enum diff_type)
|
||||
(((int) DIFF_1ST)
|
||||
+ rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
|
||||
char *format_2nd = "<<<<<<< %s\n";
|
||||
char const *format_2nd = "<<<<<<< %s\n";
|
||||
|
||||
/* If we aren't supposed to do this output block, skip it. */
|
||||
switch (type)
|
||||
@ -1630,8 +1644,7 @@ reverse_diff3_blocklist (diff)
|
||||
{
|
||||
register struct diff3_block *tmp, *next, *prev;
|
||||
|
||||
for (tmp = diff, prev = (struct diff3_block *) 0;
|
||||
tmp; tmp = next)
|
||||
for (tmp = diff, prev = 0; tmp; tmp = next)
|
||||
{
|
||||
next = tmp->next;
|
||||
tmp->next = prev;
|
||||
@ -1641,41 +1654,42 @@ reverse_diff3_blocklist (diff)
|
||||
return prev;
|
||||
}
|
||||
|
||||
static int
|
||||
static size_t
|
||||
myread (fd, ptr, size)
|
||||
int fd, size;
|
||||
int fd;
|
||||
char *ptr;
|
||||
size_t size;
|
||||
{
|
||||
int result = read (fd, ptr, size);
|
||||
if (result < 0)
|
||||
size_t result = read (fd, ptr, size);
|
||||
if (result == -1)
|
||||
perror_with_exit ("read failed");
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID *
|
||||
static VOID *
|
||||
xmalloc (size)
|
||||
unsigned size;
|
||||
size_t size;
|
||||
{
|
||||
VOID *result = (VOID *) malloc (size ? size : 1);
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted");
|
||||
fatal ("memory exhausted");
|
||||
return result;
|
||||
}
|
||||
|
||||
static VOID *
|
||||
xrealloc (ptr, size)
|
||||
VOID *ptr;
|
||||
unsigned size;
|
||||
size_t size;
|
||||
{
|
||||
VOID *result = (VOID *) realloc (ptr, size ? size : 1);
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted");
|
||||
fatal ("memory exhausted");
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
fatal (string)
|
||||
char *string;
|
||||
char const *string;
|
||||
{
|
||||
fprintf (stderr, "%s: %s\n", argv0, string);
|
||||
exit (2);
|
||||
@ -1683,7 +1697,7 @@ fatal (string)
|
||||
|
||||
static void
|
||||
perror_with_exit (string)
|
||||
char *string;
|
||||
char const *string;
|
||||
{
|
||||
int e = errno;
|
||||
fprintf (stderr, "%s: ", argv0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Read, sort and compare two directories. Used for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -19,8 +19,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
static int compare_names ();
|
||||
|
||||
/* Read the directory named by DIR and store into DIRDATA a sorted vector
|
||||
of filenames for its contents. DIR->desc == -1 means this directory is
|
||||
known to be nonexistent, so set DIRDATA to an empty vector.
|
||||
@ -28,31 +26,35 @@ static int compare_names ();
|
||||
|
||||
struct dirdata
|
||||
{
|
||||
char **files; /* Sorted names of files in dir, terminated by (char *) 0. */
|
||||
char const **names; /* Sorted names of files in dir, 0-terminated. */
|
||||
char *data; /* Allocated storage for file names. */
|
||||
};
|
||||
|
||||
static int compare_names PARAMS((void const *, void const *));
|
||||
static int dir_sort PARAMS((struct file_data const *, struct dirdata *));
|
||||
|
||||
static int
|
||||
dir_sort (dir, dirdata)
|
||||
struct file_data *dir;
|
||||
struct file_data const *dir;
|
||||
struct dirdata *dirdata;
|
||||
{
|
||||
register struct direct *next;
|
||||
register struct dirent *next;
|
||||
register int i;
|
||||
|
||||
/* Address of block containing the files that are described. */
|
||||
char **files;
|
||||
char const **names;
|
||||
|
||||
/* Number of files in directory. */
|
||||
int nfiles;
|
||||
size_t nnames;
|
||||
|
||||
/* Allocated and used storage for file name data. */
|
||||
char *data;
|
||||
size_t data_alloc, data_used;
|
||||
|
||||
dirdata->files = 0;
|
||||
dirdata->names = 0;
|
||||
dirdata->data = 0;
|
||||
nfiles = 0;
|
||||
nnames = 0;
|
||||
data = 0;
|
||||
|
||||
if (dir->desc != -1)
|
||||
{
|
||||
@ -65,7 +67,7 @@ dir_sort (dir, dirdata)
|
||||
|
||||
data_alloc = max (1, (size_t) dir->stat.st_size);
|
||||
data_used = 0;
|
||||
dirdata->data = data = (char *) xmalloc (data_alloc);
|
||||
dirdata->data = data = xmalloc (data_alloc);
|
||||
|
||||
/* Read the directory entries, and insert the subfiles
|
||||
into the `data' table. */
|
||||
@ -85,10 +87,10 @@ dir_sort (dir, dirdata)
|
||||
|
||||
d_size = strlen (d_name) + 1;
|
||||
while (data_alloc < data_used + d_size)
|
||||
dirdata->data = data = (char *) xrealloc (data, data_alloc *= 2);
|
||||
bcopy (d_name, data + data_used, d_size);
|
||||
dirdata->data = data = xrealloc (data, data_alloc *= 2);
|
||||
memcpy (data + data_used, d_name, d_size);
|
||||
data_used += d_size;
|
||||
nfiles++;
|
||||
nnames++;
|
||||
}
|
||||
if (errno)
|
||||
{
|
||||
@ -97,7 +99,7 @@ dir_sort (dir, dirdata)
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
#ifdef VOID_CLOSEDIR
|
||||
#if VOID_CLOSEDIR
|
||||
closedir (reading);
|
||||
#else
|
||||
if (closedir (reading) != 0)
|
||||
@ -105,17 +107,18 @@ dir_sort (dir, dirdata)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create the `files' table from the `data' table. */
|
||||
dirdata->files = files = (char **) xmalloc (sizeof (char *) * (nfiles + 1));
|
||||
for (i = 0; i < nfiles; i++)
|
||||
/* Create the `names' table from the `data' table. */
|
||||
dirdata->names = names = (char const **) xmalloc (sizeof (char *)
|
||||
* (nnames + 1));
|
||||
for (i = 0; i < nnames; i++)
|
||||
{
|
||||
files[i] = data;
|
||||
names[i] = data;
|
||||
data += strlen (data) + 1;
|
||||
}
|
||||
files[nfiles] = 0;
|
||||
names[nnames] = 0;
|
||||
|
||||
/* Sort the table. */
|
||||
qsort (files, nfiles, sizeof (char *), compare_names);
|
||||
qsort (names, nnames, sizeof (char *), compare_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -124,9 +127,9 @@ dir_sort (dir, dirdata)
|
||||
|
||||
static int
|
||||
compare_names (file1, file2)
|
||||
char **file1, **file2;
|
||||
void const *file1, *file2;
|
||||
{
|
||||
return strcmp (*file1, *file2);
|
||||
return strcmp (* (char const *const *) file1, * (char const *const *) file2);
|
||||
}
|
||||
|
||||
/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1].
|
||||
@ -151,8 +154,8 @@ compare_names (file1, file2)
|
||||
|
||||
int
|
||||
diff_dirs (filevec, handle_file, depth)
|
||||
struct file_data filevec[];
|
||||
int (*handle_file) ();
|
||||
struct file_data const filevec[];
|
||||
int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int));
|
||||
int depth;
|
||||
{
|
||||
struct dirdata dirdata[2];
|
||||
@ -169,42 +172,42 @@ diff_dirs (filevec, handle_file, depth)
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
register char **files0 = dirdata[0].files;
|
||||
register char **files1 = dirdata[1].files;
|
||||
char *name0 = filevec[0].name;
|
||||
char *name1 = filevec[1].name;
|
||||
register char const * const *names0 = dirdata[0].names;
|
||||
register char const * const *names1 = dirdata[1].names;
|
||||
char const *name0 = filevec[0].name;
|
||||
char const *name1 = filevec[1].name;
|
||||
|
||||
/* If `-S name' was given, and this is the topmost level of comparison,
|
||||
ignore all file names less than the specified starting name. */
|
||||
|
||||
if (dir_start_file && depth == 0)
|
||||
{
|
||||
while (*files0 && strcmp (*files0, dir_start_file) < 0)
|
||||
files0++;
|
||||
while (*files1 && strcmp (*files1, dir_start_file) < 0)
|
||||
files1++;
|
||||
while (*names0 && strcmp (*names0, dir_start_file) < 0)
|
||||
names0++;
|
||||
while (*names1 && strcmp (*names1, dir_start_file) < 0)
|
||||
names1++;
|
||||
}
|
||||
|
||||
/* Loop while files remain in one or both dirs. */
|
||||
while (*files0 || *files1)
|
||||
while (*names0 || *names1)
|
||||
{
|
||||
/* Compare next name in dir 0 with next name in dir 1.
|
||||
At the end of a dir,
|
||||
pretend the "next name" in that dir is very large. */
|
||||
int nameorder = (!*files0 ? 1 : !*files1 ? -1
|
||||
: strcmp (*files0, *files1));
|
||||
int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *files0++,
|
||||
name1, nameorder < 0 ? 0 : *files1++,
|
||||
int nameorder = (!*names0 ? 1 : !*names1 ? -1
|
||||
: strcmp (*names0, *names1));
|
||||
int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++,
|
||||
name1, nameorder < 0 ? 0 : *names1++,
|
||||
depth + 1);
|
||||
if (v1 > val)
|
||||
val = v1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (dirdata[i].files)
|
||||
free (dirdata[i].files);
|
||||
if (dirdata[i].names)
|
||||
free (dirdata[i].names);
|
||||
if (dirdata[i].data)
|
||||
free (dirdata[i].data);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Output routines for ed-script format.
|
||||
Copyright (C) 1988, 89, 91, 92 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 89, 91, 92, 93 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -19,14 +19,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
int change_letter ();
|
||||
int translate_line_number ();
|
||||
static void print_rcs_hunk ();
|
||||
static void print_ed_hunk ();
|
||||
static void pr_forward_ed_hunk ();
|
||||
void translate_range ();
|
||||
struct change *find_change ();
|
||||
struct change *find_reverse_change ();
|
||||
static void print_ed_hunk PARAMS((struct change *));
|
||||
static void print_rcs_hunk PARAMS((struct change *));
|
||||
static void pr_forward_ed_hunk PARAMS((struct change *));
|
||||
|
||||
/* Print our script as ed commands. */
|
||||
|
||||
|
@ -20,31 +20,24 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* NOTE!!! AIX requires this to be the first thing in the file.
|
||||
Do not put ANYTHING before it! */
|
||||
#if !defined (__GNUC__) && defined (_AIX)
|
||||
#pragma alloca
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#if defined (emacs) || defined (CONFIG_BROKETS)
|
||||
/* We use <config.h> instead of "config.h" so that a compilation
|
||||
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
|
||||
(which it would do because it found this file in $srcdir). */
|
||||
#include <config.h>
|
||||
#else
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not __GNUC__ */
|
||||
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifndef _AIX
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif /* alloca.h */
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
#if !__STDC__ && !defined(const) && IN_GCC
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
|
||||
#ifndef _NO_PROTO
|
||||
@ -67,12 +60,9 @@ char *alloca ();
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#undef alloca
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
#include <stdlib.h>
|
||||
#else /* Not GNU C library. */
|
||||
#define __alloca alloca
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
|
||||
@ -180,7 +170,6 @@ static enum
|
||||
in GCC. */
|
||||
#include <string.h>
|
||||
#define my_index strchr
|
||||
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
@ -202,16 +191,19 @@ my_index (str, chr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
my_bcopy (from, to, size)
|
||||
const char *from;
|
||||
char *to;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
to[i] = from[i];
|
||||
}
|
||||
/* If using GCC, we can safely declare strlen this way.
|
||||
If not using GCC, it is ok not to declare it.
|
||||
(Supposedly there are some machines where it might get a warning,
|
||||
but changing this conditional to __STDC__ is too risky.) */
|
||||
#ifdef __GNUC__
|
||||
#ifdef IN_GCC
|
||||
#include "gstddef.h"
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
extern size_t strlen (const char *);
|
||||
#endif
|
||||
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* Handle permutation of arguments. */
|
||||
@ -236,17 +228,51 @@ static void
|
||||
exchange (argv)
|
||||
char **argv;
|
||||
{
|
||||
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
|
||||
char **temp = (char **) __alloca (nonopts_size);
|
||||
int bottom = first_nonopt;
|
||||
int middle = last_nonopt;
|
||||
int top = optind;
|
||||
char *tem;
|
||||
|
||||
/* Interchange the two blocks of data in ARGV. */
|
||||
/* Exchange the shorter segment with the far end of the longer segment.
|
||||
That puts the shorter segment into the right place.
|
||||
It leaves the longer segment in the right place overall,
|
||||
but it consists of two parts that need to be swapped next. */
|
||||
|
||||
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
|
||||
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
|
||||
(optind - last_nonopt) * sizeof (char *));
|
||||
my_bcopy ((char *) temp,
|
||||
(char *) &argv[first_nonopt + optind - last_nonopt],
|
||||
nonopts_size);
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
/* Bottom segment is the short one. */
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the top part of the top segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
/* Exclude the moved bottom segment from further swapping. */
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Top segment is the short one. */
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
|
||||
/* Swap it with the bottom part of the bottom segment. */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
/* Exclude the moved top segment from further swapping. */
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
|
@ -17,14 +17,25 @@
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#if defined (emacs) || defined (CONFIG_BROKETS)
|
||||
/* We use <config.h> instead of "config.h" so that a compilation
|
||||
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
|
||||
(which it would do because it found this file in $srcdir). */
|
||||
#include <config.h>
|
||||
#else
|
||||
#include "config.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if !__STDC__ && !defined(const) && IN_GCC
|
||||
#ifndef __STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* #ifdef-format output routines for GNU DIFF.
|
||||
Copyright (C) 1989, 91, 92 Free Software Foundation, Inc.
|
||||
Copyright (C) 1989, 91, 92, 93 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -21,10 +21,19 @@ and this notice must be preserved on all copies. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
static void format_ifdef ();
|
||||
static void print_ifdef_hunk ();
|
||||
static void print_ifdef_lines ();
|
||||
struct change *find_change ();
|
||||
struct group
|
||||
{
|
||||
struct file_data const *file;
|
||||
int from, upto; /* start and limit lines for this group of lines */
|
||||
};
|
||||
|
||||
static char *format_group PARAMS((FILE *, char *, int, struct group const[]));
|
||||
static char *scan_char_literal PARAMS((char *, int *));
|
||||
static char *scan_printf_spec PARAMS((char *));
|
||||
static int groups_letter_value PARAMS((struct group const[], int));
|
||||
static void format_ifdef PARAMS((char *, int, int, int, int));
|
||||
static void print_ifdef_hunk PARAMS((struct change *));
|
||||
static void print_ifdef_lines PARAMS((FILE *, char *, struct group const *));
|
||||
|
||||
static int next_line;
|
||||
|
||||
@ -40,7 +49,8 @@ print_ifdef_script (script)
|
||||
{
|
||||
begin_output ();
|
||||
format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines,
|
||||
0, -1);
|
||||
next_line - files[0].valid_lines + files[1].valid_lines,
|
||||
files[1].valid_lines);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +63,7 @@ print_ifdef_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
int first0, last0, first1, last1, deletes, inserts;
|
||||
const char *format;
|
||||
char *format;
|
||||
|
||||
/* Determine range of line numbers involved in each file. */
|
||||
analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
|
||||
@ -68,7 +78,8 @@ print_ifdef_hunk (hunk)
|
||||
|
||||
/* Print lines up to this change. */
|
||||
if (next_line < first0)
|
||||
format_ifdef (group_format[UNCHANGED], next_line, first0, 0, -1);
|
||||
format_ifdef (group_format[UNCHANGED], next_line, first0,
|
||||
next_line - first0 + first1, first1);
|
||||
|
||||
/* Print this change. */
|
||||
next_line = last0 + 1;
|
||||
@ -76,87 +87,223 @@ print_ifdef_hunk (hunk)
|
||||
}
|
||||
|
||||
/* Print a set of lines according to FORMAT.
|
||||
Lines BEG0 up to END0 are from the first file.
|
||||
If END1 is -1, then the second file's lines are identical to the first;
|
||||
otherwise, lines BEG1 up to END1 are from the second file. */
|
||||
Lines BEG0 up to END0 are from the first file;
|
||||
lines BEG1 up to END1 are from the second file. */
|
||||
|
||||
static void
|
||||
format_ifdef (format, beg0, end0, beg1, end1)
|
||||
const char *format;
|
||||
char *format;
|
||||
int beg0, end0, beg1, end1;
|
||||
{
|
||||
register FILE *out = outfile;
|
||||
register char c;
|
||||
register const char *f = format;
|
||||
struct group groups[2];
|
||||
|
||||
while ((c = *f++) != 0)
|
||||
{
|
||||
if (c == '%')
|
||||
switch ((c = *f++))
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
|
||||
case '<':
|
||||
/* Print lines deleted from first file. */
|
||||
print_ifdef_lines (line_format[OLD], &files[0], beg0, end0);
|
||||
continue;
|
||||
|
||||
case '=':
|
||||
/* Print common lines. */
|
||||
print_ifdef_lines (line_format[UNCHANGED], &files[0], beg0, end0);
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
/* Print lines inserted from second file. */
|
||||
if (end1 == -1)
|
||||
print_ifdef_lines (line_format[NEW], &files[0], beg0, end0);
|
||||
else
|
||||
print_ifdef_lines (line_format[NEW], &files[1], beg1, end1);
|
||||
continue;
|
||||
|
||||
case '0':
|
||||
c = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
putc (c, out);
|
||||
}
|
||||
groups[0].file = &files[0];
|
||||
groups[0].from = beg0;
|
||||
groups[0].upto = end0;
|
||||
groups[1].file = &files[1];
|
||||
groups[1].from = beg1;
|
||||
groups[1].upto = end1;
|
||||
format_group (outfile, format, '\0', groups);
|
||||
}
|
||||
|
||||
/* Use FORMAT to print each line of CURRENT starting with FROM
|
||||
and continuing up to UPTO. */
|
||||
static void
|
||||
print_ifdef_lines (format, current, from, upto)
|
||||
const char *format;
|
||||
const struct file_data *current;
|
||||
int from, upto;
|
||||
/* Print to file OUT a set of lines according to FORMAT.
|
||||
The format ends at the first free instance of ENDCHAR.
|
||||
Yield the address of the terminating character.
|
||||
GROUPS specifies which lines to print.
|
||||
If OUT is zero, do not actually print anything; just scan the format. */
|
||||
|
||||
static char *
|
||||
format_group (out, format, endchar, groups)
|
||||
register FILE *out;
|
||||
char *format;
|
||||
int endchar;
|
||||
struct group const groups[];
|
||||
{
|
||||
const char * const *linbuf = current->linbuf;
|
||||
register char c;
|
||||
register char *f = format;
|
||||
|
||||
while ((c = *f) != endchar && c != 0)
|
||||
{
|
||||
f++;
|
||||
if (c == '%')
|
||||
{
|
||||
char *spec = f;
|
||||
switch ((c = *f++))
|
||||
{
|
||||
case '%':
|
||||
break;
|
||||
|
||||
case '(':
|
||||
/* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
|
||||
{
|
||||
int i, value[2];
|
||||
FILE *thenout, *elseout;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
unsigned char f0 = f[0];
|
||||
if (isdigit (f0))
|
||||
{
|
||||
value[i] = atoi (f);
|
||||
while (isdigit ((unsigned char) *++f))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value[i] = groups_letter_value (groups, f0);
|
||||
if (value[i] < 0)
|
||||
goto bad_format;
|
||||
f++;
|
||||
}
|
||||
if (*f++ != "=?"[i])
|
||||
goto bad_format;
|
||||
}
|
||||
if (value[0] == value[1])
|
||||
thenout = out, elseout = 0;
|
||||
else
|
||||
thenout = 0, elseout = out;
|
||||
f = format_group (thenout, f, ':', groups);
|
||||
if (*f)
|
||||
{
|
||||
f = format_group (elseout, f + 1, ')', groups);
|
||||
if (*f)
|
||||
f++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case '<':
|
||||
/* Print lines deleted from first file. */
|
||||
print_ifdef_lines (out, line_format[OLD], &groups[0]);
|
||||
continue;
|
||||
|
||||
case '=':
|
||||
/* Print common lines. */
|
||||
print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
|
||||
continue;
|
||||
|
||||
case '>':
|
||||
/* Print lines inserted from second file. */
|
||||
print_ifdef_lines (out, line_format[NEW], &groups[1]);
|
||||
continue;
|
||||
|
||||
default:
|
||||
{
|
||||
int value;
|
||||
char *speclim;
|
||||
|
||||
f = scan_printf_spec (spec);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
speclim = f;
|
||||
c = *f++;
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
f = scan_char_literal (f, &value);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = groups_letter_value (groups, c);
|
||||
if (value < 0)
|
||||
goto bad_format;
|
||||
break;
|
||||
}
|
||||
if (out)
|
||||
{
|
||||
/* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
|
||||
*speclim = 0;
|
||||
fprintf (out, spec - 1, value);
|
||||
/* Undo the temporary replacement. */
|
||||
*speclim = c;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
bad_format:
|
||||
c = '%';
|
||||
f = spec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
putc (c, out);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/* For the line group pair G, return the number corresponding to LETTER.
|
||||
Return -1 if LETTER is not a group format letter. */
|
||||
static int
|
||||
groups_letter_value (g, letter)
|
||||
struct group const g[];
|
||||
int letter;
|
||||
{
|
||||
if (isupper (letter))
|
||||
{
|
||||
g++;
|
||||
letter = tolower (letter);
|
||||
}
|
||||
switch (letter)
|
||||
{
|
||||
case 'e': return translate_line_number (g->file, g->from) - 1;
|
||||
case 'f': return translate_line_number (g->file, g->from);
|
||||
case 'l': return translate_line_number (g->file, g->upto) - 1;
|
||||
case 'm': return translate_line_number (g->file, g->upto);
|
||||
case 'n': return g->upto - g->from;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print to file OUT, using FORMAT to print the line group GROUP.
|
||||
But do nothing if OUT is zero. */
|
||||
static void
|
||||
print_ifdef_lines (out, format, group)
|
||||
register FILE *out;
|
||||
char *format;
|
||||
struct group const *group;
|
||||
{
|
||||
struct file_data const *file = group->file;
|
||||
char const * const *linbuf = file->linbuf;
|
||||
int from = group->from, upto = group->upto;
|
||||
|
||||
if (!out)
|
||||
return;
|
||||
|
||||
/* If possible, use a single fwrite; it's faster. */
|
||||
if (!tab_expand_flag && strcmp (format, "%l\n") == 0)
|
||||
fwrite (linbuf[from], sizeof (char),
|
||||
linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
|
||||
outfile);
|
||||
else if (!tab_expand_flag && strcmp (format, "%L") == 0)
|
||||
fwrite (linbuf[from], sizeof (char), linbuf[upto] - linbuf[from], outfile);
|
||||
else
|
||||
for (; from < upto; from++)
|
||||
{
|
||||
register FILE *out = outfile;
|
||||
register char c;
|
||||
register const char *f = format;
|
||||
if (!tab_expand_flag && format[0] == '%')
|
||||
{
|
||||
if (format[1] == 'l' && format[2] == '\n' && !format[3])
|
||||
{
|
||||
fwrite (linbuf[from], sizeof (char),
|
||||
linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
|
||||
out);
|
||||
return;
|
||||
}
|
||||
if (format[1] == 'L' && !format[2])
|
||||
{
|
||||
fwrite (linbuf[from], sizeof (char),
|
||||
linbuf[upto] - linbuf[from], out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while ((c = *f++) != 0)
|
||||
{
|
||||
if (c == '%')
|
||||
for (; from < upto; from++)
|
||||
{
|
||||
register char c;
|
||||
register char *f = format;
|
||||
|
||||
while ((c = *f++) != 0)
|
||||
{
|
||||
if (c == '%')
|
||||
{
|
||||
char *spec = f;
|
||||
switch ((c = *f++))
|
||||
{
|
||||
case 0:
|
||||
goto format_done;
|
||||
case '%':
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
output_1_line (linbuf[from],
|
||||
@ -168,16 +315,114 @@ print_ifdef_lines (format, current, from, upto)
|
||||
output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
|
||||
continue;
|
||||
|
||||
case '0':
|
||||
c = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
int value;
|
||||
char *speclim;
|
||||
|
||||
f = scan_printf_spec (spec);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
speclim = f;
|
||||
c = *f++;
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
f = scan_char_literal (f, &value);
|
||||
if (!f)
|
||||
goto bad_format;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
value = translate_line_number (file, from);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto bad_format;
|
||||
}
|
||||
/* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
|
||||
*speclim = 0;
|
||||
fprintf (out, spec - 1, value);
|
||||
/* Undo the temporary replacement. */
|
||||
*speclim = c;
|
||||
}
|
||||
continue;
|
||||
|
||||
bad_format:
|
||||
c = '%';
|
||||
f = spec;
|
||||
break;
|
||||
}
|
||||
putc (c, out);
|
||||
}
|
||||
|
||||
format_done:;
|
||||
}
|
||||
}
|
||||
putc (c, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the character literal represented in the string LIT; LIT points just
|
||||
after the initial apostrophe. Put the literal's value into *INTPTR.
|
||||
Yield the address of the first character after the closing apostrophe,
|
||||
or zero if the literal is ill-formed. */
|
||||
static char *
|
||||
scan_char_literal (lit, intptr)
|
||||
char *lit;
|
||||
int *intptr;
|
||||
{
|
||||
register char *p = lit;
|
||||
int value, digits;
|
||||
char c = *p++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
case '\'':
|
||||
return 0;
|
||||
|
||||
case '\\':
|
||||
value = 0;
|
||||
while ((c = *p++) != '\'')
|
||||
{
|
||||
unsigned digit = c - '0';
|
||||
if (8 <= digit)
|
||||
return 0;
|
||||
value = 8 * value + digit;
|
||||
}
|
||||
digits = p - lit - 2;
|
||||
if (! (1 <= digits && digits <= 3))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = c;
|
||||
if (*p++ != '\'')
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
*intptr = value;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
|
||||
Return the address of the character following SPEC, or zero if failure. */
|
||||
static char *
|
||||
scan_printf_spec (spec)
|
||||
register char *spec;
|
||||
{
|
||||
register unsigned char c;
|
||||
|
||||
while ((c = *spec++) == '-')
|
||||
continue;
|
||||
while (isdigit (c))
|
||||
c = *spec++;
|
||||
if (c == '.')
|
||||
while (isdigit (c = *spec++))
|
||||
continue;
|
||||
switch (c)
|
||||
{
|
||||
case 'c': case 'd': case 'o': case 'x': case 'X':
|
||||
return spec;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* File I/O for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -26,51 +26,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/* Given a hash value and a new character, return a new hash value. */
|
||||
#define HASH(h, c) ((c) + ROL (h, 7))
|
||||
|
||||
int line_cmp ();
|
||||
|
||||
/* Guess remaining number of lines from number N of lines so far,
|
||||
size S so far, and total size T. */
|
||||
#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5)
|
||||
|
||||
/* Type used for fast prefix comparison in find_identical_ends. */
|
||||
typedef long word;
|
||||
|
||||
/* Character classes. */
|
||||
const char textchar[] = {
|
||||
/* ISO 8859 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 1, 2, 2, 2, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
typedef int word;
|
||||
|
||||
/* Lines are put into equivalence classes (of lines that match in line_cmp).
|
||||
Each equivalence class is represented by one of these structures,
|
||||
@ -80,8 +41,8 @@ struct equivclass
|
||||
{
|
||||
int next; /* Next item in this bucket. */
|
||||
unsigned hash; /* Hash of lines in this class. */
|
||||
const char *line; /* A line that fits this class. */
|
||||
int length; /* The length of that line. */
|
||||
char const *line; /* A line that fits this class. */
|
||||
size_t length; /* The length of that line. */
|
||||
};
|
||||
|
||||
/* Hash-table: array of buckets, each being a chain of equivalence classes. */
|
||||
@ -100,6 +61,10 @@ static int equivs_index;
|
||||
|
||||
/* Number of elements allocated in the array `equivs'. */
|
||||
static int equivs_alloc;
|
||||
|
||||
static void find_and_hash_each_line PARAMS((struct file_data *));
|
||||
static void find_identical_ends PARAMS((struct file_data[]));
|
||||
static void prepare_text_end PARAMS((struct file_data *));
|
||||
|
||||
/* Check for binary files and compare them for exact identity. */
|
||||
|
||||
@ -121,38 +86,27 @@ sip (current, skip_test)
|
||||
if (current->desc < 0)
|
||||
{
|
||||
/* Leave room for a sentinel. */
|
||||
current->buffer = xmalloc (sizeof (word));
|
||||
current->bufsize = sizeof (word);
|
||||
current->buffered_chars = 0;
|
||||
current->buffer = xmalloc (current->bufsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
current->bufsize = current->buffered_chars
|
||||
= STAT_BLOCKSIZE (current->stat);
|
||||
|
||||
if (S_ISREG (current->stat.st_mode))
|
||||
/* Get the size out of the stat block.
|
||||
Allocate enough room for appended newline and sentinel.
|
||||
Allocate at least one block, to prevent overrunning the buffer
|
||||
when comparing growing binary files. */
|
||||
current->bufsize = max (current->bufsize,
|
||||
current->stat.st_size + sizeof (word) + 1);
|
||||
|
||||
current->bufsize = STAT_BLOCKSIZE (current->stat);
|
||||
current->buffer = xmalloc (current->bufsize);
|
||||
if (skip_test)
|
||||
current->buffered_chars = 0;
|
||||
else
|
||||
|
||||
if (! skip_test)
|
||||
{
|
||||
/* Check first part of file to see if it's a binary file. */
|
||||
current->buffered_chars = read (current->desc,
|
||||
current->buffer,
|
||||
current->buffered_chars);
|
||||
if (current->buffered_chars < 0)
|
||||
current->bufsize);
|
||||
if (current->buffered_chars == -1)
|
||||
pfatal_with_name (current->name);
|
||||
return binary_file_p (current->buffer, current->buffered_chars);
|
||||
}
|
||||
}
|
||||
|
||||
current->buffered_chars = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -162,7 +116,7 @@ void
|
||||
slurp (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
int cc;
|
||||
size_t cc;
|
||||
|
||||
if (current->desc < 0)
|
||||
/* The file is nonexistent. */
|
||||
@ -170,13 +124,22 @@ slurp (current)
|
||||
else if (S_ISREG (current->stat.st_mode))
|
||||
{
|
||||
/* It's a regular file; slurp in the rest all at once. */
|
||||
cc = current->stat.st_size - current->buffered_chars;
|
||||
if (cc)
|
||||
|
||||
/* Get the size out of the stat block.
|
||||
Allocate enough room for appended newline and sentinel. */
|
||||
cc = current->stat.st_size + 1 + sizeof (word);
|
||||
if (current->bufsize < cc)
|
||||
{
|
||||
current->bufsize = cc;
|
||||
current->buffer = xrealloc (current->buffer, cc);
|
||||
}
|
||||
|
||||
if (current->buffered_chars < current->stat.st_size)
|
||||
{
|
||||
cc = read (current->desc,
|
||||
current->buffer + current->buffered_chars,
|
||||
cc);
|
||||
if (cc < 0)
|
||||
current->stat.st_size - current->buffered_chars);
|
||||
if (cc == -1)
|
||||
pfatal_with_name (current->name);
|
||||
current->buffered_chars += cc;
|
||||
}
|
||||
@ -189,21 +152,20 @@ slurp (current)
|
||||
if (current->buffered_chars == current->bufsize)
|
||||
{
|
||||
current->bufsize = current->bufsize * 2;
|
||||
current->buffer = (char *) xrealloc (current->buffer,
|
||||
current->bufsize);
|
||||
current->buffer = xrealloc (current->buffer, current->bufsize);
|
||||
}
|
||||
cc = read (current->desc,
|
||||
current->buffer + current->buffered_chars,
|
||||
current->bufsize - current->buffered_chars);
|
||||
if (cc == 0)
|
||||
break;
|
||||
if (cc < 0)
|
||||
if (cc == -1)
|
||||
pfatal_with_name (current->name);
|
||||
current->buffered_chars += cc;
|
||||
}
|
||||
/* Allocate just enough room for appended newline and sentinel. */
|
||||
current->bufsize = current->buffered_chars + sizeof (word) + 1;
|
||||
current->buffer = (char *) xrealloc (current->buffer, current->bufsize);
|
||||
current->bufsize = current->buffered_chars + 1 + sizeof (word);
|
||||
current->buffer = xrealloc (current->buffer, current->bufsize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,12 +177,13 @@ find_and_hash_each_line (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
unsigned h;
|
||||
const unsigned char *p = (const unsigned char *) current->prefix_end;
|
||||
unsigned char const *p = (unsigned char const *) current->prefix_end;
|
||||
unsigned char c;
|
||||
int i, length, *bucket;
|
||||
int i, *bucket;
|
||||
size_t length;
|
||||
|
||||
/* Cache often-used quantities in local variables to help the compiler. */
|
||||
const char **linbuf = current->linbuf;
|
||||
char const **linbuf = current->linbuf;
|
||||
int alloc_lines = current->alloc_lines;
|
||||
int line = 0;
|
||||
int linbuf_base = current->linbuf_base;
|
||||
@ -228,16 +191,16 @@ find_and_hash_each_line (current)
|
||||
struct equivclass *eqs = equivs;
|
||||
int eqs_index = equivs_index;
|
||||
int eqs_alloc = equivs_alloc;
|
||||
const char *suffix_begin = current->suffix_begin;
|
||||
const char *bufend = current->buffer + current->buffered_chars;
|
||||
const char *incomplete_tail
|
||||
char const *suffix_begin = current->suffix_begin;
|
||||
char const *bufend = current->buffer + current->buffered_chars;
|
||||
char const *incomplete_tail
|
||||
= current->missing_newline && ROBUST_OUTPUT_STYLE (output_style)
|
||||
? bufend : (const char *) 0;
|
||||
? bufend : (char const *) 0;
|
||||
int varies = length_varies;
|
||||
|
||||
while ((const char *) p < suffix_begin)
|
||||
while ((char const *) p < suffix_begin)
|
||||
{
|
||||
const char *ip = (const char *) p;
|
||||
char const *ip = (char const *) p;
|
||||
|
||||
/* Compute the equivalence class for this line. */
|
||||
|
||||
@ -249,18 +212,17 @@ find_and_hash_each_line (current)
|
||||
if (ignore_all_space_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (! Is_space (c))
|
||||
if (! isspace (c))
|
||||
h = HASH (h, isupper (c) ? tolower (c) : c);
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (c == ' ' || c == '\t')
|
||||
if (isspace (c))
|
||||
{
|
||||
while ((c = *p++) == ' ' || c == '\t')
|
||||
;
|
||||
if (c == '\n')
|
||||
break;
|
||||
while (isspace (c = *p++))
|
||||
if (c == '\n')
|
||||
goto hashing_done;
|
||||
h = HASH (h, ' ');
|
||||
}
|
||||
/* C is now the first non-space. */
|
||||
@ -275,18 +237,17 @@ find_and_hash_each_line (current)
|
||||
if (ignore_all_space_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (! Is_space (c))
|
||||
if (! isspace (c))
|
||||
h = HASH (h, c);
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
while ((c = *p++) != '\n')
|
||||
{
|
||||
if (c == ' ' || c == '\t')
|
||||
if (isspace (c))
|
||||
{
|
||||
while ((c = *p++) == ' ' || c == '\t')
|
||||
;
|
||||
if (c == '\n')
|
||||
break;
|
||||
while (isspace (c = *p++))
|
||||
if (c == '\n')
|
||||
goto hashing_done;
|
||||
h = HASH (h, ' ');
|
||||
}
|
||||
/* C is now the first non-space. */
|
||||
@ -296,9 +257,10 @@ find_and_hash_each_line (current)
|
||||
while ((c = *p++) != '\n')
|
||||
h = HASH (h, c);
|
||||
}
|
||||
hashing_done:;
|
||||
|
||||
bucket = &buckets[h % nbuckets];
|
||||
length = (const char *) p - ip - ((const char *) p == incomplete_tail);
|
||||
length = (char const *) p - ip - ((char const *) p == incomplete_tail);
|
||||
for (i = *bucket; ; i = eqs[i].next)
|
||||
if (!i)
|
||||
{
|
||||
@ -326,7 +288,7 @@ find_and_hash_each_line (current)
|
||||
/* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
|
||||
alloc_lines = 2 * alloc_lines - linbuf_base;
|
||||
cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs));
|
||||
linbuf = (const char **) xrealloc (linbuf + linbuf_base,
|
||||
linbuf = (char const **) xrealloc (linbuf + linbuf_base,
|
||||
(alloc_lines - linbuf_base)
|
||||
* sizeof (*linbuf))
|
||||
- linbuf_base;
|
||||
@ -347,16 +309,16 @@ find_and_hash_each_line (current)
|
||||
{
|
||||
/* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */
|
||||
alloc_lines = 2 * alloc_lines - linbuf_base;
|
||||
linbuf = (const char **) xrealloc (linbuf + linbuf_base,
|
||||
linbuf = (char const **) xrealloc (linbuf + linbuf_base,
|
||||
(alloc_lines - linbuf_base)
|
||||
* sizeof (*linbuf))
|
||||
- linbuf_base;
|
||||
}
|
||||
linbuf[line] = (const char *) p;
|
||||
linbuf[line] = (char const *) p;
|
||||
|
||||
if ((const char *) p == bufend)
|
||||
if ((char const *) p == bufend)
|
||||
{
|
||||
linbuf[line] -= (const char *) p == incomplete_tail;
|
||||
linbuf[line] -= (char const *) p == incomplete_tail;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -387,7 +349,7 @@ static void
|
||||
prepare_text_end (current)
|
||||
struct file_data *current;
|
||||
{
|
||||
int buffered_chars = current->buffered_chars;
|
||||
size_t buffered_chars = current->buffered_chars;
|
||||
char *p = current->buffer;
|
||||
|
||||
if (buffered_chars == 0 || p[buffered_chars - 1] == '\n')
|
||||
@ -413,12 +375,12 @@ find_identical_ends (filevec)
|
||||
{
|
||||
word *w0, *w1;
|
||||
char *p0, *p1, *buffer0, *buffer1;
|
||||
const char *end0, *beg0;
|
||||
const char **linbuf0, **linbuf1;
|
||||
char const *end0, *beg0;
|
||||
char const **linbuf0, **linbuf1;
|
||||
int i, lines;
|
||||
int n0, n1, alloc_lines0, alloc_lines1;
|
||||
size_t n0, n1, tem;
|
||||
int alloc_lines0, alloc_lines1;
|
||||
int buffered_prefix, prefix_count, prefix_mask;
|
||||
int tem;
|
||||
|
||||
slurp (&filevec[0]);
|
||||
if (filevec[0].desc != filevec[1].desc)
|
||||
@ -564,7 +526,7 @@ find_identical_ends (filevec)
|
||||
}
|
||||
|
||||
lines = 0;
|
||||
linbuf0 = (const char **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
|
||||
linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
|
||||
|
||||
/* If the prefix is needed, find the prefix lines. */
|
||||
if (! (no_diff_means_no_output
|
||||
@ -577,7 +539,7 @@ find_identical_ends (filevec)
|
||||
{
|
||||
int l = lines++ & prefix_mask;
|
||||
if (l == alloc_lines0)
|
||||
linbuf0 = (const char **) xrealloc (linbuf0, (alloc_lines0 *= 2)
|
||||
linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2)
|
||||
* sizeof(*linbuf0));
|
||||
linbuf0[l] = p0;
|
||||
while (*p0++ != '\n')
|
||||
@ -593,7 +555,7 @@ find_identical_ends (filevec)
|
||||
= (buffered_prefix
|
||||
+ GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem)
|
||||
+ context);
|
||||
linbuf1 = (const char **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
|
||||
linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
|
||||
|
||||
if (buffered_prefix != lines)
|
||||
{
|
||||
@ -621,7 +583,7 @@ find_identical_ends (filevec)
|
||||
/* Largest primes less than some power of two, for nbuckets. Values range
|
||||
from useful to preposterous. If one of these numbers isn't prime
|
||||
after all, don't blame it on me, blame it on primes (6) . . . */
|
||||
static const int primes[] =
|
||||
static int const primes[] =
|
||||
{
|
||||
509,
|
||||
1021,
|
||||
@ -630,6 +592,7 @@ static const int primes[] =
|
||||
8191,
|
||||
16381,
|
||||
32749,
|
||||
#if 32767 < INT_MAX
|
||||
65521,
|
||||
131071,
|
||||
262139,
|
||||
@ -646,20 +609,23 @@ static const int primes[] =
|
||||
536870909,
|
||||
1073741789,
|
||||
2147483647,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
/* Given a vector of two file_data objects, read the file associated
|
||||
with each one, and build the table of equivalence classes.
|
||||
Return 1 if either file appears to be a binary file. */
|
||||
Return 1 if either file appears to be a binary file.
|
||||
If PRETEND_BINARY is nonzero, pretend they are binary regardless. */
|
||||
|
||||
int
|
||||
read_files (filevec)
|
||||
read_files (filevec, pretend_binary)
|
||||
struct file_data filevec[];
|
||||
int pretend_binary;
|
||||
{
|
||||
int i;
|
||||
int skip_test = always_text_flag | no_details_flag;
|
||||
int appears_binary = no_details_flag | sip (&filevec[0], skip_test);
|
||||
int skip_test = always_text_flag | pretend_binary;
|
||||
int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
|
||||
|
||||
if (filevec[0].desc != filevec[1].desc)
|
||||
appears_binary |= sip (&filevec[1], skip_test | appears_binary);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Normal-format output routines for GNU DIFF.
|
||||
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -20,10 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
int change_letter ();
|
||||
void print_normal_hunk ();
|
||||
void print_number_range ();
|
||||
struct change *find_change ();
|
||||
static void print_normal_hunk PARAMS((struct change *));
|
||||
|
||||
/* Print the edit-script SCRIPT as a normal diff.
|
||||
INF points to an array of descriptions of the two files. */
|
||||
@ -39,7 +36,7 @@ print_normal_script (script)
|
||||
This is a contiguous portion of a complete edit script,
|
||||
describing changes in consecutive lines. */
|
||||
|
||||
void
|
||||
static void
|
||||
print_normal_hunk (hunk)
|
||||
struct change *hunk;
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/* Definitions for data structures and routines for the regular
|
||||
expression library, version 0.12.
|
||||
|
||||
Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
Copyright (C) 1985, 89, 90, 91, 92, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* SDIFF -- interactive merge front end to diff
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -19,18 +19,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* GNU SDIFF was written by Thomas Lord. */
|
||||
|
||||
#include "system.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "system.h"
|
||||
#include <signal.h>
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
/* Size of chunks read from files which must be parsed into lines. */
|
||||
#define SDIFF_BUFSIZE 65536
|
||||
#define SDIFF_BUFSIZE ((size_t) 65536)
|
||||
|
||||
/* Default name of the diff program */
|
||||
#ifndef DIFF_PROGRAM
|
||||
@ -42,7 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#define DEFAULT_EDITOR "ed"
|
||||
#endif
|
||||
|
||||
extern char *version_string;
|
||||
extern char version_string[];
|
||||
static char const *prog;
|
||||
static char const *diffbin = DIFF_PROGRAM;
|
||||
static char const *edbin = DEFAULT_EDITOR;
|
||||
@ -52,19 +48,42 @@ static int volatile tmpmade;
|
||||
static pid_t volatile diffpid;
|
||||
|
||||
struct line_filter;
|
||||
static void diffarg (); /* (char *); */
|
||||
static void execdiff (); /* (int, char const *, char const *, char const *); */
|
||||
static int edit (); /* (struct line_filter *left, int lenl, struct
|
||||
line_filter *right, int lenr, FILE *outfile); */
|
||||
static int interact (); /* (struct line_filter *diff,
|
||||
struct line_filter *left,
|
||||
struct line_filter *right, FILE *outfile); */
|
||||
static void trapsigs (); /* (void); */
|
||||
|
||||
static FILE *ck_fdopen PARAMS((int, char const *));
|
||||
static FILE *ck_fopen PARAMS((char const *, char const *));
|
||||
static RETSIGTYPE catchsig PARAMS((int));
|
||||
static VOID *xmalloc PARAMS((size_t));
|
||||
static char const *expand_name PARAMS((char *, int, char const *));
|
||||
static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*));
|
||||
static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*));
|
||||
static int lf_snarf PARAMS((struct line_filter *, char *, size_t));
|
||||
static int skip_white PARAMS((void));
|
||||
static size_t ck_fread PARAMS((char *, size_t, FILE *));
|
||||
static size_t lf_refill PARAMS((struct line_filter *));
|
||||
static void checksigs PARAMS((void));
|
||||
static void ck_fclose PARAMS((FILE *));
|
||||
static void ck_fflush PARAMS((FILE *));
|
||||
static void ck_fwrite PARAMS((char const *, size_t, FILE *));
|
||||
static void cleanup PARAMS((void));
|
||||
static void diffarg PARAMS((char const *));
|
||||
static void execdiff PARAMS((int, char const *, char const *, char const *));
|
||||
static void exiterr PARAMS((void));
|
||||
static void fatal PARAMS((char const *));
|
||||
static void flush_line PARAMS((void));
|
||||
static void give_help PARAMS((void));
|
||||
static void lf_copy PARAMS((struct line_filter *, int, FILE *));
|
||||
static void lf_init PARAMS((struct line_filter *, FILE *));
|
||||
static void lf_skip PARAMS((struct line_filter *, int));
|
||||
static void perror_fatal PARAMS((char const *));
|
||||
static void trapsigs PARAMS((void));
|
||||
static void untrapsig PARAMS((int));
|
||||
static void usage PARAMS((int));
|
||||
|
||||
/* this lossage until the gnu libc conquers the universe */
|
||||
#define TMPNAMSIZE 1024
|
||||
#define PVT_tmpdir "/tmp"
|
||||
static char *private_tempnam (); /* (const char *, const char *, int, int *); */
|
||||
static int diraccess ();
|
||||
static char *private_tempnam PARAMS((char const *, char const *, int, size_t *));
|
||||
static int diraccess PARAMS((char const *));
|
||||
static int exists PARAMS((char const *));
|
||||
|
||||
/* Options: */
|
||||
|
||||
@ -74,38 +93,40 @@ static char *out_file;
|
||||
/* do not print common lines if true, set by -s option */
|
||||
static int suppress_common_flag;
|
||||
|
||||
static struct option longopts[] =
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"ignore-blank-lines", 0, NULL, 'B'},
|
||||
{"speed-large-files", 0, NULL, 'H'},
|
||||
{"ignore-matching-lines", 1, NULL, 'I'},
|
||||
{"ignore-all-space", 0, NULL, 'W'}, /* swap W and w for historical reasons */
|
||||
{"text", 0, NULL, 'a'},
|
||||
{"ignore-space-change", 0, NULL, 'b'},
|
||||
{"minimal", 0, NULL, 'd'},
|
||||
{"ignore-case", 0, NULL, 'i'},
|
||||
{"left-column", 0, NULL, 'l'},
|
||||
{"output", 1, NULL, 'o'},
|
||||
{"suppress-common-lines", 0, NULL, 's'},
|
||||
{"expand-tabs", 0, NULL, 't'},
|
||||
{"width", 1, NULL, 'w'},
|
||||
{"version", 0, NULL, 'v'},
|
||||
{NULL, 0, NULL, 0}
|
||||
{"ignore-blank-lines", 0, 0, 'B'},
|
||||
{"speed-large-files", 0, 0, 'H'},
|
||||
{"ignore-matching-lines", 1, 0, 'I'},
|
||||
{"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
|
||||
{"text", 0, 0, 'a'},
|
||||
{"ignore-space-change", 0, 0, 'b'},
|
||||
{"minimal", 0, 0, 'd'},
|
||||
{"ignore-case", 0, 0, 'i'},
|
||||
{"left-column", 0, 0, 'l'},
|
||||
{"output", 1, 0, 'o'},
|
||||
{"suppress-common-lines", 0, 0, 's'},
|
||||
{"expand-tabs", 0, 0, 't'},
|
||||
{"width", 1, 0, 'w'},
|
||||
{"version", 0, 0, 'v'},
|
||||
{"help", 0, 0, 129},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* prints usage message and quits */
|
||||
static void
|
||||
usage ()
|
||||
usage (status)
|
||||
int status;
|
||||
{
|
||||
fprintf (stderr, "Usage: %s [options] from-file to-file\n", prog);
|
||||
fprintf (stderr, "Options:\n\
|
||||
[-abBdHilstv] [-I regexp] [-o outfile] [-w columns]\n\
|
||||
[--text] [--minimal] [--speed-large-files] [--expand-tabs]\n\
|
||||
[--ignore-case] [--ignore-matching-lines=regexp]\n\
|
||||
[--ignore-space-change] [--ignore-blank-lines] [--ignore-all-space]\n\
|
||||
[--suppress-common-lines] [--left-column] [--output=outfile]\n\
|
||||
[--version] [--width=columns]\n");
|
||||
exit (2);
|
||||
printf ("Usage: %s [options] from-file to-file\n", prog);
|
||||
printf ("Options:\n\
|
||||
[-abBdHilstv] [-I regexp] [-o outfile] [-w columns]\n\
|
||||
[--expand-tabs] [--help] [--ignore-all-space] [--ignore-blank-lines]\n\
|
||||
[--ignore-case] [--ignore-matching-lines=regexp]\n\
|
||||
[--ignore-space-change] [--left-column] [--minimal]\n\
|
||||
[--output=outfile] [--speed-large-files] [--suppress-common-lines]\n\
|
||||
[--text] [--version] [--width=columns]\n");
|
||||
exit (status);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -121,12 +142,14 @@ static void
|
||||
exiterr ()
|
||||
{
|
||||
cleanup ();
|
||||
untrapsig (0);
|
||||
checksigs ();
|
||||
exit (2);
|
||||
}
|
||||
|
||||
static void
|
||||
fatal (msg)
|
||||
char *msg;
|
||||
char const *msg;
|
||||
{
|
||||
fprintf (stderr, "%s: %s\n", prog, msg);
|
||||
exiterr ();
|
||||
@ -134,9 +157,10 @@ fatal (msg)
|
||||
|
||||
static void
|
||||
perror_fatal (msg)
|
||||
char *msg;
|
||||
char const *msg;
|
||||
{
|
||||
int e = errno;
|
||||
checksigs ();
|
||||
fprintf (stderr, "%s: ", prog);
|
||||
errno = e;
|
||||
perror (msg);
|
||||
@ -145,19 +169,19 @@ perror_fatal (msg)
|
||||
|
||||
|
||||
/* malloc freely or DIE! */
|
||||
char *
|
||||
static VOID *
|
||||
xmalloc (size)
|
||||
size_t size;
|
||||
{
|
||||
char *r = malloc (size);
|
||||
VOID *r = (VOID *) malloc (size);
|
||||
if (!r)
|
||||
fatal ("virtual memory exhausted");
|
||||
fatal ("memory exhausted");
|
||||
return r;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
ck_fopen (fname, type)
|
||||
char *fname, *type;
|
||||
char const *fname, *type;
|
||||
{
|
||||
FILE *r = fopen (fname, type);
|
||||
if (!r)
|
||||
@ -169,7 +193,7 @@ ck_fopen (fname, type)
|
||||
static FILE *
|
||||
ck_fdopen (fd, type)
|
||||
int fd;
|
||||
char *type;
|
||||
char const *type;
|
||||
{
|
||||
FILE *r = fdopen (fd, type);
|
||||
if (!r)
|
||||
@ -199,7 +223,7 @@ ck_fread (buf, size, f)
|
||||
|
||||
static void
|
||||
ck_fwrite (buf, size, f)
|
||||
char *buf;
|
||||
char const *buf;
|
||||
size_t size;
|
||||
FILE *f;
|
||||
{
|
||||
@ -218,11 +242,11 @@ ck_fflush (f)
|
||||
#if !HAVE_MEMCHR
|
||||
char *
|
||||
memchr (s, c, n)
|
||||
char *s;
|
||||
char const *s;
|
||||
int c;
|
||||
size_t n;
|
||||
{
|
||||
unsigned char *p = (unsigned char *) s, *lim = p + n;
|
||||
unsigned char const *p = (unsigned char const *) s, *lim = p + n;
|
||||
for (; p < lim; p++)
|
||||
if (*p == c)
|
||||
return (char *) p;
|
||||
@ -273,14 +297,14 @@ expand_name (name, isdir, other_name)
|
||||
else
|
||||
{
|
||||
/* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */
|
||||
const char
|
||||
*p = rindex (other_name, '/'),
|
||||
char const
|
||||
*p = strrchr (other_name, '/'),
|
||||
*base = p ? p+1 : other_name;
|
||||
size_t namelen = strlen (name), baselen = strlen (base);
|
||||
char *r = xmalloc (namelen + baselen + 2);
|
||||
bcopy (name, r, namelen);
|
||||
memcpy (r, name, namelen);
|
||||
r[namelen] = '/';
|
||||
bcopy (base, r + namelen + 1, baselen + 1);
|
||||
memcpy (r + namelen + 1, base, baselen + 1);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@ -313,6 +337,7 @@ lf_refill (lf)
|
||||
lf->bufpos = lf->buffer;
|
||||
lf->buflim = lf->buffer + s;
|
||||
lf->buflim[0] = '\n';
|
||||
checksigs ();
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -327,7 +352,7 @@ lf_copy (lf, lines, outfile)
|
||||
|
||||
while (lines)
|
||||
{
|
||||
lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
|
||||
lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
|
||||
if (! lf->bufpos)
|
||||
{
|
||||
ck_fwrite (start, lf->buflim - start, outfile);
|
||||
@ -353,7 +378,7 @@ lf_skip (lf, lines)
|
||||
{
|
||||
while (lines)
|
||||
{
|
||||
lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
|
||||
lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
|
||||
if (! lf->bufpos)
|
||||
{
|
||||
if (! lf_refill (lf))
|
||||
@ -378,11 +403,11 @@ lf_snarf (lf, buffer, bufsize)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char *next = memchr (start, '\n', lf->buflim + 1 - start);
|
||||
char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);
|
||||
size_t s = next - start;
|
||||
if (bufsize <= s)
|
||||
return 0;
|
||||
bcopy (start, buffer, s);
|
||||
memcpy (buffer, start, s);
|
||||
if (next < lf->buflim)
|
||||
{
|
||||
buffer[s] = 0;
|
||||
@ -405,7 +430,6 @@ main (argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
int opt;
|
||||
int version_requested = 0;
|
||||
char *editor = getenv ("EDITOR");
|
||||
char *differ = getenv ("DIFF");
|
||||
|
||||
@ -418,7 +442,8 @@ main (argc, argv)
|
||||
diffarg ("diff");
|
||||
|
||||
/* parse command line args */
|
||||
while ((opt=getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, (int *)0)) != EOF)
|
||||
while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@ -468,10 +493,8 @@ main (argc, argv)
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
version_requested = 1;
|
||||
fprintf (stderr, "GNU sdiff version %s\n", version_string);
|
||||
ck_fflush (stderr);
|
||||
break;
|
||||
printf ("GNU sdiff version %s\n", version_string);
|
||||
exit (0);
|
||||
|
||||
case 'w':
|
||||
diffarg ("-W");
|
||||
@ -482,17 +505,16 @@ main (argc, argv)
|
||||
diffarg ("-w");
|
||||
break;
|
||||
|
||||
case 129:
|
||||
usage (0);
|
||||
|
||||
default:
|
||||
usage ();
|
||||
usage (2);
|
||||
}
|
||||
}
|
||||
|
||||
/* check: did user just want version message? if so exit. */
|
||||
if (version_requested && argc - optind == 0)
|
||||
exit (0);
|
||||
|
||||
if (argc - optind != 2)
|
||||
usage ();
|
||||
usage (2);
|
||||
|
||||
if (! out_file)
|
||||
/* easy case: diff does everything for us */
|
||||
@ -530,9 +552,9 @@ main (argc, argv)
|
||||
signal (SIGPIPE, SIG_DFL);
|
||||
|
||||
close (diff_fds[0]);
|
||||
if (diff_fds[1] != fileno (stdout))
|
||||
if (diff_fds[1] != STDOUT_FILENO)
|
||||
{
|
||||
dup2 (diff_fds[1], fileno (stdout));
|
||||
dup2 (diff_fds[1], STDOUT_FILENO);
|
||||
close (diff_fds[1]);
|
||||
}
|
||||
|
||||
@ -559,8 +581,11 @@ main (argc, argv)
|
||||
{
|
||||
int wstatus;
|
||||
|
||||
if (waitpid (pid, &wstatus, 0) < 0)
|
||||
perror_fatal ("wait failed");
|
||||
while (waitpid (pid, &wstatus, 0) < 0)
|
||||
if (errno == EINTR)
|
||||
checksigs ();
|
||||
else
|
||||
perror_fatal ("wait failed");
|
||||
diffpid = 0;
|
||||
|
||||
if (tmpmade)
|
||||
@ -570,22 +595,24 @@ main (argc, argv)
|
||||
}
|
||||
|
||||
if (! interact_ok)
|
||||
exit (2);
|
||||
exiterr ();
|
||||
|
||||
if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
|
||||
fatal ("Subsidiary diff failed");
|
||||
|
||||
untrapsig (0);
|
||||
checksigs ();
|
||||
exit (WEXITSTATUS (wstatus));
|
||||
}
|
||||
}
|
||||
return 0; /* Fool -Wall . . . */
|
||||
}
|
||||
|
||||
static char **diffargv;
|
||||
static char const **diffargv;
|
||||
|
||||
static void
|
||||
diffarg (a)
|
||||
char *a;
|
||||
char const *a;
|
||||
{
|
||||
static unsigned diffargs, diffargsmax;
|
||||
|
||||
@ -593,11 +620,12 @@ diffarg (a)
|
||||
{
|
||||
if (! diffargsmax)
|
||||
{
|
||||
diffargv = (char **) xmalloc (sizeof (char));
|
||||
diffargv = (char const **) xmalloc (sizeof (char));
|
||||
diffargsmax = 8;
|
||||
}
|
||||
diffargsmax *= 2;
|
||||
diffargv = (char **) realloc (diffargv, diffargsmax * sizeof (char *));
|
||||
diffargv = (char const **) realloc (diffargv,
|
||||
diffargsmax * sizeof (char const *));
|
||||
if (! diffargv)
|
||||
fatal ("out of memory");
|
||||
}
|
||||
@ -607,7 +635,7 @@ diffarg (a)
|
||||
static void
|
||||
execdiff (differences_only, option, file1, file2)
|
||||
int differences_only;
|
||||
char *option, *file1, *file2;
|
||||
char const *option, *file1, *file2;
|
||||
{
|
||||
if (differences_only)
|
||||
diffarg ("--suppress-common-lines");
|
||||
@ -617,9 +645,9 @@ execdiff (differences_only, option, file1, file2)
|
||||
diffarg (file2);
|
||||
diffarg (0);
|
||||
|
||||
execvp (diffbin, diffargv);
|
||||
write (fileno (stderr), diffbin, strlen (diffbin));
|
||||
write (fileno (stderr), ": not found\n", 12);
|
||||
execvp (diffbin, (char **) diffargv);
|
||||
write (STDERR_FILENO, diffbin, strlen (diffbin));
|
||||
write (STDERR_FILENO, ": not found\n", 12);
|
||||
_exit (2);
|
||||
}
|
||||
|
||||
@ -628,47 +656,120 @@ execdiff (differences_only, option, file1, file2)
|
||||
|
||||
/* Signal handling */
|
||||
|
||||
static int volatile ignore_signals;
|
||||
#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
|
||||
static int const sigs[] = {
|
||||
#ifdef SIGHUP
|
||||
SIGHUP,
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
SIGQUIT,
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
SIGTERM,
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
SIGXCPU,
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
SIGXFSZ,
|
||||
#endif
|
||||
SIGINT,
|
||||
SIGPIPE
|
||||
};
|
||||
|
||||
static void
|
||||
/* Prefer `sigaction' if it is available, since `signal' can lose signals. */
|
||||
#if HAVE_SIGACTION
|
||||
static struct sigaction initial_action[NUM_SIGS];
|
||||
#define initial_handler(i) (initial_action[i].sa_handler)
|
||||
#else
|
||||
static RETSIGTYPE (*initial_action[NUM_SIGS]) ();
|
||||
#define initial_handler(i) (initial_action[i])
|
||||
#endif
|
||||
|
||||
static int volatile ignore_SIGINT;
|
||||
static int volatile signal_received;
|
||||
static int sigs_trapped;
|
||||
|
||||
static RETSIGTYPE
|
||||
catchsig (s)
|
||||
int s;
|
||||
{
|
||||
signal (s, catchsig);
|
||||
if (! ignore_signals)
|
||||
{
|
||||
cleanup ();
|
||||
_exit (2);
|
||||
}
|
||||
#if ! HAVE_SIGACTION
|
||||
signal (s, SIG_IGN);
|
||||
#endif
|
||||
if (! (s == SIGINT && ignore_SIGINT))
|
||||
signal_received = s;
|
||||
}
|
||||
|
||||
static void
|
||||
trapsigs ()
|
||||
{
|
||||
static int const sigs[] = {
|
||||
# ifdef SIGHUP
|
||||
SIGHUP,
|
||||
# endif
|
||||
# ifdef SIGQUIT
|
||||
SIGQUIT,
|
||||
# endif
|
||||
# ifdef SIGTERM
|
||||
SIGTERM,
|
||||
# endif
|
||||
# ifdef SIGXCPU
|
||||
SIGXCPU,
|
||||
# endif
|
||||
# ifdef SIGXFSZ
|
||||
SIGXFSZ,
|
||||
# endif
|
||||
SIGINT,
|
||||
SIGPIPE
|
||||
};
|
||||
int const *p;
|
||||
int i;
|
||||
|
||||
for (p = sigs; p < sigs + sizeof (sigs) / sizeof (*sigs); p++)
|
||||
if (signal (*p, SIG_IGN) != SIG_IGN && signal (*p, catchsig) != SIG_IGN)
|
||||
fatal ("signal error");
|
||||
#if HAVE_SIGACTION
|
||||
struct sigaction catchaction;
|
||||
bzero (&catchaction, sizeof (catchaction));
|
||||
catchaction.sa_handler = catchsig;
|
||||
#ifdef SA_INTERRUPT
|
||||
/* Non-Posix BSD-style systems like SunOS 4.1.x need this
|
||||
so that `read' calls are interrupted properly. */
|
||||
catchaction.sa_flags = SA_INTERRUPT;
|
||||
#endif
|
||||
sigemptyset (&catchaction.sa_mask);
|
||||
for (i = 0; i < NUM_SIGS; i++)
|
||||
sigaddset (&catchaction.sa_mask, sigs[i]);
|
||||
for (i = 0; i < NUM_SIGS; i++)
|
||||
{
|
||||
sigaction (sigs[i], 0, &initial_action[i]);
|
||||
if (initial_handler (i) != SIG_IGN
|
||||
&& sigaction (sigs[i], &catchaction, 0) != 0)
|
||||
fatal ("signal error");
|
||||
}
|
||||
#else /* ! HAVE_SIGACTION */
|
||||
for (i = 0; i < NUM_SIGS; i++)
|
||||
{
|
||||
initial_action[i] = signal (sigs[i], SIG_IGN);
|
||||
if (initial_handler (i) != SIG_IGN
|
||||
&& signal (sigs[i], catchsig) != SIG_IGN)
|
||||
fatal ("signal error");
|
||||
}
|
||||
#endif /* ! HAVE_SIGACTION */
|
||||
sigs_trapped = 1;
|
||||
}
|
||||
|
||||
/* Untrap signal S, or all trapped signals if S is zero. */
|
||||
static void
|
||||
untrapsig (s)
|
||||
int s;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sigs_trapped)
|
||||
for (i = 0; i < NUM_SIGS; i++)
|
||||
if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN)
|
||||
#if HAVE_SIGACTION
|
||||
sigaction (sigs[i], &initial_action[i], 0);
|
||||
#else
|
||||
signal (sigs[i], initial_action[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Exit if a signal has been received. */
|
||||
static void
|
||||
checksigs ()
|
||||
{
|
||||
int s = signal_received;
|
||||
if (s)
|
||||
{
|
||||
cleanup ();
|
||||
|
||||
/* Yield an exit status indicating that a signal was received. */
|
||||
untrapsig (s);
|
||||
kill (getpid (), s);
|
||||
|
||||
/* That didn't work, so exit with error status. */
|
||||
exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -692,7 +793,7 @@ skip_white ()
|
||||
{
|
||||
int c;
|
||||
while (isspace (c = getchar ()) && c != '\n')
|
||||
;
|
||||
checksigs ();
|
||||
if (ferror (stdin))
|
||||
perror_fatal ("input error");
|
||||
return c;
|
||||
@ -723,6 +824,8 @@ edit (left, lenl, right, lenr, outfile)
|
||||
int cmd0, cmd1;
|
||||
int gotcmd = 0;
|
||||
|
||||
cmd1 = 0; /* Pacify `gcc -W'. */
|
||||
|
||||
while (!gotcmd)
|
||||
{
|
||||
if (putchar ('%') != '%')
|
||||
@ -773,8 +876,10 @@ edit (left, lenl, right, lenr, outfile)
|
||||
}
|
||||
/* falls through */
|
||||
default:
|
||||
give_help ();
|
||||
flush_line ();
|
||||
/* falls through */
|
||||
case '\n':
|
||||
give_help ();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -822,7 +927,8 @@ edit (left, lenl, right, lenr, outfile)
|
||||
pid_t pid;
|
||||
int wstatus;
|
||||
|
||||
ignore_signals = 1;
|
||||
ignore_SIGINT = 1;
|
||||
checksigs ();
|
||||
|
||||
pid = vfork ();
|
||||
if (pid == 0)
|
||||
@ -835,8 +941,8 @@ edit (left, lenl, right, lenr, outfile)
|
||||
argv[i++] = 0;
|
||||
|
||||
execvp (edbin, (char **) argv);
|
||||
write (fileno (stderr), edbin, strlen (edbin));
|
||||
write (fileno (stderr), ": not found\n", 12);
|
||||
write (STDERR_FILENO, edbin, strlen (edbin));
|
||||
write (STDERR_FILENO, ": not found\n", 12);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
@ -844,10 +950,12 @@ edit (left, lenl, right, lenr, outfile)
|
||||
perror_fatal ("fork failed");
|
||||
|
||||
while (waitpid (pid, &wstatus, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
if (errno == EINTR)
|
||||
checksigs ();
|
||||
else
|
||||
perror_fatal ("wait failed");
|
||||
|
||||
ignore_signals = 0;
|
||||
ignore_SIGINT = 0;
|
||||
|
||||
if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 1))
|
||||
fatal ("Subsidiary editor failed");
|
||||
@ -858,11 +966,14 @@ edit (left, lenl, right, lenr, outfile)
|
||||
{
|
||||
/* SDIFF_BUFSIZE is too big for a local var
|
||||
in some compilers, so we allocate it dynamically. */
|
||||
char *buf = (char *) xmalloc (SDIFF_BUFSIZE);
|
||||
char *buf = xmalloc (SDIFF_BUFSIZE);
|
||||
size_t size;
|
||||
|
||||
while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
|
||||
ck_fwrite (buf, size, outfile);
|
||||
{
|
||||
checksigs ();
|
||||
ck_fwrite (buf, size, outfile);
|
||||
}
|
||||
ck_fclose (tmp);
|
||||
|
||||
free (buf);
|
||||
@ -878,7 +989,7 @@ edit (left, lenl, right, lenr, outfile)
|
||||
|
||||
|
||||
|
||||
/* Alternately reveal bursts of diff output and handle user editing comands. */
|
||||
/* Alternately reveal bursts of diff output and handle user commands. */
|
||||
static int
|
||||
interact (diff, left, right, outfile)
|
||||
struct line_filter *diff;
|
||||
@ -894,6 +1005,8 @@ interact (diff, left, right, outfile)
|
||||
if (snarfed <= 0)
|
||||
return snarfed;
|
||||
|
||||
checksigs ();
|
||||
|
||||
switch (diff_help[0])
|
||||
{
|
||||
case ' ':
|
||||
@ -902,7 +1015,7 @@ interact (diff, left, right, outfile)
|
||||
case 'i':
|
||||
{
|
||||
int lenl = atoi (diff_help + 1), lenr, lenmax;
|
||||
char *p = index (diff_help, ',');
|
||||
char *p = strchr (diff_help, ',');
|
||||
|
||||
if (!p)
|
||||
fatal (diff_help);
|
||||
@ -921,7 +1034,7 @@ interact (diff, left, right, outfile)
|
||||
case 'c':
|
||||
{
|
||||
int lenl = atoi (diff_help + 1), lenr;
|
||||
char *p = index (diff_help, ',');
|
||||
char *p = strchr (diff_help, ',');
|
||||
|
||||
if (!p)
|
||||
fatal (diff_help);
|
||||
@ -941,10 +1054,10 @@ interact (diff, left, right, outfile)
|
||||
|
||||
|
||||
/* temporary lossage: this is torn from gnu libc */
|
||||
/* Return nonzero if DIR is an existent directory. */
|
||||
/* Return nonzero if DIR is an existing directory. */
|
||||
static int
|
||||
diraccess (dir)
|
||||
const char *dir;
|
||||
char const *dir;
|
||||
{
|
||||
struct stat buf;
|
||||
return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
|
||||
@ -953,21 +1066,21 @@ diraccess (dir)
|
||||
/* Return nonzero if FILE exists. */
|
||||
static int
|
||||
exists (file)
|
||||
const char *file;
|
||||
char const *file;
|
||||
{
|
||||
struct stat buf;
|
||||
return stat (file, &buf) == 0;
|
||||
}
|
||||
|
||||
/* These are the characters used in temporary filenames. */
|
||||
static const char letters[] =
|
||||
static char const letters[] =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
/* Generate a temporary filename.
|
||||
If DIR_SEARCH is nonzero, DIR and PFX are used as
|
||||
described for tempnam. If not, a temporary filename
|
||||
in P_tmpdir with no special prefix is generated. If LENPTR
|
||||
is not NULL, *LENPTR is set the to length (including the
|
||||
is not 0, *LENPTR is set the to length (including the
|
||||
terminating '\0') of the resultant filename, which is returned.
|
||||
This goes through a cyclic pattern of all possible filenames
|
||||
consisting of five decimal digits of the current pid and three
|
||||
@ -976,50 +1089,51 @@ static const char letters[] =
|
||||
prefix (i.e, it is identical to tmpnam), the same data is used.
|
||||
Each potential filename is tested for an already-existing file of
|
||||
the same name, and no name of an existing file will be returned.
|
||||
When the cycle reaches its end (12345ZZZ), NULL is returned. */
|
||||
When the cycle reaches its end (12345ZZZ), 0 is returned. */
|
||||
|
||||
|
||||
static char *
|
||||
private_tempnam (dir, pfx, dir_search, lenptr)
|
||||
const char *dir;
|
||||
const char *pfx;
|
||||
char const *dir;
|
||||
char const *pfx;
|
||||
int dir_search;
|
||||
size_t *lenptr;
|
||||
{
|
||||
static const char tmpdir[] = PVT_tmpdir;
|
||||
static char const tmpdir[] = PVT_tmpdir;
|
||||
static struct
|
||||
{
|
||||
char buf[3];
|
||||
char *s;
|
||||
size_t i;
|
||||
} infos[2], *info;
|
||||
static char buf[TMPNAMSIZE];
|
||||
static char *buf;
|
||||
static size_t bufsize = 1;
|
||||
static pid_t oldpid = 0;
|
||||
pid_t pid = getpid ();
|
||||
register size_t len, plen;
|
||||
|
||||
if (dir_search)
|
||||
{
|
||||
register const char *d = getenv ("TMPDIR");
|
||||
if (d != NULL && !diraccess (d))
|
||||
d = NULL;
|
||||
if (d == NULL && dir != NULL && diraccess (dir))
|
||||
register char const *d = getenv ("TMPDIR");
|
||||
if (d && !diraccess (d))
|
||||
d = 0;
|
||||
if (!d && dir && diraccess (dir))
|
||||
d = dir;
|
||||
if (d == NULL && diraccess (tmpdir))
|
||||
if (!d && diraccess (tmpdir))
|
||||
d = tmpdir;
|
||||
if (d == NULL && diraccess ("/tmp"))
|
||||
if (!d && diraccess ("/tmp"))
|
||||
d = "/tmp";
|
||||
if (d == NULL)
|
||||
if (!d)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
dir = d;
|
||||
}
|
||||
else
|
||||
dir = tmpdir;
|
||||
|
||||
if (pfx != NULL && *pfx != '\0')
|
||||
if (pfx && *pfx)
|
||||
{
|
||||
plen = strlen (pfx);
|
||||
if (plen > 5)
|
||||
@ -1041,11 +1155,23 @@ private_tempnam (dir, pfx, dir_search, lenptr)
|
||||
}
|
||||
|
||||
len = strlen (dir) + 1 + plen + 8;
|
||||
if (bufsize <= len)
|
||||
{
|
||||
do
|
||||
{
|
||||
bufsize *= 2;
|
||||
}
|
||||
while (bufsize <= len);
|
||||
|
||||
if (buf)
|
||||
free (buf);
|
||||
buf = xmalloc (bufsize);
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
*info->s = letters[info->i];
|
||||
sprintf (buf, "%s/%.*s%.5d%.3s", dir, (int) plen, pfx,
|
||||
pid % 100000, info->buf);
|
||||
sprintf (buf, "%s/%.*s%.5lu%.3s", dir, (int) plen, pfx,
|
||||
(unsigned long) pid % 100000, info->buf);
|
||||
if (!exists (buf))
|
||||
break;
|
||||
++info->i;
|
||||
@ -1055,13 +1181,13 @@ private_tempnam (dir, pfx, dir_search, lenptr)
|
||||
if (info->s == &info->buf[2])
|
||||
{
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
++info->s;
|
||||
}
|
||||
}
|
||||
|
||||
if (lenptr != NULL)
|
||||
if (lenptr)
|
||||
*lenptr = len;
|
||||
return buf;
|
||||
}
|
||||
|
@ -21,10 +21,11 @@ and this notice must be preserved on all copies. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
|
||||
static void print_sdiff_hunk ();
|
||||
static void print_sdiff_common_lines ();
|
||||
static void print_1sdiff_line ();
|
||||
static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned));
|
||||
static unsigned tab_from_to PARAMS((unsigned, unsigned));
|
||||
static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *));
|
||||
static void print_sdiff_common_lines PARAMS((int, int));
|
||||
static void print_sdiff_hunk PARAMS((struct change *));
|
||||
|
||||
/* Next line number to be printed in the two input files. */
|
||||
static int next0, next1;
|
||||
@ -70,12 +71,12 @@ tab_from_to (from, to)
|
||||
*/
|
||||
static unsigned
|
||||
print_half_line (line, indent, out_bound)
|
||||
const char * const *line;
|
||||
char const * const *line;
|
||||
unsigned indent, out_bound;
|
||||
{
|
||||
FILE *out = outfile;
|
||||
register unsigned in_position = 0, out_position = 0;
|
||||
register const char
|
||||
register char const
|
||||
*text_pointer = line[0],
|
||||
*text_limit = line[1];
|
||||
|
||||
@ -132,21 +133,21 @@ print_half_line (line, indent, out_bound)
|
||||
|
||||
case '\f':
|
||||
case '\v':
|
||||
control_char:
|
||||
if (in_position < out_bound)
|
||||
putc (c, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
register unsigned p = in_position;
|
||||
if (textchar[c])
|
||||
in_position++;
|
||||
if (p < out_bound)
|
||||
{
|
||||
out_position = in_position;
|
||||
putc (c, out);
|
||||
}
|
||||
}
|
||||
if (! isprint (c))
|
||||
goto control_char;
|
||||
/* falls through */
|
||||
case ' ':
|
||||
if (in_position++ < out_bound)
|
||||
{
|
||||
out_position = in_position;
|
||||
putc (c, out);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
@ -159,15 +160,15 @@ print_half_line (line, indent, out_bound)
|
||||
|
||||
/*
|
||||
* Print side by side lines with a separator in the middle.
|
||||
* NULL parameters are taken to indicate whitespace text.
|
||||
* 0 parameters are taken to indicate white space text.
|
||||
* Blank lines that can easily be caught are reduced to a single newline.
|
||||
*/
|
||||
|
||||
static void
|
||||
print_1sdiff_line (left, sep, right)
|
||||
const char * const *left;
|
||||
char const * const *left;
|
||||
int sep;
|
||||
const char * const *right;
|
||||
char const * const *right;
|
||||
{
|
||||
FILE *out = outfile;
|
||||
unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset;
|
||||
|
@ -17,20 +17,84 @@ You should have received a copy of the GNU General Public License
|
||||
along with GNU DIFF; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* We must define `volatile' and `const' first (the latter inside config.h),
|
||||
so that they're used consistently in all system includes. */
|
||||
#if !__STDC__
|
||||
#ifndef volatile
|
||||
#define volatile
|
||||
#endif
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if __STDC__
|
||||
#define PARAMS(args) args
|
||||
#define VOID void
|
||||
#else
|
||||
#define PARAMS(args) ()
|
||||
#define VOID char
|
||||
#endif
|
||||
|
||||
#if STAT_MACROS_BROKEN
|
||||
#undef S_ISBLK
|
||||
#undef S_ISCHR
|
||||
#undef S_ISDIR
|
||||
#undef S_ISFIFO
|
||||
#undef S_ISREG
|
||||
#undef S_ISSOCK
|
||||
#endif
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#if !defined(S_ISBLK) && defined(S_IFBLK)
|
||||
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
|
||||
#endif
|
||||
#if !defined(S_ISCHR) && defined(S_IFCHR)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||
#endif
|
||||
#if !defined(S_ISFIFO) && defined(S_IFFIFO)
|
||||
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
|
||||
#endif
|
||||
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
|
||||
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
|
||||
#endif
|
||||
|
||||
#ifndef S_IXOTH
|
||||
#define S_IXOTH 1
|
||||
#endif
|
||||
#ifndef S_IXGRP
|
||||
#define S_IXGRP (S_IXOTH << 3)
|
||||
#endif
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR (S_IXGRP << 3)
|
||||
#endif
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#if HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#else
|
||||
@ -73,15 +137,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#if HAVE_ST_BLKSIZE
|
||||
#define STAT_BLOCKSIZE(s) (s).st_blksize
|
||||
#else
|
||||
#define STAT_BLOCKSIZE(s) (S_ISREG ((s).st_mode) ? 8192 : 4096)
|
||||
#define STAT_BLOCKSIZE(s) (8 * 1024)
|
||||
#endif
|
||||
|
||||
#if DIRENT || defined (_POSIX_VERSION)
|
||||
#include <dirent.h>
|
||||
#ifdef direct
|
||||
#undef direct
|
||||
#endif
|
||||
#define direct dirent
|
||||
#else /* ! (DIRENT || defined (_POSIX_VERSION)) */
|
||||
#if SYSNDIR
|
||||
#include <sys/ndir.h>
|
||||
@ -92,49 +152,58 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <ndir.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef dirent
|
||||
#undef dirent
|
||||
#endif
|
||||
#define dirent direct
|
||||
#endif /* ! (DIRENT || defined (_POSIX_VERSION)) */
|
||||
|
||||
#if HAVE_VFORK_H
|
||||
#include <vfork.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H || STDC_HEADERS
|
||||
#include <string.h>
|
||||
#ifndef index
|
||||
#define index strchr
|
||||
#endif
|
||||
#ifndef rindex
|
||||
#define rindex strrchr
|
||||
#endif
|
||||
#ifndef bcopy
|
||||
#define bcopy(s,d,n) memcpy (d,s,n)
|
||||
#endif
|
||||
#ifndef bcmp
|
||||
#define bcmp(s1,s2,n) memcmp (s1,s2,n)
|
||||
#endif
|
||||
#ifndef bzero
|
||||
#define bzero(s,n) memset (s,0,n)
|
||||
#endif
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <strings.h>
|
||||
VOID *malloc ();
|
||||
VOID *realloc ();
|
||||
#endif
|
||||
#if !HAVE_MEMCHR && !STDC_HEADERS
|
||||
char *memchr ();
|
||||
#ifndef getenv
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#else
|
||||
char *getenv ();
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
#if __STDC__ || __GNUC__
|
||||
#include "limits.h"
|
||||
#else
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 2147483647
|
||||
#endif
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#ifndef bzero
|
||||
#define bzero(s,n) memset (s,0,n)
|
||||
#endif
|
||||
#else /* !HAVE_STRING_H */
|
||||
#include <strings.h>
|
||||
#ifndef strchr
|
||||
#define strchr index
|
||||
#endif
|
||||
#ifndef strrchr
|
||||
#define strrchr rindex
|
||||
#endif
|
||||
#ifndef memcpy
|
||||
#define memcpy(d,s,n) bcopy (s,d,n)
|
||||
#endif
|
||||
#ifndef memcmp
|
||||
#define memcmp(s1,s2,n) bcmp (s1,s2,n)
|
||||
#endif
|
||||
#endif /* !HAVE_STRING_H */
|
||||
#if !HAVE_MEMCHR
|
||||
char *memchr ();
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
@ -142,18 +211,5 @@ char *realloc ();
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#if !__STDC__
|
||||
#define volatile
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Support routines for GNU DIFF.
|
||||
Copyright (C) 1988, 1989, 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU DIFF.
|
||||
|
||||
@ -19,12 +19,33 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "diff.h"
|
||||
|
||||
/* Queue up one-line messages to be printed at the end,
|
||||
when -l is specified. Each message is recorded with a `struct msg'. */
|
||||
|
||||
struct msg
|
||||
{
|
||||
struct msg *next;
|
||||
char const *format;
|
||||
char const *arg1;
|
||||
char const *arg2;
|
||||
char const *arg3;
|
||||
char const *arg4;
|
||||
};
|
||||
|
||||
/* Head of the chain of queues messages. */
|
||||
|
||||
static struct msg *msg_chain;
|
||||
|
||||
/* Tail of the chain of queues messages. */
|
||||
|
||||
static struct msg **msg_chain_end = &msg_chain;
|
||||
|
||||
/* Use when a system call returns non-zero status.
|
||||
TEXT should normally be the file name. */
|
||||
|
||||
void
|
||||
perror_with_name (text)
|
||||
char *text;
|
||||
char const *text;
|
||||
{
|
||||
int e = errno;
|
||||
fprintf (stderr, "%s: ", program);
|
||||
@ -36,7 +57,7 @@ perror_with_name (text)
|
||||
|
||||
void
|
||||
pfatal_with_name (text)
|
||||
char *text;
|
||||
char const *text;
|
||||
{
|
||||
int e = errno;
|
||||
print_message_queue ();
|
||||
@ -51,9 +72,7 @@ pfatal_with_name (text)
|
||||
|
||||
void
|
||||
error (format, arg, arg1)
|
||||
char *format;
|
||||
char *arg;
|
||||
char *arg1;
|
||||
char const *format, *arg, *arg1;
|
||||
{
|
||||
fprintf (stderr, "%s: ", program);
|
||||
fprintf (stderr, format, arg, arg1);
|
||||
@ -64,7 +83,7 @@ error (format, arg, arg1)
|
||||
|
||||
void
|
||||
fatal (m)
|
||||
char *m;
|
||||
char const *m;
|
||||
{
|
||||
print_message_queue ();
|
||||
error ("%s", m, 0);
|
||||
@ -76,28 +95,32 @@ fatal (m)
|
||||
|
||||
void
|
||||
message (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
char const *format, *arg1, *arg2;
|
||||
{
|
||||
message5 (format, arg1, arg2, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
message5 (format, arg1, arg2, arg3, arg4)
|
||||
char const *format, *arg1, *arg2, *arg3, *arg4;
|
||||
{
|
||||
if (paginate_flag)
|
||||
{
|
||||
struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
|
||||
if (msg_chain_end == 0)
|
||||
msg_chain = msg_chain_end = new;
|
||||
else
|
||||
{
|
||||
msg_chain_end->next = new;
|
||||
msg_chain_end = new;
|
||||
}
|
||||
new->format = format;
|
||||
new->arg1 = concat (arg1, "", "");
|
||||
new->arg2 = concat (arg2, "", "");
|
||||
new->arg3 = arg3 ? concat (arg3, "", "") : 0;
|
||||
new->arg4 = arg4 ? concat (arg4, "", "") : 0;
|
||||
new->next = 0;
|
||||
*msg_chain_end = new;
|
||||
msg_chain_end = &new->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sdiff_help_sdiff)
|
||||
putchar (' ');
|
||||
printf (format, arg1, arg2);
|
||||
printf (format, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +132,7 @@ print_message_queue ()
|
||||
struct msg *m;
|
||||
|
||||
for (m = msg_chain; m; m = m->next)
|
||||
printf (m->format, m->arg1, m->arg2);
|
||||
printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
|
||||
}
|
||||
|
||||
/* Call before outputting the results of comparing files NAME0 and NAME1
|
||||
@ -119,13 +142,13 @@ print_message_queue ()
|
||||
we fork off a `pr' and make OUTFILE a pipe to it.
|
||||
`pr' then outputs to our stdout. */
|
||||
|
||||
static char *current_name0;
|
||||
static char *current_name1;
|
||||
static char const *current_name0;
|
||||
static char const *current_name1;
|
||||
static int current_depth;
|
||||
|
||||
void
|
||||
setup_output (name0, name1, depth)
|
||||
char *name0, *name1;
|
||||
char const *name0, *name1;
|
||||
int depth;
|
||||
{
|
||||
current_name0 = name0;
|
||||
@ -134,6 +157,8 @@ setup_output (name0, name1, depth)
|
||||
outfile = 0;
|
||||
}
|
||||
|
||||
static pid_t pr_pid;
|
||||
|
||||
void
|
||||
begin_output ()
|
||||
{
|
||||
@ -143,49 +168,47 @@ begin_output ()
|
||||
return;
|
||||
|
||||
/* Construct the header of this piece of diff. */
|
||||
name = (char *) xmalloc (strlen (current_name0) + strlen (current_name1)
|
||||
+ strlen (switch_string) + 15);
|
||||
|
||||
strcpy (name, "diff");
|
||||
strcat (name, switch_string);
|
||||
strcat (name, " ");
|
||||
strcat (name, current_name0);
|
||||
strcat (name, " ");
|
||||
strcat (name, current_name1);
|
||||
name = xmalloc (strlen (current_name0) + strlen (current_name1)
|
||||
+ strlen (switch_string) + 7);
|
||||
/* Posix.2 section 4.17.6.1.1 specifies this format. But there are some
|
||||
bugs in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
|
||||
it says that we must print only the last component of the pathnames,
|
||||
and it requires two spaces after "diff" if there are no options.
|
||||
These requirements are silly and do not match historical practice. */
|
||||
sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
|
||||
|
||||
if (paginate_flag)
|
||||
{
|
||||
int pipes[2];
|
||||
int desc;
|
||||
|
||||
/* For a `pr' and make OUTFILE a pipe to it. */
|
||||
/* Fork a `pr' and make OUTFILE a pipe to it. */
|
||||
if (pipe (pipes) < 0)
|
||||
pfatal_with_name ("pipe");
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
desc = vfork ();
|
||||
if (desc < 0)
|
||||
pr_pid = vfork ();
|
||||
if (pr_pid < 0)
|
||||
pfatal_with_name ("vfork");
|
||||
|
||||
if (desc == 0)
|
||||
if (pr_pid == 0)
|
||||
{
|
||||
close (pipes[1]);
|
||||
if (pipes[0] != fileno (stdin))
|
||||
if (pipes[0] != STDIN_FILENO)
|
||||
{
|
||||
if (dup2 (pipes[0], fileno (stdin)) < 0)
|
||||
if (dup2 (pipes[0], STDIN_FILENO) < 0)
|
||||
pfatal_with_name ("dup2");
|
||||
close (pipes[0]);
|
||||
}
|
||||
|
||||
if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0)
|
||||
pfatal_with_name (PR_FILE_NAME);
|
||||
execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0);
|
||||
pfatal_with_name (PR_FILE_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
close (pipes[0]);
|
||||
outfile = fdopen (pipes[1], "w");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -226,8 +249,25 @@ finish_output ()
|
||||
{
|
||||
if (outfile != 0 && outfile != stdout)
|
||||
{
|
||||
fclose (outfile);
|
||||
wait (0);
|
||||
int wstatus;
|
||||
if (ferror (outfile))
|
||||
fatal ("write error");
|
||||
if (fclose (outfile) != 0)
|
||||
pfatal_with_name ("write error");
|
||||
#if HAVE_WAITPID
|
||||
if (waitpid (pr_pid, &wstatus, 0) < 0)
|
||||
pfatal_with_name ("waitpid");
|
||||
#else
|
||||
for (;;) {
|
||||
pid_t w = wait (&wstatus);
|
||||
if (w < 0)
|
||||
pfatal_with_name ("wait");
|
||||
if (w == pr_pid)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (! WIFEXITED (wstatus) || WEXITSTATUS (wstatus) != 0)
|
||||
fatal ("subsidiary pr failed");
|
||||
}
|
||||
|
||||
outfile = 0;
|
||||
@ -235,14 +275,14 @@ finish_output ()
|
||||
|
||||
/* Compare two lines (typically one from each input file)
|
||||
according to the command line options.
|
||||
Return 1 if the lines differ, like `bcmp'. */
|
||||
Return 1 if the lines differ, like `memcmp'. */
|
||||
|
||||
int
|
||||
line_cmp (s1, len1, s2, len2)
|
||||
const char *s1, *s2;
|
||||
int len1, len2;
|
||||
char const *s1, *s2;
|
||||
size_t len1, len2;
|
||||
{
|
||||
register const unsigned char *t1, *t2;
|
||||
register unsigned char const *t1, *t2;
|
||||
register unsigned char end_char = line_end_char;
|
||||
|
||||
/* Check first for exact identity.
|
||||
@ -250,43 +290,41 @@ line_cmp (s1, len1, s2, len2)
|
||||
This detects the common case of exact identity
|
||||
faster than complete comparison would. */
|
||||
|
||||
if (len1 == len2 && bcmp (s1, s2, len1) == 0)
|
||||
if (len1 == len2 && memcmp (s1, s2, len1) == 0)
|
||||
return 0;
|
||||
|
||||
/* Not exactly identical, but perhaps they match anyway
|
||||
when case or whitespace is ignored. */
|
||||
when case or white space is ignored. */
|
||||
|
||||
if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag)
|
||||
if (ignore_case_flag | ignore_space_change_flag | ignore_all_space_flag)
|
||||
{
|
||||
t1 = (const unsigned char *) s1;
|
||||
t2 = (const unsigned char *) s2;
|
||||
t1 = (unsigned char const *) s1;
|
||||
t2 = (unsigned char const *) s2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
register unsigned char c1 = *t1++;
|
||||
register unsigned char c2 = *t2++;
|
||||
|
||||
/* Ignore horizontal whitespace if -b or -w is specified. */
|
||||
/* Ignore horizontal white space if -b or -w is specified. */
|
||||
|
||||
if (ignore_all_space_flag)
|
||||
{
|
||||
/* For -w, just skip past any white space. */
|
||||
while (Is_space (c1)) c1 = *t1++;
|
||||
while (Is_space (c2)) c2 = *t2++;
|
||||
while (isspace (c1) && c1 != end_char) c1 = *t1++;
|
||||
while (isspace (c2) && c2 != end_char) c2 = *t2++;
|
||||
}
|
||||
else if (ignore_space_change_flag)
|
||||
{
|
||||
/* For -b, advance past any sequence of whitespace in line 1
|
||||
/* For -b, advance past any sequence of white space in line 1
|
||||
and consider it just one Space, or nothing at all
|
||||
if it is at the end of the line. */
|
||||
if (c1 == ' ' || c1 == '\t')
|
||||
if (isspace (c1))
|
||||
{
|
||||
while (1)
|
||||
while (c1 != end_char)
|
||||
{
|
||||
c1 = *t1++;
|
||||
if (c1 == end_char)
|
||||
break;
|
||||
if (c1 != ' ' && c1 != '\t')
|
||||
if (! isspace (c1))
|
||||
{
|
||||
--t1;
|
||||
c1 = ' ';
|
||||
@ -296,14 +334,12 @@ line_cmp (s1, len1, s2, len2)
|
||||
}
|
||||
|
||||
/* Likewise for line 2. */
|
||||
if (c2 == ' ' || c2 == '\t')
|
||||
if (isspace (c2))
|
||||
{
|
||||
while (1)
|
||||
while (c2 != end_char)
|
||||
{
|
||||
c2 = *t2++;
|
||||
if (c2 == end_char)
|
||||
break;
|
||||
if (c2 != ' ' && c2 != '\t')
|
||||
if (! isspace (c2))
|
||||
{
|
||||
--t2;
|
||||
c2 = ' ';
|
||||
@ -364,8 +400,8 @@ find_reverse_change (start)
|
||||
void
|
||||
print_script (script, hunkfun, printfun)
|
||||
struct change *script;
|
||||
struct change * (*hunkfun) ();
|
||||
void (*printfun) ();
|
||||
struct change * (*hunkfun) PARAMS((struct change *));
|
||||
void (*printfun) PARAMS((struct change *));
|
||||
{
|
||||
struct change *next = script;
|
||||
|
||||
@ -380,7 +416,7 @@ print_script (script, hunkfun, printfun)
|
||||
/* Disconnect them from the rest of the changes,
|
||||
making them a hunk, and remember the rest for next iteration. */
|
||||
next = end->link;
|
||||
end->link = NULL;
|
||||
end->link = 0;
|
||||
#ifdef DEBUG
|
||||
debug_script (this);
|
||||
#endif
|
||||
@ -399,18 +435,18 @@ print_script (script, hunkfun, printfun)
|
||||
|
||||
void
|
||||
print_1_line (line_flag, line)
|
||||
const char *line_flag;
|
||||
const char * const *line;
|
||||
char const *line_flag;
|
||||
char const * const *line;
|
||||
{
|
||||
const char *text = line[0], *limit = line[1]; /* Help the compiler. */
|
||||
char const *text = line[0], *limit = line[1]; /* Help the compiler. */
|
||||
FILE *out = outfile; /* Help the compiler some more. */
|
||||
const char *flag_format = 0;
|
||||
char const *flag_format = 0;
|
||||
|
||||
/* If -T was specified, use a Tab between the line-flag and the text.
|
||||
Otherwise use a Space (as Unix diff does).
|
||||
Print neither space nor tab if line-flags are empty. */
|
||||
|
||||
if (line_flag != NULL && line_flag[0] != 0)
|
||||
if (line_flag && *line_flag)
|
||||
{
|
||||
flag_format = tab_align_flag ? "%s\t" : "%s ";
|
||||
fprintf (out, flag_format, line_flag);
|
||||
@ -418,7 +454,7 @@ print_1_line (line_flag, line)
|
||||
|
||||
output_1_line (text, limit, flag_format, line_flag);
|
||||
|
||||
if ((line_flag == NULL || line_flag[0] != 0) && limit[-1] != '\n'
|
||||
if ((!line_flag || line_flag[0]) && limit[-1] != '\n'
|
||||
&& line_end_char == '\n')
|
||||
fprintf (out, "\n\\ No newline at end of file\n");
|
||||
}
|
||||
@ -430,15 +466,15 @@ print_1_line (line_flag, line)
|
||||
|
||||
void
|
||||
output_1_line (text, limit, flag_format, line_flag)
|
||||
const char *text, *limit, *flag_format, *line_flag;
|
||||
char const *text, *limit, *flag_format, *line_flag;
|
||||
{
|
||||
if (!tab_expand_flag)
|
||||
fwrite (text, sizeof (char), limit - text, outfile);
|
||||
else
|
||||
{
|
||||
register FILE *out = outfile;
|
||||
register char c;
|
||||
register const char *t = text;
|
||||
register unsigned char c;
|
||||
register char const *t = text;
|
||||
register unsigned column = 0;
|
||||
|
||||
while (t < limit)
|
||||
@ -469,11 +505,8 @@ output_1_line (text, limit, flag_format, line_flag)
|
||||
break;
|
||||
|
||||
default:
|
||||
if (textchar[(unsigned char) c])
|
||||
if (isprint (c))
|
||||
column++;
|
||||
/* fall into */
|
||||
case '\f':
|
||||
case '\v':
|
||||
putc (c, out);
|
||||
break;
|
||||
}
|
||||
@ -501,7 +534,7 @@ change_letter (inserts, deletes)
|
||||
|
||||
int
|
||||
translate_line_number (file, lnum)
|
||||
struct file_data *file;
|
||||
struct file_data const *file;
|
||||
int lnum;
|
||||
{
|
||||
return lnum + file->prefix_lines + 1;
|
||||
@ -509,7 +542,7 @@ translate_line_number (file, lnum)
|
||||
|
||||
void
|
||||
translate_range (file, a, b, aptr, bptr)
|
||||
struct file_data *file;
|
||||
struct file_data const *file;
|
||||
int a, b;
|
||||
int *aptr, *bptr;
|
||||
{
|
||||
@ -544,7 +577,7 @@ print_number_range (sepchar, file, a, b)
|
||||
/* Look at a hunk of edit script and report the range of lines in each file
|
||||
that it applies to. HUNK is the start of the hunk, which is a chain
|
||||
of `struct change'. The first and last line numbers of file 0 are stored in
|
||||
*FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
|
||||
*FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
|
||||
Note that these are internal line numbers that count from 0.
|
||||
|
||||
If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
|
||||
@ -560,28 +593,29 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
|
||||
int *first0, *last0, *first1, *last1;
|
||||
int *deletes, *inserts;
|
||||
{
|
||||
int f0, l0, f1, l1, show_from, show_to;
|
||||
int l0, l1, show_from, show_to;
|
||||
int i;
|
||||
int nontrivial = !(ignore_blank_lines_flag || ignore_regexp_list);
|
||||
int trivial = ignore_blank_lines_flag || ignore_regexp_list;
|
||||
struct change *next;
|
||||
|
||||
show_from = show_to = 0;
|
||||
|
||||
f0 = hunk->line0;
|
||||
f1 = hunk->line1;
|
||||
*first0 = hunk->line0;
|
||||
*first1 = hunk->line1;
|
||||
|
||||
for (next = hunk; next; next = next->link)
|
||||
next = hunk;
|
||||
do
|
||||
{
|
||||
l0 = next->line0 + next->deleted - 1;
|
||||
l1 = next->line1 + next->inserted - 1;
|
||||
show_from += next->deleted;
|
||||
show_to += next->inserted;
|
||||
|
||||
for (i = next->line0; i <= l0 && ! nontrivial; i++)
|
||||
for (i = next->line0; i <= l0 && trivial; i++)
|
||||
if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
|
||||
{
|
||||
struct regexp_list *r;
|
||||
const char *line = files[0].linbuf[i];
|
||||
char const *line = files[0].linbuf[i];
|
||||
int len = files[0].linbuf[i + 1] - line;
|
||||
|
||||
for (r = ignore_regexp_list; r; r = r->next)
|
||||
@ -589,15 +623,15 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
|
||||
break; /* Found a match. Ignore this line. */
|
||||
/* If we got all the way through the regexp list without
|
||||
finding a match, then it's nontrivial. */
|
||||
if (r == NULL)
|
||||
nontrivial = 1;
|
||||
if (!r)
|
||||
trivial = 0;
|
||||
}
|
||||
|
||||
for (i = next->line1; i <= l1 && ! nontrivial; i++)
|
||||
for (i = next->line1; i <= l1 && trivial; i++)
|
||||
if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
|
||||
{
|
||||
struct regexp_list *r;
|
||||
const char *line = files[1].linbuf[i];
|
||||
char const *line = files[1].linbuf[i];
|
||||
int len = files[1].linbuf[i + 1] - line;
|
||||
|
||||
for (r = ignore_regexp_list; r; r = r->next)
|
||||
@ -605,20 +639,19 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
|
||||
break; /* Found a match. Ignore this line. */
|
||||
/* If we got all the way through the regexp list without
|
||||
finding a match, then it's nontrivial. */
|
||||
if (r == NULL)
|
||||
nontrivial = 1;
|
||||
if (!r)
|
||||
trivial = 0;
|
||||
}
|
||||
}
|
||||
while ((next = next->link) != 0);
|
||||
|
||||
*first0 = f0;
|
||||
*last0 = l0;
|
||||
*first1 = f1;
|
||||
*last1 = l1;
|
||||
|
||||
/* If all inserted or deleted lines are ignorable,
|
||||
tell the caller to ignore this hunk. */
|
||||
|
||||
if (!nontrivial)
|
||||
if (trivial)
|
||||
show_from = show_to = 0;
|
||||
|
||||
*deletes = show_from;
|
||||
@ -629,7 +662,7 @@ analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
|
||||
|
||||
VOID *
|
||||
xmalloc (size)
|
||||
unsigned size;
|
||||
size_t size;
|
||||
{
|
||||
register VOID *value;
|
||||
|
||||
@ -639,7 +672,7 @@ xmalloc (size)
|
||||
value = (VOID *) malloc (size);
|
||||
|
||||
if (!value)
|
||||
fatal ("virtual memory exhausted");
|
||||
fatal ("memory exhausted");
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -648,7 +681,7 @@ xmalloc (size)
|
||||
VOID *
|
||||
xrealloc (old, size)
|
||||
VOID *old;
|
||||
unsigned int size;
|
||||
size_t size;
|
||||
{
|
||||
register VOID *value;
|
||||
|
||||
@ -658,7 +691,7 @@ xrealloc (old, size)
|
||||
value = (VOID *) realloc (old, size);
|
||||
|
||||
if (!value)
|
||||
fatal ("virtual memory exhausted");
|
||||
fatal ("memory exhausted");
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -666,15 +699,23 @@ xrealloc (old, size)
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
char const *s1, *s2, *s3;
|
||||
{
|
||||
int len = strlen (s1) + strlen (s2) + strlen (s3);
|
||||
char *new = (char *) xmalloc (len + 1);
|
||||
strcpy (new, s1);
|
||||
strcat (new, s2);
|
||||
strcat (new, s3);
|
||||
size_t len = strlen (s1) + strlen (s2) + strlen (s3);
|
||||
char *new = xmalloc (len + 1);
|
||||
sprintf (new, "%s%s%s", s1, s2, s3);
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Yield the newly malloc'd pathname
|
||||
of the file in DIR whose filename is FILE. */
|
||||
|
||||
char *
|
||||
dir_file_pathname (dir, file)
|
||||
char const *dir, *file;
|
||||
{
|
||||
return concat (dir, "/" + (*dir && dir[strlen (dir) - 1] == '/'), file);
|
||||
}
|
||||
|
||||
void
|
||||
debug_script (sp)
|
||||
@ -690,11 +731,11 @@ debug_script (sp)
|
||||
#if !HAVE_MEMCHR
|
||||
char *
|
||||
memchr (s, c, n)
|
||||
char *s;
|
||||
char const *s;
|
||||
int c;
|
||||
size_t n;
|
||||
{
|
||||
unsigned char *p = (unsigned char *) s, *lim = p + n;
|
||||
unsigned char const *p = (unsigned char const *) s, *lim = p + n;
|
||||
for (; p < lim; p++)
|
||||
if (*p == c)
|
||||
return (char *) p;
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* Version number of GNU diff. */
|
||||
|
||||
char *version_string = "2.3";
|
||||
#include "config.h"
|
||||
|
||||
char const version_string[] = "2.6";
|
||||
|
@ -1,10 +1,7 @@
|
||||
PROG= diff3
|
||||
SRCS= diff3.c getopt.c getopt1.c version.c
|
||||
CFLAGS+= -I$(.CURDIR)/../diff\
|
||||
-DDIRENT=1 -DHAVE_UNISTD_H=1 -DHAVE_DUP2=1 -DHAVE_MEMCHR=1\
|
||||
-DHAVE_STRERROR=1 -DHAVE_WAITPID=1 -DHAVE_FCNTL_H=1\
|
||||
-DHAVE_STRING_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_TIME_H=1\
|
||||
-DHAVE_ST_BLKSIZE=1 -DDIFF_PROGRAM=\"/usr/bin/diff\"
|
||||
CFLAGS+= -I$(.CURDIR)/../diff -DHAVE_CONFIG_H \
|
||||
-DDIFF_PROGRAM=\"/usr/bin/diff\"
|
||||
MAN= diff3.1
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user