LCOV - code coverage report
Current view: top level - src/utils/common - StringUtils.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 77.7 % 296 230
Test Date: 2026-07-26 16:30:20 Functions: 74.4 % 39 29

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    StringUtils.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Laura Bieker
      17              : /// @author  Michael Behrisch
      18              : /// @author  Robert Hilbrich
      19              : /// @date    unknown
      20              : ///
      21              : // Some static methods for string processing
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <string>
      26              : #include <iostream>
      27              : #include <cstdio>
      28              : #include <cstring>
      29              : #include <regex>
      30              : #ifdef WIN32
      31              : #define NOMINMAX
      32              : #include <windows.h>
      33              : #undef NOMINMAX
      34              : #else
      35              : #include <unistd.h>
      36              : #endif
      37              : #include <utils/common/UtilExceptions.h>
      38              : #include <utils/common/ToString.h>
      39              : #include <utils/common/StringTokenizer.h>
      40              : #include "StringUtils.h"
      41              : 
      42              : #define KM_PER_MILE 1.609344
      43              : 
      44              : 
      45              : // ===========================================================================
      46              : // static member definitions
      47              : // ===========================================================================
      48              : std::string StringUtils::emptyString;
      49              : 
      50              : 
      51              : // ===========================================================================
      52              : // method definitions
      53              : // ===========================================================================
      54              : std::string
      55      1589779 : StringUtils::prune(const std::string& str) {
      56              :     const std::string::size_type endpos = str.find_last_not_of(" \t\n\r");
      57      1589779 :     if (std::string::npos != endpos) {
      58      1586641 :         const int startpos = (int)str.find_first_not_of(" \t\n\r");
      59      1586641 :         return str.substr(startpos, endpos - startpos + 1);
      60              :     }
      61         3138 :     return "";
      62              : }
      63              : 
      64              : 
      65              : std::string
      66        57154 : StringUtils::pruneZeros(const std::string& str, int max) {
      67              :     const std::string::size_type endpos = str.find_last_not_of("0");
      68        57154 :     if (endpos != std::string::npos && str.back() == '0') {
      69        38117 :         std::string res = str.substr(0, MAX2((int)str.size() - max, (int)endpos + 1));
      70        38117 :         return res;
      71              :     }
      72              :     return str;
      73              : }
      74              : 
      75              : std::string
      76      8287196 : StringUtils::to_lower_case(const std::string& str) {
      77              :     std::string s = str;
      78              :     std::transform(s.begin(), s.end(), s.begin(), [](char c) {
      79     57285894 :         return (char)::tolower(c);
      80              :     });
      81      8287196 :     return s;
      82              : }
      83              : 
      84              : 
      85              : std::string
      86            0 : StringUtils::to_upper_case(const std::string& str) {
      87              :     std::string s = str;
      88              :     std::transform(s.begin(), s.end(), s.begin(), [](char c) {
      89            0 :         return (char)::toupper(c);
      90              :     });
      91            0 :     return s;
      92              : }
      93              : 
      94              : 
      95              : std::string
      96         1956 : StringUtils::latin1_to_utf8(std::string str) {
      97              :     // inspired by http://stackoverflow.com/questions/4059775/convert-iso-8859-1-strings-to-utf-8-in-c-c
      98              :     std::string result;
      99         8781 :     for (const auto& c : str) {
     100         6825 :         const unsigned char uc = (unsigned char)c;
     101         6825 :         if (uc < 128) {
     102              :             result += uc;
     103              :         } else {
     104          100 :             result += (char)(0xc2 + (uc > 0xbf));
     105          100 :             result += (char)((uc & 0x3f) + 0x80);
     106              :         }
     107              :     }
     108         1956 :     return result;
     109              : }
     110              : 
     111              : 
     112              : std::string
     113      1314608 : StringUtils::convertUmlaute(std::string str) {
     114      3943824 :     str = replace(str, "\xE4", "ae");
     115      3943824 :     str = replace(str, "\xC4", "Ae");
     116      3943824 :     str = replace(str, "\xF6", "oe");
     117      3943824 :     str = replace(str, "\xD6", "Oe");
     118      3943824 :     str = replace(str, "\xFC", "ue");
     119      3943824 :     str = replace(str, "\xDC", "Ue");
     120      3943824 :     str = replace(str, "\xDF", "ss");
     121      3943824 :     str = replace(str, "\xC9", "E");
     122      3943824 :     str = replace(str, "\xE9", "e");
     123      3943824 :     str = replace(str, "\xC8", "E");
     124      3943824 :     str = replace(str, "\xE8", "e");
     125      1314608 :     return str;
     126              : }
     127              : 
     128              : 
     129              : std::string
     130     72310267 : StringUtils::replace(std::string str, const std::string& what, const std::string& by) {
     131              :     std::string::size_type idx = str.find(what);
     132     72310267 :     const int what_len = (int)what.length();
     133     72310267 :     if (what_len > 0) {
     134     72310266 :         const int by_len = (int)by.length();
     135     72314193 :         while (idx != std::string::npos) {
     136         3927 :             str = str.replace(idx, what_len, by);
     137         3927 :             idx = str.find(what, idx + by_len);
     138              :         }
     139              :     }
     140     72310267 :     return str;
     141              : }
     142              : 
     143              : 
     144              : std::string
     145      1340182 : StringUtils::substituteEnvironment(const std::string& str, const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
     146              :     std::string s = str;
     147      1340182 :     if (timeRef != nullptr) {
     148              :         const std::string::size_type localTimeIndex = str.find("${LOCALTIME}");
     149              :         const std::string::size_type utcIndex = str.find("${UTC}");
     150              :         const bool isUTC = utcIndex != std::string::npos;
     151      1340176 :         if (localTimeIndex != std::string::npos || isUTC) {
     152            6 :             const time_t rawtime = std::chrono::system_clock::to_time_t(*timeRef);
     153              :             char buffer [80];
     154            6 :             struct tm* timeinfo = isUTC ? gmtime(&rawtime) : localtime(&rawtime);
     155            6 :             strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S.", timeinfo);
     156              :             auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(*timeRef);
     157              :             auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(*timeRef - seconds);
     158            6 :             const std::string micro = buffer + toString(microseconds.count());
     159            6 :             if (isUTC) {
     160              :                 s.replace(utcIndex, 6, micro);
     161              :             } else {
     162              :                 s.replace(localTimeIndex, 12, micro);
     163              :             }
     164              :         }
     165              :     }
     166              :     const std::string::size_type pidIndex = str.find("${PID}");
     167      1340182 :     if (pidIndex != std::string::npos) {
     168              : #ifdef WIN32
     169              :         s.replace(pidIndex, 6, toString(::GetCurrentProcessId()));
     170              : #else
     171            6 :         s.replace(pidIndex, 6, toString(::getpid()));
     172              : #endif
     173              :     }
     174      1340182 :     if (std::getenv("SUMO_LOGO") == nullptr) {
     175      4020546 :         s = replace(s, "${SUMO_LOGO}", "${SUMO_HOME}/data/logo/sumo-128x138.png");
     176              :     }
     177              :     const std::string::size_type tildeIndex = str.find("~");
     178      1340182 :     if (tildeIndex == 0) {
     179            3 :         s.replace(0, 1, "${HOME}");
     180              :     }
     181      4020546 :     s = replace(s, ",~", ",${HOME}");
     182              : #ifdef WIN32
     183              :     if (std::getenv("HOME") == nullptr) {
     184              :         s = replace(s, "${HOME}", "${USERPROFILE}");
     185              :     }
     186              : #endif
     187              : 
     188              :     // Expression for an environment variables, e.g. ${NAME}
     189              :     // Note: - R"(...)" is a raw string literal syntax to simplify a regex declaration
     190              :     //       - .+? looks for the shortest match (non-greedy)
     191              :     //       - (.+?) defines a "subgroup" which is already stripped of the $ and {, }
     192      1340182 :     std::regex envVarExpr(R"(\$\{(.+?)\})");
     193              : 
     194              :     // Are there any variables in this string?
     195              :     std::smatch match;
     196              :     std::string strIter = s;
     197              : 
     198              :     // Loop over the entire value string and look for variable names
     199      1340248 :     while (std::regex_search(strIter, match, envVarExpr)) {
     200              :         std::string varName = match[1];
     201              : 
     202              :         // Find the variable in the environment and its value
     203              :         std::string varValue;
     204           66 :         if (std::getenv(varName.c_str()) != nullptr) {
     205           65 :             varValue = std::getenv(varName.c_str());
     206              :         }
     207              : 
     208              :         // Replace the variable placeholder with its value in the original string
     209          264 :         s = std::regex_replace(s, std::regex("\\$\\{" + varName + "\\}"), varValue);
     210              : 
     211              :         // Continue the loop with the remainder of the string
     212          132 :         strIter = match.suffix();
     213              :     }
     214      1340182 :     return s;
     215      1340182 : }
     216              : 
     217              : 
     218              : std::string
     219        88375 : StringUtils::isoTimeString(const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
     220        88375 :     const std::chrono::system_clock::time_point now = timeRef == nullptr ? std::chrono::system_clock::now() : *timeRef;
     221              :     const auto now_seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
     222        88375 :     const std::time_t now_c = std::chrono::system_clock::to_time_t(now);
     223              :     const auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - now_seconds).count();
     224        88375 :     std::tm local_tm = *std::localtime(&now_c);
     225              : 
     226              :     // Get the time zone offset
     227        88375 :     std::time_t utc_time = std::time(nullptr);
     228        88375 :     std::tm utc_tm = *std::gmtime(&utc_time);
     229        88375 :     const double offset = std::difftime(std::mktime(&local_tm), std::mktime(&utc_tm)) / 3600.0;
     230        88375 :     const int hours_offset = static_cast<int>(offset);
     231        88375 :     const int minutes_offset = static_cast<int>((offset - hours_offset) * 60);
     232              : 
     233              :     // Format the time
     234        88375 :     std::ostringstream oss;
     235              :     char buf[32];
     236        88375 :     std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &local_tm);
     237              :     oss << buf << "."
     238              :         << std::setw(6) << std::setfill('0') << std::abs(microseconds)
     239              :         << (hours_offset >= 0 ? "+" : "-")
     240        88375 :         << std::setw(2) << std::setfill('0') << std::abs(hours_offset) << ":"
     241       176750 :         << std::setw(2) << std::setfill('0') << std::abs(minutes_offset);
     242        88375 :     return oss.str();
     243        88375 : }
     244              : 
     245              : 
     246              : bool
     247      6720067 : StringUtils::startsWith(const std::string& str, const std::string prefix) {
     248      6720067 :     return str.compare(0, prefix.length(), prefix) == 0;
     249              : }
     250              : 
     251              : 
     252              : bool
     253       224477 : StringUtils::endsWith(const std::string& str, const std::string suffix) {
     254       224477 :     if (str.length() >= suffix.length()) {
     255       224454 :         return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
     256              :     } else {
     257              :         return false;
     258              :     }
     259              : }
     260              : 
     261              : 
     262              : std::string
     263            0 : StringUtils::padFront(const std::string& str, int length, char padding) {
     264            0 :     return std::string(MAX2(0, length - (int)str.size()), padding) + str;
     265              : }
     266              : 
     267              : 
     268              : std::string
     269      1504861 : StringUtils::escapeXML(const std::string& orig, const bool maskDoubleHyphen) {
     270      4514583 :     std::string result = replace(orig, "&", "&amp;");
     271      4514583 :     result = replace(result, ">", "&gt;");
     272      4514583 :     result = replace(result, "<", "&lt;");
     273      4514583 :     result = replace(result, "\"", "&quot;");
     274      1504861 :     if (maskDoubleHyphen) {
     275      2342838 :         result = replace(result, "--", "&#45;&#45;");
     276              :     }
     277     48155552 :     for (char invalid = '\1'; invalid < ' '; invalid++) {
     278    233253455 :         result = replace(result, std::string(1, invalid).c_str(), "");
     279              :     }
     280      4514583 :     return replace(result, "'", "&apos;");
     281              : }
     282              : 
     283              : 
     284              : std::string
     285            0 : StringUtils::escapeShell(const std::string& orig) {
     286            0 :     return replace(orig, "\"", "\\\"");
     287              : }
     288              : 
     289              : 
     290              : std::string
     291         4072 : StringUtils::escapeCSV(const std::string& orig, const char separator, const char quote) {
     292         4072 :     const std::string chars{separator, quote};
     293         4072 :     if (orig.find_first_of(chars) == std::string::npos) {
     294              :         return orig;
     295              :     }
     296           36 :     const std::string quoteStr{quote};
     297          108 :     return quoteStr + replace(orig, quoteStr, {'\\', quote}) + quoteStr;
     298              : }
     299              : 
     300              : 
     301              : std::string
     302         5121 : StringUtils::urlEncode(const std::string& toEncode, const std::string encodeWhich) {
     303         5121 :     std::ostringstream out;
     304              : 
     305       131266 :     for (int i = 0; i < (int)toEncode.length(); ++i) {
     306       126145 :         const char t = toEncode.at(i);
     307              : 
     308       126145 :         if ((encodeWhich != "" && encodeWhich.find(t) == std::string::npos) ||
     309            1 :                 (encodeWhich == "" &&
     310            0 :                  ((t >= 45 && t <= 57) ||       // hyphen, period, slash, 0-9
     311            0 :                   (t >= 65 && t <= 90) ||        // A-Z
     312              :                   t == 95 ||                     // underscore
     313              :                   (t >= 97 && t <= 122) ||       // a-z
     314              :                   t == 126))                     // tilde
     315              :            ) {
     316       126144 :             out << toEncode.at(i);
     317              :         } else {
     318            2 :             out << charToHex(toEncode.at(i));
     319              :         }
     320              :     }
     321              : 
     322         5121 :     return out.str();
     323         5121 : }
     324              : 
     325              : 
     326              : std::string
     327        92738 : StringUtils::urlDecode(const std::string& toDecode) {
     328        92738 :     std::ostringstream out;
     329              : 
     330      1971581 :     for (int i = 0; i < (int)toDecode.length(); ++i) {
     331      1878845 :         if (toDecode.at(i) == '%') {
     332            2 :             std::string str(toDecode.substr(i + 1, 2));
     333            2 :             out << hexToChar(str);
     334            0 :             i += 2;
     335              :         } else {
     336      1878843 :             out << toDecode.at(i);
     337              :         }
     338              :     }
     339              : 
     340        92736 :     return out.str();
     341        92738 : }
     342              : 
     343              : std::string
     344            1 : StringUtils::charToHex(unsigned char c) {
     345              :     short i = c;
     346              : 
     347            1 :     std::stringstream s;
     348              : 
     349            1 :     s << "%" << std::setw(2) << std::setfill('0') << std::hex << i;
     350              : 
     351            1 :     return s.str();
     352            1 : }
     353              : 
     354              : 
     355              : unsigned char
     356            2 : StringUtils::hexToChar(const std::string& str) {
     357            2 :     short c = 0;
     358            2 :     if (!str.empty()) {
     359            2 :         std::istringstream in(str);
     360            2 :         in >> std::hex >> c;
     361            2 :         if (in.fail()) {
     362            4 :             throw NumberFormatException(str + " could not be interpreted as hex");
     363              :         }
     364            2 :     }
     365            0 :     return static_cast<unsigned char>(c);
     366              : }
     367              : 
     368              : 
     369              : int
     370     19144172 : StringUtils::toInt(const std::string& sData) {
     371     19144172 :     long long int result = toLong(sData);
     372     19126704 :     if (result > std::numeric_limits<int>::max() || result < std::numeric_limits<int>::min()) {
     373            3 :         throw NumberFormatException(toString(result) + " int overflow");
     374              :     }
     375     19126703 :     return (int)result;
     376              : }
     377              : 
     378              : 
     379              : bool
     380            8 : StringUtils::isInt(const std::string& sData) {
     381              :     // first check if can be converted to long int
     382            8 :     if (isLong(sData)) {
     383            0 :         const long long int result = toLong(sData);
     384              :         // now check if the result is in the range of an int
     385            0 :         return ((result <= std::numeric_limits<int>::max()) && (result >= std::numeric_limits<int>::min()));
     386              :     }
     387              :     return false;
     388              : }
     389              : 
     390              : 
     391              : int
     392            0 : StringUtils::toIntSecure(const std::string& sData, int def) {
     393            0 :     if (sData.length() == 0) {
     394              :         return def;
     395              :     }
     396            0 :     return toInt(sData);
     397              : }
     398              : 
     399              : 
     400              : long long int
     401     20588135 : StringUtils::toLong(const std::string& sData) {
     402              :     const char* const data = sData.c_str();
     403     20588135 :     if (data == 0 || data[0] == 0) {
     404           64 :         throw EmptyData();
     405              :     }
     406              :     char* end;
     407     20588071 :     errno = 0;
     408              : #ifdef _MSC_VER
     409              :     long long int ret = _strtoi64(data, &end, 10);
     410              : #else
     411     20588071 :     long long int ret = strtoll(data, &end, 10);
     412              : #endif
     413     20588071 :     if (errno == ERANGE) {
     414            0 :         errno = 0;
     415            0 :         throw NumberFormatException("(long long integer range) " + sData);
     416              :     }
     417     20588071 :     if ((int)(end - data) != (int)strlen(data)) {
     418        36054 :         throw NumberFormatException("(long long integer format) " + sData);
     419              :     }
     420     20570044 :     return ret;
     421              : }
     422              : 
     423              : 
     424              : bool
     425            8 : StringUtils::isLong(const std::string& sData) {
     426              :     const char* const data = sData.c_str();
     427            8 :     if (data == 0 || data[0] == 0) {
     428              :         return false;
     429              :     }
     430              :     char* end;
     431              :     // reset errno before parsing, to keep errors
     432            8 :     errno = 0;
     433              :     // continue depending of current plattform
     434              : #ifdef _MSC_VER
     435              :     _strtoi64(data, &end, 10);
     436              : #else
     437            8 :     strtoll(data, &end, 10);
     438              : #endif
     439              :     // check out of range
     440            8 :     if (errno == ERANGE) {
     441              :         return false;
     442              :     }
     443              :     // check length of converted data
     444            8 :     if ((int)(end - data) != (int)strlen(data)) {
     445              :         return false;
     446              :     }
     447              :     return true;
     448              : }
     449              : 
     450              : 
     451              : int
     452          968 : StringUtils::hexToInt(const std::string& sData) {
     453          968 :     if (sData.length() == 0) {
     454            0 :         throw EmptyData();
     455              :     }
     456          968 :     size_t idx = 0;
     457              :     int result;
     458              :     try {
     459          968 :         if (sData[0] == '#') { // for html color codes
     460          884 :             result = std::stoi(sData.substr(1), &idx, 16);
     461          884 :             idx++;
     462              :         } else {
     463              :             result = std::stoi(sData, &idx, 16);
     464              :         }
     465            0 :     } catch (...) {
     466            0 :         throw NumberFormatException("(hex integer format) " + sData);
     467            0 :     }
     468          968 :     if (idx != sData.length()) {
     469            0 :         throw NumberFormatException("(hex integer format) " + sData);
     470              :     }
     471          968 :     return result;
     472              : }
     473              : 
     474              : 
     475              : bool
     476            0 : StringUtils::isHex(std::string sData) {
     477            0 :     if (sData.length() == 0) {
     478              :         return false;
     479              :     }
     480              :     // remove the first character (for HTML color codes)
     481            0 :     if (sData[0] == '#') {
     482            0 :         sData = sData.substr(1);
     483              :     }
     484              :     const char* sDataPtr = sData.c_str();
     485              :     char* returnPtr;
     486              :     // reset errno
     487            0 :     errno = 0;
     488              :     // call string to long (size 16) from standard library
     489            0 :     strtol(sDataPtr, &returnPtr, 16);
     490              :     // check out of range
     491            0 :     if (errno == ERANGE) {
     492              :         return false;
     493              :     }
     494              :     // check if there was an error converting sDataPtr to double,
     495            0 :     if (sDataPtr == returnPtr) {
     496              :         return false;
     497              :     }
     498              :     // compare size of start and end points
     499            0 :     if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
     500              :         return false;
     501              :     }
     502              :     return true;
     503              : }
     504              : 
     505              : 
     506              : double
     507     76541635 : StringUtils::toDouble(const std::string& sData) {
     508     76541635 :     if (sData.size() == 0) {
     509          191 :         throw EmptyData();
     510              :     }
     511              :     try {
     512     76541444 :         size_t idx = 0;
     513              :         const double result = std::stod(sData, &idx);
     514     76539863 :         if (idx != sData.size()) {
     515           34 :             throw NumberFormatException("(double format) " + sData);
     516              :         } else {
     517     76539846 :             return result;
     518              :         }
     519         1598 :     } catch (...) {
     520              :         // invalid_argument or out_of_range
     521         3196 :         throw NumberFormatException("(double) " + sData);
     522         1598 :     }
     523              : }
     524              : 
     525              : 
     526              : bool
     527            0 : StringUtils::isDouble(const std::string& sData) {
     528            0 :     if (sData.size() == 0) {
     529              :         return false;
     530              :     }
     531              :     const char* sDataPtr = sData.c_str();
     532              :     char* returnPtr;
     533              :     // reset errno
     534            0 :     errno = 0;
     535              :     // call string to double from standard library
     536            0 :     strtod(sDataPtr, &returnPtr);
     537              :     // check out of range
     538            0 :     if (errno == ERANGE) {
     539              :         return false;
     540              :     }
     541              :     // check if there was an error converting sDataPtr to double,
     542            0 :     if (sDataPtr == returnPtr) {
     543              :         return false;
     544              :     }
     545              :     // compare size of start and end points
     546            0 :     if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
     547              :         return false;
     548              :     }
     549              :     return true;
     550              : }
     551              : 
     552              : 
     553              : double
     554          368 : StringUtils::toDoubleSecure(const std::string& sData, const double def) {
     555          368 :     if (sData.length() == 0) {
     556              :         return def;
     557              :     }
     558          368 :     return toDouble(sData);
     559              : }
     560              : 
     561              : 
     562              : bool
     563      3348393 : StringUtils::toBool(const std::string& sData) {
     564      3348393 :     if (sData.length() == 0) {
     565            1 :         throw EmptyData();
     566              :     }
     567      3348392 :     const std::string s = to_lower_case(sData);
     568      3348392 :     if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
     569              :         return true;
     570              :     }
     571      2704265 :     if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
     572              :         return false;
     573              :     }
     574          147 :     throw BoolFormatException(s);
     575              : }
     576              : 
     577              : 
     578              : bool
     579        75642 : StringUtils::isBool(const std::string& sData) {
     580        75642 :     if (sData.length() == 0) {
     581              :         return false;
     582              :     }
     583        17628 :     const std::string s = to_lower_case(sData);
     584              :     // check true values
     585        17628 :     if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
     586              :         return true;
     587              :     }
     588              :     // check false values
     589         1064 :     if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
     590              :         return true;
     591              :     }
     592              :     // no valid true or false values
     593              :     return false;
     594              : }
     595              : 
     596              : 
     597              : MMVersion
     598        47883 : StringUtils::toVersion(const std::string& sData) {
     599       143649 :     std::vector<std::string> parts = StringTokenizer(sData, ".").getVector();
     600        95766 :     return MMVersion(toInt(parts.front()), toDouble(parts.back()));
     601        47883 : }
     602              : 
     603              : 
     604              : double
     605         2287 : StringUtils::parseDist(const std::string& sData) {
     606         2287 :     if (sData.size() == 0) {
     607            1 :         throw EmptyData();
     608              :     }
     609              :     try {
     610         2286 :         size_t idx = 0;
     611              :         const double result = std::stod(sData, &idx);
     612         2285 :         if (idx != sData.size()) {
     613            5 :             const std::string unit = prune(sData.substr(idx));
     614            5 :             if (unit == "m" || unit == "metre" || unit == "meter" || unit == "metres" || unit == "meters") {
     615              :                 return result;
     616              :             }
     617            2 :             if (unit == "km" || unit == "kilometre" || unit == "kilometer" || unit == "kilometres" || unit == "kilometers") {
     618            1 :                 return result * 1000.;
     619              :             }
     620            1 :             if (unit == "mi" || unit == "mile" || unit == "miles") {
     621            0 :                 return result * 1000. * KM_PER_MILE;
     622              :             }
     623            1 :             if (unit == "nmi") {
     624            0 :                 return result * 1852.;
     625              :             }
     626            1 :             if (unit == "ft" || unit == "foot" || unit == "feet") {
     627            0 :                 return result * 12. * 0.0254;
     628              :             }
     629            1 :             if (unit == "\"" || unit == "in" || unit == "inch" || unit == "inches") {
     630            0 :                 return result * 0.0254;
     631              :             }
     632            1 :             if (unit[0] == '\'') {
     633            0 :                 double inches = 12 * result;
     634            0 :                 if (unit.length() > 1) {
     635            0 :                     inches += std::stod(unit.substr(1), &idx);
     636            1 :                     if (unit.substr(idx) == "\"") {
     637            0 :                         return inches * 0.0254;
     638              :                     }
     639              :                 }
     640              :             }
     641            2 :             throw NumberFormatException("(distance format) " + sData);
     642              :         } else {
     643              :             return result;
     644              :         }
     645            2 :     } catch (...) {
     646              :         // invalid_argument or out_of_range
     647            4 :         throw NumberFormatException("(double) " + sData);
     648            2 :     }
     649              : }
     650              : 
     651              : 
     652              : double
     653         8129 : StringUtils::parseSpeed(const std::string& sData, const bool defaultKmph) {
     654         8129 :     if (sData.size() == 0) {
     655            1 :         throw EmptyData();
     656              :     }
     657              :     try {
     658         8128 :         size_t idx = 0;
     659              :         const double result = std::stod(sData, &idx);
     660         8124 :         if (idx != sData.size()) {
     661         1247 :             const std::string unit = prune(sData.substr(idx));
     662         1247 :             if (unit == "km/h" || unit == "kph" || unit == "kmh" || unit == "kmph") {
     663            3 :                 return result / 3.6;
     664              :             }
     665         1244 :             if (unit == "m/s") {
     666              :                 return result;
     667              :             }
     668         1242 :             if (unit == "mph") {
     669         1241 :                 return result * KM_PER_MILE / 3.6;
     670              :             }
     671            1 :             if (unit == "knots") {
     672            0 :                 return result * 1.852 / 3.6;
     673              :             }
     674            2 :             throw NumberFormatException("(speed format) " + sData);
     675              :         } else {
     676         6877 :             return defaultKmph ? result / 3.6 : result;
     677              :         }
     678            5 :     } catch (...) {
     679              :         // invalid_argument or out_of_range
     680           10 :         throw NumberFormatException("(double) " + sData);
     681            5 :     }
     682              : }
     683              : 
     684              : 
     685              : 
     686              : std::string
     687            0 : StringUtils::trim_left(const std::string s, const std::string& t) {
     688              :     std::string result = s;
     689            0 :     result.erase(0, s.find_first_not_of(t));
     690            0 :     return result;
     691              : }
     692              : 
     693              : std::string
     694            0 : StringUtils::trim_right(const std::string s, const std::string& t) {
     695              :     std::string result = s;
     696            0 :     result.erase(s.find_last_not_of(t) + 1);
     697            0 :     return result;
     698              : }
     699              : 
     700              : std::string
     701            0 : StringUtils::trim(const std::string s, const std::string& t) {
     702            0 :     return trim_right(trim_left(s, t), t);
     703              : }
     704              : 
     705              : 
     706              : std::string
     707            0 : StringUtils::wrapText(const std::string s, int width) {
     708            0 :     std::vector<std::string> parts = StringTokenizer(s).getVector();
     709              :     std::string result;
     710              :     std::string line;
     711              :     bool firstLine = true;
     712              :     bool firstWord = true;
     713            0 :     for (std::string p : parts) {
     714            0 :         if ((int)(line.size() + p.size()) < width || firstWord) {
     715            0 :             if (firstWord) {
     716              :                 firstWord = false;
     717              :             } else {
     718              :                 line += " ";
     719              :             }
     720              :             line += p;
     721              :         } else {
     722            0 :             if (firstLine) {
     723              :                 firstLine = false;
     724              :             } else {
     725              :                 result += "\n";
     726              :             }
     727              :             result += line;
     728              :             line.clear();
     729              :             line += p;
     730              :         }
     731              :     }
     732            0 :     if (line.size() > 0) {
     733            0 :         if (firstLine) {
     734              :             firstLine = false;
     735              :         } else {
     736              :             result += "\n";
     737              :         }
     738              :         result += line;
     739              :     }
     740            0 :     return result;
     741            0 : }
     742              : 
     743              : 
     744              : std::string
     745          966 : StringUtils::adjustDecimalValue(double value, int precision) {
     746              :     // obtain value in string format with 20 decimals precision
     747          966 :     auto valueStr = toString(value, precision);
     748              :     // now clear all zeros
     749        16970 :     while (valueStr.size() > 1) {
     750        16970 :         if (valueStr.back() == '0') {
     751              :             valueStr.pop_back();
     752          966 :         } else if (valueStr.back() == '.') {
     753              :             valueStr.pop_back();
     754              :             return valueStr;
     755              :         } else {
     756              :             return valueStr;
     757              :         }
     758              :     }
     759              :     return valueStr;
     760              : }
     761              : 
     762              : 
     763              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1