blob: c76d625adeb3143ee39e8b9f0262b450efb1b868 [file] [log] [blame]
Elliott Hughes7dd8e202015-09-04 16:26:51 -07001/*
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
Elliott Hughese3c5a2a2018-06-26 17:17:41 -070017#pragma once
Elliott Hughes7dd8e202015-09-04 16:26:51 -070018
19#include <errno.h>
20#include <stdlib.h>
Elliott Hughes06768992018-04-19 19:48:25 -070021#include <string.h>
Elliott Hughes7dd8e202015-09-04 16:26:51 -070022
23#include <limits>
Elliott Hughes31d04db2016-10-11 17:09:00 -070024#include <string>
Tom Cherry06518bc2018-08-22 15:26:20 -070025#include <type_traits>
Elliott Hughes7dd8e202015-09-04 16:26:51 -070026
27namespace android {
28namespace base {
29
Inseob Kim06c19d02018-06-29 18:07:00 +090030// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
Steven Moreland4d396612018-08-08 16:39:35 -070031// '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.
Elliott Hughes7dd8e202015-09-04 16:26:51 -070034template <typename T>
Elliott Hughes06768992018-04-19 19:48:25 -070035bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
36 bool allow_suffixes = false) {
Tom Cherry06518bc2018-08-22 15:26:20 -070037 static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
Tom Cherry9e58f1b2018-08-22 14:38:02 -070038 while (isspace(*s)) {
39 s++;
40 }
41
42 if (s[0] == '-') {
Christopher Ferris3ac40852018-08-28 14:35:38 -070043 errno = EINVAL;
Tom Cherry9e58f1b2018-08-22 14:38:02 -070044 return false;
45 }
46
Florian Mayerb7c6e5a2022-08-11 22:58:22 +000047 // 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'.
Yifan Hong6b1e33b2016-10-07 16:48:17 -070050 int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
Elliott Hughes7dd8e202015-09-04 16:26:51 -070051 errno = 0;
52 char* end;
Elliott Hughesefa901e2015-11-02 09:01:53 -080053 unsigned long long int result = strtoull(s, &end, base);
Christopher Ferris3ac40852018-08-28 14:35:38 -070054 if (errno != 0) return false;
55 if (end == s) {
56 errno = EINVAL;
57 return false;
58 }
Elliott Hughes06768992018-04-19 19:48:25 -070059 if (*end != '\0') {
60 const char* suffixes = "bkmgtpe";
61 const char* suffix;
Christopher Ferris3ac40852018-08-28 14:35:38 -070062 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 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -070067 }
68 if (max < result) {
Christopher Ferris3ac40852018-08-28 14:35:38 -070069 errno = ERANGE;
Elliott Hughes7dd8e202015-09-04 16:26:51 -070070 return false;
71 }
Steven Morelandc4f40bf2018-07-20 11:02:47 -070072 if (out != nullptr) {
73 *out = static_cast<T>(result);
74 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -070075 return true;
76}
77
Elliott Hughes31d04db2016-10-11 17:09:00 -070078// TODO: string_view
79template <typename T>
Elliott Hughes06768992018-04-19 19:48:25 -070080bool 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
85template <typename T>
86bool 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
91template <typename T>
92bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
93 return ParseByteCount(s.c_str(), out, max);
Elliott Hughes31d04db2016-10-11 17:09:00 -070094}
95
Inseob Kim06c19d02018-06-29 18:07:00 +090096// Parses the signed decimal or hexadecimal integer in the string 's' and sets
Steven Moreland4d396612018-08-08 16:39:35 -070097// '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.
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700100template <typename T>
101bool ParseInt(const char* s, T* out,
102 T min = std::numeric_limits<T>::min(),
103 T max = std::numeric_limits<T>::max()) {
Tom Cherry06518bc2018-08-22 15:26:20 -0700104 static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
Tom Cherry9e58f1b2018-08-22 14:38:02 -0700105 while (isspace(*s)) {
106 s++;
107 }
108
Yifan Hong6b1e33b2016-10-07 16:48:17 -0700109 int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700110 errno = 0;
111 char* end;
Elliott Hughesefa901e2015-11-02 09:01:53 -0800112 long long int result = strtoll(s, &end, base);
Christopher Ferris3ac40852018-08-28 14:35:38 -0700113 if (errno != 0) {
114 return false;
115 }
116 if (s == end || *end != '\0') {
117 errno = EINVAL;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700118 return false;
119 }
120 if (result < min || max < result) {
Christopher Ferris3ac40852018-08-28 14:35:38 -0700121 errno = ERANGE;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700122 return false;
123 }
Steven Morelandc4f40bf2018-07-20 11:02:47 -0700124 if (out != nullptr) {
125 *out = static_cast<T>(result);
126 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700127 return true;
128}
129
Elliott Hughes31d04db2016-10-11 17:09:00 -0700130// TODO: string_view
131template <typename T>
132bool 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
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700138} // namespace base
139} // namespace android