Simplify by using mb_casecmp.
[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.  */
34
35 #include "mbchar.h"
36
37 #include <assert.h>
38 #include <stdbool.h>
39 #include <stdlib.h>
40 #include <wchar.h>
41 #include <wctype.h>
42
43 struct mbiter_multi
44 {
45   bool at_end;          /* true if the end of the string has been reached */
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), (iter).at_end = false, \
123    (iter).in_shift = false, memset (&(iter).state, '\0', sizeof (mbstate_t)), \
124    (iter).next_done = false)
125 #define mbi_avail(iter) \
126   (!(iter).at_end && (mbiter_multi_next (&(iter)), true))
127 #define mbi_advance(iter) \
128   ((mb_isnul ((iter).cur) ? ((iter).at_end = true) : 0), \
129    (iter).cur.ptr += (iter).cur.bytes, (iter).next_done = false)
130
131 /* Access to the current character.  */
132 #define mbi_cur(iter) (iter).cur
133 #define mbi_cur_ptr(iter) (iter).cur.ptr
134
135 #endif
136
137 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
138
139 /* Compare strings S1 and S2, ignoring case, returning less than, equal to or
140    greater than zero if S1 is lexicographically less than, equal to or greater
141    than S2.
142    Note: This function may, in multibyte locales, return 0 for strings of
143    different lengths!  */
144 int
145 strcasecmp (const char *s1, const char *s2)
146 {
147   if (s1 == s2)
148     return 0;
149
150   /* Be careful not to look at the entire extent of s1 or s2 until needed.
151      This is useful because when two strings differ, the difference is
152      most often already in the very few first characters.  */
153 #if HAVE_MBRTOWC
154   if (MB_CUR_MAX > 1)
155     {
156       mbi_iterator_t iter1;
157       mbi_iterator_t iter2;
158
159       mbi_init (iter1, s1);
160       mbi_init (iter2, s2);
161
162       while (mbi_avail (iter1) && mbi_avail (iter2))
163         {
164           int cmp = mb_casecmp (mbi_cur (iter1), mbi_cur (iter2));
165
166           if (cmp != 0)
167             return cmp;
168
169           mbi_advance (iter1);
170           mbi_advance (iter2);
171         }
172       if (mbi_avail (iter1))
173         /* s2 terminated before s1.  */
174         return 1;
175       if (mbi_avail (iter2))
176         /* s1 terminated before s2.  */
177         return -1;
178       return 0;
179     }
180   else
181 #endif
182     {
183       const unsigned char *p1 = (const unsigned char *) s1;
184       const unsigned char *p2 = (const unsigned char *) s2;
185       unsigned char c1, c2;
186
187       do
188         {
189           c1 = TOLOWER (*p1);
190           c2 = TOLOWER (*p2);
191
192           if (c1 == '\0')
193             break;
194
195           ++p1;
196           ++p2;
197         }
198       while (c1 == c2);
199
200       return c1 - c2;
201     }
202 }