• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // This is never out of bounds. If string is zero-sized, s[0] == '\0'
48   // so the second condition is not checked. If string is "0",
49   // s[1] will compare against the '\0'.
50   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
51   errno = 0;
52   char* end;
53   unsigned long long int result = strtoull(s, &end, base);
54   if (errno != 0) return false;
55   if (end == s) {
56     errno = EINVAL;
57     return false;
58   }
59   if (*end != '\0') {
60     const char* suffixes = "bkmgtpe";
61     const char* suffix;
62     if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
63         __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
64       errno = EINVAL;
65       return false;
66     }
67   }
68   if (max < result) {
69     errno = ERANGE;
70     return false;
71   }
72   if (out != nullptr) {
73     *out = static_cast<T>(result);
74   }
75   return true;
76 }
77 
78 // TODO: string_view
79 template <typename T>
80 bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
81                bool allow_suffixes = false) {
82   return ParseUint(s.c_str(), out, max, allow_suffixes);
83 }
84 
85 template <typename T>
86 bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
87   return ParseUint(s, out, max, true);
88 }
89 
90 // TODO: string_view
91 template <typename T>
92 bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
93   return ParseByteCount(s.c_str(), out, max);
94 }
95 
96 // Parses the signed decimal or hexadecimal integer in the string 's' and sets
97 // 'out' to that value if it is specified. Optionally allows the caller to define
98 // a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns
99 // boolean success; 'out' is untouched if parsing fails.
100 template <typename T>
101 bool ParseInt(const char* s, T* out,
102               T min = std::numeric_limits<T>::min(),
103               T max = std::numeric_limits<T>::max()) {
104   static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
105   while (isspace(*s)) {
106     s++;
107   }
108 
109   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
110   errno = 0;
111   char* end;
112   long long int result = strtoll(s, &end, base);
113   if (errno != 0) {
114     return false;
115   }
116   if (s == end || *end != '\0') {
117     errno = EINVAL;
118     return false;
119   }
120   if (result < min || max < result) {
121     errno = ERANGE;
122     return false;
123   }
124   if (out != nullptr) {
125     *out = static_cast<T>(result);
126   }
127   return true;
128 }
129 
130 // TODO: string_view
131 template <typename T>
132 bool ParseInt(const std::string& s, T* out,
133               T min = std::numeric_limits<T>::min(),
134               T max = std::numeric_limits<T>::max()) {
135   return ParseInt(s.c_str(), out, min, max);
136 }
137 
138 }  // namespace base
139 }  // namespace android
140