OBS User unknown 2009-04-02 16:49:52 +00:00 committed by Git OBS Bridge
parent 4031722516
commit 940f272444
23 changed files with 29 additions and 5205 deletions

View File

@ -1,105 +0,0 @@
---
common.h | 2 ++
merge.c | 8 ++++----
patch.c | 14 +++++++++++++-
3 files changed, 19 insertions(+), 5 deletions(-)
Index: b/common.h
===================================================================
--- a/common.h
+++ b/common.h
@@ -310,6 +310,8 @@ XTERN LINENUM last_offset;
/* how many input lines have been irretractably output */
XTERN LINENUM last_frozen_line;
+XTERN const char *file_label[2];
+
bool similar (char const *, size_t, char const *, size_t);
bool copy_till (struct outstate *, LINENUM);
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -70,6 +70,8 @@ static void usage (FILE *, int) __attrib
static void (*abort_hunk) (bool, bool) = abort_hunk_context;
static bool merge;
+const char *file_label[2];
+
static bool make_backups;
static bool backup_if_mismatch;
static char const *version_control;
@@ -506,7 +508,7 @@ reinitialize_almost_everything (void)
skip_rest_of_patch = false;
}
-static char const shortopts[] = "bB:cd:D:eEfF:g:i:lMnNo:p:r:RstTuvV:x:Y:z:Z";
+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lL:MnNo:p:r:RstTuvV:x:Y:z:Z";
static struct option const longopts[] =
{
{"backup", no_argument, NULL, 'b'},
@@ -521,6 +523,7 @@ static struct option const longopts[] =
{"get", no_argument, NULL, 'g'},
{"input", required_argument, NULL, 'i'},
{"ignore-whitespace", no_argument, NULL, 'l'},
+ {"label", required_argument, NULL, 'L'},
{"merge", no_argument, NULL, 'M'},
{"normal", no_argument, NULL, 'n'},
{"forward", no_argument, NULL, 'N'},
@@ -577,6 +580,7 @@ static char const *const option_help[] =
"",
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
" -M --merge Produce a diff3-style merge for rejects.",
+" -L LABEL --label=LABEL Use LABEL instead of file name in merge.",
" -E --remove-empty-files Remove output files that are empty after patching.",
"",
" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
@@ -718,6 +722,14 @@ get_some_switches (void)
case 'M':
merge = true;
break;
+ case 'L':
+ if (!file_label[0])
+ file_label[0] = optarg;
+ else if (!file_label[1])
+ file_label[1] = optarg;
+ else
+ fatal ("too many file label options");
+ break;
case 'n':
diff_type = NORMAL_DIFF;
break;
Index: b/merge.c
===================================================================
--- a/merge.c
+++ b/merge.c
@@ -50,7 +50,7 @@ merge_hunk (struct outstate *outstate)
return false;
/* "From" lines in the patch */
- name = pch_name(OLD);
+ name = file_label[OLD] ? file_label[OLD] : pch_name(OLD);
if (!name)
name = "";
fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n",
@@ -84,7 +84,7 @@ merge_hunk (struct outstate *outstate)
if (! same_result)
{
/* "To" lines in the patch */
- name = pch_name(NEW);
+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW);
if (!name)
name = "";
fprintf(fp, outstate->after_newline + "\n|||||||%*s\n",
@@ -112,8 +112,8 @@ merge_hunk (struct outstate *outstate)
result with the new file's name. */
if (same_result)
{
- name = pch_name(NEW);
- if (!name)
+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW);
+ if (! name)
name = "";
}
else

View File

@ -1,337 +0,0 @@
---
Makefile.in | 3 -
bestmatch.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
common.h | 11 ++++
merge.c | 95 ++++++++++++++++++++++++++++++++++++++++-
patch.c | 19 ++++++--
5 files changed, 256 insertions(+), 10 deletions(-)
Index: b/Makefile.in
===================================================================
--- a/Makefile.in
+++ b/Makefile.in
@@ -85,7 +85,8 @@ HDRS = argmatch.h backupfile.h common.h
error.h getopt.h gettext.h \
inp.h maketime.h partime.h pch.h \
quote.h quotearg.h quotesys.h \
- unlocked-io.h util.h version.h xalloc.h hash.h
+ unlocked-io.h util.h version.h xalloc.h hash.h \
+ bestmatch.h
MISC = AUTHORS COPYING ChangeLog INSTALL Makefile.in NEWS README \
aclocal.m4 \
config.hin configure configure.ac \
Index: b/common.h
===================================================================
--- a/common.h
+++ b/common.h
@@ -296,6 +296,14 @@ void *realloc ();
#define TTY_DEVICE "/dev/tty"
#endif
+#ifndef MIN
+# define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+# define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#endif
+
/* Output stream state. */
struct outstate
{
@@ -316,4 +324,5 @@ bool similar (char const *, size_t, char
bool copy_till (struct outstate *, LINENUM);
/* Defined in merge.c */
-bool merge_hunk (struct outstate *);
+LINENUM locate_merge (LINENUM, LINENUM *);
+bool merge_hunk (struct outstate *, LINENUM, LINENUM);
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -286,13 +286,22 @@ main (int argc, char **argv)
goto skip_hunk;
} else if (!where) {
if (merge) {
- if (merge_hunk(&outstate)) {
+ LINENUM matched;
+
+ where = locate_merge (maxfuzz, &matched);
+ if (! where)
+ {
+ where = pch_first () + last_offset;
+ matched = 0;
+ }
+
+ if (merge_hunk (&outstate, where, matched))
+ {
merged++;
mismatch = 1;
- } else {
- /* FIXME: try harder! */
- goto skip_hunk;
- }
+ }
+ else
+ goto skip_hunk;
} else
goto skip_hunk;
} else {
Index: b/merge.c
===================================================================
--- a/merge.c
+++ b/merge.c
@@ -7,8 +7,97 @@
static bool context_matches_file (LINENUM, LINENUM);
static bool common_context (LINENUM, LINENUM, LINENUM);
+#define OFFSET LINENUM
+#define EQUAL(x, y) (context_matches_file (x, y))
+
+#include "bestmatch.h"
+
+LINENUM
+locate_merge (LINENUM fuzz, LINENUM *matched)
+{
+ LINENUM first_guess = pch_first () + last_offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ LINENUM suffix_context = pch_suffix_context ();
+ LINENUM max_where = input_lines - (pat_lines - suffix_context) + 1;
+ LINENUM min_where = last_frozen_line + 1;
+ LINENUM max_pos_offset = max_where - first_guess;
+ LINENUM max_neg_offset = first_guess - min_where;
+ LINENUM max_offset = (max_pos_offset < max_neg_offset
+ ? max_neg_offset : max_pos_offset);
+ LINENUM prefix_fuzz = MIN (fuzz, pch_prefix_context());
+ LINENUM suffix_fuzz = MIN (fuzz, pch_suffix_context());
+ LINENUM where = 0, max_matched = 0;
+ LINENUM min, max;
+ LINENUM offset;
+
+ /* The minimum number of matched lines and maximum number of changes
+ are mostly guesses. */
+ min = pat_lines - (prefix_fuzz + suffix_fuzz);
+ max = 2 * (prefix_fuzz + suffix_fuzz);
+
+ /* Do not try lines <= 0. */
+ if (first_guess <= max_neg_offset)
+ max_neg_offset = first_guess - 1;
+
+ for (offset = 0; offset <= max_offset; offset++)
+ {
+ if (offset <= max_pos_offset)
+ {
+ LINENUM guess = first_guess + offset;
+ LINENUM last;
+ LINENUM changes;
+
+ changes = bestmatch(1, pat_lines + 1, guess, input_lines + 1,
+ min, max, &last);
+ if (changes <= max && max_matched < last - guess)
+ {
+ max_matched = last - guess;
+ where = guess;
+ if (changes == 0)
+ break;
+ min = last - guess;
+ max = changes - 1;
+ }
+ }
+ if (0 < offset && offset <= max_neg_offset)
+ {
+ LINENUM guess = first_guess - offset;
+ LINENUM last;
+ LINENUM changes;
+
+ changes = bestmatch(1, pat_lines + 1, guess, input_lines + 1,
+ min, max, &last);
+ if (changes <= max && max_matched < last - guess)
+ {
+ max_matched = last - guess;
+ where = guess;
+ if (changes == 0)
+ break;
+ min = last - guess;
+ max = changes - 1;
+ }
+ }
+ }
+ if (debug & 1)
+ {
+ char numbuf0[LINENUM_LENGTH_BOUND + 1];
+ char numbuf1[LINENUM_LENGTH_BOUND + 1];
+ char numbuf2[LINENUM_LENGTH_BOUND + 1];
+ char numbuf3[LINENUM_LENGTH_BOUND + 1];
+ say ("locating merge: min=%s max=%s where=%s matched=%s\n",
+ format_linenum (numbuf0, min),
+ format_linenum (numbuf1, max),
+ format_linenum (numbuf2, where),
+ format_linenum (numbuf3, max_matched));
+ }
+
+ if (where)
+ *matched = max_matched;
+ return where;
+}
+
bool
-merge_hunk (struct outstate *outstate)
+merge_hunk (struct outstate *outstate, LINENUM where, LINENUM matched)
{
LINENUM old = 1;
LINENUM lastold = pch_ptrn_lines ();
@@ -22,8 +111,8 @@ merge_hunk (struct outstate *outstate)
while (pch_char(new) == '=' || pch_char(new) == '\n')
new++;
- merge = pch_first () + last_offset;
- lastmerge = merge + lastold - 1;
+ merge = where;
+ lastmerge = where + matched - 1;
if (! common_context(lastmerge, lastold, lastnew))
lastmerge = merge - 1;
Index: b/bestmatch.h
===================================================================
--- /dev/null
+++ b/bestmatch.h
@@ -0,0 +1,138 @@
+/* Before including this file, you need to define:
+ EQUAL(x, y) A two-argument macro that tests elements
+ at index x and y for equality.
+ OFFSET A signed integer type sufficient to hold the
+ difference between two indices. Usually
+ something like ssize_t. */
+
+/*
+ * Shortest Edit Sequence
+ *
+ * Based on the Greedy LCS/SES Algorithm (Figure 2) in:
+ *
+ * Eugene W. Myers, "An O(ND) Difference Algorithm and Its Variations",
+ * Algorithmica, Vol. 1, No. 1, pp. 251-266, March 1986.
+ * Available: http://dx.doi.org/10.1007/BF01840446
+ * http://xmailserver.org/diff2.pdf
+ *
+ * Returns the number of changes (insertions and deletions) required to get
+ * from a[] to b[]. Returns MAX + 1 if a[] cannot be turned into b[] with
+ * MAX or fewer changes.
+ *
+ * MIN specifies the minimum number of elements in which a[] and b[] must
+ * match. This allows to prevent trivial matches in which a sequence is
+ * completely discarded, or completely made up.
+ *
+ * If PY is not NULL, matches a[] against a prefix of b[], and returns the
+ * number of elements in b[] that were matched in *PY. Otherwise, matches
+ * all elements of b[].
+ *
+ * Note that the divide-and-conquer strategy discussed in section 4b of the
+ * paper is more efficient, but does not allow an open-ended prefix string
+ * search.
+ */
+
+OFFSET
+bestmatch(OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim,
+ OFFSET min, OFFSET max, OFFSET *py)
+{
+ const OFFSET dmin = xoff - ylim; /* Minimum valid diagonal. */
+ const OFFSET dmax = xlim - yoff; /* Maximum valid diagonal. */
+ const OFFSET fmid = xoff - yoff; /* Center diagonal. */
+ OFFSET fmin = fmid;
+ OFFSET fmax = fmid;
+ OFFSET V[2 * max + 3], *fd = V + max + 2 - fmid;
+ OFFSET fmid_plus_2_min, ymax = -1;
+ OFFSET c;
+
+ /*
+ The number of elements that were matched in x and in y can be
+ computed as either (x - x_skipped) or (y - y_skipped), with:
+
+ delta = (x - xoff) - (y - yoff)
+ x_skipped = (c + delta) / 2
+ y_skipped = (c - delta) / 2
+
+ For searching for a minimum number of matching elements, we end up
+ with this check:
+
+ (x - x_skipped) >= min
+ ...
+ x + y - c >= (xoff - yoff) + 2 * min
+ x + y - c >= fmid + 2 * min
+ */
+
+ if (min)
+ {
+ fmid_plus_2_min = fmid + 2 * min;
+ min += yoff;
+ if (min > ylim)
+ return max + 1;
+ }
+ else
+ fmid_plus_2_min = 0; /* disable this check */
+ if (!py)
+ min = ylim;
+
+ /* Handle the exact-match case. */
+ while (xoff < xlim && yoff < ylim && EQUAL (xoff, yoff))
+ {
+ xoff++;
+ yoff++;
+ }
+ if (xoff == xlim && yoff >= min
+ && xoff + yoff >= fmid_plus_2_min)
+ {
+ ymax = yoff;
+ c = 0;
+ }
+ else
+ {
+ fd[fmid] = xoff;
+ for (c = 1; c <= max; c++)
+ {
+ OFFSET d;
+
+ if (fmin > dmin)
+ fd[--fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ fd[++fmax + 1] = -1;
+ else
+ --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ OFFSET x, y;
+
+ if (fd[d - 1] < fd[d + 1])
+ x = fd[d + 1];
+ else
+ x = fd[d - 1] + 1;
+ for (y = x - d;
+ x < xlim && y < ylim && EQUAL (x, y);
+ x++, y++)
+ continue;
+ fd[d] = x;
+ if (x == xlim && y >= min
+ && x + y - c >= fmid_plus_2_min)
+ {
+ if (ymax < y)
+ ymax = y;
+ if (y == ylim)
+ goto done;
+ }
+ }
+ if (ymax != -1)
+ goto done;
+ }
+ }
+
+ done:
+ if (py)
+ *py = ymax;
+ return c;
+}
+
+#undef OFFSET
+#undef EQUAL

View File

@ -1,61 +0,0 @@
---
patch.c | 42 ++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 22 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -288,32 +288,30 @@ main (int argc, char **argv)
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
goto skip_hunk;
- }
- else if (!where
- || (where == 1 && pch_says_nonexistent (reverse) == 2
- && instat.st_size)) {
-
- if (where)
- say ("Patch attempted to create file %s, which already exists.\n",
- quotearg (inname));
+ } else if (where == 1 && pch_says_nonexistent (reverse) == 2
+ && instat.st_size) {
+ say ("Patch attempted to create file %s, "
+ "which already exists.\n", quotearg (inname));
goto skip_hunk;
- }
- else if (! apply_hunk (&outstate, where)) {
+ } else if (!where) {
goto skip_hunk;
} else {
- if (verbosity == VERBOSE
- || (verbosity != SILENT && (fuzz || last_offset))) {
- say ("Hunk #%d succeeded at %s", hunk,
- format_linenum (numbuf, newwhere));
- if (fuzz)
- say (" with fuzz %s", format_linenum (numbuf, fuzz));
- if (last_offset)
- say (" (offset %s line%s)",
- format_linenum (numbuf, last_offset),
- "s" + (last_offset == 1));
- say (".\n");
- }
+ if (!apply_hunk (&outstate, where))
+ goto skip_hunk;
+ }
+
+ if (verbosity == VERBOSE
+ || (verbosity != SILENT && (fuzz || last_offset))) {
+ say ("Hunk #%d succeeded at %s", hunk,
+ format_linenum (numbuf, newwhere));
+ if (fuzz)
+ say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ if (last_offset)
+ say (" (offset %s line%s)",
+ format_linenum (numbuf, last_offset),
+ "s" + (last_offset == 1));
+ say (".\n");
}
continue;

View File

@ -1,59 +0,0 @@
---
patch.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -287,11 +287,7 @@ main (int argc, char **argv)
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
- abort_hunk(!failed, reverse);
- failed++;
- if (verbosity == VERBOSE)
- say ("Hunk #%d ignored at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
}
else if (!where
|| (where == 1 && pch_says_nonexistent (reverse) == 2
@@ -301,18 +297,10 @@ main (int argc, char **argv)
say ("Patch attempted to create file %s, which already exists.\n",
quotearg (inname));
- abort_hunk(!failed, reverse);
- failed++;
- if (verbosity != SILENT)
- say ("Hunk #%d FAILED at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
}
else if (! apply_hunk (&outstate, where)) {
- abort_hunk (!failed, reverse);
- failed++;
- if (verbosity != SILENT)
- say ("Hunk #%d FAILED at %s.\n", hunk,
- format_linenum (numbuf, newwhere));
+ goto skip_hunk;
} else {
if (verbosity == VERBOSE
|| (verbosity != SILENT && (fuzz || last_offset))) {
@@ -327,6 +315,16 @@ main (int argc, char **argv)
say (".\n");
}
}
+ continue;
+
+skip_hunk:
+ abort_hunk(!failed, reverse);
+ failed++;
+ if (verbosity == VERBOSE ||
+ (!skip_rest_of_patch && verbosity != SILENT))
+ say ("Hunk #%d %s at %s.\n", hunk,
+ skip_rest_of_patch ? "ignored" : "FAILED",
+ format_linenum (numbuf, newwhere));
}
if (!skip_rest_of_patch)

View File

@ -1,442 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges
Implement a diff3-style merge format: with the --merge option alone,
all hunks that apply without fuzz will be applied as usual, and
hunks that apply within the allowed fuzz limit will be bracketed as:
<<<<<<<
old lines from patch
|||||||
new lines from patch
=======
merge result
>>>>>>>
When the --show-all option is given in addition, hunks that apply without
fuzz will be bracketed as:
<<<<<<<
old lines from patch
=======
merge result
>>>>>>>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
Makefile.in | 6 +-
common.h | 20 +++++++
merge.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
patch.c | 62 +++++++++++++----------
4 files changed, 222 insertions(+), 27 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -48,22 +48,12 @@ struct utimbuf
};
#endif
-/* Output stream state. */
-struct outstate
-{
- FILE *ofp;
- bool after_newline;
- bool zero_output;
-};
-
/* procedures */
static FILE *create_output_file (char const *, int);
static LINENUM locate_hunk (LINENUM);
static bool apply_hunk (struct outstate *, LINENUM);
-static bool copy_till (struct outstate *, LINENUM);
static bool patch_match (LINENUM, LINENUM, LINENUM, LINENUM);
-static bool similar (char const *, size_t, char const *, size_t);
static bool spew_output (struct outstate *);
static char const *make_temp (char);
static void abort_hunk_context (bool, bool);
@@ -79,6 +69,7 @@ static void usage (FILE *, int) __attrib
static void (*abort_hunk) (bool, bool) = abort_hunk_context;
+static bool merge;
static bool make_backups;
static bool backup_if_mismatch;
static char const *version_control;
@@ -88,9 +79,6 @@ static bool remove_empty_files;
/* true if -R was specified on command line. */
static bool reverse_flag_specified;
-/* how many input lines have been irretractably output */
-static LINENUM last_frozen_line;
-
static char const *do_defines; /* symbol to patch using ifdef, ifndef, etc. */
static char const if_defined[] = "\n#ifdef %s\n";
static char const not_defined[] = "\n#ifndef %s\n";
@@ -108,7 +96,6 @@ static char *rejname;
static char const * volatile TMPREJNAME;
static int volatile TMPREJNAME_needs_removal;
-static LINENUM last_offset;
static LINENUM maxfuzz = 2;
static char serrbuf[BUFSIZ];
@@ -119,7 +106,7 @@ int
main (int argc, char **argv)
{
char const *val;
- bool somefailed = false;
+ bool somemerged = false, somefailed = false;
struct outstate outstate;
char numbuf[LINENUM_LENGTH_BOUND + 1];
@@ -186,6 +173,7 @@ main (int argc, char **argv)
reinitialize_almost_everything()
) { /* for each patch in patch file */
int hunk = 0;
+ int merged = 0;
int failed = 0;
bool mismatch = false;
char *outname = outfile ? outfile : inname;
@@ -295,7 +283,16 @@ main (int argc, char **argv)
goto skip_hunk;
} else if (!where) {
- goto skip_hunk;
+ if (merge) {
+ if (merge_hunk(&outstate)) {
+ merged++;
+ mismatch = 1;
+ } else {
+ /* FIXME: try harder! */
+ goto skip_hunk;
+ }
+ } else
+ goto skip_hunk;
} else {
if (!apply_hunk (&outstate, where))
goto skip_hunk;
@@ -303,10 +300,16 @@ main (int argc, char **argv)
if (verbosity == VERBOSE
|| (verbosity != SILENT && (fuzz || last_offset))) {
- say ("Hunk #%d succeeded at %s", hunk,
- format_linenum (numbuf, newwhere));
- if (fuzz)
- say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ if (fuzz > mymaxfuzz) {
+ say ("Hunk #%d merged at %s with conflicts", hunk,
+ format_linenum (numbuf, newwhere));
+ somefailed = true;
+ } else {
+ say ("Hunk #%d succeeded at %s", hunk,
+ format_linenum (numbuf, newwhere));
+ if (fuzz)
+ say (" with fuzz %s", format_linenum (numbuf, fuzz));
+ }
if (last_offset)
say (" (offset %s line%s)",
format_linenum (numbuf, last_offset),
@@ -325,6 +328,9 @@ skip_hunk:
format_linenum (numbuf, newwhere));
}
+ if (merged)
+ somemerged = true;
+
if (!skip_rest_of_patch)
{
if (got_hunk < 0 && using_plan_a)
@@ -374,7 +380,8 @@ skip_hunk:
else
{
if (! outstate.zero_output
- && pch_says_nonexistent (! reverse))
+ && pch_says_nonexistent (! reverse)
+ && !merged)
{
mismatch = true;
if (verbosity != SILENT)
@@ -465,7 +472,7 @@ skip_hunk:
if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
write_fatal ();
cleanup ();
- if (somefailed)
+ if (somemerged || somefailed)
exit (1);
return 0;
}
@@ -499,7 +506,7 @@ reinitialize_almost_everything (void)
skip_rest_of_patch = false;
}
-static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z";
+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lMnNo:p:r:RstTuvV:x:Y:z:Z";
static struct option const longopts[] =
{
{"backup", no_argument, NULL, 'b'},
@@ -514,6 +521,7 @@ static struct option const longopts[] =
{"get", no_argument, NULL, 'g'},
{"input", required_argument, NULL, 'i'},
{"ignore-whitespace", no_argument, NULL, 'l'},
+ {"merge", no_argument, NULL, 'M'},
{"normal", no_argument, NULL, 'n'},
{"forward", no_argument, NULL, 'N'},
{"output", required_argument, NULL, 'o'},
@@ -568,6 +576,7 @@ static char const *const option_help[] =
" -r FILE --reject-file=FILE Output rejects to FILE.",
"",
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
+" -M --merge Produce a diff3-style merge for rejects.",
" -E --remove-empty-files Remove output files that are empty after patching.",
"",
" -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
@@ -706,6 +715,9 @@ get_some_switches (void)
case 'l':
canonicalize = true;
break;
+ case 'M':
+ merge = true;
+ break;
case 'n':
diff_type = NORMAL_DIFF;
break;
@@ -1289,7 +1301,7 @@ init_reject (void)
/* Copy input file to output, up to wherever hunk is to be applied. */
-static bool
+bool
copy_till (register struct outstate *outstate, register LINENUM lastline)
{
register LINENUM R_last_frozen_line = last_frozen_line;
@@ -1375,7 +1387,7 @@ patch_match (LINENUM base, LINENUM offse
/* Do two lines match with canonicalized white space? */
-static bool
+bool
similar (register char const *a, register size_t alen,
register char const *b, register size_t blen)
{
Index: b/Makefile.in
===================================================================
--- a/Makefile.in
+++ b/Makefile.in
@@ -70,7 +70,8 @@ SRCS = $(LIBSRCS) \
maketime.c partime.c \
patch.c pch.c \
quote.c quotearg.c quotesys.c \
- util.c version.c xmalloc.c
+ util.c version.c xmalloc.c \
+ merge.c
OBJS = $(LIBOBJS) \
addext.$(OBJEXT) argmatch.$(OBJEXT) backupfile.$(OBJEXT) \
basename.$(OBJEXT) dirname.$(OBJEXT) \
@@ -78,7 +79,8 @@ OBJS = $(LIBOBJS) \
maketime.$(OBJEXT) partime.$(OBJEXT) \
patch.$(OBJEXT) pch.$(OBJEXT) \
quote.$(OBJEXT) quotearg.$(OBJEXT) quotesys.$(OBJEXT) \
- util.$(OBJEXT) version.$(OBJEXT) xmalloc.$(OBJEXT) hash.$(OBJEXT)
+ util.$(OBJEXT) version.$(OBJEXT) xmalloc.$(OBJEXT) hash.$(OBJEXT) \
+ merge.$(OBJEXT)
HDRS = argmatch.h backupfile.h common.h dirname.h \
error.h getopt.h gettext.h \
inp.h maketime.h partime.h pch.h \
Index: b/common.h
===================================================================
--- a/common.h
+++ b/common.h
@@ -295,3 +295,23 @@ void *realloc ();
#ifndef TTY_DEVICE
#define TTY_DEVICE "/dev/tty"
#endif
+
+/* Output stream state. */
+struct outstate
+{
+ FILE *ofp;
+ bool after_newline;
+ bool zero_output;
+};
+
+/* offset at which the previous hunk matched */
+XTERN LINENUM last_offset;
+
+/* how many input lines have been irretractably output */
+XTERN LINENUM last_frozen_line;
+
+bool similar (char const *, size_t, char const *, size_t);
+bool copy_till (struct outstate *, LINENUM);
+
+/* Defined in merge.c */
+bool merge_hunk (struct outstate *);
Index: b/merge.c
===================================================================
--- /dev/null
+++ b/merge.c
@@ -0,0 +1,161 @@
+#define XTERN extern
+#include <common.h>
+#include <inp.h>
+#include <pch.h>
+#include <util.h>
+
+static bool context_matches_file (LINENUM, LINENUM);
+static bool common_context (LINENUM, LINENUM, LINENUM);
+
+bool
+merge_hunk (struct outstate *outstate)
+{
+ LINENUM old = 1;
+ LINENUM lastold = pch_ptrn_lines ();
+ LINENUM new = lastold + 1;
+ LINENUM lastnew = pch_end ();
+ LINENUM merge, lastmerge;
+ FILE *fp = outstate->ofp;
+ bool same_result, succeeded = true;
+ const char *name;
+
+ while (pch_char(new) == '=' || pch_char(new) == '\n')
+ new++;
+
+ merge = pch_first () + last_offset;
+ lastmerge = merge + lastold - 1;
+ if (! common_context(lastmerge, lastold, lastnew))
+ lastmerge = merge - 1;
+
+ /* Hide common prefix context */
+ while (old <= lastold && new <= lastnew && merge <= lastmerge &&
+ common_context(merge, old, new))
+ {
+ old++;
+ new++;
+ merge++;
+ }
+
+ /* Hide common suffix context */
+ while (old <= lastold && new <= lastnew && merge <= lastmerge &&
+ common_context(lastmerge, lastold, lastnew))
+ {
+ lastold--;
+ lastnew--;
+ lastmerge--;
+ }
+
+ assert (outstate->after_newline);
+ if (! copy_till(outstate, merge - 1))
+ return false;
+
+ /* "From" lines in the patch */
+ name = pch_name(OLD);
+ if (!name)
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ while (old <= lastold)
+ {
+ outstate->after_newline = pch_write_line(old, fp);
+ old++;
+ }
+
+ same_result = (lastmerge - merge == lastnew - new);
+ if (same_result)
+ {
+ LINENUM n = new, m = merge;
+
+ while (n <= lastnew)
+ {
+ if (! context_matches_file (n, m))
+ {
+ same_result = false;
+ break;
+ }
+ n++;
+ m++;
+ }
+ }
+
+ if (! same_result)
+ {
+ /* "To" lines in the patch */
+ name = pch_name(NEW);
+ if (!name)
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n|||||||%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ while (new <= lastnew)
+ {
+ outstate->after_newline = pch_write_line(new, fp);
+ new++;
+ }
+ }
+
+ /* Merge result */
+ fprintf(fp, outstate->after_newline + "\n=======\n");
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+
+ if (! copy_till(outstate, lastmerge))
+ succeeded = false;
+
+ /* If the merge result and the new file are the same, label the merge
+ result with the new file's name. */
+ if (same_result)
+ {
+ name = pch_name(NEW);
+ if (!name)
+ name = "";
+ }
+ else
+ name = "";
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
+ strlen(name) ? strlen(name) + 1 : 0, name);
+ if (ferror (fp))
+ write_fatal ();
+ outstate->after_newline = true;
+ outstate->zero_output = false;
+ return succeeded;
+}
+
+static bool
+context_matches_file (LINENUM old, LINENUM where)
+{
+ size_t size;
+ const char *line;
+
+ line = ifetch (where, false, &size);
+ return size &&
+ (canonicalize ?
+ similar(pfetch(old), pch_line_len(old), line, size) :
+ (size == pch_line_len(old) &&
+ memcmp(line, pfetch(old), size) == 0));
+}
+
+static bool
+common_context (LINENUM where, LINENUM old, LINENUM new)
+{
+ size_t size;
+ const char *line;
+
+ if (pch_char(old) != ' ' || pch_char(new) != ' ')
+ return false;
+
+ line = ifetch (where, false, &size);
+ return size &&
+ (canonicalize ?
+ (similar(pfetch(old), pch_line_len(old), line, size) &&
+ similar(pfetch(new), pch_line_len(new), line, size)) :
+ (size == pch_line_len(old) && size == pch_line_len(new) &&
+ memcmp(line, pfetch(old), size) == 0 &&
+ memcmp(line, pfetch(new), size) == 0));
+}

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
---
pch.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Index: b/pch.c
===================================================================
--- a/pch.c
+++ b/pch.c
@@ -1877,7 +1877,9 @@ pch_line_len (LINENUM line)
return p_len[line];
}
-/* Return the control character (+, -, *, !, etc) for a patch line. */
+/* Return the control character (+, -, *, !, etc) for a patch line. A '\n'
+ indicates an empty line in a hunk that isn't part of the old or new
+ file's contents -- the context format allows that. */
char
pch_char (LINENUM line)

View File

@ -1,91 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Patch fails to apply hunks with asymmetric context correctly
Patch assumes that hunks with fewer context lines at the top than at the bottom
can only match at the beginning of the file, and hunks with fewer lines at the
bottom can only match at the end. The result is that patches with such hunks
will only apply with fuzz N if the prefix context is N lines longer or shorter
than the suffix context. This makes no sense; hunks with asymmetric context
are perfectly valid.
---
ChangeLog | 7 +++++++
patch.c | 43 ++++---------------------------------------
2 files changed, 11 insertions(+), 39 deletions(-)
Index: b/ChangeLog
===================================================================
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2007-11-02 Andreas Gruenbacher <agruen@suse.de>
+
+ * patch.c (locate_hunk): Hunks that have fewer or more lines of
+ context at the beginning than at the end can match anywhere; the
+ assumption that this can only occur at the beginning or end of the
+ file is wrong.
+
2003-05-20 Paul Eggert <eggert@twinsun.com>
* NEWS, configure.ac (AC_INIT): Version 2.5.9 released.
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -880,10 +880,10 @@ locate_hunk (LINENUM fuzz)
LINENUM pat_lines = pch_ptrn_lines();
LINENUM prefix_context = pch_prefix_context ();
LINENUM suffix_context = pch_suffix_context ();
- LINENUM context = (prefix_context < suffix_context
- ? suffix_context : prefix_context);
- LINENUM prefix_fuzz = fuzz + prefix_context - context;
- LINENUM suffix_fuzz = fuzz + suffix_context - context;
+ LINENUM prefix_fuzz = (prefix_context < fuzz
+ ? prefix_context : fuzz);
+ LINENUM suffix_fuzz = (suffix_context < fuzz
+ ? suffix_context : fuzz);
LINENUM max_where = input_lines - (pat_lines - suffix_fuzz) + 1;
LINENUM min_where = last_frozen_line + 1 - (prefix_context - prefix_fuzz);
LINENUM max_pos_offset = max_where - first_guess;
@@ -898,41 +898,6 @@ locate_hunk (LINENUM fuzz)
if (first_guess <= max_neg_offset)
max_neg_offset = first_guess - 1;
- if (prefix_fuzz < 0)
- {
- /* Can only match start of file. */
-
- if (suffix_fuzz < 0)
- /* Can only match entire file. */
- if (pat_lines != input_lines || prefix_context < last_frozen_line)
- return 0;
-
- offset = 1 - first_guess;
- if (last_frozen_line <= prefix_context
- && offset <= max_pos_offset
- && patch_match (first_guess, offset, (LINENUM) 0, suffix_fuzz))
- {
- last_offset += offset;
- return first_guess + offset;
- }
- else
- return 0;
- }
-
- if (suffix_fuzz < 0)
- {
- /* Can only match end of file. */
- offset = first_guess - (input_lines - pat_lines + 1);
- if (offset <= max_neg_offset
- && patch_match (first_guess, -offset, prefix_fuzz, (LINENUM) 0))
- {
- last_offset -= offset;
- return first_guess - offset;
- }
- else
- return 0;
- }
-
for (offset = 0; offset <= max_offset; offset++) {
char numbuf0[LINENUM_LENGTH_BOUND + 1];
char numbuf1[LINENUM_LENGTH_BOUND + 1];

View File

@ -1,58 +0,0 @@
* str2time() will happily parse "\n" and similar; the result will be
undistinguishable from a valid timestamp. Avoid this by skipping
whitespace before and checking if anything remains first.
* Always parse timestamps in patch headers relative to the local timezone
or UTC so that pch_timestamp() will always contain reasonable values
if a timestamp is present: we may need the timestamps later.
* Change the bizarre logic which checks whether a timestamp is close to
the epoch by checking for exactly that. The result is the same, and we
won't have to parse the timestamp again.
---
util.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
Index: b/util.c
===================================================================
--- a/util.c
+++ b/util.c
@@ -996,25 +996,23 @@ fetchname (char *at, int strip_leading,
if (*u != '\t' && strchr (u + 1, '\t'))
continue;
- if (set_time | set_utc)
- stamp = str2time (&u, initial_time,
- set_utc ? 0L : TM_LOCAL_ZONE);
- else
- {
+ while (ISSPACE((unsigned char) *u))
+ u++;
+ if (*u) {
+ stamp = str2time (&u, initial_time,
+ set_utc ? 0L : TM_LOCAL_ZONE);
+
/* The head says the file is nonexistent if the timestamp
is the epoch; but the listed time is local time, not UTC,
and POSIX.1 allows local time offset anywhere in the range
- -25:00 < offset < +26:00. Match any time in that
- range by assuming local time is -25:00 and then matching
- any ``local'' time T in the range 0 < T < 25+26 hours. */
- stamp = str2time (&u, initial_time, -25L * 60 * 60);
- if (0 < stamp && stamp < (25 + 26) * 60L * 60)
+ -25:00 < offset < +26:00. Match any time in that range. */
+ if (!(set_time || set_utc)
+ && 25 * 60L * 60 < stamp && stamp < 26 * 60L * 60)
stamp = 0;
- }
-
- if (*u && ! ISSPACE ((unsigned char) *u))
- stamp = (time_t) -1;
+ if (*u && ! ISSPACE ((unsigned char) *u))
+ stamp = (time_t) -1;
+ }
*t = '\0';
break;
}

View File

@ -1,74 +0,0 @@
---
util.c | 30 +++++++++++++++++++++++++++---
util.h | 2 ++
2 files changed, 29 insertions(+), 3 deletions(-)
Index: b/util.c
===================================================================
--- a/util.c
+++ b/util.c
@@ -466,10 +466,9 @@ remove_prefix (char *p, size_t prefixlen
continue;
}
-char *
-format_linenum (char numbuf[LINENUM_LENGTH_BOUND + 1], LINENUM n)
+static char *
+__format_linenum (char *p, LINENUM n)
{
- char *p = numbuf + LINENUM_LENGTH_BOUND;
*p = '\0';
if (n < 0)
@@ -490,6 +489,31 @@ format_linenum (char numbuf[LINENUM_LENG
return p;
}
+char *
+format_linenum (char numbuf[LINENUM_LENGTH_BOUND + 1], LINENUM n)
+{
+ return __format_linenum(numbuf + LINENUM_LENGTH_BOUND, n);
+}
+
+char *
+format_startcount (char rangebuf[LINERANGE_LENGTH_BOUND + 1],
+ LINENUM first, LINENUM lines)
+{
+ char *p = rangebuf + LINERANGE_LENGTH_BOUND;
+
+ if (lines == 1)
+ rangebuf = __format_linenum (p, first);
+ else
+ {
+ if (lines == 0 && first == 1)
+ first = 0; /* what diff produces ... */
+ p = __format_linenum(p, lines);
+ rangebuf = __format_linenum(--p, first);
+ *p = ',';
+ }
+ return rangebuf;
+}
+
#if !HAVE_VPRINTF
#define vfprintf my_vfprintf
static int
Index: b/util.h
===================================================================
--- a/util.h
+++ b/util.h
@@ -25,6 +25,7 @@
/* An upper bound on the print length of a signed decimal line number.
Add one for the sign. */
#define LINENUM_LENGTH_BOUND (sizeof (LINENUM) * CHAR_BIT / 3 + 1)
+#define LINERANGE_LENGTH_BOUND (LINENUM_LENGTH_BOUND * 2 + 1)
XTERN enum backup_type backup_type;
@@ -45,6 +46,7 @@ bool version_get (char const *, char con
int create_file (char const *, int, mode_t);
int systemic (char const *);
char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], LINENUM);
+char *format_startcount (char[LINERANGE_LENGTH_BOUND + 1], LINENUM, LINENUM);
void Fseek (FILE *, file_offset, int);
void copy_file (char const *, char const *, int, mode_t);
void exit_with_signal (int) __attribute__ ((noreturn));

View File

@ -1,130 +0,0 @@
---
patch.c | 33 ++++++++++++++++++++++++++++-----
patch.man | 9 +++++++++
2 files changed, 37 insertions(+), 5 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -101,6 +101,7 @@ static int Argc;
static char * const *Argv;
static FILE *rejfp; /* reject file pointer */
+char *global_reject;
static char const *patchname;
static char *rejname;
@@ -175,6 +176,10 @@ main (int argc, char **argv)
/* Make sure we clean up in case of disaster. */
set_signals (false);
+ /* initialize global reject file */
+ if (global_reject)
+ init_reject ();
+
for (
open_patch_file (patchname);
there_is_another_patch();
@@ -211,8 +216,9 @@ main (int argc, char **argv)
init_output (TMPOUTNAME, exclusive, &outstate);
}
- /* initialize reject file */
- init_reject ();
+ /* initialize per-patch reject file */
+ if (!global_reject)
+ init_reject ();
/* find out where all the lines are */
if (!skip_rest_of_patch)
@@ -335,7 +341,8 @@ main (int argc, char **argv)
fclose (outstate.ofp);
outstate.ofp = 0;
}
- fclose (rejfp);
+ if (!global_reject)
+ fclose (rejfp);
continue;
}
@@ -415,13 +422,13 @@ main (int argc, char **argv)
}
}
if (diff_type != ED_DIFF) {
- if (fclose (rejfp) != 0)
+ if (!global_reject && fclose (rejfp) != 0)
write_fatal ();
if (failed) {
somefailed = true;
say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),
skip_rest_of_patch ? "ignored" : "FAILED");
- if (outname) {
+ if (!global_reject && outname) {
char *rej = rejname;
if (!rejname) {
rej = xmalloc (strlen (outname) + 5);
@@ -448,6 +455,17 @@ main (int argc, char **argv)
}
set_signals (true);
}
+ if (global_reject)
+ {
+ if (fclose (rejfp) != 0)
+ write_fatal ();
+ if (somefailed)
+ {
+ say (" -- saving rejects to file %s\n", quotearg (global_reject));
+ move_file (TMPREJNAME, &TMPREJNAME_needs_removal,
+ global_reject, 0644, false);
+ }
+ }
if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
write_fatal ();
cleanup ();
@@ -526,6 +544,7 @@ static struct option const longopts[] =
{"posix", no_argument, NULL, CHAR_MAX + 7},
{"quoting-style", required_argument, NULL, CHAR_MAX + 8},
{"unified-reject-files", no_argument, NULL, CHAR_MAX + 9},
+ {"global-reject-file", required_argument, NULL, CHAR_MAX + 10},
{NULL, no_argument, NULL, 0}
};
@@ -585,6 +604,7 @@ static char const *const option_help[] =
" --dry-run Do not actually change any files; just print what would happen.",
" --posix Conform to the POSIX standard.",
" --unified-reject-files Create unified reject files.",
+" --global-reject-file=file Put all rejects into one file.",
"",
" -d DIR --directory=DIR Change the working directory to DIR first.",
#if HAVE_SETMODE_DOS
@@ -787,6 +807,9 @@ get_some_switches (void)
case CHAR_MAX + 9:
abort_hunk = abort_hunk_unified;
break;
+ case CHAR_MAX + 10:
+ global_reject = savestr (optarg);
+ break;
default:
usage (stderr, 2);
}
Index: b/patch.man
===================================================================
--- a/patch.man
+++ b/patch.man
@@ -520,6 +520,15 @@ file.
\fB\*=unified\-reject\-files\fP
Produce unified reject files. The default is to produce context type reject files.
.TP
+.BI \*=global\-reject\-file= rejectfile
+Put all rejects into
+.I rejectfile
+instead of creating separate reject files for all files that have rejects. The
+.I rejectfile
+will contain headers that identify which file each reject refers to. Note that
+the global reject file is created even if \-\-dry\-run is specified (while
+non-global reject files will only be created without \-\-dry\-run).
+.TP
\fB\-R\fP or \fB\*=reverse\fP
Assume that this patch was created with the old and new files swapped.
(Yes, I'm afraid that does happen occasionally, human nature being what it

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3645c3b7a0e9d77ed2136a122f28df472d812f0349c038ed13e1194f6f8d170b
size 240329

View File

@ -1,96 +0,0 @@
---
patch.c | 2 +-
util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
util.h | 1 +
3 files changed, 52 insertions(+), 1 deletion(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -440,7 +440,7 @@ main (int argc, char **argv)
{
move_file (TMPREJNAME, &TMPREJNAME_needs_removal,
rej, instat.st_mode, false);
- if (! inerrno
+ if (! inerrno && !s_is_chrblkfifosock(rej)
&& (chmod (rej, (instat.st_mode
& ~(S_IXUSR|S_IXGRP|S_IXOTH)))
!= 0))
Index: b/util.c
===================================================================
--- a/util.c
+++ b/util.c
@@ -65,6 +65,49 @@ static bool fid_search (const char *, co
FROM_NEEDS_REMOVAL must be nonnull if FROM is nonnull.
Back up TO if BACKUP is true. */
+int
+s_is_chrblkfifosock (const char *path)
+{
+ int r;
+ struct stat st;
+
+ r = stat(path, &st);
+ if (r < 0)
+ return r;
+
+ return (((st.st_mode & S_IFMT) == S_IFCHR) ||
+ ((st.st_mode & S_IFMT) == S_IFBLK) ||
+ ((st.st_mode & S_IFMT) == S_IFIFO) ||
+ ((st.st_mode & S_IFMT) == S_IFSOCK));
+}
+
+void
+cat_file_to_dev (const char *from, const char *to)
+{
+ size_t i;
+ int fromfd, tofd;
+
+ fromfd = open(from, O_RDONLY);
+ if (fromfd < 0)
+ pfatal("could not open %s for reading", quotearg(from));
+
+ tofd = open(to, O_WRONLY | O_NONBLOCK);
+ if (tofd < 0)
+ pfatal("could not open %s for writing", quotearg(to));
+
+ while ((i = read (fromfd, buf, bufsize)) != 0)
+ {
+ if (i == (size_t) -1)
+ read_fatal ();
+ if (write (tofd, buf, i) != i)
+ write_fatal ();
+ }
+ if (close (fromfd) != 0)
+ read_fatal ();
+ if (close (tofd) != 0)
+ write_fatal ();
+}
+
void
move_file (char const *from, int volatile *from_needs_removal,
char *to, mode_t mode, bool backup)
@@ -165,6 +208,13 @@ move_file (char const *from, int volatil
goto rename_succeeded;
}
+ if (errno == EACCES && (s_is_chrblkfifosock(to) > 0))
+ {
+ cat_file_to_dev (from, to);
+ unlink(from);
+ return;
+ }
+
if (errno == EXDEV)
{
if (! backup)
Index: b/util.h
===================================================================
--- a/util.h
+++ b/util.h
@@ -59,3 +59,4 @@ void remove_prefix (char *, size_t);
void removedirs (char *);
void set_signals (bool);
void write_fatal (void) __attribute__ ((noreturn));
+int s_is_chrblkfifosock (const char *);

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:612a424b80bccf4638059742dc77676387c75a880723fc990a5d3a0ad0799de3
size 158619

View File

@ -1,221 +0,0 @@
---
patch.c | 42 +++++++++++++++++++++++++++++++--------
tests/unified-reject-files.shrun | 32 ++++++++++++++++++++++-------
2 files changed, 58 insertions(+), 16 deletions(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -66,8 +66,8 @@ static bool patch_match (LINENUM, LINENU
static bool similar (char const *, size_t, char const *, size_t);
static bool spew_output (struct outstate *);
static char const *make_temp (char);
-static void abort_hunk_context (void);
-static void abort_hunk_unified (void);
+static void abort_hunk_context (bool, bool);
+static void abort_hunk_unified (bool, bool);
static int numeric_string (char const *, bool, char const *);
static void cleanup (void);
static void get_some_switches (void);
@@ -77,7 +77,7 @@ static void reinitialize_almost_everythi
static void remove_if_needed (char const *, int volatile *);
static void usage (FILE *, int) __attribute__((noreturn));
-static void (*abort_hunk) (void) = abort_hunk_context;
+static void (*abort_hunk) (bool, bool) = abort_hunk_context;
static bool make_backups;
static bool backup_if_mismatch;
@@ -281,7 +281,7 @@ main (int argc, char **argv)
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
- abort_hunk();
+ abort_hunk(!failed, reverse);
failed++;
if (verbosity == VERBOSE)
say ("Hunk #%d ignored at %s.\n", hunk,
@@ -295,14 +295,14 @@ main (int argc, char **argv)
say ("Patch attempted to create file %s, which already exists.\n",
quotearg (inname));
- abort_hunk();
+ abort_hunk(!failed, reverse);
failed++;
if (verbosity != SILENT)
say ("Hunk #%d FAILED at %s.\n", hunk,
format_linenum (numbuf, newwhere));
}
else if (! apply_hunk (&outstate, where)) {
- abort_hunk ();
+ abort_hunk (!failed, reverse);
failed++;
if (verbosity != SILENT)
say ("Hunk #%d FAILED at %s.\n", hunk,
@@ -938,7 +938,24 @@ locate_hunk (LINENUM fuzz)
/* We did not find the pattern, dump out the hunk so they can handle it. */
static void
-abort_hunk_context (void)
+print_header_line(FILE *fp, const char *tag, bool reverse)
+{
+ const char *name = pch_name(reverse);
+ time_t time = pch_timestamp(reverse);
+ char timebuf[37];
+
+ if (time != -1) {
+ timebuf[0] = '\t';
+ strftime(timebuf + 1, sizeof(timebuf),
+ "%Y-%m-%d %H:%M:%S %z",
+ (set_utc ? gmtime : localtime)(&time));
+ } else
+ *timebuf = '\0';
+ fprintf(fp, "%s %s%s\n", tag, name ? name : "/dev/null", timebuf);
+}
+
+static void
+abort_hunk_context (bool header, bool reverse)
{
register LINENUM i;
register LINENUM pat_end = pch_end ();
@@ -953,6 +970,10 @@ abort_hunk_context (void)
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
char const *c_function = pch_c_function();
+ if (header) {
+ print_header_line(rejfp, "***", reverse);
+ print_header_line(rejfp, "---", ! reverse);
+ }
fprintf(rejfp, "***************%s\n", c_function ? c_function : "");
for (i=0; i<=pat_end; i++) {
char numbuf0[LINENUM_LENGTH_BOUND + 1];
@@ -1066,7 +1087,7 @@ print_unified(FILE *fp)
}
static void
-abort_hunk_unified (void)
+abort_hunk_unified (bool header, bool reverse)
{
char rangebuf0[LINERANGE_LENGTH_BOUND + 1];
char rangebuf1[LINERANGE_LENGTH_BOUND + 1];
@@ -1074,6 +1095,11 @@ abort_hunk_unified (void)
LINENUM newfirst = pch_newfirst () + last_offset;
char const *c_function = pch_c_function ();
+ if (header)
+ {
+ print_header_line (rejfp, "---", reverse);
+ print_header_line (rejfp, "+++", ! reverse);
+ }
fprintf (rejfp, "@@ -%s +%s @@%s\n",
format_startcount (rangebuf0, oldfirst, pch_ptrn_lines ()),
format_startcount (rangebuf1, newfirst, pch_repl_lines ()),
Index: b/tests/unified-reject-files.shrun
===================================================================
--- a/tests/unified-reject-files.shrun
+++ b/tests/unified-reject-files.shrun
@@ -1,4 +1,6 @@
-$ PATCH=$(pwd)/patch
+$ PATCH=$(PATH=.:$PATH which patch)
+$ patch() { $PATCH "$@"; }
+
$ tmpdir=$(mktemp -d)
$ trap "cd /; rm -rf $tmpdir" EXIT
$ cd $tmpdir
@@ -17,12 +19,14 @@ $ diff -U0 -p \
+ -L "f 2009-02-07 14:49:03.000000000 +0100" \
+ f.orig f > f.diff
-$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff
+$ patch -f -F0 -s --no-backup-if-mismatch f < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
Note: patch cannot deal with nanosecond timestamps :-(
$ cat f.rej
+> *** f.orig 2009-02-07 14:49:02 +0100
+> --- f 2009-02-07 14:49:03 +0100
> *************** a() {
> *** 5 ****
> - 5
@@ -30,38 +34,46 @@ $ cat f.rej
> + 5a
$ diff -U0 -p -L f.orig -L f f.orig f > f.diff
-$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
+$ patch -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
$ cat f.rej
+> --- f.orig
+> +++ f
> @@ -5 +5 @@ a() {
> -5
> +5a
-$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff
+$ patch -f -F0 -s --no-backup-if-mismatch f < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
$ cat f.rej
+> *** f.orig
+> --- f
> *************** a() {
> *** 5 ****
> - 5
> --- 5 ----
> + 5a
-$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff
+$ patch -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.orig.rej
$ cat f.orig.rej
+> --- f
+> +++ f.orig
> @@ -5 +5 @@ a() {
> -5a
> +5
$ diff -U2 -p -L f.orig -L f f.orig f > f.diff
$ sed -e 's/5/5a/' -e 's/6/6x/' f.orig > f
-$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
+$ patch -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
$ cat f.rej
+> --- f.orig
+> +++ f
> @@ -3,5 +3,5 @@ a() {
> 3
>
@@ -70,10 +82,12 @@ $ cat f.rej
> 6
> }
-$ $PATCH -F0 -s --no-backup-if-mismatch f < f.diff
+$ patch -F0 -s --no-backup-if-mismatch f < f.diff
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
$ cat f.rej
+> *** f.orig
+> --- f
> *************** a() {
> *** 3,7 ****
> 3
@@ -89,11 +103,13 @@ $ cat f.rej
> }
$ diff -Nu -p -L /dev/null -L f.orig /dev/null f.orig > f2.diff
-$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff
+$ patch -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff
> Patch attempted to create file f, which already exists.
> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
$ cat f.rej
+> --- /dev/null 1970-01-01 00:00:00 +0000
+> +++ f.orig
> @@ -0,0 +1,7 @@
> +a() {
> +2

View File

@ -1,3 +1,10 @@
-------------------------------------------------------------------
Thu Apr 2 16:21:14 CEST 2009 - agruen@suse.de
- Update to version patch-2.5.9.69 which has all our patches
merged in one form or anther, along with many other fixes and
improvements (see NEWS).
-------------------------------------------------------------------
Tue Feb 24 12:56:06 CET 2009 - agruen@suse.de

View File

@ -1,5 +1,5 @@
#
# spec file for package patch (Version 2.5.9)
# spec file for package patch (Version 2.5.9.70)
#
# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
@ -17,35 +17,18 @@
# norootforbuild
Url: ftp://alpha.gnu.org/gnu/diffutils/
%define ver 2.5.9-70-g71a9b5b
Name: patch
BuildRequires: ed
License: GPL v2 or later
Group: Productivity/Text/Utilities
AutoReqProv: on
Version: 2.5.9
Release: 288
Version: 2.5.9.70
Release: 1
Summary: GNU patch
Source: ftp://prep.ai.mit.edu/pub/gnu/patch/%{name}-%{version}.tar.bz2
Url: ftp://alpha.gnu.org/gnu/diffutils/
Patch: trailing-cr-fix.diff
Patch1: remember-backup-files.diff
Patch2: pch_c_function.diff
Patch3: pch_name.diff
Patch4: preserve-c_function-in-reject-files.diff
Patch5: format_startcount.diff
Patch6: fix-timestamp-parsing.diff
Patch7: unified-reject-files.diff
Patch8: patch-headers-in-reject-files.diff
Patch9: global-reject-file.diff
Patch10: patch-2.5.9-cat_if_device.diff
Patch11: fix-partial-context.diff
Patch12: explain-pch_char-oddity.diff
Patch13: diff3-style-merges-tests.diff
Patch14: diff3-style-merges-refactoring.diff
Patch15: diff3-style-merges-refactoring-2.diff
Patch16: diff3-style-merges-simple-merge.diff
Patch17: diff3-style-merges-add-file-labels.diff
Patch18: diff3-style-merges-locate-merge.diff
Source: ftp://alpha.gnu.org/gnu/patch/patch-%ver.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
@ -60,44 +43,18 @@ Authors:
Paul Eggert
%prep
%setup -q
%suse_update_config
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%setup -n patch-%ver
%build
aclocal --acdir=m4
autoheader
autoconf
CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE -Wall -O2 -pipe" \
./configure \
%ifarch sparc sparc64
--disable-largefile \
%endif
--prefix=%{_prefix}
make CPPFLAGS=""
CFLAGS="$RPM_OPT_FLAGS -Wall -O2 -pipe" \
./configure --prefix=%{_prefix}
make #CPPFLAGS=""
%check
make check
%install
make install \
bindir=$RPM_BUILD_ROOT%{_bindir} \
man1dir=$RPM_BUILD_ROOT%{_mandir}/man1
make install DESTDIR=$RPM_BUILD_ROOT
%files
%defattr(-,root,root)
@ -106,6 +63,10 @@ make install \
%doc %{_mandir}/man1/patch.1.gz
%changelog
* Thu Apr 02 2009 agruen@suse.de
- Update to version patch-2.5.9.69 which has all our patches
merged in one form or anther, along with many other fixes and
improvements (see NEWS).
* Tue Feb 24 2009 agruen@suse.de
- Include patch headers in reject files so that they form proper
patches themselves.

View File

@ -1,84 +0,0 @@
FIXME: free()
---
pch.c | 32 +++++++++++++++++++++++++++++++-
pch.h | 1 +
2 files changed, 32 insertions(+), 1 deletion(-)
Index: b/pch.c
===================================================================
--- a/pch.c
+++ b/pch.c
@@ -68,6 +68,7 @@ static LINENUM p_sline; /* and the lin
static LINENUM p_hunk_beg; /* line number of current hunk */
static LINENUM p_efake = -1; /* end of faked up lines--don't free */
static LINENUM p_bfake = -1; /* beg of faked up lines */
+static char *p_c_function; /* the C function a hunk is in */
enum nametype { OLD, NEW, INDEX, NONE };
@@ -888,6 +889,19 @@ another_hunk (enum diff difftype, bool r
next_intuit_at(line_beginning,p_input_line);
return chars_read == (size_t) -1 ? -1 : 0;
}
+ s = buf;
+ while (*s == '*')
+ s++;
+ if (*s == ' ')
+ {
+ p_c_function = s;
+ while (*s != '\n')
+ s++;
+ *s = '\0';
+ p_c_function = savestr (p_c_function);
+ }
+ else
+ p_c_function = NULL;
p_hunk_beg = p_input_line + 1;
while (p_end < p_max) {
chars_read = get_line ();
@@ -1277,8 +1291,18 @@ another_hunk (enum diff difftype, bool r
else
p_repl_lines = 1;
if (*s == ' ') s++;
- if (*s != '@')
+ if (*s++ != '@')
malformed ();
+ if (*s++ == '@' && *s == ' ' && *s != '\0')
+ {
+ p_c_function = s;
+ while (*s != '\n')
+ s++;
+ *s = '\0';
+ p_c_function = savestr (p_c_function);
+ }
+ else
+ p_c_function = NULL;
if (!p_ptrn_lines)
p_first++; /* do append rather than insert */
if (!p_repl_lines)
@@ -1884,6 +1908,12 @@ pch_hunk_beg (void)
return p_hunk_beg;
}
+char const *
+pch_c_function (void)
+{
+ return p_c_function;
+}
+
/* Is the newline-terminated line a valid `ed' command for patch
input? If so, return the command character; if not, return 0.
This accepts accepts just a subset of the valid commands, but it's
Index: b/pch.h
===================================================================
--- a/pch.h
+++ b/pch.h
@@ -25,6 +25,7 @@
LINENUM pch_end (void);
LINENUM pch_first (void);
LINENUM pch_hunk_beg (void);
+char const *pch_c_function (void);
LINENUM pch_newfirst (void);
LINENUM pch_prefix_context (void);
LINENUM pch_ptrn_lines (void);

View File

@ -1,281 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: diff3-style merges: pch_name()
Make a pch_name() function available for accessing the old and the new
filename in the patch header.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
pch.c | 88 ++++++++++++++++++++++++++++++++++--------------------------------
pch.h | 3 ++
2 files changed, 49 insertions(+), 42 deletions(-)
Index: b/pch.c
===================================================================
--- a/pch.c
+++ b/pch.c
@@ -43,6 +43,7 @@ static int p_says_nonexistent[2]; /* [0]
1 for existent and probably (but not necessarily) empty,
2 for nonexistent */
static int p_rfc934_nesting; /* RFC 934 nesting level */
+static char *p_name[3]; /* filenames in patch headers */
static time_t p_timestamp[2]; /* timestamps in patch headers */
static off_t p_filesize; /* size of the patch file */
static LINENUM p_first; /* 1st line number */
@@ -70,8 +71,6 @@ static LINENUM p_efake = -1; /* end of
static LINENUM p_bfake = -1; /* beg of faked up lines */
static char *p_c_function; /* the C function a hunk is in */
-enum nametype { OLD, NEW, INDEX, NONE };
-
static char *scan_linenum (char *, LINENUM *);
static enum diff intuit_diff_type (void);
static enum nametype best_name (char * const *, int const *);
@@ -300,13 +299,17 @@ intuit_diff_type (void)
register bool this_is_a_command = false;
register bool stars_this_line = false;
enum nametype i;
- char *name[3];
struct stat st[3];
int stat_errno[3];
int version_controlled[3];
register enum diff retval;
- name[OLD] = name[NEW] = name[INDEX] = 0;
+ for (i = OLD; i <= INDEX; i++)
+ if (p_name[i]) {
+ free (p_name[i]);
+ p_name[i] = 0;
+ }
+
version_controlled[OLD] = -1;
version_controlled[NEW] = -1;
version_controlled[INDEX] = -1;
@@ -365,16 +368,16 @@ intuit_diff_type (void)
p_strip_trailing_cr = strip_trailing_cr;
}
if (!stars_last_line && strnEQ(s, "*** ", 4))
- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
else if (strnEQ(s, "+++ ", 4))
{
/* Swap with NEW below. */
- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
p_strip_trailing_cr = strip_trailing_cr;
}
else if (strnEQ(s, "Index:", 6))
{
- name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
+ p_name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
p_strip_trailing_cr = strip_trailing_cr;
}
else if (strnEQ(s, "Prereq:", 7)) {
@@ -410,7 +413,7 @@ intuit_diff_type (void)
if (strnEQ(t, "--- ", 4))
{
time_t timestamp = (time_t) -1;
- name[NEW] = fetchname (t+4, strippath, &timestamp);
+ p_name[NEW] = fetchname (t+4, strippath, &timestamp);
if (timestamp != (time_t) -1)
{
p_timestamp[NEW] = timestamp;
@@ -430,13 +433,13 @@ intuit_diff_type (void)
if ((diff_type == NO_DIFF || diff_type == UNI_DIFF)
&& strnEQ(s, "@@ -", 4)) {
- /* `name' and `p_timestamp' are backwards; swap them. */
+ /* `p_name' and `p_timestamp' are backwards; swap them. */
time_t ti = p_timestamp[OLD];
p_timestamp[OLD] = p_timestamp[NEW];
p_timestamp[NEW] = ti;
- t = name[OLD];
- name[OLD] = name[NEW];
- name[NEW] = t;
+ t = p_name[OLD];
+ p_name[OLD] = p_name[NEW];
+ p_name[NEW] = t;
s += 4;
if (s[0] == '0' && !ISDIGIT (s[1]))
@@ -451,9 +454,9 @@ intuit_diff_type (void)
p_start = this_line;
p_sline = p_input_line;
retval = UNI_DIFF;
- if (! ((name[OLD] || ! p_timestamp[OLD])
- && (name[NEW] || ! p_timestamp[NEW]))
- && ! name[INDEX])
+ if (! ((p_name[OLD] || ! p_timestamp[OLD])
+ && (p_name[NEW] || ! p_timestamp[NEW]))
+ && ! p_name[INDEX])
{
char numbuf[LINENUM_LENGTH_BOUND + 1];
say ("missing header for unified diff at line %s of patch\n",
@@ -492,9 +495,9 @@ intuit_diff_type (void)
next_intuit_at (saved_p_base, saved_p_bline);
}
- if (! ((name[OLD] || ! p_timestamp[OLD])
- && (name[NEW] || ! p_timestamp[NEW]))
- && ! name[INDEX])
+ if (! ((p_name[OLD] || ! p_timestamp[OLD])
+ && (p_name[NEW] || ! p_timestamp[NEW]))
+ && ! p_name[INDEX])
{
char numbuf[LINENUM_LENGTH_BOUND + 1];
say ("missing header for context diff at line %s of patch\n",
@@ -543,23 +546,23 @@ intuit_diff_type (void)
{
enum nametype i0 = NONE;
- if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX])
+ if (! posixly_correct && (p_name[OLD] || p_name[NEW]) && p_name[INDEX])
{
- free (name[INDEX]);
- name[INDEX] = 0;
+ free (p_name[INDEX]);
+ p_name[INDEX] = 0;
}
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
- if (i0 != NONE && strcmp (name[i0], name[i]) == 0)
+ if (i0 != NONE && strcmp (p_name[i0], p_name[i]) == 0)
{
/* It's the same name as before; reuse stat results. */
stat_errno[i] = stat_errno[i0];
if (! stat_errno[i])
st[i] = st[i0];
}
- else if (stat (name[i], &st[i]) != 0)
+ else if (stat (p_name[i], &st[i]) != 0)
stat_errno[i] = errno;
else
{
@@ -574,30 +577,30 @@ intuit_diff_type (void)
{
bool is_empty;
- i = best_name (name, stat_errno);
+ i = best_name (p_name, stat_errno);
if (i == NONE && patch_get)
{
enum nametype nope = NONE;
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
char const *cs;
char *getbuf;
char *diffbuf;
bool readonly = (outfile
- && strcmp (outfile, name[i]) != 0);
+ && strcmp (outfile, p_name[i]) != 0);
- if (nope == NONE || strcmp (name[nope], name[i]) != 0)
+ if (nope == NONE || strcmp (p_name[nope], p_name[i]) != 0)
{
cs = (version_controller
- (name[i], readonly, (struct stat *) 0,
+ (p_name[i], readonly, (struct stat *) 0,
&getbuf, &diffbuf));
version_controlled[i] = !! cs;
if (cs)
{
- if (version_get (name[i], cs, false, readonly,
+ if (version_get (p_name[i], cs, false, readonly,
getbuf, &st[i]))
stat_errno[i] = 0;
else
@@ -627,7 +630,7 @@ intuit_diff_type (void)
(i == NONE ? "delete"
: st[i].st_size == 0 ? "empty out"
: "create"),
- quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]),
+ quotearg (p_name[i == NONE || st[i].st_size == 0 ? i0 : i]),
(i == NONE ? "does not exist"
: st[i].st_size == 0 ? "is already empty"
: "already exists"));
@@ -640,19 +643,19 @@ intuit_diff_type (void)
int distance_from_minimum[3];
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
{
- newdirs[i] = (prefix_components (name[i], false)
- - prefix_components (name[i], true));
+ newdirs[i] = (prefix_components (p_name[i], false)
+ - prefix_components (p_name[i], true));
if (newdirs[i] < newdirs_min)
newdirs_min = newdirs[i];
}
for (i = OLD; i <= INDEX; i++)
- if (name[i])
+ if (p_name[i])
distance_from_minimum[i] = newdirs[i] - newdirs_min;
- i = best_name (name, distance_from_minimum);
+ i = best_name (p_name, distance_from_minimum);
}
}
}
@@ -661,17 +664,12 @@ intuit_diff_type (void)
inerrno = -1;
else
{
- inname = name[i];
- name[i] = 0;
+ inname = savestr(p_name[i]);
inerrno = stat_errno[i];
invc = version_controlled[i];
instat = st[i];
}
- for (i = OLD; i <= INDEX; i++)
- if (name[i])
- free (name[i]);
-
return retval;
}
@@ -1800,6 +1798,12 @@ pch_says_nonexistent (bool which)
return p_says_nonexistent[which];
}
+const char *
+pch_name (enum nametype type)
+{
+ return type == NONE ? NULL : p_name[type];
+}
+
/* Return timestamp of patch header for file WHICH (false = old, true = new),
or -1 if there was no timestamp or an error in the timestamp. */
Index: b/pch.h
===================================================================
--- a/pch.h
+++ b/pch.h
@@ -22,6 +22,8 @@
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+enum nametype { OLD, NEW, INDEX, NONE };
+
LINENUM pch_end (void);
LINENUM pch_first (void);
LINENUM pch_hunk_beg (void);
@@ -39,6 +41,7 @@ char pch_char (LINENUM);
int another_hunk (enum diff, bool);
int pch_says_nonexistent (bool);
size_t pch_line_len (LINENUM);
+const char *pch_name(enum nametype);
time_t pch_timestamp (bool);
void do_ed_script (FILE *);
void open_patch_file (char const *);

View File

@ -1,21 +0,0 @@
Include the C function names in reject files whenever possible.
---
patch.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -943,8 +943,9 @@ abort_hunk (void)
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : "";
char const *minuses =
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
+ char const *c_function = pch_c_function();
- fprintf(rejfp, "***************\n");
+ fprintf(rejfp, "***************%s\n", c_function ? c_function : "");
for (i=0; i<=pat_end; i++) {
char numbuf0[LINENUM_LENGTH_BOUND + 1];
char numbuf1[LINENUM_LENGTH_BOUND + 1];

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
From: "Paul Eggert" <eggert@twinsun.com>
Date: Wed, 2 Jul 2003 15:22:09 -0700
Subject: Re: patch bug with carriage returns
> From: Andreas Gruenbacher <agruen@suse.de>
> Date: Mon, 30 Jun 2003 13:43:33 +0200
> unified diffs with CRLF line endings are not recognized correctly
> anymore in 2.5.9. Here is a fix.
Thanks for the bug report. Unfortunately that fix doesn't handle the
case correctly where a Unix file contains a trailing CR in a header
line that is output by "diff -p" (trailing CR and all).
How about the following patch instead?
--- patch-2.5.9.orig/pch.c 2003/05/20 14:03:17 1.44
+++ patch-2.5.9/pch.c 2003/07/02 22:19:21 1.45
@@ -1,6 +1,6 @@
/* reading patches */
-/* $Id: pch.c,v 1.44 2003/05/20 14:03:17 eggert Exp $ */
+/* $Id: pch.c,v 1.45 2003/07/02 22:19:21 eggert Exp $ */
/* Copyright (C) 1986, 1987, 1988 Larry Wall
@@ -366,10 +366,16 @@ intuit_diff_type (void)
if (!stars_last_line && strnEQ(s, "*** ", 4))
name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
else if (strnEQ(s, "+++ ", 4))
+ {
/* Swap with NEW below. */
name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]);
+ p_strip_trailing_cr = strip_trailing_cr;
+ }
else if (strnEQ(s, "Index:", 6))
+ {
name[INDEX] = fetchname (s+6, strippath, (time_t *) 0);
+ p_strip_trailing_cr = strip_trailing_cr;
+ }
else if (strnEQ(s, "Prereq:", 7)) {
for (t = s + 7; ISSPACE ((unsigned char) *t); t++)
continue;
@@ -409,6 +415,7 @@ intuit_diff_type (void)
p_timestamp[NEW] = timestamp;
p_rfc934_nesting = (t - s) >> 1;
}
+ p_strip_trailing_cr = strip_trailing_cr;
}
}
if ((diff_type == NO_DIFF || diff_type == ED_DIFF) &&
#--- patch-2.5.9.orig/pch.c 2003-06-30 13:28:39.000000000 +0200
#+++ patch-2.5.9/pch.c 2003-06-30 13:28:03.000000000 +0200
#@@ -440,6 +440,7 @@
# if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2]))
# p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW];
# p_indent = indent;
#+ p_strip_trailing_cr = strip_trailing_cr;
# p_start = this_line;
# p_sline = p_input_line;
# retval = UNI_DIFF;

View File

@ -1,295 +0,0 @@
Generate unified diff style reject files.
---
patch.c | 104 +++++++++++++++++++++++++++++++++++++--
patch.man | 3 +
tests/unified-reject-files.shrun | 104 +++++++++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+), 3 deletions(-)
Index: b/patch.man
===================================================================
--- a/patch.man
+++ b/patch.man
@@ -517,6 +517,9 @@ instead of the default
.B \&.rej
file.
.TP
+\fB\*=unified\-reject\-files\fP
+Produce unified reject files. The default is to produce context type reject files.
+.TP
\fB\-R\fP or \fB\*=reverse\fP
Assume that this patch was created with the old and new files swapped.
(Yes, I'm afraid that does happen occasionally, human nature being what it
Index: b/patch.c
===================================================================
--- a/patch.c
+++ b/patch.c
@@ -66,8 +66,9 @@ static bool patch_match (LINENUM, LINENU
static bool similar (char const *, size_t, char const *, size_t);
static bool spew_output (struct outstate *);
static char const *make_temp (char);
+static void abort_hunk_context (void);
+static void abort_hunk_unified (void);
static int numeric_string (char const *, bool, char const *);
-static void abort_hunk (void);
static void cleanup (void);
static void get_some_switches (void);
static void init_output (char const *, int, struct outstate *);
@@ -76,6 +77,8 @@ static void reinitialize_almost_everythi
static void remove_if_needed (char const *, int volatile *);
static void usage (FILE *, int) __attribute__((noreturn));
+static void (*abort_hunk) (void) = abort_hunk_context;
+
static bool make_backups;
static bool backup_if_mismatch;
static char const *version_control;
@@ -522,6 +525,7 @@ static struct option const longopts[] =
{"no-backup-if-mismatch", no_argument, NULL, CHAR_MAX + 6},
{"posix", no_argument, NULL, CHAR_MAX + 7},
{"quoting-style", required_argument, NULL, CHAR_MAX + 8},
+ {"unified-reject-files", no_argument, NULL, CHAR_MAX + 9},
{NULL, no_argument, NULL, 0}
};
@@ -580,6 +584,7 @@ static char const *const option_help[] =
" --verbose Output extra information about the work being done.",
" --dry-run Do not actually change any files; just print what would happen.",
" --posix Conform to the POSIX standard.",
+" --unified-reject-files Create unified reject files.",
"",
" -d DIR --directory=DIR Change the working directory to DIR first.",
#if HAVE_SETMODE_DOS
@@ -779,6 +784,9 @@ get_some_switches (void)
(enum quoting_style) i);
}
break;
+ case CHAR_MAX + 9:
+ abort_hunk = abort_hunk_unified;
+ break;
default:
usage (stderr, 2);
}
@@ -930,7 +938,7 @@ locate_hunk (LINENUM fuzz)
/* We did not find the pattern, dump out the hunk so they can handle it. */
static void
-abort_hunk (void)
+abort_hunk_context (void)
{
register LINENUM i;
register LINENUM pat_end = pch_end ();
@@ -979,13 +987,103 @@ abort_hunk (void)
pch_write_line (i, rejfp);
break;
default:
- fatal ("fatal internal error in abort_hunk");
+ fatal ("fatal internal error in abort_hunk_context");
}
if (ferror (rejfp))
write_fatal ();
}
}
+/* Produce unified reject files */
+
+static void
+print_unified(FILE *fp)
+{
+ register LINENUM old = 1;
+ register LINENUM lastline = pch_ptrn_lines ();
+ register LINENUM new = lastline + 1;
+ register LINENUM pat_end = pch_end ();
+
+ while (pch_char (new) == '=' || pch_char (new) == '\n')
+ new++;
+
+ while (old <= lastline)
+ {
+ if (pch_char (old) == '-')
+ {
+ fputc ('-', fp);
+ pch_write_line (old++, fp);
+ }
+ else if (new > pat_end)
+ break;
+ else if (pch_char (new) == '+')
+ {
+ fputc ('+', fp);
+ pch_write_line (new++, fp);
+ }
+ else if (pch_char (new) != pch_char (old))
+ {
+ char numbuf0[LINENUM_LENGTH_BOUND + 1];
+ char numbuf1[LINENUM_LENGTH_BOUND + 1];
+ if (debug & 1)
+ say ("oldchar = '%c', newchar = '%c'\n",
+ pch_char (old), pch_char (new));
+ fatal ("Out-of-sync patch, lines %s,%s -- mangled text or "
+ "line numbers, maybe?",
+ format_linenum (numbuf0, pch_hunk_beg () + old),
+ format_linenum (numbuf1, pch_hunk_beg () + new));
+ }
+ else if (pch_char (new) == '!')
+ {
+ do
+ {
+ fputc ('-', fp);
+ pch_write_line (old++, fp);
+ }
+ while (pch_char (old) == '!');
+ do
+ {
+ fputc ('+', fp);
+ pch_write_line (new++, fp);
+ }
+ while (pch_char (new) == '!');
+ }
+ else
+ {
+ assert (pch_char (new) == ' ');
+ fputc (' ', fp);
+ pch_write_line (new, fp);
+ old++;
+ new++;
+ }
+ }
+ while (pch_char (new) == '+' || pch_char (new) == ' ')
+ {
+ fputc ('+', fp);
+ pch_write_line (new++, fp);
+ }
+ assert (new > pat_end);
+}
+
+static void
+abort_hunk_unified (void)
+{
+ char rangebuf0[LINERANGE_LENGTH_BOUND + 1];
+ char rangebuf1[LINERANGE_LENGTH_BOUND + 1];
+ LINENUM oldfirst = pch_first () + last_offset;
+ LINENUM newfirst = pch_newfirst () + last_offset;
+ char const *c_function = pch_c_function ();
+
+ fprintf (rejfp, "@@ -%s +%s @@%s\n",
+ format_startcount (rangebuf0, oldfirst, pch_ptrn_lines ()),
+ format_startcount (rangebuf1, newfirst, pch_repl_lines ()),
+ c_function ? c_function : "");
+ print_unified (rejfp);
+
+ if (ferror (rejfp))
+ write_fatal ();
+}
+
/* We found where to apply it (we hope), so do it. */
static bool
Index: b/tests/unified-reject-files.shrun
===================================================================
--- /dev/null
+++ b/tests/unified-reject-files.shrun
@@ -0,0 +1,104 @@
+$ PATCH=$(pwd)/patch
+$ tmpdir=$(mktemp -d)
+$ trap "cd /; rm -rf $tmpdir" EXIT
+$ cd $tmpdir
+$ cat > f.orig
+< a() {
+< 2
+< 3
+<
+< 5
+< 6
+< }
+
+$ sed -e 's/5/5a/' f.orig > f
+$ diff -U0 -p \
++ -L "f.orig 2009-02-07 14:49:02.000000000 +0100" \
++ -L "f 2009-02-07 14:49:03.000000000 +0100" \
++ f.orig f > f.diff
+
+$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+Note: patch cannot deal with nanosecond timestamps :-(
+
+$ cat f.rej
+> *************** a() {
+> *** 5 ****
+> - 5
+> --- 5 ----
+> + 5a
+
+$ diff -U0 -p -L f.orig -L f f.orig f > f.diff
+$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+$ cat f.rej
+> @@ -5 +5 @@ a() {
+> -5
+> +5a
+
+$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+$ cat f.rej
+> *************** a() {
+> *** 5 ****
+> - 5
+> --- 5 ----
+> + 5a
+
+$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.orig.rej
+
+$ cat f.orig.rej
+> @@ -5 +5 @@ a() {
+> -5a
+> +5
+
+$ diff -U2 -p -L f.orig -L f f.orig f > f.diff
+$ sed -e 's/5/5a/' -e 's/6/6x/' f.orig > f
+$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+$ cat f.rej
+> @@ -3,5 +3,5 @@ a() {
+> 3
+>
+> -5
+> +5a
+> 6
+> }
+
+$ $PATCH -F0 -s --no-backup-if-mismatch f < f.diff
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+$ cat f.rej
+> *************** a() {
+> *** 3,7 ****
+> 3
+>
+> - 5
+> 6
+> }
+> --- 3,7 ----
+> 3
+>
+> + 5a
+> 6
+> }
+
+$ diff -Nu -p -L /dev/null -L f.orig /dev/null f.orig > f2.diff
+$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff
+> Patch attempted to create file f, which already exists.
+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej
+
+$ cat f.rej
+> @@ -0,0 +1,7 @@
+> +a() {
+> +2
+> +3
+> +
+> +5
+> +6
+> +}