]> Dogcows Code - chaz/yoink/blobdiff - src/stlplus/strings/string_utilities.cpp
testing new non-autotools build system
[chaz/yoink] / src / stlplus / strings / string_utilities.cpp
diff --git a/src/stlplus/strings/string_utilities.cpp b/src/stlplus/strings/string_utilities.cpp
new file mode 100644 (file)
index 0000000..9ff5345
--- /dev/null
@@ -0,0 +1,442 @@
+////////////////////////////////////////////////////////////////////////////////\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
This page took 0.03027 seconds and 4 git commands to generate.