2 * Simple pattern matching
5 * Gonzalo Paniagua Javier (gonzalo@novell.com
7 * (C) 2006 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50 struct _GPatternSpec
{
55 compile_pattern (const gchar
*pattern
)
61 MatchType last
= MATCH_INVALID
;
71 str
= g_string_new ("");
72 for (i
= 0, len
= strlen (pattern
); i
< len
; i
++) {
74 if (c
== '*' || c
== '?') {
76 data
= g_new0 (PData
, 1);
77 data
->type
= MATCH_LITERAL
;
78 data
->str
= g_string_free (str
, FALSE
);
79 list
= g_slist_append (list
, data
);
80 str
= g_string_new ("");
83 if (last
== MATCH_ANYTHING
&& c
== '*')
86 data
= g_new0 (PData
, 1);
87 data
->type
= (c
== '*') ? MATCH_ANYTHING
: MATCH_ANYCHAR
;
88 list
= g_slist_append (list
, data
);
91 g_string_append_c (str
, c
);
96 if (last
== MATCH_ANYTHING
&& str
->len
== 0) {
97 data
->type
= MATCH_ANYTHING_END
;
99 } else if (str
->len
> 0) {
100 data
= g_new0 (PData
, 1);
101 data
->type
= MATCH_LITERAL
;
102 data
->str
= str
->str
;
104 list
= g_slist_append (list
, data
);
106 g_string_free (str
, free_str
);
112 print_pattern (gpointer data
, gpointer user_data
)
114 PData
*d
= (PData
*) data
;
116 printf ("Type: %s", d
->type
== MATCH_LITERAL
? "literal" : d
->type
== MATCH_ANYCHAR
? "any char" : "anything");
117 if (d
->type
== MATCH_LITERAL
)
118 printf (" String: %s", d
->str
);
124 g_pattern_spec_new (const gchar
*pattern
)
128 g_return_val_if_fail (pattern
!= NULL
, NULL
);
129 spec
= g_new0 (GPatternSpec
, 1);
131 spec
->pattern
= compile_pattern (pattern
);
133 g_slist_foreach (spec
->pattern
, print_pattern
, NULL
);
141 free_pdata (gpointer data
, gpointer user_data
)
143 PData
*d
= (PData
*) data
;
151 g_pattern_spec_free (GPatternSpec
*pspec
)
154 g_slist_foreach (pspec
->pattern
, free_pdata
, NULL
);
155 g_slist_free (pspec
->pattern
);
156 pspec
->pattern
= NULL
;
162 match_string (GSList
*list
, const gchar
*str
, size_t idx
, size_t max
)
166 while (list
&& idx
< max
) {
167 PData
*data
= (PData
*) list
->data
;
169 if (data
->type
== MATCH_ANYTHING_END
)
172 if (data
->type
== MATCH_LITERAL
) {
173 len
= strlen (data
->str
);
174 if (strncmp (&str
[idx
], data
->str
, len
) != 0)
180 * When recursing, we need this to avoid returning FALSE
181 * because 'list' will not be NULL
183 data
= (PData
*) list
->data
;
184 if (data
->type
== MATCH_ANYTHING_END
)
187 } else if (data
->type
== MATCH_ANYCHAR
) {
190 } else if (data
->type
== MATCH_ANYTHING
) {
192 if (match_string (list
->next
, str
, idx
++, max
))
197 g_assert_not_reached ();
201 return (list
== NULL
&& idx
>= max
);
204 g_pattern_match_string (GPatternSpec
*pspec
, const gchar
*string
)
206 g_return_val_if_fail (pspec
!= NULL
, FALSE
);
207 g_return_val_if_fail (string
!= NULL
, FALSE
);
209 if (pspec
->pattern
== NULL
)
211 return match_string (pspec
->pattern
, string
, 0, strlen (string
));