Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * Portions of this file are copyright Rebirth contributors and licensed as
3
 * described in COPYING.txt.
4
 * Portions of this file are copyright Parallax Software and licensed
5
 * according to the Parallax license below.
6
 * See COPYING.txt for license details.
7
 
8
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12
IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * string manipulation utility code
23
 *
24
 */
25
 
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <ctype.h>
29
#include <string.h>
30
#include <stdarg.h>
31
 
32
#include "u_mem.h"
33
#include "dxxerror.h"
34
#include "strutil.h"
35
#include "inferno.h"
36
 
37
#include "compiler-range_for.h"
38
 
39
namespace dcx {
40
 
41
#ifdef macintosh
42
void snprintf(char *out_string, int size, char * format, ... )
43
{
44
        va_list         args;
45
        char            buf[1024];
46
 
47
        va_start(args, format );
48
        vsprintf(buf,format,args);
49
        va_end(args);
50
 
51
        // Hack! Don't know any other [simple] way to do this, but I doubt it would ever exceed 1024 long.
52
        Assert(strlen(buf) < 1024);
53
        Assert(size < 1024);
54
 
55
        strncpy(out_string, buf, size);
56
}
57
#endif // macintosh
58
 
59
// string compare without regard to case
60
 
61
#ifndef DXX_HAVE_STRCASECMP
62
int d_stricmp( const char *s1, const char *s2 )
63
{
64
        for (;; ++s1, ++s2)
65
        {
66
                auto u1 = toupper(static_cast<unsigned>(*s1));
67
                auto u2 = toupper(static_cast<unsigned>(*s2));
68
                if (u1 != u2)
69
                        return (u1 > u2) ? 1 : -1;
70
                if (!u1)
71
                        return u1;
72
        }
73
}
74
 
75
int d_strnicmp(const char *s1, const char *s2, uint_fast32_t n)
76
{
77
        for (; n; ++s1, ++s2, --n)
78
        {
79
                auto u1 = toupper(static_cast<unsigned>(*s1));
80
                auto u2 = toupper(static_cast<unsigned>(*s2));
81
                if (u1 != u2)
82
                        return (u1 > u2) ? 1 : -1;
83
                if (!u1)
84
                        return u1;
85
        }
86
        return 0;
87
}
88
#endif
89
 
90
void d_strlwr( char *s1 )
91
{
92
        while( *s1 )    {
93
                *s1 = tolower(*s1);
94
                s1++;
95
        }
96
}
97
 
98
void d_strupr( char *s1 )
99
{
100
        while( *s1 )    {
101
                *s1 = toupper(*s1);
102
                s1++;
103
        }
104
}
105
 
106
void d_strrev( char *s1 )
107
{
108
        char *h, *t;
109
        h = s1;
110
        t = s1 + strlen(s1) - 1;
111
        while (h < t) {
112
                char c;
113
                c = *h;
114
                *h++ = *t;
115
                *t-- = c;
116
        }
117
}
118
 
119
#ifdef DEBUG_MEMORY_ALLOCATIONS
120
char *(d_strdup)(const char *str, const char *var, const char *file, unsigned line)
121
{
122
        char *newstr;
123
 
124
        const auto len = strlen(str) + 1;
125
        MALLOC<char>(newstr, len, var, file, line);
126
        return static_cast<char *>(memcpy(newstr, str, len));
127
}
128
#endif
129
 
130
// remove extension from filename
131
void removeext(const char *const filename, std::array<char, 20> &out)
132
{
133
        const char *p = nullptr;
134
        auto i = filename;
135
        for (; const char c = *i; ++i)
136
        {
137
                if (c == '.')
138
                        p = i;
139
                /* No break - find the last '.', not the first. */
140
        }
141
        if (!p)
142
                p = i;
143
        const std::size_t rawlen = p - filename;
144
        const std::size_t copy_len = rawlen < out.size() ? rawlen : 0;
145
        out[copy_len] = 0;
146
        memcpy(out.data(), filename, copy_len);
147
}
148
 
149
 
150
//give a filename a new extension, won't append if strlen(dest) > 8 chars.
151
void change_filename_extension( char *dest, const char *src, const char *ext )
152
{
153
        char *p;
154
 
155
        strcpy (dest, src);
156
 
157
        if (ext[0] == '.')
158
                ext++;
159
 
160
        p = strrchr(dest, '.');
161
        if (!p) {
162
                if (strlen(dest) > FILENAME_LEN - 5)
163
                        return; // a non-opened file is better than a bad memory access
164
 
165
                p = dest + strlen(dest);
166
                *p = '.';
167
        }
168
 
169
        strcpy(p+1,ext);
170
}
171
 
172
void d_splitpath(const char *name, struct splitpath_t *path)
173
{
174
        const char *s, *p;
175
 
176
        p = name;
177
        s = strchr(p, ':');
178
        if ( s != NULL ) {
179
                path->drive_start = p;
180
                path->drive_end = s;
181
                p = s+1;
182
        } else
183
                path->drive_start = path->drive_end = NULL;
184
        s = strrchr(p, '\\');
185
        if ( s != NULL) {
186
                path->path_start = p;
187
                path->path_end = s + 1;
188
                p = s+1;
189
        } else
190
                path->path_start = path->path_end = NULL;
191
 
192
        s = strchr(p, '.');
193
        if ( s != NULL) {
194
                path->base_start = p;
195
                path->base_end = s;
196
                p = s+1;
197
        } else
198
                path->base_start = path->base_end = NULL;
199
        path->ext_start = p;
200
}
201
 
202
int string_array_sort_func(const void *v0, const void *v1)
203
{
204
        const auto e0 = reinterpret_cast<const char *const *>(v0);
205
        const auto e1 = reinterpret_cast<const char *const *>(v1);
206
        return d_stricmp(*e0, *e1);
207
}
208
 
209
void string_array_t::add(const char *s)
210
{
211
        const auto insert_string = [this, s]{
212
                auto &b = this->buffer;
213
                b.insert(b.end(), s, s + strlen(s) + 1);
214
        };
215
        if (buffer.empty())
216
        {
217
                insert_string();
218
                ptr.emplace_back(&buffer.front());
219
                return;
220
        }
221
        const char *ob = &buffer.front();
222
        ptr.emplace_back(1 + &buffer.back());
223
        insert_string();
224
        if (auto d = &buffer.front() - ob)
225
        {
226
                // Update all the pointers in the pointer list
227
                range_for (auto &i, ptr)
228
                        i += d;
229
        }
230
}
231
 
232
void string_array_t::tidy(std::size_t offset, int (*comp)( const char *, const char * ))
233
{
234
        // Sort by name, starting at offset
235
        auto b = std::next(ptr.begin(), offset);
236
        auto e = ptr.end();
237
        std::sort(b, e, [](const char *sa, const char *sb) { return d_stricmp(sa, sb) < 0; });
238
        // Remove duplicates
239
        // Can't do this before reallocating, otherwise it makes a mess of things (the strings in the buffer aren't ordered)
240
        ptr.erase(std::unique(b, e, [=](const char *sa, const char *sb) { return (*comp)(sa, sb) == 0; }), e);
241
}
242
 
243
}