4 * Full file wildcard matching
6 * © 1998 Straylight/Edgeware
9 /*----- Licensing note ----------------------------------------------------*
11 * This file is part of Straylight's core utilities (coreutils).
13 * Coreutils is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * Coreutils is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with coreutils. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /*----- Header files ------------------------------------------------------*/
42 /*----- Type definitions --------------------------------------------------*/
44 typedef struct glob_ctx {
45 char buf[1024]; /* Pointer to output buffer */
46 void (*proc)(const char *, void *); /* User procedure */
47 void *ctx; /* Context to pass the procedure */
48 int done; /* Number of matches found */
51 /*----- Main code ---------------------------------------------------------*/
53 /* --- Wildcard syntax --- *
55 * The wildcards `*' and `#' do what they normally do: match zero-or-more
56 * and any-one characters respectively. Additionally, a `.' where a
57 * filename is expected will search recursively down the directory
58 * structure. Only globby matches with really existing things are counted;
59 * if a name contains nothing globbable then it matches nothing. This is
60 * done for speed: I expect the client to use a name literally if it fails
61 * to match anything. The syntax is a sort of blend between traditional
62 * RISC OS and kpathsea.
65 /* --- Hack note --- *
67 * This will fail gloriously given something like `adfs::ak*ha.$.foo.*'.
68 * Do I look like I care? This program has already taken five times longer
69 * than it should have done because I decided I wanted to do wildcarding.
72 /* --- Forward reference --- */
74 static void glob_do(glob_ctx *g, char *p, char *in);
76 /* --- @glob_got@ --- *
78 * Arguments: @glob_ctx *g@ = pointer to my context
79 * @char *p@ = pointer to current position in buffer
80 * @char *fn@ = filename to add
81 * @char *in@ = rest of wildcard pattern to match
85 * Use: Handles a matched filename in the glob matcher.
88 static void glob_got(glob_ctx *g, char *p, char *fn, char *in)
92 /* --- Build the filename --- */
97 memcpy(p, fn, sz + 1);
100 /* --- See if this is the final element --- */
105 if (_swix(OS_File, _inr(0, 1) | _out(0), 17, g->buf, &ty) || !ty)
108 g->proc(g->buf, g->ctx);
113 /* --- @glob_match@ --- *
115 * Arguments: @const char *pat@ = pointer to pattern string
116 * @const char *s@ = pointer to candidate string
118 * Returns: Nonzero if pattern matches candidate.
120 * Use: Tries to match globbily. This is very simple stuff.
121 * I may add character classes later if I feel really eager.
124 static int glob_match(const char *pat, const char *s)
131 else if (*pat == '*') {
132 do pat++; while (*pat == '*');
134 if (glob_match(pat, s))
140 else if (*pat != '#' && tolower(*pat) != tolower(*s))
147 /* --- @glob_do@ --- *
149 * Arguments: @glob_ctx *g@ = pointer to my context
150 * @char *p@ = pointer to current position in buffer
151 * @char *in@ = rest of wildcard pattern to match
155 * Use: Main recursive glob matcher.
158 static void glob_do(glob_ctx *g, char *p, char *in)
163 /* --- Pick out the next component of the pathname --- */
166 do in++; while (*in == '.');
177 /* --- See if this contains any wildcards --- */
182 char *qq = q ? q - 1 : 0;
183 for (gf_init(&gx, "*", g->buf); *p = 0, (n = gf_next(&gx)) != 0; ) {
185 if (glob_match(in, n))
186 glob_got(g, p, n, q);
188 glob_got(g, p, n, rec);
190 } else if (strpbrk(in, "*#")) {
193 for (gf_init(&gx, in, g->buf); *p = 0, (n = gf_next(&gx)) != 0; )
194 glob_got(g, p, n, q);
196 glob_got(g, p, in, q);
201 * Arguments: @const char *pat@ = pointer to pattern string to match
202 * @void (*proc)(const char *, void *)@ = client function
203 * @void *ctx@ = context pointer to pass function
205 * Returns: Number of filenames matched.
207 * Use: Does filename globbing.
210 int glob(const char *pat, void (*proc)(const char *, void *), void *ctx)
215 if (!strpbrk(pat, "*#") && !strstr(pat, ".."))
222 glob_do(&gx, gx.buf, in);
227 /*----- That's all, folks -------------------------------------------------*/