1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997, 1999 Peter Mattis, Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
27 #include "gmessages.h"
32 /* keep enum and structure of gpattern.c and patterntest.c in sync */
35 G_MATCH_ALL
, /* "*A?A*" */
36 G_MATCH_ALL_TAIL
, /* "*A?AA" */
37 G_MATCH_HEAD
, /* "AAAA*" */
38 G_MATCH_TAIL
, /* "*AAAA" */
39 G_MATCH_EXACT
, /* "AAAAA" */
45 GMatchType match_type
;
52 /* --- functions --- */
54 static inline gboolean
55 g_pattern_ph_match (const gchar
*match_pattern
,
56 const gchar
*match_string
)
58 register const gchar
*pattern
, *string
;
61 pattern
= match_pattern
;
62 string
= match_string
;
73 string
= g_utf8_next_char (string
);
85 string
= g_utf8_next_char (string
);
88 while (ch
== '*' || ch
== '?');
97 string
= g_utf8_next_char (string
);
100 if (g_pattern_ph_match (pattern
, string
))
122 g_pattern_match (GPatternSpec
*pspec
,
125 const gchar
*string_reversed
)
127 g_return_val_if_fail (pspec
!= NULL
, FALSE
);
128 g_return_val_if_fail (string
!= NULL
, FALSE
);
130 if (pspec
->min_length
> string_length
)
133 switch (pspec
->match_type
)
136 return g_pattern_ph_match (pspec
->pattern
, string
);
137 case G_MATCH_ALL_TAIL
:
139 return g_pattern_ph_match (pspec
->pattern
, string_reversed
);
144 tmp
= g_utf8_strreverse (string
, string_length
);
145 result
= g_pattern_ph_match (pspec
->pattern
, tmp
);
150 if (pspec
->pattern_length
== string_length
)
151 return strcmp (pspec
->pattern
, string
) == 0;
152 else if (pspec
->pattern_length
)
153 return strncmp (pspec
->pattern
, string
, pspec
->pattern_length
) == 0;
157 if (pspec
->pattern_length
)
158 return strcmp (pspec
->pattern
, string
+ (string_length
- pspec
->pattern_length
)) == 0;
162 if (pspec
->pattern_length
!= string_length
)
165 return strcmp (pspec
->pattern
, string
) == 0;
167 g_return_val_if_fail (pspec
->match_type
< G_MATCH_LAST
, FALSE
);
173 g_pattern_spec_new (const gchar
*pattern
)
176 gboolean seen_joker
= FALSE
, seen_wildcard
= FALSE
, more_wildcards
= FALSE
;
177 gint hw_pos
= -1, tw_pos
= -1, hj_pos
= -1, tj_pos
= -1;
178 gboolean follows_wildcard
= FALSE
;
179 guint pending_jokers
= 0;
184 g_return_val_if_fail (pattern
!= NULL
, NULL
);
186 /* canonicalize pattern and collect necessary stats */
187 pspec
= g_new (GPatternSpec
, 1);
188 pspec
->pattern_length
= strlen (pattern
);
189 pspec
->min_length
= 0;
190 pspec
->pattern
= g_new (gchar
, pspec
->pattern_length
+ 1);
192 for (i
= 0, s
= pattern
; *s
!= 0; s
++)
197 if (follows_wildcard
) /* compress multiple wildcards */
199 pspec
->pattern_length
--;
202 follows_wildcard
= TRUE
;
212 for (; pending_jokers
; pending_jokers
--, i
++) {
218 follows_wildcard
= FALSE
;
225 for (; pending_jokers
; pending_jokers
--) {
232 seen_joker
= hj_pos
>= 0;
233 seen_wildcard
= hw_pos
>= 0;
234 more_wildcards
= seen_wildcard
&& hw_pos
!= tw_pos
;
236 /* special case sole head/tail wildcard or exact matches */
237 if (!seen_joker
&& !more_wildcards
)
239 if (pspec
->pattern
[0] == '*')
241 pspec
->match_type
= G_MATCH_TAIL
;
242 memmove (pspec
->pattern
, pspec
->pattern
+ 1, --pspec
->pattern_length
);
243 pspec
->pattern
[pspec
->pattern_length
] = 0;
246 if (pspec
->pattern_length
> 0 &&
247 pspec
->pattern
[pspec
->pattern_length
- 1] == '*')
249 pspec
->match_type
= G_MATCH_HEAD
;
250 pspec
->pattern
[--pspec
->pattern_length
] = 0;
255 pspec
->match_type
= G_MATCH_EXACT
;
260 /* now just need to distinguish between head or tail match start */
261 tw_pos
= pspec
->pattern_length
- 1 - tw_pos
; /* last pos to tail distance */
262 tj_pos
= pspec
->pattern_length
- 1 - tj_pos
; /* last pos to tail distance */
264 pspec
->match_type
= tw_pos
> hw_pos
? G_MATCH_ALL_TAIL
: G_MATCH_ALL
;
265 else /* seen_joker */
266 pspec
->match_type
= tj_pos
> hj_pos
? G_MATCH_ALL_TAIL
: G_MATCH_ALL
;
267 if (pspec
->match_type
== G_MATCH_ALL_TAIL
) {
268 gchar
*tmp
= pspec
->pattern
;
269 pspec
->pattern
= g_utf8_strreverse (pspec
->pattern
, pspec
->pattern_length
);
276 g_pattern_spec_free (GPatternSpec
*pspec
)
278 g_return_if_fail (pspec
!= NULL
);
280 g_free (pspec
->pattern
);
285 g_pattern_spec_equal (GPatternSpec
*pspec1
,
286 GPatternSpec
*pspec2
)
288 g_return_val_if_fail (pspec1
!= NULL
, FALSE
);
289 g_return_val_if_fail (pspec2
!= NULL
, FALSE
);
291 return (pspec1
->pattern_length
== pspec2
->pattern_length
&&
292 pspec1
->match_type
== pspec2
->match_type
&&
293 strcmp (pspec1
->pattern
, pspec2
->pattern
) == 0);
297 g_pattern_match_string (GPatternSpec
*pspec
,
300 g_return_val_if_fail (pspec
!= NULL
, FALSE
);
301 g_return_val_if_fail (string
!= NULL
, FALSE
);
303 return g_pattern_match (pspec
, strlen (string
), string
, NULL
);
307 g_pattern_match_simple (const gchar
*pattern
,
313 g_return_val_if_fail (pattern
!= NULL
, FALSE
);
314 g_return_val_if_fail (string
!= NULL
, FALSE
);
316 pspec
= g_pattern_spec_new (pattern
);
317 ergo
= g_pattern_match (pspec
, strlen (string
), string
, NULL
);
318 g_pattern_spec_free (pspec
);