xref: /titanic_41/usr/src/lib/libast/common/string/strmatch.c (revision bb294766735789e8f3edfcbac1edb83dfb9ee53b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2009 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 /*
25  * D. G. Korn
26  * G. S. Fowler
27  * AT&T Research
28  *
29  * match shell file patterns
30  * this interface is a wrapper on regex
31  *
32  *	sh pattern	egrep RE	description
33  *	----------	--------	-----------
34  *	*		.*		0 or more chars
35  *	?		.		any single char
36  *	[.]		[.]		char class
37  *	[!.]		[^.]		negated char class
38  *	[[:.:]]		[[:.:]]		ctype class
39  *	[[=.=]]		[[=.=]]		equivalence class
40  *	[[...]]		[[...]]		collation element
41  *	*(.)		(.)*		0 or more of
42  *	+(.)		(.)+		1 or more of
43  *	?(.)		(.)?		0 or 1 of
44  *	(.)		(.)		1 of
45  *	@(.)		(.)		1 of
46  *	a|b		a|b		a or b
47  *	\#				() subgroup back reference [1-9]
48  *	a&b				a and b
49  *	!(.)				none of
50  *
51  * \ used to escape metacharacters
52  *
53  *	*, ?, (, |, &, ), [, \ must be \'d outside of [...]
54  *	only ] must be \'d inside [...]
55  *
56  */
57 
58 #include <ast.h>
59 #include <regex.h>
60 
61 static struct State_s
62 {
63 	regmatch_t*	match;
64 	int		nmatch;
65 } matchstate;
66 
67 /*
68  * subgroup match
69  * 0 returned if no match
70  * otherwise number of subgroups matched returned
71  * match group begin offsets are even elements of sub
72  * match group end offsets are odd elements of sub
73  * the matched string is from s+sub[0] up to but not
74  * including s+sub[1]
75  */
76 
77 int
78 strgrpmatch(const char* b, const char* p, int* sub, int n, register int flags)
79 {
80 	register regex_t*	re;
81 	register int*		end;
82 	register int		i;
83 	register regflags_t	reflags;
84 
85 	/*
86 	 * 0 and empty patterns are special
87 	 */
88 
89 	if (!p || !b)
90 	{
91 		if (!p && !b)
92 			regcache(NiL, 0, NiL);
93 		return 0;
94 	}
95 	if (!*p)
96 	{
97 		if (sub && n > 0)
98 			sub[0] = sub[1] = 0;
99 		return *b == 0;
100 	}
101 
102 	/*
103 	 * convert flags
104 	 */
105 
106 	if (flags & REG_ADVANCE)
107 		reflags = flags & ~REG_ADVANCE;
108 	else
109 	{
110 		reflags = REG_SHELL|REG_AUGMENTED;
111 		if (!(flags & STR_MAXIMAL))
112 			reflags |= REG_MINIMAL;
113 		if (flags & STR_GROUP)
114 			reflags |= REG_SHELL_GROUP;
115 		if (flags & STR_LEFT)
116 			reflags |= REG_LEFT;
117 		if (flags & STR_RIGHT)
118 			reflags |= REG_RIGHT;
119 		if (flags & STR_ICASE)
120 			reflags |= REG_ICASE;
121 	}
122 	if (!sub || n <= 0)
123 		reflags |= REG_NOSUB;
124 	if (!(re = regcache(p, reflags, NiL)))
125 		return 0;
126 	if (n > matchstate.nmatch)
127 	{
128 		if (!(matchstate.match = newof(matchstate.match, regmatch_t, n, 0)))
129 			return 0;
130 		matchstate.nmatch = n;
131 	}
132 	if (regexec(re, b, n, matchstate.match, reflags & ~(REG_MINIMAL|REG_SHELL_GROUP|REG_LEFT|REG_RIGHT|REG_ICASE)))
133 		return 0;
134 	if (!sub || n <= 0)
135 		return 1;
136 	i = re->re_nsub;
137 	end = sub + n * 2;
138 	for (n = 0; sub < end && n <= i; n++)
139 	{
140 		*sub++ = matchstate.match[n].rm_so;
141 		*sub++ = matchstate.match[n].rm_eo;
142 	}
143 	return i + 1;
144 }
145 
146 /*
147  * compare the string s with the shell pattern p
148  * returns 1 for match 0 otherwise
149  */
150 
151 int
152 strmatch(const char* s, const char* p)
153 {
154 	return strgrpmatch(s, p, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT);
155 }
156 
157 /*
158  * leading substring match
159  * first char after end of substring returned
160  * 0 returned if no match
161  *
162  * OBSOLETE: use strgrpmatch()
163  */
164 
165 char*
166 strsubmatch(const char* s, const char* p, int flags)
167 {
168 	int	match[2];
169 
170 	return strgrpmatch(s, p, match, 1, (flags ? STR_MAXIMAL : 0)|STR_LEFT) ? (char*)s + match[1] : (char*)0;
171 }
172