-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstrutil.cpp
More file actions
342 lines (300 loc) · 8.01 KB
/
strutil.cpp
File metadata and controls
342 lines (300 loc) · 8.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#include "strutil.h"
#include <stdarg.h>
#include <stdio.h>
// strutil uses default tolower if STRUTIL_TOLOWER not defined
#ifndef STRUTIL_TOLOWER
#define STRUTIL_TOLOWER(C) ( ((C)&~0x7F) ? (C) : tolower(C) )
#include <ctype.h>
#endif
// strutil uses toupper if STRUTIL_TOUPPER not defined
#ifndef STRUTIL_TOUPPER
#define STRUTIL_TOUPPER(C) ( ((C)&~0x7F) ? (C) : toupper(C) )
#include <ctype.h>
#endif
// strutil uses isspace is STRUTIL_ISSPACE not defined
#ifndef STRUTIL_ISSPACE
#define STRUTIL_ISSPACE(C) ( ((C)&~0x7F) ? false : isspace(C) != 0 )
#include <ctype.h>
#endif
namespace str
{
/* Maximum Unicode UTF-32 value */
static const unsigned UNICODE_MAX_LEGAL_UTF32 = 0x0010FFFF;
/* UTF-8 first byte encoding table. */
static const unsigned char s_firstByteMarks[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* Magic values subtracted from a buffer value during uint8_t conversion. */
static const unsigned s_offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
int utf8_encode( unsigned ch, char* target )
{
register int bytes = 0;
if ( ch < 0x80 )
bytes = 1;
else if ( ch < 0x800 )
bytes = 2;
else if ( ch < 0x10000 )
bytes = 3;
else if ( ch <= UNICODE_MAX_LEGAL_UTF32 )
bytes = 4;
else
bytes = 3, ch = UNICODE_REPLACEMENT_CHAR;
const unsigned bytemask = 0xBF;
const unsigned bytemark = 0x80;
target += bytes;
switch (bytes)
{
case 4: *--target = (char)((ch | bytemark) & bytemask); ch >>= 6;
case 3: *--target = (char)((ch | bytemark) & bytemask); ch >>= 6;
case 2: *--target = (char)((ch | bytemark) & bytemask); ch >>= 6;
case 1: *--target = (char) (ch | s_firstByteMarks[bytes]);
}
return bytes;
}
unsigned utf8_decode( const char* source, int* bytes )
{
const int chsize = utf8_chsize(source);
const int trail = chsize - 1;
register unsigned ch = 0;
switch (trail)
{
case 5: ch += (unsigned char)*source++; ch <<= 6;
case 4: ch += (unsigned char)*source++; ch <<= 6;
case 3: ch += (unsigned char)*source++; ch <<= 6;
case 2: ch += (unsigned char)*source++; ch <<= 6;
case 1: ch += (unsigned char)*source++; ch <<= 6;
case 0: ch += (unsigned char)*source++;
}
ch -= s_offsetsFromUTF8[trail];
if (bytes)
*bytes = chsize;
return ch;
}
int utf8_chsize( const char* source )
{
const unsigned ch = (unsigned char)*source;
if ( ch < 192 )
return 1;
else if ( ch < 224 )
return 2;
else if ( ch < 240 )
return 3;
else if ( ch < 248 )
return 4;
else if ( ch < 252 )
return 5;
else
return 6;
}
unsigned utf8_at( const string_type& s, size_type n )
{
const char* it = s.c_str();
for ( size_type i = 0 ; i < n ; ++i )
it += utf8_chsize( it );
return utf8_decode(it);
}
size_type utf8_len( const string_type& s )
{
const char* it = s.c_str();
size_type n = 0;
while ( *it )
{
++n;
it += utf8_chsize( it );
}
return n;
}
string_type ssprintf( const char* fmt, ... )
{
char msgbuf[2048];
va_list marker;
va_start( marker, fmt );
#ifdef _WIN32
vsprintf_s( msgbuf, sizeof(msgbuf), fmt, marker );
#else
vsnprintf( msgbuf, sizeof(msgbuf), fmt, marker );
#endif
va_end( marker );
msgbuf[sizeof(msgbuf)-1] = 0;
return string_type( msgbuf );
}
string_type trim( const string_type& s )
{
size_type i1 = s.length();
size_type i0 = 0;
while ( i0 < i1 && STRUTIL_ISSPACE((unsigned char)s.at(i0)) )
++i0;
while ( i1 > 0 && STRUTIL_ISSPACE((unsigned char)s.at(i1-1)) )
--i1;
return i0 < i1 ? s.substr(i0,i1-i0) : "";
}
string_type ltrim( const string_type& s )
{
const size_type i1 = s.length();
size_type i0 = 0;
while ( i0 < i1 && STRUTIL_ISSPACE((unsigned char)s.at(i0)) )
++i0;
return i0 < i1 ? s.substr(i0,i1-i0) : "";
}
string_type rtrim( const string_type& s )
{
size_type i1 = s.length();
while ( i1 > 0 && STRUTIL_ISSPACE((unsigned char)s.at(i1-1)) )
--i1;
return 0 < i1 ? s.substr(0,i1) : "";
}
string_vector_type explode( const string_type& delim, const string_type& input )
{
string_vector_type out;
explode(delim,input,out);
return out;
}
string_type uppercase( const string_type& s )
{
char_vector_type vec;
vec.reserve( s.length()+1 );
for ( const char* p = s.c_str() ; *p ; )
{
int bytes;
char buf[8];
unsigned ch = utf8_decode( p, &bytes );
p += bytes;
ch = STRUTIL_TOUPPER( ch );
bytes = utf8_encode( ch, buf );
vec.insert( vec.end(), buf, buf+bytes );
}
return string_type( vec.begin(), vec.end() );
}
string_type lowercase( const string_type& s )
{
char_vector_type vec;
vec.reserve( s.length()+1 );
for ( const char* p = s.c_str() ; *p ; )
{
int bytes;
char buf[8];
unsigned ch = utf8_decode( p, &bytes );
p += bytes;
ch = STRUTIL_TOLOWER( ch );
bytes = utf8_encode( ch, buf );
vec.insert( vec.end(), buf, buf+bytes );
}
return string_type( vec.begin(), vec.end() );
}
wstring_type to_wcs( const string_type& s )
{
wchar_vector_type vec;
vec.reserve( s.length()+1 );
for ( const char* p = s.c_str() ; *p ; )
{
int bytes;
unsigned ch = utf8_decode( p, &bytes );
p += bytes;
vec.push_back( ch );
}
return wstring_type( vec.begin(), vec.end() );
}
string_type to_utf8( const wstring_type& s )
{
char_vector_type vec;
vec.reserve( s.length()*2+1 );
for ( const wchar_type* p = s.c_str() ; *p ; ++p )
{
char buf[8];
int bytes = utf8_encode( *p, buf );
vec.insert( vec.end(), buf, buf+bytes );
}
return string_type( vec.begin(), vec.end() );
}
string_type substr( const string_type& s, size_type offset, size_type count )
{
const size_type len = s.length();
if ( offset >= len )
offset = (offset+len)%len;
if ( count >= len )
count = len+count-offset;
return s.substr( offset, count );
}
string_type replace( const string_type& needle, const string_type& target, const string_type& haystack, size_type n )
{
const size_type len = haystack.length();
const size_type needle_len = needle.length();
char_vector_type vec;
vec.reserve( len+1 );
for ( size_type i = 0 ; i < len ; )
{
if ( !haystack.compare(i,needle_len,needle) )
{
vec.insert( vec.end(), target.begin(), target.end() );
i += needle_len;
if ( --n == 0 )
break;
}
else
{
vec.push_back( haystack.at(i++) );
}
}
return string_type( vec.begin(), vec.end() );
}
string_type replace( char needle, char target, const string_type& haystack, size_type n )
{
const size_type len = haystack.length();
char_vector_type vec( len );
for ( size_type i = 0 ; i < len ; ++i )
vec[i] = ( haystack[i]==needle ? target : haystack[i] );
return string_type( vec.begin(), vec.end() );
}
inline static bool sep( char ch )
{
return ch == '/' || ch == '\\';
}
string_type basename( const string_type& path, const string_type& suffix )
{
// printf("@ basename: %s %s\n", path.c_str(), suffix.c_str());
// cut terminating dir separator
size_type len = path.length();
if ( len > 0 && sep(path[len-1]) )
--len;
// cut suffix if specified and matches
size_type suffix_len = suffix.length();
const size_type suffix_offset = len - suffix_len;
for ( size_type k = 0 ; k < suffix_len ; ++k )
{
if ( path[suffix_offset+k] != suffix[k] )
{
suffix_len = 0;
break;
}
}
len -= suffix_len;
// cut basename
size_type i = len;
while ( i > 0 )
{
if ( sep(path[i-1]) )
break;
--i;
}
return path.substr( i, len-i );
}
string_type dirname( const string_type& path )
{
// cut terminating dir separator if any
size_type len = path.length();
if ( !len )
return path;
if ( len > 0 && sep(path[len-1]) )
--len;
if ( !len )
return path; // dir separator only
// find prev dir separator
size_t i = len;
while ( i > 0 && !sep(path[i-1]) )
--i;
if ( !i )
return ".";
if ( --i == 0 )
return "/";
return path.substr( 0, i );
}
} // str
// strutil library is copyright (C) 2009-2018 Jani Kajala (kajala@gmail.com). Licensed under BSD/MIT license.