1
// StringUtil.cc for fluxbox
2
// Copyright (c) 2001 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
4
// Permission is hereby granted, free of charge, to any person obtaining a
5
// copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
// DEALINGS IN THE SOFTWARE.
22
#include "StringUtil.hh"
24
#include "../defaults.hh"
69
int extractBigNumber(const char* in, T (*extractFunc)(const char*, char**, int), T& out) {
75
T result = extractFunc(in, &end, 0);
77
if (errno == 0 && end != in) {
86
int extractSignedNumber(const std::string& in, T& out) {
88
long long int result = 0;
90
if (::extractBigNumber(in.c_str(), strtoll, result)) {
91
out = static_cast<T>(result);
99
int extractUnsignedNumber(const std::string& in, T& out) {
101
unsigned long long int result = 0;
103
if (::extractBigNumber(in.c_str(), strtoull, result)) {
104
out = static_cast<T>(result);
118
namespace StringUtil {
120
int extractNumber(const std::string& in, int& out) {
121
return ::extractSignedNumber<int>(in, out);
124
int extractNumber(const std::string& in, unsigned int& out) {
125
return ::extractUnsignedNumber<unsigned int>(in, out);
128
int extractNumber(const std::string& in, long& out) {
129
return ::extractSignedNumber<long>(in, out);
132
int extractNumber(const std::string& in, unsigned long& out) {
133
return ::extractUnsignedNumber<unsigned long>(in, out);
136
int extractNumber(const std::string& in, long long& out) {
137
return ::extractSignedNumber<long long>(in, out);
140
int extractNumber(const std::string& in, unsigned long long& out) {
141
return ::extractUnsignedNumber<unsigned long long>(in, out);
146
std::string number2String(long long num) {
148
snprintf(s, sizeof(s), "%lld", num);
149
return std::string(s);
152
std::string number2HexString(long long num) {
154
snprintf(s, sizeof(s), "%lx", num);
155
return std::string(s);
160
Tries to find a string in another and
161
ignoring the case of the characters
162
Returns 0 on failure else pointer to str.
164
const char *strcasestr(const char *str, const char *ptn) {
166
for( ; *str; str++) {
167
for(s2=str, p2=ptn; ; s2++,p2++) {
168
// check if we reached the end of ptn, if so, return str
171
// check if the chars match(ignoring case)
172
if (toupper(*s2) != toupper(*p2))
183
#define WIN32_LEAN_AND_MEAN 1
187
static void removeTrailingPathSeparators(std::string & path) {
188
// Remove any trailing path separators
189
size_t beforeLastPathSep = path.find_last_not_of("/\\");
190
if (beforeLastPathSep != path.size() - 1) {
191
path.erase(beforeLastPathSep + 1);
195
static std::string getFluxboxPrefix() {
196
static std::string ret;
197
static bool init = false;
200
HMODULE module = GetModuleHandle(NULL);
201
DWORD size = GetModuleFileName(module, buffer, sizeof(buffer));
202
if (sizeof(buffer) > 0)
204
buffer[sizeof(buffer) - 1] = 0;
206
static const char slash = '/';
207
static const char backslash = '\\';
208
char * lastslash = std::find_end(buffer, buffer+size, &slash, &slash + 1);
209
char * lastbackslash = std::find_end(buffer, buffer+size, &backslash, &backslash + 1);
212
// Remove the filename
213
size_t lastPathSep = ret.find_last_of("/\\");
214
if (lastPathSep != std::string::npos) {
215
ret.erase(lastPathSep);
218
removeTrailingPathSeparators(ret);
220
// If the last directory is bin, remove that too.
221
lastPathSep = ret.find_last_of("/\\");
222
if (lastPathSep != std::string::npos && ret.substr(lastPathSep + 1) == "bin") {
223
ret.erase(lastPathSep);
226
removeTrailingPathSeparators(ret);
234
if ~ then expand it to home of user
235
if /DUMMYPREFIX on Windows then expand it to the prefix relative to the
236
executable on Windows.
237
returns expanded filename
239
string expandFilename(const string &filename) {
241
size_t pos = filename.find_first_not_of(" \t");
242
if (pos != string::npos && filename[pos] == '~') {
244
retval = getenv("USERPROFILE");
246
retval = getenv("HOME");
248
if (pos + 1 < filename.size()) {
249
// copy from the character after '~'
250
retval += static_cast<const char *>(filename.c_str() + pos + 1);
253
retval = filename; //return unmodified value
256
#if defined(_WIN32) && defined(DUMMYPREFIX)
257
if (retval.find(DUMMYPREFIX) == 0) {
258
static const std::string dummyPrefix = DUMMYPREFIX;
259
retval.replace(0, dummyPrefix.size(), getFluxboxPrefix());
267
@return string from last "." to end of string
269
string findExtension(const string &filename) {
270
//get start of extension
271
string::size_type start_pos = filename.find_last_of(".");
272
if (start_pos == string::npos && start_pos != filename.size())
274
// return from last . to end of string
275
return filename.substr(start_pos + 1);
278
string::size_type findCharFromAlphabetAfterTrigger(const std::string& in, char trigger, const char alphabet[], size_t len_alphabet, size_t* found) {
279
for (const char* s = in.c_str(); *s != '\0'; ) {
280
if (*s++ == trigger && *s != '\0') {
281
for (const char* a = alphabet; (a - alphabet) < static_cast<ssize_t>(len_alphabet); ++a) {
284
*found = a - alphabet;
286
return s - in.c_str() - 1;
296
string replaceString(const string &original,
297
const char *findthis,
298
const char *replace) {
300
const int size_of_replace = strlen(replace);
301
const int size_of_find = strlen(findthis);
302
string ret_str(original);
303
while (i < ret_str.size()) {
304
i = ret_str.find(findthis, i);
305
if (i == string::npos)
307
// erase old string and insert replacement
308
ret_str.erase(i, size_of_find);
309
ret_str.insert(i, replace);
310
// jump to next position after insert
311
i += size_of_replace;
318
Parses a string between "first" and "last" characters
319
and ignoring ok_chars as whitespaces. The value is
321
Returns negative value on error and this value is the position
322
in the in-string where the error occured.
323
Returns positive value on success and this value is
324
for the position + 1 in the in-string where the "last"-char value
327
int getStringBetween(string& out, const char *instr, char first, char last,
328
const char *ok_chars, bool allow_nesting) {
333
string::size_type i = 0;
334
string::size_type total_add=0; //used to add extra if there is a \last to skip
337
// eat leading whitespace
338
i = in.find_first_not_of(ok_chars);
339
if (i == string::npos)
340
return -in.size(); // nothing left but whitespace
343
return -i; //return position to error
345
// find the end of the token
346
string::size_type j = i, k;
349
k = in.find_first_of(first, j+1);
350
j = in.find_first_of(last, j+1);
352
return -in.size(); //send negative size
354
if (allow_nesting && k < j && in[k-1] != '\\') {
359
//we found the last char, check so it doesn't have a '\' before
360
if (j>1 && in[j-1] != '\\') {
361
if (allow_nesting && nesting > 0) nesting--;
364
} else if (j>1 && !allow_nesting) { // we leave escapes if we're allowing nesting
365
in.erase(j-1, 1); //remove the '\'
367
total_add++; //save numchars removed so we can calculate totalpos
371
out = in.substr(i+1, j-i-1); //copy the string between first and last
372
//return value to last character
373
return (j+1+total_add);
376
string toLower(const string &conv) {
378
transform(ret.begin(), ret.end(), ret.begin(), tolower);
382
string toUpper(const string &conv) {
384
transform(ret.begin(), ret.end(), ret.begin(), toupper);
388
string basename(const string &filename) {
389
string::size_type first_pos = filename.find_last_of("/");
390
if (first_pos != string::npos)
391
return filename.substr(first_pos + 1);
395
string::size_type removeFirstWhitespace(string &str) {
396
string::size_type first_pos = str.find_first_not_of(" \t");
397
str.erase(0, first_pos);
402
string::size_type removeTrailingWhitespace(string &str) {
403
// strip trailing whitespace
404
string::size_type first_pos = str.find_last_not_of(" \t");
405
string::size_type last_pos = str.find_first_of(" \t", first_pos);
406
if (last_pos != string::npos)
411
void getFirstWord(const std::string &in, std::string &word, std::string &rest) {
413
string::size_type first_pos = StringUtil::removeFirstWhitespace(word);
414
string::size_type second_pos = word.find_first_of(" \t", first_pos);
415
if (second_pos != string::npos) {
416
rest = word.substr(second_pos);
417
word.erase(second_pos);
421
} // end namespace StringUtil
423
} // end namespace FbTk