xref: /titanic_41/usr/src/lib/libast/common/string/strmatch.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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 		return *b == 0;
97 
98 	/*
99 	 * convert flags
100 	 */
101 
102 	if (flags & REG_ADVANCE)
103 		reflags = flags & ~REG_ADVANCE;
104 	else
105 	{
106 		reflags = REG_SHELL|REG_AUGMENTED;
107 		if (!(flags & STR_MAXIMAL))
108 			reflags |= REG_MINIMAL;
109 		if (flags & STR_GROUP)
110 			reflags |= REG_SHELL_GROUP;
111 		if (flags & STR_LEFT)
112 			reflags |= REG_LEFT;
113 		if (flags & STR_RIGHT)
114 			reflags |= REG_RIGHT;
115 		if (flags & STR_ICASE)
116 			reflags |= REG_ICASE;
117 	}
118 	if (!sub || n <= 0)
119 		reflags |= REG_NOSUB;
120 	if (!(re = regcache(p, reflags, NiL)))
121 		return 0;
122 	if (n > matchstate.nmatch)
123 	{
124 		if (!(matchstate.match = newof(matchstate.match, regmatch_t, n, 0)))
125 			return 0;
126 		matchstate.nmatch = n;
127 	}
128 	if (regexec(re, b, n, matchstate.match, reflags & ~(REG_MINIMAL|REG_SHELL_GROUP|REG_LEFT|REG_RIGHT|REG_ICASE)))
129 		return 0;
130 	if (!sub || n <= 0)
131 		return 1;
132 	i = re->re_nsub;
133 	end = sub + n * 2;
134 	for (n = 0; sub < end && n <= i; n++)
135 	{
136 		*sub++ = matchstate.match[n].rm_so;
137 		*sub++ = matchstate.match[n].rm_eo;
138 	}
139 	return i + 1;
140 }
141 
142 /*
143  * compare the string s with the shell pattern p
144  * returns 1 for match 0 otherwise
145  */
146 
147 int
148 strmatch(const char* s, const char* p)
149 {
150 	return strgrpmatch(s, p, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT);
151 }
152 
153 /*
154  * leading substring match
155  * first char after end of substring returned
156  * 0 returned if no match
157  *
158  * OBSOLETE: use strgrpmatch()
159  */
160 
161 char*
162 strsubmatch(const char* s, const char* p, int flags)
163 {
164 	int	match[2];
165 
166 	return strgrpmatch(s, p, match, 1, (flags ? STR_MAXIMAL : 0)|STR_LEFT) ? (char*)s + match[1] : (char*)0;
167 }
168