This commit is contained in:
parent
e553963af3
commit
4031722516
@ -1,29 +1,36 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: diff3-style merges: add file labels
|
||||
|
||||
Add a --label=LABEL option for overriding the labels in the diff3-style
|
||||
format. The option can be given up to three times for overriding the
|
||||
old, new, and output filename.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
patch.c | 19 +++++++++++++++----
|
||||
1 file changed, 15 insertions(+), 4 deletions(-)
|
||||
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
|
||||
@@ -82,6 +82,7 @@ static void usage (FILE *, int) __attrib
|
||||
enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
|
||||
static enum mergetype mergetype;
|
||||
@@ -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;
|
||||
@@ -538,7 +539,7 @@ reinitialize_almost_everything (void)
|
||||
@@ -506,7 +508,7 @@ reinitialize_almost_everything (void)
|
||||
skip_rest_of_patch = false;
|
||||
}
|
||||
|
||||
@ -32,25 +39,25 @@ Index: b/patch.c
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"backup", no_argument, NULL, 'b'},
|
||||
@@ -553,6 +554,7 @@ static struct option const longopts[] =
|
||||
@@ -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'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
@@ -609,6 +611,7 @@ static char const *const option_help[] =
|
||||
@@ -577,6 +580,7 @@ static char const *const option_help[] =
|
||||
"",
|
||||
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
|
||||
" --merge={rejects,fuzz,all} Produce a diff3-style merge.",
|
||||
" -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).",
|
||||
@@ -747,6 +750,14 @@ get_some_switches (void)
|
||||
case 'l':
|
||||
canonicalize = true;
|
||||
@@ -718,6 +722,14 @@ get_some_switches (void)
|
||||
case 'M':
|
||||
merge = true;
|
||||
break;
|
||||
+ case 'L':
|
||||
+ if (!file_label[0])
|
||||
@ -60,11 +67,15 @@ Index: b/patch.c
|
||||
+ else
|
||||
+ fatal ("too many file label options");
|
||||
+ break;
|
||||
case 'M':
|
||||
mergetype |= MERGE_REJECTS;
|
||||
case 'n':
|
||||
diff_type = NORMAL_DIFF;
|
||||
break;
|
||||
@@ -1411,7 +1422,7 @@ static bool merge_hunk (struct outstate
|
||||
}
|
||||
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);
|
||||
@ -72,21 +83,23 @@ Index: b/patch.c
|
||||
if (!name)
|
||||
name = "";
|
||||
fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n",
|
||||
@@ -1426,7 +1437,7 @@ static bool merge_hunk (struct outstate
|
||||
|
||||
if (fuzz) {
|
||||
@@ -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",
|
||||
@@ -1453,7 +1464,7 @@ static bool merge_hunk (struct outstate
|
||||
|
||||
/* If the merge result and the new file are the same, label the merge
|
||||
@@ -112,8 +112,8 @@ merge_hunk (struct outstate *outstate)
|
||||
result with the new file's name. */
|
||||
- name = fuzz ? NULL : pch_name(NEW);
|
||||
+ name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] : pch_name(NEW));
|
||||
if (!name)
|
||||
name = "";
|
||||
fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
|
||||
if (same_result)
|
||||
{
|
||||
- name = pch_name(NEW);
|
||||
- if (!name)
|
||||
+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW);
|
||||
+ if (! name)
|
||||
name = "";
|
||||
}
|
||||
else
|
||||
|
@ -1,293 +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>
|
||||
|
||||
---
|
||||
patch.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 170 insertions(+), 5 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -61,6 +61,8 @@ struct outstate
|
||||
static FILE *create_output_file (char const *, int);
|
||||
static LINENUM locate_hunk (LINENUM);
|
||||
static bool apply_hunk (struct outstate *, LINENUM);
|
||||
+static bool common_context(LINENUM, LINENUM, LINENUM);
|
||||
+static bool merge_hunk (struct outstate *, LINENUM, 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);
|
||||
@@ -77,6 +79,9 @@ static void reinitialize_almost_everythi
|
||||
static void remove_if_needed (char const *, int volatile *);
|
||||
static void usage (FILE *, int) __attribute__((noreturn));
|
||||
|
||||
+enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2 };
|
||||
+static enum mergetype mergetype;
|
||||
+
|
||||
static bool make_backups;
|
||||
static bool backup_if_mismatch;
|
||||
static char const *version_control;
|
||||
@@ -117,7 +122,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];
|
||||
|
||||
@@ -184,6 +189,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,8 +301,17 @@ main (int argc, char **argv)
|
||||
} else if (!where) {
|
||||
goto skip_hunk;
|
||||
} else {
|
||||
- if (!apply_hunk (&outstate, where))
|
||||
- goto skip_hunk;
|
||||
+ if ((mergetype & SHOW_ALL) ||
|
||||
+ (fuzz && (mergetype & SHOW_FUZZ))) {
|
||||
+ if (merge_hunk(&outstate, where, fuzz)) {
|
||||
+ merged++;
|
||||
+ mismatch = true;
|
||||
+ } else
|
||||
+ goto skip_hunk;
|
||||
+ } else {
|
||||
+ if (!apply_hunk (&outstate, where))
|
||||
+ goto skip_hunk;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (verbosity == VERBOSE
|
||||
@@ -325,6 +340,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 +392,8 @@ skip_hunk:
|
||||
else
|
||||
{
|
||||
if (! outstate.zero_output
|
||||
- && pch_says_nonexistent (! reverse))
|
||||
+ && pch_says_nonexistent (! reverse)
|
||||
+ && !merged)
|
||||
{
|
||||
mismatch = true;
|
||||
if (verbosity != SILENT)
|
||||
@@ -468,7 +487,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;
|
||||
}
|
||||
@@ -544,6 +563,7 @@ static struct option const longopts[] =
|
||||
{"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},
|
||||
+ {"merge", required_argument, NULL, CHAR_MAX + 11},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -571,6 +591,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.",
|
||||
+" --merge={fuzz,all} Produce a diff3-style 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).",
|
||||
@@ -809,6 +830,23 @@ get_some_switches (void)
|
||||
case CHAR_MAX + 10:
|
||||
global_reject = savestr (optarg);
|
||||
break;
|
||||
+ case CHAR_MAX + 11:
|
||||
+ {
|
||||
+ char *tok = strtok(optarg, ",");
|
||||
+
|
||||
+ do {
|
||||
+ if (!strcmp(tok, "fuzz"))
|
||||
+ mergetype |= SHOW_FUZZ;
|
||||
+ else if (!strcmp(tok, "all"))
|
||||
+ mergetype |= SHOW_ALL;
|
||||
+ else {
|
||||
+ fprintf(stderr, "%s: invalid merge option %s\n",
|
||||
+ program_name, quotearg(tok));
|
||||
+ usage (stderr, 2);
|
||||
+ }
|
||||
+ } while ((tok = strtok(NULL, ",")));
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
usage (stderr, 2);
|
||||
}
|
||||
@@ -1264,6 +1302,133 @@ apply_hunk (struct outstate *outstate, L
|
||||
return true;
|
||||
}
|
||||
|
||||
+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));
|
||||
+}
|
||||
+
|
||||
+/* A FUZZ value of -1 indicates that the hunk could not be applied. */
|
||||
+
|
||||
+static bool merge_hunk (struct outstate *outstate, LINENUM where, LINENUM fuzz)
|
||||
+{
|
||||
+ register LINENUM old = 1;
|
||||
+ register LINENUM lastline = pch_ptrn_lines ();
|
||||
+ register LINENUM new = lastline + 1;
|
||||
+ register LINENUM pat_end = pch_end ();
|
||||
+ register LINENUM merge, merge_end;
|
||||
+ register FILE *fp = outstate->ofp;
|
||||
+ bool succeeded = true;
|
||||
+
|
||||
+ while (pch_char(new) == '=' || pch_char(new) == '\n' /* ??? */)
|
||||
+ new++;
|
||||
+
|
||||
+ /* Hide common prefix context */
|
||||
+ merge = where;
|
||||
+ while (old <= lastline && new <= pat_end) {
|
||||
+ if (!common_context(merge, old, new))
|
||||
+ break;
|
||||
+ old++;
|
||||
+ new++;
|
||||
+ merge++;
|
||||
+ }
|
||||
+
|
||||
+ if (fuzz != -1) {
|
||||
+ /* Hide common suffix context */
|
||||
+ merge_end = where + lastline - 1;
|
||||
+ while (old <= lastline && new <= pat_end) {
|
||||
+ if (!common_context(merge_end, lastline, pat_end))
|
||||
+ break;
|
||||
+ lastline--;
|
||||
+ pat_end--;
|
||||
+ merge_end--;
|
||||
+ }
|
||||
+ } else {
|
||||
+ LINENUM overlap = pch_suffix_context ();
|
||||
+
|
||||
+ /* Hide common suffix context: check how much overlap we have! */
|
||||
+ merge_end = merge - 1;
|
||||
+ while (overlap) {
|
||||
+ LINENUM n = 0;
|
||||
+
|
||||
+ merge_end += overlap;
|
||||
+ while (n < overlap && old <= lastline && new <= pat_end) {
|
||||
+ if (!common_context(merge_end, lastline, pat_end))
|
||||
+ break;
|
||||
+ lastline--;
|
||||
+ pat_end--;
|
||||
+ merge_end--;
|
||||
+ n++;
|
||||
+ }
|
||||
+ merge_end -= overlap - n;
|
||||
+ if (n == overlap)
|
||||
+ break;
|
||||
+ lastline += n;
|
||||
+ pat_end += n;
|
||||
+ overlap--;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ assert (outstate->after_newline);
|
||||
+ if (last_frozen_line < merge) {
|
||||
+ if (!copy_till(outstate, merge - 1))
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* "From" lines in the patch */
|
||||
+ fprintf(fp, outstate->after_newline + "\n<<<<<<<\n");
|
||||
+ if (ferror (fp))
|
||||
+ write_fatal ();
|
||||
+ outstate->after_newline = true;
|
||||
+ while (old <= lastline) {
|
||||
+ outstate->after_newline = pch_write_line(old, fp);
|
||||
+ old++;
|
||||
+ }
|
||||
+
|
||||
+ if (fuzz) {
|
||||
+ /* "To" lines in the patch */
|
||||
+ fprintf(fp, outstate->after_newline + "\n|||||||\n");
|
||||
+ if (ferror (fp))
|
||||
+ write_fatal ();
|
||||
+ outstate->after_newline = true;
|
||||
+ while (new <= pat_end) {
|
||||
+ outstate->after_newline = pch_write_line(new, fp);
|
||||
+ new++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (fuzz != -1) {
|
||||
+ /* Merge result */
|
||||
+ fprintf(fp, outstate->after_newline + "\n=======\n");
|
||||
+ if (ferror (fp))
|
||||
+ write_fatal ();
|
||||
+ outstate->after_newline = true;
|
||||
+
|
||||
+ succeeded = apply_hunk(outstate, where) &&
|
||||
+ copy_till(outstate, merge_end);
|
||||
+ }
|
||||
+
|
||||
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>\n");
|
||||
+ if (ferror (fp))
|
||||
+ write_fatal ();
|
||||
+ outstate->after_newline = true;
|
||||
+
|
||||
+ outstate->zero_output = false;
|
||||
+ return succeeded;
|
||||
+}
|
||||
+
|
||||
/* Create an output file. */
|
||||
|
||||
static FILE *
|
@ -1,73 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: diff3-style merges: include filenames
|
||||
|
||||
Include the filenames from the patch header in the diff3-style format.
|
||||
Use the name of the output file as the third filename.
|
||||
|
||||
<<<<<<< old-filename
|
||||
old lines from patch
|
||||
||||||| new-filename
|
||||
new lines from patch
|
||||
=======
|
||||
merge result
|
||||
>>>>>>> output-filename
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
patch.c | 21 ++++++++++++++++++---
|
||||
1 file changed, 18 insertions(+), 3 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -1353,6 +1353,7 @@ static bool merge_hunk (struct outstate
|
||||
register LINENUM merge, merge_end;
|
||||
register FILE *fp = outstate->ofp;
|
||||
bool succeeded = true;
|
||||
+ const char *name;
|
||||
|
||||
while (pch_char(new) == '=' || pch_char(new) == '\n' /* ??? */)
|
||||
new++;
|
||||
@@ -1410,7 +1411,11 @@ static bool merge_hunk (struct outstate
|
||||
}
|
||||
|
||||
/* "From" lines in the patch */
|
||||
- fprintf(fp, outstate->after_newline + "\n<<<<<<<\n");
|
||||
+ 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;
|
||||
@@ -1421,7 +1426,11 @@ static bool merge_hunk (struct outstate
|
||||
|
||||
if (fuzz) {
|
||||
/* "To" lines in the patch */
|
||||
- fprintf(fp, outstate->after_newline + "\n|||||||\n");
|
||||
+ 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;
|
||||
@@ -1442,7 +1451,13 @@ static bool merge_hunk (struct outstate
|
||||
copy_till(outstate, merge_end);
|
||||
}
|
||||
|
||||
- fprintf(fp, outstate->after_newline + "\n>>>>>>>\n");
|
||||
+ /* If the merge result and the new file are the same, label the merge
|
||||
+ result with the new file's name. */
|
||||
+ name = fuzz ? NULL : 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;
|
@ -1,70 +1,100 @@
|
||||
---
|
||||
patch.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 72 insertions(+), 6 deletions(-)
|
||||
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
|
||||
@@ -62,6 +62,8 @@ static FILE *create_output_file (char co
|
||||
static LINENUM locate_hunk (LINENUM);
|
||||
static bool apply_hunk (struct outstate *, LINENUM);
|
||||
static bool common_context(LINENUM, LINENUM, LINENUM);
|
||||
+static LINENUM min_mismatches(LINENUM, LINENUM);
|
||||
+static LINENUM locate_merge (void);
|
||||
static bool merge_hunk (struct outstate *, LINENUM, LINENUM);
|
||||
static void merge_ends_here(struct outstate *outstate);
|
||||
static bool copy_till (struct outstate *, LINENUM);
|
||||
@@ -304,15 +306,11 @@ main (int argc, char **argv)
|
||||
@@ -286,13 +286,22 @@ main (int argc, char **argv)
|
||||
goto skip_hunk;
|
||||
} else if (!where) {
|
||||
if (mergetype & MERGE_REJECTS) {
|
||||
- LINENUM guess = pch_first () + last_offset;
|
||||
-
|
||||
- if (merge_hunk(&outstate, guess, -1)) {
|
||||
+ if (merge_hunk(&outstate, locate_merge(), -1)) {
|
||||
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: guess harder! */
|
||||
+ } else
|
||||
goto skip_hunk;
|
||||
- /* FIXME: try harder! */
|
||||
- goto skip_hunk;
|
||||
- }
|
||||
+ }
|
||||
+ else
|
||||
+ goto skip_hunk;
|
||||
} else
|
||||
goto skip_hunk;
|
||||
} else {
|
||||
@@ -1356,6 +1354,74 @@ static bool common_context(LINENUM where
|
||||
memcmp(line, pfetch(new), size) == 0));
|
||||
}
|
||||
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);
|
||||
|
||||
+static LINENUM min_mismatches(LINENUM where, LINENUM lowest)
|
||||
+#define OFFSET LINENUM
|
||||
+#define EQUAL(x, y) (context_matches_file (x, y))
|
||||
+
|
||||
+#include "bestmatch.h"
|
||||
+
|
||||
+LINENUM
|
||||
+locate_merge (LINENUM fuzz, LINENUM *matched)
|
||||
+{
|
||||
+ register LINENUM ptrn_lines = pch_ptrn_lines();
|
||||
+ register LINENUM old, mismatched = 0;
|
||||
+
|
||||
+ for (old = 1; old <= ptrn_lines; old++, where++) {
|
||||
+ size_t size;
|
||||
+ const char *line;
|
||||
+
|
||||
+ line = ifetch (where, false, &size);
|
||||
+ if (!size ||
|
||||
+ !(canonicalize ?
|
||||
+ similar(pfetch(old), pch_line_len(old), line, size) :
|
||||
+ (size == pch_line_len(old) &&
|
||||
+ memcmp(line, pfetch(old), size) == 0))) {
|
||||
+ mismatched++;
|
||||
+ if (mismatched >= lowest)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ return mismatched;
|
||||
+}
|
||||
+
|
||||
+static LINENUM locate_merge ()
|
||||
+{
|
||||
+ register LINENUM first_guess = pch_first () + last_offset;
|
||||
+ register LINENUM lowest = input_lines, where = first_guess;
|
||||
+ register LINENUM offset;
|
||||
+ 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;
|
||||
@ -73,38 +103,235 @@ Index: b/patch.c
|
||||
+ 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;
|
||||
+ max_neg_offset = first_guess - 1;
|
||||
+
|
||||
+ for (offset = 0; offset <= max_offset; offset++) {
|
||||
+ if (offset <= max_pos_offset) {
|
||||
+ register LINENUM mismatched;
|
||||
+ for (offset = 0; offset <= max_offset; offset++)
|
||||
+ {
|
||||
+ if (offset <= max_pos_offset)
|
||||
+ {
|
||||
+ LINENUM guess = first_guess + offset;
|
||||
+ LINENUM last;
|
||||
+ LINENUM changes;
|
||||
+
|
||||
+ mismatched = min_mismatches(first_guess - offset, lowest);
|
||||
+ if (mismatched < lowest) {
|
||||
+ lowest = mismatched;
|
||||
+ where = first_guess - offset;
|
||||
+ if (lowest == 1)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (0 < offset && offset <= max_neg_offset) {
|
||||
+ register LINENUM mismatched;
|
||||
+ 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;
|
||||
+
|
||||
+ mismatched = min_mismatches(first_guess + offset, lowest);
|
||||
+ if (mismatched < lowest) {
|
||||
+ lowest = mismatched;
|
||||
+ where = first_guess + offset;
|
||||
+ if (lowest == 1)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ 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;
|
||||
+}
|
||||
+
|
||||
/* A FUZZ value of -1 indicates that the hunk could not be applied. */
|
||||
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++;
|
||||
|
||||
static bool merge_hunk (struct outstate *outstate, LINENUM where, LINENUM fuzz)
|
||||
- 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,36 +0,0 @@
|
||||
---
|
||||
patch.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -1459,6 +1459,18 @@ static bool merge_hunk (struct outstate
|
||||
R_merge_end--;
|
||||
}
|
||||
} else {
|
||||
+#if 1
|
||||
+ /* Hide common suffix context */
|
||||
+ R_merge_end = where + lastline - 1;
|
||||
+ while (old <= lastline && new <= pat_end) {
|
||||
+ if (!common_context(R_merge_end, lastline, pat_end))
|
||||
+ break;
|
||||
+ lastline--;
|
||||
+ pat_end--;
|
||||
+ R_merge_end--;
|
||||
+ }
|
||||
+ R_merge_end = merge - 1;
|
||||
+#else
|
||||
LINENUM overlap = pch_suffix_context ();
|
||||
|
||||
/* Hide common suffix context: check how much overlap we have! */
|
||||
@@ -1482,6 +1494,8 @@ static bool merge_hunk (struct outstate
|
||||
pat_end += n;
|
||||
overlap--;
|
||||
}
|
||||
+ /*assert(R_merge_end == merge - 1);*/
|
||||
+#endif
|
||||
}
|
||||
|
||||
assert (outstate->after_newline);
|
@ -1,249 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: diff3-style merges: overlapping merges
|
||||
|
||||
In some situations, hunks in a patch may apply so that their context
|
||||
lines overlap. Patch never commits context lines to the output until
|
||||
their contents are fully determined.
|
||||
|
||||
The diff3-style merge format may include context lines. For example,
|
||||
when he following patch:
|
||||
|
||||
# --- a
|
||||
# +++ b
|
||||
# @@ -2,3 +2,3 @@
|
||||
# x
|
||||
# -3
|
||||
# +3b
|
||||
# x
|
||||
|
||||
is applied to `seq 1 6` file with --merge=all, this is what you get (with
|
||||
fuzz 1):
|
||||
|
||||
1
|
||||
<<<<<<< a
|
||||
x
|
||||
3
|
||||
x
|
||||
||||||| b
|
||||
x
|
||||
3b
|
||||
x
|
||||
=======
|
||||
2
|
||||
3b
|
||||
4
|
||||
>>>>>>>
|
||||
5
|
||||
6
|
||||
|
||||
At this point, the first four lines of the output file are "frozen", and
|
||||
the next hunk cannot modify the fourth line anymore. This can cause the diff3-
|
||||
style merge format to reject hunks that would otherwise be accepted. To
|
||||
avoid this regression, this patch adds delayed printing of the end marker,
|
||||
with this effect on the merge format:
|
||||
|
||||
1
|
||||
<<<<<<< a
|
||||
x
|
||||
3
|
||||
x
|
||||
||||||| b
|
||||
x
|
||||
3b
|
||||
x
|
||||
=======
|
||||
2
|
||||
3b
|
||||
>>>>>>>
|
||||
<<<<<<< a
|
||||
x
|
||||
4
|
||||
x
|
||||
||||||| b
|
||||
x
|
||||
4b
|
||||
x
|
||||
=======
|
||||
4b
|
||||
5
|
||||
>>>>>>>
|
||||
6
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
patch.c | 71 +++++++++++++++++++++++++++++++++++++++++++---------------------
|
||||
1 file changed, 48 insertions(+), 23 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -63,6 +63,7 @@ static LINENUM locate_hunk (LINENUM);
|
||||
static bool apply_hunk (struct outstate *, LINENUM);
|
||||
static bool common_context(LINENUM, LINENUM, LINENUM);
|
||||
static bool merge_hunk (struct outstate *, LINENUM, LINENUM);
|
||||
+static void merge_ends_here(struct outstate *outstate);
|
||||
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);
|
||||
@@ -81,6 +82,8 @@ static void usage (FILE *, int) __attrib
|
||||
|
||||
enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
|
||||
static enum mergetype mergetype;
|
||||
+static LINENUM merge_end = -1;
|
||||
+static const char *merge_name;
|
||||
|
||||
const char *file_label[2];
|
||||
static bool make_backups;
|
||||
@@ -1361,7 +1364,7 @@ static bool merge_hunk (struct outstate
|
||||
register LINENUM lastline = pch_ptrn_lines ();
|
||||
register LINENUM new = lastline + 1;
|
||||
register LINENUM pat_end = pch_end ();
|
||||
- register LINENUM merge, merge_end;
|
||||
+ register LINENUM merge, R_merge_end;
|
||||
register FILE *fp = outstate->ofp;
|
||||
bool succeeded = true;
|
||||
const char *name;
|
||||
@@ -1381,32 +1384,32 @@ static bool merge_hunk (struct outstate
|
||||
|
||||
if (fuzz != -1) {
|
||||
/* Hide common suffix context */
|
||||
- merge_end = where + lastline - 1;
|
||||
+ R_merge_end = where + lastline - 1;
|
||||
while (old <= lastline && new <= pat_end) {
|
||||
- if (!common_context(merge_end, lastline, pat_end))
|
||||
+ if (!common_context(R_merge_end, lastline, pat_end))
|
||||
break;
|
||||
lastline--;
|
||||
pat_end--;
|
||||
- merge_end--;
|
||||
+ R_merge_end--;
|
||||
}
|
||||
} else {
|
||||
LINENUM overlap = pch_suffix_context ();
|
||||
|
||||
/* Hide common suffix context: check how much overlap we have! */
|
||||
- merge_end = merge - 1;
|
||||
+ R_merge_end = merge - 1;
|
||||
while (overlap) {
|
||||
LINENUM n = 0;
|
||||
|
||||
- merge_end += overlap;
|
||||
+ R_merge_end += overlap;
|
||||
while (n < overlap && old <= lastline && new <= pat_end) {
|
||||
- if (!common_context(merge_end, lastline, pat_end))
|
||||
+ if (!common_context(R_merge_end, lastline, pat_end))
|
||||
break;
|
||||
lastline--;
|
||||
pat_end--;
|
||||
- merge_end--;
|
||||
+ R_merge_end--;
|
||||
n++;
|
||||
}
|
||||
- merge_end -= overlap - n;
|
||||
+ R_merge_end -= overlap - n;
|
||||
if (n == overlap)
|
||||
break;
|
||||
lastline += n;
|
||||
@@ -1419,7 +1422,8 @@ static bool merge_hunk (struct outstate
|
||||
if (last_frozen_line < merge) {
|
||||
if (!copy_till(outstate, merge - 1))
|
||||
return false;
|
||||
- }
|
||||
+ } else
|
||||
+ merge_ends_here(outstate);
|
||||
|
||||
/* "From" lines in the patch */
|
||||
name = file_label[OLD] ? file_label[OLD] : pch_name(OLD);
|
||||
@@ -1458,25 +1462,41 @@ static bool merge_hunk (struct outstate
|
||||
write_fatal ();
|
||||
outstate->after_newline = true;
|
||||
|
||||
- succeeded = apply_hunk(outstate, where) &&
|
||||
- copy_till(outstate, merge_end);
|
||||
+ succeeded = apply_hunk(outstate, where);
|
||||
}
|
||||
|
||||
+ assert(merge_end == -1);
|
||||
+ merge_end = R_merge_end;
|
||||
+
|
||||
/* If the merge result and the new file are the same, label the merge
|
||||
result with the new file's name. */
|
||||
- name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] : 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;
|
||||
+ merge_name = fuzz ? NULL : (file_label[NEW] ? file_label[NEW] :
|
||||
+ pch_name(NEW));
|
||||
|
||||
outstate->zero_output = false;
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
+static void
|
||||
+merge_ends_here(struct outstate *outstate)
|
||||
+{
|
||||
+ register FILE *fp = outstate->ofp;
|
||||
+
|
||||
+ if (merge_end != -1)
|
||||
+ {
|
||||
+ if (!merge_name)
|
||||
+ merge_name = "";
|
||||
+ fprintf(fp, outstate->after_newline + "\n>>>>>>>%*s\n",
|
||||
+ strlen(merge_name) ? strlen(merge_name) + 1 : 0,
|
||||
+ merge_name);
|
||||
+ if (ferror (fp))
|
||||
+ write_fatal ();
|
||||
+ outstate->after_newline = true;
|
||||
+ outstate->zero_output = false;
|
||||
+ merge_end = -1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* Create an output file. */
|
||||
|
||||
static FILE *
|
||||
@@ -1516,6 +1536,7 @@ static bool
|
||||
copy_till (register struct outstate *outstate, register LINENUM lastline)
|
||||
{
|
||||
register LINENUM R_last_frozen_line = last_frozen_line;
|
||||
+ register LINENUM R_merge_end = (merge_end != -1) ? merge_end : lastline;
|
||||
register FILE *fp = outstate->ofp;
|
||||
register char const *s;
|
||||
size_t size;
|
||||
@@ -1527,6 +1548,9 @@ copy_till (register struct outstate *out
|
||||
}
|
||||
while (R_last_frozen_line < lastline)
|
||||
{
|
||||
+ if (R_merge_end == R_last_frozen_line)
|
||||
+ merge_ends_here(outstate);
|
||||
+
|
||||
s = ifetch (++R_last_frozen_line, false, &size);
|
||||
if (size)
|
||||
{
|
||||
@@ -1538,6 +1562,8 @@ copy_till (register struct outstate *out
|
||||
}
|
||||
}
|
||||
last_frozen_line = R_last_frozen_line;
|
||||
+ if (merge_end != -1)
|
||||
+ merge_ends_here(outstate);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1555,9 +1581,8 @@ spew_output (struct outstate *outstate)
|
||||
format_linenum (numbuf1, last_frozen_line));
|
||||
}
|
||||
|
||||
- if (last_frozen_line < input_lines)
|
||||
- if (! copy_till (outstate, input_lines))
|
||||
- return false;
|
||||
+ if (! copy_till (outstate, input_lines))
|
||||
+ return false;
|
||||
|
||||
if (outstate->ofp && ! outfile)
|
||||
{
|
@ -6,7 +6,7 @@ Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -286,32 +286,30 @@ main (int argc, char **argv)
|
||||
@@ -288,32 +288,30 @@ main (int argc, char **argv)
|
||||
newwhere = pch_newfirst() + last_offset;
|
||||
if (skip_rest_of_patch) {
|
||||
goto skip_hunk;
|
||||
@ -44,7 +44,7 @@ Index: b/patch.c
|
||||
+ if (!apply_hunk (&outstate, where))
|
||||
+ goto skip_hunk;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (verbosity == VERBOSE
|
||||
+ || (verbosity != SILENT && (fuzz || last_offset))) {
|
||||
+ say ("Hunk #%d succeeded at %s", hunk,
|
||||
|
@ -1,18 +1,16 @@
|
||||
---
|
||||
patch.c | 36 +++++++++++++++---------------------
|
||||
1 file changed, 15 insertions(+), 21 deletions(-)
|
||||
patch.c | 28 +++++++++++++---------------
|
||||
1 file changed, 13 insertions(+), 15 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -285,13 +285,7 @@ main (int argc, char **argv)
|
||||
@@ -287,11 +287,7 @@ main (int argc, char **argv)
|
||||
|
||||
newwhere = pch_newfirst() + last_offset;
|
||||
if (skip_rest_of_patch) {
|
||||
- if (!failed)
|
||||
- reject_header(outname);
|
||||
- abort_hunk();
|
||||
- abort_hunk(!failed, reverse);
|
||||
- failed++;
|
||||
- if (verbosity == VERBOSE)
|
||||
- say ("Hunk #%d ignored at %s.\n", hunk,
|
||||
@ -21,13 +19,11 @@ Index: b/patch.c
|
||||
}
|
||||
else if (!where
|
||||
|| (where == 1 && pch_says_nonexistent (reverse) == 2
|
||||
@@ -301,22 +295,10 @@ main (int argc, char **argv)
|
||||
@@ -301,18 +297,10 @@ main (int argc, char **argv)
|
||||
say ("Patch attempted to create file %s, which already exists.\n",
|
||||
quotearg (inname));
|
||||
|
||||
- if (!failed)
|
||||
- reject_header(outname);
|
||||
- abort_hunk();
|
||||
- abort_hunk(!failed, reverse);
|
||||
- failed++;
|
||||
- if (verbosity != SILENT)
|
||||
- say ("Hunk #%d FAILED at %s.\n", hunk,
|
||||
@ -35,9 +31,7 @@ Index: b/patch.c
|
||||
+ goto skip_hunk;
|
||||
}
|
||||
else if (! apply_hunk (&outstate, where)) {
|
||||
- if (!failed)
|
||||
- reject_header(outname);
|
||||
- abort_hunk ();
|
||||
- abort_hunk (!failed, reverse);
|
||||
- failed++;
|
||||
- if (verbosity != SILENT)
|
||||
- say ("Hunk #%d FAILED at %s.\n", hunk,
|
||||
@ -46,16 +40,14 @@ Index: b/patch.c
|
||||
} else {
|
||||
if (verbosity == VERBOSE
|
||||
|| (verbosity != SILENT && (fuzz || last_offset))) {
|
||||
@@ -331,6 +313,18 @@ main (int argc, char **argv)
|
||||
@@ -327,6 +315,16 @@ main (int argc, char **argv)
|
||||
say (".\n");
|
||||
}
|
||||
}
|
||||
+ continue;
|
||||
+
|
||||
+skip_hunk:
|
||||
+ if (!failed)
|
||||
+ reject_header(outname);
|
||||
+ abort_hunk ();
|
||||
+ abort_hunk(!failed, reverse);
|
||||
+ failed++;
|
||||
+ if (verbosity == VERBOSE ||
|
||||
+ (!skip_rest_of_patch && verbosity != SILENT))
|
||||
|
@ -1,116 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: diff3-style merges: merge rejects
|
||||
|
||||
With the --merge-all option, hunks which do not apply and which would
|
||||
end up in a *.rej file will also get added to output files. They will
|
||||
be bracketed like this:
|
||||
|
||||
<<<<<<<
|
||||
old lines from patch
|
||||
|||||||
|
||||
new lines from patch
|
||||
>>>>>>>
|
||||
|
||||
With this change, all pieces of a patch can be applied, and all the
|
||||
resulting merge conflicts can be fixed in the patched files instead
|
||||
of looking at the reject files.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
patch.c | 40 +++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 31 insertions(+), 9 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -79,7 +79,7 @@ static void reinitialize_almost_everythi
|
||||
static void remove_if_needed (char const *, int volatile *);
|
||||
static void usage (FILE *, int) __attribute__((noreturn));
|
||||
|
||||
-enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2 };
|
||||
+enum mergetype { SHOW_ALL = 1, SHOW_FUZZ = 2, MERGE_REJECTS = 4 };
|
||||
static enum mergetype mergetype;
|
||||
|
||||
static bool make_backups;
|
||||
@@ -299,7 +299,18 @@ main (int argc, char **argv)
|
||||
|
||||
goto skip_hunk;
|
||||
} else if (!where) {
|
||||
- goto skip_hunk;
|
||||
+ if (mergetype & MERGE_REJECTS) {
|
||||
+ LINENUM guess = pch_first () + last_offset;
|
||||
+
|
||||
+ if (merge_hunk(&outstate, guess, -1)) {
|
||||
+ merged++;
|
||||
+ mismatch = 1;
|
||||
+ } else {
|
||||
+ /* FIXME: guess harder! */
|
||||
+ goto skip_hunk;
|
||||
+ }
|
||||
+ } else
|
||||
+ goto skip_hunk;
|
||||
} else {
|
||||
if ((mergetype & SHOW_ALL) ||
|
||||
(fuzz && (mergetype & SHOW_FUZZ))) {
|
||||
@@ -316,10 +327,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 errors", 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),
|
||||
@@ -521,7 +538,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'},
|
||||
@@ -591,7 +608,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.",
|
||||
-" --merge={fuzz,all} Produce a diff3-style merge.",
|
||||
+" --merge={rejects,fuzz,all} Produce a diff3-style 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).",
|
||||
@@ -730,6 +747,9 @@ get_some_switches (void)
|
||||
case 'l':
|
||||
canonicalize = true;
|
||||
break;
|
||||
+ case 'M':
|
||||
+ mergetype |= MERGE_REJECTS;
|
||||
+ break;
|
||||
case 'n':
|
||||
diff_type = NORMAL_DIFF;
|
||||
break;
|
||||
@@ -835,7 +855,9 @@ get_some_switches (void)
|
||||
char *tok = strtok(optarg, ",");
|
||||
|
||||
do {
|
||||
- if (!strcmp(tok, "fuzz"))
|
||||
+ if (!strcmp(tok, "rejects"))
|
||||
+ mergetype |= MERGE_REJECTS;
|
||||
+ else if (!strcmp(tok, "fuzz"))
|
||||
mergetype |= SHOW_FUZZ;
|
||||
else if (!strcmp(tok, "all"))
|
||||
mergetype |= SHOW_ALL;
|
442
diff3-style-merges-simple-merge.diff
Normal file
442
diff3-style-merges-simple-merge.diff
Normal file
@ -0,0 +1,442 @@
|
||||
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
19
explain-pch_char-oddity.diff
Normal file
19
explain-pch_char-oddity.diff
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
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)
|
@ -13,6 +13,8 @@ are perfectly valid.
|
||||
patch.c | 43 ++++---------------------------------------
|
||||
2 files changed, 11 insertions(+), 39 deletions(-)
|
||||
|
||||
Index: b/ChangeLog
|
||||
===================================================================
|
||||
--- a/ChangeLog
|
||||
+++ b/ChangeLog
|
||||
@@ -1,3 +1,10 @@
|
||||
@ -26,9 +28,11 @@ are perfectly valid.
|
||||
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
|
||||
@@ -849,10 +849,10 @@ locate_hunk (LINENUM fuzz)
|
||||
@@ -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 ();
|
||||
@ -43,7 +47,7 @@ are perfectly valid.
|
||||
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;
|
||||
@@ -867,41 +867,6 @@ locate_hunk (LINENUM fuzz)
|
||||
@@ -898,41 +898,6 @@ locate_hunk (LINENUM fuzz)
|
||||
if (first_guess <= max_neg_offset)
|
||||
max_neg_offset = first_guess - 1;
|
||||
|
||||
|
58
fix-timestamp-parsing.diff
Normal file
58
fix-timestamp-parsing.diff
Normal file
@ -0,0 +1,58 @@
|
||||
* 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;
|
||||
}
|
74
format_startcount.diff
Normal file
74
format_startcount.diff
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
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,44 +1,21 @@
|
||||
Index: patch-2.5.9/patch.man
|
||||
---
|
||||
patch.c | 33 ++++++++++++++++++++++++++++-----
|
||||
patch.man | 9 +++++++++
|
||||
2 files changed, 37 insertions(+), 5 deletions(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.man
|
||||
+++ patch-2.5.9/patch.man
|
||||
@@ -520,6 +520,15 @@ file.
|
||||
\fB\*=reject\-unified\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
|
||||
Index: patch-2.5.9/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.c
|
||||
+++ patch-2.5.9/patch.c
|
||||
@@ -67,6 +67,7 @@ static bool similar (char const *, size_
|
||||
static bool spew_output (struct outstate *);
|
||||
static char const *make_temp (char);
|
||||
static int numeric_string (char const *, bool, char const *);
|
||||
+static void reject_header (const char *filename);
|
||||
static void abort_hunk (void);
|
||||
static void cleanup (void);
|
||||
static void get_some_switches (void);
|
||||
@@ -98,6 +99,7 @@ static int Argc;
|
||||
--- a/patch.c
|
||||
+++ b/patch.c
|
||||
@@ -101,6 +101,7 @@ static int Argc;
|
||||
static char * const *Argv;
|
||||
|
||||
static FILE *rejfp; /* reject file pointer */
|
||||
+static char *global_reject;
|
||||
+char *global_reject;
|
||||
|
||||
static char const *patchname;
|
||||
static char *rejname;
|
||||
@@ -172,6 +174,10 @@ main (int argc, char **argv)
|
||||
@@ -175,6 +176,10 @@ main (int argc, char **argv)
|
||||
/* Make sure we clean up in case of disaster. */
|
||||
set_signals (false);
|
||||
|
||||
@ -49,7 +26,7 @@ Index: patch-2.5.9/patch.c
|
||||
for (
|
||||
open_patch_file (patchname);
|
||||
there_is_another_patch();
|
||||
@@ -208,8 +214,9 @@ main (int argc, char **argv)
|
||||
@@ -211,8 +216,9 @@ main (int argc, char **argv)
|
||||
init_output (TMPOUTNAME, exclusive, &outstate);
|
||||
}
|
||||
|
||||
@ -61,34 +38,7 @@ Index: patch-2.5.9/patch.c
|
||||
|
||||
/* find out where all the lines are */
|
||||
if (!skip_rest_of_patch)
|
||||
@@ -278,6 +285,8 @@ main (int argc, char **argv)
|
||||
|
||||
newwhere = pch_newfirst() + last_offset;
|
||||
if (skip_rest_of_patch) {
|
||||
+ if (!failed)
|
||||
+ reject_header(outname);
|
||||
abort_hunk();
|
||||
failed++;
|
||||
if (verbosity == VERBOSE)
|
||||
@@ -292,6 +301,8 @@ main (int argc, char **argv)
|
||||
say ("Patch attempted to create file %s, which already exists.\n",
|
||||
quotearg (inname));
|
||||
|
||||
+ if (!failed)
|
||||
+ reject_header(outname);
|
||||
abort_hunk();
|
||||
failed++;
|
||||
if (verbosity != SILENT)
|
||||
@@ -299,6 +310,8 @@ main (int argc, char **argv)
|
||||
format_linenum (numbuf, newwhere));
|
||||
}
|
||||
else if (! apply_hunk (&outstate, where)) {
|
||||
+ if (!failed)
|
||||
+ reject_header(outname);
|
||||
abort_hunk ();
|
||||
failed++;
|
||||
if (verbosity != SILENT)
|
||||
@@ -332,7 +345,8 @@ main (int argc, char **argv)
|
||||
@@ -335,7 +341,8 @@ main (int argc, char **argv)
|
||||
fclose (outstate.ofp);
|
||||
outstate.ofp = 0;
|
||||
}
|
||||
@ -98,7 +48,7 @@ Index: patch-2.5.9/patch.c
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -412,13 +426,13 @@ main (int argc, char **argv)
|
||||
@@ -415,13 +422,13 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
if (diff_type != ED_DIFF) {
|
||||
@ -114,7 +64,7 @@ Index: patch-2.5.9/patch.c
|
||||
char *rej = rejname;
|
||||
if (!rejname) {
|
||||
rej = xmalloc (strlen (outname) + 5);
|
||||
@@ -445,6 +459,20 @@ main (int argc, char **argv)
|
||||
@@ -448,6 +455,17 @@ main (int argc, char **argv)
|
||||
}
|
||||
set_signals (true);
|
||||
}
|
||||
@ -124,18 +74,15 @@ Index: patch-2.5.9/patch.c
|
||||
+ write_fatal ();
|
||||
+ if (somefailed)
|
||||
+ {
|
||||
+ say (" -- saving rejects to file %s\n", quotearg (global_reject));
|
||||
+ /*if (! dry_run)
|
||||
+ {*/
|
||||
+ move_file (TMPREJNAME, &TMPREJNAME_needs_removal,
|
||||
+ global_reject, 0644, false);
|
||||
+ /*}*/
|
||||
+ 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 ();
|
||||
@@ -523,6 +551,7 @@ static struct option const longopts[] =
|
||||
@@ -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},
|
||||
@ -143,7 +90,7 @@ Index: patch-2.5.9/patch.c
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -582,6 +611,7 @@ static char const *const option_help[] =
|
||||
@@ -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.",
|
||||
@ -151,9 +98,9 @@ Index: patch-2.5.9/patch.c
|
||||
"",
|
||||
" -d DIR --directory=DIR Change the working directory to DIR first.",
|
||||
#if HAVE_SETMODE_DOS
|
||||
@@ -784,6 +814,9 @@ get_some_switches (void)
|
||||
@@ -787,6 +807,9 @@ get_some_switches (void)
|
||||
case CHAR_MAX + 9:
|
||||
unified_reject_files = true;
|
||||
abort_hunk = abort_hunk_unified;
|
||||
break;
|
||||
+ case CHAR_MAX + 10:
|
||||
+ global_reject = savestr (optarg);
|
||||
@ -161,41 +108,23 @@ Index: patch-2.5.9/patch.c
|
||||
default:
|
||||
usage (stderr, 2);
|
||||
}
|
||||
@@ -933,6 +966,37 @@ locate_hunk (LINENUM fuzz)
|
||||
}
|
||||
|
||||
static char *
|
||||
+format_timestamp (char timebuf[37], bool which)
|
||||
+{
|
||||
+ time_t ts = pch_timestamp(which);
|
||||
+ if (ts != -1)
|
||||
+ {
|
||||
+ struct tm *tm = localtime(&ts);
|
||||
+ strftime(timebuf, 37, "\t%Y-%m-%d %H:%M:%S.000000000 %z", tm);
|
||||
+ }
|
||||
+ else
|
||||
+ timebuf[0] = 0;
|
||||
+ return timebuf;
|
||||
+}
|
||||
+
|
||||
+/* Write a header in a reject file that combines multiple hunks. */
|
||||
+static void
|
||||
+reject_header (const char *outname)
|
||||
+{
|
||||
+ char timebuf0[37], timebuf1[37];
|
||||
+ if (!global_reject)
|
||||
+ return;
|
||||
+ if (diff_type == UNI_DIFF)
|
||||
+ fprintf(rejfp, "--- %s.orig%s\n+++ %s%s\n",
|
||||
+ outname, format_timestamp(timebuf0, reverse),
|
||||
+ outname, format_timestamp(timebuf1, !reverse));
|
||||
+ else
|
||||
+ fprintf(rejfp, "*** %s.orig%s\n--- %s%s\n",
|
||||
+ outname, format_timestamp(timebuf0, reverse),
|
||||
+ outname, format_timestamp(timebuf1, !reverse));
|
||||
+}
|
||||
+
|
||||
+static char *
|
||||
format_linerange (char rangebuf[LINENUM_LENGTH_BOUND*2 + 2],
|
||||
LINENUM first, LINENUM lines)
|
||||
{
|
||||
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
|
||||
|
@ -1,75 +0,0 @@
|
||||
Index: patch-2.5.9/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.c 2003-06-05 00:22:56.000000000 +0200
|
||||
+++ patch-2.5.9/patch.c 2003-06-05 00:23:16.000000000 +0200
|
||||
@@ -91,8 +91,8 @@ 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";
|
||||
-static char const else_defined[] = "\n#else\n";
|
||||
-static char const end_defined[] = "\n#endif\n";
|
||||
+static char const else_defined[] = "\n#else /* %s */\n";
|
||||
+static char const end_defined[] = "\n#endif /* %s */\n";
|
||||
|
||||
static int Argc;
|
||||
static char * const *Argv;
|
||||
@@ -1097,7 +1097,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
def_state = IN_IFNDEF;
|
||||
}
|
||||
else if (def_state == IN_IFDEF) {
|
||||
- fprintf (fp, outstate->after_newline + else_defined);
|
||||
+ fprintf (fp, outstate->after_newline + else_defined,
|
||||
+ R_do_defines);
|
||||
def_state = IN_ELSE;
|
||||
}
|
||||
if (ferror (fp))
|
||||
@@ -1116,7 +1117,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
return false;
|
||||
if (R_do_defines) {
|
||||
if (def_state == IN_IFNDEF) {
|
||||
- fprintf (fp, outstate->after_newline + else_defined);
|
||||
+ fprintf (fp, outstate->after_newline + else_defined,
|
||||
+ R_do_defines);
|
||||
def_state = IN_ELSE;
|
||||
}
|
||||
else if (def_state == OUTSIDE) {
|
||||
@@ -1164,7 +1166,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
while (pch_char (old) == '!');
|
||||
|
||||
if (R_do_defines) {
|
||||
- fprintf (fp, outstate->after_newline + else_defined);
|
||||
+ fprintf (fp, outstate->after_newline + else_defined,
|
||||
+ R_do_defines);
|
||||
if (ferror (fp))
|
||||
write_fatal ();
|
||||
def_state = IN_ELSE;
|
||||
@@ -1183,7 +1186,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
old++;
|
||||
new++;
|
||||
if (R_do_defines && def_state != OUTSIDE) {
|
||||
- fprintf (fp, outstate->after_newline + end_defined);
|
||||
+ fprintf (fp, outstate->after_newline + end_defined,
|
||||
+ R_do_defines);
|
||||
if (ferror (fp))
|
||||
write_fatal ();
|
||||
outstate->after_newline = true;
|
||||
@@ -1201,7 +1205,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
def_state = IN_IFDEF;
|
||||
}
|
||||
else if (def_state == IN_IFNDEF) {
|
||||
- fprintf (fp, outstate->after_newline + else_defined);
|
||||
+ fprintf (fp, outstate->after_newline + else_defined,
|
||||
+ R_do_defines);
|
||||
def_state = IN_ELSE;
|
||||
}
|
||||
if (ferror (fp))
|
||||
@@ -1220,7 +1225,8 @@ apply_hunk (struct outstate *outstate, L
|
||||
while (new <= pat_end && pch_char (new) == '+');
|
||||
}
|
||||
if (R_do_defines && def_state != OUTSIDE) {
|
||||
- fprintf (fp, outstate->after_newline + end_defined);
|
||||
+ fprintf (fp, outstate->after_newline + end_defined,
|
||||
+ R_do_defines);
|
||||
if (ferror (fp))
|
||||
write_fatal ();
|
||||
outstate->after_newline = true;
|
@ -1,8 +1,14 @@
|
||||
Index: patch-2.5.9/patch.c
|
||||
---
|
||||
patch.c | 2 +-
|
||||
util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
util.h | 1 +
|
||||
3 files changed, 52 insertions(+), 1 deletion(-)
|
||||
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.c
|
||||
+++ patch-2.5.9/patch.c
|
||||
@@ -444,7 +444,7 @@ main (int argc, char **argv)
|
||||
--- 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);
|
||||
@ -11,10 +17,10 @@ Index: patch-2.5.9/patch.c
|
||||
&& (chmod (rej, (instat.st_mode
|
||||
& ~(S_IXUSR|S_IXGRP|S_IXOTH)))
|
||||
!= 0))
|
||||
Index: patch-2.5.9/util.c
|
||||
Index: b/util.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/util.c
|
||||
+++ patch-2.5.9/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. */
|
||||
@ -79,11 +85,11 @@ Index: patch-2.5.9/util.c
|
||||
if (errno == EXDEV)
|
||||
{
|
||||
if (! backup)
|
||||
Index: patch-2.5.9/util.h
|
||||
Index: b/util.h
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/util.h
|
||||
+++ patch-2.5.9/util.h
|
||||
@@ -57,3 +57,4 @@ void remove_prefix (char *, size_t);
|
||||
--- 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));
|
||||
|
221
patch-headers-in-reject-files.diff
Normal file
221
patch-headers-in-reject-files.diff
Normal file
@ -0,0 +1,221 @@
|
||||
---
|
||||
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,11 +0,0 @@
|
||||
--- patch-2.5.9/patch.man
|
||||
+++ patch-2.5.9/patch.man
|
||||
@@ -517,7 +517,7 @@
|
||||
.B \&.rej
|
||||
file.
|
||||
.TP
|
||||
-\fB\*=reject\-unified\fP
|
||||
+\fB\*=unified\-reject\-files\fP
|
||||
Produce unified reject files. The default is to produce context type reject files.
|
||||
.TP
|
||||
.BI \*=global\-reject\-file= rejectfile
|
@ -1,3 +1,12 @@
|
||||
-------------------------------------------------------------------
|
||||
Tue Feb 24 12:56:06 CET 2009 - agruen@suse.de
|
||||
|
||||
- Include patch headers in reject files so that they form proper
|
||||
patches themselves.
|
||||
- Rewrite the unified reject files patch; this is much cleaner
|
||||
now.
|
||||
- Add an improved strategy for locating merges.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Feb 3 06:10:49 CET 2009 - agruen@suse.de
|
||||
|
||||
@ -137,14 +146,14 @@ Wed Apr 9 19:33:59 CEST 2003 - agruen@suse.de
|
||||
Wed Mar 26 14:00:55 CET 2003 - mmj@suse.de
|
||||
|
||||
- Update to 2.5.8:
|
||||
· Bugfixes
|
||||
· patch -D now outputs preprocessor lines without comments, as
|
||||
+ Bugfixes
|
||||
+ patch -D now outputs preprocessor lines without comments, as
|
||||
required by POSIX 1003.1-2001
|
||||
· File names in context patches may now contain spaces, so long
|
||||
+ File names in context patches may now contain spaces, so long
|
||||
as the context patch headers use a tab to separate the file name
|
||||
from the time stamp
|
||||
· Perforce is now supported
|
||||
· Patch lines beginning with "#" are comments and are ignored
|
||||
+ Perforce is now supported
|
||||
+ Patch lines beginning with "#" are comments and are ignored
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jan 15 16:50:57 CET 2003 - agruen@suse.de
|
||||
|
53
patch.spec
53
patch.spec
@ -23,29 +23,29 @@ License: GPL v2 or later
|
||||
Group: Productivity/Text/Utilities
|
||||
AutoReqProv: on
|
||||
Version: 2.5.9
|
||||
Release: 287
|
||||
Release: 288
|
||||
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: unified-reject-files.diff
|
||||
Patch3: global-reject-file.diff
|
||||
Patch4: if_else_endif_comments.diff
|
||||
Patch5: patch-2.5.9-cat_if_device.diff
|
||||
Patch6: patch-man-unified-reject.diff
|
||||
Patch7: fix-partial-context.diff
|
||||
Patch8: diff3-style-merges-tests.diff
|
||||
Patch9: diff3-style-merges-refactoring.diff
|
||||
Patch10: diff3-style-merges-refactoring-2.diff
|
||||
Patch11: diff3-style-merges-base.diff
|
||||
Patch12: diff3-style-merges-rejects.diff
|
||||
Patch13: diff3-style-merges-pch_name.diff
|
||||
Patch14: diff3-style-merges-include-filenames.diff
|
||||
Patch15: diff3-style-merges-add-file-labels.diff
|
||||
Patch16: diff3-style-merges-overlap.diff
|
||||
Patch17: diff3-style-merges-locate-merge.diff
|
||||
Patch18: diff3-style-merges-other-strategy.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
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
|
||||
%description
|
||||
@ -66,6 +66,7 @@ Authors:
|
||||
%patch1 -p1
|
||||
%patch2 -p1
|
||||
%patch3 -p1
|
||||
%patch4 -p1
|
||||
%patch5 -p1
|
||||
%patch6 -p1
|
||||
%patch7 -p1
|
||||
@ -105,6 +106,12 @@ make install \
|
||||
%doc %{_mandir}/man1/patch.1.gz
|
||||
|
||||
%changelog
|
||||
* Tue Feb 24 2009 agruen@suse.de
|
||||
- Include patch headers in reject files so that they form proper
|
||||
patches themselves.
|
||||
- Rewrite the unified reject files patch; this is much cleaner
|
||||
now.
|
||||
- Add an improved strategy for locating merges.
|
||||
* Tue Feb 03 2009 agruen@suse.de
|
||||
- Implement diff3-style merges (including several fixes and
|
||||
improvements).
|
||||
@ -188,14 +195,14 @@ make install \
|
||||
patch more than once.
|
||||
* Wed Mar 26 2003 mmj@suse.de
|
||||
- Update to 2.5.8:
|
||||
· Bugfixes
|
||||
· patch -D now outputs preprocessor lines without comments, as
|
||||
+ Bugfixes
|
||||
+ patch -D now outputs preprocessor lines without comments, as
|
||||
required by POSIX 1003.1-2001
|
||||
· File names in context patches may now contain spaces, so long
|
||||
+ File names in context patches may now contain spaces, so long
|
||||
as the context patch headers use a tab to separate the file name
|
||||
from the time stamp
|
||||
· Perforce is now supported
|
||||
· Patch lines beginning with "#" are comments and are ignored
|
||||
+ Perforce is now supported
|
||||
+ Patch lines beginning with "#" are comments and are ignored
|
||||
* Wed Jan 15 2003 agruen@suse.de
|
||||
- Fix a bug with hardlinks (see rename-same-file.patch)
|
||||
* Tue Sep 17 2002 ro@suse.de
|
||||
|
84
pch_c_function.diff
Normal file
84
pch_c_function.diff
Normal file
@ -0,0 +1,84 @@
|
||||
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);
|
@ -245,9 +245,9 @@ Index: b/pch.c
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1803,6 +1801,12 @@ pch_says_nonexistent (bool which)
|
||||
/* 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. */
|
||||
@@ -1800,6 +1798,12 @@ pch_says_nonexistent (bool which)
|
||||
return p_says_nonexistent[which];
|
||||
}
|
||||
|
||||
+const char *
|
||||
+pch_name (enum nametype type)
|
||||
@ -255,9 +255,9 @@ Index: b/pch.c
|
||||
+ return type == NONE ? NULL : p_name[type];
|
||||
+}
|
||||
+
|
||||
time_t
|
||||
pch_timestamp (bool which)
|
||||
{
|
||||
/* 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
|
21
preserve-c_function-in-reject-files.diff
Normal file
21
preserve-c_function-in-reject-files.diff
Normal file
@ -0,0 +1,21 @@
|
||||
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];
|
@ -1,173 +1,50 @@
|
||||
Generate unified diff style reject files. Also include the C function names
|
||||
in reject files whenever possible.
|
||||
Generate unified diff style reject files.
|
||||
|
||||
$ cat > f.orig
|
||||
< a() {
|
||||
< 2
|
||||
< 3
|
||||
<
|
||||
< 5
|
||||
< 6
|
||||
< }
|
||||
---
|
||||
patch.c | 104 +++++++++++++++++++++++++++++++++++++--
|
||||
patch.man | 3 +
|
||||
tests/unified-reject-files.shrun | 104 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 208 insertions(+), 3 deletions(-)
|
||||
|
||||
$ sed -e 's/5/5a/' f.orig > f
|
||||
$ diff -U2 -p f.orig f > f.diff
|
||||
$ sed -e 's/5/5a/' -e 's/6/6x/' f.orig > f
|
||||
$ ./patch -F0 -s --no-backup-if-mismatch f --reject-unified < 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 /dev/null f.orig > f2.diff
|
||||
$ ./patch -F0 -s --no-backup-if-mismatch f --reject-unified < 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
|
||||
> +}
|
||||
|
||||
$ rm -f f f.orig f.rej f.diff f2.diff
|
||||
|
||||
Index: patch-2.5.9/pch.c
|
||||
Index: b/patch.man
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/pch.c
|
||||
+++ patch-2.5.9/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: patch-2.5.9/pch.h
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/pch.h
|
||||
+++ patch-2.5.9/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);
|
||||
Index: patch-2.5.9/patch.man
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.man
|
||||
+++ patch-2.5.9/patch.man
|
||||
--- a/patch.man
|
||||
+++ b/patch.man
|
||||
@@ -517,6 +517,9 @@ instead of the default
|
||||
.B \&.rej
|
||||
file.
|
||||
.TP
|
||||
+\fB\*=reject\-unified\fP
|
||||
+\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: patch-2.5.9/common.h
|
||||
Index: b/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/common.h
|
||||
+++ patch-2.5.9/common.h
|
||||
@@ -146,6 +146,7 @@ XTERN int invc;
|
||||
XTERN struct stat instat;
|
||||
XTERN bool dry_run;
|
||||
XTERN bool posixly_correct;
|
||||
+XTERN bool unified_reject_files;
|
||||
--- 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));
|
||||
|
||||
XTERN char const *origprae;
|
||||
XTERN char const *origbase;
|
||||
Index: patch-2.5.9/patch.c
|
||||
===================================================================
|
||||
--- patch-2.5.9.orig/patch.c
|
||||
+++ patch-2.5.9/patch.c
|
||||
@@ -522,6 +522,7 @@ static struct option const longopts[] =
|
||||
+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},
|
||||
@ -175,7 +52,7 @@ Index: patch-2.5.9/patch.c
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -580,6 +581,7 @@ static char const *const option_help[] =
|
||||
@@ -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.",
|
||||
@ -183,123 +60,236 @@ Index: patch-2.5.9/patch.c
|
||||
"",
|
||||
" -d DIR --directory=DIR Change the working directory to DIR first.",
|
||||
#if HAVE_SETMODE_DOS
|
||||
@@ -779,6 +781,9 @@ get_some_switches (void)
|
||||
@@ -779,6 +784,9 @@ get_some_switches (void)
|
||||
(enum quoting_style) i);
|
||||
}
|
||||
break;
|
||||
+ case CHAR_MAX + 9:
|
||||
+ unified_reject_files = true;
|
||||
+ abort_hunk = abort_hunk_unified;
|
||||
+ break;
|
||||
default:
|
||||
usage (stderr, 2);
|
||||
}
|
||||
@@ -927,6 +932,24 @@ locate_hunk (LINENUM fuzz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static char *
|
||||
+format_linerange (char rangebuf[LINENUM_LENGTH_BOUND*2 + 2],
|
||||
+ LINENUM first, LINENUM lines)
|
||||
+{
|
||||
+ if (lines == 1)
|
||||
+ rangebuf = format_linenum (rangebuf, first);
|
||||
+ else
|
||||
+ {
|
||||
+ char *rb;
|
||||
+ rangebuf = format_linenum (rangebuf + LINENUM_LENGTH_BOUND + 1, lines);
|
||||
+ rb = rangebuf-1;
|
||||
+ rangebuf = format_linenum (rangebuf - LINENUM_LENGTH_BOUND - 1,
|
||||
+ (lines > 0) ? first : 0);
|
||||
+ *rb = ',';
|
||||
+ }
|
||||
+ return rangebuf;
|
||||
+}
|
||||
+
|
||||
@@ -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
|
||||
@@ -943,8 +966,83 @@ abort_hunk (void)
|
||||
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : "";
|
||||
char const *minuses =
|
||||
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
|
||||
+ char const *function = pch_c_function();
|
||||
+ if (function == NULL)
|
||||
+ function = "";
|
||||
+
|
||||
+ if (unified_reject_files)
|
||||
+ {
|
||||
+ /* produce unified reject files */
|
||||
+ char rangebuf0[LINENUM_LENGTH_BOUND*2 + 2];
|
||||
+ char rangebuf1[LINENUM_LENGTH_BOUND*2 + 2];
|
||||
+ LINENUM j;
|
||||
+
|
||||
+ /* Find the beginning of the remove and insert section. */
|
||||
+ for (j = 0; j <= pat_end; j++)
|
||||
+ if (pch_char (j) == '=')
|
||||
+ break;
|
||||
+ for (i = j+1; i <= pat_end; i++)
|
||||
+ if (pch_char (i) == '^')
|
||||
+ break;
|
||||
+ if (pch_char (0) != '*' || j > pat_end || i > pat_end+1)
|
||||
+ fatal ("internal error in abort_hunk");
|
||||
+ i = 1; j++;
|
||||
+
|
||||
+ /* @@ -from,lines +to,lines @@ */
|
||||
+ fprintf (rejfp, "@@ -%s +%s @@%s\n",
|
||||
+ format_linerange (rangebuf0, oldfirst, pch_ptrn_lines()),
|
||||
+ format_linerange (rangebuf1, newfirst, pch_repl_lines()),
|
||||
+ function);
|
||||
+
|
||||
+ while ( (i <= pat_end && pch_char (i) != '=')
|
||||
+ || (j <= pat_end && pch_char (j) != '^'))
|
||||
+ {
|
||||
+ if (i <= pat_end
|
||||
+ && (pch_char (i) == '-' || pch_char (i) == '!'))
|
||||
+ {
|
||||
+ fputc('-', rejfp);
|
||||
+ pch_write_line (i++, rejfp);
|
||||
+ }
|
||||
+ else if (j <= pat_end
|
||||
+ && (pch_char (j) == '+' || pch_char (j) == '!'))
|
||||
+ {
|
||||
+ fputc('+', rejfp);
|
||||
+ pch_write_line (j++, rejfp);
|
||||
+ }
|
||||
+ else if ((i <= pat_end
|
||||
+ && (pch_char (i) == ' ' || pch_char (i) == '\n')) &&
|
||||
+ (j > pat_end
|
||||
+ || (pch_char (j) == ' ' || pch_char (j) == '\n')))
|
||||
+ {
|
||||
+ /* Unless j is already past the end, lines i and j
|
||||
+ must be equal here. */
|
||||
+
|
||||
+ if (pch_char (i) == ' ')
|
||||
+ fputc(' ', rejfp);
|
||||
+ pch_write_line (i++, rejfp);
|
||||
+ if (j <= pat_end)
|
||||
+ j++;
|
||||
+ }
|
||||
+ else if ((j <= pat_end &&
|
||||
+ (pch_char (j) == ' ' || pch_char (j) == '\n')) &&
|
||||
+ (pch_char (i) == '='))
|
||||
+ {
|
||||
+ if (pch_char (j) == ' ')
|
||||
+ fputc(' ', rejfp);
|
||||
+ pch_write_line (j++, rejfp);
|
||||
+ }
|
||||
+ else
|
||||
+ fatal ("internal error in abort_hunk");
|
||||
+ }
|
||||
+
|
||||
+ if (ferror (rejfp))
|
||||
+ write_fatal ();
|
||||
+ return;
|
||||
+ }
|
||||
-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 ();
|
||||
}
|
||||
}
|
||||
|
||||
- fprintf(rejfp, "***************\n");
|
||||
+ /* produce context type reject files */
|
||||
+
|
||||
+ fprintf(rejfp, "***************%s\n", function);
|
||||
for (i=0; i<=pat_end; i++) {
|
||||
char numbuf0[LINENUM_LENGTH_BOUND + 1];
|
||||
char numbuf1[LINENUM_LENGTH_BOUND + 1];
|
||||
+/* 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