1 /* Searching in a string. 2 Copyright (C) 2005-2006 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2005. 4 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 2, or (at your option) 8 any later version. 9 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. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 18 19 #include <config.h> 20 21 /* Specification. */ 22 #include "strstr.h" 23 24 #include <stddef.h> /* for NULL */ 25 26 #if HAVE_MBRTOWC 27 # include "mbuiter.h" 28 #endif 29 30 /* Find the first occurrence of NEEDLE in HAYSTACK. */ 31 char * 32 strstr (const char *haystack, const char *needle) 33 { 34 /* Be careful not to look at the entire extent of haystack or needle 35 until needed. This is useful because of these two cases: 36 - haystack may be very long, and a match of needle found early, 37 - needle may be very long, and not even a short initial segment of 38 needle may be found in haystack. */ 39 #if HAVE_MBRTOWC 40 if (MB_CUR_MAX > 1) 41 { 42 mbui_iterator_t iter_needle; 43 44 mbui_init (iter_needle, needle); 45 if (mbui_avail (iter_needle)) 46 { 47 mbui_iterator_t iter_haystack; 48 49 mbui_init (iter_haystack, haystack); 50 for (;; mbui_advance (iter_haystack)) 51 { 52 if (!mbui_avail (iter_haystack)) 53 /* No match. */ 54 return NULL; 55 56 if (mb_equal (mbui_cur (iter_haystack), mbui_cur (iter_needle))) 57 /* The first character matches. */ 58 { 59 mbui_iterator_t rhaystack; 60 mbui_iterator_t rneedle; 61 62 memcpy (&rhaystack, &iter_haystack, sizeof (mbui_iterator_t)); 63 mbui_advance (rhaystack); 64 65 mbui_init (rneedle, needle); 66 if (!mbui_avail (rneedle)) 67 abort (); 68 mbui_advance (rneedle); 69 70 for (;; mbui_advance (rhaystack), mbui_advance (rneedle)) 71 { 72 if (!mbui_avail (rneedle)) 73 /* Found a match. */ 74 return (char *) mbui_cur_ptr (iter_haystack); 75 if (!mbui_avail (rhaystack)) 76 /* No match. */ 77 return NULL; 78 if (!mb_equal (mbui_cur (rhaystack), mbui_cur (rneedle))) 79 /* Nothing in this round. */ 80 break; 81 } 82 } 83 } 84 } 85 else 86 return (char *) haystack; 87 } 88 else 89 #endif 90 { 91 if (*needle != '\0') 92 { 93 /* Speed up the following searches of needle by caching its first 94 character. */ 95 char b = *needle++; 96 97 for (;; haystack++) 98 { 99 if (*haystack == '\0') 100 /* No match. */ 101 return NULL; 102 if (*haystack == b) 103 /* The first character matches. */ 104 { 105 const char *rhaystack = haystack + 1; 106 const char *rneedle = needle; 107 108 for (;; rhaystack++, rneedle++) 109 { 110 if (*rneedle == '\0') 111 /* Found a match. */ 112 return (char *) haystack; 113 if (*rhaystack == '\0') 114 /* No match. */ 115 return NULL; 116 if (*rhaystack != *rneedle) 117 /* Nothing in this round. */ 118 break; 119 } 120 } 121 } 122 } 123 else 124 return (char *) haystack; 125 } 126 } 127