📄 analyze.c
字号:
/* This should be impossible, because it implies that
one of the two subsequences is empty,
and that case was handled above without calling `diag'.
Let's verify that this is true. */
abort ();
#if 0
/* The two subsequences differ by a single insert or delete;
record it and we are done. */
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[part.xmid]] = 1;
#endif
}
else
{
/* 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);
}
}
}
/* Discard lines from one file that have no matches in the other file.
A line which is discarded will not be considered by the actual
comparison algorithm; it will be as if that line were not in the file.
The file's `realindexes' table maps virtual line numbers
(which don't count the discarded lines) into real line numbers;
this is how the actual comparison algorithm produces results
that are comprehensible when the discarded lines are counted.
When we discard a line, we also mark it as a deletion or insertion
so that it will be printed in the output. */
static void
discard_confusing_lines (struct file_data filevec[])
{
unsigned int f, i;
char *discarded[2];
int *equiv_count[2];
int *p;
/* Allocate our results. */
p = (int *) xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines)
* (2 * sizeof (int)));
for (f = 0; f < 2; f++)
{
filevec[f].undiscarded = p; p += filevec[f].buffered_lines;
filevec[f].realindexes = p; p += filevec[f].buffered_lines;
}
/* Set up equiv_count[F][I] as the number of lines in file F
that fall in equivalence class I. */
p = (int *) xmalloc (filevec[0].equiv_max * (2 * sizeof (int)));
equiv_count[0] = p;
equiv_count[1] = p + filevec[0].equiv_max;
bzero (p, filevec[0].equiv_max * (2 * sizeof (int)));
for (i = 0; i < (unsigned int)filevec[0].buffered_lines; ++i)
++equiv_count[0][filevec[0].equivs[i]];
for (i = 0; i < (unsigned int)filevec[1].buffered_lines; ++i)
++equiv_count[1][filevec[1].equivs[i]];
/* Set up tables of which lines are going to be discarded. */
discarded[0] = xmalloc (sizeof (char)
* (filevec[0].buffered_lines
+ filevec[1].buffered_lines));
discarded[1] = discarded[0] + filevec[0].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. */
for (f = 0; f < 2; f++)
{
unsigned int end = filevec[f].buffered_lines;
char *discards = discarded[f];
int *counts = equiv_count[1 - f];
int *equivs = filevec[f].equivs;
unsigned int many = 5;
unsigned int tem = end / 64;
/* Multiply MANY by approximate square root of number of lines.
That is the threshold for provisionally discardable lines. */
while ((tem = tem >> 2) > 0)
many *= 2;
for (i = 0; i < end; i++)
{
int nmatch;
if (equivs[i] == 0)
continue;
nmatch = counts[equivs[i]];
if (nmatch == 0)
discards[i] = 1;
else if (nmatch > (int)many)
discards[i] = 2;
}
}
/* Don't really discard the provisional lines except when they occur
in a run of discardables, with nonprovisionals at the beginning
and end. */
for (f = 0; f < 2; f++)
{
unsigned int end = filevec[f].buffered_lines;
register char *discards = discarded[f];
for (i = 0; i < end; i++)
{
/* Cancel provisional discards not in middle of run of discards. */
if (discards[i] == 2)
discards[i] = 0;
else if (discards[i] != 0)
{
/* We have found a nonprovisional discard. */
register int j;
unsigned int length;
unsigned int provisional = 0;
/* Find end of this run of discardable lines.
Count how many are provisionally discardable. */
for (j = (int)i; (unsigned int)j < end; j++)
{
if (discards[j] == 0)
break;
if (discards[j] == 2)
++provisional;
}
/* Cancel provisional discards at end, and shrink the run. */
while (j > (int)i && discards[j - 1] == 2)
discards[--j] = 0, --provisional;
/* Now we have the length of a run of discardable lines
whose first and last are not provisional. */
length = j - i;
/* If 1/4 of the lines in the run are provisional,
cancel discarding of all provisional lines in the run. */
if (provisional * 4 > length)
{
while (j > (int)i)
if (discards[--j] == 2)
discards[j] = 0;
}
else
{
register unsigned int consec;
unsigned int minimum = 1;
unsigned int tem = length / 4;
/* MINIMUM is approximate square root of LENGTH/4.
A subrun of two or more provisionals can stand
when LENGTH is at least 16.
A subrun of 4 or more can stand when LENGTH >= 64. */
while ((tem = tem >> 2) > 0)
minimum *= 2;
minimum++;
/* Cancel any subrun of MINIMUM or more provisionals
within the larger run. */
for (j = 0, consec = 0; (unsigned int)j < length; j++)
if (discards[i + j] != 2)
consec = 0;
else if (minimum == ++consec)
/* Back up to start of subrun, to cancel it all. */
j -= consec;
else if (minimum < consec)
discards[i + j] = 0;
/* Scan from beginning of run
until we find 3 or more nonprovisionals in a row
or until the first nonprovisional at least 8 lines in.
Until that point, cancel any provisionals. */
for (j = 0, consec = 0; (unsigned int)j < length; j++)
{
if (j >= 8 && discards[i + j] == 1)
break;
if (discards[i + j] == 2)
consec = 0, discards[i + j] = 0;
else if (discards[i + j] == 0)
consec = 0;
else
consec++;
if (consec == 3)
break;
}
/* I advances to the last line of the run. */
i += length - 1;
/* Same thing, from end. */
for (j = 0, consec = 0; (unsigned int)j < length; j++)
{
if (j >= 8 && discards[i - j] == 1)
break;
if (discards[i - j] == 2)
consec = 0, discards[i - j] = 0;
else if (discards[i - j] == 0)
consec = 0;
else
consec++;
if (consec == 3)
break;
}
}
}
}
}
/* Actually discard the lines. */
for (f = 0; f < 2; f++)
{
char *discards = discarded[f];
unsigned int end = filevec[f].buffered_lines;
unsigned int j = 0;
for (i = 0; i < end; ++i)
if (no_discards || discards[i] == 0)
{
filevec[f].undiscarded[j] = filevec[f].equivs[i];
filevec[f].realindexes[j++] = i;
}
else
filevec[f].changed_flag[i] = 1;
filevec[f].nondiscarded_lines = j;
}
free (discarded[0]);
free (equiv_count[0]);
}
/* Adjust inserts/deletes of identical lines to join changes
as much as possible.
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;
static void
shift_boundaries (struct file_data filevec[])
{
int f;
if (inhibit)
return;
for (f = 0; f < 2; f++)
{
char *changed = filevec[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;
while (1)
{
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. */
while (i < i_end && changed[i] == 0)
{
while (other_changed[j++])
continue;
i++;
}
if (i == i_end)
break;
start = i;
/* Find the end of this run of changes. */
while (changed[++i])
continue;
while (other_changed[j])
j++;
do
{
/* Record the length of this run of changes, so that
we can later determine whether the run has grown. */
runlength = i - start;
/* Move the changed region back, so long as the
previous unchanged line matches the last changed one.
This merges with previous changed regions. */
while (start && equivs[start - 1] == equivs[i - 1])
{
changed[--start] = 1;
changed[--i] = 0;
while (changed[start - 1])
start--;
while (other_changed[--j])
continue;
}
/* 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;
/* 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;
while (changed[i])
i++;
while (other_changed[++j])
corresponding = i;
}
}
while (runlength != i - start);
/* 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;
}
}
}
}
/* Cons an additional entry onto the front of an edit script OLD.
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.
If DELETED is 0 then LINE0 is the number of the line before
which the insertion was done; vice versa for INSERTED and LINE1. */
static struct change *
add_change (line0, line1, deleted, inserted, old)
int line0, line1, deleted, inserted;
struct change *old;
{
struct change *newob = (struct change *) xmalloc (sizeof (struct change));
memset(newob, 0, sizeof(*newob));
newob->line0 = line0;
newob->line1 = line1;
newob->inserted = inserted;
newob->deleted = deleted;
newob->link = old;
newob->match0 = -1; /* WinMerge moved block code */
newob->match1 = -1; /* WinMerge moved block code */
return newob;
}
/* Scan the tables of which lines are inserted and deleted,
producing an edit script in reverse order. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -