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.
48 struct _GPatternSpec {
53 compile_pattern (const gchar *pattern)
69 str = g_string_new ("");
70 for (i = 0, len = strlen (pattern); i < len; i++) {
72 if (c == '*' || c == '?') {
74 data = g_new0 (PData, 1);
75 data->type = MATCH_LITERAL;
76 data->str = g_string_free (str, FALSE);
77 list = g_slist_append (list, data);
78 str = g_string_new ("");
81 if (last == MATCH_ANYTHING && c == '*')
84 data = g_new0 (PData, 1);
85 data->type = (c == '*') ? MATCH_ANYTHING : MATCH_ANYCHAR;
86 list = g_slist_append (list, data);
89 g_string_append_c (str, c);
94 if (last == MATCH_ANYTHING && str->len == 0) {
95 data->type = MATCH_ANYTHING_END;
97 } else if (str->len > 0) {
98 data = g_new0 (PData, 1);
99 data->type = MATCH_LITERAL;
100 data->str = str->str;
102 list = g_slist_append (list, data);
104 g_string_free (str, free_str);
110 print_pattern (gpointer data, gpointer user_data)
112 PData *d = (PData *) data;
114 printf ("Type: %s", d->type == MATCH_LITERAL ? "literal" : d->type == MATCH_ANYCHAR ? "any char" : "anything");
115 if (d->type == MATCH_LITERAL)
116 printf (" String: %s", d->str);
122 g_pattern_spec_new (const gchar *pattern)
126 g_return_val_if_fail (pattern != NULL, NULL);
127 spec = g_new0 (GPatternSpec, 1);
129 spec->pattern = compile_pattern (pattern);
131 g_slist_foreach (spec->pattern, print_pattern, NULL);
139 free_pdata (gpointer data, gpointer user_data)
141 PData *d = (PData *) data;
149 g_pattern_spec_free (GPatternSpec *pspec)
152 g_slist_foreach (pspec->pattern, free_pdata, NULL);
153 g_slist_free (pspec->pattern);
154 pspec->pattern = NULL;
160 match_string (GSList *list, const gchar *str, gint idx, gint max)
164 while (list && idx < max) {
165 PData *data = (PData *) list->data;
167 if (data->type == MATCH_ANYTHING_END)
170 if (data->type == MATCH_LITERAL) {
171 len = strlen (data->str);
172 if (strncmp (&str [idx], data->str, len) != 0)
178 * When recursing, we need this to avoid returning FALSE
179 * because 'list' will not be NULL
181 data = (PData *) list->data;
182 if (data->type == MATCH_ANYTHING_END)
185 } else if (data->type == MATCH_ANYCHAR) {
188 } else if (data->type == MATCH_ANYTHING) {
190 if (match_string (list->next, str, idx++, max))
195 g_assert_not_reached ();
199 return (list == NULL && idx >= max);
202 g_pattern_match_string (GPatternSpec *pspec, const gchar *string)
204 g_return_val_if_fail (pspec != NULL, FALSE);
205 g_return_val_if_fail (string != NULL, FALSE);
207 if (pspec->pattern == NULL)
209 return match_string (pspec->pattern, string, 0, strlen (string));