unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Michal Nazarewicz <mina86@mina86.com>
To: 24603@debbugs.gnu.org
Subject: bug#24603: [RFC 18/18] Fix case-fold-search character class matching
Date: Tue,  4 Oct 2016 03:10:41 +0200	[thread overview]
Message-ID: <1475543441-10493-18-git-send-email-mina86@mina86.com> (raw)
In-Reply-To: <1475543441-10493-1-git-send-email-mina86@mina86.com>

The uppar and lower character classes should match any cased characters
when case-fold-search is enabled.  So ‘[[:upper:]]’ sould match ‘a’ but
also ‘ł’, ‘ß’ and ‘fi’.  Fix character class tests to make that happen.

* src/character.h (CHAR_BIT_TITLE): New character bit for title case
characters (such as Dz).
* src/character.c (category_char_bits): Characters in Lt category are
title case; update lookup table.

* src/regex.c (re_wctype_to_bit): When case-folding is enabled return
any-case bits pattern for RECC_LOWER and RECC_UPPER.
(regex_compile): Update re_wctype_to_bit calls (it has new argument).
(execute_charset): Simplify case-folding case since now it’s encoded
in the bits.  corig argument is no longer necessary.
(mutually_exclusive_p, re_match_2_internal): Update execute_charset (it
no longer has corig argument).

* test/src/regex-tests.el (regex-tests--letter-character-classes): Fix
case-fold letter matching.
---
 src/character.c         |  2 +-
 src/character.h         |  5 +++--
 src/regex.c             | 53 ++++++++++++++++++++-----------------------------
 test/src/regex-tests.el | 16 +++++----------
 4 files changed, 30 insertions(+), 46 deletions(-)

diff --git a/src/character.c b/src/character.c
index 63f89d3..cf42f30 100644
--- a/src/character.c
+++ b/src/character.c
@@ -979,7 +979,7 @@ const unsigned char category_char_bits[] = {
   [UNICODE_CATEGORY_UNKNOWN] = 0,
   [UNICODE_CATEGORY_Lu] = CHAR_BIT_ALPHA_ | CHAR_BIT_UPPER,
   [UNICODE_CATEGORY_Ll] = CHAR_BIT_ALPHA_ | CHAR_BIT_LOWER,
-  [UNICODE_CATEGORY_Lt] = CHAR_BIT_ALPHA_,
+  [UNICODE_CATEGORY_Lt] = CHAR_BIT_ALPHA_ | CHAR_BIT_TITLE,
   [UNICODE_CATEGORY_Lm] = CHAR_BIT_ALPHA_,
   [UNICODE_CATEGORY_Lo] = CHAR_BIT_ALPHA_,
   [UNICODE_CATEGORY_Mn] = CHAR_BIT_ALPHA_,
diff --git a/src/character.h b/src/character.h
index 6dc95ad..f2849e5 100644
--- a/src/character.h
+++ b/src/character.h
@@ -665,8 +665,9 @@ extern unicode_category_t char_unicode_category (int);
 #define CHAR_BIT_ALPHA        (1 << 1)
 #define CHAR_BIT_UPPER        (1 << 2)
 #define CHAR_BIT_LOWER        (1 << 3)
-#define CHAR_BIT_GRAPH        (1 << 4)
-#define CHAR_BIT_PRINT        (1 << 5)
+#define CHAR_BIT_TITLE        (1 << 4)
+#define CHAR_BIT_GRAPH        (1 << 5)
+#define CHAR_BIT_PRINT        (1 << 6)
 
 /* Map from Unicode general category to character classes the character is in.
  *
diff --git a/src/regex.c b/src/regex.c
index bfd04a1..aa8c6ef 100644
--- a/src/regex.c
+++ b/src/regex.c
@@ -1794,6 +1794,7 @@ struct range_table_work_area
 #  define BIT_ALPHA	CHAR_BIT_ALPHA
 #  define BIT_UPPER	CHAR_BIT_UPPER
 #  define BIT_LOWER	CHAR_BIT_LOWER
+#  define BIT_TITLE	CHAR_BIT_TITLE
 #  define BIT_GRAPH	CHAR_BIT_GRAPH
 #  define BIT_PRINT	CHAR_BIT_PRINT
 #else
@@ -1801,8 +1802,9 @@ struct range_table_work_area
 #  define BIT_ALPHA	(1 << 1)
 #  define BIT_UPPER	(1 << 2)
 #  define BIT_LOWER	(1 << 3)
-#  define BIT_GRAPH	(1 << 4)
-#  define BIT_PRINT	(1 << 5)
+#  define BIT_TITLE	(1 << 4)
+#  define BIT_GRAPH	(1 << 5)
+#  define BIT_PRINT	(1 << 6)
 #endif
 #define BIT_WORD	(BIT_PRINT << 1)
 #define BIT_PUNCT	(BIT_PRINT << 2)
@@ -2067,7 +2069,7 @@ re_iswctype (int ch, re_wctype_t cc)
 /* Return a bit-pattern to use in the range-table bits to match multibyte
    chars of class CC.  */
 static int
-re_wctype_to_bit (re_wctype_t cc)
+re_wctype_to_bit (re_wctype_t cc, bool case_fold)
 {
   switch (cc)
     {
@@ -2076,8 +2078,10 @@ re_wctype_to_bit (re_wctype_t cc)
     case RECC_ALPHA: return BIT_ALPHA;
     case RECC_ALNUM: return BIT_ALNUM;
     case RECC_WORD: return BIT_WORD;
-    case RECC_LOWER: return BIT_LOWER;
-    case RECC_UPPER: return BIT_UPPER;
+    case RECC_LOWER:
+      return case_fold ? BIT_LOWER | BIT_UPPER | BIT_TITLE : BIT_LOWER;
+    case RECC_UPPER:
+      return case_fold ? BIT_LOWER | BIT_UPPER | BIT_TITLE : BIT_UPPER;
     case RECC_PUNCT: return BIT_PUNCT;
     case RECC_SPACE: return BIT_SPACE;
     case RECC_GRAPH: return BIT_GRAPH;
@@ -2886,7 +2890,8 @@ regex_compile (const_re_char *pattern, size_t size,
 			    SET_LIST_BIT (c1);
 			}
 		    SET_RANGE_TABLE_WORK_AREA_BIT
-		      (range_table_work, re_wctype_to_bit (cc));
+		      (range_table_work,
+		       re_wctype_to_bit (cc, RE_TRANSLATE_P (translate)));
 #endif	/* emacs */
 		    /* In most cases the matching rule for char classes only
 		       uses the syntax table for multibyte chars, so that the
@@ -4633,11 +4638,10 @@ skip_noops (const_re_char *p, const_re_char *pend)
 
 /* Test if C matches charset op.  *PP points to the charset or charset_not
    opcode.  When the function finishes, *PP will be advanced past that opcode.
-   C is character to test (possibly after translations) and CORIG is original
-   character (i.e. without any translations).  UNIBYTE denotes whether c is
-   unibyte or multibyte character. */
+   C is character to test.  UNIBYTE denotes whether c is unibyte or multibyte
+   character. */
 static bool
-execute_charset (const_re_char **pp, unsigned c, unsigned corig, bool unibyte)
+execute_charset (const_re_char **pp, unsigned c, bool unibyte)
 {
   re_char *p = *pp, *rtp = NULL;
   bool not = (re_opcode_t) *p == charset_not;
@@ -4675,24 +4679,9 @@ execute_charset (const_re_char **pp, unsigned c, unsigned corig, bool unibyte)
 	 IS_REAL_ASCII (c), we can ignore that. */
 
       bits = class_bits & (BIT_ALNUM | BIT_ALPHA | BIT_UPPER | BIT_LOWER |
-			   BIT_GRAPH | BIT_PRINT);
-      if (bits)
-	{
-	  int char_bits = category_char_bits[char_unicode_category (c)];
-	  if (bits & char_bits)
-	    return !not;
-
-	  /* Handle case folding. */
-	  if (corig != c)
-	    {
-	      if ((bits & BIT_UPPER) && (char_bits & BIT_LOWER) &&
-		  c == downcase (corig))
-		return !not;
-	      if ((bits & BIT_LOWER) && (char_bits & BIT_UPPER) &&
-		  c == upcase (corig))
-		return !not;
-	    }
-	}
+			   BIT_TITLE | BIT_GRAPH | BIT_PRINT);
+      if (bits && (category_char_bits[char_unicode_category (c)] & bits))
+	return !not;
 
       if (class_bits & (BIT_SPACE | BIT_WORD | BIT_PUNCT))
 	{
@@ -4772,7 +4761,7 @@ mutually_exclusive_p (struct re_pattern_buffer *bufp, const_re_char *p1,
 	else if ((re_opcode_t) *p1 == charset
 		 || (re_opcode_t) *p1 == charset_not)
 	  {
-	    if (!execute_charset (&p1, c, c, !multibyte || IS_REAL_ASCII (c)))
+	    if (!execute_charset (&p1, c, !multibyte || IS_REAL_ASCII (c)))
 	      {
 		DEBUG_PRINT ("	 No match => fast loop.\n");
 		return 1;
@@ -5482,7 +5471,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, const_re_char *string1,
 	case charset:
 	case charset_not:
 	  {
-	    register unsigned int c, corig;
+	    register unsigned int c;
 	    int len;
 
 	    /* Whether matching against a unibyte character.  */
@@ -5492,7 +5481,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, const_re_char *string1,
 			 (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
 
 	    PREFETCH ();
-	    corig = c = RE_STRING_CHAR_AND_LENGTH (d, len, target_multibyte);
+	    c = RE_STRING_CHAR_AND_LENGTH (d, len, target_multibyte);
 	    if (target_multibyte)
 	      {
 		int c1;
@@ -5524,7 +5513,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp, const_re_char *string1,
 	      }
 
 	    p -= 1;
-	    if (!execute_charset (&p, c, corig, unibyte_char))
+	    if (!execute_charset (&p, c, unibyte_char))
 	      goto fail;
 
 	    d += len;
diff --git a/test/src/regex-tests.el b/test/src/regex-tests.el
index 7617823..4da9ab3 100644
--- a/test/src/regex-tests.el
+++ b/test/src/regex-tests.el
@@ -127,17 +127,11 @@ regex--test-cc
          (?ẞ . "Lu | alnum alpha upper | case-fold: alnum alpha upper lower")
          (?DZ . "Lu | alnum alpha upper | case-fold: alnum alpha upper lower")
          (?a . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         ;; FIXME: Should match upper when case-fold case
-         ;; (?ł . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         ;; (?ß . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         ;; (?fi . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         ;; (?ɕ . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         ;; (?dz . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
-         (?ł . "Ll | alnum alpha lower | case-fold: alnum alpha lower")
-         (?ß . "Ll | alnum alpha lower | case-fold: alnum alpha lower")
-         (?fi . "Ll | alnum alpha lower | case-fold: alnum alpha lower")
-         (?ɕ . "Ll | alnum alpha lower | case-fold: alnum alpha lower")
-         (?dz . "Ll | alnum alpha lower | case-fold: alnum alpha lower")
+         (?ł . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
+         (?ß . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
+         (?fi . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
+         (?ɕ . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
+         (?dz . "Ll | alnum alpha lower | case-fold: alnum alpha upper lower")
          (?Dz . "Lt | alnum alpha | case-fold: alnum alpha upper lower")
          (?ʰ . "Lm | alnum alpha | case-fold: alnum alpha")
          (?º . "Lo | alnum alpha | case-fold: alnum alpha")))))))
-- 
2.8.0.rc3.226.g39d4020






  parent reply	other threads:[~2016-10-04  1:10 UTC|newest]

Thread overview: 89+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-04  1:05 bug#24603: [RFC 00/18] Improvement to casing Michal Nazarewicz
2016-10-04  1:10 ` bug#24603: [RFC 01/18] Add tests for casefiddle.c Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 02/18] Generate upcase and downcase tables from Unicode data Michal Nazarewicz
2016-10-04  7:27     ` Eli Zaretskii
2016-10-04 14:54       ` Michal Nazarewicz
2016-10-04 15:06         ` Eli Zaretskii
2016-10-04 16:57           ` Michal Nazarewicz
2016-10-04 17:27             ` Eli Zaretskii
2016-10-04 17:44               ` Eli Zaretskii
2016-10-06 20:29                 ` Michal Nazarewicz
2016-10-07  6:52                   ` Eli Zaretskii
2016-10-04  1:10   ` bug#24603: [RFC 03/18] Don’t assume character can be either upper- or lower-case when casing Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 04/18] Split casify_object into multiple functions Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 05/18] Introduce case_character function Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 06/18] Add support for title-casing letters Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 07/18] Split up casify_region function Michal Nazarewicz
2016-10-04  7:17     ` Eli Zaretskii
2016-10-18  2:27       ` Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 08/18] Support casing characters which map into multiple code points Michal Nazarewicz
2016-10-04  7:38     ` Eli Zaretskii
2016-10-06 21:40       ` Michal Nazarewicz
2016-10-07  7:46         ` Eli Zaretskii
2017-01-28 23:48           ` Michal Nazarewicz
2017-02-10  9:12             ` Eli Zaretskii
2016-10-04  1:10   ` bug#24603: [RFC 09/18] Implement special sigma casing rule Michal Nazarewicz
2016-10-04  7:22     ` Eli Zaretskii
2016-10-04  1:10   ` bug#24603: [RFC 10/18] Implement Turkic dotless and dotted i handling when casing strings Michal Nazarewicz
2016-10-04  7:12     ` Eli Zaretskii
2016-10-04  1:10   ` bug#24603: [RFC 11/18] Implement casing rules for Lithuanian Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 12/18] Implement rules for title-casing Dutch ij ‘letter’ Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 13/18] Add some tricky Unicode characters to regex test Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 14/18] Factor out character category lookup to separate function Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 15/18] Base lower- and upper-case tests on Unicode properties Michal Nazarewicz
2016-10-04  6:54     ` Eli Zaretskii
2016-10-04  1:10   ` bug#24603: [RFC 16/18] Refactor character class checking; optimise ASCII case Michal Nazarewicz
2016-10-04  7:48     ` Eli Zaretskii
2016-10-17 13:22       ` Michal Nazarewicz
2016-11-06 19:26       ` Michal Nazarewicz
2016-11-06 19:44         ` Eli Zaretskii
2016-12-20 14:32           ` Michal Nazarewicz
2016-12-20 16:39             ` Eli Zaretskii
2016-12-22 14:02               ` Michal Nazarewicz
2016-10-04  1:10   ` bug#24603: [RFC 17/18] Optimise character class matching in regexes Michal Nazarewicz
2016-10-04  1:10   ` Michal Nazarewicz [this message]
2016-10-17 22:03 ` bug#24603: [PATCH 0/3] Case table updates Michal Nazarewicz
2016-10-17 22:03   ` bug#24603: [PATCH 1/3] Add tests for casefiddle.c Michal Nazarewicz
2016-10-17 22:03   ` bug#24603: [PATCH 2/3] Generate upcase and downcase tables from Unicode data Michal Nazarewicz
2016-10-17 22:03   ` bug#24603: [PATCH 3/3] Don’t generate ‘X maps to X’ entries in case tables Michal Nazarewicz
2016-10-18  6:36   ` bug#24603: [PATCH 0/3] Case table updates Eli Zaretskii
2016-10-24 15:11     ` Michal Nazarewicz
2016-10-24 15:33       ` Eli Zaretskii
2017-03-09 21:51 ` bug#24603: [PATCHv5 00/11] Casing improvements Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 01/11] Split casify_object into multiple functions Michal Nazarewicz
2017-03-10  9:00     ` Andreas Schwab
2017-03-09 21:51   ` bug#24603: [PATCHv5 02/11] Introduce case_character function Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 03/11] Add support for title-casing letters (bug#24603) Michal Nazarewicz
2017-03-11  9:03     ` Eli Zaretskii
2017-03-09 21:51   ` bug#24603: [PATCHv5 04/11] Split up casify_region function (bug#24603) Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 05/11] Support casing characters which map into multiple code points (bug#24603) Michal Nazarewicz
2017-03-11  9:14     ` Eli Zaretskii
2017-03-21  2:09       ` Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 06/11] Implement special sigma casing rule (bug#24603) Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 07/11] Introduce ‘buffer-language’ buffer-locar variable Michal Nazarewicz
2017-03-11  9:29     ` Eli Zaretskii
2017-03-09 21:51   ` bug#24603: [PATCHv5 08/11] Implement rules for title-casing Dutch ij ‘letter’ (bug#24603) Michal Nazarewicz
2017-03-11  9:40     ` Eli Zaretskii
2017-03-16 21:30       ` Michal Nazarewicz
2017-03-17 13:43         ` Eli Zaretskii
2017-03-09 21:51   ` bug#24603: [PATCHv5 09/11] Implement Turkic dotless and dotted i casing rules (bug#24603) Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 10/11] Implement casing rules for Lithuanian (bug#24603) Michal Nazarewicz
2017-03-09 21:51   ` bug#24603: [PATCHv5 11/11] Implement Irish casing rules (bug#24603) Michal Nazarewicz
2017-03-11  9:44     ` Eli Zaretskii
2017-03-16 22:16       ` Michal Nazarewicz
2017-03-17  8:20         ` Eli Zaretskii
2017-03-11 10:00   ` bug#24603: [PATCHv5 00/11] Casing improvements Eli Zaretskii
2017-03-21  1:27   ` bug#24603: [PATCHv6 0/6] Casing improvements, language-independent part Michal Nazarewicz
2017-03-21  1:27     ` bug#24603: [PATCHv6 1/6] Split casify_object into multiple functions Michal Nazarewicz
2017-03-21  1:27     ` bug#24603: [PATCHv6 2/6] Introduce case_character function Michal Nazarewicz
2017-03-21  1:27     ` bug#24603: [PATCHv6 3/6] Add support for title-casing letters (bug#24603) Michal Nazarewicz
2017-03-21  1:27     ` bug#24603: [PATCHv6 4/6] Split up casify_region function (bug#24603) Michal Nazarewicz
2017-03-21  1:27     ` bug#24603: [PATCHv6 5/6] Support casing characters which map into multiple code points (bug#24603) Michal Nazarewicz
2017-03-22 16:06       ` Eli Zaretskii
2017-04-03  9:01         ` Michal Nazarewicz
2017-04-03 14:52           ` Eli Zaretskii
2019-06-25  0:09           ` Lars Ingebrigtsen
2019-06-25  0:29             ` Michał Nazarewicz
2020-08-11 13:46               ` Lars Ingebrigtsen
2021-05-10 11:51                 ` bug#24603: [RFC 00/18] Improvement to casing Lars Ingebrigtsen
2017-03-21  1:27     ` bug#24603: [PATCHv6 6/6] Implement special sigma casing rule (bug#24603) Michal Nazarewicz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1475543441-10493-18-git-send-email-mina86@mina86.com \
    --to=mina86@mina86.com \
    --cc=24603@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).