diff --git a/diff3-style-merges-add-file-labels.diff b/diff3-style-merges-add-file-labels.diff deleted file mode 100644 index b676f72..0000000 --- a/diff3-style-merges-add-file-labels.diff +++ /dev/null @@ -1,105 +0,0 @@ ---- - common.h | 2 ++ - merge.c | 8 ++++---- - patch.c | 14 +++++++++++++- - 3 files changed, 19 insertions(+), 5 deletions(-) - -Index: b/common.h -=================================================================== ---- a/common.h -+++ b/common.h -@@ -310,6 +310,8 @@ XTERN LINENUM last_offset; - /* how many input lines have been irretractably output */ - XTERN LINENUM last_frozen_line; - -+XTERN const char *file_label[2]; -+ - bool similar (char const *, size_t, char const *, size_t); - bool copy_till (struct outstate *, LINENUM); - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -70,6 +70,8 @@ static void usage (FILE *, int) __attrib - static void (*abort_hunk) (bool, bool) = abort_hunk_context; - - static bool merge; -+const char *file_label[2]; -+ - static bool make_backups; - static bool backup_if_mismatch; - static char const *version_control; -@@ -506,7 +508,7 @@ reinitialize_almost_everything (void) - skip_rest_of_patch = false; - } - --static char const shortopts[] = "bB:cd:D:eEfF:g:i:lMnNo:p:r:RstTuvV:x:Y:z:Z"; -+static char const shortopts[] = "bB:cd:D:eEfF:g:i:lL:MnNo:p:r:RstTuvV:x:Y:z:Z"; - static struct option const longopts[] = - { - {"backup", no_argument, NULL, 'b'}, -@@ -521,6 +523,7 @@ static struct option const longopts[] = - {"get", no_argument, NULL, 'g'}, - {"input", required_argument, NULL, 'i'}, - {"ignore-whitespace", no_argument, NULL, 'l'}, -+ {"label", required_argument, NULL, 'L'}, - {"merge", no_argument, NULL, 'M'}, - {"normal", no_argument, NULL, 'n'}, - {"forward", no_argument, NULL, 'N'}, -@@ -577,6 +580,7 @@ static char const *const option_help[] = - "", - " -D NAME --ifdef=NAME Make merged if-then-else output using NAME.", - " -M --merge Produce a diff3-style merge for rejects.", -+" -L LABEL --label=LABEL Use LABEL instead of file name in merge.", - " -E --remove-empty-files Remove output files that are empty after patching.", - "", - " -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).", -@@ -718,6 +722,14 @@ get_some_switches (void) - case 'M': - merge = true; - break; -+ case 'L': -+ if (!file_label[0]) -+ file_label[0] = optarg; -+ else if (!file_label[1]) -+ file_label[1] = optarg; -+ else -+ fatal ("too many file label options"); -+ break; - case 'n': - diff_type = NORMAL_DIFF; - break; -Index: b/merge.c -=================================================================== ---- a/merge.c -+++ b/merge.c -@@ -50,7 +50,7 @@ merge_hunk (struct outstate *outstate) - return false; - - /* "From" lines in the patch */ -- name = pch_name(OLD); -+ name = file_label[OLD] ? file_label[OLD] : pch_name(OLD); - if (!name) - name = ""; - fprintf(fp, outstate->after_newline + "\n<<<<<<<%*s\n", -@@ -84,7 +84,7 @@ merge_hunk (struct outstate *outstate) - if (! same_result) - { - /* "To" lines in the patch */ -- name = pch_name(NEW); -+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW); - if (!name) - name = ""; - fprintf(fp, outstate->after_newline + "\n|||||||%*s\n", -@@ -112,8 +112,8 @@ merge_hunk (struct outstate *outstate) - result with the new file's name. */ - if (same_result) - { -- name = pch_name(NEW); -- if (!name) -+ name = file_label[NEW] ? file_label[NEW] : pch_name(NEW); -+ if (! name) - name = ""; - } - else diff --git a/diff3-style-merges-locate-merge.diff b/diff3-style-merges-locate-merge.diff deleted file mode 100644 index 8bb65fe..0000000 --- a/diff3-style-merges-locate-merge.diff +++ /dev/null @@ -1,337 +0,0 @@ ---- - Makefile.in | 3 - - bestmatch.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - common.h | 11 ++++ - merge.c | 95 ++++++++++++++++++++++++++++++++++++++++- - patch.c | 19 ++++++-- - 5 files changed, 256 insertions(+), 10 deletions(-) - -Index: b/Makefile.in -=================================================================== ---- a/Makefile.in -+++ b/Makefile.in -@@ -85,7 +85,8 @@ HDRS = argmatch.h backupfile.h common.h - error.h getopt.h gettext.h \ - inp.h maketime.h partime.h pch.h \ - quote.h quotearg.h quotesys.h \ -- unlocked-io.h util.h version.h xalloc.h hash.h -+ unlocked-io.h util.h version.h xalloc.h hash.h \ -+ bestmatch.h - MISC = AUTHORS COPYING ChangeLog INSTALL Makefile.in NEWS README \ - aclocal.m4 \ - config.hin configure configure.ac \ -Index: b/common.h -=================================================================== ---- a/common.h -+++ b/common.h -@@ -296,6 +296,14 @@ void *realloc (); - #define TTY_DEVICE "/dev/tty" - #endif - -+#ifndef MIN -+# define MIN(a, b) ((a) <= (b) ? (a) : (b)) -+#endif -+ -+#ifndef MAX -+# define MAX(a, b) ((a) >= (b) ? (a) : (b)) -+#endif -+ - /* Output stream state. */ - struct outstate - { -@@ -316,4 +324,5 @@ bool similar (char const *, size_t, char - bool copy_till (struct outstate *, LINENUM); - - /* Defined in merge.c */ --bool merge_hunk (struct outstate *); -+LINENUM locate_merge (LINENUM, LINENUM *); -+bool merge_hunk (struct outstate *, LINENUM, LINENUM); -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -286,13 +286,22 @@ main (int argc, char **argv) - goto skip_hunk; - } else if (!where) { - if (merge) { -- if (merge_hunk(&outstate)) { -+ LINENUM matched; -+ -+ where = locate_merge (maxfuzz, &matched); -+ if (! where) -+ { -+ where = pch_first () + last_offset; -+ matched = 0; -+ } -+ -+ if (merge_hunk (&outstate, where, matched)) -+ { - merged++; - mismatch = 1; -- } else { -- /* FIXME: try harder! */ -- goto skip_hunk; -- } -+ } -+ else -+ goto skip_hunk; - } else - goto skip_hunk; - } else { -Index: b/merge.c -=================================================================== ---- a/merge.c -+++ b/merge.c -@@ -7,8 +7,97 @@ - static bool context_matches_file (LINENUM, LINENUM); - static bool common_context (LINENUM, LINENUM, LINENUM); - -+#define OFFSET LINENUM -+#define EQUAL(x, y) (context_matches_file (x, y)) -+ -+#include "bestmatch.h" -+ -+LINENUM -+locate_merge (LINENUM fuzz, LINENUM *matched) -+{ -+ LINENUM first_guess = pch_first () + last_offset; -+ LINENUM pat_lines = pch_ptrn_lines(); -+ LINENUM suffix_context = pch_suffix_context (); -+ LINENUM max_where = input_lines - (pat_lines - suffix_context) + 1; -+ LINENUM min_where = last_frozen_line + 1; -+ LINENUM max_pos_offset = max_where - first_guess; -+ LINENUM max_neg_offset = first_guess - min_where; -+ LINENUM max_offset = (max_pos_offset < max_neg_offset -+ ? max_neg_offset : max_pos_offset); -+ LINENUM prefix_fuzz = MIN (fuzz, pch_prefix_context()); -+ LINENUM suffix_fuzz = MIN (fuzz, pch_suffix_context()); -+ LINENUM where = 0, max_matched = 0; -+ LINENUM min, max; -+ LINENUM offset; -+ -+ /* The minimum number of matched lines and maximum number of changes -+ are mostly guesses. */ -+ min = pat_lines - (prefix_fuzz + suffix_fuzz); -+ max = 2 * (prefix_fuzz + suffix_fuzz); -+ -+ /* Do not try lines <= 0. */ -+ if (first_guess <= max_neg_offset) -+ max_neg_offset = first_guess - 1; -+ -+ for (offset = 0; offset <= max_offset; offset++) -+ { -+ if (offset <= max_pos_offset) -+ { -+ LINENUM guess = first_guess + offset; -+ LINENUM last; -+ LINENUM changes; -+ -+ changes = bestmatch(1, pat_lines + 1, guess, input_lines + 1, -+ min, max, &last); -+ if (changes <= max && max_matched < last - guess) -+ { -+ max_matched = last - guess; -+ where = guess; -+ if (changes == 0) -+ break; -+ min = last - guess; -+ max = changes - 1; -+ } -+ } -+ if (0 < offset && offset <= max_neg_offset) -+ { -+ LINENUM guess = first_guess - offset; -+ LINENUM last; -+ LINENUM changes; -+ -+ changes = bestmatch(1, pat_lines + 1, guess, input_lines + 1, -+ min, max, &last); -+ if (changes <= max && max_matched < last - guess) -+ { -+ max_matched = last - guess; -+ where = guess; -+ if (changes == 0) -+ break; -+ min = last - guess; -+ max = changes - 1; -+ } -+ } -+ } -+ if (debug & 1) -+ { -+ char numbuf0[LINENUM_LENGTH_BOUND + 1]; -+ char numbuf1[LINENUM_LENGTH_BOUND + 1]; -+ char numbuf2[LINENUM_LENGTH_BOUND + 1]; -+ char numbuf3[LINENUM_LENGTH_BOUND + 1]; -+ say ("locating merge: min=%s max=%s where=%s matched=%s\n", -+ format_linenum (numbuf0, min), -+ format_linenum (numbuf1, max), -+ format_linenum (numbuf2, where), -+ format_linenum (numbuf3, max_matched)); -+ } -+ -+ if (where) -+ *matched = max_matched; -+ return where; -+} -+ - bool --merge_hunk (struct outstate *outstate) -+merge_hunk (struct outstate *outstate, LINENUM where, LINENUM matched) - { - LINENUM old = 1; - LINENUM lastold = pch_ptrn_lines (); -@@ -22,8 +111,8 @@ merge_hunk (struct outstate *outstate) - while (pch_char(new) == '=' || pch_char(new) == '\n') - new++; - -- merge = pch_first () + last_offset; -- lastmerge = merge + lastold - 1; -+ merge = where; -+ lastmerge = where + matched - 1; - if (! common_context(lastmerge, lastold, lastnew)) - lastmerge = merge - 1; - -Index: b/bestmatch.h -=================================================================== ---- /dev/null -+++ b/bestmatch.h -@@ -0,0 +1,138 @@ -+/* Before including this file, you need to define: -+ EQUAL(x, y) A two-argument macro that tests elements -+ at index x and y for equality. -+ OFFSET A signed integer type sufficient to hold the -+ difference between two indices. Usually -+ something like ssize_t. */ -+ -+/* -+ * Shortest Edit Sequence -+ * -+ * Based on the Greedy LCS/SES Algorithm (Figure 2) in: -+ * -+ * Eugene W. Myers, "An O(ND) Difference Algorithm and Its Variations", -+ * Algorithmica, Vol. 1, No. 1, pp. 251-266, March 1986. -+ * Available: http://dx.doi.org/10.1007/BF01840446 -+ * http://xmailserver.org/diff2.pdf -+ * -+ * Returns the number of changes (insertions and deletions) required to get -+ * from a[] to b[]. Returns MAX + 1 if a[] cannot be turned into b[] with -+ * MAX or fewer changes. -+ * -+ * MIN specifies the minimum number of elements in which a[] and b[] must -+ * match. This allows to prevent trivial matches in which a sequence is -+ * completely discarded, or completely made up. -+ * -+ * If PY is not NULL, matches a[] against a prefix of b[], and returns the -+ * number of elements in b[] that were matched in *PY. Otherwise, matches -+ * all elements of b[]. -+ * -+ * Note that the divide-and-conquer strategy discussed in section 4b of the -+ * paper is more efficient, but does not allow an open-ended prefix string -+ * search. -+ */ -+ -+OFFSET -+bestmatch(OFFSET xoff, OFFSET xlim, OFFSET yoff, OFFSET ylim, -+ OFFSET min, OFFSET max, OFFSET *py) -+{ -+ const OFFSET dmin = xoff - ylim; /* Minimum valid diagonal. */ -+ const OFFSET dmax = xlim - yoff; /* Maximum valid diagonal. */ -+ const OFFSET fmid = xoff - yoff; /* Center diagonal. */ -+ OFFSET fmin = fmid; -+ OFFSET fmax = fmid; -+ OFFSET V[2 * max + 3], *fd = V + max + 2 - fmid; -+ OFFSET fmid_plus_2_min, ymax = -1; -+ OFFSET c; -+ -+ /* -+ The number of elements that were matched in x and in y can be -+ computed as either (x - x_skipped) or (y - y_skipped), with: -+ -+ delta = (x - xoff) - (y - yoff) -+ x_skipped = (c + delta) / 2 -+ y_skipped = (c - delta) / 2 -+ -+ For searching for a minimum number of matching elements, we end up -+ with this check: -+ -+ (x - x_skipped) >= min -+ ... -+ x + y - c >= (xoff - yoff) + 2 * min -+ x + y - c >= fmid + 2 * min -+ */ -+ -+ if (min) -+ { -+ fmid_plus_2_min = fmid + 2 * min; -+ min += yoff; -+ if (min > ylim) -+ return max + 1; -+ } -+ else -+ fmid_plus_2_min = 0; /* disable this check */ -+ if (!py) -+ min = ylim; -+ -+ /* Handle the exact-match case. */ -+ while (xoff < xlim && yoff < ylim && EQUAL (xoff, yoff)) -+ { -+ xoff++; -+ yoff++; -+ } -+ if (xoff == xlim && yoff >= min -+ && xoff + yoff >= fmid_plus_2_min) -+ { -+ ymax = yoff; -+ c = 0; -+ } -+ else -+ { -+ fd[fmid] = xoff; -+ for (c = 1; c <= max; c++) -+ { -+ OFFSET d; -+ -+ if (fmin > dmin) -+ fd[--fmin - 1] = -1; -+ else -+ ++fmin; -+ if (fmax < dmax) -+ fd[++fmax + 1] = -1; -+ else -+ --fmax; -+ for (d = fmax; d >= fmin; d -= 2) -+ { -+ OFFSET x, y; -+ -+ if (fd[d - 1] < fd[d + 1]) -+ x = fd[d + 1]; -+ else -+ x = fd[d - 1] + 1; -+ for (y = x - d; -+ x < xlim && y < ylim && EQUAL (x, y); -+ x++, y++) -+ continue; -+ fd[d] = x; -+ if (x == xlim && y >= min -+ && x + y - c >= fmid_plus_2_min) -+ { -+ if (ymax < y) -+ ymax = y; -+ if (y == ylim) -+ goto done; -+ } -+ } -+ if (ymax != -1) -+ goto done; -+ } -+ } -+ -+ done: -+ if (py) -+ *py = ymax; -+ return c; -+} -+ -+#undef OFFSET -+#undef EQUAL diff --git a/diff3-style-merges-refactoring-2.diff b/diff3-style-merges-refactoring-2.diff deleted file mode 100644 index 8b50c38..0000000 --- a/diff3-style-merges-refactoring-2.diff +++ /dev/null @@ -1,61 +0,0 @@ ---- - patch.c | 42 ++++++++++++++++++++---------------------- - 1 file changed, 20 insertions(+), 22 deletions(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -288,32 +288,30 @@ main (int argc, char **argv) - newwhere = pch_newfirst() + last_offset; - if (skip_rest_of_patch) { - goto skip_hunk; -- } -- else if (!where -- || (where == 1 && pch_says_nonexistent (reverse) == 2 -- && instat.st_size)) { -- -- if (where) -- say ("Patch attempted to create file %s, which already exists.\n", -- quotearg (inname)); -+ } else if (where == 1 && pch_says_nonexistent (reverse) == 2 -+ && instat.st_size) { -+ say ("Patch attempted to create file %s, " -+ "which already exists.\n", quotearg (inname)); - - goto skip_hunk; -- } -- else if (! apply_hunk (&outstate, where)) { -+ } else if (!where) { - goto skip_hunk; - } else { -- if (verbosity == VERBOSE -- || (verbosity != SILENT && (fuzz || last_offset))) { -- say ("Hunk #%d succeeded at %s", hunk, -- format_linenum (numbuf, newwhere)); -- if (fuzz) -- say (" with fuzz %s", format_linenum (numbuf, fuzz)); -- if (last_offset) -- say (" (offset %s line%s)", -- format_linenum (numbuf, last_offset), -- "s" + (last_offset == 1)); -- say (".\n"); -- } -+ if (!apply_hunk (&outstate, where)) -+ goto skip_hunk; -+ } -+ -+ if (verbosity == VERBOSE -+ || (verbosity != SILENT && (fuzz || last_offset))) { -+ say ("Hunk #%d succeeded at %s", hunk, -+ format_linenum (numbuf, newwhere)); -+ if (fuzz) -+ say (" with fuzz %s", format_linenum (numbuf, fuzz)); -+ if (last_offset) -+ say (" (offset %s line%s)", -+ format_linenum (numbuf, last_offset), -+ "s" + (last_offset == 1)); -+ say (".\n"); - } - continue; - diff --git a/diff3-style-merges-refactoring.diff b/diff3-style-merges-refactoring.diff deleted file mode 100644 index 1df83aa..0000000 --- a/diff3-style-merges-refactoring.diff +++ /dev/null @@ -1,59 +0,0 @@ ---- - patch.c | 28 +++++++++++++--------------- - 1 file changed, 13 insertions(+), 15 deletions(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -287,11 +287,7 @@ main (int argc, char **argv) - - newwhere = pch_newfirst() + last_offset; - if (skip_rest_of_patch) { -- abort_hunk(!failed, reverse); -- failed++; -- if (verbosity == VERBOSE) -- say ("Hunk #%d ignored at %s.\n", hunk, -- format_linenum (numbuf, newwhere)); -+ goto skip_hunk; - } - else if (!where - || (where == 1 && pch_says_nonexistent (reverse) == 2 -@@ -301,18 +297,10 @@ main (int argc, char **argv) - say ("Patch attempted to create file %s, which already exists.\n", - quotearg (inname)); - -- abort_hunk(!failed, reverse); -- failed++; -- if (verbosity != SILENT) -- say ("Hunk #%d FAILED at %s.\n", hunk, -- format_linenum (numbuf, newwhere)); -+ goto skip_hunk; - } - else if (! apply_hunk (&outstate, where)) { -- abort_hunk (!failed, reverse); -- failed++; -- if (verbosity != SILENT) -- say ("Hunk #%d FAILED at %s.\n", hunk, -- format_linenum (numbuf, newwhere)); -+ goto skip_hunk; - } else { - if (verbosity == VERBOSE - || (verbosity != SILENT && (fuzz || last_offset))) { -@@ -327,6 +315,16 @@ main (int argc, char **argv) - say (".\n"); - } - } -+ continue; -+ -+skip_hunk: -+ abort_hunk(!failed, reverse); -+ failed++; -+ if (verbosity == VERBOSE || -+ (!skip_rest_of_patch && verbosity != SILENT)) -+ say ("Hunk #%d %s at %s.\n", hunk, -+ skip_rest_of_patch ? "ignored" : "FAILED", -+ format_linenum (numbuf, newwhere)); - } - - if (!skip_rest_of_patch) diff --git a/diff3-style-merges-simple-merge.diff b/diff3-style-merges-simple-merge.diff deleted file mode 100644 index 7c85546..0000000 --- a/diff3-style-merges-simple-merge.diff +++ /dev/null @@ -1,442 +0,0 @@ -From: Andreas Gruenbacher -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 - ---- - 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 -+#include -+#include -+#include -+ -+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)); -+} diff --git a/diff3-style-merges-tests.diff b/diff3-style-merges-tests.diff deleted file mode 100644 index 659354a..0000000 --- a/diff3-style-merges-tests.diff +++ /dev/null @@ -1,1189 +0,0 @@ ---- - tests/NOTES | 23 ++ - tests/diff3-merge.shrun | 51 ++++ - tests/locate-rejects.shrun | 77 +++++++ - tests/modes.shrun | 401 ++++++++++++++++++++++++++++++++++++++ - tests/prefix-suffix.shrun | 42 +++ - tests/rejects.shrun | 133 ++++++++++++ - tests/wiggle-base.shrun | 157 ++++++++++++++ - tests/wiggle-bugs.shrun | 179 ++++++++++++++++ - tests/wiggle-changeafteradd.shrun | 69 ++++++ - 9 files changed, 1132 insertions(+) - -Index: b/tests/diff3-merge.shrun -=================================================================== ---- /dev/null -+++ b/tests/diff3-merge.shrun -@@ -0,0 +1,51 @@ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+ $ seq 1 4 > a -+ $ sed -e 's/2/2b/' a > b -+ $ sed -e 's/4/4d/' a > c -+ -+Diff3 will merge changes if there is a one-line gap between them. -+(Patch would merge this as well.) -+ -+ $ diff3 -m b a c -+ > 1 -+ > 2b -+ > 3 -+ > 4d -+ -+But it will not merge adjacent but nonoverlapping changes. -+(Patch would merge this.) -+ -+ $ sed -e 's/3/3c/' a > d -+ $ diff3 -m b a d -+ > 1 -+ > <<<<<<< b -+ > 2b -+ > 3 -+ > ||||||| a -+ > 2 -+ > 3 -+ > ======= -+ > 2 -+ > 3c -+ > >>>>>>> d -+ > 4 -+ -+This is what you get when the first and third files are identical (i.e., -+a patch has already been applied). This is confusing because it is not -+immediately obvious which section refers to the first file. (It is the -+section between === and >>>, while it was the section between <<< and ||| -+above.) -+ -+ $ cp b e -+ $ diff3 -m e a b -+ > 1 -+ > <<<<<<< a -+ > 2 -+ > ======= -+ > 2b -+ > >>>>>>> b -+ > 3 -+ > 4 -Index: b/tests/modes.shrun -=================================================================== ---- /dev/null -+++ b/tests/modes.shrun -@@ -0,0 +1,401 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ cat > clean.diff -+< --- a -+< +++ b -+< @@ -2 +2 @@ -+< -2 -+< +2clean -+ -+$ seq 1 3 > c ; patch c < clean.diff -+> patching file c -+ -+$ cat c -+> 1 -+> 2clean -+> 3 -+ -+$ seq 1 3 > c ; patch -M c < clean.diff -+> patching file c -+ -+$ cat c -+> 1 -+> 2clean -+> 3 -+ -+$ cat > fuzz.diff -+< --- a -+< +++ b -+< @@ -1,3 +1,3 @@ -+< x -+< -2 -+< +2fuzz -+< x -+ -+$ seq 1 3 > c ; patch c < fuzz.diff -+> patching file c -+> Hunk #1 succeeded at 1 with fuzz 1. -+ -+$ cat c -+> 1 -+> 2fuzz -+> 3 -+ -+$ patch -f -M c < fuzz.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> <<<<<<< a -+> x -+> 2 -+> x -+> ||||||| b -+> x -+> 2fuzz -+> x -+> ======= -+> >>>>>>> -+> 1 -+> 2fuzz -+> 3 -+ -+$ seq 1 3 > c ; patch -M c < fuzz.diff -+> patching file c -+> Hunk #1 succeeded at 1 with fuzz 1. -+ -+$ cat c -+> 1 -+> 2fuzz -+> 3 -+ -+$ seq 1 3 > c ; patch --fuzz=0 -M c < fuzz.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> <<<<<<< a -+> x -+> 2 -+> x -+> ||||||| b -+> x -+> 2fuzz -+> x -+> ======= -+> >>>>>>> -+> 1 -+> 2 -+> 3 -+ -+$ cat > reject.diff -+< --- a -+< +++ b -+< @@ -2 +2 @@ -+< -2reject -+< +2tcejer -+ -+$ seq 1 3 > c ; patch c < reject.diff -+> patching file c -+> Hunk #1 FAILED at 2. -+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej -+ -+$ seq 1 3 > c ; patch -M c < reject.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> <<<<<<< a -+> 2reject -+> ||||||| b -+> 2tcejer -+> ======= -+> >>>>>>> -+> 2 -+> 3 -+ -+$ cat > insert.diff -+< --- a -+< +++ b -+< @@ -2,4 +2,5 @@ -+< 2 -+< 3x -+< +ins -+< 4 -+< 5 -+ -+$ seq 1 6 > c ; patch -M c < insert.diff -+> patching file c -+> Hunk #1 succeeded at 2 with fuzz 2. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> ins -+> 4 -+> 5 -+> 6 -+ -+$ cat > insert.diff -+< --- a -+< +++ b -+< @@ -2,4 +2,5 @@ -+< 2 -+< 3 -+< +ins -+< 4x -+< 5 -+ -+$ seq 1 6 > c ; patch --fuzz=1 -M c < insert.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4x -+> ||||||| b -+> ins -+> 4x -+> ======= -+> 4 -+> >>>>>>> -+> 5 -+> 6 -+ -+$ cat > insert.diff -+< --- a -+< +++ b -+< @@ -2,4 +2,5 @@ -+< 2 -+< 3x -+< +ins -+< 4x -+< 5 -+ -+$ seq 1 6 > c ; patch --fuzz=1 -M c < insert.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3x -+> 4x -+> ||||||| b -+> 3x -+> ins -+> 4x -+> ======= -+> 3 -+> 4 -+> >>>>>>> -+> 5 -+> 6 -+ -+$ seq 1 6 > c ; patch -M c < insert.diff -+> patching file c -+> Hunk #1 succeeded at 2 with fuzz 2. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> ins -+> 4 -+> 5 -+> 6 -+ -+$ cat > delete.diff -+< --- a -+< +++ b -+< @@ -2,5 +2,4 @@ -+< 2 -+< 3x -+< -4 -+< 5 -+< 6 -+ -+$ seq 1 7 > c ; patch --fuzz=1 -M c < delete.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3x -+> 4 -+> ||||||| b -+> 3x -+> ======= -+> 3 -+> 4 -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -+$ cat > delete.diff -+< --- a -+< +++ b -+< @@ -2,5 +2,4 @@ -+< 2 -+< 3 -+< -4x -+< 5 -+< 6 -+ -+$ seq 1 7 > c ; patch --fuzz=1 -M c < delete.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4x -+> ||||||| b -+> ======= -+> 4 -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -+$ cat > delete.diff -+< --- a -+< +++ b -+< @@ -2,5 +2,4 @@ -+< 2 -+< 3 -+< -4 -+< 5x -+< 6 -+ -+$ seq 1 7 > c ; patch --fuzz=1 -M c < delete.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4 -+> 5x -+> ||||||| b -+> 5x -+> ======= -+> 4 -+> 5 -+> >>>>>>> -+> 6 -+> 7 -+ -+$ cat > change.diff -+< --- a -+< +++ b -+< @@ -2,5 +2,5 @@ -+< 2 -+< 3x -+< -4 -+< +4x -+< 5 -+< 6 -+ -+$ seq 1 7 > c ; patch --fuzz=1 -M c < change.diff -+> patching file c -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3x -+> 4 -+> ||||||| b -+> 3x -+> 4x -+> ======= -+> 3 -+> 4 -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -+$ cat > delete-gone.diff -+< --- a -+< +++ b -+< @@ -1,7 +1,6 @@ -+< 1 -+< 2 -+< 3 -+< -4x -+< 5 -+< 6 -+< 7 -+ -+$ seq 1 7 | sed -e '3,5d' > c; patch --fuzz=2 -M c < delete-gone.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3 -+> 4x -+> 5 -+> ||||||| b -+> 3 -+> 5 -+> ======= -+> >>>>>>> -+> 6 -+> 7 -+ -+ -+$ cat > insert-gone.diff -+< --- a -+< +++ b -+< @@ -1,6 +1,7 @@ -+< 1 -+< 2 -+< 3 -+< +4x -+< 5 -+< 6 -+< 7 -+ -+$ seq 1 7 | sed -e '3,5d' > c; patch --fuzz=2 -M c < insert-gone.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3 -+> 5 -+> ||||||| b -+> 3 -+> 4x -+> 5 -+> ======= -+> >>>>>>> -+> 6 -+> 7 -+ -Index: b/tests/prefix-suffix.shrun -=================================================================== ---- /dev/null -+++ b/tests/prefix-suffix.shrun -@@ -0,0 +1,42 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ seq 1 7 > a -+$ seq 1 7 | sed -e '4d' > b -+$ diff -u -L a -L b a b > ab.diff -+$ diff -u -L b -L a b a > ba.diff -+ -+$ seq -f '%gc' 1 7 > c -+$ patch -M c < ab.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> <<<<<<< a -+> 1 -+> 2 -+> 3 -+> 4 -+> 5 -+> 6 -+> 7 -+> ||||||| b -+> 1 -+> 2 -+> 3 -+> 5 -+> 6 -+> 7 -+> ======= -+> >>>>>>> -+> 1c -+> 2c -+> 3c -+> 4c -+> 5c -+> 6c -+> 7c -Index: b/tests/locate-rejects.shrun -=================================================================== ---- /dev/null -+++ b/tests/locate-rejects.shrun -@@ -0,0 +1,77 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ seq 1 7 > a -+$ seq 1 7 | sed -e 's/4/4b/' > b -+$ seq 1 7 | sed -e 's/4/4c/' > c -+ -+$ diff -u a b > ab.diff -+ -+$ patch c < ab.diff -+> patching file c -+> Hunk #1 FAILED at 1. -+> 1 out of 1 hunk FAILED -- saving rejects to file c.rej -+ -+$ patch -M c < ab.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4 -+> ||||||| b -+> 4b -+> ======= -+> 4c -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -+$ (seq 1 3; echo 7) > c -+$ patch -M c < ab.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4 -+> 5 -+> 6 -+> ||||||| b -+> 4b -+> 5 -+> 6 -+> ======= -+> >>>>>>> -+> 7 -+ -+$ seq 1 7 | sed -e '4d' > c -+$ patch -M c < ab.diff -+> patching file c -+> Hunk #1 merged at 1 with conflicts. -+ -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4 -+> ||||||| b -+> 4b -+> ======= -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -Index: b/tests/rejects.shrun -=================================================================== ---- /dev/null -+++ b/tests/rejects.shrun -@@ -0,0 +1,133 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ set +o posix -+ -+$ x() { -++ local max=$1 b -++ shift -++ -++ while [ "$1" != -- ]; do -++ b[${#b[@]}]=$1 -++ shift -++ done -++ shift -++ local c=("$@") -++ -++ seq 1 $max > a -++ seq 1 $max | sed -f <(printf "%s\n" "${b[@]}") > b -++ seq 1 $max | sed -f <(printf "%s\n" "${c[@]}") > c -++ -++ diff -u a b | patch -s -f -M c -++ cat c -++ #diff3 -m c a b -++ } -+ -+$ x 9 -- -+> 1 -+> 2 -+> 3 -+> 4 -+> 5 -+> 6 -+> 7 -+> 8 -+> 9 -+ -+$ x 9 5d -- -+> 1 -+> 2 -+> 3 -+> 4 -+> 6 -+> 7 -+> 8 -+> 9 -+ -+$ x 9 5d -- 5d -+> 1 -+> 2 -+> 3 -+> 4 -+> <<<<<<< a -+> 5 -+> ======= -+> >>>>>>> b -+> 6 -+> 7 -+> 8 -+> 9 -+ -+$ x 9 5d -- 6d -+> 1 -+> 2 -+> 3 -+> 4 -+> <<<<<<< a -+> 5 -+> 6 -+> ||||||| b -+> 6 -+> ======= -+> 5 -+> >>>>>>> -+> 7 -+> 8 -+> 9 -+ -+$ x 9 5d -- 4d -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4 -+> 5 -+> ||||||| b -+> 4 -+> ======= -+> 5 -+> >>>>>>> -+> 6 -+> 7 -+> 8 -+> 9 -+ -+$ x 9 5aa -- 5aa -+> 1 -+> 2 -+> 3 -+> 4 -+> 5 -+> <<<<<<< a -+> ======= -+> a -+> >>>>>>> b -+> 6 -+> 7 -+> 8 -+> 9 -+ -+$ x 9 s/4/4b/ -- s/3/3c/ s/5/5c/ -+> 1 -+> 2 -+> <<<<<<< a -+> 3 -+> 4 -+> 5 -+> ||||||| b -+> 3 -+> 4b -+> 5 -+> ======= -+> 3c -+> 4 -+> 5c -+> >>>>>>> -+> 6 -+> 7 -+> 8 -+> 9 -Index: b/tests/wiggle-bugs.shrun -=================================================================== ---- /dev/null -+++ b/tests/wiggle-bugs.shrun -@@ -0,0 +1,179 @@ -+$ WIGGLE=wiggle -+ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+======================================== -+ -+$ echo a > a -+$ echo b > b -+$ diff -u a b > ab.diff -+$ echo c > c -+$ diff3 -m c a b -+> <<<<<<< c -+> c -+> ||||||| a -+> a -+> ======= -+> b -+> >>>>>>> b -+ -+In this case, patch has no way to know that c is part of the conflict. -+It could make a blind guess, though. -+ -+$ patch -s -M c < ab.diff -+$ cat c -+> <<<<<<< a -+> a -+> ||||||| b -+> b -+> ======= -+> >>>>>>> -+> c -+ -+======================================== -+ -+$ seq 1 7 | sed -e 's/4/4a/' > a -+$ seq 1 7 | sed -e 's/4/4b/' > b -+$ diff -u a b > ab.diff -+$ seq 1 7 | sed -e 's/4/4c/' > c -+$ diff3 -m c a b -+> 1 -+> 2 -+> 3 -+> <<<<<<< c -+> 4c -+> ||||||| a -+> 4a -+> ======= -+> 4b -+> >>>>>>> b -+> 5 -+> 6 -+> 7 -+ -+$ patch -s -M c < ab.diff -+$ cat c -+> 1 -+> 2 -+> 3 -+> <<<<<<< a -+> 4a -+> ||||||| b -+> 4b -+> ======= -+> 4c -+> >>>>>>> -+> 5 -+> 6 -+> 7 -+ -+======================================== -+ -+$ seq 1 7 | sed -e 's/4/4a/' > a -+$ seq 1 7 | sed -e 's/4/4b/' > b -+$ diff -u a b > ab.diff -+$ seq 1 7 | sed -e 's/[345]/&c/' > c -+$ diff3 -m c a b -+> 1 -+> 2 -+> <<<<<<< c -+> 3c -+> 4c -+> 5c -+> ||||||| a -+> 3 -+> 4a -+> 5 -+> ======= -+> 3 -+> 4b -+> 5 -+> >>>>>>> b -+> 6 -+> 7 -+ -+$ patch -s -M c < ab.diff -+$ cat c -+> 1 -+> 2 -+> <<<<<<< a -+> 3 -+> 4a -+> 5 -+> ||||||| b -+> 3 -+> 4b -+> 5 -+> ======= -+> 3c -+> 4c -+> 5c -+> >>>>>>> -+> 6 -+> 7 -+ -+======================================== -+ -+$ seq 1 7 | sed -e 's/4/4a/' > a -+$ seq 1 7 | sed -e 's/4/4b/' > b -+$ diff -u a b > ab.diff -+$ seq 1 7 | sed -e 's/./&c/' > c -+$ diff3 -m c a b -+> <<<<<<< c -+> 1c -+> 2c -+> 3c -+> 4c -+> 5c -+> 6c -+> 7c -+> ||||||| a -+> 1 -+> 2 -+> 3 -+> 4a -+> 5 -+> 6 -+> 7 -+> ======= -+> 1 -+> 2 -+> 3 -+> 4b -+> 5 -+> 6 -+> 7 -+> >>>>>>> b -+ -+$ patch -s -M c < ab.diff 2>/dev/null -+$ cat c -+> <<<<<<< a -+> 1 -+> 2 -+> 3 -+> 4a -+> 5 -+> 6 -+> 7 -+> ||||||| b -+> 1 -+> 2 -+> 3 -+> 4b -+> 5 -+> 6 -+> 7 -+> ======= -+> >>>>>>> -+> 1c -+> 2c -+> 3c -+> 4c -+> 5c -+> 6c -+> 7c -Index: b/tests/NOTES -=================================================================== ---- /dev/null -+++ b/tests/NOTES -@@ -0,0 +1,23 @@ -+Same change in b and c: -+ <<<<<<< a -+ old lines from patch -+ ======= -+ new version == new lines from patch -+ >>>>>>> b -+ -+Conflicting change (section order differs from diff3, otherwise equivalent): -+ <<<<<<< a -+ old lines from patch -+ ||||||| b -+ new lines from patch -+ ======= -+ new version -+ >>>>>>> -+ -+Clean change (diff3 doesn't have that, so maybe we don't need it either -+except for debugging): -+ <<<<<<< a -+ old lines -+ ======= -+ new version == new lines of patch -+ >>>>>>> -Index: b/tests/wiggle-changeafteradd.shrun -=================================================================== ---- /dev/null -+++ b/tests/wiggle-changeafteradd.shrun -@@ -0,0 +1,69 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ cat > orig -+< here -+< is -+< the -+< original -+< file -+ -+$ cat > new -+< here -+< is -+< the -+< new version of the -+< original -+< file -+ -+$ cat > new2 -+< here -+< is -+< the -+< new version of the -+< inaugural -+< file -+ -+$ diff3 -m new new2 orig -+> here -+> is -+> the -+> <<<<<<< new -+> new version of the -+> original -+> ||||||| new2 -+> new version of the -+> inaugural -+> ======= -+> original -+> >>>>>>> orig -+> file -+ -+In this case, merging without marking the conflict would be desirable: -+it should be possible to detect that this is only a minor change to a -+context line, there are context matches before and after, and the -+number of changes required is small. -+ -+$ diff -u new new2 > ab.diff -+$ patch orig -M < ab.diff -+> patching file orig -+> Hunk #1 merged at 2 with conflicts. -+ -+$ cat orig -+> here -+> is -+> the -+> <<<<<<< new -+> new version of the -+> original -+> ||||||| new2 -+> new version of the -+> inaugural -+> ======= -+> original -+> >>>>>>> -+> file -Index: b/tests/wiggle-base.shrun -=================================================================== ---- /dev/null -+++ b/tests/wiggle-base.shrun -@@ -0,0 +1,157 @@ -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+ -+$ cat > orig -+< -+< This is a base file -+< some changes are going to happen to it -+< but it has -+< several lines -+< so that alll -+< the changes -+< don't h... -+< I don't know waht I am saying. -+< This lion will have some changes made. -+< but this one wont -+< stuf stuf stuff -+< thing thing -+< xxxxx -+< that is all -+< except -+< for -+< this -+< last -+< bit -+ -+$ cat > new -+< s is a base file -+< some changes are going to happen to it -+< but it has -+< had -+< several lines -+< so that alll -+< the changes -+< don't h... -+< I don't know what I am saying. -+< This line will have some changes made. -+< but this one wont -+< stuf stuf stuff -+< thing thing -+< xxxxx -+< that is all -+< except -+< for -+< this -+< last -+< bit -+< x -+ -+$ cat > new2 -+< This is a base file -+< some changes are going to happen to it -+< but it has -+< had -+< several lines -+< so that alll -+< the changes -+< don't h... -+< I don't know what I am saying. -+< This line will have some modifications made. -+< but this one wont -+< stuf stuf stuff -+< thing thing -+< xxxxx -+< that is all -+< except -+< for -+< this -+< last -+< bit -+< x -+< -+ -+$ diff -u new new2 > ab.diff -+$ patch orig -f -M < ab.diff -+> patching file orig -+> Hunk #1 merged at 1 with conflicts. -+> Hunk #2 merged at 7 with conflicts. -+> Hunk #3 merged at 19 with conflicts. -+ -+$ cat orig -+> <<<<<<< new -+> s is a base file -+> some changes are going to happen to it -+> but it has -+> had -+> ||||||| new2 -+> This is a base file -+> some changes are going to happen to it -+> but it has -+> had -+> ======= -+> >>>>>>> -+> -+> This is a base file -+> some changes are going to happen to it -+> but it has -+> several lines -+> so that alll -+> the changes -+> don't h... -+> <<<<<<< new -+> I don't know what I am saying. -+> This line will have some changes made. -+> ||||||| new2 -+> I don't know what I am saying. -+> This line will have some modifications made. -+> ======= -+> I don't know waht I am saying. -+> This lion will have some changes made. -+> >>>>>>> -+> but this one wont -+> stuf stuf stuff -+> thing thing -+> xxxxx -+> that is all -+> except -+> for -+> <<<<<<< new -+> last -+> bit -+> x -+> ||||||| new2 -+> last -+> bit -+> x -+> -+> ======= -+> >>>>>>> -+> this -+> last -+> bit -+ -+#$ cat > merge -+#< -+#< This is a base file -+#< some changes are going to happen to it -+#< but it has -+#< several lines -+#< so that alll -+#< the changes -+#< don't h... -+#< I don't know waht I am saying. -+#< This lion will have some modifications made. -+#< but this one wont -+#< stuf stuf stuff -+#< thing thing -+#< xxxxx -+#< that is all -+#< except -+#< for -+#< this -+#< last -+#< bit diff --git a/explain-pch_char-oddity.diff b/explain-pch_char-oddity.diff deleted file mode 100644 index b13f755..0000000 --- a/explain-pch_char-oddity.diff +++ /dev/null @@ -1,19 +0,0 @@ ---- - pch.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -Index: b/pch.c -=================================================================== ---- a/pch.c -+++ b/pch.c -@@ -1877,7 +1877,9 @@ pch_line_len (LINENUM line) - return p_len[line]; - } - --/* Return the control character (+, -, *, !, etc) for a patch line. */ -+/* Return the control character (+, -, *, !, etc) for a patch line. A '\n' -+ indicates an empty line in a hunk that isn't part of the old or new -+ file's contents -- the context format allows that. */ - - char - pch_char (LINENUM line) diff --git a/fix-partial-context.diff b/fix-partial-context.diff deleted file mode 100644 index ad1ff50..0000000 --- a/fix-partial-context.diff +++ /dev/null @@ -1,91 +0,0 @@ -From: Andreas Gruenbacher -Subject: Patch fails to apply hunks with asymmetric context correctly - -Patch assumes that hunks with fewer context lines at the top than at the bottom -can only match at the beginning of the file, and hunks with fewer lines at the -bottom can only match at the end. The result is that patches with such hunks -will only apply with fuzz N if the prefix context is N lines longer or shorter -than the suffix context. This makes no sense; hunks with asymmetric context -are perfectly valid. - ---- - ChangeLog | 7 +++++++ - patch.c | 43 ++++--------------------------------------- - 2 files changed, 11 insertions(+), 39 deletions(-) - -Index: b/ChangeLog -=================================================================== ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,3 +1,10 @@ -+2007-11-02 Andreas Gruenbacher -+ -+ * patch.c (locate_hunk): Hunks that have fewer or more lines of -+ context at the beginning than at the end can match anywhere; the -+ assumption that this can only occur at the beginning or end of the -+ file is wrong. -+ - 2003-05-20 Paul Eggert - - * NEWS, configure.ac (AC_INIT): Version 2.5.9 released. -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -880,10 +880,10 @@ locate_hunk (LINENUM fuzz) - LINENUM pat_lines = pch_ptrn_lines(); - LINENUM prefix_context = pch_prefix_context (); - LINENUM suffix_context = pch_suffix_context (); -- LINENUM context = (prefix_context < suffix_context -- ? suffix_context : prefix_context); -- LINENUM prefix_fuzz = fuzz + prefix_context - context; -- LINENUM suffix_fuzz = fuzz + suffix_context - context; -+ LINENUM prefix_fuzz = (prefix_context < fuzz -+ ? prefix_context : fuzz); -+ LINENUM suffix_fuzz = (suffix_context < fuzz -+ ? suffix_context : fuzz); - LINENUM max_where = input_lines - (pat_lines - suffix_fuzz) + 1; - LINENUM min_where = last_frozen_line + 1 - (prefix_context - prefix_fuzz); - LINENUM max_pos_offset = max_where - first_guess; -@@ -898,41 +898,6 @@ locate_hunk (LINENUM fuzz) - if (first_guess <= max_neg_offset) - max_neg_offset = first_guess - 1; - -- if (prefix_fuzz < 0) -- { -- /* Can only match start of file. */ -- -- if (suffix_fuzz < 0) -- /* Can only match entire file. */ -- if (pat_lines != input_lines || prefix_context < last_frozen_line) -- return 0; -- -- offset = 1 - first_guess; -- if (last_frozen_line <= prefix_context -- && offset <= max_pos_offset -- && patch_match (first_guess, offset, (LINENUM) 0, suffix_fuzz)) -- { -- last_offset += offset; -- return first_guess + offset; -- } -- else -- return 0; -- } -- -- if (suffix_fuzz < 0) -- { -- /* Can only match end of file. */ -- offset = first_guess - (input_lines - pat_lines + 1); -- if (offset <= max_neg_offset -- && patch_match (first_guess, -offset, prefix_fuzz, (LINENUM) 0)) -- { -- last_offset -= offset; -- return first_guess - offset; -- } -- else -- return 0; -- } -- - for (offset = 0; offset <= max_offset; offset++) { - char numbuf0[LINENUM_LENGTH_BOUND + 1]; - char numbuf1[LINENUM_LENGTH_BOUND + 1]; diff --git a/fix-timestamp-parsing.diff b/fix-timestamp-parsing.diff deleted file mode 100644 index fdf6a87..0000000 --- a/fix-timestamp-parsing.diff +++ /dev/null @@ -1,58 +0,0 @@ -* str2time() will happily parse "\n" and similar; the result will be - undistinguishable from a valid timestamp. Avoid this by skipping - whitespace before and checking if anything remains first. - -* Always parse timestamps in patch headers relative to the local timezone - or UTC so that pch_timestamp() will always contain reasonable values - if a timestamp is present: we may need the timestamps later. - -* Change the bizarre logic which checks whether a timestamp is close to - the epoch by checking for exactly that. The result is the same, and we - won't have to parse the timestamp again. - ---- - util.c | 26 ++++++++++++-------------- - 1 file changed, 12 insertions(+), 14 deletions(-) - -Index: b/util.c -=================================================================== ---- a/util.c -+++ b/util.c -@@ -996,25 +996,23 @@ fetchname (char *at, int strip_leading, - if (*u != '\t' && strchr (u + 1, '\t')) - continue; - -- if (set_time | set_utc) -- stamp = str2time (&u, initial_time, -- set_utc ? 0L : TM_LOCAL_ZONE); -- else -- { -+ while (ISSPACE((unsigned char) *u)) -+ u++; -+ if (*u) { -+ stamp = str2time (&u, initial_time, -+ set_utc ? 0L : TM_LOCAL_ZONE); -+ - /* The head says the file is nonexistent if the timestamp - is the epoch; but the listed time is local time, not UTC, - and POSIX.1 allows local time offset anywhere in the range -- -25:00 < offset < +26:00. Match any time in that -- range by assuming local time is -25:00 and then matching -- any ``local'' time T in the range 0 < T < 25+26 hours. */ -- stamp = str2time (&u, initial_time, -25L * 60 * 60); -- if (0 < stamp && stamp < (25 + 26) * 60L * 60) -+ -25:00 < offset < +26:00. Match any time in that range. */ -+ if (!(set_time || set_utc) -+ && 25 * 60L * 60 < stamp && stamp < 26 * 60L * 60) - stamp = 0; -- } -- -- if (*u && ! ISSPACE ((unsigned char) *u)) -- stamp = (time_t) -1; - -+ if (*u && ! ISSPACE ((unsigned char) *u)) -+ stamp = (time_t) -1; -+ } - *t = '\0'; - break; - } diff --git a/format_startcount.diff b/format_startcount.diff deleted file mode 100644 index d0b4a9b..0000000 --- a/format_startcount.diff +++ /dev/null @@ -1,74 +0,0 @@ ---- - util.c | 30 +++++++++++++++++++++++++++--- - util.h | 2 ++ - 2 files changed, 29 insertions(+), 3 deletions(-) - -Index: b/util.c -=================================================================== ---- a/util.c -+++ b/util.c -@@ -466,10 +466,9 @@ remove_prefix (char *p, size_t prefixlen - continue; - } - --char * --format_linenum (char numbuf[LINENUM_LENGTH_BOUND + 1], LINENUM n) -+static char * -+__format_linenum (char *p, LINENUM n) - { -- char *p = numbuf + LINENUM_LENGTH_BOUND; - *p = '\0'; - - if (n < 0) -@@ -490,6 +489,31 @@ format_linenum (char numbuf[LINENUM_LENG - return p; - } - -+char * -+format_linenum (char numbuf[LINENUM_LENGTH_BOUND + 1], LINENUM n) -+{ -+ return __format_linenum(numbuf + LINENUM_LENGTH_BOUND, n); -+} -+ -+char * -+format_startcount (char rangebuf[LINERANGE_LENGTH_BOUND + 1], -+ LINENUM first, LINENUM lines) -+{ -+ char *p = rangebuf + LINERANGE_LENGTH_BOUND; -+ -+ if (lines == 1) -+ rangebuf = __format_linenum (p, first); -+ else -+ { -+ if (lines == 0 && first == 1) -+ first = 0; /* what diff produces ... */ -+ p = __format_linenum(p, lines); -+ rangebuf = __format_linenum(--p, first); -+ *p = ','; -+ } -+ return rangebuf; -+} -+ - #if !HAVE_VPRINTF - #define vfprintf my_vfprintf - static int -Index: b/util.h -=================================================================== ---- a/util.h -+++ b/util.h -@@ -25,6 +25,7 @@ - /* An upper bound on the print length of a signed decimal line number. - Add one for the sign. */ - #define LINENUM_LENGTH_BOUND (sizeof (LINENUM) * CHAR_BIT / 3 + 1) -+#define LINERANGE_LENGTH_BOUND (LINENUM_LENGTH_BOUND * 2 + 1) - - XTERN enum backup_type backup_type; - -@@ -45,6 +46,7 @@ bool version_get (char const *, char con - int create_file (char const *, int, mode_t); - int systemic (char const *); - char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], LINENUM); -+char *format_startcount (char[LINERANGE_LENGTH_BOUND + 1], LINENUM, LINENUM); - void Fseek (FILE *, file_offset, int); - void copy_file (char const *, char const *, int, mode_t); - void exit_with_signal (int) __attribute__ ((noreturn)); diff --git a/global-reject-file.diff b/global-reject-file.diff deleted file mode 100644 index b6d33be..0000000 --- a/global-reject-file.diff +++ /dev/null @@ -1,130 +0,0 @@ ---- - patch.c | 33 ++++++++++++++++++++++++++++----- - patch.man | 9 +++++++++ - 2 files changed, 37 insertions(+), 5 deletions(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -101,6 +101,7 @@ static int Argc; - static char * const *Argv; - - static FILE *rejfp; /* reject file pointer */ -+char *global_reject; - - static char const *patchname; - static char *rejname; -@@ -175,6 +176,10 @@ main (int argc, char **argv) - /* Make sure we clean up in case of disaster. */ - set_signals (false); - -+ /* initialize global reject file */ -+ if (global_reject) -+ init_reject (); -+ - for ( - open_patch_file (patchname); - there_is_another_patch(); -@@ -211,8 +216,9 @@ main (int argc, char **argv) - init_output (TMPOUTNAME, exclusive, &outstate); - } - -- /* initialize reject file */ -- init_reject (); -+ /* initialize per-patch reject file */ -+ if (!global_reject) -+ init_reject (); - - /* find out where all the lines are */ - if (!skip_rest_of_patch) -@@ -335,7 +341,8 @@ main (int argc, char **argv) - fclose (outstate.ofp); - outstate.ofp = 0; - } -- fclose (rejfp); -+ if (!global_reject) -+ fclose (rejfp); - continue; - } - -@@ -415,13 +422,13 @@ main (int argc, char **argv) - } - } - if (diff_type != ED_DIFF) { -- if (fclose (rejfp) != 0) -+ if (!global_reject && fclose (rejfp) != 0) - write_fatal (); - if (failed) { - somefailed = true; - say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1), - skip_rest_of_patch ? "ignored" : "FAILED"); -- if (outname) { -+ if (!global_reject && outname) { - char *rej = rejname; - if (!rejname) { - rej = xmalloc (strlen (outname) + 5); -@@ -448,6 +455,17 @@ main (int argc, char **argv) - } - set_signals (true); - } -+ if (global_reject) -+ { -+ if (fclose (rejfp) != 0) -+ write_fatal (); -+ if (somefailed) -+ { -+ say (" -- saving rejects to file %s\n", quotearg (global_reject)); -+ move_file (TMPREJNAME, &TMPREJNAME_needs_removal, -+ global_reject, 0644, false); -+ } -+ } - if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0)) - write_fatal (); - cleanup (); -@@ -526,6 +544,7 @@ static struct option const longopts[] = - {"posix", no_argument, NULL, CHAR_MAX + 7}, - {"quoting-style", required_argument, NULL, CHAR_MAX + 8}, - {"unified-reject-files", no_argument, NULL, CHAR_MAX + 9}, -+ {"global-reject-file", required_argument, NULL, CHAR_MAX + 10}, - {NULL, no_argument, NULL, 0} - }; - -@@ -585,6 +604,7 @@ static char const *const option_help[] = - " --dry-run Do not actually change any files; just print what would happen.", - " --posix Conform to the POSIX standard.", - " --unified-reject-files Create unified reject files.", -+" --global-reject-file=file Put all rejects into one file.", - "", - " -d DIR --directory=DIR Change the working directory to DIR first.", - #if HAVE_SETMODE_DOS -@@ -787,6 +807,9 @@ get_some_switches (void) - case CHAR_MAX + 9: - abort_hunk = abort_hunk_unified; - break; -+ case CHAR_MAX + 10: -+ global_reject = savestr (optarg); -+ break; - default: - usage (stderr, 2); - } -Index: b/patch.man -=================================================================== ---- a/patch.man -+++ b/patch.man -@@ -520,6 +520,15 @@ file. - \fB\*=unified\-reject\-files\fP - Produce unified reject files. The default is to produce context type reject files. - .TP -+.BI \*=global\-reject\-file= rejectfile -+Put all rejects into -+.I rejectfile -+instead of creating separate reject files for all files that have rejects. The -+.I rejectfile -+will contain headers that identify which file each reject refers to. Note that -+the global reject file is created even if \-\-dry\-run is specified (while -+non-global reject files will only be created without \-\-dry\-run). -+.TP - \fB\-R\fP or \fB\*=reverse\fP - Assume that this patch was created with the old and new files swapped. - (Yes, I'm afraid that does happen occasionally, human nature being what it diff --git a/patch-2.5.9-70-g71a9b5b.tar.gz b/patch-2.5.9-70-g71a9b5b.tar.gz new file mode 100644 index 0000000..08600f8 --- /dev/null +++ b/patch-2.5.9-70-g71a9b5b.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3645c3b7a0e9d77ed2136a122f28df472d812f0349c038ed13e1194f6f8d170b +size 240329 diff --git a/patch-2.5.9-cat_if_device.diff b/patch-2.5.9-cat_if_device.diff deleted file mode 100644 index 5efe1d8..0000000 --- a/patch-2.5.9-cat_if_device.diff +++ /dev/null @@ -1,96 +0,0 @@ ---- - patch.c | 2 +- - util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ - util.h | 1 + - 3 files changed, 52 insertions(+), 1 deletion(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -440,7 +440,7 @@ main (int argc, char **argv) - { - move_file (TMPREJNAME, &TMPREJNAME_needs_removal, - rej, instat.st_mode, false); -- if (! inerrno -+ if (! inerrno && !s_is_chrblkfifosock(rej) - && (chmod (rej, (instat.st_mode - & ~(S_IXUSR|S_IXGRP|S_IXOTH))) - != 0)) -Index: b/util.c -=================================================================== ---- a/util.c -+++ b/util.c -@@ -65,6 +65,49 @@ static bool fid_search (const char *, co - FROM_NEEDS_REMOVAL must be nonnull if FROM is nonnull. - Back up TO if BACKUP is true. */ - -+int -+s_is_chrblkfifosock (const char *path) -+{ -+ int r; -+ struct stat st; -+ -+ r = stat(path, &st); -+ if (r < 0) -+ return r; -+ -+ return (((st.st_mode & S_IFMT) == S_IFCHR) || -+ ((st.st_mode & S_IFMT) == S_IFBLK) || -+ ((st.st_mode & S_IFMT) == S_IFIFO) || -+ ((st.st_mode & S_IFMT) == S_IFSOCK)); -+} -+ -+void -+cat_file_to_dev (const char *from, const char *to) -+{ -+ size_t i; -+ int fromfd, tofd; -+ -+ fromfd = open(from, O_RDONLY); -+ if (fromfd < 0) -+ pfatal("could not open %s for reading", quotearg(from)); -+ -+ tofd = open(to, O_WRONLY | O_NONBLOCK); -+ if (tofd < 0) -+ pfatal("could not open %s for writing", quotearg(to)); -+ -+ while ((i = read (fromfd, buf, bufsize)) != 0) -+ { -+ if (i == (size_t) -1) -+ read_fatal (); -+ if (write (tofd, buf, i) != i) -+ write_fatal (); -+ } -+ if (close (fromfd) != 0) -+ read_fatal (); -+ if (close (tofd) != 0) -+ write_fatal (); -+} -+ - void - move_file (char const *from, int volatile *from_needs_removal, - char *to, mode_t mode, bool backup) -@@ -165,6 +208,13 @@ move_file (char const *from, int volatil - goto rename_succeeded; - } - -+ if (errno == EACCES && (s_is_chrblkfifosock(to) > 0)) -+ { -+ cat_file_to_dev (from, to); -+ unlink(from); -+ return; -+ } -+ - if (errno == EXDEV) - { - if (! backup) -Index: b/util.h -=================================================================== ---- a/util.h -+++ b/util.h -@@ -59,3 +59,4 @@ void remove_prefix (char *, size_t); - void removedirs (char *); - void set_signals (bool); - void write_fatal (void) __attribute__ ((noreturn)); -+int s_is_chrblkfifosock (const char *); diff --git a/patch-2.5.9.tar.bz2 b/patch-2.5.9.tar.bz2 deleted file mode 100644 index 3a1fadb..0000000 --- a/patch-2.5.9.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:612a424b80bccf4638059742dc77676387c75a880723fc990a5d3a0ad0799de3 -size 158619 diff --git a/patch-headers-in-reject-files.diff b/patch-headers-in-reject-files.diff deleted file mode 100644 index f51ae04..0000000 --- a/patch-headers-in-reject-files.diff +++ /dev/null @@ -1,221 +0,0 @@ ---- - patch.c | 42 +++++++++++++++++++++++++++++++-------- - tests/unified-reject-files.shrun | 32 ++++++++++++++++++++++------- - 2 files changed, 58 insertions(+), 16 deletions(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -66,8 +66,8 @@ static bool patch_match (LINENUM, LINENU - static bool similar (char const *, size_t, char const *, size_t); - static bool spew_output (struct outstate *); - static char const *make_temp (char); --static void abort_hunk_context (void); --static void abort_hunk_unified (void); -+static void abort_hunk_context (bool, bool); -+static void abort_hunk_unified (bool, bool); - static int numeric_string (char const *, bool, char const *); - static void cleanup (void); - static void get_some_switches (void); -@@ -77,7 +77,7 @@ static void reinitialize_almost_everythi - static void remove_if_needed (char const *, int volatile *); - static void usage (FILE *, int) __attribute__((noreturn)); - --static void (*abort_hunk) (void) = abort_hunk_context; -+static void (*abort_hunk) (bool, bool) = abort_hunk_context; - - static bool make_backups; - static bool backup_if_mismatch; -@@ -281,7 +281,7 @@ main (int argc, char **argv) - - newwhere = pch_newfirst() + last_offset; - if (skip_rest_of_patch) { -- abort_hunk(); -+ abort_hunk(!failed, reverse); - failed++; - if (verbosity == VERBOSE) - say ("Hunk #%d ignored at %s.\n", hunk, -@@ -295,14 +295,14 @@ main (int argc, char **argv) - say ("Patch attempted to create file %s, which already exists.\n", - quotearg (inname)); - -- abort_hunk(); -+ abort_hunk(!failed, reverse); - failed++; - if (verbosity != SILENT) - say ("Hunk #%d FAILED at %s.\n", hunk, - format_linenum (numbuf, newwhere)); - } - else if (! apply_hunk (&outstate, where)) { -- abort_hunk (); -+ abort_hunk (!failed, reverse); - failed++; - if (verbosity != SILENT) - say ("Hunk #%d FAILED at %s.\n", hunk, -@@ -938,7 +938,24 @@ locate_hunk (LINENUM fuzz) - /* We did not find the pattern, dump out the hunk so they can handle it. */ - - static void --abort_hunk_context (void) -+print_header_line(FILE *fp, const char *tag, bool reverse) -+{ -+ const char *name = pch_name(reverse); -+ time_t time = pch_timestamp(reverse); -+ char timebuf[37]; -+ -+ if (time != -1) { -+ timebuf[0] = '\t'; -+ strftime(timebuf + 1, sizeof(timebuf), -+ "%Y-%m-%d %H:%M:%S %z", -+ (set_utc ? gmtime : localtime)(&time)); -+ } else -+ *timebuf = '\0'; -+ fprintf(fp, "%s %s%s\n", tag, name ? name : "/dev/null", timebuf); -+} -+ -+static void -+abort_hunk_context (bool header, bool reverse) - { - register LINENUM i; - register LINENUM pat_end = pch_end (); -@@ -953,6 +970,10 @@ abort_hunk_context (void) - (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----"; - char const *c_function = pch_c_function(); - -+ if (header) { -+ print_header_line(rejfp, "***", reverse); -+ print_header_line(rejfp, "---", ! reverse); -+ } - fprintf(rejfp, "***************%s\n", c_function ? c_function : ""); - for (i=0; i<=pat_end; i++) { - char numbuf0[LINENUM_LENGTH_BOUND + 1]; -@@ -1066,7 +1087,7 @@ print_unified(FILE *fp) - } - - static void --abort_hunk_unified (void) -+abort_hunk_unified (bool header, bool reverse) - { - char rangebuf0[LINERANGE_LENGTH_BOUND + 1]; - char rangebuf1[LINERANGE_LENGTH_BOUND + 1]; -@@ -1074,6 +1095,11 @@ abort_hunk_unified (void) - LINENUM newfirst = pch_newfirst () + last_offset; - char const *c_function = pch_c_function (); - -+ if (header) -+ { -+ print_header_line (rejfp, "---", reverse); -+ print_header_line (rejfp, "+++", ! reverse); -+ } - fprintf (rejfp, "@@ -%s +%s @@%s\n", - format_startcount (rangebuf0, oldfirst, pch_ptrn_lines ()), - format_startcount (rangebuf1, newfirst, pch_repl_lines ()), -Index: b/tests/unified-reject-files.shrun -=================================================================== ---- a/tests/unified-reject-files.shrun -+++ b/tests/unified-reject-files.shrun -@@ -1,4 +1,6 @@ --$ PATCH=$(pwd)/patch -+$ PATCH=$(PATH=.:$PATH which patch) -+$ patch() { $PATCH "$@"; } -+ - $ tmpdir=$(mktemp -d) - $ trap "cd /; rm -rf $tmpdir" EXIT - $ cd $tmpdir -@@ -17,12 +19,14 @@ $ diff -U0 -p \ - + -L "f 2009-02-07 14:49:03.000000000 +0100" \ - + f.orig f > f.diff - --$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff -+$ patch -f -F0 -s --no-backup-if-mismatch f < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - Note: patch cannot deal with nanosecond timestamps :-( - - $ cat f.rej -+> *** f.orig 2009-02-07 14:49:02 +0100 -+> --- f 2009-02-07 14:49:03 +0100 - > *************** a() { - > *** 5 **** - > - 5 -@@ -30,38 +34,46 @@ $ cat f.rej - > + 5a - - $ diff -U0 -p -L f.orig -L f f.orig f > f.diff --$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff -+$ patch -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - $ cat f.rej -+> --- f.orig -+> +++ f - > @@ -5 +5 @@ a() { - > -5 - > +5a - --$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff -+$ patch -f -F0 -s --no-backup-if-mismatch f < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - $ cat f.rej -+> *** f.orig -+> --- f - > *************** a() { - > *** 5 **** - > - 5 - > --- 5 ---- - > + 5a - --$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff -+$ patch -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.orig.rej - - $ cat f.orig.rej -+> --- f -+> +++ f.orig - > @@ -5 +5 @@ a() { - > -5a - > +5 - - $ diff -U2 -p -L f.orig -L f f.orig f > f.diff - $ sed -e 's/5/5a/' -e 's/6/6x/' f.orig > f --$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff -+$ patch -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - $ cat f.rej -+> --- f.orig -+> +++ f - > @@ -3,5 +3,5 @@ a() { - > 3 - > -@@ -70,10 +82,12 @@ $ cat f.rej - > 6 - > } - --$ $PATCH -F0 -s --no-backup-if-mismatch f < f.diff -+$ patch -F0 -s --no-backup-if-mismatch f < f.diff - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - $ cat f.rej -+> *** f.orig -+> --- f - > *************** a() { - > *** 3,7 **** - > 3 -@@ -89,11 +103,13 @@ $ cat f.rej - > } - - $ diff -Nu -p -L /dev/null -L f.orig /dev/null f.orig > f2.diff --$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff -+$ patch -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff - > Patch attempted to create file f, which already exists. - > 1 out of 1 hunk FAILED -- saving rejects to file f.rej - - $ cat f.rej -+> --- /dev/null 1970-01-01 00:00:00 +0000 -+> +++ f.orig - > @@ -0,0 +1,7 @@ - > +a() { - > +2 diff --git a/patch.changes b/patch.changes index 5afca9d..85a2cc5 100644 --- a/patch.changes +++ b/patch.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Apr 2 16:21:14 CEST 2009 - agruen@suse.de + +- Update to version patch-2.5.9.69 which has all our patches + merged in one form or anther, along with many other fixes and + improvements (see NEWS). + ------------------------------------------------------------------- Tue Feb 24 12:56:06 CET 2009 - agruen@suse.de diff --git a/patch.spec b/patch.spec index c281b83..8240526 100644 --- a/patch.spec +++ b/patch.spec @@ -1,5 +1,5 @@ # -# spec file for package patch (Version 2.5.9) +# spec file for package patch (Version 2.5.9.70) # # Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. # @@ -17,35 +17,18 @@ # norootforbuild +Url: ftp://alpha.gnu.org/gnu/diffutils/ +%define ver 2.5.9-70-g71a9b5b Name: patch +BuildRequires: ed License: GPL v2 or later Group: Productivity/Text/Utilities AutoReqProv: on -Version: 2.5.9 -Release: 288 +Version: 2.5.9.70 +Release: 1 Summary: GNU patch -Source: ftp://prep.ai.mit.edu/pub/gnu/patch/%{name}-%{version}.tar.bz2 -Url: ftp://alpha.gnu.org/gnu/diffutils/ -Patch: trailing-cr-fix.diff -Patch1: remember-backup-files.diff -Patch2: pch_c_function.diff -Patch3: pch_name.diff -Patch4: preserve-c_function-in-reject-files.diff -Patch5: format_startcount.diff -Patch6: fix-timestamp-parsing.diff -Patch7: unified-reject-files.diff -Patch8: patch-headers-in-reject-files.diff -Patch9: global-reject-file.diff -Patch10: patch-2.5.9-cat_if_device.diff -Patch11: fix-partial-context.diff -Patch12: explain-pch_char-oddity.diff -Patch13: diff3-style-merges-tests.diff -Patch14: diff3-style-merges-refactoring.diff -Patch15: diff3-style-merges-refactoring-2.diff -Patch16: diff3-style-merges-simple-merge.diff -Patch17: diff3-style-merges-add-file-labels.diff -Patch18: diff3-style-merges-locate-merge.diff +Source: ftp://alpha.gnu.org/gnu/patch/patch-%ver.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -60,44 +43,18 @@ Authors: Paul Eggert %prep -%setup -q -%suse_update_config -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 +%setup -n patch-%ver %build -aclocal --acdir=m4 -autoheader -autoconf -CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE -Wall -O2 -pipe" \ -./configure \ -%ifarch sparc sparc64 - --disable-largefile \ -%endif - --prefix=%{_prefix} -make CPPFLAGS="" +CFLAGS="$RPM_OPT_FLAGS -Wall -O2 -pipe" \ +./configure --prefix=%{_prefix} +make #CPPFLAGS="" + +%check +make check %install -make install \ - bindir=$RPM_BUILD_ROOT%{_bindir} \ - man1dir=$RPM_BUILD_ROOT%{_mandir}/man1 +make install DESTDIR=$RPM_BUILD_ROOT %files %defattr(-,root,root) @@ -106,6 +63,10 @@ make install \ %doc %{_mandir}/man1/patch.1.gz %changelog +* Thu Apr 02 2009 agruen@suse.de +- Update to version patch-2.5.9.69 which has all our patches + merged in one form or anther, along with many other fixes and + improvements (see NEWS). * Tue Feb 24 2009 agruen@suse.de - Include patch headers in reject files so that they form proper patches themselves. diff --git a/pch_c_function.diff b/pch_c_function.diff deleted file mode 100644 index b225bf0..0000000 --- a/pch_c_function.diff +++ /dev/null @@ -1,84 +0,0 @@ -FIXME: free() - ---- - pch.c | 32 +++++++++++++++++++++++++++++++- - pch.h | 1 + - 2 files changed, 32 insertions(+), 1 deletion(-) - -Index: b/pch.c -=================================================================== ---- a/pch.c -+++ b/pch.c -@@ -68,6 +68,7 @@ static LINENUM p_sline; /* and the lin - static LINENUM p_hunk_beg; /* line number of current hunk */ - static LINENUM p_efake = -1; /* end of faked up lines--don't free */ - static LINENUM p_bfake = -1; /* beg of faked up lines */ -+static char *p_c_function; /* the C function a hunk is in */ - - enum nametype { OLD, NEW, INDEX, NONE }; - -@@ -888,6 +889,19 @@ another_hunk (enum diff difftype, bool r - next_intuit_at(line_beginning,p_input_line); - return chars_read == (size_t) -1 ? -1 : 0; - } -+ s = buf; -+ while (*s == '*') -+ s++; -+ if (*s == ' ') -+ { -+ p_c_function = s; -+ while (*s != '\n') -+ s++; -+ *s = '\0'; -+ p_c_function = savestr (p_c_function); -+ } -+ else -+ p_c_function = NULL; - p_hunk_beg = p_input_line + 1; - while (p_end < p_max) { - chars_read = get_line (); -@@ -1277,8 +1291,18 @@ another_hunk (enum diff difftype, bool r - else - p_repl_lines = 1; - if (*s == ' ') s++; -- if (*s != '@') -+ if (*s++ != '@') - malformed (); -+ if (*s++ == '@' && *s == ' ' && *s != '\0') -+ { -+ p_c_function = s; -+ while (*s != '\n') -+ s++; -+ *s = '\0'; -+ p_c_function = savestr (p_c_function); -+ } -+ else -+ p_c_function = NULL; - if (!p_ptrn_lines) - p_first++; /* do append rather than insert */ - if (!p_repl_lines) -@@ -1884,6 +1908,12 @@ pch_hunk_beg (void) - return p_hunk_beg; - } - -+char const * -+pch_c_function (void) -+{ -+ return p_c_function; -+} -+ - /* Is the newline-terminated line a valid `ed' command for patch - input? If so, return the command character; if not, return 0. - This accepts accepts just a subset of the valid commands, but it's -Index: b/pch.h -=================================================================== ---- a/pch.h -+++ b/pch.h -@@ -25,6 +25,7 @@ - LINENUM pch_end (void); - LINENUM pch_first (void); - LINENUM pch_hunk_beg (void); -+char const *pch_c_function (void); - LINENUM pch_newfirst (void); - LINENUM pch_prefix_context (void); - LINENUM pch_ptrn_lines (void); diff --git a/pch_name.diff b/pch_name.diff deleted file mode 100644 index 2852f10..0000000 --- a/pch_name.diff +++ /dev/null @@ -1,281 +0,0 @@ -From: Andreas Gruenbacher -Subject: diff3-style merges: pch_name() - -Make a pch_name() function available for accessing the old and the new -filename in the patch header. - -Signed-off-by: Andreas Gruenbacher - ---- - pch.c | 88 ++++++++++++++++++++++++++++++++++-------------------------------- - pch.h | 3 ++ - 2 files changed, 49 insertions(+), 42 deletions(-) - -Index: b/pch.c -=================================================================== ---- a/pch.c -+++ b/pch.c -@@ -43,6 +43,7 @@ static int p_says_nonexistent[2]; /* [0] - 1 for existent and probably (but not necessarily) empty, - 2 for nonexistent */ - static int p_rfc934_nesting; /* RFC 934 nesting level */ -+static char *p_name[3]; /* filenames in patch headers */ - static time_t p_timestamp[2]; /* timestamps in patch headers */ - static off_t p_filesize; /* size of the patch file */ - static LINENUM p_first; /* 1st line number */ -@@ -70,8 +71,6 @@ static LINENUM p_efake = -1; /* end of - static LINENUM p_bfake = -1; /* beg of faked up lines */ - static char *p_c_function; /* the C function a hunk is in */ - --enum nametype { OLD, NEW, INDEX, NONE }; -- - static char *scan_linenum (char *, LINENUM *); - static enum diff intuit_diff_type (void); - static enum nametype best_name (char * const *, int const *); -@@ -300,13 +299,17 @@ intuit_diff_type (void) - register bool this_is_a_command = false; - register bool stars_this_line = false; - enum nametype i; -- char *name[3]; - struct stat st[3]; - int stat_errno[3]; - int version_controlled[3]; - register enum diff retval; - -- name[OLD] = name[NEW] = name[INDEX] = 0; -+ for (i = OLD; i <= INDEX; i++) -+ if (p_name[i]) { -+ free (p_name[i]); -+ p_name[i] = 0; -+ } -+ - version_controlled[OLD] = -1; - version_controlled[NEW] = -1; - version_controlled[INDEX] = -1; -@@ -365,16 +368,16 @@ intuit_diff_type (void) - p_strip_trailing_cr = strip_trailing_cr; - } - if (!stars_last_line && strnEQ(s, "*** ", 4)) -- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); -+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); - else if (strnEQ(s, "+++ ", 4)) - { - /* Swap with NEW below. */ -- name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); -+ p_name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); - p_strip_trailing_cr = strip_trailing_cr; - } - else if (strnEQ(s, "Index:", 6)) - { -- name[INDEX] = fetchname (s+6, strippath, (time_t *) 0); -+ p_name[INDEX] = fetchname (s+6, strippath, (time_t *) 0); - p_strip_trailing_cr = strip_trailing_cr; - } - else if (strnEQ(s, "Prereq:", 7)) { -@@ -410,7 +413,7 @@ intuit_diff_type (void) - if (strnEQ(t, "--- ", 4)) - { - time_t timestamp = (time_t) -1; -- name[NEW] = fetchname (t+4, strippath, ×tamp); -+ p_name[NEW] = fetchname (t+4, strippath, ×tamp); - if (timestamp != (time_t) -1) - { - p_timestamp[NEW] = timestamp; -@@ -430,13 +433,13 @@ intuit_diff_type (void) - if ((diff_type == NO_DIFF || diff_type == UNI_DIFF) - && strnEQ(s, "@@ -", 4)) { - -- /* `name' and `p_timestamp' are backwards; swap them. */ -+ /* `p_name' and `p_timestamp' are backwards; swap them. */ - time_t ti = p_timestamp[OLD]; - p_timestamp[OLD] = p_timestamp[NEW]; - p_timestamp[NEW] = ti; -- t = name[OLD]; -- name[OLD] = name[NEW]; -- name[NEW] = t; -+ t = p_name[OLD]; -+ p_name[OLD] = p_name[NEW]; -+ p_name[NEW] = t; - - s += 4; - if (s[0] == '0' && !ISDIGIT (s[1])) -@@ -451,9 +454,9 @@ intuit_diff_type (void) - p_start = this_line; - p_sline = p_input_line; - retval = UNI_DIFF; -- if (! ((name[OLD] || ! p_timestamp[OLD]) -- && (name[NEW] || ! p_timestamp[NEW])) -- && ! name[INDEX]) -+ if (! ((p_name[OLD] || ! p_timestamp[OLD]) -+ && (p_name[NEW] || ! p_timestamp[NEW])) -+ && ! p_name[INDEX]) - { - char numbuf[LINENUM_LENGTH_BOUND + 1]; - say ("missing header for unified diff at line %s of patch\n", -@@ -492,9 +495,9 @@ intuit_diff_type (void) - next_intuit_at (saved_p_base, saved_p_bline); - } - -- if (! ((name[OLD] || ! p_timestamp[OLD]) -- && (name[NEW] || ! p_timestamp[NEW])) -- && ! name[INDEX]) -+ if (! ((p_name[OLD] || ! p_timestamp[OLD]) -+ && (p_name[NEW] || ! p_timestamp[NEW])) -+ && ! p_name[INDEX]) - { - char numbuf[LINENUM_LENGTH_BOUND + 1]; - say ("missing header for context diff at line %s of patch\n", -@@ -543,23 +546,23 @@ intuit_diff_type (void) - { - enum nametype i0 = NONE; - -- if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX]) -+ if (! posixly_correct && (p_name[OLD] || p_name[NEW]) && p_name[INDEX]) - { -- free (name[INDEX]); -- name[INDEX] = 0; -+ free (p_name[INDEX]); -+ p_name[INDEX] = 0; - } - - for (i = OLD; i <= INDEX; i++) -- if (name[i]) -+ if (p_name[i]) - { -- if (i0 != NONE && strcmp (name[i0], name[i]) == 0) -+ if (i0 != NONE && strcmp (p_name[i0], p_name[i]) == 0) - { - /* It's the same name as before; reuse stat results. */ - stat_errno[i] = stat_errno[i0]; - if (! stat_errno[i]) - st[i] = st[i0]; - } -- else if (stat (name[i], &st[i]) != 0) -+ else if (stat (p_name[i], &st[i]) != 0) - stat_errno[i] = errno; - else - { -@@ -574,30 +577,30 @@ intuit_diff_type (void) - { - bool is_empty; - -- i = best_name (name, stat_errno); -+ i = best_name (p_name, stat_errno); - - if (i == NONE && patch_get) - { - enum nametype nope = NONE; - - for (i = OLD; i <= INDEX; i++) -- if (name[i]) -+ if (p_name[i]) - { - char const *cs; - char *getbuf; - char *diffbuf; - bool readonly = (outfile -- && strcmp (outfile, name[i]) != 0); -+ && strcmp (outfile, p_name[i]) != 0); - -- if (nope == NONE || strcmp (name[nope], name[i]) != 0) -+ if (nope == NONE || strcmp (p_name[nope], p_name[i]) != 0) - { - cs = (version_controller -- (name[i], readonly, (struct stat *) 0, -+ (p_name[i], readonly, (struct stat *) 0, - &getbuf, &diffbuf)); - version_controlled[i] = !! cs; - if (cs) - { -- if (version_get (name[i], cs, false, readonly, -+ if (version_get (p_name[i], cs, false, readonly, - getbuf, &st[i])) - stat_errno[i] = 0; - else -@@ -627,7 +630,7 @@ intuit_diff_type (void) - (i == NONE ? "delete" - : st[i].st_size == 0 ? "empty out" - : "create"), -- quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]), -+ quotearg (p_name[i == NONE || st[i].st_size == 0 ? i0 : i]), - (i == NONE ? "does not exist" - : st[i].st_size == 0 ? "is already empty" - : "already exists")); -@@ -640,19 +643,19 @@ intuit_diff_type (void) - int distance_from_minimum[3]; - - for (i = OLD; i <= INDEX; i++) -- if (name[i]) -+ if (p_name[i]) - { -- newdirs[i] = (prefix_components (name[i], false) -- - prefix_components (name[i], true)); -+ newdirs[i] = (prefix_components (p_name[i], false) -+ - prefix_components (p_name[i], true)); - if (newdirs[i] < newdirs_min) - newdirs_min = newdirs[i]; - } - - for (i = OLD; i <= INDEX; i++) -- if (name[i]) -+ if (p_name[i]) - distance_from_minimum[i] = newdirs[i] - newdirs_min; - -- i = best_name (name, distance_from_minimum); -+ i = best_name (p_name, distance_from_minimum); - } - } - } -@@ -661,17 +664,12 @@ intuit_diff_type (void) - inerrno = -1; - else - { -- inname = name[i]; -- name[i] = 0; -+ inname = savestr(p_name[i]); - inerrno = stat_errno[i]; - invc = version_controlled[i]; - instat = st[i]; - } - -- for (i = OLD; i <= INDEX; i++) -- if (name[i]) -- free (name[i]); -- - return retval; - } - -@@ -1800,6 +1798,12 @@ pch_says_nonexistent (bool which) - return p_says_nonexistent[which]; - } - -+const char * -+pch_name (enum nametype type) -+{ -+ return type == NONE ? NULL : p_name[type]; -+} -+ - /* Return timestamp of patch header for file WHICH (false = old, true = new), - or -1 if there was no timestamp or an error in the timestamp. */ - -Index: b/pch.h -=================================================================== ---- a/pch.h -+++ b/pch.h -@@ -22,6 +22,8 @@ - If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -+enum nametype { OLD, NEW, INDEX, NONE }; -+ - LINENUM pch_end (void); - LINENUM pch_first (void); - LINENUM pch_hunk_beg (void); -@@ -39,6 +41,7 @@ char pch_char (LINENUM); - int another_hunk (enum diff, bool); - int pch_says_nonexistent (bool); - size_t pch_line_len (LINENUM); -+const char *pch_name(enum nametype); - time_t pch_timestamp (bool); - void do_ed_script (FILE *); - void open_patch_file (char const *); diff --git a/preserve-c_function-in-reject-files.diff b/preserve-c_function-in-reject-files.diff deleted file mode 100644 index 4d63ef4..0000000 --- a/preserve-c_function-in-reject-files.diff +++ /dev/null @@ -1,21 +0,0 @@ -Include the C function names in reject files whenever possible. - ---- - patch.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -943,8 +943,9 @@ abort_hunk (void) - (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : ""; - char const *minuses = - (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----"; -+ char const *c_function = pch_c_function(); - -- fprintf(rejfp, "***************\n"); -+ fprintf(rejfp, "***************%s\n", c_function ? c_function : ""); - for (i=0; i<=pat_end; i++) { - char numbuf0[LINENUM_LENGTH_BOUND + 1]; - char numbuf1[LINENUM_LENGTH_BOUND + 1]; diff --git a/remember-backup-files.diff b/remember-backup-files.diff deleted file mode 100644 index bec287e..0000000 --- a/remember-backup-files.diff +++ /dev/null @@ -1,1520 +0,0 @@ -This patch remembers backup file names patch has already created -in a binary tree, and prevents patch from overwriting backup -files it has created before. - -Index: patch-2.5.9/Makefile.in -=================================================================== ---- patch-2.5.9.orig/Makefile.in -+++ patch-2.5.9/Makefile.in -@@ -62,7 +62,7 @@ CONFIG_STATUS = config.status - SHELL = /bin/sh - - LIBSRCS = error.c malloc.c memchr.c mkdir.c \ -- realloc.c rmdir.c strcasecmp.c strncasecmp.c -+ realloc.c rmdir.c strcasecmp.c strncasecmp.c hash.c - SRCS = $(LIBSRCS) \ - addext.c argmatch.c backupfile.c \ - basename.c dirname.c \ -@@ -78,12 +78,12 @@ OBJS = $(LIBOBJS) \ - maketime.$(OBJEXT) partime.$(OBJEXT) \ - patch.$(OBJEXT) pch.$(OBJEXT) \ - quote.$(OBJEXT) quotearg.$(OBJEXT) quotesys.$(OBJEXT) \ -- util.$(OBJEXT) version.$(OBJEXT) xmalloc.$(OBJEXT) -+ util.$(OBJEXT) version.$(OBJEXT) xmalloc.$(OBJEXT) hash.$(OBJEXT) - HDRS = argmatch.h backupfile.h common.h dirname.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 -+ unlocked-io.h util.h version.h xalloc.h hash.h - MISC = AUTHORS COPYING ChangeLog INSTALL Makefile.in NEWS README \ - aclocal.m4 \ - config.hin configure configure.ac \ -Index: patch-2.5.9/configure.ac -=================================================================== ---- patch-2.5.9.orig/configure.ac -+++ patch-2.5.9/configure.ac -@@ -64,6 +64,9 @@ gl_GETOPT - gl_PREREQ_XMALLOC - gl_QUOTE - gl_QUOTEARG -+gl_HASH -+ -+ag_CHECK_NANOSECOND_STAT - - dnl This should be in gnulib, but isn't for some reason. - AC_DEFUN([jm_PREREQ_ADDEXT], -Index: patch-2.5.9/m4/hash.m4 -=================================================================== ---- /dev/null -+++ patch-2.5.9/m4/hash.m4 -@@ -0,0 +1,15 @@ -+# hash.m4 serial 1 -+dnl Copyright (C) 2002 Free Software Foundation, Inc. -+dnl This file is free software, distributed under the terms of the GNU -+dnl General Public License. As a special exception to the GNU General -+dnl Public License, this file may be distributed as part of a program -+dnl that contains a configuration script generated by Autoconf, under -+dnl the same distribution terms as the rest of that program. -+ -+AC_DEFUN([gl_HASH], -+[ -+ dnl Prerequisites of lib/hash.c. -+ AC_CHECK_HEADERS_ONCE(stdlib.h) -+ AC_HEADER_STDBOOL -+ AC_CHECK_DECLS_ONCE(free malloc) -+]) -Index: patch-2.5.9/util.c -=================================================================== ---- patch-2.5.9.orig/util.c -+++ patch-2.5.9/util.c -@@ -45,9 +45,17 @@ - # define raise(sig) kill (getpid (), sig) - #endif - -+#if defined(HAVE_STAT_TIMEVAL) -+#include -+#endif -+ - #include -+#include - - static void makedirs (char *); -+static bool fid_search (const char *, const struct stat *, bool); -+# define fid_exists(name, pst) fid_search (name, pst, false) -+# define insert_fid(name) fid_search (name, NULL, true) - - /* Move a file FROM (where *FROM_NEEDS_REMOVAL is nonzero if FROM - needs removal when cleaning up at the end of execution) -@@ -64,6 +72,9 @@ move_file (char const *from, int volatil - struct stat to_st; - int to_errno = ! backup ? -1 : stat (to, &to_st) == 0 ? 0 : errno; - -+ if (backup && ! to_errno && fid_exists (to, &to_st)) -+ backup = false; -+ - if (backup) - { - int try_makedirs_errno = 0; -@@ -123,6 +134,7 @@ move_file (char const *from, int volatil - quotearg_n (0, to), quotearg_n (1, bakname)); - while (rename (to, bakname) != 0) - { -+ /* FIXME: copy if errno == EXDEV */ - if (errno != try_makedirs_errno) - pfatal ("Can't rename file %s to %s", - quotearg_n (0, to), quotearg_n (1, bakname)); -@@ -165,6 +177,7 @@ move_file (char const *from, int volatil - if (! to_dir_known_to_exist) - makedirs (to); - copy_file (from, to, 0, mode); -+ insert_fid (to); - return; - } - -@@ -173,6 +186,7 @@ move_file (char const *from, int volatil - } - - rename_succeeded: -+ insert_fid (to); - /* Do not clear *FROM_NEEDS_REMOVAL if it's possible that the - rename returned zero because FROM and TO are hard links to - the same file. */ -@@ -1011,3 +1025,105 @@ Fseek (FILE *stream, file_offset offset, - if (file_seek (stream, offset, ptrname) != 0) - pfatal ("fseek"); - } -+ -+typedef struct -+{ -+ dev_t fid_dev; -+ ino_t fid_ino; -+ time_t fid_mtime; -+ unsigned long fid_mtimensec; -+} file_id; -+ -+unsigned -+file_id_hasher (file_id *entry, unsigned table_size) -+{ -+ return ((unsigned long) entry->fid_ino + -+ (unsigned long) entry->fid_dev + -+ (unsigned long) entry->fid_mtime + -+ (unsigned long) entry->fid_mtimensec) % table_size; -+} -+ -+bool -+file_id_comparator (file_id *entry1, file_id *entry2) -+{ -+ return (entry1->fid_dev == entry2->fid_dev && -+ entry1->fid_ino == entry2->fid_ino && -+ entry1->fid_mtime == entry2->fid_mtime && -+ entry1->fid_mtimensec == entry2->fid_mtimensec); -+} -+ -+void -+file_id_freer (file_id *entry) -+{ -+ free (entry); -+} -+ -+Hash_table *file_id_hash; -+ -+/* Check if the file identified by FILENAME and PST was already seen. If the -+ file was already seen, returns TRUE. If the file has not yet been seen -+ and INSERT is TRUE, it is inserted. PST or FILENAME may be NULL (but not -+ both of them). */ -+ -+static bool -+fid_search (const char *filename, const struct stat *pst, bool insert) -+{ -+ struct stat st; -+ -+ if (!file_id_hash) -+ { -+ file_id_hash = hash_initialize (0, NULL, (Hash_hasher) file_id_hasher, -+ (Hash_comparator) file_id_comparator, -+ (Hash_data_freer) file_id_freer); -+ if (!file_id_hash) -+ pfatal ("hash_initialize"); -+ } -+ -+ if (!pst) -+ { -+ if (stat (filename, &st) != 0) -+ pfatal ("%s", quotearg (filename)); -+ pst = &st; -+ } -+ -+ if (insert) -+ { -+ file_id *pfid = xmalloc (sizeof (file_id)), *old_pfid; -+ pfid->fid_dev = pst->st_dev; -+ pfid->fid_ino = pst->st_ino; -+ pfid->fid_mtime = pst->st_mtime; -+#if defined(HAVE_STAT_NSEC) -+ pfid->fid_mtimensec = pst->st_mtimensec; -+#elif defined(HAVE_STAT_TIMEVAL) -+ pfid->fid_mtimensec = pst->st_mtim.tv_nsec; -+#else -+ pfid->fid_mtimensec = 0; -+#endif -+ old_pfid = hash_insert (file_id_hash, pfid); -+ if (!old_pfid) -+ pfatal ("hash_insert"); -+ else if (old_pfid != pfid) -+ { -+ free (pfid); -+ return true; -+ } -+ else -+ return false; -+ } -+ else -+ { -+ file_id fid; -+ fid.fid_dev = pst->st_dev; -+ fid.fid_ino = pst->st_ino; -+ fid.fid_mtime = pst->st_mtime; -+#if defined(HAVE_STAT_NSEC) -+ fid.fid_mtimensec = pst->st_mtimensec; -+#elif defined(HAVE_STAT_TIMEVAL) -+ fid.fid_mtimensec = pst->st_mtim.tv_nsec; -+#else -+ fid.fid_mtimensec = 0; -+#endif -+ return hash_lookup (file_id_hash, &fid) != 0; -+ } -+} -+ -Index: patch-2.5.9/hash.c -=================================================================== ---- /dev/null -+++ patch-2.5.9/hash.c -@@ -0,0 +1,1051 @@ -+/* hash - hashing table processing. -+ -+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software -+ Foundation, Inc. -+ -+ Written by Jim Meyering, 1992. -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2, or (at your option) -+ any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software Foundation, -+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -+ -+/* A generic hash table package. */ -+ -+/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead -+ of malloc. If you change USE_OBSTACK, you have to recompile! */ -+ -+#if HAVE_CONFIG_H -+# include -+#endif -+#if HAVE_STDLIB_H -+# include -+#endif -+ -+#include -+#include -+#include -+ -+#ifndef HAVE_DECL_FREE -+"this configure-time declaration test was not run" -+#endif -+#if !HAVE_DECL_FREE -+void free (); -+#endif -+ -+#ifndef HAVE_DECL_MALLOC -+"this configure-time declaration test was not run" -+#endif -+#if !HAVE_DECL_MALLOC -+char *malloc (); -+#endif -+ -+#if USE_OBSTACK -+# include "obstack.h" -+# ifndef obstack_chunk_alloc -+# define obstack_chunk_alloc malloc -+# endif -+# ifndef obstack_chunk_free -+# define obstack_chunk_free free -+# endif -+#endif -+ -+#include "hash.h" -+ -+struct hash_table -+ { -+ /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1, -+ for a possibility of N_BUCKETS. Among those, N_BUCKETS_USED buckets -+ are not empty, there are N_ENTRIES active entries in the table. */ -+ struct hash_entry *bucket; -+ struct hash_entry *bucket_limit; -+ unsigned n_buckets; -+ unsigned n_buckets_used; -+ unsigned n_entries; -+ -+ /* Tuning arguments, kept in a physicaly separate structure. */ -+ const Hash_tuning *tuning; -+ -+ /* Three functions are given to `hash_initialize', see the documentation -+ block for this function. In a word, HASHER randomizes a user entry -+ into a number up from 0 up to some maximum minus 1; COMPARATOR returns -+ true if two user entries compare equally; and DATA_FREER is the cleanup -+ function for a user entry. */ -+ Hash_hasher hasher; -+ Hash_comparator comparator; -+ Hash_data_freer data_freer; -+ -+ /* A linked list of freed struct hash_entry structs. */ -+ struct hash_entry *free_entry_list; -+ -+#if USE_OBSTACK -+ /* Whenever obstacks are used, it is possible to allocate all overflowed -+ entries into a single stack, so they all can be freed in a single -+ operation. It is not clear if the speedup is worth the trouble. */ -+ struct obstack entry_stack; -+#endif -+ }; -+ -+/* A hash table contains many internal entries, each holding a pointer to -+ some user provided data (also called a user entry). An entry indistinctly -+ refers to both the internal entry and its associated user entry. A user -+ entry contents may be hashed by a randomization function (the hashing -+ function, or just `hasher' for short) into a number (or `slot') between 0 -+ and the current table size. At each slot position in the hash table, -+ starts a linked chain of entries for which the user data all hash to this -+ slot. A bucket is the collection of all entries hashing to the same slot. -+ -+ A good `hasher' function will distribute entries rather evenly in buckets. -+ In the ideal case, the length of each bucket is roughly the number of -+ entries divided by the table size. Finding the slot for a data is usually -+ done in constant time by the `hasher', and the later finding of a precise -+ entry is linear in time with the size of the bucket. Consequently, a -+ larger hash table size (that is, a larger number of buckets) is prone to -+ yielding shorter chains, *given* the `hasher' function behaves properly. -+ -+ Long buckets slow down the lookup algorithm. One might use big hash table -+ sizes in hope to reduce the average length of buckets, but this might -+ become inordinate, as unused slots in the hash table take some space. The -+ best bet is to make sure you are using a good `hasher' function (beware -+ that those are not that easy to write! :-), and to use a table size -+ larger than the actual number of entries. */ -+ -+/* If an insertion makes the ratio of nonempty buckets to table size larger -+ than the growth threshold (a number between 0.0 and 1.0), then increase -+ the table size by multiplying by the growth factor (a number greater than -+ 1.0). The growth threshold defaults to 0.8, and the growth factor -+ defaults to 1.414, meaning that the table will have doubled its size -+ every second time 80% of the buckets get used. */ -+#define DEFAULT_GROWTH_THRESHOLD 0.8 -+#define DEFAULT_GROWTH_FACTOR 1.414 -+ -+/* If a deletion empties a bucket and causes the ratio of used buckets to -+ table size to become smaller than the shrink threshold (a number between -+ 0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a -+ number greater than the shrink threshold but smaller than 1.0). The shrink -+ threshold and factor default to 0.0 and 1.0, meaning that the table never -+ shrinks. */ -+#define DEFAULT_SHRINK_THRESHOLD 0.0 -+#define DEFAULT_SHRINK_FACTOR 1.0 -+ -+/* Use this to initialize or reset a TUNING structure to -+ some sensible values. */ -+static const Hash_tuning default_tuning = -+ { -+ DEFAULT_SHRINK_THRESHOLD, -+ DEFAULT_SHRINK_FACTOR, -+ DEFAULT_GROWTH_THRESHOLD, -+ DEFAULT_GROWTH_FACTOR, -+ false -+ }; -+ -+/* Information and lookup. */ -+ -+/* The following few functions provide information about the overall hash -+ table organization: the number of entries, number of buckets and maximum -+ length of buckets. */ -+ -+/* Return the number of buckets in the hash table. The table size, the total -+ number of buckets (used plus unused), or the maximum number of slots, are -+ the same quantity. */ -+ -+unsigned -+hash_get_n_buckets (const Hash_table *table) -+{ -+ return table->n_buckets; -+} -+ -+/* Return the number of slots in use (non-empty buckets). */ -+ -+unsigned -+hash_get_n_buckets_used (const Hash_table *table) -+{ -+ return table->n_buckets_used; -+} -+ -+/* Return the number of active entries. */ -+ -+unsigned -+hash_get_n_entries (const Hash_table *table) -+{ -+ return table->n_entries; -+} -+ -+/* Return the length of the longest chain (bucket). */ -+ -+unsigned -+hash_get_max_bucket_length (const Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ unsigned max_bucket_length = 0; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ struct hash_entry *cursor = bucket; -+ unsigned bucket_length = 1; -+ -+ while (cursor = cursor->next, cursor) -+ bucket_length++; -+ -+ if (bucket_length > max_bucket_length) -+ max_bucket_length = bucket_length; -+ } -+ } -+ -+ return max_bucket_length; -+} -+ -+/* Do a mild validation of a hash table, by traversing it and checking two -+ statistics. */ -+ -+bool -+hash_table_ok (const Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ unsigned n_buckets_used = 0; -+ unsigned n_entries = 0; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ struct hash_entry *cursor = bucket; -+ -+ /* Count bucket head. */ -+ n_buckets_used++; -+ n_entries++; -+ -+ /* Count bucket overflow. */ -+ while (cursor = cursor->next, cursor) -+ n_entries++; -+ } -+ } -+ -+ if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries) -+ return true; -+ -+ return false; -+} -+ -+void -+hash_print_statistics (const Hash_table *table, FILE *stream) -+{ -+ unsigned n_entries = hash_get_n_entries (table); -+ unsigned n_buckets = hash_get_n_buckets (table); -+ unsigned n_buckets_used = hash_get_n_buckets_used (table); -+ unsigned max_bucket_length = hash_get_max_bucket_length (table); -+ -+ fprintf (stream, "# entries: %u\n", n_entries); -+ fprintf (stream, "# buckets: %u\n", n_buckets); -+ fprintf (stream, "# buckets used: %u (%.2f%%)\n", n_buckets_used, -+ (100.0 * n_buckets_used) / n_buckets); -+ fprintf (stream, "max bucket length: %u\n", max_bucket_length); -+} -+ -+/* If ENTRY matches an entry already in the hash table, return the -+ entry from the table. Otherwise, return NULL. */ -+ -+void * -+hash_lookup (const Hash_table *table, const void *entry) -+{ -+ struct hash_entry *bucket -+ = table->bucket + table->hasher (entry, table->n_buckets); -+ struct hash_entry *cursor; -+ -+ if (! (bucket < table->bucket_limit)) -+ abort (); -+ -+ if (bucket->data == NULL) -+ return NULL; -+ -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ if (table->comparator (entry, cursor->data)) -+ return cursor->data; -+ -+ return NULL; -+} -+ -+/* Walking. */ -+ -+/* The functions in this page traverse the hash table and process the -+ contained entries. For the traversal to work properly, the hash table -+ should not be resized nor modified while any particular entry is being -+ processed. In particular, entries should not be added or removed. */ -+ -+/* Return the first data in the table, or NULL if the table is empty. */ -+ -+void * -+hash_get_first (const Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ -+ if (table->n_entries == 0) -+ return NULL; -+ -+ for (bucket = table->bucket; ; bucket++) -+ if (! (bucket < table->bucket_limit)) -+ abort (); -+ else if (bucket->data) -+ return bucket->data; -+} -+ -+/* Return the user data for the entry following ENTRY, where ENTRY has been -+ returned by a previous call to either `hash_get_first' or `hash_get_next'. -+ Return NULL if there are no more entries. */ -+ -+void * -+hash_get_next (const Hash_table *table, const void *entry) -+{ -+ struct hash_entry *bucket -+ = table->bucket + table->hasher (entry, table->n_buckets); -+ struct hash_entry *cursor; -+ -+ if (! (bucket < table->bucket_limit)) -+ abort (); -+ -+ /* Find next entry in the same bucket. */ -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ if (cursor->data == entry && cursor->next) -+ return cursor->next->data; -+ -+ /* Find first entry in any subsequent bucket. */ -+ while (++bucket < table->bucket_limit) -+ if (bucket->data) -+ return bucket->data; -+ -+ /* None found. */ -+ return NULL; -+} -+ -+/* Fill BUFFER with pointers to active user entries in the hash table, then -+ return the number of pointers copied. Do not copy more than BUFFER_SIZE -+ pointers. */ -+ -+unsigned -+hash_get_entries (const Hash_table *table, void **buffer, -+ unsigned buffer_size) -+{ -+ unsigned counter = 0; -+ struct hash_entry *bucket; -+ struct hash_entry *cursor; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ { -+ if (counter >= buffer_size) -+ return counter; -+ buffer[counter++] = cursor->data; -+ } -+ } -+ } -+ -+ return counter; -+} -+ -+/* Call a PROCESSOR function for each entry of a hash table, and return the -+ number of entries for which the processor function returned success. A -+ pointer to some PROCESSOR_DATA which will be made available to each call to -+ the processor function. The PROCESSOR accepts two arguments: the first is -+ the user entry being walked into, the second is the value of PROCESSOR_DATA -+ as received. The walking continue for as long as the PROCESSOR function -+ returns nonzero. When it returns zero, the walking is interrupted. */ -+ -+unsigned -+hash_do_for_each (const Hash_table *table, Hash_processor processor, -+ void *processor_data) -+{ -+ unsigned counter = 0; -+ struct hash_entry *bucket; -+ struct hash_entry *cursor; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ { -+ if (!(*processor) (cursor->data, processor_data)) -+ return counter; -+ counter++; -+ } -+ } -+ } -+ -+ return counter; -+} -+ -+/* Allocation and clean-up. */ -+ -+/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1. -+ This is a convenience routine for constructing other hashing functions. */ -+ -+#if USE_DIFF_HASH -+ -+/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see -+ B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm, -+ Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash -+ algorithms tend to be domain-specific, so what's good for [diffutils'] io.c -+ may not be good for your application." */ -+ -+unsigned -+hash_string (const char *string, unsigned n_buckets) -+{ -+# define ROTATE_LEFT(Value, Shift) \ -+ ((Value) << (Shift) | (Value) >> ((sizeof (unsigned) * CHAR_BIT) - (Shift))) -+# define HASH_ONE_CHAR(Value, Byte) \ -+ ((Byte) + ROTATE_LEFT (Value, 7)) -+ -+ unsigned value = 0; -+ -+ for (; *string; string++) -+ value = HASH_ONE_CHAR (value, *(const unsigned char *) string); -+ return value % n_buckets; -+ -+# undef ROTATE_LEFT -+# undef HASH_ONE_CHAR -+} -+ -+#else /* not USE_DIFF_HASH */ -+ -+/* This one comes from `recode', and performs a bit better than the above as -+ per a few experiments. It is inspired from a hashing routine found in the -+ very old Cyber `snoop', itself written in typical Greg Mansfield style. -+ (By the way, what happened to this excellent man? Is he still alive?) */ -+ -+unsigned -+hash_string (const char *string, unsigned n_buckets) -+{ -+ unsigned value = 0; -+ -+ while (*string) -+ value = ((value * 31 + (int) *(const unsigned char *) string++) -+ % n_buckets); -+ return value; -+} -+ -+#endif /* not USE_DIFF_HASH */ -+ -+/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd -+ number at least equal to 11. */ -+ -+static bool -+is_prime (unsigned long candidate) -+{ -+ unsigned long divisor = 3; -+ unsigned long square = divisor * divisor; -+ -+ while (square < candidate && (candidate % divisor)) -+ { -+ divisor++; -+ square += 4 * divisor; -+ divisor++; -+ } -+ -+ return (candidate % divisor ? true : false); -+} -+ -+/* Round a given CANDIDATE number up to the nearest prime, and return that -+ prime. Primes lower than 10 are merely skipped. */ -+ -+static unsigned long -+next_prime (unsigned long candidate) -+{ -+ /* Skip small primes. */ -+ if (candidate < 10) -+ candidate = 10; -+ -+ /* Make it definitely odd. */ -+ candidate |= 1; -+ -+ while (!is_prime (candidate)) -+ candidate += 2; -+ -+ return candidate; -+} -+ -+void -+hash_reset_tuning (Hash_tuning *tuning) -+{ -+ *tuning = default_tuning; -+} -+ -+/* For the given hash TABLE, check the user supplied tuning structure for -+ reasonable values, and return true if there is no gross error with it. -+ Otherwise, definitively reset the TUNING field to some acceptable default -+ in the hash table (that is, the user loses the right of further modifying -+ tuning arguments), and return false. */ -+ -+static bool -+check_tuning (Hash_table *table) -+{ -+ const Hash_tuning *tuning = table->tuning; -+ -+ if (tuning->growth_threshold > 0.0 -+ && tuning->growth_threshold < 1.0 -+ && tuning->growth_factor > 1.0 -+ && tuning->shrink_threshold >= 0.0 -+ && tuning->shrink_threshold < 1.0 -+ && tuning->shrink_factor > tuning->shrink_threshold -+ && tuning->shrink_factor <= 1.0 -+ && tuning->shrink_threshold < tuning->growth_threshold) -+ return true; -+ -+ table->tuning = &default_tuning; -+ return false; -+} -+ -+/* Allocate and return a new hash table, or NULL upon failure. The initial -+ number of buckets is automatically selected so as to _guarantee_ that you -+ may insert at least CANDIDATE different user entries before any growth of -+ the hash table size occurs. So, if have a reasonably tight a-priori upper -+ bound on the number of entries you intend to insert in the hash table, you -+ may save some table memory and insertion time, by specifying it here. If -+ the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE -+ argument has its meaning changed to the wanted number of buckets. -+ -+ TUNING points to a structure of user-supplied values, in case some fine -+ tuning is wanted over the default behavior of the hasher. If TUNING is -+ NULL, the default tuning parameters are used instead. -+ -+ The user-supplied HASHER function should be provided. It accepts two -+ arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a -+ slot number for that entry which should be in the range 0..TABLE_SIZE-1. -+ This slot number is then returned. -+ -+ The user-supplied COMPARATOR function should be provided. It accepts two -+ arguments pointing to user data, it then returns true for a pair of entries -+ that compare equal, or false otherwise. This function is internally called -+ on entries which are already known to hash to the same bucket index. -+ -+ The user-supplied DATA_FREER function, when not NULL, may be later called -+ with the user data as an argument, just before the entry containing the -+ data gets freed. This happens from within `hash_free' or `hash_clear'. -+ You should specify this function only if you want these functions to free -+ all of your `data' data. This is typically the case when your data is -+ simply an auxiliary struct that you have malloc'd to aggregate several -+ values. */ -+ -+Hash_table * -+hash_initialize (unsigned candidate, const Hash_tuning *tuning, -+ Hash_hasher hasher, Hash_comparator comparator, -+ Hash_data_freer data_freer) -+{ -+ Hash_table *table; -+ struct hash_entry *bucket; -+ -+ if (hasher == NULL || comparator == NULL) -+ return NULL; -+ -+ table = (Hash_table *) malloc (sizeof (Hash_table)); -+ if (table == NULL) -+ return NULL; -+ -+ if (!tuning) -+ tuning = &default_tuning; -+ table->tuning = tuning; -+ if (!check_tuning (table)) -+ { -+ /* Fail if the tuning options are invalid. This is the only occasion -+ when the user gets some feedback about it. Once the table is created, -+ if the user provides invalid tuning options, we silently revert to -+ using the defaults, and ignore further request to change the tuning -+ options. */ -+ free (table); -+ return NULL; -+ } -+ -+ table->n_buckets -+ = next_prime (tuning->is_n_buckets ? candidate -+ : (unsigned) (candidate / tuning->growth_threshold)); -+ -+ table->bucket = (struct hash_entry *) -+ malloc (table->n_buckets * sizeof (struct hash_entry)); -+ if (table->bucket == NULL) -+ { -+ free (table); -+ return NULL; -+ } -+ table->bucket_limit = table->bucket + table->n_buckets; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ bucket->data = NULL; -+ bucket->next = NULL; -+ } -+ table->n_buckets_used = 0; -+ table->n_entries = 0; -+ -+ table->hasher = hasher; -+ table->comparator = comparator; -+ table->data_freer = data_freer; -+ -+ table->free_entry_list = NULL; -+#if USE_OBSTACK -+ obstack_init (&table->entry_stack); -+#endif -+ return table; -+} -+ -+/* Make all buckets empty, placing any chained entries on the free list. -+ Apply the user-specified function data_freer (if any) to the datas of any -+ affected entries. */ -+ -+void -+hash_clear (Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ struct hash_entry *cursor; -+ struct hash_entry *next; -+ -+ /* Free the bucket overflow. */ -+ for (cursor = bucket->next; cursor; cursor = next) -+ { -+ if (table->data_freer) -+ (*table->data_freer) (cursor->data); -+ cursor->data = NULL; -+ -+ next = cursor->next; -+ /* Relinking is done one entry at a time, as it is to be expected -+ that overflows are either rare or short. */ -+ cursor->next = table->free_entry_list; -+ table->free_entry_list = cursor; -+ } -+ -+ /* Free the bucket head. */ -+ if (table->data_freer) -+ (*table->data_freer) (bucket->data); -+ bucket->data = NULL; -+ bucket->next = NULL; -+ } -+ } -+ -+ table->n_buckets_used = 0; -+ table->n_entries = 0; -+} -+ -+/* Reclaim all storage associated with a hash table. If a data_freer -+ function has been supplied by the user when the hash table was created, -+ this function applies it to the data of each entry before freeing that -+ entry. */ -+ -+void -+hash_free (Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ struct hash_entry *cursor; -+ struct hash_entry *next; -+ -+ /* Call the user data_freer function. */ -+ if (table->data_freer && table->n_entries) -+ { -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ if (bucket->data) -+ { -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ { -+ (*table->data_freer) (cursor->data); -+ } -+ } -+ } -+ } -+ -+#if USE_OBSTACK -+ -+ obstack_free (&table->entry_stack, NULL); -+ -+#else -+ -+ /* Free all bucket overflowed entries. */ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ for (cursor = bucket->next; cursor; cursor = next) -+ { -+ next = cursor->next; -+ free (cursor); -+ } -+ } -+ -+ /* Also reclaim the internal list of previously freed entries. */ -+ for (cursor = table->free_entry_list; cursor; cursor = next) -+ { -+ next = cursor->next; -+ free (cursor); -+ } -+ -+#endif -+ -+ /* Free the remainder of the hash table structure. */ -+ free (table->bucket); -+ free (table); -+} -+ -+/* Insertion and deletion. */ -+ -+/* Get a new hash entry for a bucket overflow, possibly by reclying a -+ previously freed one. If this is not possible, allocate a new one. */ -+ -+static struct hash_entry * -+allocate_entry (Hash_table *table) -+{ -+ struct hash_entry *new; -+ -+ if (table->free_entry_list) -+ { -+ new = table->free_entry_list; -+ table->free_entry_list = new->next; -+ } -+ else -+ { -+#if USE_OBSTACK -+ new = (struct hash_entry *) -+ obstack_alloc (&table->entry_stack, sizeof (struct hash_entry)); -+#else -+ new = (struct hash_entry *) malloc (sizeof (struct hash_entry)); -+#endif -+ } -+ -+ return new; -+} -+ -+/* Free a hash entry which was part of some bucket overflow, -+ saving it for later recycling. */ -+ -+static void -+free_entry (Hash_table *table, struct hash_entry *entry) -+{ -+ entry->data = NULL; -+ entry->next = table->free_entry_list; -+ table->free_entry_list = entry; -+} -+ -+/* This private function is used to help with insertion and deletion. When -+ ENTRY matches an entry in the table, return a pointer to the corresponding -+ user data and set *BUCKET_HEAD to the head of the selected bucket. -+ Otherwise, return NULL. When DELETE is true and ENTRY matches an entry in -+ the table, unlink the matching entry. */ -+ -+static void * -+hash_find_entry (Hash_table *table, const void *entry, -+ struct hash_entry **bucket_head, bool delete) -+{ -+ struct hash_entry *bucket -+ = table->bucket + table->hasher (entry, table->n_buckets); -+ struct hash_entry *cursor; -+ -+ if (! (bucket < table->bucket_limit)) -+ abort (); -+ -+ *bucket_head = bucket; -+ -+ /* Test for empty bucket. */ -+ if (bucket->data == NULL) -+ return NULL; -+ -+ /* See if the entry is the first in the bucket. */ -+ if ((*table->comparator) (entry, bucket->data)) -+ { -+ void *data = bucket->data; -+ -+ if (delete) -+ { -+ if (bucket->next) -+ { -+ struct hash_entry *next = bucket->next; -+ -+ /* Bump the first overflow entry into the bucket head, then save -+ the previous first overflow entry for later recycling. */ -+ *bucket = *next; -+ free_entry (table, next); -+ } -+ else -+ { -+ bucket->data = NULL; -+ } -+ } -+ -+ return data; -+ } -+ -+ /* Scan the bucket overflow. */ -+ for (cursor = bucket; cursor->next; cursor = cursor->next) -+ { -+ if ((*table->comparator) (entry, cursor->next->data)) -+ { -+ void *data = cursor->next->data; -+ -+ if (delete) -+ { -+ struct hash_entry *next = cursor->next; -+ -+ /* Unlink the entry to delete, then save the freed entry for later -+ recycling. */ -+ cursor->next = next->next; -+ free_entry (table, next); -+ } -+ -+ return data; -+ } -+ } -+ -+ /* No entry found. */ -+ return NULL; -+} -+ -+/* For an already existing hash table, change the number of buckets through -+ specifying CANDIDATE. The contents of the hash table are preserved. The -+ new number of buckets is automatically selected so as to _guarantee_ that -+ the table may receive at least CANDIDATE different user entries, including -+ those already in the table, before any other growth of the hash table size -+ occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the -+ exact number of buckets desired. */ -+ -+bool -+hash_rehash (Hash_table *table, unsigned candidate) -+{ -+ Hash_table *new_table; -+ struct hash_entry *bucket; -+ struct hash_entry *cursor; -+ struct hash_entry *next; -+ -+ new_table = hash_initialize (candidate, table->tuning, table->hasher, -+ table->comparator, table->data_freer); -+ if (new_table == NULL) -+ return false; -+ -+ /* Merely reuse the extra old space into the new table. */ -+#if USE_OBSTACK -+ obstack_free (&new_table->entry_stack, NULL); -+ new_table->entry_stack = table->entry_stack; -+#endif -+ new_table->free_entry_list = table->free_entry_list; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ if (bucket->data) -+ for (cursor = bucket; cursor; cursor = next) -+ { -+ void *data = cursor->data; -+ struct hash_entry *new_bucket -+ = (new_table->bucket -+ + new_table->hasher (data, new_table->n_buckets)); -+ -+ if (! (new_bucket < new_table->bucket_limit)) -+ abort (); -+ -+ next = cursor->next; -+ -+ if (new_bucket->data) -+ { -+ if (cursor == bucket) -+ { -+ /* Allocate or recycle an entry, when moving from a bucket -+ header into a bucket overflow. */ -+ struct hash_entry *new_entry = allocate_entry (new_table); -+ -+ if (new_entry == NULL) -+ return false; -+ -+ new_entry->data = data; -+ new_entry->next = new_bucket->next; -+ new_bucket->next = new_entry; -+ } -+ else -+ { -+ /* Merely relink an existing entry, when moving from a -+ bucket overflow into a bucket overflow. */ -+ cursor->next = new_bucket->next; -+ new_bucket->next = cursor; -+ } -+ } -+ else -+ { -+ /* Free an existing entry, when moving from a bucket -+ overflow into a bucket header. Also take care of the -+ simple case of moving from a bucket header into a bucket -+ header. */ -+ new_bucket->data = data; -+ new_table->n_buckets_used++; -+ if (cursor != bucket) -+ free_entry (new_table, cursor); -+ } -+ } -+ -+ free (table->bucket); -+ table->bucket = new_table->bucket; -+ table->bucket_limit = new_table->bucket_limit; -+ table->n_buckets = new_table->n_buckets; -+ table->n_buckets_used = new_table->n_buckets_used; -+ table->free_entry_list = new_table->free_entry_list; -+ /* table->n_entries already holds its value. */ -+#if USE_OBSTACK -+ table->entry_stack = new_table->entry_stack; -+#endif -+ free (new_table); -+ -+ return true; -+} -+ -+/* If ENTRY matches an entry already in the hash table, return the pointer -+ to the entry from the table. Otherwise, insert ENTRY and return ENTRY. -+ Return NULL if the storage required for insertion cannot be allocated. */ -+ -+void * -+hash_insert (Hash_table *table, const void *entry) -+{ -+ void *data; -+ struct hash_entry *bucket; -+ -+ /* The caller cannot insert a NULL entry. */ -+ if (! entry) -+ abort (); -+ -+ /* If there's a matching entry already in the table, return that. */ -+ if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL) -+ return data; -+ -+ /* ENTRY is not matched, it should be inserted. */ -+ -+ if (bucket->data) -+ { -+ struct hash_entry *new_entry = allocate_entry (table); -+ -+ if (new_entry == NULL) -+ return NULL; -+ -+ /* Add ENTRY in the overflow of the bucket. */ -+ -+ new_entry->data = (void *) entry; -+ new_entry->next = bucket->next; -+ bucket->next = new_entry; -+ table->n_entries++; -+ return (void *) entry; -+ } -+ -+ /* Add ENTRY right in the bucket head. */ -+ -+ bucket->data = (void *) entry; -+ table->n_entries++; -+ table->n_buckets_used++; -+ -+ /* If the growth threshold of the buckets in use has been reached, increase -+ the table size and rehash. There's no point in checking the number of -+ entries: if the hashing function is ill-conditioned, rehashing is not -+ likely to improve it. */ -+ -+ if (table->n_buckets_used -+ > table->tuning->growth_threshold * table->n_buckets) -+ { -+ /* Check more fully, before starting real work. If tuning arguments -+ became invalid, the second check will rely on proper defaults. */ -+ check_tuning (table); -+ if (table->n_buckets_used -+ > table->tuning->growth_threshold * table->n_buckets) -+ { -+ const Hash_tuning *tuning = table->tuning; -+ unsigned candidate -+ = (unsigned) (tuning->is_n_buckets -+ ? (table->n_buckets * tuning->growth_factor) -+ : (table->n_buckets * tuning->growth_factor -+ * tuning->growth_threshold)); -+ -+ /* If the rehash fails, arrange to return NULL. */ -+ if (!hash_rehash (table, candidate)) -+ entry = NULL; -+ } -+ } -+ -+ return (void *) entry; -+} -+ -+/* If ENTRY is already in the table, remove it and return the just-deleted -+ data (the user may want to deallocate its storage). If ENTRY is not in the -+ table, don't modify the table and return NULL. */ -+ -+void * -+hash_delete (Hash_table *table, const void *entry) -+{ -+ void *data; -+ struct hash_entry *bucket; -+ -+ data = hash_find_entry (table, entry, &bucket, true); -+ if (!data) -+ return NULL; -+ -+ table->n_entries--; -+ if (!bucket->data) -+ { -+ table->n_buckets_used--; -+ -+ /* If the shrink threshold of the buckets in use has been reached, -+ rehash into a smaller table. */ -+ -+ if (table->n_buckets_used -+ < table->tuning->shrink_threshold * table->n_buckets) -+ { -+ /* Check more fully, before starting real work. If tuning arguments -+ became invalid, the second check will rely on proper defaults. */ -+ check_tuning (table); -+ if (table->n_buckets_used -+ < table->tuning->shrink_threshold * table->n_buckets) -+ { -+ const Hash_tuning *tuning = table->tuning; -+ unsigned candidate -+ = (unsigned) (tuning->is_n_buckets -+ ? table->n_buckets * tuning->shrink_factor -+ : (table->n_buckets * tuning->shrink_factor -+ * tuning->growth_threshold)); -+ -+ hash_rehash (table, candidate); -+ } -+ } -+ } -+ -+ return data; -+} -+ -+/* Testing. */ -+ -+#if TESTING -+ -+void -+hash_print (const Hash_table *table) -+{ -+ struct hash_entry *bucket; -+ -+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++) -+ { -+ struct hash_entry *cursor; -+ -+ if (bucket) -+ printf ("%d:\n", bucket - table->bucket); -+ -+ for (cursor = bucket; cursor; cursor = cursor->next) -+ { -+ char *s = (char *) cursor->data; -+ /* FIXME */ -+ if (s) -+ printf (" %s\n", s); -+ } -+ } -+} -+ -+#endif /* TESTING */ -Index: patch-2.5.9/hash.h -=================================================================== ---- /dev/null -+++ patch-2.5.9/hash.h -@@ -0,0 +1,93 @@ -+/* hash - hashing table processing. -+ Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. -+ Written by Jim Meyering , 1998. -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2, or (at your option) -+ any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software Foundation, -+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -+ -+/* A generic hash table package. */ -+ -+/* Make sure USE_OBSTACK is defined to 1 if you want the allocator to use -+ obstacks instead of malloc, and recompile `hash.c' with same setting. */ -+ -+#ifndef HASH_H_ -+# define HASH_H_ -+ -+# ifndef PARAMS -+# if PROTOTYPES || __STDC__ -+# define PARAMS(Args) Args -+# else -+# define PARAMS(Args) () -+# endif -+# endif -+ -+typedef unsigned (*Hash_hasher) PARAMS ((const void *, unsigned)); -+typedef bool (*Hash_comparator) PARAMS ((const void *, const void *)); -+typedef void (*Hash_data_freer) PARAMS ((void *)); -+typedef bool (*Hash_processor) PARAMS ((void *, void *)); -+ -+struct hash_entry -+ { -+ void *data; -+ struct hash_entry *next; -+ }; -+ -+struct hash_tuning -+ { -+ /* This structure is mainly used for `hash_initialize', see the block -+ documentation of `hash_reset_tuning' for more complete comments. */ -+ -+ float shrink_threshold; /* ratio of used buckets to trigger a shrink */ -+ float shrink_factor; /* ratio of new smaller size to original size */ -+ float growth_threshold; /* ratio of used buckets to trigger a growth */ -+ float growth_factor; /* ratio of new bigger size to original size */ -+ bool is_n_buckets; /* if CANDIDATE really means table size */ -+ }; -+ -+typedef struct hash_tuning Hash_tuning; -+ -+struct hash_table; -+ -+typedef struct hash_table Hash_table; -+ -+/* Information and lookup. */ -+unsigned hash_get_n_buckets PARAMS ((const Hash_table *)); -+unsigned hash_get_n_buckets_used PARAMS ((const Hash_table *)); -+unsigned hash_get_n_entries PARAMS ((const Hash_table *)); -+unsigned hash_get_max_bucket_length PARAMS ((const Hash_table *)); -+bool hash_table_ok PARAMS ((const Hash_table *)); -+void hash_print_statistics PARAMS ((const Hash_table *, FILE *)); -+void *hash_lookup PARAMS ((const Hash_table *, const void *)); -+ -+/* Walking. */ -+void *hash_get_first PARAMS ((const Hash_table *)); -+void *hash_get_next PARAMS ((const Hash_table *, const void *)); -+unsigned hash_get_entries PARAMS ((const Hash_table *, void **, unsigned)); -+unsigned hash_do_for_each PARAMS ((const Hash_table *, Hash_processor, void *)); -+ -+/* Allocation and clean-up. */ -+unsigned hash_string PARAMS ((const char *, unsigned)); -+void hash_reset_tuning PARAMS ((Hash_tuning *)); -+Hash_table *hash_initialize PARAMS ((unsigned, const Hash_tuning *, -+ Hash_hasher, Hash_comparator, -+ Hash_data_freer)); -+void hash_clear PARAMS ((Hash_table *)); -+void hash_free PARAMS ((Hash_table *)); -+ -+/* Insertion and deletion. */ -+bool hash_rehash PARAMS ((Hash_table *, unsigned)); -+void *hash_insert PARAMS ((Hash_table *, const void *)); -+void *hash_delete PARAMS ((Hash_table *, const void *)); -+ -+#endif -Index: patch-2.5.9/m4/nanosecond_stat.m4 -=================================================================== ---- /dev/null -+++ patch-2.5.9/m4/nanosecond_stat.m4 -@@ -0,0 +1,35 @@ -+AC_DEFUN([ag_CHECK_NANOSECOND_STAT], -+ [AC_CACHE_CHECK([for nanosecond timestamps in struct stat], -+ [ac_cv_stat_nsec], -+ [AC_TRY_COMPILE( -+ [ -+ #include -+ #include -+ #include -+ struct stat st; -+ ], -+ [ return st.st_atimensec + st.st_mtimensec + st.st_ctimensec; ], -+ [ac_cv_stat_nsec=yes], -+ [ac_cv_stat_nsec=no]) -+ ]) -+ if test $ac_cv_stat_nsec = yes; then -+ AC_DEFINE(HAVE_STAT_NSEC, 1, [Define to 1 if struct stat has nanosecond timestamps.]) -+ fi -+ -+ AC_CACHE_CHECK([for nanosecond timestamps in struct stat], -+ [ac_cv_stat_timeval], -+ [AC_TRY_COMPILE( -+ [ -+ #include -+ #include -+ #include -+ #include -+ struct stat st; -+ ], -+ [ return st.st_atim.tv_nsec + st.st_mtim.tv_nsec + st.st_ctim.tv_nsec; ], -+ [ac_cv_stat_timeval=yes], -+ [ac_cv_stat_timeval=no]) -+ ]) -+ if test $ac_cv_stat_timeval = yes; then -+ AC_DEFINE(HAVE_STAT_TIMEVAL, 1, [Define to 1 if struct stat comtains struct timeval's.]) -+ fi]) -Index: patch-2.5.9/remember-tests/hardlinks.test -=================================================================== ---- /dev/null -+++ patch-2.5.9/remember-tests/hardlinks.test -@@ -0,0 +1,31 @@ -+Test case with hard links between source files. -+ -+$ cat > f -+< one -+ -+$ ln f g -+$ cat > fg.patch -+<--- f.orig -+<+++ f -+<@@ -2 +2 @@ -+<-one -+<+two -+<--- g.orig -+<+++ g -+<@@ -2 +2 @@ -+<-one -+<+two -+ -+$ ../patch -p0 < fg.patch -+> patching file f -+> Hunk #1 succeeded at 1 (offset -1 lines). -+> patching file g -+> Hunk #1 succeeded at 1 (offset -1 lines). -+ -+$ cat f.orig -+> one -+ -+$ cat g.orig -+> one -+ -+$ rm f f.orig g g.orig fg.patch -Index: patch-2.5.9/remember-tests/multi-modify.test -=================================================================== ---- /dev/null -+++ patch-2.5.9/remember-tests/multi-modify.test -@@ -0,0 +1,35 @@ -+A patch that modifies the same file three times. An unpatched version of -+GNU patch will destroy the backup file. -+ -+$ cat > f -+< one -+ -+$ cat > f.patch -+<--- f.orig -+<+++ f -+<@@ -2 +2 @@ -+<-one -+<+two -+<--- f.orig -+<+++ f -+<@@ -2 +2 @@ -+<-two -+<+three -+<--- f.orig -+<+++ f -+<@@ -2 +2 @@ -+<-three -+<+four -+ -+$ ../patch -p0 < f.patch -+> patching file f -+> Hunk #1 succeeded at 1 (offset -1 lines). -+> patching file f -+> Hunk #1 succeeded at 1 (offset -1 lines). -+> patching file f -+> Hunk #1 succeeded at 1 (offset -1 lines). -+ -+$ cat f.orig -+> one -+ -+$ rm f f.orig f.patch -Index: patch-2.5.9/remember-tests/permission.test -=================================================================== ---- /dev/null -+++ patch-2.5.9/remember-tests/permission.test -@@ -0,0 +1,17 @@ -+This test case failed with a Permission denied error with a previous -+version of this patch. -+ -+$ echo 1 > f -+$ echo 2 > f.new -+$ diff -Nu f f.new > f.diff -+$ mv f.new f -+$ echo 3 > f.new -+$ diff -Nu f f.new >> f.diff -+$ rm f.new -+$ echo 1 > f -+$ chmod a=r f -+$ ../patch -p0 --backup < f.diff -+> patching file f -+> patching file f -+ -+$ rm -f f f.diff f.orig f.rej diff --git a/trailing-cr-fix.diff b/trailing-cr-fix.diff deleted file mode 100644 index 1caeeb5..0000000 --- a/trailing-cr-fix.diff +++ /dev/null @@ -1,61 +0,0 @@ -From: "Paul Eggert" -Date: Wed, 2 Jul 2003 15:22:09 -0700 -Subject: Re: patch bug with carriage returns - - > From: Andreas Gruenbacher - > Date: Mon, 30 Jun 2003 13:43:33 +0200 - - > unified diffs with CRLF line endings are not recognized correctly - > anymore in 2.5.9. Here is a fix. - - Thanks for the bug report. Unfortunately that fix doesn't handle the - case correctly where a Unix file contains a trailing CR in a header - line that is output by "diff -p" (trailing CR and all). - - How about the following patch instead? - ---- patch-2.5.9.orig/pch.c 2003/05/20 14:03:17 1.44 -+++ patch-2.5.9/pch.c 2003/07/02 22:19:21 1.45 -@@ -1,6 +1,6 @@ - /* reading patches */ - --/* $Id: pch.c,v 1.44 2003/05/20 14:03:17 eggert Exp $ */ -+/* $Id: pch.c,v 1.45 2003/07/02 22:19:21 eggert Exp $ */ - - /* Copyright (C) 1986, 1987, 1988 Larry Wall - -@@ -366,10 +366,16 @@ intuit_diff_type (void) - if (!stars_last_line && strnEQ(s, "*** ", 4)) - name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); - else if (strnEQ(s, "+++ ", 4)) -+ { - /* Swap with NEW below. */ - name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); -+ p_strip_trailing_cr = strip_trailing_cr; -+ } - else if (strnEQ(s, "Index:", 6)) -+ { - name[INDEX] = fetchname (s+6, strippath, (time_t *) 0); -+ p_strip_trailing_cr = strip_trailing_cr; -+ } - else if (strnEQ(s, "Prereq:", 7)) { - for (t = s + 7; ISSPACE ((unsigned char) *t); t++) - continue; -@@ -409,6 +415,7 @@ intuit_diff_type (void) - p_timestamp[NEW] = timestamp; - p_rfc934_nesting = (t - s) >> 1; - } -+ p_strip_trailing_cr = strip_trailing_cr; - } - } - if ((diff_type == NO_DIFF || diff_type == ED_DIFF) && -#--- patch-2.5.9.orig/pch.c 2003-06-30 13:28:39.000000000 +0200 -#+++ patch-2.5.9/pch.c 2003-06-30 13:28:03.000000000 +0200 -#@@ -440,6 +440,7 @@ -# if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2])) -# p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; -# p_indent = indent; -#+ p_strip_trailing_cr = strip_trailing_cr; -# p_start = this_line; -# p_sline = p_input_line; -# retval = UNI_DIFF; diff --git a/unified-reject-files.diff b/unified-reject-files.diff deleted file mode 100644 index 3fd31fc..0000000 --- a/unified-reject-files.diff +++ /dev/null @@ -1,295 +0,0 @@ -Generate unified diff style reject files. - ---- - patch.c | 104 +++++++++++++++++++++++++++++++++++++-- - patch.man | 3 + - tests/unified-reject-files.shrun | 104 +++++++++++++++++++++++++++++++++++++++ - 3 files changed, 208 insertions(+), 3 deletions(-) - -Index: b/patch.man -=================================================================== ---- a/patch.man -+++ b/patch.man -@@ -517,6 +517,9 @@ instead of the default - .B \&.rej - file. - .TP -+\fB\*=unified\-reject\-files\fP -+Produce unified reject files. The default is to produce context type reject files. -+.TP - \fB\-R\fP or \fB\*=reverse\fP - Assume that this patch was created with the old and new files swapped. - (Yes, I'm afraid that does happen occasionally, human nature being what it -Index: b/patch.c -=================================================================== ---- a/patch.c -+++ b/patch.c -@@ -66,8 +66,9 @@ static bool patch_match (LINENUM, LINENU - static bool similar (char const *, size_t, char const *, size_t); - static bool spew_output (struct outstate *); - static char const *make_temp (char); -+static void abort_hunk_context (void); -+static void abort_hunk_unified (void); - static int numeric_string (char const *, bool, char const *); --static void abort_hunk (void); - static void cleanup (void); - static void get_some_switches (void); - static void init_output (char const *, int, struct outstate *); -@@ -76,6 +77,8 @@ static void reinitialize_almost_everythi - static void remove_if_needed (char const *, int volatile *); - static void usage (FILE *, int) __attribute__((noreturn)); - -+static void (*abort_hunk) (void) = abort_hunk_context; -+ - static bool make_backups; - static bool backup_if_mismatch; - static char const *version_control; -@@ -522,6 +525,7 @@ static struct option const longopts[] = - {"no-backup-if-mismatch", no_argument, NULL, CHAR_MAX + 6}, - {"posix", no_argument, NULL, CHAR_MAX + 7}, - {"quoting-style", required_argument, NULL, CHAR_MAX + 8}, -+ {"unified-reject-files", no_argument, NULL, CHAR_MAX + 9}, - {NULL, no_argument, NULL, 0} - }; - -@@ -580,6 +584,7 @@ static char const *const option_help[] = - " --verbose Output extra information about the work being done.", - " --dry-run Do not actually change any files; just print what would happen.", - " --posix Conform to the POSIX standard.", -+" --unified-reject-files Create unified reject files.", - "", - " -d DIR --directory=DIR Change the working directory to DIR first.", - #if HAVE_SETMODE_DOS -@@ -779,6 +784,9 @@ get_some_switches (void) - (enum quoting_style) i); - } - break; -+ case CHAR_MAX + 9: -+ abort_hunk = abort_hunk_unified; -+ break; - default: - usage (stderr, 2); - } -@@ -930,7 +938,7 @@ locate_hunk (LINENUM fuzz) - /* We did not find the pattern, dump out the hunk so they can handle it. */ - - static void --abort_hunk (void) -+abort_hunk_context (void) - { - register LINENUM i; - register LINENUM pat_end = pch_end (); -@@ -979,13 +987,103 @@ abort_hunk (void) - pch_write_line (i, rejfp); - break; - default: -- fatal ("fatal internal error in abort_hunk"); -+ fatal ("fatal internal error in abort_hunk_context"); - } - if (ferror (rejfp)) - write_fatal (); - } - } - -+/* Produce unified reject files */ -+ -+static void -+print_unified(FILE *fp) -+{ -+ register LINENUM old = 1; -+ register LINENUM lastline = pch_ptrn_lines (); -+ register LINENUM new = lastline + 1; -+ register LINENUM pat_end = pch_end (); -+ -+ while (pch_char (new) == '=' || pch_char (new) == '\n') -+ new++; -+ -+ while (old <= lastline) -+ { -+ if (pch_char (old) == '-') -+ { -+ fputc ('-', fp); -+ pch_write_line (old++, fp); -+ } -+ else if (new > pat_end) -+ break; -+ else if (pch_char (new) == '+') -+ { -+ fputc ('+', fp); -+ pch_write_line (new++, fp); -+ } -+ else if (pch_char (new) != pch_char (old)) -+ { -+ char numbuf0[LINENUM_LENGTH_BOUND + 1]; -+ char numbuf1[LINENUM_LENGTH_BOUND + 1]; -+ if (debug & 1) -+ say ("oldchar = '%c', newchar = '%c'\n", -+ pch_char (old), pch_char (new)); -+ fatal ("Out-of-sync patch, lines %s,%s -- mangled text or " -+ "line numbers, maybe?", -+ format_linenum (numbuf0, pch_hunk_beg () + old), -+ format_linenum (numbuf1, pch_hunk_beg () + new)); -+ } -+ else if (pch_char (new) == '!') -+ { -+ do -+ { -+ fputc ('-', fp); -+ pch_write_line (old++, fp); -+ } -+ while (pch_char (old) == '!'); -+ do -+ { -+ fputc ('+', fp); -+ pch_write_line (new++, fp); -+ } -+ while (pch_char (new) == '!'); -+ } -+ else -+ { -+ assert (pch_char (new) == ' '); -+ fputc (' ', fp); -+ pch_write_line (new, fp); -+ old++; -+ new++; -+ } -+ } -+ while (pch_char (new) == '+' || pch_char (new) == ' ') -+ { -+ fputc ('+', fp); -+ pch_write_line (new++, fp); -+ } -+ assert (new > pat_end); -+} -+ -+static void -+abort_hunk_unified (void) -+{ -+ char rangebuf0[LINERANGE_LENGTH_BOUND + 1]; -+ char rangebuf1[LINERANGE_LENGTH_BOUND + 1]; -+ LINENUM oldfirst = pch_first () + last_offset; -+ LINENUM newfirst = pch_newfirst () + last_offset; -+ char const *c_function = pch_c_function (); -+ -+ fprintf (rejfp, "@@ -%s +%s @@%s\n", -+ format_startcount (rangebuf0, oldfirst, pch_ptrn_lines ()), -+ format_startcount (rangebuf1, newfirst, pch_repl_lines ()), -+ c_function ? c_function : ""); -+ print_unified (rejfp); -+ -+ if (ferror (rejfp)) -+ write_fatal (); -+} -+ - /* We found where to apply it (we hope), so do it. */ - - static bool -Index: b/tests/unified-reject-files.shrun -=================================================================== ---- /dev/null -+++ b/tests/unified-reject-files.shrun -@@ -0,0 +1,104 @@ -+$ PATCH=$(pwd)/patch -+$ tmpdir=$(mktemp -d) -+$ trap "cd /; rm -rf $tmpdir" EXIT -+$ cd $tmpdir -+$ cat > f.orig -+< a() { -+< 2 -+< 3 -+< -+< 5 -+< 6 -+< } -+ -+$ sed -e 's/5/5a/' f.orig > f -+$ diff -U0 -p \ -++ -L "f.orig 2009-02-07 14:49:02.000000000 +0100" \ -++ -L "f 2009-02-07 14:49:03.000000000 +0100" \ -++ f.orig f > f.diff -+ -+$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+Note: patch cannot deal with nanosecond timestamps :-( -+ -+$ cat f.rej -+> *************** a() { -+> *** 5 **** -+> - 5 -+> --- 5 ---- -+> + 5a -+ -+$ diff -U0 -p -L f.orig -L f f.orig f > f.diff -+$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+$ cat f.rej -+> @@ -5 +5 @@ a() { -+> -5 -+> +5a -+ -+$ $PATCH -f -F0 -s --no-backup-if-mismatch f < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+$ cat f.rej -+> *************** a() { -+> *** 5 **** -+> - 5 -+> --- 5 ---- -+> + 5a -+ -+$ $PATCH -f -F0 -s --no-backup-if-mismatch --unified-reject-files -R f.orig < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.orig.rej -+ -+$ cat f.orig.rej -+> @@ -5 +5 @@ a() { -+> -5a -+> +5 -+ -+$ diff -U2 -p -L f.orig -L f f.orig f > f.diff -+$ sed -e 's/5/5a/' -e 's/6/6x/' f.orig > f -+$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+$ cat f.rej -+> @@ -3,5 +3,5 @@ a() { -+> 3 -+> -+> -5 -+> +5a -+> 6 -+> } -+ -+$ $PATCH -F0 -s --no-backup-if-mismatch f < f.diff -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+$ cat f.rej -+> *************** a() { -+> *** 3,7 **** -+> 3 -+> -+> - 5 -+> 6 -+> } -+> --- 3,7 ---- -+> 3 -+> -+> + 5a -+> 6 -+> } -+ -+$ diff -Nu -p -L /dev/null -L f.orig /dev/null f.orig > f2.diff -+$ $PATCH -F0 -s --no-backup-if-mismatch --unified-reject-files f --set-utc < f2.diff -+> Patch attempted to create file f, which already exists. -+> 1 out of 1 hunk FAILED -- saving rejects to file f.rej -+ -+$ cat f.rej -+> @@ -0,0 +1,7 @@ -+> +a() { -+> +2 -+> +3 -+> + -+> +5 -+> +6 -+> +}