// ---------------------------------------------------------------------- // File: ParseUtils.hh // Author: Georgios Bitzes - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ //------------------------------------------------------------------------------ //! @author Georgios Bitzes //! @brief Parse utilities with proper error checking //------------------------------------------------------------------------------ #pragma once #include "common/Namespace.hh" #include "common/Logging.hh" #include "common/StringTokenizer.hh" #include #include EOSCOMMONNAMESPACE_BEGIN //------------------------------------------------------------------------------ //! Parse an int64 encoded in the given numerical base, return true if parsing //! was successful, false otherwise. //------------------------------------------------------------------------------ inline bool ParseInt64(const std::string& str, int64_t& ret, int base = 10) { char* endptr = NULL; ret = std::strtoll(str.c_str(), &endptr, base); if (endptr != str.c_str() + str.size() || ret == std::numeric_limits::min() || ret == std::numeric_limits::max()) { return false; } return true; } //------------------------------------------------------------------------------ //! Parse an uint64 encoded in the given numerical base, return true if parsing //! was successful, false otherwise. //------------------------------------------------------------------------------ inline bool ParseUInt64(const std::string& str, uint64_t& ret, int base = 10) { char* endptr = NULL; ret = std::strtoull(str.c_str(), &endptr, base); if (endptr != str.c_str() + str.size() || ret == std::numeric_limits::min() || ret == std::numeric_limits::max()) { return false; } return true; } //------------------------------------------------------------------------------ //! Parse a long long - behave exactly the same as old XrdMq "GetLongLong". //------------------------------------------------------------------------------ inline long long ParseLongLong(const std::string& str) { if (str.length()) { errno = 0; long long ret = strtoll(str.c_str(), 0, 10); if (!errno) { return ret; } } return 0; } //------------------------------------------------------------------------------ //! Parse a long long - behave exactly the same as old XrdMq "GetDouble". //------------------------------------------------------------------------------ inline double ParseDouble(const std::string& str) { if (str.length()) { return atof(str.c_str()); } return 0; } //------------------------------------------------------------------------------ //! Parse hostname and port from input string. If no port value present then //! default to 1094. //! //! @param input input string e.g. hostname.cern.ch:port //! @param host parsed hostname //! @parma port parsed port //! //! @return true if parsing succeeded, otherwise false //------------------------------------------------------------------------------ inline bool ParseHostNamePort(const std::string& input, std::string& host, int& port) { if (input.empty()) { return false; } size_t pos = input.find(':'); if ((pos == std::string::npos) || (pos == input.length())) { host = input; port = 1094; } else { host = input.substr(0, pos); int64_t ret = 0ll; if (!ParseInt64(input.substr(pos + 1), ret)) { return false; } port = ret; } return true; } //------------------------------------------------------------------------------ //! Check that the given string is a valid hostname or IP specification //! //! @param input hostname host.cern.ch or IP address //------------------------------------------------------------------------------ inline bool ValidHostnameOrIP(const std::string& input) { for (const auto& c : input) { if (!std::isalnum(c) && (c != '.') && (c != '-') && (c != ':')) { return false; } } return true; } //----------------------------------------------------------------------------- //! Make sure that geotag contains only alphanumeric segments which //! are no longer than 8 characters, in ::::...:: format. //! //! @param geotag input value //! //! @return error message if geotag is not valid, otherwise geotag //----------------------------------------------------------------------------- inline std::string SanitizeGeoTag(const std::string& geotag) { if (geotag.empty()) { return std::string("Error: empty geotag"); } if (geotag == "") { return geotag; } std::string tmp_tag(geotag); auto segments = eos::common::StringTokenizer::split> (tmp_tag, ':'); tmp_tag.clear(); for (const auto& segment : segments) { if (segment.empty()) { continue; } if (segment.length() > 8) { return std::string("Error: geotag segment '" + segment + "' is longer than 8 chars"); } for (const auto& c : segment) { if (!std::isalnum(c)) { return std::string("Error: geotag segment '" + segment + "' " "contains non-alphanumeric char '" + c + "'"); } } tmp_tag += segment; tmp_tag += "::"; } if (tmp_tag.length() <= 2) { return std::string("Error: empty geotag"); } tmp_tag.erase(tmp_tag.length() - 2); if (tmp_tag != geotag) { return std::string("Error: invalid geotag format '" + geotag + "'"); } return tmp_tag; } EOSCOMMONNAMESPACE_END