uchar C++ tests: Fix build error on FreeBSD 12.
[gnulib.git] / lib / mbmemcasecoll.c
blob195be30cec3e383b362310b3429eea95aaf88c50
1 /* Locale-specific case-ignoring memory comparison.
2 Copyright (C) 2001, 2009-2020 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2001.
5 This program is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as published
7 by 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "mbmemcasecoll.h"
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
27 /* Get tolower(). */
28 #include <ctype.h>
30 /* Get mbstate_t, mbrtowc(), wcrtomb(). */
31 #include <wchar.h>
33 /* Get towlower(). */
34 #include <wctype.h>
36 #include "malloca.h"
37 #include "memcmp2.h"
38 #include "memcoll.h"
40 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
42 /* Apply towlower() to the multibyte character sequence in INBUF, storing the
43 result as a multibyte character sequence in OUTBUF. */
44 static size_t
45 apply_towlower (const char *inbuf, size_t inbufsize,
46 char *outbuf, size_t outbufsize)
48 char *outbuf_orig = outbuf;
49 size_t remaining;
51 remaining = inbufsize;
52 while (remaining > 0)
54 wchar_t wc1;
55 size_t n1;
56 mbstate_t state;
58 memset (&state, '\0', sizeof (mbstate_t));
59 n1 = mbrtowc (&wc1, inbuf, remaining, &state);
60 if (n1 == (size_t)(-2))
61 break;
62 if (n1 != (size_t)(-1))
64 wint_t wc2;
66 if (n1 == 0) /* NUL character? */
67 n1 = 1;
69 wc2 = towlower (wc1);
70 if (wc2 != wc1)
72 size_t n2;
74 memset (&state, '\0', sizeof (mbstate_t));
75 n2 = wcrtomb (outbuf, wc2, &state);
76 if (n2 != (size_t)(-1))
78 /* Store the translated multibyte character. */
79 inbuf += n1;
80 remaining -= n1;
81 outbuf += n2;
82 continue;
86 /* Nothing to translate. */
87 memcpy (outbuf, inbuf, n1);
88 inbuf += n1;
89 remaining -= n1;
90 outbuf += n1;
91 continue;
94 /* Invalid multibyte character on input.
95 Copy one byte without modification. */
96 *outbuf++ = *inbuf++;
97 remaining -= 1;
99 /* Incomplete multibyte sequence on input.
100 Pass it through unmodified. */
101 while (remaining > 0)
103 *outbuf++ = *inbuf++;
104 remaining -= 1;
107 /* Verify the output buffer was large enough. */
108 if (outbuf - outbuf_orig > outbufsize)
109 abort ();
111 /* Return the number of written output bytes. */
112 return outbuf - outbuf_orig;
115 /* Apply tolower() to the unibyte character sequence in INBUF, storing the
116 result as a unibyte character sequence in OUTBUF. */
117 static void
118 apply_tolower (const char *inbuf, char *outbuf, size_t bufsize)
120 for (; bufsize > 0; bufsize--)
122 *outbuf = TOLOWER ((unsigned char) *inbuf);
123 inbuf++;
124 outbuf++;
129 mbmemcasecoll (const char *s1, size_t s1len, const char *s2, size_t s2len,
130 bool hard_LC_COLLATE)
132 char *t1;
133 size_t t1len;
134 char *t2;
135 size_t t2len;
136 char *memory;
137 int cmp;
139 if (MB_CUR_MAX > 1)
141 /* Application of towlower grows each character by a factor 2
142 at most. */
143 t1len = 2 * s1len;
144 t2len = 2 * s2len;
146 else
148 /* Application of tolower doesn't change the size. */
149 t1len = s1len;
150 t2len = s2len;
152 /* Allocate memory for t1 and t2. */
153 memory = (char *) malloca (t1len + 1 + t2len + 1);
154 if (memory == NULL)
156 errno = ENOMEM;
157 return 0;
159 t1 = memory;
160 t2 = memory + t1len + 1;
162 /* Csae-fold the two argument strings. */
163 if (MB_CUR_MAX > 1)
165 t1len = apply_towlower (s1, s1len, t1, t1len);
166 t2len = apply_towlower (s2, s2len, t2, t2len);
168 else
170 apply_tolower (s1, t1, s1len);
171 apply_tolower (s2, t2, s2len);
174 /* Compare the two case-folded strings. */
175 if (hard_LC_COLLATE)
176 cmp = memcoll (t1, t1len, t2, t2len);
177 else
179 cmp = memcmp2 (t1, t1len, t2, t2len);
180 errno = 0;
184 int saved_errno = errno;
185 freea (memory);
186 errno = saved_errno;
189 return cmp;