Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/** \file globbing.c */
2
 
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <ctype.h>
7
#include <assert.h>
8
 
9
#include "globbing.h"
10
 
11
/**
12
 * Please see globbing.h for details.
13
 *
14
 * License: this code is public domain. I make no warranty that it is useful,
15
 *  correct, harmless, or environmentally safe.
16
 *
17
 * This particular file may be used however you like, including copying it
18
 *  verbatim into a closed-source project, exploiting it commercially, and
19
 *  removing any trace of my name from the source (although I hope you won't
20
 *  do that). I welcome enhancements and corrections to this file, but I do
21
 *  not require you to send me patches if you make changes. This code has
22
 *  NO WARRANTY.
23
 *
24
 * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
25
 *  Please see the file LICENSE.txt in the source's root directory.
26
 *
27
 *  \author Ryan C. Gordon.
28
 */
29
 
30
 
31
static int matchesPattern(const char *fname, const char *wildcard,
32
                          int caseSensitive)
33
{
34
    char x, y;
35
    const char *fnameptr = fname;
36
    const char *wildptr = wildcard;
37
 
38
    while ((*wildptr) && (*fnameptr))
39
    {
40
        y = *wildptr;
41
        if (y == '*')
42
        {
43
            do
44
            {
45
                wildptr++;  /* skip multiple '*' in a row... */
46
            } while (*wildptr == '*');
47
 
48
            y = (caseSensitive) ? *wildptr : (char) tolower(*wildptr);
49
 
50
            while (1)
51
            {
52
                x = (caseSensitive) ? *fnameptr : (char) tolower(*fnameptr);
53
                if ((!x) || (x == y))
54
                    break;
55
                else
56
                    fnameptr++;
57
            } /* while */
58
        } /* if */
59
 
60
        else if (y == '?')
61
        {
62
            wildptr++;
63
            fnameptr++;
64
        } /* else if */
65
 
66
        else
67
        {
68
            if (caseSensitive)
69
                x = *fnameptr;
70
            else
71
            {
72
                x = tolower(*fnameptr);
73
                y = tolower(y);
74
            } /* if */
75
 
76
            wildptr++;
77
            fnameptr++;
78
 
79
            if (x != y)
80
                return 0;
81
        } /* else */
82
    } /* while */
83
 
84
    while (*wildptr == '*')
85
        wildptr++;
86
 
87
    return (*fnameptr == *wildptr);
88
} /* matchesPattern */
89
 
90
typedef struct
91
{
92
    const PHYSFS_Allocator *allocator;
93
    const char *wildcard;
94
    int caseSensitive;
95
    PHYSFS_EnumFilesCallback callback;
96
    void *origData;
97
} WildcardCallbackData;
98
 
99
 
100
/*
101
 * This callback sits between the enumerator and the enduser callback,
102
 *  filtering out files that don't match the wildcard pattern.
103
 */
104
static void wildcardCallback(void *_d, const char *origdir, const char *fname)
105
{
106
    const WildcardCallbackData *data = (const WildcardCallbackData *) _d;
107
    if (matchesPattern(fname, data->wildcard, data->caseSensitive))
108
        data->callback(data->origData, origdir, fname);
109
} /* wildcardCallback */
110
 
111
 
112
void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
113
                                              const char *wildcard,
114
                                              int caseSensitive,
115
                                              PHYSFS_EnumFilesCallback c,
116
                                              void *d)
117
{
118
    WildcardCallbackData data;
119
    data.allocator = PHYSFS_getAllocator();
120
    data.wildcard = wildcard;
121
    data.caseSensitive = caseSensitive;
122
    data.callback = c;
123
    data.origData = d;
124
    PHYSFS_enumerateFilesCallback(dir, wildcardCallback, &data);
125
} /* PHYSFSEXT_enumerateFilesCallbackWildcard */
126
 
127
 
128
void PHYSFSEXT_freeEnumeration(char **list)
129
{
130
    const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
131
    int i;
132
    if (list != NULL)
133
    {
134
        for (i = 0; list[i] != NULL; i++)
135
            allocator->Free(list[i]);
136
        allocator->Free(list);
137
    } /* if */
138
} /* PHYSFSEXT_freeEnumeration */
139
 
140
 
141
char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
142
                                        int caseSensitive)
143
{
144
    const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
145
    char **list = PHYSFS_enumerateFiles(dir);
146
    char **retval = NULL;
147
    int totalmatches = 0;
148
    int matches = 0;
149
    char **i;
150
 
151
    for (i = list; *i != NULL; i++)
152
    {
153
        #if 0
154
        printf("matchesPattern: '%s' vs '%s' (%s) ... %s\n", *i, wildcard,
155
               caseSensitive ? "case" : "nocase",
156
               matchesPattern(*i, wildcard, caseSensitive) ? "true" : "false");
157
        #endif
158
        if (matchesPattern(*i, wildcard, caseSensitive))
159
            totalmatches++;
160
    } /* for */
161
 
162
    retval = (char **) allocator->Malloc(sizeof (char *) * (totalmatches+1));
163
    if (retval != NULL)
164
    {
165
        for (i = list; ((matches < totalmatches) && (*i != NULL)); i++)
166
        {
167
            if (matchesPattern(*i, wildcard, caseSensitive))
168
            {
169
                retval[matches] = (char *) allocator->Malloc(strlen(*i) + 1);
170
                if (retval[matches] == NULL)
171
                {
172
                    while (matches--)
173
                        allocator->Free(retval[matches]);
174
                    allocator->Free(retval);
175
                    retval = NULL;
176
                    break;
177
                } /* if */
178
                strcpy(retval[matches], *i);
179
                matches++;
180
            } /* if */
181
        } /* for */
182
 
183
        if (retval != NULL)
184
        {
185
            assert(totalmatches == matches);
186
            retval[matches] = NULL;
187
        } /* if */
188
    } /* if */
189
 
190
    PHYSFS_freeList(list);
191
    return retval;
192
} /* PHYSFSEXT_enumerateFilesWildcard */
193
 
194
 
195
#ifdef TEST_PHYSFSEXT_ENUMERATEFILESWILDCARD
196
int main(int argc, char **argv)
197
{
198
    int rc;
199
    char **flist;
200
    char **i;
201
 
202
    if (argc != 3)
203
    {
204
        printf("USAGE: %s <pattern> <caseSen>\n"
205
               "   where <caseSen> is 1 or 0.\n", argv[0]);
206
        return 1;
207
    } /* if */
208
 
209
    if (!PHYSFS_init(argv[0]))
210
    {
211
        fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
212
        return 1;
213
    } /* if */
214
 
215
    if (!PHYSFS_addToSearchPath(".", 1))
216
    {
217
        fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
218
        PHYSFS_deinit();
219
        return 1;
220
    } /* if */
221
 
222
    flist = PHYSFSEXT_enumerateFilesWildcard("/", argv[1], atoi(argv[2]));
223
    rc = 0;
224
    for (i = flist; *i; i++)
225
    {
226
        printf("%s\n", *i);
227
        rc++;
228
    } /* for */
229
    printf("\n  total %d files.\n\n", rc);
230
 
231
    PHYSFSEXT_freeEnumeration(flist);
232
    PHYSFS_deinit();
233
 
234
    return 0;
235
} /* main */
236
#endif
237
 
238
/* end of globbing.c ... */
239