1 /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
26 bool no_leading_period
;
29 /* Match STRING against the file name pattern PATTERN, returning zero if
30 it matches, nonzero if not. */
31 static int FCT (const CHAR
*pattern
, const CHAR
*string
,
32 const CHAR
*string_end
, bool no_leading_period
, int flags
,
34 static int EXT (INT opt
, const CHAR
*pattern
, const CHAR
*string
,
35 const CHAR
*string_end
, bool no_leading_period
, int flags
);
36 static const CHAR
*END (const CHAR
*patternp
);
39 FCT (const CHAR
*pattern
, const CHAR
*string
, const CHAR
*string_end
,
40 bool no_leading_period
, int flags
, struct STRUCT
*ends
)
42 const CHAR
*p
= pattern
, *n
= string
;
45 # if WIDE_CHAR_VERSION
46 const char *collseq
= (const char *)
47 _NL_CURRENT(LC_COLLATE
, _NL_COLLATE_COLLSEQWC
);
49 const UCHAR
*collseq
= (const UCHAR
*)
50 _NL_CURRENT(LC_COLLATE
, _NL_COLLATE_COLLSEQMB
);
54 while ((c
= *p
++) != L_('\0'))
56 bool new_no_leading_period
= false;
62 if (__glibc_unlikely (flags
& FNM_EXTMATCH
) && *p
== '(')
64 int res
= EXT (c
, p
, n
, string_end
, no_leading_period
, flags
);
71 else if (*n
== L_('/') && (flags
& FNM_FILE_NAME
))
73 else if (*n
== L_('.') && no_leading_period
)
78 if (!(flags
& FNM_NOESCAPE
))
82 /* Trailing \ loses. */
86 if (n
== string_end
|| FOLD ((UCHAR
) *n
) != c
)
91 if (__glibc_unlikely (flags
& FNM_EXTMATCH
) && *p
== '(')
93 int res
= EXT (c
, p
, n
, string_end
, no_leading_period
, flags
);
97 else if (ends
!= NULL
)
99 ends
->pattern
= p
- 1;
101 ends
->no_leading_period
= no_leading_period
;
105 if (n
!= string_end
&& *n
== L_('.') && no_leading_period
)
108 for (c
= *p
++; c
== L_('?') || c
== L_('*'); c
= *p
++)
110 if (*p
== L_('(') && (flags
& FNM_EXTMATCH
) != 0)
112 const CHAR
*endp
= END (p
);
115 /* This is a pattern. Skip over it. */
123 /* A ? needs to match one character. */
125 /* There isn't another character; no match. */
127 else if (*n
== L_('/')
128 && __glibc_unlikely (flags
& FNM_FILE_NAME
))
129 /* A slash does not match a wildcard under
133 /* One character of the string is consumed in matching
134 this ? wildcard, so *??? won't match if there are
135 less than three characters. */
141 /* The wildcard(s) is/are the last element of the pattern.
142 If the name is a file name and contains another slash
143 this means it cannot match, unless the FNM_LEADING_DIR
146 int result
= (flags
& FNM_FILE_NAME
) == 0 ? 0 : FNM_NOMATCH
;
148 if (flags
& FNM_FILE_NAME
)
150 if (flags
& FNM_LEADING_DIR
)
154 if (MEMCHR (n
, L_('/'), string_end
- n
) == NULL
)
167 endp
= MEMCHR (n
, (flags
& FNM_FILE_NAME
) ? L_('/') : L_('\0'),
173 || (__glibc_unlikely (flags
& FNM_EXTMATCH
)
174 && (c
== L_('@') || c
== L_('+') || c
== L_('!'))
177 int flags2
= ((flags
& FNM_FILE_NAME
)
178 ? flags
: (flags
& ~FNM_PERIOD
));
180 for (--p
; n
< endp
; ++n
, no_leading_period
= false)
181 if (FCT (p
, n
, string_end
, no_leading_period
, flags2
,
185 else if (c
== L_('/') && (flags
& FNM_FILE_NAME
))
187 while (n
< string_end
&& *n
!= L_('/'))
189 if (n
< string_end
&& *n
== L_('/')
190 && (FCT (p
, n
+ 1, string_end
, flags
& FNM_PERIOD
, flags
,
196 int flags2
= ((flags
& FNM_FILE_NAME
)
197 ? flags
: (flags
& ~FNM_PERIOD
));
199 if (c
== L_('\\') && !(flags
& FNM_NOESCAPE
))
202 for (--p
; n
< endp
; ++n
, no_leading_period
= false)
203 if (FOLD ((UCHAR
) *n
) == c
204 && (FCT (p
, n
, string_end
, no_leading_period
, flags2
,
208 if (end
.pattern
== NULL
)
212 if (end
.pattern
!= NULL
)
216 no_leading_period
= end
.no_leading_period
;
222 /* If we come here no match is possible with the wildcard. */
227 /* Nonzero if the sense of the character class is inverted. */
228 const CHAR
*p_init
= p
;
229 const CHAR
*n_init
= n
;
234 if (posixly_correct
== 0)
235 posixly_correct
= getenv ("POSIXLY_CORRECT") != NULL
? 1 : -1;
240 if (*n
== L_('.') && no_leading_period
)
243 if (*n
== L_('/') && (flags
& FNM_FILE_NAME
))
244 /* '/' cannot be matched. */
247 not = (*p
== L_('!') || (posixly_correct
< 0 && *p
== L_('^')));
251 fn
= FOLD ((UCHAR
) *n
);
256 if (!(flags
& FNM_NOESCAPE
) && c
== L_('\\'))
260 c
= FOLD ((UCHAR
) *p
);
265 else if (c
== L_('[') && *p
== L_(':'))
267 /* Leave room for the null. */
268 CHAR str
[CHAR_CLASS_MAX_LENGTH
+ 1];
271 const CHAR
*startp
= p
;
275 if (c1
== CHAR_CLASS_MAX_LENGTH
)
276 /* The name is too long and therefore the pattern
281 if (c
== L_(':') && p
[1] == L_(']'))
286 if (c
< L_('a') || c
>= L_('z'))
288 /* This cannot possibly be a character class name.
289 Match it as a normal range. */
298 wt
= IS_CHAR_CLASS (str
);
300 /* Invalid character class name. */
303 #if defined _LIBC && ! WIDE_CHAR_VERSION
304 /* The following code is glibc specific but does
305 there a good job in speeding up the code since
306 we can avoid the btowc() call. */
307 if (_ISCTYPE ((UCHAR
) *n
, wt
))
310 if (iswctype (BTOWC ((UCHAR
) *n
), wt
))
316 else if (c
== L_('[') && *p
== L_('='))
318 /* It's important that STR be a scalar variable rather
319 than a one-element array, because GCC (at least 4.9.2
320 -O2 on x86-64) can be confused by the array and
321 diagnose a "used initialized" in a dead branch in the
325 _NL_CURRENT_WORD (LC_COLLATE
, _NL_COLLATE_NRULES
);
326 const CHAR
*startp
= p
;
338 if (c
!= L_('=') || p
[1] != L_(']'))
348 if ((UCHAR
) *n
== str
)
353 const int32_t *table
;
354 # if WIDE_CHAR_VERSION
355 const int32_t *weights
;
358 const unsigned char *weights
;
359 const unsigned char *extra
;
361 const int32_t *indirect
;
363 const UCHAR
*cp
= (const UCHAR
*) &str
;
365 # if WIDE_CHAR_VERSION
366 table
= (const int32_t *)
367 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_TABLEWC
);
368 weights
= (const int32_t *)
369 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_WEIGHTWC
);
370 extra
= (const wint_t *)
371 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_EXTRAWC
);
372 indirect
= (const int32_t *)
373 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_INDIRECTWC
);
375 table
= (const int32_t *)
376 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_TABLEMB
);
377 weights
= (const unsigned char *)
378 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_WEIGHTMB
);
379 extra
= (const unsigned char *)
380 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_EXTRAMB
);
381 indirect
= (const int32_t *)
382 _NL_CURRENT (LC_COLLATE
, _NL_COLLATE_INDIRECTMB
);
385 idx
= FINDIDX (table
, indirect
, extra
, &cp
, 1);
388 /* We found a table entry. Now see whether the
389 character we are currently at has the same
390 equivalence class value. */
391 int len
= weights
[idx
& 0xffffff];
393 const UCHAR
*np
= (const UCHAR
*) n
;
395 idx2
= FINDIDX (table
, indirect
, extra
,
396 &np
, string_end
- n
);
398 && (idx
>> 24) == (idx2
>> 24)
399 && len
== weights
[idx2
& 0xffffff])
407 && (weights
[idx
+ 1 + cnt
]
408 == weights
[idx2
+ 1 + cnt
]))
420 else if (c
== L_('\0'))
422 /* [ unterminated, treat as normal character. */
430 bool is_range
= false;
433 bool is_seqval
= false;
435 if (c
== L_('[') && *p
== L_('.'))
438 _NL_CURRENT_WORD (LC_COLLATE
, _NL_COLLATE_NRULES
);
439 const CHAR
*startp
= p
;
445 if (c
== L_('.') && p
[1] == L_(']'))
455 /* We have to handling the symbols differently in
456 ranges since then the collation sequence is
458 is_range
= *p
== L_('-') && p
[1] != L_('\0');
462 /* There are no names defined in the collation
463 data. Therefore we only accept the trivial
464 names consisting of the character itself. */
468 if (!is_range
&& *n
== startp
[1])
477 const int32_t *symb_table
;
478 const unsigned char *extra
;
481 # if WIDE_CHAR_VERSION
486 _NL_CURRENT_WORD (LC_COLLATE
,
487 _NL_COLLATE_SYMB_HASH_SIZEMB
);
488 symb_table
= (const int32_t *)
489 _NL_CURRENT (LC_COLLATE
,
490 _NL_COLLATE_SYMB_TABLEMB
);
491 extra
= (const unsigned char *)
492 _NL_CURRENT (LC_COLLATE
,
493 _NL_COLLATE_SYMB_EXTRAMB
);
495 for (elem
= 0; elem
< table_size
; elem
++)
496 if (symb_table
[2 * elem
] != 0)
498 idx
= symb_table
[2 * elem
+ 1];
499 /* Skip the name of collating element. */
500 idx
+= 1 + extra
[idx
];
501 # if WIDE_CHAR_VERSION
502 /* Skip the byte sequence of the
503 collating element. */
504 idx
+= 1 + extra
[idx
];
505 /* Adjust for the alignment. */
506 idx
= (idx
+ 3) & ~3;
508 wextra
= (CHAR
*) &extra
[idx
+ 4];
510 if (/* Compare the length of the sequence. */
512 /* Compare the wide char sequence. */
513 && (__wmemcmp (startp
+ 1, &wextra
[1],
516 /* Yep, this is the entry. */
519 if (/* Compare the length of the sequence. */
521 /* Compare the byte sequence. */
522 && memcmp (startp
+ 1,
523 &extra
[idx
+ 1], c1
) == 0)
524 /* Yep, this is the entry. */
529 if (elem
< table_size
)
531 /* Compare the byte sequence but only if
532 this is not part of a range. */
534 /* The compiler might warn that idx may be
535 used uninitialized, however it will be
536 reached iff elem < table_size which means
537 that it was properly set in the loop
539 DIAG_PUSH_NEEDS_COMMENT
;
540 DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
543 # if WIDE_CHAR_VERSION
544 && __wmemcmp (n
, &wextra
[1], c1
) == 0
546 && memcmp (n
, &extra
[idx
+ 1], c1
) == 0
553 DIAG_POP_NEEDS_COMMENT
;
555 /* Get the collation sequence value. */
557 # if WIDE_CHAR_VERSION
558 /* The compile might warn that wextra may be
559 used uninitialized and similar to 'idx'
560 above it will be properly set by the loop.
562 DIAG_PUSH_NEEDS_COMMENT
;
563 DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
564 cold
= wextra
[1 + wextra
[0]];
565 DIAG_POP_NEEDS_COMMENT
;
567 idx
+= 1 + extra
[idx
];
568 /* Adjust for the alignment. */
569 idx
= (idx
+ 3) & ~3;
570 cold
= *((int32_t *) &extra
[idx
]);
577 /* No valid character. Match it as a
579 if (!is_range
&& *n
== startp
[1])
595 /* We have to handling the symbols differently in
596 ranges since then the collation sequence is
598 is_range
= (*p
== L_('-') && p
[1] != L_('\0')
601 if (!is_range
&& c
== fn
)
605 /* This is needed if we goto normal_bracket; from
606 outside of is_seqval's scope. */
613 if (c
== L_('-') && *p
!= L_(']'))
616 /* We have to find the collation sequence
617 value for C. Collation sequence is nothing
618 we can regularly access. The sequence
619 value is defined by the order in which the
620 definitions of the collation values for the
621 various characters appear in the source
622 file. A strange concept, nowhere
628 # if WIDE_CHAR_VERSION
629 /* Search in the 'names' array for the characters. */
630 fcollseq
= __collseq_table_lookup (collseq
, fn
);
631 if (fcollseq
== ~((uint32_t) 0))
632 /* XXX We don't know anything about the character
633 we are supposed to match. This means we are
635 goto range_not_matched
;
640 lcollseq
= __collseq_table_lookup (collseq
, cold
);
642 fcollseq
= collseq
[fn
];
643 lcollseq
= is_seqval
? cold
: collseq
[(UCHAR
) cold
];
647 if (cend
== L_('[') && *p
== L_('.'))
650 _NL_CURRENT_WORD (LC_COLLATE
,
652 const CHAR
*startp
= p
;
658 if (c
== L_('.') && p
[1] == L_(']'))
670 /* There are no names defined in the
671 collation data. Therefore we only
672 accept the trivial names consisting
673 of the character itself. */
682 const int32_t *symb_table
;
683 const unsigned char *extra
;
686 # if WIDE_CHAR_VERSION
691 _NL_CURRENT_WORD (LC_COLLATE
,
692 _NL_COLLATE_SYMB_HASH_SIZEMB
);
693 symb_table
= (const int32_t *)
694 _NL_CURRENT (LC_COLLATE
,
695 _NL_COLLATE_SYMB_TABLEMB
);
696 extra
= (const unsigned char *)
697 _NL_CURRENT (LC_COLLATE
,
698 _NL_COLLATE_SYMB_EXTRAMB
);
700 for (elem
= 0; elem
< table_size
; elem
++)
701 if (symb_table
[2 * elem
] != 0)
703 idx
= symb_table
[2 * elem
+ 1];
704 /* Skip the name of collating
706 idx
+= 1 + extra
[idx
];
707 # if WIDE_CHAR_VERSION
708 /* Skip the byte sequence of the
709 collating element. */
710 idx
+= 1 + extra
[idx
];
711 /* Adjust for the alignment. */
712 idx
= (idx
+ 3) & ~3;
714 wextra
= (CHAR
*) &extra
[idx
+ 4];
716 if (/* Compare the length of the
719 /* Compare the wide char sequence. */
720 && (__wmemcmp (startp
+ 1,
723 /* Yep, this is the entry. */
726 if (/* Compare the length of the
729 /* Compare the byte sequence. */
730 && memcmp (startp
+ 1,
731 &extra
[idx
+ 1], c1
) == 0)
732 /* Yep, this is the entry. */
737 if (elem
< table_size
)
739 /* Get the collation sequence value. */
741 # if WIDE_CHAR_VERSION
742 /* The compiler might warn that wextra may
743 be used uninitialized, however it will
744 be reached iff elem < table_size which
745 means that it was properly set in the
747 DIAG_PUSH_NEEDS_COMMENT
;
748 DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
749 cend
= wextra
[1 + wextra
[0]];
750 DIAG_POP_NEEDS_COMMENT
;
752 /* The compile might warn that idx may
753 be used uninitialized and similar to
754 wextra above it will be properly set by
756 DIAG_PUSH_NEEDS_COMMENT
;
757 DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
758 idx
+= 1 + extra
[idx
];
759 DIAG_POP_NEEDS_COMMENT
;
760 /* Adjust for the alignment. */
761 idx
= (idx
+ 3) & ~3;
762 cend
= *((int32_t *) &extra
[idx
]);
776 if (!(flags
& FNM_NOESCAPE
) && cend
== L_('\\'))
778 if (cend
== L_('\0'))
783 /* XXX It is not entirely clear to me how to handle
784 characters which are not mentioned in the
785 collation specification. */
787 # if WIDE_CHAR_VERSION
788 lcollseq
== 0xffffffff ||
790 lcollseq
<= fcollseq
)
792 /* We have to look at the upper bound. */
799 # if WIDE_CHAR_VERSION
801 __collseq_table_lookup (collseq
, cend
);
802 if (hcollseq
== ~((uint32_t) 0))
804 /* Hum, no information about the upper
805 bound. The matching succeeds if the
806 lower bound is matched exactly. */
807 if (lcollseq
!= fcollseq
)
808 goto range_not_matched
;
813 hcollseq
= collseq
[cend
];
817 if (lcollseq
<= hcollseq
&& fcollseq
<= hcollseq
)
820 # if WIDE_CHAR_VERSION
824 /* We use a boring value comparison of the character
825 values. This is better than comparing using
826 'strcoll' since the latter would have surprising
827 and sometimes fatal consequences. */
830 if (!(flags
& FNM_NOESCAPE
) && cend
== L_('\\'))
832 if (cend
== L_('\0'))
836 if ((UCHAR
) cold
<= fn
&& fn
<= cend
)
853 /* Skip the rest of the [...] that already matched. */
854 while ((c
= *p
++) != L_(']'))
858 /* [ unterminated, treat as normal character. */
865 if (!(flags
& FNM_NOESCAPE
) && c
== L_('\\'))
869 /* XXX 1003.2d11 is unclear if this is right. */
872 else if (c
== L_('[') && *p
== L_(':'))
875 const CHAR
*startp
= p
;
880 if (++c1
== CHAR_CLASS_MAX_LENGTH
)
883 if (*p
== L_(':') && p
[1] == L_(']'))
886 if (c
< L_('a') || c
>= L_('z'))
894 else if (c
== L_('[') && *p
== L_('='))
900 if (c
!= L_('=') || p
[1] != L_(']'))
904 else if (c
== L_('[') && *p
== L_('.'))
912 if (c
== L_('.') && p
[1] == L_(']'))
926 if (__glibc_unlikely (flags
& FNM_EXTMATCH
) && *p
== '(')
928 int res
= EXT (c
, p
, n
, string_end
, no_leading_period
, flags
);
935 if (NO_LEADING_PERIOD (flags
))
937 if (n
== string_end
|| c
!= (UCHAR
) *n
)
940 new_no_leading_period
= true;
946 if (n
== string_end
|| c
!= FOLD ((UCHAR
) *n
))
950 no_leading_period
= new_no_leading_period
;
957 if ((flags
& FNM_LEADING_DIR
) && n
!= string_end
&& *n
== L_('/'))
958 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
966 END (const CHAR
*pattern
)
968 const CHAR
*p
= pattern
;
971 if (*++p
== L_('\0'))
972 /* This is an invalid pattern. */
974 else if (*p
== L_('['))
976 /* Handle brackets special. */
977 if (posixly_correct
== 0)
978 posixly_correct
= getenv ("POSIXLY_CORRECT") != NULL
? 1 : -1;
980 /* Skip the not sign. We have to recognize it because of a possibly
982 if (*++p
== L_('!') || (posixly_correct
< 0 && *p
== L_('^')))
984 /* A leading ']' is recognized as such. */
987 /* Skip over all characters of the list. */
988 while (*p
!= L_(']'))
989 if (*p
++ == L_('\0'))
990 /* This is no valid pattern. */
993 else if ((*p
== L_('?') || *p
== L_('*') || *p
== L_('+') || *p
== L_('@')
994 || *p
== L_('!')) && p
[1] == L_('('))
998 /* This is an invalid pattern. */
1001 else if (*p
== L_(')'))
1007 #if WIDE_CHAR_VERSION
1008 # define PATTERN_PREFIX pattern_list
1010 # define PATTERN_PREFIX wpattern_list
1013 #define PASTE(a,b) PASTE1(a,b)
1014 #define PASTE1(a,b) a##b
1016 #define DYNARRAY_STRUCT PATTERN_PREFIX
1017 #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
1018 #define DYNARRAY_ELEMENT CHAR *
1019 #define DYNARRAY_PREFIX PASTE(PATTERN_PREFIX,_)
1020 #define DYNARRAY_INITIAL_SIZE 8
1021 #include <malloc/dynarray-skeleton.c>
1024 EXT (INT opt
, const CHAR
*pattern
, const CHAR
*string
, const CHAR
*string_end
,
1025 bool no_leading_period
, int flags
)
1029 struct PATTERN_PREFIX list
;
1030 size_t pattern_len
= STRLEN (pattern
);
1031 size_t pattern_i
= 0;
1036 PASTE (PATTERN_PREFIX
, _init
) (&list
);
1038 /* Parse the pattern. Store the individual parts in the list. */
1040 for (startp
= p
= pattern
+ 1; level
>= 0; ++p
)
1043 /* This is an invalid pattern. */
1047 else if (*p
== L_('['))
1049 /* Handle brackets special. */
1050 if (posixly_correct
== 0)
1051 posixly_correct
= getenv ("POSIXLY_CORRECT") != NULL
? 1 : -1;
1053 /* Skip the not sign. We have to recognize it because of a possibly
1055 if (*++p
== L_('!') || (posixly_correct
< 0 && *p
== L_('^')))
1057 /* A leading ']' is recognized as such. */
1060 /* Skip over all characters of the list. */
1061 while (*p
!= L_(']'))
1062 if (*p
++ == L_('\0'))
1064 /* This is no valid pattern. */
1069 else if ((*p
== L_('?') || *p
== L_('*') || *p
== L_('+') || *p
== L_('@')
1070 || *p
== L_('!')) && p
[1] == L_('('))
1071 /* Remember the nesting level. */
1073 else if (*p
== L_(')') || *p
== L_('|'))
1077 size_t slen
= opt
== L_('?') || opt
== L_('@')
1078 ? pattern_len
: p
- startp
+ 1;
1079 CHAR
*newp
= malloc (slen
* sizeof (CHAR
));
1082 *((CHAR
*) MEMPCPY (newp
, startp
, p
- startp
)) = L_('\0');
1083 PASTE (PATTERN_PREFIX
,_add
) (&list
, newp
);
1085 if (newp
== NULL
|| PASTE (PATTERN_PREFIX
, _has_failed
) (&list
))
1097 assert (p
[-1] == L_(')'));
1102 if (FCT (p
, string
, string_end
, no_leading_period
, flags
, NULL
) == 0)
1106 for (; pattern_i
< PASTE (PATTERN_PREFIX
, _size
)(&list
); pattern_i
++)
1108 for (rs
= string
; rs
<= string_end
; ++rs
)
1109 /* First match the prefix with the current pattern with the
1111 if (FCT (*PASTE (PATTERN_PREFIX
, _at
) (&list
, pattern_i
), string
,
1112 rs
, no_leading_period
,
1113 flags
& FNM_FILE_NAME
? flags
: flags
& ~FNM_PERIOD
,
1115 /* This was successful. Now match the rest with the rest
1117 && (FCT (p
, rs
, string_end
,
1120 : rs
[-1] == '/' && NO_LEADING_PERIOD (flags
),
1121 flags
& FNM_FILE_NAME
1122 ? flags
: flags
& ~FNM_PERIOD
, NULL
) == 0
1123 /* This didn't work. Try the whole pattern. */
1125 && FCT (pattern
- 1, rs
, string_end
,
1128 : rs
[-1] == '/' && NO_LEADING_PERIOD (flags
),
1129 flags
& FNM_FILE_NAME
1130 ? flags
: flags
& ~FNM_PERIOD
, NULL
) == 0)))
1131 /* It worked. Signal success. */
1135 /* None of the patterns lead to a match. */
1136 retval
= FNM_NOMATCH
;
1140 if (FCT (p
, string
, string_end
, no_leading_period
, flags
, NULL
) == 0)
1144 for (; pattern_i
< PASTE (PATTERN_PREFIX
, _size
) (&list
); pattern_i
++)
1146 /* I cannot believe it but `strcat' is actually acceptable
1147 here. Match the entire string with the prefix from the
1148 pattern list and the rest of the pattern following the
1150 if (FCT (STRCAT (*PASTE (PATTERN_PREFIX
, _at
) (&list
, pattern_i
), p
),
1151 string
, string_end
, no_leading_period
,
1152 flags
& FNM_FILE_NAME
? flags
: flags
& ~FNM_PERIOD
,
1154 /* It worked. Signal success. */
1158 /* None of the patterns lead to a match. */
1159 retval
= FNM_NOMATCH
;
1163 for (rs
= string
; rs
<= string_end
; ++rs
)
1167 for (runp_i
= pattern_i
;
1168 runp_i
!= PASTE (PATTERN_PREFIX
, _size
) (&list
);
1171 if (FCT (*PASTE (PATTERN_PREFIX
, _at
) (&list
, runp_i
), string
, rs
,
1173 flags
& FNM_FILE_NAME
? flags
: flags
& ~FNM_PERIOD
,
1178 /* If none of the patterns matched see whether the rest does. */
1179 if (runp_i
== PASTE (PATTERN_PREFIX
, _size
) (&list
)
1180 && (FCT (p
, rs
, string_end
,
1183 : rs
[-1] == '/' && NO_LEADING_PERIOD (flags
),
1184 flags
& FNM_FILE_NAME
? flags
: flags
& ~FNM_PERIOD
,
1186 /* This is successful. */
1190 /* None of the patterns together with the rest of the pattern
1192 retval
= FNM_NOMATCH
;
1196 assert (! "Invalid extended matching operator");
1203 PASTE (PATTERN_PREFIX
, _free
) (&list
);
1208 #undef PATTERN_PREFIX
1226 #undef WIDE_CHAR_VERSION