1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef LIBPANDABASE_UTILS_STRING_HELPERS_H
17#define LIBPANDABASE_UTILS_STRING_HELPERS_H
18
19#include <securec.h>
20
21#include <cstdarg>
22
23#include <algorithm>
24#include <array>
25#include <string>
26#include <cerrno>
27#include <cstdlib>
28#include <limits>
29#include <type_traits>
30
31namespace panda::helpers::string {
32
33inline std::string Vformat(const char *fmt, va_list args)
34{
35    static constexpr size_t SIZE = 1024;
36
37    std::string result;
38    result.resize(SIZE);
39
40    bool is_truncated = true;
41    while (is_truncated) {
42        va_list copy_args;
43        va_copy(copy_args, args);
44        int r = vsnprintf_truncated_s(result.data(), result.size() + 1, fmt, copy_args);
45        va_end(copy_args);
46
47        if (r < 0) {
48            return "";
49        }
50
51        is_truncated = static_cast<size_t>(r) == result.size();
52        result.resize(result.size() * 2U);
53    }
54
55    result.erase(std::find(result.begin(), result.end(), '\0'), result.end());
56
57    return result;
58}
59
60// NOLINTNEXTLINE(cert-dcl50-cpp)
61inline std::string Format(const char *fmt, ...)
62{
63    va_list args;
64    va_start(args, fmt);  // NOLINT(cppcoreguidelines-pro-type-vararg)
65
66    std::string result = Vformat(fmt, args);
67
68    va_end(args);
69    return result;
70}
71
72template <typename T>
73bool ParseInt(const char *str, T *num, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max())
74{
75    static_assert(std::is_signed<T>::value, "it can't parse unsigned types");
76    while (isspace(*str)) {
77        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
78        str++;
79    }
80
81    constexpr size_t BASE16 = 16;
82    constexpr size_t BASE10 = 10;
83    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
84    int base = (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) ? BASE16 : BASE10;
85    errno = 0;
86    char *end = nullptr;
87    // NOLINTNEXTLINE(google-runtime-int)
88    long long int result = strtoll(str, &end, base);
89    if (str == end || *end != '\0') {
90        errno = EINVAL;
91        return false;
92    }
93    if (result < min || max < result) {
94        errno = ERANGE;
95        return false;
96    }
97    if (num != nullptr) {
98        *num = static_cast<T>(result);
99    }
100    return true;
101}
102
103template <typename T>
104bool ParseInt(const std::string &str, T *num, T min = std::numeric_limits<T>::min(),
105              T max = std::numeric_limits<T>::max())
106{
107    return ParseInt(str.c_str(), num, min, max);
108}
109
110}  // namespace panda::helpers::string
111
112#endif  // LIBPANDABASE_UTILS_STRING_HELPERS_H
113