1 #ifndef ULINUX_UTILS_ASCII_MATCH_MATCH_C
2 #define ULINUX_UTILS_ASCII_MATCH_MATCH_C
4 * This is a derived work based on GNU glibc implementation on 20130409.
5 * Switch to GNU Lesser GPLv3 protection.
6 * author:Sylvain BERTRAND
8 /******************************************************************************/
10 * NOTE:do *NOT* even try to read that code without ksh extended glob
11 * specifications, and keeping an eye on the abbreviations below
13 * upstream code is hard to grasp
15 /******************************************************************************/
17 #include <ulinux/compiler_types.h>
18 #include <ulinux/types.h>
19 #include <ulinux/sysc.h>
20 #include <ulinux/error.h>
22 #include <ulinux/utils/mem.h>
23 #include <ulinux/utils/ascii/ascii.h>
24 #include <ulinux/utils/ascii/string/string.h>
25 #include <ulinux/utils/ascii/match/match.h>
26 #include <ulinux/mmap.h>
28 /*----------------------------------------------------------------------------*/
29 /* "One Compilation Unit" support */
30 #ifdef ULINUX_UTILS_EXTERNAL
33 #define ULINUX_EXPORT static
35 /*----------------------------------------------------------------------------*/
37 /*----------------------------------------------------------------------------*/
38 /* ulinux namespace */
40 #define ANONYMOUS ULINUX_MAP_ANONYMOUS
41 #define CASEFOLD ULINUX_MATCH_CASEFOLD
42 #define ERR ULINUX_MATCH_ERR
43 #define ERR_NOMEM ULINUX_MATCH_ERR_NOMEM
44 #define EXTMATCH ULINUX_MATCH_EXTMATCH
45 #define is_alnum ulinux_is_alnum
46 #define is_alpha ulinux_is_alpha
47 #define is_blank ulinux_is_blank
48 #define is_cntrl ulinux_is_cntrl
49 #define is_digit ulinux_is_digit
50 #define is_graph ulinux_is_graph
51 #define is_lower ulinux_is_lower
52 #define is_print ulinux_is_print
53 #define is_punct ulinux_is_punct
54 #define is_space ulinux_is_space
55 #define is_upper ulinux_is_upper
56 #define is_xdigit ulinux_is_xdigit
57 #define ISERR ULINUX_ISERR
59 #define MATCH ULINUX_MATCH_MATCH
60 #define memchr ulinux_memchr
61 #define memcpy ulinux_memcpy
62 #define mmap(a,b,c) ulinux_sysc(mmap,6,0,a,b,c,-1,0)
63 #define mremap(a,b,c) ulinux_sysc(mremap,4,a,b,c,0)
64 #define munmap(a,b) ulinux_sysc(munmap,2,a,b)
65 #define NOMATCH ULINUX_MATCH_NOMATCH
66 #define PRIVATE ULINUX_MAP_PRIVATE
67 #define RD ULINUX_PROT_READ
68 #define s64 ulinux_s64
70 #define u16 ulinux_u16
71 #define u64 ulinux_u64
73 #define strcat ulinux_strcat
74 #define strcmp ulinux_strcmp
75 #define strlen ulinux_strlen
76 #define WR ULINUX_PROT_WRITE
77 /*----------------------------------------------------------------------------*/
78 /* local symbols and types */
79 #define match_params ulinux_utils_ascii_match_match_params
80 #define fold ulinux_utils_ascii_match_fold
81 #define endp ulinux_utils_ascii_match_endp
82 #define star_handler ulinux_utils_ascii_match_star_handler
83 #define bracket_skip ulinux_utils_ascii_match_bracket_skip
84 #define bracket_matched ulinux_utils_ascii_match_bracket_matched
85 #define bracket_normal ulinux_utils_ascii_match_bracket_normal
86 #define bracket_char_class_get ulinux_utils_ascii_match_bracket_char_class_get
87 #define bracket_escape ulinux_utils_ascii_match_bracket_escape
88 #define bracket_class ulinux_utils_ascii_match_bracket_class
89 #define bracket_handler ulinux_utils_ascii_match_bracket_handler
90 #define question_mark_handler ulinux_utils_ascii_match_question_mark_handler
91 #define misc_handler ulinux_utils_ascii_match_misc_handler
92 #define escape_handler ulinux_utils_ascii_match_escape_handler
93 #define special_char ulinux_utils_ascii_match_special_char
94 #define match ulinux_utils_ascii_match_match
95 #define p ulinux_utils_ascii_match_p
96 #define ep ulinux_utils_ascii_match_ep
97 #define ep_p_new ulinux_utils_ascii_match_ep_p_new
98 #define ep_p_get ulinux_utils_ascii_match_ep_p_get
99 #define ep_p_next ulinux_utils_ascii_match_ep_p_next
100 #define ep_split ulinux_utils_ascii_match_ep_split
101 #define match_at_least_once ulinux_utils_ascii_match_match_at_least_once
102 #define match_only_once ulinux_utils_ascii_match_match_only_once
103 #define match_none ulinux_utils_ascii_match_match_none
104 #define extended_match_try ulinux_utils_ascii_match_extended_match_try
105 /*----------------------------------------------------------------------------*/
110 * char(s) character(s)
112 * ep(s) extended pattern(s)
127 /*----------------------------------------------------------------------------*/
128 #define CHAR_CLASS_MAX (sizeof("xdigit") - 1)
129 #define STREQ(s1,s2) (strcmp(s1, s2) == 0)
130 /*----------------------------------------------------------------------------*/
132 /*#define ULINUX_MATCH_ERR_NOMEM -3*/
133 /*#define ULINUX_MATCH_ERR -2*/
134 #define NO_VALID_P -1
135 /*#define ULINUX_MATCH_MATCH 0*/
137 /*#define ULINUX_MATCH_NOMATCH 1*/
138 /*----------------------------------------------------------------------------*/
140 * In the context a match call, it's used to store the location of the
141 * "ending" * following, at the same depth, a "starting" *.
142 * The matcher is locked in the star_handler between 2 stars at the
145 struct match_params
{
150 static u8
fold(u8 c
, u8 flgs
)
152 if(!(flgs
& CASEFOLD
))
154 return ulinux_2lower(c
);
158 * Recursively skip a p. Return a pointer right after it, or a pointer on the
159 *start of the p to skip if the 0 terminating char is encountered before the
162 static u8
*end_p(u8
*p
)
167 return p
; /* this is an invalid p */
168 else if (*pc
== '[') {/* handle brackets special */
170 * Skip the not sign. We have to recognize it because of
171 * a possibly following ']'.
173 if ((*++pc
== '!') || (*pc
== '^'))
176 ++pc
; /* a leading ']' is recognized as such */
177 /* skip over all chars of the list */
182 return p
; /* this is no valid p */
184 } else if (((*pc
== '?') || (*pc
== '*') || (*pc
== '+')
185 || (*pc
== '@') || (*pc
== '!')) && (pc
[1] == '(')) {
187 } else if (*pc
== ')') {
194 static s8
extended_match_try(u8 type
, u8
*p
, u8
*str
, u8
*str_end
, u8 flgs
);
195 static s8
match(u8
*p
, u8
*str
, u8
*str_end
, u8 flgs
,
196 struct match_params
*end_star
);
198 /*----------------------------------------------------------------------------*/
199 /* return value for the following handlers */
200 #define BIT(x) (1 << x)
201 #define R_GET(r) ((s8)(r & 0xff))
202 #define R_SET(r) ((u16)(r & 0xff))
203 #define RETURN_R BIT(9)
204 #define MATCH_NORMAL BIT(10)
205 #define NEXT_STR_CHAR BIT(11)
206 #define NEXT_P_CHAR BIT(12)
207 #define TEST_STR_END_REACHED BIT(13)
208 /*----------------------------------------------------------------------------*/
210 static u16
star_handler(u8
*c
, u8
**pc
, u8
**sc
, u8
*str_end
, u8 flgs
,
211 struct match_params
*end_star
)
213 struct match_params local_end_star
;
215 if ((flgs
& EXTMATCH
) && (**pc
== '(')) {
216 s8 r
= extended_match_try(*c
, *pc
, *sc
, str_end
, flgs
);
218 return RETURN_R
| R_SET(r
);
219 } else if (end_star
) {
220 /* this star will exit the current star context matching */
221 end_star
->p
= *pc
- 1;
223 return RETURN_R
| R_SET(MATCH
);
230 * do "absorb" in the current * the following sequence of
233 if ((*c
!= '?') && (*c
!= '*'))
237 * ?() and *() are "zero or one|more" occurences of matched
238 * patterns, then absorbed them in the *
240 if ((**pc
== '(') && (flgs
& EXTMATCH
)) {
241 u8
*endp
= end_p(*pc
);
242 if (endp
!= *pc
) { /* This is a p. Skip over it */
248 if (*c
== '?') { /* match one any char from the string */
249 /* a ? needs to match one char */
250 if (*sc
== str_end
) {
251 /* there isn't another char; no match */
252 return RETURN_R
| R_SET(NOMATCH
);
255 * one char of the str is consumed in matching
256 * this ? wildcard, so *??? won't match if there
257 * are less than three chars
264 /* the wildcard(s) is/are the last element of the p flag is set */
266 return RETURN_R
| R_SET(MATCH
);
268 local_end_star
.p
= 0;
270 if ((*c
== '[') || ((flgs
& EXTMATCH
) && ((*c
== '@') || (*c
== '+')
271 || (*c
=='!')) && (**pc
== '('))) {
272 /* the * is followed by a bracket or an "not absorbed" ep */
275 * See explanation of star context matching right below. Instead
276 * of a char like below, it's an ep.
282 r
= match(*pc
, *sc
, str_end
, flgs
, &local_end_star
);
284 if (local_end_star
.p
== 0)
285 return RETURN_R
| R_SET(MATCH
);
290 } else { /* the * is followed by a "normal" char */
296 * scan the str till we find a char which is the same than the
297 * first p char right after the *, then start to match in star
298 * context, namely till we reach the end, or we find another
299 * will will end the matching in that context
304 if(fold(**sc
, flgs
) == *c
) {
305 s8 r
= match(*pc
, *sc
, str_end
, flgs
,
308 if (local_end_star
.p
== 0)
309 return RETURN_R
| R_SET(MATCH
);
315 if (local_end_star
.p
!= 0) {
316 /* we are finish to match the str in star context */
317 *pc
= local_end_star
.p
;
318 *sc
= local_end_star
.str
;
322 /* if we come here no match is possible with the wildcard */
323 return RETURN_R
| R_SET(NOMATCH
);
326 static u16
bracket_skip(u8
*c
, u8
**pc
)
333 /* [... (unterminated) loses */
334 return RETURN_R
| R_SET(NOMATCH
);
339 return RETURN_R
| R_SET(NOMATCH
);
340 /* XXX 1003.2d11 is unclear if this is right */
342 } else if ((*c
== '[') && (**pc
== ':')) {
344 u8
*char_class_start_pc
= *pc
;
348 if (++char_class_n
== (CHAR_CLASS_MAX
+ 1))
349 return RETURN_R
| R_SET(NOMATCH
);
351 if ((**pc
== ':') && ((*pc
)[1] == ']'))
354 if ((*c
< 'a') || (*c
>= 'z')) {
355 /* is_lower(c) && is_weaker_alpha(c) */
356 *pc
= char_class_start_pc
;
357 goto ignore_next
; /* XXX: goto here */
369 static u16
bracket_matched(u8
*c
, u8
**pc
, u8
not)
371 u16 r
= bracket_skip(c
, pc
);
376 return RETURN_R
| R_SET(NOMATCH
);
377 return NEXT_STR_CHAR
;
380 /* input:*c may not be folded */
381 static u16
bracket_normal(u8
*c
, u8
**pc
, u8
not, u8 sc_folded
)
384 u8 is_range
= ((**pc
=='-') && ((*pc
)[1] != '\0') && ((*pc
)[1] != ']'));
386 if (!is_range
&& (*c
== sc_folded
))
387 return bracket_matched(c
, pc
, not);
392 if ((*c
== '-') && (**pc
!= ']')) {
398 return RETURN_R
| R_SET(NOMATCH
);
400 /* it is a range, ascii collation */
401 if ((c_old
<= sc_folded
) && (sc_folded
<= c_end
))
402 return bracket_matched(c
, pc
, not);
408 static u16
bracket_char_class_get(u8
*c
, u8
**pc
, u8
not, u8 sc_folded
,
412 u8
*char_class_start_pc
= *pc
;
415 if (char_class_n
== (CHAR_CLASS_MAX
+ 1))
416 return RETURN_R
| R_SET(NOMATCH
);
419 if ((*c
== ':') && ((*pc
)[1] == ']')) {
424 if ((*c
< 'a') || (*c
>= 'z')) {
425 /* is_lower(c) && is_weaker_alpha(c) */
428 * This cannot possibly be a char class name. Rewind and
429 * try to match it as a normal range.
431 *pc
= char_class_start_pc
;
433 r
= bracket_normal(c
, pc
, not, sc_folded
);
437 char_class
[char_class_n
++] = *c
;
439 char_class
[char_class_n
] = '\0';
443 static u16
bracket_escape(u8
*c
, u8
**pc
, u8 flgs
, u8
not, u8 sc_folded
)
448 return RETURN_R
| R_SET(NOMATCH
);
449 *c
= fold(**pc
, flgs
);
451 r
= bracket_normal(c
, pc
, not, sc_folded
);
457 /* input: *c=='[' **pc==':' */
458 static u16
bracket_class(u8
*c
, u8
**pc
, u8
**sc
, u8
not, u8 sc_folded
)
460 /*don't forget the 0 terminating char*/
461 u8 char_class
[CHAR_CLASS_MAX
+ 1];
462 u16 r
= bracket_char_class_get(c
, pc
, not, sc_folded
, &char_class
[0]);
466 if ( (STREQ(char_class
,"alnum") && is_alnum(**sc
))
467 || (STREQ(char_class
,"alpha") && is_alpha(**sc
))
468 || (STREQ(char_class
,"blank") && is_blank(**sc
))
469 || (STREQ(char_class
,"cntrl") && is_cntrl(**sc
))
470 || (STREQ(char_class
,"digit") && is_digit(**sc
))
471 || (STREQ(char_class
,"graph") && is_graph(**sc
))
472 || (STREQ(char_class
,"lower") && is_lower(**sc
))
473 || (STREQ(char_class
,"print") && is_print(**sc
))
474 || (STREQ(char_class
,"punct") && is_punct(**sc
))
475 || (STREQ(char_class
,"space") && is_space(**sc
))
476 || (STREQ(char_class
,"upper") && is_upper(**sc
))
477 || (STREQ(char_class
,"xdigit") && is_xdigit(**sc
)))
478 return bracket_matched(c
, pc
, not);
483 static u16
bracket_handler(u8
*c
, u8
**pc
, u8
**sc
, void *str_end
, u8 flgs
)
490 return RETURN_R
| R_SET(NOMATCH
);
492 not =((**pc
== '!') || (**pc
== '^'));
496 sc_folded
= fold(**sc
, flgs
);
501 u16 r
= bracket_escape(c
, pc
, flgs
, not, sc_folded
);
504 } else if ((*c
== '[') && (**pc
== ':')) {
505 u16 r
= bracket_class(c
, pc
, sc
, not, sc_folded
);
508 } else if (c
== '\0') {
510 * [ unterminated, rewind and tell above to match normal
518 r
= bracket_normal(c
, pc
, not, sc_folded
);
526 return RETURN_R
| R_SET(NOMATCH
);
527 return NEXT_STR_CHAR
;
530 static u16
question_mark_handler(u8 c
, u8
*pc
, u8
*sc
, void *str_end
, u8 flgs
)
532 if ((flgs
& EXTMATCH
) && (*pc
=='(')) {
533 s8 r
= extended_match_try(c
, pc
, sc
, str_end
, flgs
);
535 return RETURN_R
| R_SET(r
);
537 return TEST_STR_END_REACHED
;
540 static u16
misc_handler(u8 c
, u8
*pc
, u8
*sc
, void *str_end
, u8 flgs
)
542 if ((flgs
& EXTMATCH
) && (*pc
=='(')) {
543 s8 r
= extended_match_try(c
, pc
, sc
, str_end
, flgs
);
545 return RETURN_R
| R_SET(r
);
550 static u16
escape_handler(u8
*c
, u8
**pc
, u8 flgs
)
552 u16 r
= MATCH_NORMAL
;
555 return r
| RETURN_R
| R_SET(NOMATCH
); /*railing \ loses*/
560 static u16
special_char(u8
*c
, u8
**pc
, u8
**sc
, void *str_end
, u8 flgs
,
561 struct match_params
*end_star
)
563 u16 r
= RETURN_R
| R_SET(ERR
);
566 r
= bracket_handler(c
, pc
, sc
, str_end
, flgs
);
569 r
= star_handler(c
, pc
, sc
, str_end
, flgs
, end_star
);
572 r
= question_mark_handler(*c
, *pc
, *sc
, str_end
, flgs
);
577 r
= misc_handler(*c
, *pc
, *sc
, str_end
, flgs
);
580 r
= escape_handler(c
, pc
, flgs
);
586 /* str_end points right after the last char of str, the '\0' char */
587 static s8
match(u8
*p
, u8
*str
, u8
*str_end
, u8 flgs
,
588 struct match_params
*end_star
)
612 r
= special_char(&c
, &pc
, &sc
, str_end
, flgs
, end_star
);
618 if (!(r
& NEXT_STR_CHAR
)) {
623 if ((r
& MATCH_NORMAL
) || (r
& TEST_STR_END_REACHED
))
627 if (c
!= fold(*sc
, flgs
))
638 /*============================================================================*/
641 u64 sz
; /* not accounting the 0 terminating char */
646 u64 full_p_sz
; /* the p sz from which the ep belongs to */
648 s64 last
; /* offset */
650 u8
*p_rem
; /* remainder of the p (right and side of the ep) */
655 * based on the ep type, we may need to book enough room to put a worst case
656 * scenario of a concatenated sub-p with the ep p rem
658 static s8
ep_p_new(struct ep
*ep
,u8
*p_str
,u64 p_sz
)
661 * We will do some p concatenation for the following p types. Then book
662 * room for the worst case scenario.
668 u64 str_sz
= (ep
->type
== '?') || (ep
->type
== '@') ? ep
->full_p_sz
671 if (!ep
->ps
) {/* first allocation */
672 /* count the 0 terminating char */
673 map_sz
= sizeof(*ep
->ps
) + str_sz
+ 1;
674 addr
= mmap(map_sz
, RD
| WR
,PRIVATE
| ANONYMOUS
);
675 if (!addr
|| ISERR(addr
))
681 /* count the 0 terminating char */
682 u64 new_p_sz
= sizeof(*ep
->ps
) + str_sz
+ 1;
683 map_sz
= ep
->sz
+ new_p_sz
;
684 addr
= mremap(ep
->ps
, ep
->sz
, map_sz
);
685 if (!addr
|| ISERR(addr
))
686 return ERR_NOMEM
; /* ep is unmapped elsewhere */
688 p_last
=(struct p
*)((u8
*)(ep
->ps
) + ep
->last
);
689 /* count the 0 terminating char */
690 ep
->last
+= sizeof(*p_last
) + p_last
->sz
+ 1;
692 ep
->ps
= (struct p
*)addr
;
694 p
= (struct p
*)((u8
*)(ep
->ps
) + ep
->last
);
696 memcpy(&p
->str
[0], p_str
, p_sz
); /* copy only p_sz chars */
697 p
->str
[p_sz
] = 0; /* set the 0 terminating char */
701 static struct p
*ep_p_get(struct ep
*ep
, s64 of
)
703 return (struct p
*)((u8
*)(ep
->ps
) + of
);
707 static s64
ep_p_next(struct ep
*ep
, s64 p_of
)
709 struct p
*p
= (struct p
*)((u8
*)(ep
->ps
) + p_of
);
710 if (ep
->sz
== p_of
+ sizeof(*p
) + p
->sz
+ 1)
712 return p_of
+ sizeof(*p
) + p
->sz
+ 1;
715 /*============================================================================*/
718 * This function splits the ep in sub-ps which use '|' char as a separator. Deal
719 * with nested eps. Sub-ps are stored (copied) in a list (the ep struct)
721 * - p to point on the opening ( of the ep
722 * - ep is where the sub-patterns will be stored (copied)
724 * - p will point right after the closing ) fo the ep
725 * - ep will contain copies of all sub-ps of the ep
726 * if successful ep will contain at least one p
728 static s8
ep_split(u8
*p
, struct ep
*ep
)
731 s64 depth
; /* depth, if we have nested eps */
736 ++pc
; /* skip the opening ( */
747 }else if (*pc
== '[') { /* handle brackets special */
749 * Skip the not sign. We have to recognize it because of
750 * a possibly following ']'.
753 if ((*pc
== '!') || (*pc
== '^'))
757 ++pc
; /* a leading ']' is recognized as such */
759 loop
{ /* skip over all chars of the list */
768 } else if (((*pc
== '?') || (*pc
== '*') || (*pc
== '+')
769 || (*pc
== '@') || (*pc
== '!')) && (pc
[1] == '(')) {
770 ++depth
; /* remember the nesting depth of nested eps */
771 } else if (*pc
==')') {
772 /* this means we found the end of the ep */
774 r
= ep_p_new(ep
, sub_p_start
,
775 pc
- (u8
*)sub_p_start
);
780 } else if(*pc
== '|') {
782 r
= ep_p_new(ep
, sub_p_start
,
783 pc
- (u8
*)sub_p_start
);
791 /* store a pointer on the rem of the p, right after the closing ) */
797 static s8
match_at_least_once(struct ep
*ep
, u8
*p
, u8
*str
, u8
*str_end
,
802 struct p
*cur_p
= ep_p_get(ep
, cur_p_of
);
808 if (sc
> (u8
*)str_end
)
811 /* first match the prefix with the cur p */
812 r
= match(cur_p
->str
, str
, sc
, flgs
, 0);
815 * This was successful. Now match the str rem
818 r
= match(ep
->p_rem
, sc
, str_end
, flgs
, 0);
821 * Unable to match the p rem with the
822 * str rem, then try to match again the
823 * ep by rewinding the p from the start.
824 * We can because we are to match the ep
828 r
= match((u8
*)p
- 1, sc
,
833 } else if (r
== MATCH
) {
836 return r
; /* oops! */
840 cur_p_of
= ep_p_next(ep
, cur_p_of
);
841 if (cur_p_of
== NO_MORE_P
)
844 return NOMATCH
; /* none of the ps lead to a match */
847 static s8
match_only_once(struct ep
*ep
, u8
*str
, u8
*str_end
, u8 flgs
)
849 s64 cur_p_of
= 0; /* offset */
851 struct p
*cur_p
= ep_p_get(ep
, cur_p_of
);
853 * I cannot believe it but `strcat' is actually acceptable here.
854 * Match the entire str with the prefix from the ep and the
855 * rem of the p following the ep. We made room in the p str
856 * buffer in order to store the concatened p.
858 s8 r
= match(strcat(cur_p
->str
, ep
->p_rem
), str
, str_end
, flgs
,
863 cur_p_of
= ep_p_next(ep
, cur_p_of
);
864 if (cur_p_of
== NO_MORE_P
)
867 return NOMATCH
; /* none of the ps lead to a match */
870 static s8
match_none(struct ep
*ep
, u8
*str
, u8
*str_end
, u8 flgs
)
876 if (sc
> (u8
*)str_end
)
883 struct p
*cur_p
= ep_p_get(ep
, cur_p_of
);
885 r
= match(cur_p
->str
, str
, sc
, flgs
, 0);
889 cur_p_of
= ep_p_next(ep
, cur_p_of
);
890 if (cur_p_of
== NO_MORE_P
)
895 * if none of the ps matched see whether the p rem match the str
898 if (cur_p_of
== NO_MORE_P
) {
899 s8 r
= match(ep
->p_rem
, sc
, str_end
, flgs
, 0);
905 /* none of the ps together with the rem of the p lead to a match */
909 /* will return WATCH/NOMATCH/NO_VALID_P *and* misc errors */
910 static s8
extended_match_try(u8 type
, u8
*p
, u8
*str
, u8
*str_end
, u8 flgs
)
916 /* count the ep type char right befor the opening ( */
917 ep
.full_p_sz
= strlen(p
) + 1;
923 r
= ep_split(p
, &ep
);
927 /* from here, p_rem points right after the closing ) of the ep */
932 if (match(ep
.p_rem
, str
, str_end
, flgs
, 0) == MATCH
)
934 /* FALLTHROUGH to at least once sub-p matched */
936 r
= match_at_least_once(&ep
, p
, str
, str_end
, flgs
);
939 if (match(ep
.p_rem
, str
, str_end
, flgs
, 0) == MATCH
)
941 /* FALLTHROUGH to only once sub-p matched */
943 r
= match_only_once(&ep
, str
, str_end
, flgs
);
946 r
= match_none(&ep
, str
, str_end
, flgs
);
953 munmap(ep
.ps
, ep
.sz
);
957 ULINUX_EXPORT s8
ulinux_match(u8
*pattern
, u8
*str
, u8 flgs
)
959 return match(pattern
, str
,(u8
*)str
+ strlen(str
), flgs
, 0);
962 /*----------------------------------------------------------------------------*/
1002 /*----------------------------------------------------------------------------*/
1003 #undef CHAR_CLASS_MAX
1007 /*----------------------------------------------------------------------------*/
1013 #undef NEXT_STR_CHAR
1015 #undef TEST_STR_END_REACHED
1016 /*----------------------------------------------------------------------------*/
1018 /*----------------------------------------------------------------------------*/
1019 #undef ULINUX_EXPORT