blob: be8b97b788eed9f93e2be4346278f3cafcac3711 [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
Yifan Hong6b1e33b2016-10-07 16:48:17 -070047 int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
Elliott Hughes7dd8e202015-09-04 16:26:51 -070048 errno = 0;
49 char* end;
Elliott Hughesefa901e2015-11-02 09:01:53 -080050 unsigned long long int result = strtoull(s, &end, base);
Christopher Ferris3ac40852018-08-28 14:35:38 -070051 if (errno != 0) return false;
52 if (end == s) {
53 errno = EINVAL;
54 return false;
55 }
Elliott Hughes06768992018-04-19 19:48:25 -070056 if (*end != '\0') {
57 const char* suffixes = "bkmgtpe";
58 const char* suffix;
Christopher Ferris3ac40852018-08-28 14:35:38 -070059 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 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -070064 }
65 if (max < result) {
Christopher Ferris3ac40852018-08-28 14:35:38 -070066 errno = ERANGE;
Elliott Hughes7dd8e202015-09-04 16:26:51 -070067 return false;
68 }
Steven Morelandc4f40bf2018-07-20 11:02:47 -070069 if (out != nullptr) {
70 *out = static_cast<T>(result);
71 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -070072 return true;
73}
74
Elliott Hughes31d04db2016-10-11 17:09:00 -070075// TODO: string_view
76template <typename T>
Elliott Hughes06768992018-04-19 19:48:25 -070077bool 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
82template <typename T>
83bool 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
88template <typename T>
89bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
90 return ParseByteCount(s.c_str(), out, max);
Elliott Hughes31d04db2016-10-11 17:09:00 -070091}
92
Inseob Kim06c19d02018-06-29 18:07:00 +090093// Parses the signed decimal or hexadecimal integer in the string 's' and sets
Steven Moreland4d396612018-08-08 16:39:35 -070094// '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.
Elliott Hughes7dd8e202015-09-04 16:26:51 -070097template <typename T>
98bool ParseInt(const char* s, T* out,
99 T min = std::numeric_limits<T>::min(),
100 T max = std::numeric_limits<T>::max()) {
Tom Cherry06518bc2018-08-22 15:26:20 -0700101 static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
Tom Cherry9e58f1b2018-08-22 14:38:02 -0700102 while (isspace(*s)) {
103 s++;
104 }
105
Yifan Hong6b1e33b2016-10-07 16:48:17 -0700106 int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700107 errno = 0;
108 char* end;
Elliott Hughesefa901e2015-11-02 09:01:53 -0800109 long long int result = strtoll(s, &end, base);
Christopher Ferris3ac40852018-08-28 14:35:38 -0700110 if (errno != 0) {
111 return false;
112 }
113 if (s == end || *end != '\0') {
114 errno = EINVAL;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700115 return false;
116 }
117 if (result < min || max < result) {
Christopher Ferris3ac40852018-08-28 14:35:38 -0700118 errno = ERANGE;
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700119 return false;
120 }
Steven Morelandc4f40bf2018-07-20 11:02:47 -0700121 if (out != nullptr) {
122 *out = static_cast<T>(result);
123 }
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700124 return true;
125}
126
Elliott Hughes31d04db2016-10-11 17:09:00 -0700127// TODO: string_view
128template <typename T>
129bool 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
Elliott Hughes7dd8e202015-09-04 16:26:51 -0700135} // namespace base
136} // namespace android