-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author: Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-// (c) Andy Rushton 2004-2009\r
-// License: BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_utilities.hpp"\r
-#include "string_basic.hpp"\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
- // added as a local copy to break the dependency on the portability library\r
- static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)\r
- {\r
- std::string formatted;\r
- va_list args;\r
- va_start(args, format);\r
-#ifdef MSWINDOWS\r
- int length = 0;\r
- char* buffer = 0;\r
- for(int buffer_length = 256; ; buffer_length*=2)\r
- {\r
- buffer = (char*)malloc(buffer_length);\r
- if (!buffer) throw std::invalid_argument("string_utilities");\r
- length = _vsnprintf(buffer, buffer_length-1, format, args);\r
- if (length >= 0)\r
- {\r
- buffer[length] = 0;\r
- formatted += std::string(buffer);\r
- free(buffer);\r
- break;\r
- }\r
- free(buffer);\r
- }\r
-#else\r
- char* buffer = 0;\r
- int length = vasprintf(&buffer, format, args);\r
- if (!buffer) throw std::invalid_argument("string_utilities");\r
- if (length >= 0)\r
- formatted += std::string(buffer);\r
- free(buffer);\r
-#endif\r
- va_end(args);\r
- if (length < 0) throw std::invalid_argument("string_utilities");\r
- return formatted;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string pad(const std::string& str, alignment_t alignment, unsigned width, char padch)\r
- throw(std::invalid_argument)\r
- {\r
- std::string result = str;\r
- switch(alignment)\r
- {\r
- case align_left:\r
- {\r
- unsigned padding = width>str.size() ? width - str.size() : 0;\r
- unsigned i = 0;\r
- while (i++ < padding)\r
- result.insert(result.end(), padch);\r
- break;\r
- }\r
- case align_right:\r
- {\r
- unsigned padding = width>str.size() ? width - str.size() : 0;\r
- unsigned i = 0;\r
- while (i++ < padding)\r
- result.insert(result.begin(), padch);\r
- break;\r
- }\r
- case align_centre:\r
- {\r
- unsigned padding = width>str.size() ? width - str.size() : 0;\r
- unsigned i = 0;\r
- while (i++ < padding/2)\r
- result.insert(result.end(), padch);\r
- i--;\r
- while (i++ < padding)\r
- result.insert(result.begin(), padch);\r
- break;\r
- }\r
- default:\r
- throw std::invalid_argument("invalid alignment value");\r
- }\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string trim_left(const std::string& val)\r
- {\r
- std::string result = val;\r
- while (!result.empty() && isspace(result[0]))\r
- result.erase(result.begin());\r
- return result;\r
- }\r
-\r
- std::string trim_right(const std::string& val)\r
- {\r
- std::string result = val;\r
- while (!result.empty() && isspace(result[result.size()-1]))\r
- result.erase(result.end()-1);\r
- return result;\r
- }\r
-\r
- std::string trim(const std::string& val)\r
- {\r
- std::string result = val;\r
- while (!result.empty() && isspace(result[0]))\r
- result.erase(result.begin());\r
- while (!result.empty() && isspace(result[result.size()-1]))\r
- result.erase(result.end()-1);\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string lowercase(const std::string& val)\r
- {\r
- std::string text = val;\r
- for (unsigned i = 0; i < text.size(); i++)\r
- text[i] = tolower(text[i]);\r
- return text;\r
- }\r
-\r
- std::string uppercase(const std::string& val)\r
- {\r
- std::string text = val;\r
- for (unsigned i = 0; i < text.size(); i++)\r
- text[i] = toupper(text[i]);\r
- return text;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string translate(const std::string& input, const std::string& from_set, const std::string& to_set)\r
- {\r
- std::string result;\r
- for (unsigned i = 0; i < input.size(); i++)\r
- {\r
- char ch = input[i];\r
- // check to see if the character is in the from set\r
- std::string::size_type found = from_set.find(ch);\r
- if (found == std::string::npos)\r
- {\r
- // not found so just copy across\r
- result += ch;\r
- }\r
- else if (found < to_set.size())\r
- {\r
- // found and in range so translate\r
- result += to_set[found];\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
- // WARNING: wheel re-invention follows\r
- // Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????\r
- // The problem:\r
- // * matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches\r
- // if not, try 2 characters and see if the remainder matches etc.\r
- // this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression\r
- // ? matches exactly one character so doesn't need the what-if approach\r
- // \ escapes special characters such as *, ? and [\r
- // [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]\r
- // a set cannot be empty and the ] character can be included by making it the first character\r
-\r
- // function for testing whether a character matches a set\r
- // I can't remember the exact rules and I have no definitive references but:\r
- // a set contains characters, escaped characters (I think) and ranges in the form a-z\r
- // The character '-' can only appear at the start of the set where it is not interpreted as a range\r
- // This is a horrible mess - blame the Unix folks for making a hash of wildcards\r
-\r
- static bool match_set (const std::string& set, char match)\r
- {\r
- // first expand any ranges and remove escape characters to make life more palatable\r
- std::string simple_set;\r
- for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)\r
- {\r
- switch(*i)\r
- {\r
- case '-':\r
- {\r
- if (i == set.begin())\r
- {\r
- simple_set += *i;\r
- }\r
- else if (i+1 == set.end())\r
- {\r
- return false;\r
- }\r
- else\r
- {\r
- // found a set. The first character is already in the result, so first remove it (the set might be empty)\r
- simple_set.erase(simple_set.end()-1);\r
- char last = *++i;\r
- for (char ch = *(i-2); ch <= last; ch++)\r
- {\r
- simple_set += ch;\r
- }\r
- }\r
- break;\r
- }\r
- case '\\':\r
- if (i+1 == set.end()) {return false;}\r
- simple_set += *++i;\r
- break;\r
- default:\r
- simple_set += *i;\r
- break;\r
- }\r
- }\r
- std::string::size_type result = simple_set.find(match);\r
- return result != std::string::npos;\r
- }\r
-\r
- // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match\r
- // until either it succeeds or you run out of string to match\r
- // for each * in the wildcard another level of recursion is created\r
-\r
- static bool match_remainder (const std::string& wild, std::string::const_iterator wildi,\r
- const std::string& match, std::string::const_iterator matchi)\r
- {\r
- //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;\r
- while (wildi != wild.end() && matchi != match.end())\r
- {\r
- //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;\r
- switch(*wildi)\r
- {\r
- case '*':\r
- {\r
- ++wildi;\r
- ++matchi;\r
- for (std::string::const_iterator i = matchi; i != match.end(); ++i)\r
- {\r
- // deal with * at the end of the wildcard - there is no remainder then\r
- if (wildi == wild.end())\r
- {\r
- if (i == match.end()-1)\r
- return true;\r
- }\r
- else if (match_remainder(wild, wildi, match, i))\r
- {\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
- case '[':\r
- {\r
- // scan for the end of the set using a similar method for avoiding escaped characters\r
- bool found = false;\r
- std::string::const_iterator end = wildi + 1;\r
- for (; !found && end != wild.end(); ++end)\r
- {\r
- switch(*end)\r
- {\r
- case ']':\r
- {\r
- // found the set, now match with its contents excluding the brackets\r
- if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))\r
- return false;\r
- found = true;\r
- break;\r
- }\r
- case '\\':\r
- if (end == wild.end()-1)\r
- return false;\r
- ++end;\r
- break;\r
- default:\r
- break;\r
- }\r
- }\r
- if (!found)\r
- return false;\r
- ++matchi;\r
- wildi = end;\r
- break;\r
- }\r
- case '?':\r
- ++wildi;\r
- ++matchi;\r
- break;\r
- case '\\':\r
- if (wildi == wild.end()-1)\r
- return false;\r
- ++wildi;\r
- if (*wildi != *matchi)\r
- return false;\r
- ++wildi;\r
- ++matchi;\r
- break;\r
- default:\r
- if (*wildi != *matchi)\r
- return false;\r
- ++wildi;\r
- ++matchi;\r
- break;\r
- }\r
- }\r
- bool result = wildi == wild.end() && matchi == match.end();\r
- return result;\r
- }\r
-\r
- // like all recursions the exported function has a simpler interface than the\r
- // recursive function and is just a 'seed' to the recursion itself\r
-\r
- bool match_wildcard(const std::string& wild, const std::string& match)\r
- {\r
- return match_remainder(wild, wild.begin(), match, match.begin());\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::vector<std::string> split(const std::string& str, const std::string& splitter)\r
- {\r
- std::vector<std::string> result;\r
- if (!str.empty())\r
- {\r
- for(std::string::size_type offset = 0;;)\r
- {\r
- std::string::size_type found = str.find(splitter, offset);\r
- if (found != std::string::npos)\r
- {\r
- result.push_back(str.substr(offset, found-offset));\r
- offset = found + splitter.size();\r
- }\r
- else\r
- {\r
- result.push_back(str.substr(offset, str.size()-offset));\r
- break;\r
- }\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- std::string join (const std::vector<std::string>& str,\r
- const std::string& joiner,\r
- const std::string& prefix,\r
- const std::string& suffix)\r
- {\r
- std::string result = prefix;\r
- for (unsigned i = 0; i < str.size(); i++)\r
- {\r
- if (i) result += joiner;\r
- result += str[i];\r
- }\r
- result += suffix;\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string display_bytes(long bytes)\r
- {\r
- std::string result;\r
- if (bytes < 0)\r
- {\r
- result += '-';\r
- bytes = -bytes;\r
- }\r
- static const long kB = 1024l;\r
- static const long MB = kB * kB;\r
- static const long GB = MB * kB;\r
- if (bytes < kB)\r
- result += local_dformat("%i", bytes);\r
- else if (bytes < (10l * kB))\r
- result += local_dformat("%.2fk", ((float)bytes / (float)kB));\r
- else if (bytes < (100l * kB))\r
- result += local_dformat("%.1fk", ((float)bytes / (float)kB));\r
- else if (bytes < MB)\r
- result += local_dformat("%.0fk", ((float)bytes / (float)kB));\r
- else if (bytes < (10l * MB))\r
- result += local_dformat("%.2fM", ((float)bytes / (float)MB));\r
- else if (bytes < (100l * MB))\r
- result += local_dformat("%.1fM", ((float)bytes / (float)MB));\r
- else if (bytes < GB)\r
- result += local_dformat("%.0fM", ((float)bytes / (float)MB));\r
- else\r
- result += local_dformat("%.2fG", ((float)bytes / (float)GB));\r
- return result;\r
- }\r
-\r
- std::string display_time(time_t seconds)\r
- {\r
- unsigned minutes = (unsigned)seconds / 60;\r
- seconds %= 60;\r
- unsigned hours = minutes / 60;\r
- minutes %= 60;\r
- unsigned days = hours / 24;\r
- hours %= 24;\r
- unsigned weeks = days / 7;\r
- days %= 7;\r
- std::string result;\r
- if (weeks > 0)\r
- {\r
- result += unsigned_to_string(weeks, 10, radix_none, 1);\r
- result += "w ";\r
- }\r
- if (!result.empty() || days > 0)\r
- {\r
- result += unsigned_to_string(days, 10, radix_none, 1);\r
- result += "d ";\r
- }\r
- if (!result.empty() || hours > 0)\r
- {\r
- result += unsigned_to_string(hours, 10, radix_none, 1);\r
- result += ":";\r
- }\r
- if (!result.empty() || minutes > 0)\r
- {\r
- if (!result.empty())\r
- result += unsigned_to_string(minutes, 10, radix_none, 2);\r
- else\r
- result += unsigned_to_string(minutes, 10, radix_none, 1);\r
- result += ":";\r
- }\r
- if (!result.empty())\r
- result += unsigned_to_string((unsigned)seconds, 10, radix_none, 2);\r
- else\r
- {\r
- result += unsigned_to_string((unsigned)seconds, 10, radix_none, 1);\r
- result += "s";\r
- }\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_utilities.hpp"
+#include "string_basic.hpp"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace stlplus
+{
+
+ // added as a local copy to break the dependency on the portability library
+ static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)
+ {
+ std::string formatted;
+ va_list args;
+ va_start(args, format);
+#ifdef MSWINDOWS
+ int length = 0;
+ char* buffer = 0;
+ for(int buffer_length = 256; ; buffer_length*=2)
+ {
+ buffer = (char*)malloc(buffer_length);
+ if (!buffer) throw std::invalid_argument("string_utilities");
+ length = _vsnprintf(buffer, buffer_length-1, format, args);
+ if (length >= 0)
+ {
+ buffer[length] = 0;
+ formatted += std::string(buffer);
+ free(buffer);
+ break;
+ }
+ free(buffer);
+ }
+#else
+ char* buffer = 0;
+ int length = vasprintf(&buffer, format, args);
+ if (!buffer) throw std::invalid_argument("string_utilities");
+ if (length >= 0)
+ formatted += std::string(buffer);
+ free(buffer);
+#endif
+ va_end(args);
+ if (length < 0) throw std::invalid_argument("string_utilities");
+ return formatted;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string pad(const std::string& str, alignment_t alignment, unsigned width, char padch)
+ throw(std::invalid_argument)
+ {
+ std::string result = str;
+ switch(alignment)
+ {
+ case align_left:
+ {
+ unsigned padding = width>str.size() ? width - str.size() : 0;
+ unsigned i = 0;
+ while (i++ < padding)
+ result.insert(result.end(), padch);
+ break;
+ }
+ case align_right:
+ {
+ unsigned padding = width>str.size() ? width - str.size() : 0;
+ unsigned i = 0;
+ while (i++ < padding)
+ result.insert(result.begin(), padch);
+ break;
+ }
+ case align_centre:
+ {
+ unsigned padding = width>str.size() ? width - str.size() : 0;
+ unsigned i = 0;
+ while (i++ < padding/2)
+ result.insert(result.end(), padch);
+ i--;
+ while (i++ < padding)
+ result.insert(result.begin(), padch);
+ break;
+ }
+ default:
+ throw std::invalid_argument("invalid alignment value");
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string trim_left(const std::string& val)
+ {
+ std::string result = val;
+ while (!result.empty() && isspace(result[0]))
+ result.erase(result.begin());
+ return result;
+ }
+
+ std::string trim_right(const std::string& val)
+ {
+ std::string result = val;
+ while (!result.empty() && isspace(result[result.size()-1]))
+ result.erase(result.end()-1);
+ return result;
+ }
+
+ std::string trim(const std::string& val)
+ {
+ std::string result = val;
+ while (!result.empty() && isspace(result[0]))
+ result.erase(result.begin());
+ while (!result.empty() && isspace(result[result.size()-1]))
+ result.erase(result.end()-1);
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string lowercase(const std::string& val)
+ {
+ std::string text = val;
+ for (unsigned i = 0; i < text.size(); i++)
+ text[i] = tolower(text[i]);
+ return text;
+ }
+
+ std::string uppercase(const std::string& val)
+ {
+ std::string text = val;
+ for (unsigned i = 0; i < text.size(); i++)
+ text[i] = toupper(text[i]);
+ return text;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string translate(const std::string& input, const std::string& from_set, const std::string& to_set)
+ {
+ std::string result;
+ for (unsigned i = 0; i < input.size(); i++)
+ {
+ char ch = input[i];
+ // check to see if the character is in the from set
+ std::string::size_type found = from_set.find(ch);
+ if (found == std::string::npos)
+ {
+ // not found so just copy across
+ result += ch;
+ }
+ else if (found < to_set.size())
+ {
+ // found and in range so translate
+ result += to_set[found];
+ }
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // WARNING: wheel re-invention follows
+ // Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????
+ // The problem:
+ // * matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches
+ // if not, try 2 characters and see if the remainder matches etc.
+ // this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression
+ // ? matches exactly one character so doesn't need the what-if approach
+ // \ escapes special characters such as *, ? and [
+ // [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]
+ // a set cannot be empty and the ] character can be included by making it the first character
+
+ // function for testing whether a character matches a set
+ // I can't remember the exact rules and I have no definitive references but:
+ // a set contains characters, escaped characters (I think) and ranges in the form a-z
+ // The character '-' can only appear at the start of the set where it is not interpreted as a range
+ // This is a horrible mess - blame the Unix folks for making a hash of wildcards
+
+ static bool match_set (const std::string& set, char match)
+ {
+ // first expand any ranges and remove escape characters to make life more palatable
+ std::string simple_set;
+ for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)
+ {
+ switch(*i)
+ {
+ case '-':
+ {
+ if (i == set.begin())
+ {
+ simple_set += *i;
+ }
+ else if (i+1 == set.end())
+ {
+ return false;
+ }
+ else
+ {
+ // found a set. The first character is already in the result, so first remove it (the set might be empty)
+ simple_set.erase(simple_set.end()-1);
+ char last = *++i;
+ for (char ch = *(i-2); ch <= last; ch++)
+ {
+ simple_set += ch;
+ }
+ }
+ break;
+ }
+ case '\\':
+ if (i+1 == set.end()) {return false;}
+ simple_set += *++i;
+ break;
+ default:
+ simple_set += *i;
+ break;
+ }
+ }
+ std::string::size_type result = simple_set.find(match);
+ return result != std::string::npos;
+ }
+
+ // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match
+ // until either it succeeds or you run out of string to match
+ // for each * in the wildcard another level of recursion is created
+
+ static bool match_remainder (const std::string& wild, std::string::const_iterator wildi,
+ const std::string& match, std::string::const_iterator matchi)
+ {
+ //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;
+ while (wildi != wild.end() && matchi != match.end())
+ {
+ //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;
+ switch(*wildi)
+ {
+ case '*':
+ {
+ ++wildi;
+ ++matchi;
+ for (std::string::const_iterator i = matchi; i != match.end(); ++i)
+ {
+ // deal with * at the end of the wildcard - there is no remainder then
+ if (wildi == wild.end())
+ {
+ if (i == match.end()-1)
+ return true;
+ }
+ else if (match_remainder(wild, wildi, match, i))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ case '[':
+ {
+ // scan for the end of the set using a similar method for avoiding escaped characters
+ bool found = false;
+ std::string::const_iterator end = wildi + 1;
+ for (; !found && end != wild.end(); ++end)
+ {
+ switch(*end)
+ {
+ case ']':
+ {
+ // found the set, now match with its contents excluding the brackets
+ if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))
+ return false;
+ found = true;
+ break;
+ }
+ case '\\':
+ if (end == wild.end()-1)
+ return false;
+ ++end;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ ++matchi;
+ wildi = end;
+ break;
+ }
+ case '?':
+ ++wildi;
+ ++matchi;
+ break;
+ case '\\':
+ if (wildi == wild.end()-1)
+ return false;
+ ++wildi;
+ if (*wildi != *matchi)
+ return false;
+ ++wildi;
+ ++matchi;
+ break;
+ default:
+ if (*wildi != *matchi)
+ return false;
+ ++wildi;
+ ++matchi;
+ break;
+ }
+ }
+ bool result = wildi == wild.end() && matchi == match.end();
+ return result;
+ }
+
+ // like all recursions the exported function has a simpler interface than the
+ // recursive function and is just a 'seed' to the recursion itself
+
+ bool match_wildcard(const std::string& wild, const std::string& match)
+ {
+ return match_remainder(wild, wild.begin(), match, match.begin());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::vector<std::string> split(const std::string& str, const std::string& splitter)
+ {
+ std::vector<std::string> result;
+ if (!str.empty())
+ {
+ for(std::string::size_type offset = 0;;)
+ {
+ std::string::size_type found = str.find(splitter, offset);
+ if (found != std::string::npos)
+ {
+ result.push_back(str.substr(offset, found-offset));
+ offset = found + splitter.size();
+ }
+ else
+ {
+ result.push_back(str.substr(offset, str.size()-offset));
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ std::string join (const std::vector<std::string>& str,
+ const std::string& joiner,
+ const std::string& prefix,
+ const std::string& suffix)
+ {
+ std::string result = prefix;
+ for (unsigned i = 0; i < str.size(); i++)
+ {
+ if (i) result += joiner;
+ result += str[i];
+ }
+ result += suffix;
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string display_bytes(long bytes)
+ {
+ std::string result;
+ if (bytes < 0)
+ {
+ result += '-';
+ bytes = -bytes;
+ }
+ static const long kB = 1024l;
+ static const long MB = kB * kB;
+ static const long GB = MB * kB;
+ if (bytes < kB)
+ result += local_dformat("%i", bytes);
+ else if (bytes < (10l * kB))
+ result += local_dformat("%.2fk", ((float)bytes / (float)kB));
+ else if (bytes < (100l * kB))
+ result += local_dformat("%.1fk", ((float)bytes / (float)kB));
+ else if (bytes < MB)
+ result += local_dformat("%.0fk", ((float)bytes / (float)kB));
+ else if (bytes < (10l * MB))
+ result += local_dformat("%.2fM", ((float)bytes / (float)MB));
+ else if (bytes < (100l * MB))
+ result += local_dformat("%.1fM", ((float)bytes / (float)MB));
+ else if (bytes < GB)
+ result += local_dformat("%.0fM", ((float)bytes / (float)MB));
+ else
+ result += local_dformat("%.2fG", ((float)bytes / (float)GB));
+ return result;
+ }
+
+ std::string display_time(time_t seconds)
+ {
+ unsigned minutes = (unsigned)seconds / 60;
+ seconds %= 60;
+ unsigned hours = minutes / 60;
+ minutes %= 60;
+ unsigned days = hours / 24;
+ hours %= 24;
+ unsigned weeks = days / 7;
+ days %= 7;
+ std::string result;
+ if (weeks > 0)
+ {
+ result += unsigned_to_string(weeks, 10, radix_none, 1);
+ result += "w ";
+ }
+ if (!result.empty() || days > 0)
+ {
+ result += unsigned_to_string(days, 10, radix_none, 1);
+ result += "d ";
+ }
+ if (!result.empty() || hours > 0)
+ {
+ result += unsigned_to_string(hours, 10, radix_none, 1);
+ result += ":";
+ }
+ if (!result.empty() || minutes > 0)
+ {
+ if (!result.empty())
+ result += unsigned_to_string(minutes, 10, radix_none, 2);
+ else
+ result += unsigned_to_string(minutes, 10, radix_none, 1);
+ result += ":";
+ }
+ if (!result.empty())
+ result += unsigned_to_string((unsigned)seconds, 10, radix_none, 2);
+ else
+ {
+ result += unsigned_to_string((unsigned)seconds, 10, radix_none, 1);
+ result += "s";
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus