git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/5] xdiff: introduce XDF_IGNORE_CASE

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 20, 2012, 02:16 UTC
Message-ID
<1329704188-9955-5-git-send-email-gitster@pobox.com>
In-Reply-To
<1329704188-9955-1-git-send-email-gitster@pobox.com>

Teach the hash function and per-line comparison logic to compare lines while ignoring the differences in case. It is not an ignore-whitespace option but still needs to trigger the inexact match logic, and that is why the previous step introduced XDF_INEXACT_MATCH mask.

Assign the 7th bit for this option, and move the bits to select diff algorithms out of the way in order to leave room for a few bits to add more variants of ignore-whitespace, such as --ignore-tab-expansion, if somebody else is inclined to do so later.

We would still need to teach the front-end to flip this bit, for this change to be any useful.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 xdiff/xdiff.h  |    7 ++++---
 xdiff/xutils.c |   50 ++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h
index 48793f9..5a01a0e 100644
--- a/xdiff/xdiff.h
+++ b/xdiff/xdiff.h
@@ -36,10 +36,11 @@ extern "C" {
 	(XDF_IGNORE_WHITESPACE | \
 	 XDF_IGNORE_WHITESPACE_CHANGE | \
 	 XDF_IGNORE_WHITESPACE_AT_EOL)
-#define XDF_INEXACT_MATCH XDF_WHITESPACE_FLAGS
+#define XDF_IGNORE_CASE (1 << 7)
+#define XDF_INEXACT_MATCH (XDF_WHITESPACE_FLAGS | XDF_IGNORE_CASE)
 
-#define XDF_PATIENCE_DIFF (1 << 5)
-#define XDF_HISTOGRAM_DIFF (1 << 6)
+#define XDF_PATIENCE_DIFF (1 << 8)
+#define XDF_HISTOGRAM_DIFF (1 << 9)
 #define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
 #define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
 
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index aa6de74..925f1d0 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -170,6 +170,19 @@ long xdl_guess_lines(mmfile_t *mf, long sample) {
 	return nl + 1;
 }
 
+static inline int match_a_byte(char ch1, char ch2, long flags)
+{
+	if (ch1 == ch2)
+		return 1;
+	if (!(flags & XDF_IGNORE_CASE) || ((ch1 | ch2) & 0x80))
+		return 0;
+	if (isupper(ch1))
+		ch1 = tolower(ch1);
+	if (isupper(ch2))
+		ch2 = tolower(ch2);
+	return (ch1 == ch2);
+}
+
 int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
 {
 	int i1, i2;
@@ -192,7 +205,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
 	if (flags & XDF_IGNORE_WHITESPACE) {
 		goto skip_ws;
 		while (i1 < s1 && i2 < s2) {
-			if (l1[i1++] != l2[i2++])
+			if (!match_a_byte(l1[i1++], l2[i2++], flags))
 				return 0;
 		skip_ws:
 			while (i1 < s1 && XDL_ISSPACE(l1[i1]))
@@ -210,15 +223,28 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
 					i2++;
 				continue;
 			}
-			if (l1[i1++] != l2[i2++])
+			if (!match_a_byte(l1[i1++], l2[i2++], flags))
 				return 0;
 		}
-	} else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
-		while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++])
+	} else {
+		/*
+		 * Either XDF_IGNORE_WHITESPACE_AT_EOL is set, or
+		 * no whitespace is ignored, but INEXACT_MATCH is
+		 * in effect for other reasons.
+		 */
+		while (i1 < s1 && i2 < s2 &&
+		       match_a_byte(l1[i1++], l2[i2++], flags))
 			; /* keep going */
 	}
 
 	/*
+	 * If we are not ignoring any whitespace, we must have consumed
+	 * everything for the lines to match.
+	 */
+	if (!(flags & XDF_WHITESPACE_FLAGS))
+		return i1 == s1 && i2 == s2;
+
+	/*
 	 * After running out of one side, the remaining side must have
 	 * nothing but whitespace for the lines to match.  Note that
 	 * ignore-whitespace-at-eol case may break out of the loop
@@ -238,6 +264,14 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
 	return 1;
 }
 
+static inline unsigned long hash_a_byte(const char ch_, long flags)
+{
+	unsigned long ch = ch_ & 0xFF;
+	if ((flags & XDF_IGNORE_CASE) && !(ch & 0x80) && isupper(ch))
+		ch = tolower(ch);
+	return ch;
+}
+
 static unsigned long xdl_hash_record_with_whitespace(char const **data,
 		char const *top, long flags) {
 	unsigned long ha = 5381;
@@ -256,20 +290,20 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
 			else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
 				 && !at_eol) {
 				ha += (ha << 5);
-				ha ^= (unsigned long) ' ';
+				ha ^= hash_a_byte(' ', flags);
 			}
 			else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
 				 && !at_eol) {
 				while (ptr2 != ptr + 1) {
 					ha += (ha << 5);
-					ha ^= (unsigned long) *ptr2;
+					ha ^= hash_a_byte(*ptr2, flags);
 					ptr2++;
 				}
 			}
 			continue;
 		}
 		ha += (ha << 5);
-		ha ^= (unsigned long) *ptr;
+		ha ^= hash_a_byte(*ptr, flags);
 	}
 	*data = ptr < top ? ptr + 1: ptr;
 
@@ -286,7 +320,7 @@ unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
 
 	for (; ptr < top && *ptr != '\n'; ptr++) {
 		ha += (ha << 5);
-		ha ^= (unsigned long) *ptr;
+		ha ^= hash_a_byte(*ptr, flags);
 	}
 	*data = ptr < top ? ptr + 1: ptr;
 
-- 
1.7.9.1.265.g25f75
Previous: Junio C HamanoNext: Jakub Narebski
Message 5 of 14 in “diff --ignore-case”
  1. 0/5 diff --ignore-caseJunio C Hamano, Feb 20, 2012
  2. 1/5 xdiff: remove XDL_PATCH_* macrosJunio C Hamano, Feb 20, 2012
  3. 2/5 xdiff: PATIENCE/HISTOGRAM are not independent option bitsJunio C Hamano, Feb 20, 2012
  4. 3/5 xdiff: introduce XDF_INEXACT_MATCHJunio C Hamano, Feb 20, 2012
  5. 4/5 xdiff: introduce XDF_IGNORE_CASEJunio C Hamano, Feb 20, 2012
  6. Jakub NarebskiFeb 22, 2012
  7. 5/5 diff: --ignore-caseJunio C Hamano, Feb 20, 2012
  8. 6/5 diff -iJunio C Hamano, Feb 20, 2012
  9. Johannes SixtFeb 20, 2012
  10. Junio C HamanoFeb 20, 2012
  11. Thomas RastFeb 20, 2012
  12. Junio C HamanoFeb 20, 2012
  13. Chris LeongFeb 20, 2012
  14. Re* [PATCH 0/5] diff --ignore-caseJunio C Hamano, Feb 21, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.