[diffutils] Ported i18n patch and reinstated it (bug #870460).
Tim Waugh
twaugh at fedoraproject.org
Fri Oct 26 19:54:06 UTC 2012
commit 2ce78f30a38f6d4fdfd909e7c72b36e750c9d519
Author: Tim Waugh <twaugh at redhat.com>
Date: Fri Oct 26 18:28:13 2012 +0100
Ported i18n patch and reinstated it (bug #870460).
Resolves: rhbz#870460
diffutils-3.2-i18n.patch | 776 ++++++++++++++++++++++++++++++++++++++++++++++
diffutils.spec | 8 +-
2 files changed, 783 insertions(+), 1 deletions(-)
---
diff --git a/diffutils-3.2-i18n.patch b/diffutils-3.2-i18n.patch
new file mode 100644
index 0000000..07bbd47
--- /dev/null
+++ b/diffutils-3.2-i18n.patch
@@ -0,0 +1,776 @@
+diff -up diffutils-3.2/src/diff.c.i18n diffutils-3.2/src/diff.c
+--- diffutils-3.2/src/diff.c.i18n 2011-08-15 06:24:38.000000000 +0100
++++ diffutils-3.2/src/diff.c 2012-10-26 18:14:22.112521391 +0100
+@@ -73,6 +73,8 @@ static void try_help (char const *, char
+ static void check_stdout (void);
+ static void usage (void);
+
++bool (*lines_differ) (char const *, size_t, char const *, size_t);
++
+ /* If comparing directories, compare their common subdirectories
+ recursively. */
+ static bool recursive;
+@@ -286,6 +288,13 @@ main (int argc, char **argv)
+ re_set_syntax (RE_SYNTAX_GREP | RE_NO_POSIX_BACKTRACKING);
+ excluded = new_exclude ();
+
++#ifdef HANDLE_MULTIBYTE
++ if (MB_CUR_MAX > 1)
++ lines_differ = lines_differ_multibyte;
++ else
++#endif
++ lines_differ = lines_differ_singlebyte;
++
+ /* Decode the options. */
+
+ while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
+diff -up diffutils-3.2/src/diff.h.i18n diffutils-3.2/src/diff.h
+--- diffutils-3.2/src/diff.h.i18n 2011-08-15 06:25:26.000000000 +0100
++++ diffutils-3.2/src/diff.h 2012-10-26 18:14:22.112521391 +0100
+@@ -23,6 +23,17 @@
+ #include <stdio.h>
+ #include <unlocked-io.h>
+
++/* For platforms which support the ISO C ammendment 1 functionality we
++ support user-defined character classes. */
++#if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H
++/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
++# include <wchar.h>
++# include <wctype.h>
++# if defined (HAVE_MBRTOWC)
++# define HANDLE_MULTIBYTE 1
++# endif
++#endif
++
+ /* What kind of changes a hunk contains. */
+ enum changes
+ {
+@@ -361,7 +372,11 @@ extern void print_sdiff_script (struct c
+ extern char const change_letter[4];
+ extern char const pr_program[];
+ extern char *concat (char const *, char const *, char const *);
+-extern bool lines_differ (char const *, char const *);
++extern bool (*lines_differ) (char const *, size_t, char const *, size_t);
++extern bool lines_differ_singlebyte (char const *, size_t, char const *, size_t);
++#ifdef HANDLE_MULTIBYTE
++extern bool lines_differ_multibyte (char const *, size_t, char const *, size_t);
++#endif
+ extern lin translate_line_number (struct file_data const *, lin);
+ extern struct change *find_change (struct change *);
+ extern struct change *find_reverse_change (struct change *);
+diff -up diffutils-3.2/src/io.c.i18n diffutils-3.2/src/io.c
+--- diffutils-3.2/src/io.c.i18n 2011-08-15 06:24:38.000000000 +0100
++++ diffutils-3.2/src/io.c 2012-10-26 18:14:22.113521396 +0100
+@@ -22,6 +22,7 @@
+ #include <cmpbuf.h>
+ #include <file-type.h>
+ #include <xalloc.h>
++#include <assert.h>
+
+ /* Rotate an unsigned value to the left. */
+ #define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n)))
+@@ -194,6 +195,28 @@ slurp (struct file_data *current)
+
+ /* Split the file into lines, simultaneously computing the equivalence
+ class for each line. */
++#ifdef HANDLE_MULTIBYTE
++# define MBC2WC(P, END, MBLENGTH, WC, STATE, CONVFAIL) \
++do \
++ { \
++ mbstate_t state_bak = STATE; \
++ \
++ CONVFAIL = 0; \
++ MBLENGTH = mbrtowc (&WC, P, END - (char const *)P, &STATE); \
++ \
++ switch (MBLENGTH) \
++ { \
++ case (size_t)-2: \
++ case (size_t)-1: \
++ STATE = state_bak; \
++ ++CONVFAIL; \
++ /* Fall through. */ \
++ case 0: \
++ MBLENGTH = 1; \
++ } \
++ } \
++ while (0)
++#endif
+
+ static void
+ find_and_hash_each_line (struct file_data *current)
+@@ -220,12 +243,298 @@ find_and_hash_each_line (struct file_dat
+ bool same_length_diff_contents_compare_anyway =
+ diff_length_compare_anyway | ig_case;
+
++#ifdef HANDLE_MULTIBYTE
++ wchar_t wc;
++ size_t mblength;
++ mbstate_t state;
++ int convfail;
++
++ memset (&state, '\0', sizeof (mbstate_t));
++#endif
++
+ while (p < suffix_begin)
+ {
+ char const *ip = p;
+ hash_value h = 0;
+ unsigned char c;
+
++#ifdef HANDLE_MULTIBYTE
++ if (MB_CUR_MAX > 1)
++ {
++ wchar_t lo_wc;
++ char mbc[MB_LEN_MAX];
++ mbstate_t state_wc;
++
++ /* Hash this line until we find a newline. */
++ switch (ig_white_space)
++ {
++ case IGNORE_ALL_SPACE:
++ while (1)
++ {
++ if (*p == '\n')
++ {
++ ++p;
++ break;
++ }
++
++ MBC2WC (p, suffix_begin, mblength, wc, state, convfail);
++
++ if (convfail)
++ mbc[0] = *p++;
++ else if (!iswspace (wc))
++ {
++ bool flag = 0;
++
++ if (ig_case)
++ {
++ lo_wc = towlower (wc);
++ if (lo_wc != wc)
++ {
++ flag = 1;
++
++ p += mblength;
++ memset (&state_wc, '\0', sizeof(mbstate_t));
++ mblength = wcrtomb (mbc, lo_wc, &state_wc);
++
++ assert (mblength != (size_t)-1 &&
++ mblength != (size_t)-2);
++
++ mblength = (mblength < 1) ? 1 : mblength;
++ }
++ }
++
++ if (!flag)
++ {
++ for (i = 0; i < mblength; i++)
++ mbc[i] = *p++;
++ }
++ }
++ else
++ {
++ p += mblength;
++ continue;
++ }
++
++ for (i = 0; i < mblength; i++)
++ h = HASH (h, mbc[i]);
++ }
++ break;
++
++ case IGNORE_SPACE_CHANGE:
++ while (1)
++ {
++ if (*p == '\n')
++ {
++ ++p;
++ break;
++ }
++
++ MBC2WC (p, suffix_begin, mblength, wc, state, convfail);
++
++ if (!convfail && iswspace (wc))
++ {
++ while (1)
++ {
++ if (*p == '\n')
++ {
++ ++p;
++ goto hashing_done;
++ }
++
++ p += mblength;
++ MBC2WC (p, suffix_begin, mblength, wc, state, convfail);
++ if (convfail || !iswspace (wc))
++ break;
++ }
++ h = HASH (h, ' ');
++ }
++
++ /* WC is now the first non-space. */
++ if (convfail)
++ mbc[0] = *p++;
++ else
++ {
++ bool flag = 0;
++
++ if (ignore_case)
++ {
++ lo_wc = towlower (wc);
++ if (lo_wc != wc)
++ {
++ flag = 1;
++
++ p += mblength;
++ memset (&state_wc, '\0', sizeof(mbstate_t));
++ mblength = wcrtomb (mbc, lo_wc, &state_wc);
++
++ assert (mblength != (size_t)-1 &&
++ mblength != (size_t)-2);
++
++ mblength = (mblength < 1) ? 1 : mblength;
++ }
++ }
++
++ if (!flag)
++ {
++ for (i = 0; i < mblength; i++)
++ mbc[i] = *p++;
++ }
++ }
++
++ for (i = 0; i < mblength; i++)
++ h = HASH (h, mbc[i]);
++ }
++ break;
++
++ case IGNORE_TAB_EXPANSION:
++ case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
++ case IGNORE_TRAILING_SPACE:
++ {
++ size_t column = 0;
++ while (1)
++ {
++ if (*p == '\n')
++ {
++ ++p;
++ break;
++ }
++
++ MBC2WC (p, suffix_begin, mblength, wc, state, convfail);
++
++ if (!convfail
++ && ig_white_space & IGNORE_TRAILING_SPACE
++ && iswspace (wc))
++ {
++ char const *p1 = p;
++ while (1)
++ {
++ if (*p1 == '\n')
++ {
++ p = p1;
++ goto hashing_done;
++ }
++
++ p1 += mblength;
++ MBC2WC (p1, suffix_begin, mblength, wc, state, convfail);
++ if (convfail || !iswspace (wc))
++ break;
++ }
++ }
++
++ size_t repetitions = 1;
++
++ if (ig_white_space & IGNORE_TAB_EXPANSION)
++ {
++ bool flag = 0;
++ if (convfail)
++ column++;
++ else
++ switch (wc)
++ {
++ case L'\b':
++ column -= 0 < column;
++ break;
++
++ case L'\t':
++ wc = L' ';
++ repetitions = tabsize - column % tabsize;
++ column = (column + repetitions < column
++ ? 0
++ : column + repetitions);
++ break;
++
++ case L'\r':
++ column = 0;
++ break;
++
++ default:
++ column += wcwidth (wc);
++ break;
++ }
++
++ if (ig_case)
++ {
++ lo_wc = towlower (wc);
++ if (lo_wc != wc)
++ {
++ flag = 1;
++ p += mblength;
++ memset (&state_wc, '\0', sizeof(mbstate_t));
++ mblength = wcrtomb (mbc, lo_wc, &state_wc);
++
++ assert (mblength != (size_t)-1 &&
++ mblength != (size_t)-2);
++
++ mblength = (mblength < 1) ? 1 : mblength;
++ }
++ }
++
++ if (!flag)
++ {
++ for (i = 0; i < mblength; i++)
++ mbc[i] = *p++;
++ }
++ }
++
++ do
++ {
++ for (i = 0; i < mblength; i++)
++ h = HASH (h, mbc[i]);
++ }
++ while (--repetitions != 0);
++ }
++ }
++ break;
++
++ default:
++ while (1)
++ {
++ if (*p == '\n')
++ {
++ ++p;
++ break;
++ }
++
++ MBC2WC (p, suffix_begin, mblength, wc, state, convfail);
++
++ if (convfail)
++ mbc[0] = *p++;
++ else
++ {
++ int flag = 0;
++
++ if (ig_case)
++ {
++ lo_wc = towlower (wc);
++ if (lo_wc != wc)
++ {
++ flag = 1;
++ p += mblength;
++ memset (&state_wc, '\0', sizeof(mbstate_t));
++ mblength = wcrtomb (mbc, lo_wc, &state_wc);
++
++ assert (mblength != (size_t)-1 &&
++ mblength != (size_t)-2);
++
++ mblength = (mblength < 1) ? 1 : mblength;
++ }
++ }
++
++ if (!flag)
++ {
++ for (i = 0; i < mblength; i++)
++ mbc[i] = *p++;
++ }
++ }
++
++ for (i = 0; i < mblength; i++)
++ h = HASH (h, mbc[i]);
++ }
++ }
++ }
++ else
++#endif
++
+ /* Hash this line until we find a newline. */
+ switch (ig_white_space)
+ {
+@@ -376,7 +685,7 @@ find_and_hash_each_line (struct file_dat
+ else if (!diff_length_compare_anyway)
+ continue;
+
+- if (! lines_differ (eqline, ip))
++ if (! lines_differ (eqline, eqs[i].length + 1, ip, length + 1))
+ break;
+ }
+
+diff -up diffutils-3.2/src/util.c.i18n diffutils-3.2/src/util.c
+--- diffutils-3.2/src/util.c.i18n 2011-08-15 06:24:38.000000000 +0100
++++ diffutils-3.2/src/util.c 2012-10-26 18:22:32.911448447 +0100
+@@ -317,7 +317,8 @@ finish_output (void)
+ Return nonzero if the lines differ. */
+
+ bool
+-lines_differ (char const *s1, char const *s2)
++lines_differ_singlebyte (char const *s1, size_t s1len,
++ char const *s2, size_t s2len)
+ {
+ register char const *t1 = s1;
+ register char const *t2 = s2;
+@@ -473,6 +474,354 @@ lines_differ (char const *s1, char const
+
+ return true;
+ }
++
++#ifdef HANDLE_MULTIBYTE
++# define MBC2WC(T, END, MBLENGTH, WC, STATE, CONVFAIL) \
++do \
++ { \
++ mbstate_t bak = STATE; \
++ \
++ CONVFAIL = 0; \
++ MBLENGTH = mbrtowc (&WC, T, END - T, &STATE); \
++ \
++ switch (MBLENGTH) \
++ { \
++ case (size_t)-2: \
++ case (size_t)-1: \
++ STATE = bak; \
++ ++CONVFAIL; \
++ /* Fall through. */ \
++ case 0: \
++ MBLENGTH = 1; \
++ } \
++ } \
++ while (0)
++
++bool
++lines_differ_multibyte (char const *s1, size_t s1len,
++ char const *s2, size_t s2len)
++{
++ char const *end1, *end2;
++ char c1, c2;
++ wchar_t wc1, wc2, wc1_bak, wc2_bak;
++ size_t mblen1, mblen2;
++ mbstate_t state1, state2, state1_bak, state2_bak;
++ int convfail1, convfail2, convfail1_bak, convfail2_bak;
++
++ char const *t1 = s1;
++ char const *t2 = s2;
++ char const *t1_bak, *t2_bak;
++ size_t column = 0;
++
++ if (ignore_white_space == IGNORE_NO_WHITE_SPACE && !ignore_case)
++ {
++ while (*t1 != '\n')
++ if (*t1++ != *t2++)
++ return 1;
++ return 0;
++ }
++
++ end1 = t1 + s1len;
++ end2 = t2 + s2len;
++
++ memset (&state1, '\0', sizeof (mbstate_t));
++ memset (&state2, '\0', sizeof (mbstate_t));
++
++ while (1)
++ {
++ c1 = *t1;
++ c2 = *t2;
++ MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
++ MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
++
++ /* Test for exact char equality first, since it's a common case. */
++ if (convfail1 ^ convfail2)
++ break;
++ else if (convfail1 && convfail2 && c1 != c2)
++ break;
++ else if (!convfail1 && !convfail2 && wc1 != wc2)
++ {
++ switch (ignore_white_space)
++ {
++ case IGNORE_ALL_SPACE:
++ /* For -w, just skip past any white space. */
++ while (1)
++ {
++ if (convfail1)
++ break;
++ else if (wc1 == L'\n' || !iswspace (wc1))
++ break;
++
++ t1 += mblen1;
++ c1 = *t1;
++ MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
++ }
++
++ while (1)
++ {
++ if (convfail2)
++ break;
++ else if (wc2 == L'\n' || !iswspace (wc2))
++ break;
++
++ t2 += mblen2;
++ c2 = *t2;
++ MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
++ }
++ t1 += mblen1;
++ t2 += mblen2;
++ break;
++
++ case IGNORE_SPACE_CHANGE:
++ /* For -b, advance past any sequence of white space in
++ line 1 and consider it just one space, or nothing at
++ all if it is at the end of the line. */
++ if (wc1 != L'\n' && iswspace (wc1))
++ {
++ size_t mblen_bak;
++ mbstate_t state_bak;
++
++ do
++ {
++ t1 += mblen1;
++ mblen_bak = mblen1;
++ state_bak = state1;
++ MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
++ }
++ while (!convfail1 && (wc1 != L'\n' && iswspace (wc1)));
++
++ state1 = state_bak;
++ mblen1 = mblen_bak;
++ t1 -= mblen1;
++ convfail1 = 0;
++ wc1 = L' ';
++ }
++
++ /* Likewise for line 2. */
++ if (wc2 != L'\n' && iswspace (wc2))
++ {
++ size_t mblen_bak;
++ mbstate_t state_bak;
++
++ do
++ {
++ t2 += mblen2;
++ mblen_bak = mblen2;
++ state_bak = state2;
++ MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
++ }
++ while (!convfail2 && (wc2 != L'\n' && iswspace (wc2)));
++
++ state2 = state_bak;
++ mblen2 = mblen_bak;
++ t2 -= mblen2;
++ convfail2 = 0;
++ wc2 = L' ';
++ }
++
++ if (wc1 != wc2)
++ {
++ /* If we went too far when doing the simple test for
++ equality, go back to the first non-whitespace
++ character in both sides and try again. */
++ if (wc2 == L' ' && wc1 != L'\n' &&
++ t1 > s1 &&
++ !convfail1_bak && iswspace (wc1_bak))
++ {
++ t1 = t1_bak;
++ wc1 = wc1_bak;
++ state1 = state1_bak;
++ convfail1 = convfail1_bak;
++ continue;
++ }
++ if (wc1 == L' ' && wc2 != L'\n'
++ && t2 > s2
++ && !convfail2_bak && iswspace (wc2_bak))
++ {
++ t2 = t2_bak;
++ wc2 = wc2_bak;
++ state2 = state2_bak;
++ convfail2 = convfail2_bak;
++ continue;
++ }
++ }
++
++ t1_bak = t1; t2_bak = t2;
++ wc1_bak = wc1; wc2_bak = wc2;
++ state1_bak = state1; state2_bak = state2;
++ convfail1_bak = convfail1; convfail2_bak = convfail2;
++
++ if (wc1 == L'\n')
++ wc1 = L' ';
++ else
++ t1 += mblen1;
++
++ if (wc2 == L'\n')
++ wc2 = L' ';
++ else
++ t2 += mblen2;
++
++ break;
++
++ case IGNORE_TRAILING_SPACE:
++ case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
++ if (iswspace (wc1) && iswspace (wc2))
++ {
++ char const *p;
++ wchar_t wc;
++ size_t mblength;
++ int convfail;
++ mbstate_t state;
++ bool just_whitespace_left = 1;
++ if (wc1 != L'\n')
++ {
++ mblength = mblen1;
++ p = t1;
++ memset (&state, '\0', sizeof(mbstate_t));
++ while (p < end1)
++ {
++ if (*p == '\n')
++ break;
++
++ p += mblength;
++ MBC2WC (p, end1, mblength, wc, state, convfail);
++ if (convfail || !iswspace (wc))
++ {
++ just_whitespace_left = 0;
++ break;
++ }
++ }
++ }
++ if (just_whitespace_left && wc2 != L'\n')
++ {
++ mblength = mblen2;
++ p = t2;
++ memset (&state, '\0', sizeof(mbstate_t));
++ while (p < end2)
++ {
++ if (*p == '\n')
++ break;
++
++ p += mblength;
++ MBC2WC (p, end2, mblength, wc, state, convfail);
++ if (convfail || !iswspace (wc))
++ {
++ just_whitespace_left = 0;
++ break;
++ }
++ }
++ }
++
++ if (just_whitespace_left)
++ /* Both lines have nothing but whitespace left. */
++ return false;
++ }
++
++ if (ignore_white_space == IGNORE_TRAILING_SPACE)
++ break;
++ /* Fall through. */
++ case IGNORE_TAB_EXPANSION:
++ if ((wc1 == L' ' && wc2 == L'\t')
++ || (wc1 == L'\t' && wc2 == L' '))
++ {
++ size_t column2 = column;
++
++ while (1)
++ {
++ if (convfail1)
++ {
++ ++t1;
++ break;
++ }
++ else if (wc1 == L' ')
++ column++;
++ else if (wc1 == L'\t')
++ column += tabsize - column % tabsize;
++ else
++ {
++ t1 += mblen1;
++ break;
++ }
++
++ t1 += mblen1;
++ c1 = *t1;
++ MBC2WC (t1, end1, mblen1, wc1, state1, convfail1);
++ }
++
++ while (1)
++ {
++ if (convfail2)
++ {
++ ++t2;
++ break;
++ }
++ else if (wc2 == L' ')
++ column2++;
++ else if (wc2 == L'\t')
++ column2 += tabsize - column2 % tabsize;
++ else
++ {
++ t2 += mblen2;
++ break;
++ }
++
++ t2 += mblen2;
++ c2 = *t2;
++ MBC2WC (t2, end2, mblen2, wc2, state2, convfail2);
++ }
++
++ if (column != column2)
++ return 1;
++ }
++ else
++ {
++ t1 += mblen1;
++ t2 += mblen2;
++ }
++ break;
++
++ case IGNORE_NO_WHITE_SPACE:
++ t1 += mblen1;
++ t2 += mblen2;
++ break;
++ }
++
++ /* Lowercase all letters if -i is specified. */
++ if (ignore_case)
++ {
++ if (!convfail1)
++ wc1 = towlower (wc1);
++ if (!convfail2)
++ wc2 = towlower (wc2);
++ }
++
++ if (convfail1 ^ convfail2)
++ break;
++ else if (convfail1 && convfail2 && c1 != c2)
++ break;
++ else if (!convfail1 && !convfail2 && wc1 != wc2)
++ break;
++ }
++ else
++ {
++ t1_bak = t1; t2_bak = t2;
++ wc1_bak = wc1; wc2_bak = wc2;
++ state1_bak = state1; state2_bak = state2;
++ convfail1_bak = convfail1; convfail2_bak = convfail2;
++
++ t1 += mblen1; t2 += mblen2;
++ }
++
++ if (!convfail1 && wc1 == L'\n')
++ return 0;
++
++ column += convfail1 ? 1 :
++ (wc1 == L'\t') ? tabsize - column % tabsize : wcwidth (wc1);
++ }
++
++ return 1;
++}
++#endif
+
+ /* Find the consecutive changes at the start of the script START.
+ Return the last link before the first gap. */
diff --git a/diffutils.spec b/diffutils.spec
index 29818c8..68c2de9 100644
--- a/diffutils.spec
+++ b/diffutils.spec
@@ -1,13 +1,14 @@
Summary: A GNU collection of diff utilities
Name: diffutils
Version: 3.2
-Release: 10%{?dist}
+Release: 11%{?dist}
Group: Applications/Text
URL: http://www.gnu.org/software/diffutils/diffutils.html
Source: ftp://ftp.gnu.org/gnu/diffutils/diffutils-%{version}.tar.xz
Patch1: diffutils-cmp-s-empty.patch
Patch2: diffutils-ppc-float.patch
Patch3: diffutils-stdio-gets.patch
+Patch4: diffutils-3.2-i18n.patch
License: GPLv3+
Requires(post): info
Requires(preun): info
@@ -39,6 +40,8 @@ Install diffutils if you need to compare text files.
# Fixed build failure.
%patch3 -p1 -b .stdio-gets
+%patch4 -p1 -b .i18n
+
%build
%configure
make PR_PROGRAM=%{_bindir}/pr
@@ -72,6 +75,9 @@ rm -rf $RPM_BUILD_ROOT
%{_infodir}/diffutils.info*gz
%changelog
+* Fri Oct 26 2012 Tim Waugh <twaugh at redhat.com> 3.2-11
+- Ported i18n patch and reinstated it (bug #870460).
+
* Wed Sep 19 2012 Tim Waugh <twaugh at redhat.com> 3.2-10
- Fixed license as current source says GPLv3+.
More information about the scm-commits
mailing list