Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
/** \file ignorecase.c */
8
 
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <ctype.h>
13
 
14
#include "physfsx.h"
15
#include "physfs_list.h"
16
#include "ignorecase.h"
17
 
18
#include "compiler-range_for.h"
19
 
20
/**
21
 * Please see ignorecase.h for details.
22
 *
23
 * License: this code is public domain. I make no warranty that it is useful,
24
 *  correct, harmless, or environmentally safe.
25
 *
26
 * This particular file may be used however you like, including copying it
27
 *  verbatim into a closed-source project, exploiting it commercially, and
28
 *  removing any trace of my name from the source (although I hope you won't
29
 *  do that). I welcome enhancements and corrections to this file, but I do
30
 *  not require you to send me patches if you make changes. This code has
31
 *  NO WARRANTY.
32
 *
33
 * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
34
 *  Please see LICENSE in the root of the source tree.
35
 *
36
 *  \author Ryan C. Gordon.
37
 */
38
 
39
namespace dcx {
40
 
41
/* I'm not screwing around with stricmp vs. strcasecmp... */
42
static int caseInsensitiveStringCompare(const char *x, const char *y)
43
{
44
    int ux, uy;
45
    do
46
    {
47
        ux = toupper(static_cast<int>(*x));
48
        uy = toupper(static_cast<int>(*y));
49
        if (ux != uy)
50
            return((ux > uy) ? 1 : -1);
51
        x++;
52
        y++;
53
    } while ((ux) && (uy));
54
 
55
    return(0);
56
} /* caseInsensitiveStringCompare */
57
 
58
namespace {
59
 
60
class search_result_t : public PHYSFSX_uncounted_list
61
{
62
        typedef PHYSFSX_uncounted_list base_ptr;
63
public:
64
        search_result_t(char *ptr, const char *buf) :
65
                base_ptr(PHYSFS_enumerateFiles(ptr ? (*ptr = 0, buf) : "/"))
66
        {
67
                if (ptr)
68
                        *ptr = '/';
69
        }
70
};
71
 
72
}
73
 
74
static int locateOneElement(char *const sptr, char *const ptr, const char *buf)
75
{
76
    if (const auto r = PHYSFS_exists(buf))
77
        return r;  /* quick rejection: exists in current case. */
78
 
79
        search_result_t rc{ptr, buf};
80
        range_for (const auto i, rc)
81
    {
82
                if (caseInsensitiveStringCompare(i, sptr) == 0)
83
        {
84
                        strcpy(sptr, i); /* found a match. Overwrite with this case. */
85
            return(1);
86
        } /* if */
87
    } /* for */
88
 
89
    /* no match at all... */
90
    return(0);
91
} /* locateOneElement */
92
 
93
 
94
int PHYSFSEXT_locateCorrectCase(char *buf)
95
{
96
    int rc;
97
 
98
    while (*buf == '/')  /* skip any '/' at start of string... */
99
        buf++;
100
        if (!*buf)
101
        return(0);  /* Uh...I guess that's success. */
102
 
103
        char *prevptr = nullptr;
104
        const auto a = [&]{
105
                return locateOneElement(prevptr ? prevptr + 1 : buf, prevptr, buf);
106
        };
107
        for (auto ptr = buf; (ptr = strchr(ptr + 1, '/')); prevptr = ptr)
108
    {
109
        *ptr = '\0';  /* block this path section off */
110
        rc = a();
111
        *ptr = '/'; /* restore path separator */
112
        if (!rc)
113
            return(-2);  /* missing element in path. */
114
    } /* while */
115
 
116
    /* check final element... */
117
    return a() ? 0 : -1;
118
} /* PHYSFSEXT_locateCorrectCase */
119
 
120
}
121
 
122
#ifdef TEST_PHYSFSEXT_LOCATECORRECTCASE
123
#define con_printf(A,B,...)     printf(B "\n", ##__VA_ARGS__)
124
int main(int argc, char **argv)
125
{
126
    int rc;
127
    char buf[128];
128
    PHYSFS_File *f;
129
 
130
    if (!PHYSFS_init(argv[0]))
131
    {
132
        con_printf(CON_CRITICAL, "PHYSFS_init(): %s", PHYSFS_getLastError());
133
        return(1);
134
    } /* if */
135
 
136
    if (!PHYSFS_addToSearchPath(".", 1))
137
    {
138
        con_printf(CON_CRITICAL, "PHYSFS_addToSearchPath(): %s", PHYSFS_getLastError());
139
        PHYSFS_deinit();
140
        return(1);
141
    } /* if */
142
 
143
    if (!PHYSFS_setWriteDir("."))
144
    {
145
        con_printf(CON_CRITICAL, "PHYSFS_setWriteDir(): %s", PHYSFS_getLastError());
146
        PHYSFS_deinit();
147
        return(1);
148
    } /* if */
149
 
150
    if (!PHYSFS_mkdir("/a/b/c"))
151
    {
152
        con_printf(CON_CRITICAL, "PHYSFS_mkdir(): %s", PHYSFS_getLastError());
153
        PHYSFS_deinit();
154
        return(1);
155
    } /* if */
156
 
157
    if (!PHYSFS_mkdir("/a/b/C"))
158
    {
159
        con_printf(CON_CRITICAL, "PHYSFS_mkdir(): %s", PHYSFS_getLastError());
160
        PHYSFS_deinit();
161
        return(1);
162
    } /* if */
163
 
164
    f = PHYSFS_openWrite("/a/b/c/x.txt");
165
    PHYSFS_close(f);
166
    if (f == NULL)
167
    {
168
        con_printf(CON_CRITICAL, "PHYSFS_openWrite(): %s", PHYSFS_getLastError());
169
        PHYSFS_deinit();
170
        return(1);
171
    } /* if */
172
 
173
    f = PHYSFS_openWrite("/a/b/C/X.txt");
174
    PHYSFS_close(f);
175
    if (f == NULL)
176
    {
177
        con_printf(CON_CRITICAL, "PHYSFS_openWrite(): %s", PHYSFS_getLastError());
178
        PHYSFS_deinit();
179
        return(1);
180
    } /* if */
181
 
182
    strcpy(buf, "/a/b/c/x.txt");
183
    rc = PHYSFSEXT_locateCorrectCase(buf);
184
    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
185
        con_printf(CON_DEBUG,"test 1 failed");
186
 
187
    strcpy(buf, "/a/B/c/x.txt");
188
    rc = PHYSFSEXT_locateCorrectCase(buf);
189
    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
190
        con_printf(CON_DEBUG,"test 2 failed");
191
 
192
    strcpy(buf, "/a/b/C/x.txt");
193
    rc = PHYSFSEXT_locateCorrectCase(buf);
194
    if ((rc != 0) || (strcmp(buf, "/a/b/C/X.txt") != 0))
195
        con_printf(CON_DEBUG,"test 3 failed");
196
 
197
    strcpy(buf, "/a/b/c/X.txt");
198
    rc = PHYSFSEXT_locateCorrectCase(buf);
199
    if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
200
        con_printf(CON_DEBUG,"test 4 failed");
201
 
202
    strcpy(buf, "/a/b/c/z.txt");
203
    rc = PHYSFSEXT_locateCorrectCase(buf);
204
    if ((rc != -1) || (strcmp(buf, "/a/b/c/z.txt") != 0))
205
        con_printf(CON_DEBUG,"test 5 failed");
206
 
207
    strcpy(buf, "/A/B/Z/z.txt");
208
    rc = PHYSFSEXT_locateCorrectCase(buf);
209
    if ((rc != -2) || (strcmp(buf, "/a/b/Z/z.txt") != 0))
210
        con_printf(CON_DEBUG,"test 6 failed");
211
 
212
    con_printf(CON_DEBUG,"Testing completed.");
213
    con_printf(CON_DEBUG,"  If no errors were reported, you're good to go.");
214
 
215
    PHYSFS_delete("/a/b/c/x.txt");
216
    PHYSFS_delete("/a/b/C/X.txt");
217
    PHYSFS_delete("/a/b/c");
218
    PHYSFS_delete("/a/b/C");
219
    PHYSFS_delete("/a/b");
220
    PHYSFS_delete("/a");
221
    PHYSFS_deinit();
222
    return(0);
223
} /* main */
224
#endif
225
 
226
/* end of ignorecase.c ... */
227