blob: 00b48bd9ad71b0e2768065ff59653dc2e7a37858 [file] [log] [blame]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenseas/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_
#define LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_
#include <exception>
#include <string>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <type_traits>
#include <limits>
#include <algorithm>
#include "PropertyErrors.h"
namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace utils {
namespace internal {
class ValueParser {
public:
explicit ValueParser(const std::string& str, std::size_t offset = 0) : str(str), offset(offset) {}
ValueParser& parse(int& out) { // NOLINT
long result; // NOLINT
auto len = safeCallConverter(std::strtol, result);
if (len == 0) {
throw ParseException("Couldn't parse int");
}
if (result < (std::numeric_limits<int>::min)() || result > (std::numeric_limits<int>::max)()) {
throw ParseException("Cannot convert long to int");
}
offset += len;
out = result;
return *this;
}
ValueParser& parse(int64_t& out) {
long long result; // NOLINT
auto len = safeCallConverter(std::strtoll, result);
if (len == 0) {
throw ParseException("Couldn't parse long long");
}
if (result < (std::numeric_limits<int64_t>::min)() || result > (std::numeric_limits<int64_t>::max)()) {
throw ParseException("Cannot convert long long to int64_t");
}
offset += len;
out = result;
return *this;
}
ValueParser& parse(uint32_t & out) {
skipWhitespace();
if (offset < str.length() && str[offset] == '-') {
throw ParseException("Not an unsigned long");
}
unsigned long result; // NOLINT
auto len = safeCallConverter(std::strtoul, result);
if (len == 0) {
throw ParseException("Couldn't parse uint32_t");
}
if (result > (std::numeric_limits<uint32_t>::max)()) {
throw ParseException("Cannot convert unsigned long to uint32_t");
}
offset += len;
out = result;
return *this;
}
ValueParser& parse(uint64_t& out) {
skipWhitespace();
if (offset < str.length() && str[offset] == '-') {
throw ParseException("Not an unsigned long");
}
unsigned long long result; // NOLINT
auto len = safeCallConverter(std::strtoull, result);
if (len == 0) {
throw ParseException("Couldn't parse unsigned long long");
}
if (result > (std::numeric_limits<uint64_t>::max)()) {
throw ParseException("Cannot convert unsigned long long to uint64_t");
}
offset += len;
out = result;
return *this;
}
ValueParser& parse(bool& out) {
skipWhitespace();
if (std::strncmp(str.c_str() + offset, "false", std::strlen("false")) == 0) {
offset += std::strlen("false");
out = false;
} else if (std::strncmp(str.c_str() + offset, "true", std::strlen("true")) == 0) {
offset += std::strlen("true");
out = true;
} else {
throw ParseException("Couldn't parse bool");
}
return *this;
}
void parseEnd() {
skipWhitespace();
if (offset < str.length()) {
throw ParseException("Expected to parse till the end");
}
}
private:
/**
*
* @tparam T
* @param converter
* @param out
* @return the number of characters used during conversion, 0 for error
*/
template<typename T>
std::size_t safeCallConverter(T (*converter)(const char* begin, char** end, int base), T& out) {
const char* const begin = str.c_str() + offset;
char* end;
errno = 0;
T result = converter(begin, &end, 10);
if (end == begin || errno == ERANGE) {
return 0;
}
out = result;
return end - begin;
}
void skipWhitespace() {
while (offset < str.length() && std::isspace(str[offset])) {
++offset;
}
}
const std::string& str;
std::size_t offset;
};
template<typename Out>
bool StringToTime(const std::string& input, Out& output, core::TimeUnit& timeunit) {
if (input.size() == 0) {
return false;
}
const char* begin = input.c_str();
char *end;
errno = 0;
auto ival = std::strtoll(begin, &end, 0);
if (end == begin || errno == ERANGE) {
return false;
}
if (end[0] == '\0') {
return false;
}
while (*end == ' ') {
// Skip the space
end++;
}
std::string unit(end);
std::transform(unit.begin(), unit.end(), unit.begin(), ::tolower);
if (unit == "sec" || unit == "s" || unit == "second" || unit == "seconds" || unit == "secs") {
timeunit = core::TimeUnit::SECOND;
output = ival;
return true;
} else if (unit == "msec" || unit == "ms" || unit == "millisecond" || unit == "milliseconds" || unit == "msecs") {
timeunit = core::TimeUnit::MILLISECOND;
output = ival;
return true;
} else if (unit == "min" || unit == "m" || unit == "mins" || unit == "minute" || unit == "minutes") {
timeunit = core::TimeUnit::MINUTE;
output = ival;
return true;
} else if (unit == "ns" || unit == "nano" || unit == "nanos" || unit == "nanoseconds") {
timeunit = core::TimeUnit::NANOSECOND;
output = ival;
return true;
} else if (unit == "ms" || unit == "milli" || unit == "millis" || unit == "milliseconds") {
timeunit = core::TimeUnit::MILLISECOND;
output = ival;
return true;
} else if (unit == "h" || unit == "hr" || unit == "hour" || unit == "hrs" || unit == "hours") {
timeunit = core::TimeUnit::HOUR;
output = ival;
return true;
} else if (unit == "d" || unit == "day" || unit == "days") {
timeunit = core::TimeUnit::DAY;
output = ival;
return true;
} else {
return false;
}
}
} /* namespace internal */
} /* namespace utils */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
#endif // LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_