mirror of
https://https.git.savannah.gnu.org/git/patch.git
synced 2026-01-27 01:44:34 +00:00
Add unified reject format and the --reject-format=FORMAT option
This commit is contained in:
parent
4399677be9
commit
0a22c10196
12
ChangeLog
12
ChangeLog
@ -1,3 +1,15 @@
|
||||
2009-03-20 Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
* patch.c: New option --reject-format=FORMAT.
|
||||
(abort_hunk_context): Rename from abort_hunk().
|
||||
(abort_hunk_unified, abort_hunk, mangled_patch,
|
||||
print_unidiff_range): New functions.
|
||||
* patch.man: Document this.
|
||||
* pch.c, pch.h (pch_normalize): New function.
|
||||
* tests/reject-format: New test case.
|
||||
* Makefile.in (TESTS): Add test case.
|
||||
* tests/preserve-c-function-names: Update.
|
||||
|
||||
2009-03-19 Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
* Makefile.in (DISTFILES): Add the files from DISTFILES_M4,
|
||||
|
||||
@ -88,9 +88,9 @@ HDRS = argmatch.h backupfile.h common.h dirname.h \
|
||||
MISC = AUTHORS COPYING ChangeLog INSTALL Makefile.in NEWS README VERSION \
|
||||
aclocal.m4 config.hin configure configure.ac install-sh \
|
||||
mkinstalldirs patch.man stdbool_.h timespec.h
|
||||
TESTS = tests/corrupt-reject-files tests/no-newline-triggers-assert \
|
||||
tests/preserve-c-function-names \
|
||||
tests/remember-backup-files tests/crlf-handling
|
||||
TESTS = tests/corrupt-reject-files tests/crlf-handling \
|
||||
tests/no-newline-triggers-assert tests/preserve-c-function-names \
|
||||
tests/reject-format tests/remember-backup-files
|
||||
DISTFILES = $(MISC) $(SRCS) $(HDRS) $(M4FILES) $(TESTS) \
|
||||
pc/chdirsaf.c pc/djgpp/config.sed pc/djgpp/configure.bat \
|
||||
pc/djgpp/configure.sed pc/djgpp/README
|
||||
|
||||
8
NEWS
8
NEWS
@ -1,3 +1,11 @@
|
||||
Changes in version 2.6:
|
||||
|
||||
* If the input patch is in unified format, any .rej output is now
|
||||
in unified format as well. Formerly it was in context format.
|
||||
This can be overridden with --reject-format=FORMAT.
|
||||
* Changed lines in reject files in context format will now be indicated
|
||||
with '!' as per the definition of the format instead of '+' and '-'.
|
||||
|
||||
Changes in versions 2.5.8 and 2.5.9: bug fixes only.
|
||||
|
||||
Changes in version 2.5.7:
|
||||
|
||||
138
patch.c
138
patch.c
@ -68,7 +68,6 @@ static bool similar (char const *, size_t, char const *, size_t);
|
||||
static bool spew_output (struct outstate *, struct stat *);
|
||||
static char const *make_temp (char);
|
||||
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 *);
|
||||
@ -77,6 +76,11 @@ static void reinitialize_almost_everything (void);
|
||||
static void remove_if_needed (char const *, int volatile *);
|
||||
static void usage (FILE *, int) __attribute__((noreturn));
|
||||
|
||||
static void abort_hunk (void);
|
||||
static void abort_hunk_context (void);
|
||||
static void abort_hunk_unified (void);
|
||||
|
||||
static enum diff reject_format = NO_DIFF; /* automatic */
|
||||
static bool make_backups;
|
||||
static bool backup_if_mismatch;
|
||||
static char const *version_control;
|
||||
@ -527,6 +531,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},
|
||||
{"reject-format", required_argument, NULL, CHAR_MAX + 9},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
@ -587,6 +592,7 @@ static char const *const option_help[] =
|
||||
" --posix Conform to the POSIX standard.",
|
||||
"",
|
||||
" -d DIR --directory=DIR Change the working directory to DIR first.",
|
||||
" --reject-format=FORMAT Create 'context' or 'unified' rejects.",
|
||||
#if HAVE_SETMODE_DOS
|
||||
" --binary Read and write data in binary mode.",
|
||||
#else
|
||||
@ -784,6 +790,14 @@ get_some_switches (void)
|
||||
(enum quoting_style) i);
|
||||
}
|
||||
break;
|
||||
case CHAR_MAX + 9:
|
||||
if (strcmp (optarg, "context") == 0)
|
||||
reject_format = NEW_CONTEXT_DIFF;
|
||||
else if (strcmp (optarg, "unified") == 0)
|
||||
reject_format = UNI_DIFF;
|
||||
else
|
||||
usage (stderr, 2);
|
||||
break;
|
||||
default:
|
||||
usage (stderr, 2);
|
||||
}
|
||||
@ -932,10 +946,99 @@ locate_hunk (LINENUM fuzz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We did not find the pattern, dump out the hunk so they can handle it. */
|
||||
static void
|
||||
mangled_patch (LINENUM old, LINENUM new)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/* Output a line number range in unified format. */
|
||||
|
||||
static void
|
||||
abort_hunk (void)
|
||||
print_unidiff_range (FILE *fp, LINENUM start, LINENUM count)
|
||||
{
|
||||
char numbuf0[LINENUM_LENGTH_BOUND + 1];
|
||||
char numbuf1[LINENUM_LENGTH_BOUND + 1];
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
fprintf (fp, "%s,0", format_linenum (numbuf0, start - 1));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
fprintf (fp, "%s", format_linenum (numbuf0, start));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (fp, "%s,%s",
|
||||
format_linenum (numbuf0, start),
|
||||
format_linenum (numbuf1, count));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Produce unified reject files */
|
||||
|
||||
static void
|
||||
abort_hunk_unified (void)
|
||||
{
|
||||
FILE *fp = rejfp;
|
||||
register LINENUM old = 1;
|
||||
register LINENUM lastline = pch_ptrn_lines ();
|
||||
register LINENUM new = lastline + 1;
|
||||
|
||||
/* Add last_offset to guess the same as the previous successful hunk. */
|
||||
fprintf (fp, "@@ -");
|
||||
print_unidiff_range (fp, pch_first () + last_offset, lastline);
|
||||
fprintf (fp, " +");
|
||||
print_unidiff_range (fp, pch_newfirst () + last_offset, pch_repl_lines ());
|
||||
fprintf (fp, " @@\n");
|
||||
|
||||
while (pch_char (new) == '=' || pch_char (new) == '\n')
|
||||
new++;
|
||||
|
||||
if (diff_type != UNI_DIFF)
|
||||
pch_normalize (UNI_DIFF);
|
||||
|
||||
for (; ; old++, new++)
|
||||
{
|
||||
for (; pch_char (old) == '-'; old++)
|
||||
{
|
||||
fputc ('-', fp);
|
||||
pch_write_line (old, fp);
|
||||
}
|
||||
for (; pch_char (new) == '+'; new++)
|
||||
{
|
||||
fputc ('+', fp);
|
||||
pch_write_line (new, fp);
|
||||
}
|
||||
|
||||
if (old > lastline)
|
||||
break;
|
||||
|
||||
if (pch_char (new) != pch_char (old))
|
||||
mangled_patch (old, new);
|
||||
|
||||
fputc (' ', fp);
|
||||
pch_write_line (old, fp);
|
||||
}
|
||||
if (pch_char (new) != '^')
|
||||
mangled_patch (old, new);
|
||||
}
|
||||
|
||||
/* Output the rejected patch in context format. */
|
||||
|
||||
static void
|
||||
abort_hunk_context (void)
|
||||
{
|
||||
register LINENUM i;
|
||||
register LINENUM pat_end = pch_end ();
|
||||
@ -950,6 +1053,9 @@ abort_hunk (void)
|
||||
(int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
|
||||
char const *c_function = pch_c_function();
|
||||
|
||||
if (diff_type == UNI_DIFF)
|
||||
pch_normalize (NEW_CONTEXT_DIFF);
|
||||
|
||||
fprintf(rejfp, "***************%s\n", c_function ? c_function : "");
|
||||
for (i=0; i<=pat_end; i++) {
|
||||
char numbuf0[LINENUM_LENGTH_BOUND + 1];
|
||||
@ -984,13 +1090,25 @@ 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 ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the rejected hunk. */
|
||||
|
||||
static void
|
||||
abort_hunk (void)
|
||||
{
|
||||
if (reject_format == UNI_DIFF
|
||||
|| (reject_format == NO_DIFF && diff_type == UNI_DIFF))
|
||||
abort_hunk_unified ();
|
||||
else
|
||||
abort_hunk_context ();
|
||||
}
|
||||
|
||||
/* We found where to apply it (we hope), so do it. */
|
||||
|
||||
static bool
|
||||
@ -1054,16 +1172,8 @@ apply_hunk (struct outstate *outstate, LINENUM where)
|
||||
outstate->zero_output = false;
|
||||
new++;
|
||||
}
|
||||
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) != pch_char(old))
|
||||
mangled_patch (old, new);
|
||||
else if (pch_char(new) == '!') {
|
||||
assert (outstate->after_newline);
|
||||
if (! copy_till (outstate, where + old - 1))
|
||||
|
||||
@ -111,8 +111,7 @@ would generate a file name that is too long
|
||||
makes the file name too long, then
|
||||
.B #
|
||||
replaces the file name's last character).
|
||||
(The rejected hunk comes out in ordinary context diff form regardless of
|
||||
the input patch's form.
|
||||
(The rejected hunk comes out in unified or context diff format.
|
||||
If the input was a normal diff, many of the contexts are simply null.)
|
||||
The line numbers on the hunks in the reject file may be different than
|
||||
in the patch file: they reflect the approximate location patch thinks the
|
||||
@ -546,6 +545,12 @@ Luckily, most patches add or change lines rather than delete them, so most
|
||||
reversed normal diffs begin with a delete, which fails, triggering
|
||||
the heuristic.)
|
||||
.TP
|
||||
\fB\*=reject\-format=\fP\fIformat\fP
|
||||
Produce reject files in the specified \fIformat\fP (either \fBcontext\fP or
|
||||
\fBunified\fP). Without this option, rejected hunks come out in unified diff
|
||||
format if the input patch was of that format, otherwise in ordinary context
|
||||
diff form.
|
||||
.TP
|
||||
\fB\-s\fP or \fB\*=silent\fP or \fB\*=quiet\fP
|
||||
Work silently, unless an error occurs.
|
||||
.TP
|
||||
|
||||
67
pch.c
67
pch.c
@ -2054,3 +2054,70 @@ do_ed_script (FILE *ofp)
|
||||
read_fatal ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pch_normalize (enum diff format)
|
||||
{
|
||||
LINENUM old = 1;
|
||||
LINENUM new = p_ptrn_lines + 1;
|
||||
|
||||
while (p_Char[new] == '=' || p_Char[new] == '\n')
|
||||
new++;
|
||||
|
||||
if (format == UNI_DIFF)
|
||||
{
|
||||
/* Convert '!' markers into '-' and '+' as defined by the Unified
|
||||
Format. */
|
||||
|
||||
for (; old <= p_ptrn_lines; old++)
|
||||
if (p_Char[old] == '!')
|
||||
p_Char[old] = '-';
|
||||
for (; new <= p_end; new++)
|
||||
if (p_Char[new] == '!')
|
||||
p_Char[new] = '+';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Convert '-' and '+' markers which are part of a group into '!' as
|
||||
defined by the Context Format. */
|
||||
|
||||
while (old <= p_ptrn_lines)
|
||||
{
|
||||
if (p_Char[old] == '-')
|
||||
{
|
||||
if (new <= p_end && p_Char[new] == '+')
|
||||
{
|
||||
do
|
||||
{
|
||||
p_Char[old] = '!';
|
||||
old++;
|
||||
}
|
||||
while (old <= p_ptrn_lines && p_Char[old] == '-');
|
||||
do
|
||||
{
|
||||
p_Char[new] = '!';
|
||||
new++;
|
||||
}
|
||||
while (new <= p_end && p_Char[new] == '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
old++;
|
||||
while (old <= p_ptrn_lines && p_Char[old] == '-');
|
||||
}
|
||||
}
|
||||
else if (new <= p_end && p_Char[new] == '+')
|
||||
{
|
||||
do
|
||||
new++;
|
||||
while (new <= p_end && p_Char[new] == '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
old++;
|
||||
new++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
pch.h
1
pch.h
@ -44,3 +44,4 @@ void do_ed_script (FILE *);
|
||||
void open_patch_file (char const *);
|
||||
void re_patch (void);
|
||||
void set_hunkmax (void);
|
||||
void pch_normalize (enum diff);
|
||||
|
||||
@ -33,7 +33,7 @@ int foo()
|
||||
}
|
||||
EOF
|
||||
|
||||
diff -p -u a b > ab.diff
|
||||
diff -p -c a b > ab.diff
|
||||
printf "" > c
|
||||
check 'patch c < ab.diff || cat c.rej' <<EOF
|
||||
patching file c
|
||||
@ -44,12 +44,12 @@ Hunk #1 FAILED at 2.
|
||||
{
|
||||
/* waste a line */
|
||||
|
||||
- return 1;
|
||||
! return 1;
|
||||
}
|
||||
--- 2,6 ----
|
||||
{
|
||||
/* waste a line */
|
||||
|
||||
+ return 2;
|
||||
! return 2;
|
||||
}
|
||||
EOF
|
||||
|
||||
126
tests/reject-format
Executable file
126
tests/reject-format
Executable file
@ -0,0 +1,126 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# in any medium, are permitted without royalty provided the copyright
|
||||
# notice and this notice are preserved.
|
||||
|
||||
# Test the --reject-format=FORMAT option
|
||||
|
||||
. $srcdir/test-lib.sh
|
||||
|
||||
require_cat
|
||||
require_diff
|
||||
use_local_patch
|
||||
use_tmpdir
|
||||
|
||||
# ==============================================================
|
||||
|
||||
cat > f.orig <<EOF
|
||||
a() {
|
||||
2
|
||||
3
|
||||
|
||||
5
|
||||
6
|
||||
}
|
||||
EOF
|
||||
|
||||
sed -e 's/5/5a/' f.orig > f
|
||||
diff -p -c f.orig f > f.diff
|
||||
|
||||
check 'patch -f -F0 --no-backup-if-mismatch f < f.diff || echo "Status: $?"' <<EOF
|
||||
patching file f
|
||||
Hunk #1 FAILED at 2.
|
||||
1 out of 1 hunk FAILED -- saving rejects to file f.rej
|
||||
Status: 1
|
||||
EOF
|
||||
|
||||
check 'cat f.rej' <<EOF
|
||||
*************** a() {
|
||||
*** 2,7 ****
|
||||
2
|
||||
3
|
||||
|
||||
! 5
|
||||
6
|
||||
}
|
||||
--- 2,7 ----
|
||||
2
|
||||
3
|
||||
|
||||
! 5a
|
||||
6
|
||||
}
|
||||
EOF
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
diff -p -u f.orig f > f.diff
|
||||
check 'patch -f -F0 --no-backup-if-mismatch f < f.diff || echo "Status: $?"' <<EOF
|
||||
patching file f
|
||||
Hunk #1 FAILED at 2.
|
||||
1 out of 1 hunk FAILED -- saving rejects to file f.rej
|
||||
Status: 1
|
||||
EOF
|
||||
|
||||
check 'cat f.rej' <<EOF
|
||||
@@ -2,6 +2,6 @@
|
||||
2
|
||||
3
|
||||
|
||||
-5
|
||||
+5a
|
||||
6
|
||||
}
|
||||
EOF
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
diff -p -c f.orig f > f.diff
|
||||
check 'patch -f -F0 --no-backup-if-mismatch --reject-format=unified f < f.diff || echo "Status: $?"' <<EOF
|
||||
patching file f
|
||||
Hunk #1 FAILED at 2.
|
||||
1 out of 1 hunk FAILED -- saving rejects to file f.rej
|
||||
Status: 1
|
||||
EOF
|
||||
|
||||
check 'cat f.rej' <<EOF
|
||||
@@ -2,6 +2,6 @@
|
||||
2
|
||||
3
|
||||
|
||||
-5
|
||||
+5a
|
||||
6
|
||||
}
|
||||
EOF
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
diff -p -u f.orig f > f.diff
|
||||
check 'patch -f -F0 --no-backup-if-mismatch --reject-format=context f < f.diff || echo "Status: $?"' <<EOF
|
||||
patching file f
|
||||
Hunk #1 FAILED at 2.
|
||||
1 out of 1 hunk FAILED -- saving rejects to file f.rej
|
||||
Status: 1
|
||||
EOF
|
||||
|
||||
check 'cat f.rej' <<EOF
|
||||
*************** a() {
|
||||
*** 2,7 ****
|
||||
2
|
||||
3
|
||||
|
||||
! 5
|
||||
6
|
||||
}
|
||||
--- 2,7 ----
|
||||
2
|
||||
3
|
||||
|
||||
! 5a
|
||||
6
|
||||
}
|
||||
EOF
|
||||
Loading…
x
Reference in New Issue
Block a user