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
31 namespace panda::helpers::string {
32
Vformat(const char * fmt,va_list args)33 inline 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)
Format(const char * fmt,...)61 inline 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
72 template <typename T>
73 bool 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
103 template <typename T>
104 bool 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