1 /* Searching in a string.
2 Copyright (C) 2005-2007 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2005.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include <stddef.h> /* for NULL, in case a nonstandard string.h lacks it */
31 /* Knuth-Morris-Pratt algorithm.
32 See http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm
33 Return a boolean indicating success. */
36 knuth_morris_pratt_unibyte (const char *haystack, const char *needle,
39 size_t m = strlen (needle);
41 /* Allocate the table. */
42 size_t *table = (size_t *) malloca (m * sizeof (size_t));
47 0 < table[i] <= i is defined such that
48 rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i]
50 forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1],
51 and table[i] is as large as possible with this property.
52 table[0] remains uninitialized. */
58 for (i = 2; i < m; i++)
60 unsigned char b = (unsigned char) needle[i - 1];
64 if (b == (unsigned char) needle[j])
79 /* Search, using the table to accelerate the processing. */
82 const char *rhaystack;
83 const char *phaystack;
89 /* Invariant: phaystack = rhaystack + j. */
90 while (*phaystack != '\0')
91 if ((unsigned char) needle[j] == (unsigned char) *phaystack)
97 /* The entire needle has been found. */
104 /* Found a match of needle[0..j-1], mismatch at needle[j]. */
105 rhaystack += table[j];
110 /* Found a mismatch at needle[0] already. */
122 knuth_morris_pratt_multibyte (const char *haystack, const char *needle,
123 const char **resultp)
125 size_t m = mbslen (needle);
126 mbchar_t *needle_mbchars;
129 /* Allocate room for needle_mbchars and the table. */
130 char *memory = (char *) malloca (m * (sizeof (mbchar_t) + sizeof (size_t)));
133 needle_mbchars = (mbchar_t *) memory;
134 table = (size_t *) (memory + m * sizeof (mbchar_t));
136 /* Fill needle_mbchars. */
138 mbui_iterator_t iter;
142 for (mbui_init (iter, needle); mbui_avail (iter); mbui_advance (iter), j++)
143 mb_copy (&needle_mbchars[j], &mbui_cur (iter));
148 0 < table[i] <= i is defined such that
149 rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i]
151 forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1],
152 and table[i] is as large as possible with this property.
153 table[0] remains uninitialized. */
159 for (i = 2; i < m; i++)
161 mbchar_t *b = &needle_mbchars[i - 1];
165 if (mb_equal (*b, needle_mbchars[j]))
180 /* Search, using the table to accelerate the processing. */
183 mbui_iterator_t rhaystack;
184 mbui_iterator_t phaystack;
188 mbui_init (rhaystack, haystack);
189 mbui_init (phaystack, haystack);
190 /* Invariant: phaystack = rhaystack + j. */
191 while (mbui_avail (phaystack))
192 if (mb_equal (needle_mbchars[j], mbui_cur (phaystack)))
195 mbui_advance (phaystack);
198 /* The entire needle has been found. */
199 *resultp = mbui_cur_ptr (rhaystack);
205 /* Found a match of needle[0..j-1], mismatch at needle[j]. */
206 size_t count = table[j];
208 for (; count > 0; count--)
210 if (!mbui_avail (rhaystack))
212 mbui_advance (rhaystack);
217 /* Found a mismatch at needle[0] already. */
218 if (!mbui_avail (rhaystack))
220 mbui_advance (rhaystack);
221 mbui_advance (phaystack);
230 /* Find the first occurrence of the character string NEEDLE in the character
231 string HAYSTACK. Return NULL if NEEDLE is not found in HAYSTACK. */
233 mbsstr (const char *haystack, const char *needle)
235 /* Be careful not to look at the entire extent of haystack or needle
236 until needed. This is useful because of these two cases:
237 - haystack may be very long, and a match of needle found early,
238 - needle may be very long, and not even a short initial segment of
239 needle may be found in haystack. */
243 mbui_iterator_t iter_needle;
245 mbui_init (iter_needle, needle);
246 if (mbui_avail (iter_needle))
248 /* Minimizing the worst-case complexity:
249 Let n = mbslen(haystack), m = mbslen(needle).
250 The naïve algorithm is O(n*m) worst-case.
251 The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a
253 To achieve linear complexity and yet amortize the cost of the
254 memory allocation, we activate the Knuth-Morris-Pratt algorithm
255 only once the naïve algorithm has already run for some time; more
257 - the outer loop count is >= 10,
258 - the average number of comparisons per outer loop is >= 5,
259 - the total number of comparisons is >= m.
260 But we try it only once. If the memory allocation attempt failed,
261 we don't retry it. */
263 size_t outer_loop_count = 0;
264 size_t comparison_count = 0;
265 size_t last_ccount = 0; /* last comparison count */
266 mbui_iterator_t iter_needle_last_ccount; /* = needle + last_ccount */
268 mbui_iterator_t iter_haystack;
270 mbui_init (iter_needle_last_ccount, needle);
271 mbui_init (iter_haystack, haystack);
272 for (;; mbui_advance (iter_haystack))
274 if (!mbui_avail (iter_haystack))
278 /* See whether it's advisable to use an asymptotically faster
281 && outer_loop_count >= 10
282 && comparison_count >= 5 * outer_loop_count)
284 /* See if needle + comparison_count now reaches the end of
286 size_t count = comparison_count - last_ccount;
288 count > 0 && mbui_avail (iter_needle_last_ccount);
290 mbui_advance (iter_needle_last_ccount);
291 last_ccount = comparison_count;
292 if (!mbui_avail (iter_needle_last_ccount))
294 /* Try the Knuth-Morris-Pratt algorithm. */
297 knuth_morris_pratt_multibyte (haystack, needle,
300 return (char *) result;
307 if (mb_equal (mbui_cur (iter_haystack), mbui_cur (iter_needle)))
308 /* The first character matches. */
310 mbui_iterator_t rhaystack;
311 mbui_iterator_t rneedle;
313 memcpy (&rhaystack, &iter_haystack, sizeof (mbui_iterator_t));
314 mbui_advance (rhaystack);
316 mbui_init (rneedle, needle);
317 if (!mbui_avail (rneedle))
319 mbui_advance (rneedle);
321 for (;; mbui_advance (rhaystack), mbui_advance (rneedle))
323 if (!mbui_avail (rneedle))
325 return (char *) mbui_cur_ptr (iter_haystack);
326 if (!mbui_avail (rhaystack))
330 if (!mb_equal (mbui_cur (rhaystack), mbui_cur (rneedle)))
331 /* Nothing in this round. */
338 return (char *) haystack;
345 /* Minimizing the worst-case complexity:
346 Let n = strlen(haystack), m = strlen(needle).
347 The naïve algorithm is O(n*m) worst-case.
348 The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a
350 To achieve linear complexity and yet amortize the cost of the
351 memory allocation, we activate the Knuth-Morris-Pratt algorithm
352 only once the naïve algorithm has already run for some time; more
354 - the outer loop count is >= 10,
355 - the average number of comparisons per outer loop is >= 5,
356 - the total number of comparisons is >= m.
357 But we try it only once. If the memory allocation attempt failed,
358 we don't retry it. */
360 size_t outer_loop_count = 0;
361 size_t comparison_count = 0;
362 size_t last_ccount = 0; /* last comparison count */
363 const char *needle_last_ccount = needle; /* = needle + last_ccount */
365 /* Speed up the following searches of needle by caching its first
371 if (*haystack == '\0')
375 /* See whether it's advisable to use an asymptotically faster
378 && outer_loop_count >= 10
379 && comparison_count >= 5 * outer_loop_count)
381 /* See if needle + comparison_count now reaches the end of
383 if (needle_last_ccount != NULL)
385 needle_last_ccount +=
386 strnlen (needle_last_ccount,
387 comparison_count - last_ccount);
388 if (*needle_last_ccount == '\0')
389 needle_last_ccount = NULL;
390 last_ccount = comparison_count;
392 if (needle_last_ccount == NULL)
394 /* Try the Knuth-Morris-Pratt algorithm. */
397 knuth_morris_pratt_unibyte (haystack, needle - 1,
400 return (char *) result;
408 /* The first character matches. */
410 const char *rhaystack = haystack + 1;
411 const char *rneedle = needle;
413 for (;; rhaystack++, rneedle++)
415 if (*rneedle == '\0')
417 return (char *) haystack;
418 if (*rhaystack == '\0')
422 if (*rhaystack != *rneedle)
423 /* Nothing in this round. */
430 return (char *) haystack;