Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ TESTS = tests/newline1/run-test \
tests/combine2/run-test \
tests/combine3/run-test \
tests/combine4/run-test \
tests/combine5/run-test \
tests/combine6/run-test \
tests/combine-devnull/run-test \
tests/combine-devnull-p/run-test \
tests/combine-no-match/run-test \
tests/interdiff-devnull/run-test \
tests/flipdiff-devnull/run-test \
tests/gendiff1/run-test \
tests/gendiff2/run-test \
tests/comma/run-test \
Expand Down
18 changes: 15 additions & 3 deletions doc/patchutils.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,11 @@
<option>-p</option> option to GNU <citerefentry>
<refentrytitle>patch</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>.)</para>
</citerefentry>.) If this option is not specified,
<command>interdiff</command> will automatically
determine the optimal number of path components to
strip by finding the smallest value where at least
one file matches between the two patches.</para>
</listitem>
</varlistentry>

Expand Down Expand Up @@ -464,7 +468,11 @@
<option>-p</option> option to GNU <citerefentry>
<refentrytitle>patch</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>.)</para>
</citerefentry>.) If this option is not specified,
<command>combinediff</command> will automatically
determine the optimal number of path components to
strip by finding the smallest value where at least
one file matches between the two patches.</para>
</listitem>
</varlistentry>

Expand Down Expand Up @@ -2922,7 +2930,11 @@ will pipe patch of file #2 to vim - -R
<option>-p</option> option to GNU <citerefentry>
<refentrytitle>patch</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>.)</para>
</citerefentry>.) If this option is not specified,
<command>flipdiff</command> will automatically
determine the optimal number of path components to
strip by finding the smallest value where at least
one file matches between the two patches.</para>
</listitem>
</varlistentry>

Expand Down
168 changes: 124 additions & 44 deletions src/interdiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ static int num_diff_opts = 0;
static unsigned int max_context_real = 3, max_context = 3;
static int context_specified = 0;
static int ignore_components = 0;
static int ignore_components_specified = 0;
static int unzip = 0;
static int no_revert_omitted = 0;
static int debug = 0;
Expand All @@ -103,6 +104,7 @@ static struct patlist *pat_drop_context = NULL;

static struct file_list *files_done = NULL;
static struct file_list *files_in_patch2 = NULL;
static struct file_list *files_in_patch1 = NULL;

/* checks whether file needs processing and sets context */
static int
Expand Down Expand Up @@ -147,6 +149,49 @@ file_in_list (struct file_list *list, const char *file)
return -1;
}

/* Determine the best ignore_components value when none was specified.
* Try different values from 0 up to a reasonable maximum, and find the
* smallest value where at least one file from patch1 matches a file from patch2.
*/
static int
determine_ignore_components (struct file_list *list1, struct file_list *list2)
{
int max_components = 0;
int p;

/* Find the maximum number of path components in any file */
for (struct file_list *l = list1; l; l = l->next) {
if (strcmp(l->file, "/dev/null") != 0) {
int components = num_pathname_components(l->file);
if (components > max_components)
max_components = components;
}
}
for (struct file_list *l = list2; l; l = l->next) {
if (strcmp(l->file, "/dev/null") != 0) {
int components = num_pathname_components(l->file);
if (components > max_components)
max_components = components;
}
}

/* Try different -p values, starting from 0 */
for (p = 0; p <= max_components; p++) {
for (struct file_list *l1 = list1; l1; l1 = l1->next) {
const char *stripped1 = stripped(l1->file, p);
for (struct file_list *l2 = list2; l2; l2 = l2->next) {
const char *stripped2 = stripped(l2->file, p);
if (!strcmp(stripped1, stripped2)) {
return p;
}
}
}
}

/* If no match found, return 0 as default */
return 0;
}

static void
free_list (struct file_list *list)
{
Expand Down Expand Up @@ -178,7 +223,7 @@ add_line (struct lines_info *lines, const char *line, size_t length,
{
struct lines *make;
struct lines *at;

make = xmalloc (sizeof *make);
make->n = n;
make->line = xmalloc (length + 1);
Expand Down Expand Up @@ -243,7 +288,7 @@ merge_lines (struct lines_info *lines1, struct lines_info *lines2)
struct lines *at, *at_prev, *make;


/*
/*
* Note: we don't care about the tail member here - not needed
* anymore.
*/
Expand Down Expand Up @@ -619,7 +664,7 @@ do_output_patch1_only (FILE *p1, FILE *out, int not_reverted)
orig_lines = orig_num_lines (d1);
new_lines = new_num_lines (d2);
}


free (d1);
free (d2);
Expand Down Expand Up @@ -1138,7 +1183,7 @@ output_delta (FILE *p1, FILE *p2, FILE *out)
memcpy (argv + 2, diff_opts, num_diff_opts * sizeof (char *));
memcpy (argv + 2 + num_diff_opts, (char *[]) { tmpp1, tmpp2, NULL }, (2 + 1) * sizeof (char *));
in = xpipe (DIFF, &child, "r", argv);

/* Eat the first line */
for (;;) {
int ch = fgetc (in);
Expand Down Expand Up @@ -1270,22 +1315,23 @@ copy_residue (FILE *p2, FILE *out)
return 0;
}

/* Generic patch indexing function that can handle both patch1 and patch2 */
static int
index_patch2 (FILE *p2)
index_patch_generic (FILE *patch_file, struct file_list **file_list, int need_skip_content)
{
char *line = NULL;
size_t linelen = 0;
int is_context = 0;
int file_is_empty = 1;

/* Index patch2 */
while (!feof (p2)) {
/* Index patch */
while (!feof (patch_file)) {
unsigned long skip;
char *names[2];
char *p, *end;
long pos = ftell (p2);
long pos = ftell (patch_file);

if (getline (&line, &linelen, p2) == -1)
if (getline (&line, &linelen, patch_file) == -1)
break;

file_is_empty = 0;
Expand All @@ -1301,7 +1347,7 @@ index_patch2 (FILE *p2)

names[0] = filename_from_header (line + 4);

if (getline (&line, &linelen, p2) == -1) {
if (getline (&line, &linelen, patch_file) == -1) {
free (names[0]);
break;
}
Expand All @@ -1313,38 +1359,44 @@ index_patch2 (FILE *p2)

names[1] = filename_from_header (line + 4);

if (getline (&line, &linelen, p2) == -1) {
free (names[0]);
free (names[1]);
break;
}

if (strncmp (line, "@@ ", 3))
goto try_next;
/* For patch2, we need to handle the @@ line and skip content */
if (need_skip_content) {
if (getline (&line, &linelen, patch_file) == -1) {
free (names[0]);
free (names[1]);
break;
}

p = strchr (line + 3, '+');
if (!p)
goto try_next;
p = strchr (p, ',');
if (p) {
/* Like '@@ -1,3 +1,3 @@' */
p++;
skip = strtoul (p, &end, 10);
if (p == end)
if (strncmp (line, "@@ ", 3))
goto try_next;
} else
/* Like '@@ -1 +1 @@' */
skip = 1;

add_to_list (&files_in_patch2, best_name (2, names), pos);

while (skip--) {
if (getline (&line, &linelen, p2) == -1)
break;

if (line[0] == '-')
/* Doesn't count towards skip count */
skip++;
p = strchr (line + 3, '+');
if (!p)
goto try_next;
p = strchr (p, ',');
if (p) {
/* Like '@@ -1,3 +1,3 @@' */
p++;
skip = strtoul (p, &end, 10);
if (p == end)
goto try_next;
} else
/* Like '@@ -1 +1 @@' */
skip = 1;

add_to_list (file_list, best_name (2, names), pos);

while (skip--) {
if (getline (&line, &linelen, patch_file) == -1)
break;

if (line[0] == '-')
/* Doesn't count towards skip count */
skip++;
}
} else {
/* For patch1, just add to list */
add_to_list (file_list, best_name (2, names), pos);
}

try_next:
Expand All @@ -1355,12 +1407,18 @@ index_patch2 (FILE *p2)
if (line)
free (line);

if (file_is_empty || files_in_patch2)
if (file_is_empty || *file_list)
return 0;
else
return 1;
}

static int
index_patch2 (FILE *p2)
{
return index_patch_generic (p2, &files_in_patch2, 1);
}

/* With flipdiff we have two patches we want to reorder. The
* algorithm is:
*
Expand Down Expand Up @@ -1424,7 +1482,7 @@ patch2_removes_line (unsigned long line, /* line number after patch1 */
return 1;
}
}

return 0;
}

Expand Down Expand Up @@ -1908,6 +1966,12 @@ no_patch (const char *f)
return 0;
}

static int
index_patch1 (FILE *p1)
{
return index_patch_generic (p1, &files_in_patch1, 0);
}

static int
interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
{
Expand All @@ -1926,6 +1990,20 @@ interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
if (index_patch2 (p2))
no_patch (patch2);

/* Index patch1 and determine ignore_components if not specified */
if (index_patch1 (p1))
no_patch (patch1);

/* Determine ignore_components automatically if not explicitly specified */
if (!ignore_components_specified) {
ignore_components = determine_ignore_components (files_in_patch1, files_in_patch2);
if (debug)
fprintf (stderr, "Auto-determined -p%d\n", ignore_components);
}

/* Reset file pointer for patch1 */
rewind (p1);

/* Search for next file to patch */
while (!feof (p1)) {
char *names[2];
Expand Down Expand Up @@ -1966,7 +2044,7 @@ interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
free (names[0]);
free (names[1]);
patch_found = 1;

/* check if we need to process it and init context */
if (!check_filename(p)) {
add_to_list (&files_done, p, 0);
Expand Down Expand Up @@ -2020,6 +2098,7 @@ interdiff (FILE *p1, FILE *p2, const char *patch1, const char *patch2)
fclose (flip1);
if (flip2)
fclose (flip2);
free_list (files_in_patch1);
free_list (files_in_patch2);
free_list (files_done);
if (line)
Expand Down Expand Up @@ -2163,6 +2242,7 @@ main (int argc, char *argv[])
ignore_components = strtoul (optarg, &end, 0);
if (optarg == end)
syntax (1);
ignore_components_specified = 1;
break;
case 'q':
human_readable = 0;
Expand Down Expand Up @@ -2221,7 +2301,7 @@ main (int argc, char *argv[])
if (unzip && flipdiff_inplace)
error (EXIT_FAILURE, 0,
"-z and --in-place are mutually exclusive.");

/* Add default color=always if no color option was specified and we're in a terminal */
int has_color_option = 0;
for (int i = 0; i < num_diff_opts; i++) {
Expand All @@ -2237,7 +2317,7 @@ main (int argc, char *argv[])

if (optind + 2 != argc)
syntax (1);

if (unzip) {
p1 = xopen_unzip (argv[optind], "rb");
p2 = xopen_unzip (argv[optind + 1], "rb");
Expand Down
Loading