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