]>
Dogcows Code - chaz/yoink/blob - src/stlplus/strings/string_utilities.cpp
1 ////////////////////////////////////////////////////////////////////////////////
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "string_utilities.hpp"
10 #include "string_basic.hpp"
19 // added as a local copy to break the dependency on the portability library
20 static std::string
local_dformat(const char* format
, ...) throw(std::invalid_argument
)
22 std::string formatted
;
24 va_start(args
, format
);
28 for(int buffer_length
= 256; ; buffer_length
*=2)
30 buffer
= (char*)malloc(buffer_length
);
31 if (!buffer
) throw std::invalid_argument("string_utilities");
32 length
= _vsnprintf(buffer
, buffer_length
-1, format
, args
);
36 formatted
+= std::string(buffer
);
44 int length
= vasprintf(&buffer
, format
, args
);
45 if (!buffer
) throw std::invalid_argument("string_utilities");
47 formatted
+= std::string(buffer
);
51 if (length
< 0) throw std::invalid_argument("string_utilities");
55 ////////////////////////////////////////////////////////////////////////////////
57 std::string
pad(const std::string
& str
, alignment_t alignment
, unsigned width
, char padch
)
58 throw(std::invalid_argument
)
60 std::string result
= str
;
65 unsigned padding
= width
>str
.size() ? width
- str
.size() : 0;
68 result
.insert(result
.end(), padch
);
73 unsigned padding
= width
>str
.size() ? width
- str
.size() : 0;
76 result
.insert(result
.begin(), padch
);
81 unsigned padding
= width
>str
.size() ? width
- str
.size() : 0;
83 while (i
++ < padding
/2)
84 result
.insert(result
.end(), padch
);
87 result
.insert(result
.begin(), padch
);
91 throw std::invalid_argument("invalid alignment value");
96 ////////////////////////////////////////////////////////////////////////////////
98 std::string
trim_left(const std::string
& val
)
100 std::string result
= val
;
101 while (!result
.empty() && isspace(result
[0]))
102 result
.erase(result
.begin());
106 std::string
trim_right(const std::string
& val
)
108 std::string result
= val
;
109 while (!result
.empty() && isspace(result
[result
.size()-1]))
110 result
.erase(result
.end()-1);
114 std::string
trim(const std::string
& val
)
116 std::string result
= val
;
117 while (!result
.empty() && isspace(result
[0]))
118 result
.erase(result
.begin());
119 while (!result
.empty() && isspace(result
[result
.size()-1]))
120 result
.erase(result
.end()-1);
124 ////////////////////////////////////////////////////////////////////////////////
126 std::string
lowercase(const std::string
& val
)
128 std::string text
= val
;
129 for (unsigned i
= 0; i
< text
.size(); i
++)
130 text
[i
] = tolower(text
[i
]);
134 std::string
uppercase(const std::string
& val
)
136 std::string text
= val
;
137 for (unsigned i
= 0; i
< text
.size(); i
++)
138 text
[i
] = toupper(text
[i
]);
142 ////////////////////////////////////////////////////////////////////////////////
144 std::string
translate(const std::string
& input
, const std::string
& from_set
, const std::string
& to_set
)
147 for (unsigned i
= 0; i
< input
.size(); i
++)
150 // check to see if the character is in the from set
151 std::string::size_type found
= from_set
.find(ch
);
152 if (found
== std::string::npos
)
154 // not found so just copy across
157 else if (found
< to_set
.size())
159 // found and in range so translate
160 result
+= to_set
[found
];
166 ////////////////////////////////////////////////////////////////////////////////
167 // WARNING: wheel re-invention follows
168 // Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????
170 // * matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches
171 // if not, try 2 characters and see if the remainder matches etc.
172 // this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression
173 // ? matches exactly one character so doesn't need the what-if approach
174 // \ escapes special characters such as *, ? and [
175 // [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]
176 // a set cannot be empty and the ] character can be included by making it the first character
178 // function for testing whether a character matches a set
179 // I can't remember the exact rules and I have no definitive references but:
180 // a set contains characters, escaped characters (I think) and ranges in the form a-z
181 // The character '-' can only appear at the start of the set where it is not interpreted as a range
182 // This is a horrible mess - blame the Unix folks for making a hash of wildcards
184 static bool match_set (const std::string
& set
, char match
)
186 // first expand any ranges and remove escape characters to make life more palatable
187 std::string simple_set
;
188 for (std::string::const_iterator i
= set
.begin(); i
!= set
.end(); ++i
)
194 if (i
== set
.begin())
198 else if (i
+1 == set
.end())
204 // found a set. The first character is already in the result, so first remove it (the set might be empty)
205 simple_set
.erase(simple_set
.end()-1);
207 for (char ch
= *(i
-2); ch
<= last
; ch
++)
215 if (i
+1 == set
.end()) {return false;}
223 std::string::size_type result
= simple_set
.find(match
);
224 return result
!= std::string::npos
;
227 // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match
228 // until either it succeeds or you run out of string to match
229 // for each * in the wildcard another level of recursion is created
231 static bool match_remainder (const std::string
& wild
, std::string::const_iterator wildi
,
232 const std::string
& match
, std::string::const_iterator matchi
)
234 //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;
235 while (wildi
!= wild
.end() && matchi
!= match
.end())
237 //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;
244 for (std::string::const_iterator i
= matchi
; i
!= match
.end(); ++i
)
246 // deal with * at the end of the wildcard - there is no remainder then
247 if (wildi
== wild
.end())
249 if (i
== match
.end()-1)
252 else if (match_remainder(wild
, wildi
, match
, i
))
261 // scan for the end of the set using a similar method for avoiding escaped characters
263 std::string::const_iterator end
= wildi
+ 1;
264 for (; !found
&& end
!= wild
.end(); ++end
)
270 // found the set, now match with its contents excluding the brackets
271 if (!match_set(wild
.substr(wildi
- wild
.begin() + 1, end
- wildi
- 1), *matchi
))
277 if (end
== wild
.end()-1)
296 if (wildi
== wild
.end()-1)
299 if (*wildi
!= *matchi
)
305 if (*wildi
!= *matchi
)
312 bool result
= wildi
== wild
.end() && matchi
== match
.end();
316 // like all recursions the exported function has a simpler interface than the
317 // recursive function and is just a 'seed' to the recursion itself
319 bool match_wildcard(const std::string
& wild
, const std::string
& match
)
321 return match_remainder(wild
, wild
.begin(), match
, match
.begin());
324 ////////////////////////////////////////////////////////////////////////////////
326 std::vector
<std::string
> split(const std::string
& str
, const std::string
& splitter
)
328 std::vector
<std::string
> result
;
331 for(std::string::size_type offset
= 0;;)
333 std::string::size_type found
= str
.find(splitter
, offset
);
334 if (found
!= std::string::npos
)
336 result
.push_back(str
.substr(offset
, found
-offset
));
337 offset
= found
+ splitter
.size();
341 result
.push_back(str
.substr(offset
, str
.size()-offset
));
349 std::string
join (const std::vector
<std::string
>& str
,
350 const std::string
& joiner
,
351 const std::string
& prefix
,
352 const std::string
& suffix
)
354 std::string result
= prefix
;
355 for (unsigned i
= 0; i
< str
.size(); i
++)
357 if (i
) result
+= joiner
;
364 ////////////////////////////////////////////////////////////////////////////////
366 std::string
display_bytes(long bytes
)
374 static const long kB
= 1024l;
375 static const long MB
= kB
* kB
;
376 static const long GB
= MB
* kB
;
378 result
+= local_dformat("%i", bytes
);
379 else if (bytes
< (10l * kB
))
380 result
+= local_dformat("%.2fk", ((float)bytes
/ (float)kB
));
381 else if (bytes
< (100l * kB
))
382 result
+= local_dformat("%.1fk", ((float)bytes
/ (float)kB
));
384 result
+= local_dformat("%.0fk", ((float)bytes
/ (float)kB
));
385 else if (bytes
< (10l * MB
))
386 result
+= local_dformat("%.2fM", ((float)bytes
/ (float)MB
));
387 else if (bytes
< (100l * MB
))
388 result
+= local_dformat("%.1fM", ((float)bytes
/ (float)MB
));
390 result
+= local_dformat("%.0fM", ((float)bytes
/ (float)MB
));
392 result
+= local_dformat("%.2fG", ((float)bytes
/ (float)GB
));
396 std::string
display_time(time_t seconds
)
398 unsigned minutes
= (unsigned)seconds
/ 60;
400 unsigned hours
= minutes
/ 60;
402 unsigned days
= hours
/ 24;
404 unsigned weeks
= days
/ 7;
409 result
+= unsigned_to_string(weeks
, 10, radix_none
, 1);
412 if (!result
.empty() || days
> 0)
414 result
+= unsigned_to_string(days
, 10, radix_none
, 1);
417 if (!result
.empty() || hours
> 0)
419 result
+= unsigned_to_string(hours
, 10, radix_none
, 1);
422 if (!result
.empty() || minutes
> 0)
425 result
+= unsigned_to_string(minutes
, 10, radix_none
, 2);
427 result
+= unsigned_to_string(minutes
, 10, radix_none
, 1);
431 result
+= unsigned_to_string((unsigned)seconds
, 10, radix_none
, 2);
434 result
+= unsigned_to_string((unsigned)seconds
, 10, radix_none
, 1);
440 ////////////////////////////////////////////////////////////////////////////////
442 } // end namespace stlplus
This page took 0.057693 seconds and 4 git commands to generate.