1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <limits>
24 #include <string>
25 #include <type_traits>
26 
27 namespace android {
28 namespace base {
29 
30 // Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
31 // 'out' to that value if it is specified. Optionally allows the caller to define
32 // a 'max' beyond which otherwise valid values will be rejected. Returns boolean
33 // success; 'out' is untouched if parsing fails.
34 template <typename T>
35 bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
36                bool allow_suffixes = false) {
37   static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
38   while (isspace(*s)) {
39     s++;
40   }
41 
42   if (s[0] == '-') {
43     errno = EINVAL;
44     return false;
45   }
46 
47   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
48   errno = 0;
49   char* end;
50   unsigned long long int result = strtoull(s, &end, base);
51   if (errno != 0) return false;
52   if (end == s) {
53     errno = EINVAL;
54     return false;
55   }
56   if (*end != '\0') {
57     const char* suffixes = "bkmgtpe";
58     const char* suffix;
59     if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
60         __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
61       errno = EINVAL;
62       return false;
63     }
64   }
65   if (max < result) {
66     errno = ERANGE;
67     return false;
68   }
69   if (out != nullptr) {
70     *out = static_cast<T>(result);
71   }
72   return true;
73 }
74 
75 // TODO: string_view
76 template <typename T>
77 bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
78                bool allow_suffixes = false) {
79   return ParseUint(s.c_str(), out, max, allow_suffixes);
80 }
81 
82 template <typename T>
83 bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
84   return ParseUint(s, out, max, true);
85 }
86 
87 // TODO: string_view
88 template <typename T>
89 bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
90   return ParseByteCount(s.c_str(), out, max);
91 }
92 
93 // Parses the signed decimal or hexadecimal integer in the string 's' and sets
94 // 'out' to that value if it is specified. Optionally allows the caller to define
95 // a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns
96 // boolean success; 'out' is untouched if parsing fails.
97 template <typename T>
98 bool ParseInt(const char* s, T* out,
99               T min = std::numeric_limits<T>::min(),
100               T max = std::numeric_limits<T>::max()) {
101   static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
102   while (isspace(*s)) {
103     s++;
104   }
105 
106   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
107   errno = 0;
108   char* end;
109   long long int result = strtoll(s, &end, base);
110   if (errno != 0) {
111     return false;
112   }
113   if (s == end || *end != '\0') {
114     errno = EINVAL;
115     return false;
116   }
117   if (result < min || max < result) {
118     errno = ERANGE;
119     return false;
120   }
121   if (out != nullptr) {
122     *out = static_cast<T>(result);
123   }
124   return true;
125 }
126 
127 // TODO: string_view
128 template <typename T>
129 bool ParseInt(const std::string& s, T* out,
130               T min = std::numeric_limits<T>::min(),
131               T max = std::numeric_limits<T>::max()) {
132   return ParseInt(s.c_str(), out, min, max);
133 }
134 
135 }  // namespace base
136 }  // namespace android
137