forked from pool/patch
This commit is contained in:
parent
4031722516
commit
940f272444
@ -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
|
@ -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
|
@ -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;
|
||||
|
@ -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)
|
@ -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
@ -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)
|
@ -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];
|
@ -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;
|
||||
}
|
@ -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));
|
@ -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
|
3
patch-2.5.9-70-g71a9b5b.tar.gz
Normal file
3
patch-2.5.9-70-g71a9b5b.tar.gz
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3645c3b7a0e9d77ed2136a122f28df472d812f0349c038ed13e1194f6f8d170b
|
||||
size 240329
|
@ -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 *);
|
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:612a424b80bccf4638059742dc77676387c75a880723fc990a5d3a0ad0799de3
|
||||
size 158619
|
@ -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
|
@ -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
|
||||
|
||||
|
77
patch.spec
77
patch.spec
@ -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.
|
||||
|
@ -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);
|
281
pch_name.diff
281
pch_name.diff
@ -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, ×tamp);
|
||||
+ p_name[NEW] = fetchname (t+4, strippath, ×tamp);
|
||||
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 *);
|
@ -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
@ -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;
|
@ -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
|
||||
+> +}
|
Loading…
Reference in New Issue
Block a user