e1f414c287f4376394553b8862809614dc1736d6
[gnulib.git] / lib / strcasecmp.c
1 /* Case-insensitive string comparison function.
2    Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2005,
4    based on earlier glibc code.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 /* Specification.  */
25 #include "strcase.h"
26
27 #include <ctype.h>
28
29 #if HAVE_MBRTOWC
30
31 #include "strnlen1.h"
32
33 /* Like mbiter.h, except it doesn't look at the entire string, only at
34    very few bytes past the current point.  */
35
36 #include "mbchar.h"
37
38 #include <assert.h>
39 #include <stdbool.h>
40 #include <stdlib.h>
41 #include <wchar.h>
42 #include <wctype.h>
43
44 struct mbiter_multi
45 {
46   bool in_shift;        /* true if next byte may not be interpreted as ASCII */
47   mbstate_t state;      /* if in_shift: current shift state */
48   bool next_done;       /* true if mbi_avail has already filled the following */
49   struct mbchar cur;    /* the current character:
50         const char *cur.ptr             pointer to current character
51         The following are only valid after mbi_avail.
52         size_t cur.bytes                number of bytes of current character
53         bool cur.wc_valid               true if wc is a valid wide character
54         wchar_t cur.wc                  if wc_valid: the current character
55         */
56 };
57
58 static inline void
59 mbiter_multi_next (struct mbiter_multi *iter)
60 {
61   if (iter->next_done)
62     return;
63   if (iter->in_shift)
64     goto with_shift;
65   /* Handle most ASCII characters quickly, without calling mbrtowc().  */
66   if (is_basic (*iter->cur.ptr))
67     {
68       /* These characters are part of the basic character set.  ISO C 99
69          guarantees that their wide character code is identical to their
70          char code.  */
71       iter->cur.bytes = 1;
72       iter->cur.wc = *iter->cur.ptr;
73       iter->cur.wc_valid = true;
74     }
75   else
76     {
77       assert (mbsinit (&iter->state));
78       iter->in_shift = true;
79     with_shift:
80       iter->cur.bytes = mbrtowc (&iter->cur.wc, iter->cur.ptr,
81                                  strnlen1 (iter->cur.ptr, MB_CUR_MAX),
82                                  &iter->state);
83       if (iter->cur.bytes == (size_t) -1)
84         {
85           /* An invalid multibyte sequence was encountered.  */
86           iter->cur.bytes = 1;
87           iter->cur.wc_valid = false;
88           /* Whether to set iter->in_shift = false and reset iter->state
89              or not is not very important; the string is bogus anyway.  */
90         }
91       else if (iter->cur.bytes == (size_t) -2)
92         {
93           /* An incomplete multibyte character at the end.  */
94           iter->cur.bytes = strlen (iter->cur.ptr) + 1;
95           iter->cur.wc_valid = false;
96           /* Whether to set iter->in_shift = false and reset iter->state
97              or not is not important; the string end is reached anyway.  */
98         }
99       else
100         {
101           if (iter->cur.bytes == 0)
102             {
103               /* A null wide character was encountered.  */
104               iter->cur.bytes = 1;
105               assert (*iter->cur.ptr == '\0');
106               assert (iter->cur.wc == 0);
107             }
108           iter->cur.wc_valid = true;
109
110           /* When in the initial state, we can go back treating ASCII
111              characters more quickly.  */
112           if (mbsinit (&iter->state))
113             iter->in_shift = false;
114         }
115     }
116   iter->next_done = true;
117 }
118
119 /* Iteration macros.  */
120 typedef struct mbiter_multi mbi_iterator_t;
121 #define mbi_init(iter, startptr) \
122   ((iter).cur.ptr = (startptr), \
123    (iter).in_shift = false, memset (&(iter).state, '\0', sizeof (mbstate_t)), \
124    (iter).next_done = false)
125 #define mbi_avail(iter) \
126   (mbiter_multi_next (&(iter)), !mb_isnul ((iter).cur))
127 #define mbi_advance(iter) \
128   ((iter).cur.ptr += (iter).cur.bytes, (iter).next_done = false)
129
130 /* Access to the current character.  */
131 #define mbi_cur(iter) (iter).cur
132 #define mbi_cur_ptr(iter) (iter).cur.ptr
133
134 #endif
135
136 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
137
138 /* Compare strings S1 and S2, ignoring case, returning less than, equal to or
139    greater than zero if S1 is lexicographically less than, equal to or greater
140    than S2.
141    Note: This function may, in multibyte locales, return 0 for strings of
142    different lengths!  */
143 int
144 strcasecmp (const char *s1, const char *s2)
145 {
146   if (s1 == s2)
147     return 0;
148
149   /* Be careful not to look at the entire extent of s1 or s2 until needed.
150      This is useful because when two strings differ, the difference is
151      most often already in the very few first characters.  */
152 #if HAVE_MBRTOWC
153   if (MB_CUR_MAX > 1)
154     {
155       mbi_iterator_t iter1;
156       mbi_iterator_t iter2;
157
158       mbi_init (iter1, s1);
159       mbi_init (iter2, s2);
160
161       while (mbi_avail (iter1) && mbi_avail (iter2))
162         {
163           int cmp = mb_casecmp (mbi_cur (iter1), mbi_cur (iter2));
164
165           if (cmp != 0)
166             return cmp;
167
168           mbi_advance (iter1);
169           mbi_advance (iter2);
170         }
171       if (mbi_avail (iter1))
172         /* s2 terminated before s1.  */
173         return 1;
174       if (mbi_avail (iter2))
175         /* s1 terminated before s2.  */
176         return -1;
177       return 0;
178     }
179   else
180 #endif
181     {
182       const unsigned char *p1 = (const unsigned char *) s1;
183       const unsigned char *p2 = (const unsigned char *) s2;
184       unsigned char c1, c2;
185
186       do
187         {
188           c1 = TOLOWER (*p1);
189           c2 = TOLOWER (*p2);
190
191           if (c1 == '\0')
192             break;
193
194           ++p1;
195           ++p2;
196         }
197       while (c1 == c2);
198
199       return c1 - c2;
200     }
201 }