xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/gnulib-lib/c-strcasestr.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /* c-strcasestr.c -- case insensitive substring search in C locale
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 "c-strcasestr.h"
23 
24 #include <stddef.h>
25 
26 #include "c-ctype.h"
27 
28 /* Find the first occurrence of NEEDLE in HAYSTACK, using case-insensitive
29    comparison.
30    Note: This function may, in multibyte locales, return success even if
31    strlen (haystack) < strlen (needle) !  */
32 char *
c_strcasestr(const char * haystack,const char * needle)33 c_strcasestr (const char *haystack, const char *needle)
34 {
35   /* Be careful not to look at the entire extent of haystack or needle
36      until needed.  This is useful because of these two cases:
37        - haystack may be very long, and a match of needle found early,
38        - needle may be very long, and not even a short initial segment of
39          needle may be found in haystack.  */
40   if (*needle != '\0')
41     {
42       /* Speed up the following searches of needle by caching its first
43 	 character.  */
44       unsigned char b = c_tolower ((unsigned char) *needle);
45 
46       needle++;
47       for (;; haystack++)
48 	{
49 	  if (*haystack == '\0')
50 	    /* No match.  */
51 	    return NULL;
52 	  if (c_tolower ((unsigned char) *haystack) == b)
53 	    /* The first character matches.  */
54 	    {
55 	      const char *rhaystack = haystack + 1;
56 	      const char *rneedle = needle;
57 
58 	      for (;; rhaystack++, rneedle++)
59 		{
60 		  if (*rneedle == '\0')
61 		    /* Found a match.  */
62 		    return (char *) haystack;
63 		  if (*rhaystack == '\0')
64 		    /* No match.  */
65 		    return NULL;
66 		  if (c_tolower ((unsigned char) *rhaystack)
67 		      != c_tolower ((unsigned char) *rneedle))
68 		    /* Nothing in this round.  */
69 		    break;
70 		}
71 	    }
72 	}
73     }
74   else
75     return (char *) haystack;
76 }
77