Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/mbmemcasecoll.c @ 17605:23cb5b2fd95b
relocatable-perl: like relocatable-script, but for Perl scripts
* build-aux/relocatable.pl.in: Add.
* doc/relocatable-maint.texi: Add documentation.
* modules/relocatable-perl: Add.
author | Reuben Thomas <rrt@sc3d.org> |
---|---|
date | Thu, 09 Jan 2014 22:31:42 +0000 |
parents | 344018b6e5d7 |
children | ab58d4870664 |
rev | line source |
---|---|
11393 | 1 /* Locale-specific case-ignoring memory comparison. |
17587 | 2 Copyright (C) 2001, 2009-2014 Free Software Foundation, Inc. |
11393 | 3 Written by Bruno Haible <bruno@clisp.org>, 2001. |
4 | |
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. | |
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 GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public License | |
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | |
18 #include <config.h> | |
19 | |
20 /* Specification. */ | |
21 #include "mbmemcasecoll.h" | |
22 | |
23 #include <errno.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 | |
27 /* Get tolower(). */ | |
28 #include <ctype.h> | |
29 | |
30 /* Get mbstate_t, mbrtowc(), wcrtomb(). */ | |
31 #include <wchar.h> | |
32 | |
33 /* Get towlower(). */ | |
34 #include <wctype.h> | |
35 | |
36 #include "malloca.h" | |
37 #include "memcmp2.h" | |
38 #include "memcoll.h" | |
39 | |
40 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) | |
41 | |
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, | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
46 char *outbuf, size_t outbufsize) |
11393 | 47 { |
48 char *outbuf_orig = outbuf; | |
49 size_t remaining; | |
50 | |
51 remaining = inbufsize; | |
52 while (remaining > 0) | |
53 { | |
54 wchar_t wc1; | |
55 size_t n1; | |
56 mbstate_t state; | |
57 | |
58 memset (&state, '\0', sizeof (mbstate_t)); | |
59 n1 = mbrtowc (&wc1, inbuf, remaining, &state); | |
60 if (n1 == (size_t)(-2)) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
61 break; |
11393 | 62 if (n1 != (size_t)(-1)) |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
63 { |
13721
5cea8d40bf2c
Fix endless loop in mbmemcasecoll.
Bruno Haible <bruno@clisp.org>
parents:
12559
diff
changeset
|
64 wint_t wc2; |
11393 | 65 |
13721
5cea8d40bf2c
Fix endless loop in mbmemcasecoll.
Bruno Haible <bruno@clisp.org>
parents:
12559
diff
changeset
|
66 if (n1 == 0) /* NUL character? */ |
5cea8d40bf2c
Fix endless loop in mbmemcasecoll.
Bruno Haible <bruno@clisp.org>
parents:
12559
diff
changeset
|
67 n1 = 1; |
5cea8d40bf2c
Fix endless loop in mbmemcasecoll.
Bruno Haible <bruno@clisp.org>
parents:
12559
diff
changeset
|
68 |
5cea8d40bf2c
Fix endless loop in mbmemcasecoll.
Bruno Haible <bruno@clisp.org>
parents:
12559
diff
changeset
|
69 wc2 = towlower (wc1); |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
70 if (wc2 != wc1) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
71 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
72 size_t n2; |
11393 | 73 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
74 memset (&state, '\0', sizeof (mbstate_t)); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
75 n2 = wcrtomb (outbuf, wc2, &state); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
76 if (n2 != (size_t)(-1)) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
77 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
78 /* Store the translated multibyte character. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
79 inbuf += n1; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
80 remaining -= n1; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
81 outbuf += n2; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
82 continue; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
83 } |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
84 } |
11393 | 85 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
86 /* Nothing to translate. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
87 memcpy (outbuf, inbuf, n1); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
88 inbuf += n1; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
89 remaining -= n1; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
90 outbuf += n1; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
91 continue; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
92 } |
11393 | 93 |
94 /* Invalid multibyte character on input. | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
95 Copy one byte without modification. */ |
11393 | 96 *outbuf++ = *inbuf++; |
97 remaining -= 1; | |
98 } | |
99 /* Incomplete multibyte sequence on input. | |
100 Pass it through unmodified. */ | |
101 while (remaining > 0) | |
102 { | |
103 *outbuf++ = *inbuf++; | |
104 remaining -= 1; | |
105 } | |
106 | |
107 /* Verify the output buffer was large enough. */ | |
108 if (outbuf - outbuf_orig > outbufsize) | |
109 abort (); | |
110 | |
111 /* Return the number of written output bytes. */ | |
112 return outbuf - outbuf_orig; | |
113 } | |
114 | |
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) | |
119 { | |
120 for (; bufsize > 0; bufsize--) | |
121 { | |
122 *outbuf = TOLOWER ((unsigned char) *inbuf); | |
123 inbuf++; | |
124 outbuf++; | |
125 } | |
126 } | |
127 | |
128 int | |
129 mbmemcasecoll (const char *s1, size_t s1len, const char *s2, size_t s2len, | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
130 bool hard_LC_COLLATE) |
11393 | 131 { |
132 char *t1; | |
133 size_t t1len; | |
134 char *t2; | |
135 size_t t2len; | |
136 char *memory; | |
137 int cmp; | |
138 | |
139 if (MB_CUR_MAX > 1) | |
140 { | |
141 /* Application of towlower grows each character by a factor 2 | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
11393
diff
changeset
|
142 at most. */ |
11393 | 143 t1len = 2 * s1len; |
144 t2len = 2 * s2len; | |
145 } | |
146 else | |
147 { | |
148 /* Application of tolower doesn't change the size. */ | |
149 t1len = s1len; | |
150 t2len = s2len; | |
151 } | |
152 /* Allocate memory for t1 and t2. */ | |
153 memory = (char *) malloca (t1len + 1 + t2len + 1); | |
154 if (memory == NULL) | |
155 { | |
156 errno = ENOMEM; | |
157 return 0; | |
158 } | |
159 t1 = memory; | |
160 t2 = memory + t1len + 1; | |
161 | |
162 /* Csae-fold the two argument strings. */ | |
163 if (MB_CUR_MAX > 1) | |
164 { | |
165 t1len = apply_towlower (s1, s1len, t1, t1len); | |
166 t2len = apply_towlower (s2, s2len, t2, t2len); | |
167 } | |
168 else | |
169 { | |
170 apply_tolower (s1, t1, s1len); | |
171 apply_tolower (s2, t2, s2len); | |
172 } | |
173 | |
174 /* Compare the two case-folded strings. */ | |
175 if (hard_LC_COLLATE) | |
176 cmp = memcoll (t1, t1len, t2, t2len); | |
177 else | |
178 { | |
179 cmp = memcmp2 (t1, t1len, t2, t2len); | |
180 errno = 0; | |
181 } | |
182 | |
183 { | |
184 int saved_errno = errno; | |
185 freea (memory); | |
186 errno = saved_errno; | |
187 } | |
188 | |
189 return cmp; | |
190 } |