X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fmbscasestr.c;h=c419b35011484af20452089e1cb14ec7351cf982;hb=cd56634a4a8179fd5a4419fbb3e27211b042ab1c;hp=ce28342c4978651ab0dfd8f1ff623104916e0dab;hpb=4bc8b69ccf12c40ba0eec577b18e24bdd3cbc945;p=gnulib.git diff --git a/lib/mbscasestr.c b/lib/mbscasestr.c index ce28342c4..c419b3501 100644 --- a/lib/mbscasestr.c +++ b/lib/mbscasestr.c @@ -1,11 +1,11 @@ /* Case-insensitive searching in a string. - Copyright (C) 2005-2007 Free Software Foundation, Inc. + Copyright (C) 2005-2014 Free Software Foundation, Inc. Written by Bruno Haible , 2005. - This program is free software; you can redistribute it and/or modify + 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. + the Free Software Foundation; either version 3 of the License, 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 @@ -13,8 +13,7 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include @@ -25,114 +24,31 @@ #include #include /* for NULL, in case a nonstandard string.h lacks it */ -#include "allocsa.h" -#if HAVE_MBRTOWC -# include "mbuiter.h" -#endif +#include "malloca.h" +#include "mbuiter.h" #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) +/* Knuth-Morris-Pratt algorithm. */ +#define UNIT unsigned char +#define CANON_ELEMENT(c) TOLOWER (c) +#include "str-kmp.h" + /* Knuth-Morris-Pratt algorithm. See http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm - Return a boolean indicating success. */ - -static bool -knuth_morris_pratt_unibyte (const char *haystack, const char *needle, - const char **resultp) -{ - size_t m = strlen (needle); - - /* Allocate the table. */ - size_t *table = (size_t *) allocsa (m * sizeof (size_t)); - if (table == NULL) - return false; - /* Fill the table. - For 0 < i < m: - 0 < table[i] <= i is defined such that - rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i] - implies - forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1], - and table[i] is as large as possible with this property. - table[0] remains uninitialized. */ - { - size_t i, j; - - table[1] = 1; - j = 0; - for (i = 2; i < m; i++) - { - unsigned char b = TOLOWER ((unsigned char) needle[i - 1]); - - for (;;) - { - if (b == TOLOWER ((unsigned char) needle[j])) - { - table[i] = i - ++j; - break; - } - if (j == 0) - { - table[i] = i; - break; - } - j = j - table[j]; - } - } - } - - /* Search, using the table to accelerate the processing. */ - { - size_t j; - const char *rhaystack; - const char *phaystack; - - *resultp = NULL; - j = 0; - rhaystack = haystack; - phaystack = haystack; - /* Invariant: phaystack = rhaystack + j. */ - while (*phaystack != '\0') - if (TOLOWER ((unsigned char) needle[j]) - == TOLOWER ((unsigned char) *phaystack)) - { - j++; - phaystack++; - if (j == m) - { - /* The entire needle has been found. */ - *resultp = rhaystack; - break; - } - } - else if (j > 0) - { - /* Found a match of needle[0..j-1], mismatch at needle[j]. */ - rhaystack += table[j]; - j -= table[j]; - } - else - { - /* Found a mismatch at needle[0] already. */ - rhaystack++; - phaystack++; - } - } - - freesa (table); - return true; -} - -#if HAVE_MBRTOWC + Return a boolean indicating success: + Return true and set *RESULTP if the search was completed. + Return false if it was aborted because not enough memory was available. */ static bool knuth_morris_pratt_multibyte (const char *haystack, const char *needle, - const char **resultp) + const char **resultp) { size_t m = mbslen (needle); mbchar_t *needle_mbchars; size_t *table; /* Allocate room for needle_mbchars and the table. */ - char *memory = (char *) allocsa (m * (sizeof (mbchar_t) + sizeof (size_t))); + char *memory = (char *) nmalloca (m, sizeof (mbchar_t) + sizeof (size_t)); if (memory == NULL) return false; needle_mbchars = (mbchar_t *) memory; @@ -146,43 +62,76 @@ knuth_morris_pratt_multibyte (const char *haystack, const char *needle, j = 0; for (mbui_init (iter, needle); mbui_avail (iter); mbui_advance (iter), j++) { - mb_copy (&needle_mbchars[j], &mbui_cur (iter)); - if (needle_mbchars[j].wc_valid) - needle_mbchars[j].wc = towlower (needle_mbchars[j].wc); + mb_copy (&needle_mbchars[j], &mbui_cur (iter)); + if (needle_mbchars[j].wc_valid) + needle_mbchars[j].wc = towlower (needle_mbchars[j].wc); } } /* Fill the table. For 0 < i < m: 0 < table[i] <= i is defined such that - rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i] - implies - forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1], + forall 0 < x < table[i]: needle[x..i-1] != needle[0..i-1-x], and table[i] is as large as possible with this property. + This implies: + 1) For 0 < i < m: + If table[i] < i, + needle[table[i]..i-1] = needle[0..i-1-table[i]]. + 2) For 0 < i < m: + rhaystack[0..i-1] == needle[0..i-1] + and exists h, i <= h < m: rhaystack[h] != needle[h] + implies + forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1]. table[0] remains uninitialized. */ { size_t i, j; + /* i = 1: Nothing to verify for x = 0. */ table[1] = 1; j = 0; + for (i = 2; i < m; i++) { - mbchar_t *b = &needle_mbchars[i - 1]; - - for (;;) - { - if (mb_equal (*b, needle_mbchars[j])) - { - table[i] = i - ++j; - break; - } - if (j == 0) - { - table[i] = i; - break; - } - j = j - table[j]; - } + /* Here: j = i-1 - table[i-1]. + The inequality needle[x..i-1] != needle[0..i-1-x] is known to hold + for x < table[i-1], by induction. + Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1]. */ + mbchar_t *b = &needle_mbchars[i - 1]; + + for (;;) + { + /* Invariants: The inequality needle[x..i-1] != needle[0..i-1-x] + is known to hold for x < i-1-j. + Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1]. */ + if (mb_equal (*b, needle_mbchars[j])) + { + /* Set table[i] := i-1-j. */ + table[i] = i - ++j; + break; + } + /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds + for x = i-1-j, because + needle[i-1] != needle[j] = needle[i-1-x]. */ + if (j == 0) + { + /* The inequality holds for all possible x. */ + table[i] = i; + break; + } + /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds + for i-1-j < x < i-1-j+table[j], because for these x: + needle[x..i-2] + = needle[x-(i-1-j)..j-1] + != needle[0..j-1-(x-(i-1-j))] (by definition of table[j]) + = needle[0..i-2-x], + hence needle[x..i-1] != needle[0..i-1-x]. + Furthermore + needle[i-1-j+table[j]..i-2] + = needle[table[j]..j-1] + = needle[0..j-1-table[j]] (by definition of table[j]). */ + j = j - table[j]; + } + /* Here: j = i - table[i]. */ } } @@ -199,49 +148,48 @@ knuth_morris_pratt_multibyte (const char *haystack, const char *needle, /* Invariant: phaystack = rhaystack + j. */ while (mbui_avail (phaystack)) { - mbchar_t c; - - mb_copy (&c, &mbui_cur (phaystack)); - if (c.wc_valid) - c.wc = towlower (c.wc); - if (mb_equal (needle_mbchars[j], c)) - { - j++; - mbui_advance (phaystack); - if (j == m) - { - /* The entire needle has been found. */ - *resultp = mbui_cur_ptr (rhaystack); - break; - } - } - else if (j > 0) - { - /* Found a match of needle[0..j-1], mismatch at needle[j]. */ - size_t count = table[j]; - j -= count; - for (; count > 0; count--) - { - if (!mbui_avail (rhaystack)) - abort (); - mbui_advance (rhaystack); - } - } - else - { - /* Found a mismatch at needle[0] already. */ - if (!mbui_avail (rhaystack)) - abort (); - mbui_advance (rhaystack); - mbui_advance (phaystack); - } + mbchar_t c; + + mb_copy (&c, &mbui_cur (phaystack)); + if (c.wc_valid) + c.wc = towlower (c.wc); + if (mb_equal (needle_mbchars[j], c)) + { + j++; + mbui_advance (phaystack); + if (j == m) + { + /* The entire needle has been found. */ + *resultp = mbui_cur_ptr (rhaystack); + break; + } + } + else if (j > 0) + { + /* Found a match of needle[0..j-1], mismatch at needle[j]. */ + size_t count = table[j]; + j -= count; + for (; count > 0; count--) + { + if (!mbui_avail (rhaystack)) + abort (); + mbui_advance (rhaystack); + } + } + else + { + /* Found a mismatch at needle[0] already. */ + if (!mbui_avail (rhaystack)) + abort (); + mbui_advance (rhaystack); + mbui_advance (phaystack); + } } } - freesa (memory); + freea (memory); return true; } -#endif /* Find the first occurrence of the character string NEEDLE in the character string HAYSTACK, using case-insensitive comparison. @@ -255,210 +203,210 @@ mbscasestr (const char *haystack, const char *needle) - haystack may be very long, and a match of needle found early, - needle may be very long, and not even a short initial segment of needle may be found in haystack. */ -#if HAVE_MBRTOWC if (MB_CUR_MAX > 1) { mbui_iterator_t iter_needle; mbui_init (iter_needle, needle); if (mbui_avail (iter_needle)) - { - /* Minimizing the worst-case complexity: - Let n = mbslen(haystack), m = mbslen(needle). - The naïve algorithm is O(n*m) worst-case. - The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a - memory allocation. - To achieve linear complexity and yet amortize the cost of the - memory allocation, we activate the Knuth-Morris-Pratt algorithm - only once the naïve algorithm has already run for some time; more - precisely, when - - the outer loop count is >= 10, - - the average number of comparisons per outer loop is >= 5, - - the total number of comparisons is >= m. - But we try it only once. If the memory allocation attempt failed, - we don't retry it. */ - bool try_kmp = true; - size_t outer_loop_count = 0; - size_t comparison_count = 0; - size_t last_ccount = 0; /* last comparison count */ - mbui_iterator_t iter_needle_last_ccount; /* = needle + last_ccount */ - - mbchar_t b; - mbui_iterator_t iter_haystack; - - mbui_init (iter_needle_last_ccount, needle); - - mb_copy (&b, &mbui_cur (iter_needle)); - if (b.wc_valid) - b.wc = towlower (b.wc); - - mbui_init (iter_haystack, haystack); - for (;; mbui_advance (iter_haystack)) - { - mbchar_t c; - - if (!mbui_avail (iter_haystack)) - /* No match. */ - return NULL; - - /* See whether it's advisable to use an asymptotically faster - algorithm. */ - if (try_kmp - && outer_loop_count >= 10 - && comparison_count >= 5 * outer_loop_count) - { - /* See if needle + comparison_count now reaches the end of - needle. */ - size_t count = comparison_count - last_ccount; - for (; - count > 0 && mbui_avail (iter_needle_last_ccount); - count--) - mbui_advance (iter_needle_last_ccount); - last_ccount = comparison_count; - if (!mbui_avail (iter_needle_last_ccount)) - { - /* Try the Knuth-Morris-Pratt algorithm. */ - const char *result; - bool success = - knuth_morris_pratt_multibyte (haystack, needle, - &result); - if (success) - return (char *) result; - try_kmp = false; - } - } - - outer_loop_count++; - comparison_count++; - mb_copy (&c, &mbui_cur (iter_haystack)); - if (c.wc_valid) - c.wc = towlower (c.wc); - if (mb_equal (c, b)) - /* The first character matches. */ - { - mbui_iterator_t rhaystack; - mbui_iterator_t rneedle; - - memcpy (&rhaystack, &iter_haystack, sizeof (mbui_iterator_t)); - mbui_advance (rhaystack); - - mbui_init (rneedle, needle); - if (!mbui_avail (rneedle)) - abort (); - mbui_advance (rneedle); - - for (;; mbui_advance (rhaystack), mbui_advance (rneedle)) - { - if (!mbui_avail (rneedle)) - /* Found a match. */ - return (char *) mbui_cur_ptr (iter_haystack); - if (!mbui_avail (rhaystack)) - /* No match. */ - return NULL; - comparison_count++; - if (!mb_caseequal (mbui_cur (rhaystack), - mbui_cur (rneedle))) - /* Nothing in this round. */ - break; - } - } - } - } + { + /* Minimizing the worst-case complexity: + Let n = mbslen(haystack), m = mbslen(needle). + The naïve algorithm is O(n*m) worst-case. + The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a + memory allocation. + To achieve linear complexity and yet amortize the cost of the + memory allocation, we activate the Knuth-Morris-Pratt algorithm + only once the naïve algorithm has already run for some time; more + precisely, when + - the outer loop count is >= 10, + - the average number of comparisons per outer loop is >= 5, + - the total number of comparisons is >= m. + But we try it only once. If the memory allocation attempt failed, + we don't retry it. */ + bool try_kmp = true; + size_t outer_loop_count = 0; + size_t comparison_count = 0; + size_t last_ccount = 0; /* last comparison count */ + mbui_iterator_t iter_needle_last_ccount; /* = needle + last_ccount */ + + mbchar_t b; + mbui_iterator_t iter_haystack; + + mbui_init (iter_needle_last_ccount, needle); + + mb_copy (&b, &mbui_cur (iter_needle)); + if (b.wc_valid) + b.wc = towlower (b.wc); + + mbui_init (iter_haystack, haystack); + for (;; mbui_advance (iter_haystack)) + { + mbchar_t c; + + if (!mbui_avail (iter_haystack)) + /* No match. */ + return NULL; + + /* See whether it's advisable to use an asymptotically faster + algorithm. */ + if (try_kmp + && outer_loop_count >= 10 + && comparison_count >= 5 * outer_loop_count) + { + /* See if needle + comparison_count now reaches the end of + needle. */ + size_t count = comparison_count - last_ccount; + for (; + count > 0 && mbui_avail (iter_needle_last_ccount); + count--) + mbui_advance (iter_needle_last_ccount); + last_ccount = comparison_count; + if (!mbui_avail (iter_needle_last_ccount)) + { + /* Try the Knuth-Morris-Pratt algorithm. */ + const char *result; + bool success = + knuth_morris_pratt_multibyte (haystack, needle, + &result); + if (success) + return (char *) result; + try_kmp = false; + } + } + + outer_loop_count++; + comparison_count++; + mb_copy (&c, &mbui_cur (iter_haystack)); + if (c.wc_valid) + c.wc = towlower (c.wc); + if (mb_equal (c, b)) + /* The first character matches. */ + { + mbui_iterator_t rhaystack; + mbui_iterator_t rneedle; + + memcpy (&rhaystack, &iter_haystack, sizeof (mbui_iterator_t)); + mbui_advance (rhaystack); + + mbui_init (rneedle, needle); + if (!mbui_avail (rneedle)) + abort (); + mbui_advance (rneedle); + + for (;; mbui_advance (rhaystack), mbui_advance (rneedle)) + { + if (!mbui_avail (rneedle)) + /* Found a match. */ + return (char *) mbui_cur_ptr (iter_haystack); + if (!mbui_avail (rhaystack)) + /* No match. */ + return NULL; + comparison_count++; + if (!mb_caseequal (mbui_cur (rhaystack), + mbui_cur (rneedle))) + /* Nothing in this round. */ + break; + } + } + } + } else - return (char *) haystack; + return (char *) haystack; } else -#endif { if (*needle != '\0') - { - /* Minimizing the worst-case complexity: - Let n = strlen(haystack), m = strlen(needle). - The naïve algorithm is O(n*m) worst-case. - The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a - memory allocation. - To achieve linear complexity and yet amortize the cost of the - memory allocation, we activate the Knuth-Morris-Pratt algorithm - only once the naïve algorithm has already run for some time; more - precisely, when - - the outer loop count is >= 10, - - the average number of comparisons per outer loop is >= 5, - - the total number of comparisons is >= m. - But we try it only once. If the memory allocation attempt failed, - we don't retry it. */ - bool try_kmp = true; - size_t outer_loop_count = 0; - size_t comparison_count = 0; - size_t last_ccount = 0; /* last comparison count */ - const char *needle_last_ccount = needle; /* = needle + last_ccount */ - - /* Speed up the following searches of needle by caching its first - character. */ - unsigned char b = TOLOWER ((unsigned char) *needle); - - needle++; - for (;; haystack++) - { - if (*haystack == '\0') - /* No match. */ - return NULL; - - /* See whether it's advisable to use an asymptotically faster - algorithm. */ - if (try_kmp - && outer_loop_count >= 10 - && comparison_count >= 5 * outer_loop_count) - { - /* See if needle + comparison_count now reaches the end of - needle. */ - if (needle_last_ccount != NULL) - { - needle_last_ccount += - strnlen (needle_last_ccount, - comparison_count - last_ccount); - if (*needle_last_ccount == '\0') - needle_last_ccount = NULL; - last_ccount = comparison_count; - } - if (needle_last_ccount == NULL) - { - /* Try the Knuth-Morris-Pratt algorithm. */ - const char *result; - bool success = - knuth_morris_pratt_unibyte (haystack, needle - 1, - &result); - if (success) - return (char *) result; - try_kmp = false; - } - } - - outer_loop_count++; - comparison_count++; - if (TOLOWER ((unsigned char) *haystack) == b) - /* The first character matches. */ - { - const char *rhaystack = haystack + 1; - const char *rneedle = needle; - - for (;; rhaystack++, rneedle++) - { - if (*rneedle == '\0') - /* Found a match. */ - return (char *) haystack; - if (*rhaystack == '\0') - /* No match. */ - return NULL; - comparison_count++; - if (TOLOWER ((unsigned char) *rhaystack) - != TOLOWER ((unsigned char) *rneedle)) - /* Nothing in this round. */ - break; - } - } - } - } + { + /* Minimizing the worst-case complexity: + Let n = strlen(haystack), m = strlen(needle). + The naïve algorithm is O(n*m) worst-case. + The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a + memory allocation. + To achieve linear complexity and yet amortize the cost of the + memory allocation, we activate the Knuth-Morris-Pratt algorithm + only once the naïve algorithm has already run for some time; more + precisely, when + - the outer loop count is >= 10, + - the average number of comparisons per outer loop is >= 5, + - the total number of comparisons is >= m. + But we try it only once. If the memory allocation attempt failed, + we don't retry it. */ + bool try_kmp = true; + size_t outer_loop_count = 0; + size_t comparison_count = 0; + size_t last_ccount = 0; /* last comparison count */ + const char *needle_last_ccount = needle; /* = needle + last_ccount */ + + /* Speed up the following searches of needle by caching its first + character. */ + unsigned char b = TOLOWER ((unsigned char) *needle); + + needle++; + for (;; haystack++) + { + if (*haystack == '\0') + /* No match. */ + return NULL; + + /* See whether it's advisable to use an asymptotically faster + algorithm. */ + if (try_kmp + && outer_loop_count >= 10 + && comparison_count >= 5 * outer_loop_count) + { + /* See if needle + comparison_count now reaches the end of + needle. */ + if (needle_last_ccount != NULL) + { + needle_last_ccount += + strnlen (needle_last_ccount, + comparison_count - last_ccount); + if (*needle_last_ccount == '\0') + needle_last_ccount = NULL; + last_ccount = comparison_count; + } + if (needle_last_ccount == NULL) + { + /* Try the Knuth-Morris-Pratt algorithm. */ + const unsigned char *result; + bool success = + knuth_morris_pratt ((const unsigned char *) haystack, + (const unsigned char *) (needle - 1), + strlen (needle - 1), + &result); + if (success) + return (char *) result; + try_kmp = false; + } + } + + outer_loop_count++; + comparison_count++; + if (TOLOWER ((unsigned char) *haystack) == b) + /* The first character matches. */ + { + const char *rhaystack = haystack + 1; + const char *rneedle = needle; + + for (;; rhaystack++, rneedle++) + { + if (*rneedle == '\0') + /* Found a match. */ + return (char *) haystack; + if (*rhaystack == '\0') + /* No match. */ + return NULL; + comparison_count++; + if (TOLOWER ((unsigned char) *rhaystack) + != TOLOWER ((unsigned char) *rneedle)) + /* Nothing in this round. */ + break; + } + } + } + } else - return (char *) haystack; + return (char *) haystack; } }