]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gnulib/import/fnmatch_loop.c
Update gnulib
[thirdparty/binutils-gdb.git] / gnulib / import / fnmatch_loop.c
CommitLineData
dc6c21da 1/* Copyright (C) 1991-2022 Free Software Foundation, Inc.
8690e634
JK
2 This file is part of the GNU C Library.
3
698be2d8 4 The GNU C Library is free software; you can redistribute it and/or
dc6c21da 5 modify it under the terms of the GNU Lesser General Public
698be2d8 6 License as published by the Free Software Foundation; either
dc6c21da 7 version 2.1 of the License, or (at your option) any later version.
8690e634 8
698be2d8 9 The GNU C Library is distributed in the hope that it will be useful,
8690e634 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
698be2d8 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dc6c21da 12 Lesser General Public License for more details.
8690e634 13
dc6c21da 14 You should have received a copy of the GNU Lesser General Public
698be2d8
CB
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18#ifdef _LIBC
19# include <stdint.h>
20#endif
21
22struct STRUCT
23{
24 const CHAR *pattern;
25 const CHAR *string;
26 bool no_leading_period;
27};
8690e634
JK
28
29/* Match STRING against the file name pattern PATTERN, returning zero if
30 it matches, nonzero if not. */
698be2d8
CB
31static int FCT (const CHAR *pattern, const CHAR *string,
32 const CHAR *string_end, bool no_leading_period, int flags,
33 struct STRUCT *ends, size_t alloca_used);
8690e634 34static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
698be2d8
CB
35 const CHAR *string_end, bool no_leading_period, int flags,
36 size_t alloca_used);
37static const CHAR *END (const CHAR *patternp);
8690e634
JK
38
39static int
8690e634 40FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
698be2d8 41 bool no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used)
8690e634 42{
698be2d8
CB
43 const CHAR *p = pattern, *n = string;
44 UCHAR c;
8690e634
JK
45#ifdef _LIBC
46# if WIDE_CHAR_VERSION
47 const char *collseq = (const char *)
48 _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
49# else
50 const UCHAR *collseq = (const UCHAR *)
51 _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
52# endif
53#endif
54
55 while ((c = *p++) != L_('\0'))
56 {
57 bool new_no_leading_period = false;
58 c = FOLD (c);
59
60 switch (c)
61 {
62 case L_('?'):
698be2d8 63 if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(')
8690e634 64 {
698be2d8
CB
65 int res = EXT (c, p, n, string_end, no_leading_period,
66 flags, alloca_used);
8690e634
JK
67 if (res != -1)
68 return res;
69 }
70
71 if (n == string_end)
72 return FNM_NOMATCH;
73 else if (*n == L_('/') && (flags & FNM_FILE_NAME))
74 return FNM_NOMATCH;
75 else if (*n == L_('.') && no_leading_period)
76 return FNM_NOMATCH;
77 break;
78
79 case L_('\\'):
80 if (!(flags & FNM_NOESCAPE))
81 {
82 c = *p++;
83 if (c == L_('\0'))
84 /* Trailing \ loses. */
85 return FNM_NOMATCH;
86 c = FOLD (c);
87 }
88 if (n == string_end || FOLD ((UCHAR) *n) != c)
89 return FNM_NOMATCH;
90 break;
91
92 case L_('*'):
698be2d8 93 if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(')
8690e634 94 {
698be2d8
CB
95 int res = EXT (c, p, n, string_end, no_leading_period,
96 flags, alloca_used);
8690e634
JK
97 if (res != -1)
98 return res;
99 }
698be2d8
CB
100 else if (ends != NULL)
101 {
102 ends->pattern = p - 1;
103 ends->string = n;
104 ends->no_leading_period = no_leading_period;
105 return 0;
106 }
8690e634
JK
107
108 if (n != string_end && *n == L_('.') && no_leading_period)
109 return FNM_NOMATCH;
110
111 for (c = *p++; c == L_('?') || c == L_('*'); c = *p++)
112 {
113 if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0)
114 {
115 const CHAR *endp = END (p);
116 if (endp != p)
117 {
118 /* This is a pattern. Skip over it. */
119 p = endp;
120 continue;
121 }
122 }
123
124 if (c == L_('?'))
125 {
126 /* A ? needs to match one character. */
127 if (n == string_end)
128 /* There isn't another character; no match. */
129 return FNM_NOMATCH;
130 else if (*n == L_('/')
698be2d8 131 && __glibc_unlikely (flags & FNM_FILE_NAME))
8690e634
JK
132 /* A slash does not match a wildcard under
133 FNM_FILE_NAME. */
134 return FNM_NOMATCH;
135 else
136 /* One character of the string is consumed in matching
137 this ? wildcard, so *??? won't match if there are
138 less than three characters. */
139 ++n;
140 }
141 }
142
143 if (c == L_('\0'))
144 /* The wildcard(s) is/are the last element of the pattern.
145 If the name is a file name and contains another slash
146 this means it cannot match, unless the FNM_LEADING_DIR
147 flag is set. */
148 {
149 int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
150
151 if (flags & FNM_FILE_NAME)
152 {
153 if (flags & FNM_LEADING_DIR)
154 result = 0;
155 else
156 {
157 if (MEMCHR (n, L_('/'), string_end - n) == NULL)
158 result = 0;
159 }
160 }
161
162 return result;
163 }
164 else
165 {
166 const CHAR *endp;
698be2d8 167 struct STRUCT end;
8690e634 168
698be2d8 169 end.pattern = NULL;
8690e634
JK
170 endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'),
171 string_end - n);
172 if (endp == NULL)
173 endp = string_end;
174
175 if (c == L_('[')
698be2d8 176 || (__glibc_unlikely (flags & FNM_EXTMATCH)
8690e634
JK
177 && (c == L_('@') || c == L_('+') || c == L_('!'))
178 && *p == L_('(')))
179 {
180 int flags2 = ((flags & FNM_FILE_NAME)
181 ? flags : (flags & ~FNM_PERIOD));
8690e634 182
698be2d8
CB
183 for (--p; n < endp; ++n, no_leading_period = false)
184 if (FCT (p, n, string_end, no_leading_period, flags2,
185 &end, alloca_used) == 0)
186 goto found;
8690e634
JK
187 }
188 else if (c == L_('/') && (flags & FNM_FILE_NAME))
189 {
190 while (n < string_end && *n != L_('/'))
191 ++n;
192 if (n < string_end && *n == L_('/')
698be2d8
CB
193 && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags,
194 NULL, alloca_used) == 0))
8690e634
JK
195 return 0;
196 }
197 else
198 {
199 int flags2 = ((flags & FNM_FILE_NAME)
200 ? flags : (flags & ~FNM_PERIOD));
8690e634
JK
201
202 if (c == L_('\\') && !(flags & FNM_NOESCAPE))
203 c = *p;
204 c = FOLD (c);
698be2d8 205 for (--p; n < endp; ++n, no_leading_period = false)
8690e634 206 if (FOLD ((UCHAR) *n) == c
698be2d8
CB
207 && (FCT (p, n, string_end, no_leading_period, flags2,
208 &end, alloca_used) == 0))
209 {
210 found:
211 if (end.pattern == NULL)
212 return 0;
213 break;
214 }
215 if (end.pattern != NULL)
216 {
217 p = end.pattern;
218 n = end.string;
219 no_leading_period = end.no_leading_period;
220 continue;
221 }
8690e634
JK
222 }
223 }
224
225 /* If we come here no match is possible with the wildcard. */
226 return FNM_NOMATCH;
227
228 case L_('['):
229 {
230 /* Nonzero if the sense of the character class is inverted. */
231 const CHAR *p_init = p;
232 const CHAR *n_init = n;
698be2d8 233 bool not;
8690e634
JK
234 CHAR cold;
235 UCHAR fn;
236
237 if (posixly_correct == 0)
238 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
239
240 if (n == string_end)
241 return FNM_NOMATCH;
242
243 if (*n == L_('.') && no_leading_period)
244 return FNM_NOMATCH;
245
246 if (*n == L_('/') && (flags & FNM_FILE_NAME))
247 /* '/' cannot be matched. */
248 return FNM_NOMATCH;
249
250 not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^')));
251 if (not)
252 ++p;
253
254 fn = FOLD ((UCHAR) *n);
255
256 c = *p++;
257 for (;;)
258 {
259 if (!(flags & FNM_NOESCAPE) && c == L_('\\'))
260 {
261 if (*p == L_('\0'))
262 return FNM_NOMATCH;
263 c = FOLD ((UCHAR) *p);
264 ++p;
265
266 goto normal_bracket;
267 }
268 else if (c == L_('[') && *p == L_(':'))
269 {
270 /* Leave room for the null. */
271 CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
272 size_t c1 = 0;
8690e634 273 wctype_t wt;
8690e634
JK
274 const CHAR *startp = p;
275
276 for (;;)
277 {
278 if (c1 == CHAR_CLASS_MAX_LENGTH)
279 /* The name is too long and therefore the pattern
280 is ill-formed. */
281 return FNM_NOMATCH;
282
283 c = *++p;
284 if (c == L_(':') && p[1] == L_(']'))
285 {
286 p += 2;
287 break;
288 }
289 if (c < L_('a') || c >= L_('z'))
290 {
291 /* This cannot possibly be a character class name.
292 Match it as a normal range. */
293 p = startp;
294 c = L_('[');
295 goto normal_bracket;
296 }
297 str[c1++] = c;
298 }
299 str[c1] = L_('\0');
300
8690e634
JK
301 wt = IS_CHAR_CLASS (str);
302 if (wt == 0)
303 /* Invalid character class name. */
304 return FNM_NOMATCH;
305
698be2d8 306#if defined _LIBC && ! WIDE_CHAR_VERSION
8690e634
JK
307 /* The following code is glibc specific but does
308 there a good job in speeding up the code since
309 we can avoid the btowc() call. */
310 if (_ISCTYPE ((UCHAR) *n, wt))
311 goto matched;
8690e634 312#else
698be2d8 313 if (iswctype (BTOWC ((UCHAR) *n), wt))
8690e634
JK
314 goto matched;
315#endif
316 c = *p++;
317 }
318#ifdef _LIBC
319 else if (c == L_('[') && *p == L_('='))
320 {
698be2d8
CB
321 /* It's important that STR be a scalar variable rather
322 than a one-element array, because GCC (at least 4.9.2
323 -O2 on x86-64) can be confused by the array and
324 diagnose a "used initialized" in a dead branch in the
325 findidx function. */
326 UCHAR str;
8690e634
JK
327 uint32_t nrules =
328 _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
329 const CHAR *startp = p;
330
331 c = *++p;
332 if (c == L_('\0'))
333 {
334 p = startp;
335 c = L_('[');
336 goto normal_bracket;
337 }
698be2d8 338 str = c;
8690e634
JK
339
340 c = *++p;
341 if (c != L_('=') || p[1] != L_(']'))
342 {
343 p = startp;
344 c = L_('[');
345 goto normal_bracket;
346 }
347 p += 2;
348
349 if (nrules == 0)
350 {
698be2d8 351 if ((UCHAR) *n == str)
8690e634
JK
352 goto matched;
353 }
354 else
355 {
356 const int32_t *table;
357# if WIDE_CHAR_VERSION
358 const int32_t *weights;
698be2d8 359 const wint_t *extra;
8690e634
JK
360# else
361 const unsigned char *weights;
362 const unsigned char *extra;
363# endif
364 const int32_t *indirect;
365 int32_t idx;
698be2d8 366 const UCHAR *cp = (const UCHAR *) &str;
8690e634
JK
367
368# if WIDE_CHAR_VERSION
369 table = (const int32_t *)
370 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
371 weights = (const int32_t *)
372 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
698be2d8 373 extra = (const wint_t *)
8690e634
JK
374 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
375 indirect = (const int32_t *)
376 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
377# else
378 table = (const int32_t *)
379 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
380 weights = (const unsigned char *)
381 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
382 extra = (const unsigned char *)
383 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
384 indirect = (const int32_t *)
385 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
386# endif
387
698be2d8 388 idx = FINDIDX (table, indirect, extra, &cp, 1);
8690e634
JK
389 if (idx != 0)
390 {
391 /* We found a table entry. Now see whether the
392 character we are currently at has the same
393 equivalence class value. */
394 int len = weights[idx & 0xffffff];
395 int32_t idx2;
396 const UCHAR *np = (const UCHAR *) n;
397
698be2d8
CB
398 idx2 = FINDIDX (table, indirect, extra,
399 &np, string_end - n);
8690e634
JK
400 if (idx2 != 0
401 && (idx >> 24) == (idx2 >> 24)
402 && len == weights[idx2 & 0xffffff])
403 {
404 int cnt = 0;
405
406 idx &= 0xffffff;
407 idx2 &= 0xffffff;
408
409 while (cnt < len
410 && (weights[idx + 1 + cnt]
411 == weights[idx2 + 1 + cnt]))
412 ++cnt;
413
414 if (cnt == len)
415 goto matched;
416 }
417 }
418 }
419
420 c = *p++;
421 }
422#endif
423 else if (c == L_('\0'))
424 {
425 /* [ unterminated, treat as normal character. */
426 p = p_init;
427 n = n_init;
428 c = L_('[');
429 goto normal_match;
430 }
431 else
432 {
698be2d8
CB
433 bool is_range = false;
434
8690e634
JK
435#ifdef _LIBC
436 bool is_seqval = false;
437
438 if (c == L_('[') && *p == L_('.'))
439 {
440 uint32_t nrules =
441 _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
442 const CHAR *startp = p;
443 size_t c1 = 0;
444
445 while (1)
446 {
447 c = *++p;
448 if (c == L_('.') && p[1] == L_(']'))
449 {
450 p += 2;
451 break;
452 }
453 if (c == '\0')
454 return FNM_NOMATCH;
455 ++c1;
456 }
457
458 /* We have to handling the symbols differently in
459 ranges since then the collation sequence is
460 important. */
461 is_range = *p == L_('-') && p[1] != L_('\0');
462
463 if (nrules == 0)
464 {
465 /* There are no names defined in the collation
466 data. Therefore we only accept the trivial
467 names consisting of the character itself. */
468 if (c1 != 1)
469 return FNM_NOMATCH;
470
471 if (!is_range && *n == startp[1])
472 goto matched;
473
474 cold = startp[1];
475 c = *p++;
476 }
477 else
478 {
479 int32_t table_size;
480 const int32_t *symb_table;
8690e634
JK
481 const unsigned char *extra;
482 int32_t idx;
483 int32_t elem;
698be2d8
CB
484# if WIDE_CHAR_VERSION
485 CHAR *wextra;
8690e634
JK
486# endif
487
488 table_size =
489 _NL_CURRENT_WORD (LC_COLLATE,
490 _NL_COLLATE_SYMB_HASH_SIZEMB);
491 symb_table = (const int32_t *)
492 _NL_CURRENT (LC_COLLATE,
493 _NL_COLLATE_SYMB_TABLEMB);
494 extra = (const unsigned char *)
495 _NL_CURRENT (LC_COLLATE,
496 _NL_COLLATE_SYMB_EXTRAMB);
497
698be2d8
CB
498 for (elem = 0; elem < table_size; elem++)
499 if (symb_table[2 * elem] != 0)
500 {
501 idx = symb_table[2 * elem + 1];
502 /* Skip the name of collating element. */
503 idx += 1 + extra[idx];
504# if WIDE_CHAR_VERSION
505 /* Skip the byte sequence of the
506 collating element. */
507 idx += 1 + extra[idx];
508 /* Adjust for the alignment. */
509 idx = (idx + 3) & ~3;
510
511 wextra = (CHAR *) &extra[idx + 4];
512
513 if (/* Compare the length of the sequence. */
514 c1 == wextra[0]
515 /* Compare the wide char sequence. */
516 && (__wmemcmp (startp + 1, &wextra[1],
517 c1)
518 == 0))
519 /* Yep, this is the entry. */
520 break;
521# else
522 if (/* Compare the length of the sequence. */
523 c1 == extra[idx]
524 /* Compare the byte sequence. */
525 && memcmp (startp + 1,
526 &extra[idx + 1], c1) == 0)
527 /* Yep, this is the entry. */
528 break;
529# endif
530 }
8690e634 531
698be2d8 532 if (elem < table_size)
8690e634
JK
533 {
534 /* Compare the byte sequence but only if
535 this is not part of a range. */
698be2d8 536 if (! is_range
8690e634 537
698be2d8
CB
538# if WIDE_CHAR_VERSION
539 && __wmemcmp (n, &wextra[1], c1) == 0
8690e634 540# else
698be2d8 541 && memcmp (n, &extra[idx + 1], c1) == 0
8690e634 542# endif
698be2d8
CB
543 )
544 {
545 n += c1 - 1;
546 goto matched;
8690e634
JK
547 }
548
549 /* Get the collation sequence value. */
550 is_seqval = true;
698be2d8 551# if WIDE_CHAR_VERSION
9c9d63b1 552 cold = wextra[1 + wextra[0]];
8690e634 553# else
8690e634 554 idx += 1 + extra[idx];
698be2d8
CB
555 /* Adjust for the alignment. */
556 idx = (idx + 3) & ~3;
8690e634
JK
557 cold = *((int32_t *) &extra[idx]);
558# endif
559
560 c = *p++;
561 }
562 else if (c1 == 1)
563 {
564 /* No valid character. Match it as a
565 single byte. */
698be2d8 566 if (!is_range && *n == startp[1])
8690e634
JK
567 goto matched;
568
698be2d8 569 cold = startp[1];
8690e634
JK
570 c = *p++;
571 }
572 else
573 return FNM_NOMATCH;
574 }
575 }
576 else
8690e634
JK
577#endif
578 {
579 c = FOLD (c);
580 normal_bracket:
581
582 /* We have to handling the symbols differently in
583 ranges since then the collation sequence is
584 important. */
585 is_range = (*p == L_('-') && p[1] != L_('\0')
586 && p[1] != L_(']'));
587
588 if (!is_range && c == fn)
589 goto matched;
590
591#if _LIBC
592 /* This is needed if we goto normal_bracket; from
593 outside of is_seqval's scope. */
594 is_seqval = false;
595#endif
8690e634
JK
596 cold = c;
597 c = *p++;
598 }
599
600 if (c == L_('-') && *p != L_(']'))
601 {
602#if _LIBC
603 /* We have to find the collation sequence
604 value for C. Collation sequence is nothing
605 we can regularly access. The sequence
606 value is defined by the order in which the
607 definitions of the collation values for the
608 various characters appear in the source
609 file. A strange concept, nowhere
610 documented. */
611 uint32_t fcollseq;
612 uint32_t lcollseq;
613 UCHAR cend = *p++;
614
698be2d8 615# if WIDE_CHAR_VERSION
8690e634
JK
616 /* Search in the 'names' array for the characters. */
617 fcollseq = __collseq_table_lookup (collseq, fn);
618 if (fcollseq == ~((uint32_t) 0))
619 /* XXX We don't know anything about the character
620 we are supposed to match. This means we are
621 failing. */
622 goto range_not_matched;
623
624 if (is_seqval)
625 lcollseq = cold;
626 else
627 lcollseq = __collseq_table_lookup (collseq, cold);
628# else
629 fcollseq = collseq[fn];
630 lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
631# endif
632
633 is_seqval = false;
634 if (cend == L_('[') && *p == L_('.'))
635 {
636 uint32_t nrules =
637 _NL_CURRENT_WORD (LC_COLLATE,
638 _NL_COLLATE_NRULES);
639 const CHAR *startp = p;
640 size_t c1 = 0;
641
642 while (1)
643 {
644 c = *++p;
645 if (c == L_('.') && p[1] == L_(']'))
646 {
647 p += 2;
648 break;
649 }
650 if (c == '\0')
651 return FNM_NOMATCH;
652 ++c1;
653 }
654
655 if (nrules == 0)
656 {
657 /* There are no names defined in the
658 collation data. Therefore we only
659 accept the trivial names consisting
660 of the character itself. */
661 if (c1 != 1)
662 return FNM_NOMATCH;
663
664 cend = startp[1];
665 }
666 else
667 {
668 int32_t table_size;
669 const int32_t *symb_table;
8690e634
JK
670 const unsigned char *extra;
671 int32_t idx;
672 int32_t elem;
698be2d8
CB
673# if WIDE_CHAR_VERSION
674 CHAR *wextra;
8690e634
JK
675# endif
676
677 table_size =
678 _NL_CURRENT_WORD (LC_COLLATE,
679 _NL_COLLATE_SYMB_HASH_SIZEMB);
680 symb_table = (const int32_t *)
681 _NL_CURRENT (LC_COLLATE,
682 _NL_COLLATE_SYMB_TABLEMB);
683 extra = (const unsigned char *)
684 _NL_CURRENT (LC_COLLATE,
685 _NL_COLLATE_SYMB_EXTRAMB);
686
698be2d8
CB
687 for (elem = 0; elem < table_size; elem++)
688 if (symb_table[2 * elem] != 0)
689 {
690 idx = symb_table[2 * elem + 1];
691 /* Skip the name of collating
692 element. */
693 idx += 1 + extra[idx];
694# if WIDE_CHAR_VERSION
695 /* Skip the byte sequence of the
696 collating element. */
697 idx += 1 + extra[idx];
698 /* Adjust for the alignment. */
699 idx = (idx + 3) & ~3;
700
701 wextra = (CHAR *) &extra[idx + 4];
702
703 if (/* Compare the length of the
704 sequence. */
705 c1 == wextra[0]
706 /* Compare the wide char sequence. */
707 && (__wmemcmp (startp + 1,
708 &wextra[1], c1)
709 == 0))
710 /* Yep, this is the entry. */
711 break;
712# else
713 if (/* Compare the length of the
714 sequence. */
715 c1 == extra[idx]
716 /* Compare the byte sequence. */
717 && memcmp (startp + 1,
718 &extra[idx + 1], c1) == 0)
719 /* Yep, this is the entry. */
720 break;
721# endif
722 }
8690e634 723
698be2d8 724 if (elem < table_size)
8690e634 725 {
8690e634
JK
726 /* Get the collation sequence value. */
727 is_seqval = true;
698be2d8 728# if WIDE_CHAR_VERSION
9c9d63b1 729 cend = wextra[1 + wextra[0]];
8690e634 730# else
8690e634 731 idx += 1 + extra[idx];
698be2d8
CB
732 /* Adjust for the alignment. */
733 idx = (idx + 3) & ~3;
8690e634
JK
734 cend = *((int32_t *) &extra[idx]);
735# endif
736 }
698be2d8 737 else if (c1 == 1)
8690e634 738 {
698be2d8 739 cend = startp[1];
8690e634
JK
740 c = *p++;
741 }
742 else
743 return FNM_NOMATCH;
744 }
8690e634
JK
745 }
746 else
747 {
748 if (!(flags & FNM_NOESCAPE) && cend == L_('\\'))
749 cend = *p++;
750 if (cend == L_('\0'))
751 return FNM_NOMATCH;
752 cend = FOLD (cend);
753 }
754
755 /* XXX It is not entirely clear to me how to handle
756 characters which are not mentioned in the
757 collation specification. */
758 if (
698be2d8 759# if WIDE_CHAR_VERSION
8690e634
JK
760 lcollseq == 0xffffffff ||
761# endif
762 lcollseq <= fcollseq)
763 {
764 /* We have to look at the upper bound. */
765 uint32_t hcollseq;
766
767 if (is_seqval)
768 hcollseq = cend;
769 else
770 {
698be2d8 771# if WIDE_CHAR_VERSION
8690e634
JK
772 hcollseq =
773 __collseq_table_lookup (collseq, cend);
774 if (hcollseq == ~((uint32_t) 0))
775 {
776 /* Hum, no information about the upper
777 bound. The matching succeeds if the
778 lower bound is matched exactly. */
779 if (lcollseq != fcollseq)
780 goto range_not_matched;
781
782 goto matched;
783 }
784# else
785 hcollseq = collseq[cend];
786# endif
787 }
788
789 if (lcollseq <= hcollseq && fcollseq <= hcollseq)
790 goto matched;
791 }
698be2d8 792# if WIDE_CHAR_VERSION
8690e634
JK
793 range_not_matched:
794# endif
795#else
796 /* We use a boring value comparison of the character
797 values. This is better than comparing using
798 'strcoll' since the latter would have surprising
799 and sometimes fatal consequences. */
800 UCHAR cend = *p++;
801
802 if (!(flags & FNM_NOESCAPE) && cend == L_('\\'))
803 cend = *p++;
804 if (cend == L_('\0'))
805 return FNM_NOMATCH;
806
807 /* It is a range. */
698be2d8 808 if ((UCHAR) cold <= fn && fn <= cend)
8690e634
JK
809 goto matched;
810#endif
811
812 c = *p++;
813 }
814 }
815
816 if (c == L_(']'))
817 break;
818 }
819
820 if (!not)
821 return FNM_NOMATCH;
822 break;
823
824 matched:
825 /* Skip the rest of the [...] that already matched. */
698be2d8 826 while ((c = *p++) != L_(']'))
8690e634 827 {
8690e634
JK
828 if (c == L_('\0'))
829 /* [... (unterminated) loses. */
830 return FNM_NOMATCH;
831
832 if (!(flags & FNM_NOESCAPE) && c == L_('\\'))
833 {
834 if (*p == L_('\0'))
835 return FNM_NOMATCH;
836 /* XXX 1003.2d11 is unclear if this is right. */
837 ++p;
838 }
839 else if (c == L_('[') && *p == L_(':'))
840 {
841 int c1 = 0;
842 const CHAR *startp = p;
843
844 while (1)
845 {
846 c = *++p;
847 if (++c1 == CHAR_CLASS_MAX_LENGTH)
848 return FNM_NOMATCH;
849
850 if (*p == L_(':') && p[1] == L_(']'))
851 break;
852
853 if (c < L_('a') || c >= L_('z'))
854 {
698be2d8
CB
855 p = startp - 2;
856 break;
8690e634
JK
857 }
858 }
859 p += 2;
8690e634
JK
860 }
861 else if (c == L_('[') && *p == L_('='))
862 {
863 c = *++p;
864 if (c == L_('\0'))
865 return FNM_NOMATCH;
866 c = *++p;
867 if (c != L_('=') || p[1] != L_(']'))
868 return FNM_NOMATCH;
869 p += 2;
8690e634
JK
870 }
871 else if (c == L_('[') && *p == L_('.'))
872 {
8690e634
JK
873 while (1)
874 {
875 c = *++p;
698be2d8 876 if (c == L_('\0'))
8690e634
JK
877 return FNM_NOMATCH;
878
698be2d8 879 if (c == L_('.') && p[1] == L_(']'))
8690e634
JK
880 break;
881 }
882 p += 2;
8690e634
JK
883 }
884 }
8690e634
JK
885 if (not)
886 return FNM_NOMATCH;
887 }
888 break;
889
890 case L_('+'):
891 case L_('@'):
892 case L_('!'):
698be2d8 893 if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(')
8690e634 894 {
698be2d8
CB
895 int res = EXT (c, p, n, string_end, no_leading_period, flags,
896 alloca_used);
8690e634
JK
897 if (res != -1)
898 return res;
899 }
900 goto normal_match;
901
902 case L_('/'):
903 if (NO_LEADING_PERIOD (flags))
904 {
905 if (n == string_end || c != (UCHAR) *n)
906 return FNM_NOMATCH;
907
908 new_no_leading_period = true;
909 break;
910 }
c0c3707f 911 FALLTHROUGH;
8690e634
JK
912 default:
913 normal_match:
914 if (n == string_end || c != FOLD ((UCHAR) *n))
915 return FNM_NOMATCH;
916 }
917
918 no_leading_period = new_no_leading_period;
919 ++n;
920 }
921
922 if (n == string_end)
923 return 0;
924
925 if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L_('/'))
926 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
927 return 0;
928
929 return FNM_NOMATCH;
930}
931
932
933static const CHAR *
8690e634
JK
934END (const CHAR *pattern)
935{
936 const CHAR *p = pattern;
937
938 while (1)
939 if (*++p == L_('\0'))
940 /* This is an invalid pattern. */
941 return pattern;
942 else if (*p == L_('['))
943 {
944 /* Handle brackets special. */
945 if (posixly_correct == 0)
946 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
947
948 /* Skip the not sign. We have to recognize it because of a possibly
949 following ']'. */
950 if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^')))
951 ++p;
952 /* A leading ']' is recognized as such. */
953 if (*p == L_(']'))
954 ++p;
955 /* Skip over all characters of the list. */
956 while (*p != L_(']'))
957 if (*p++ == L_('\0'))
958 /* This is no valid pattern. */
959 return pattern;
960 }
961 else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
962 || *p == L_('!')) && p[1] == L_('('))
698be2d8
CB
963 {
964 p = END (p + 1);
965 if (*p == L_('\0'))
966 /* This is an invalid pattern. */
967 return pattern;
968 }
8690e634
JK
969 else if (*p == L_(')'))
970 break;
971
972 return p + 1;
973}
974
975
976static int
8690e634 977EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
698be2d8 978 bool no_leading_period, int flags, size_t alloca_used)
8690e634
JK
979{
980 const CHAR *startp;
9c9d63b1 981 ptrdiff_t level;
8690e634
JK
982 struct patternlist
983 {
984 struct patternlist *next;
698be2d8 985 CHAR malloced;
9c9d63b1 986 CHAR str __flexarr;
8690e634
JK
987 } *list = NULL;
988 struct patternlist **lastp = &list;
989 size_t pattern_len = STRLEN (pattern);
698be2d8 990 bool any_malloced = false;
8690e634
JK
991 const CHAR *p;
992 const CHAR *rs;
698be2d8 993 int retval = 0;
8690e634
JK
994
995 /* Parse the pattern. Store the individual parts in the list. */
996 level = 0;
9c9d63b1 997 for (startp = p = pattern + 1; level >= 0; ++p)
8690e634 998 if (*p == L_('\0'))
698be2d8
CB
999 {
1000 /* This is an invalid pattern. */
1001 retval = -1;
1002 goto out;
1003 }
8690e634
JK
1004 else if (*p == L_('['))
1005 {
1006 /* Handle brackets special. */
1007 if (posixly_correct == 0)
1008 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
1009
1010 /* Skip the not sign. We have to recognize it because of a possibly
1011 following ']'. */
1012 if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^')))
1013 ++p;
1014 /* A leading ']' is recognized as such. */
1015 if (*p == L_(']'))
1016 ++p;
1017 /* Skip over all characters of the list. */
1018 while (*p != L_(']'))
1019 if (*p++ == L_('\0'))
698be2d8
CB
1020 {
1021 /* This is no valid pattern. */
1022 retval = -1;
1023 goto out;
1024 }
8690e634
JK
1025 }
1026 else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
1027 || *p == L_('!')) && p[1] == L_('('))
1028 /* Remember the nesting level. */
1029 ++level;
1030 else if (*p == L_(')'))
1031 {
1032 if (level-- == 0)
1033 {
1034 /* This means we found the end of the pattern. */
1035#define NEW_PATTERN \
1036 struct patternlist *newp; \
698be2d8
CB
1037 size_t plen = (opt == L_('?') || opt == L_('@') \
1038 ? pattern_len : (p - startp + 1UL)); \
9c9d63b1
PM
1039 idx_t slen = FLEXSIZEOF (struct patternlist, str, 0); \
1040 idx_t new_used = alloca_used + slen; \
1041 idx_t plensize; \
698be2d8
CB
1042 if (INT_MULTIPLY_WRAPV (plen, sizeof (CHAR), &plensize) \
1043 || INT_ADD_WRAPV (new_used, plensize, &new_used)) \
1044 { \
1045 retval = -2; \
1046 goto out; \
1047 } \
1048 slen += plensize; \
1049 bool malloced = ! __libc_use_alloca (new_used); \
1050 if (__glibc_unlikely (malloced)) \
1051 { \
1052 newp = malloc (slen); \
1053 if (newp == NULL) \
1054 { \
1055 retval = -2; \
1056 goto out; \
1057 } \
1058 any_malloced = true; \
1059 } \
1060 else \
1061 newp = alloca_account (slen, alloca_used); \
8690e634 1062 newp->next = NULL; \
698be2d8
CB
1063 newp->malloced = malloced; \
1064 *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \
8690e634
JK
1065 *lastp = newp; \
1066 lastp = &newp->next
1067 NEW_PATTERN;
8690e634
JK
1068 }
1069 }
1070 else if (*p == L_('|'))
1071 {
1072 if (level == 0)
1073 {
1074 NEW_PATTERN;
1075 startp = p + 1;
1076 }
1077 }
1078 assert (list != NULL);
1079 assert (p[-1] == L_(')'));
1080#undef NEW_PATTERN
1081
1082 switch (opt)
1083 {
1084 case L_('*'):
698be2d8
CB
1085 if (FCT (p, string, string_end, no_leading_period, flags, NULL,
1086 alloca_used) == 0)
1087 goto success;
c0c3707f 1088 FALLTHROUGH;
8690e634
JK
1089 case L_('+'):
1090 do
1091 {
1092 for (rs = string; rs <= string_end; ++rs)
1093 /* First match the prefix with the current pattern with the
1094 current pattern. */
1095 if (FCT (list->str, string, rs, no_leading_period,
698be2d8
CB
1096 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
1097 NULL, alloca_used) == 0
8690e634
JK
1098 /* This was successful. Now match the rest with the rest
1099 of the pattern. */
1100 && (FCT (p, rs, string_end,
1101 rs == string
1102 ? no_leading_period
1103 : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
1104 flags & FNM_FILE_NAME
698be2d8 1105 ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0
8690e634
JK
1106 /* This didn't work. Try the whole pattern. */
1107 || (rs != string
1108 && FCT (pattern - 1, rs, string_end,
1109 rs == string
1110 ? no_leading_period
1111 : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
1112 flags & FNM_FILE_NAME
698be2d8
CB
1113 ? flags : flags & ~FNM_PERIOD, NULL,
1114 alloca_used) == 0)))
8690e634 1115 /* It worked. Signal success. */
698be2d8 1116 goto success;
8690e634
JK
1117 }
1118 while ((list = list->next) != NULL);
1119
1120 /* None of the patterns lead to a match. */
698be2d8
CB
1121 retval = FNM_NOMATCH;
1122 break;
8690e634
JK
1123
1124 case L_('?'):
698be2d8
CB
1125 if (FCT (p, string, string_end, no_leading_period, flags, NULL,
1126 alloca_used) == 0)
1127 goto success;
c0c3707f 1128 FALLTHROUGH;
8690e634
JK
1129 case L_('@'):
1130 do
1131 /* I cannot believe it but 'strcat' is actually acceptable
1132 here. Match the entire string with the prefix from the
1133 pattern list and the rest of the pattern following the
1134 pattern list. */
1135 if (FCT (STRCAT (list->str, p), string, string_end,
1136 no_leading_period,
698be2d8
CB
1137 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
1138 NULL, alloca_used) == 0)
8690e634 1139 /* It worked. Signal success. */
698be2d8 1140 goto success;
8690e634
JK
1141 while ((list = list->next) != NULL);
1142
1143 /* None of the patterns lead to a match. */
698be2d8
CB
1144 retval = FNM_NOMATCH;
1145 break;
8690e634
JK
1146
1147 case L_('!'):
1148 for (rs = string; rs <= string_end; ++rs)
1149 {
1150 struct patternlist *runp;
1151
1152 for (runp = list; runp != NULL; runp = runp->next)
1153 if (FCT (runp->str, string, rs, no_leading_period,
698be2d8
CB
1154 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
1155 NULL, alloca_used) == 0)
8690e634
JK
1156 break;
1157
1158 /* If none of the patterns matched see whether the rest does. */
1159 if (runp == NULL
1160 && (FCT (p, rs, string_end,
1161 rs == string
1162 ? no_leading_period
1163 : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
698be2d8
CB
1164 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
1165 NULL, alloca_used) == 0))
8690e634 1166 /* This is successful. */
698be2d8 1167 goto success;
8690e634
JK
1168 }
1169
1170 /* None of the patterns together with the rest of the pattern
1171 lead to a match. */
698be2d8
CB
1172 retval = FNM_NOMATCH;
1173 break;
8690e634
JK
1174
1175 default:
1176 assert (! "Invalid extended matching operator");
698be2d8 1177 retval = -1;
8690e634
JK
1178 break;
1179 }
1180
698be2d8
CB
1181 success:
1182 out:
1183 if (any_malloced)
1184 while (list != NULL)
1185 {
1186 struct patternlist *old = list;
1187 list = list->next;
1188 if (old->malloced)
1189 free (old);
1190 }
1191
1192 return retval;
8690e634
JK
1193}
1194
1195
1196#undef FOLD
1197#undef CHAR
1198#undef UCHAR
1199#undef INT
1200#undef FCT
1201#undef EXT
1202#undef END
698be2d8 1203#undef STRUCT
8690e634
JK
1204#undef MEMPCPY
1205#undef MEMCHR
1206#undef STRLEN
1207#undef STRCAT
1208#undef L_
1209#undef BTOWC
698be2d8
CB
1210#undef WIDE_CHAR_VERSION
1211#undef FINDIDX