dirent: Fix compilation error in C++ mode on OS/2 kLIBC.
[gnulib.git] / lib / unistr / u8-strchr.c
blob5ed822ff189c6135b7f88e2b3b92bdd511353c0d
1 /* Search character in UTF-8 string.
2 Copyright (C) 1999, 2002, 2006-2007, 2009-2021 Free Software Foundation,
3 Inc.
4 Written by Bruno Haible <bruno@clisp.org>, 2002.
6 This program is free software: you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19 #include <config.h>
21 /* Specification. */
22 #include "unistr.h"
24 #include <string.h>
26 uint8_t *
27 u8_strchr (const uint8_t *s, ucs4_t uc)
29 uint8_t c[6];
31 if (uc < 0x80)
33 uint8_t c0 = uc;
35 if (false)
37 /* Unoptimized code. */
38 for (;;)
40 uint8_t s0 = *s;
41 if (s0 == c0)
42 return (uint8_t *) s;
43 s++;
44 if (s0 == 0)
45 break;
48 else
50 /* Optimized code.
51 strchr() is often so well optimized, that it's worth the
52 added function call. */
53 return (uint8_t *) strchr ((const char *) s, c0);
56 else
57 /* Loops equivalent to strstr, optimized for a specific length (2, 3, 4)
58 of the needle. We use an algorithm similar to Boyer-Moore which
59 is documented in lib/unistr/u8-chr.c. There is additional
60 complication because we need to check after every byte for
61 a NUL byte, but the idea is the same. */
62 switch (u8_uctomb_aux (c, uc, 6))
64 case 2:
65 if (*s == 0 || s[1] == 0)
66 break;
68 uint8_t c0 = c[0];
69 uint8_t c1 = c[1];
70 /* Search for { c0, c1 }. */
71 uint8_t s1 = s[1];
73 for (;;)
75 /* Here s[0] != 0, s[1] != 0.
76 Test whether s[0..1] == { c0, c1 }. */
77 if (s1 == c1)
79 if (*s == c0)
80 return (uint8_t *) s;
81 else
82 /* Skip the search at s + 1, because s[1] = c1 < c0. */
83 goto case2_skip2;
85 else
87 if (s1 == c0)
88 goto case2_skip1;
89 else
90 /* Skip the search at s + 1, because s[1] != c0. */
91 goto case2_skip2;
93 case2_skip2:
94 s++;
95 s1 = s[1];
96 if (s[1] == 0)
97 break;
98 case2_skip1:
99 s++;
100 s1 = s[1];
101 if (s[1] == 0)
102 break;
105 break;
107 case 3:
108 if (*s == 0 || s[1] == 0 || s[2] == 0)
109 break;
111 uint8_t c0 = c[0];
112 uint8_t c1 = c[1];
113 uint8_t c2 = c[2];
114 /* Search for { c0, c1, c2 }. */
115 uint8_t s2 = s[2];
117 for (;;)
119 /* Here s[0] != 0, s[1] != 0, s[2] != 0.
120 Test whether s[0..2] == { c0, c1, c2 }. */
121 if (s2 == c2)
123 if (s[1] == c1 && *s == c0)
124 return (uint8_t *) s;
125 else
126 /* If c2 != c1:
127 Skip the search at s + 1, because s[2] == c2 != c1.
128 Skip the search at s + 2, because s[2] == c2 < c0. */
129 if (c2 == c1)
130 goto case3_skip1;
131 else
132 goto case3_skip3;
134 else
136 if (s2 == c1)
137 goto case3_skip1;
138 else if (s2 == c0)
139 /* Skip the search at s + 1, because s[2] != c1. */
140 goto case3_skip2;
141 else
142 /* Skip the search at s + 1, because s[2] != c1.
143 Skip the search at s + 2, because s[2] != c0. */
144 goto case3_skip3;
146 case3_skip3:
147 s++;
148 s2 = s[2];
149 if (s[2] == 0)
150 break;
151 case3_skip2:
152 s++;
153 s2 = s[2];
154 if (s[2] == 0)
155 break;
156 case3_skip1:
157 s++;
158 s2 = s[2];
159 if (s[2] == 0)
160 break;
163 break;
165 case 4:
166 if (*s == 0 || s[1] == 0 || s[2] == 0 || s[3] == 0)
167 break;
169 uint8_t c0 = c[0];
170 uint8_t c1 = c[1];
171 uint8_t c2 = c[2];
172 uint8_t c3 = c[3];
173 /* Search for { c0, c1, c2, c3 }. */
174 uint8_t s3 = s[3];
176 for (;;)
178 /* Here s[0] != 0, s[1] != 0, s[2] != 0, s[3] != 0.
179 Test whether s[0..3] == { c0, c1, c2, c3 }. */
180 if (s3 == c3)
182 if (s[2] == c2 && s[1] == c1 && *s == c0)
183 return (uint8_t *) s;
184 else
185 /* If c3 != c2:
186 Skip the search at s + 1, because s[3] == c3 != c2.
187 If c3 != c1:
188 Skip the search at s + 2, because s[3] == c3 != c1.
189 Skip the search at s + 3, because s[3] == c3 < c0. */
190 if (c3 == c2)
191 goto case4_skip1;
192 else if (c3 == c1)
193 goto case4_skip2;
194 else
195 goto case4_skip4;
197 else
199 if (s3 == c2)
200 goto case4_skip1;
201 else if (s3 == c1)
202 /* Skip the search at s + 1, because s[3] != c2. */
203 goto case4_skip2;
204 else if (s3 == c0)
205 /* Skip the search at s + 1, because s[3] != c2.
206 Skip the search at s + 2, because s[3] != c1. */
207 goto case4_skip3;
208 else
209 /* Skip the search at s + 1, because s[3] != c2.
210 Skip the search at s + 2, because s[3] != c1.
211 Skip the search at s + 3, because s[3] != c0. */
212 goto case4_skip4;
214 case4_skip4:
215 s++;
216 s3 = s[3];
217 if (s[3] == 0)
218 break;
219 case4_skip3:
220 s++;
221 s3 = s[3];
222 if (s[3] == 0)
223 break;
224 case4_skip2:
225 s++;
226 s3 = s[3];
227 if (s[3] == 0)
228 break;
229 case4_skip1:
230 s++;
231 s3 = s[3];
232 if (s[3] == 0)
233 break;
236 break;
239 return NULL;