1 // 2 // Automated Testing Framework (atf) 3 // 4 // Copyright (c) 2007 The NetBSD Foundation, Inc. 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions 9 // are met: 10 // 1. Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // 29 30 extern "C" { 31 #include <regex.h> 32 } 33 34 #include <cctype> 35 #include <cerrno> 36 #include <cstring> 37 38 #include "exceptions.hpp" 39 #include "text.hpp" 40 41 namespace impl = tools::text; 42 #define IMPL_NAME "tools::text" 43 44 char* 45 impl::duplicate(const char* str) 46 { 47 char* copy = new char[std::strlen(str) + 1]; 48 std::strcpy(copy, str); 49 return copy; 50 } 51 52 bool 53 impl::match(const std::string& str, const std::string& regex) 54 { 55 bool found; 56 57 // Special case: regcomp does not like empty regular expressions. 58 if (regex.empty()) { 59 found = str.empty(); 60 } else { 61 ::regex_t preg; 62 63 if (::regcomp(&preg, regex.c_str(), REG_EXTENDED) != 0) 64 throw std::runtime_error("Invalid regular expression '" + regex + 65 "'"); 66 67 const int res = ::regexec(&preg, str.c_str(), 0, NULL, 0); 68 regfree(&preg); 69 if (res != 0 && res != REG_NOMATCH) 70 throw std::runtime_error("Invalid regular expression " + regex); 71 72 found = res == 0; 73 } 74 75 return found; 76 } 77 78 std::string 79 impl::to_lower(const std::string& str) 80 { 81 std::string lc; 82 for (std::string::const_iterator iter = str.begin(); iter != str.end(); 83 iter++) 84 lc += std::tolower(*iter); 85 return lc; 86 } 87 88 std::vector< std::string > 89 impl::split(const std::string& str, const std::string& delim) 90 { 91 std::vector< std::string > words; 92 93 std::string::size_type pos = 0, newpos = 0; 94 while (pos < str.length() && newpos != std::string::npos) { 95 newpos = str.find(delim, pos); 96 if (newpos != pos) 97 words.push_back(str.substr(pos, newpos - pos)); 98 pos = newpos + delim.length(); 99 } 100 101 return words; 102 } 103 104 std::string 105 impl::trim(const std::string& str) 106 { 107 std::string::size_type pos1 = str.find_first_not_of(" \t"); 108 std::string::size_type pos2 = str.find_last_not_of(" \t"); 109 110 if (pos1 == std::string::npos && pos2 == std::string::npos) 111 return ""; 112 else if (pos1 == std::string::npos) 113 return str.substr(0, str.length() - pos2); 114 else if (pos2 == std::string::npos) 115 return str.substr(pos1); 116 else 117 return str.substr(pos1, pos2 - pos1 + 1); 118 } 119 120 bool 121 impl::to_bool(const std::string& str) 122 { 123 const std::string lower = to_lower(str); 124 if (lower == "yes" || lower == "true") 125 return true; 126 else if (lower == "no" || lower == "false") 127 return false; 128 else { 129 // XXX Not really a libc error. 130 throw system_error(IMPL_NAME "::to_bool", "Cannot convert string " 131 "'" + str + "' to boolean", EINVAL); 132 } 133 } 134 135 int64_t 136 impl::to_bytes(std::string str) 137 { 138 if (str.empty()) 139 throw std::runtime_error("Empty value"); 140 141 const char unit = str[str.length() - 1]; 142 int64_t multiplier; 143 switch (unit) { 144 case 'k': case 'K': multiplier = 1 << 10; break; 145 case 'm': case 'M': multiplier = 1 << 20; break; 146 case 'g': case 'G': multiplier = 1 << 30; break; 147 case 't': case 'T': multiplier = int64_t(1) << 40; break; 148 default: 149 if (!std::isdigit(unit)) 150 throw std::runtime_error(std::string("Unknown size unit '") + unit 151 + "'"); 152 multiplier = 1; 153 } 154 if (multiplier != 1) 155 str.erase(str.length() - 1); 156 157 return to_type< int64_t >(str) * multiplier; 158 } 159