mirror of
https://github.com/clearlinux/graphene.git
synced 2026-08-28 21:35:52 +00:00
168 lines
4.5 KiB
C
168 lines
4.5 KiB
C
/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307 USA. */
|
|
|
|
/* Copyright (C) 2021 Intel Corporation
|
|
* Vijay Dhanraj <vijay.dhanraj@intel.com>
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
|
|
#include "api.h"
|
|
|
|
long strtol(const char* s, char** endptr, int base) {
|
|
int neg = 0;
|
|
long val = 0;
|
|
|
|
// gobble initial whitespace
|
|
while (*s == ' ' || *s == '\t') {
|
|
s++;
|
|
}
|
|
|
|
// plus/minus sign
|
|
if (*s == '+')
|
|
s++;
|
|
else if (*s == '-')
|
|
s++, neg = 1;
|
|
|
|
// hex or octal base prefix
|
|
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
|
|
s += 2, base = 16;
|
|
else if (base == 0 && s[0] == '0')
|
|
s++, base = 8;
|
|
else if (base == 0)
|
|
base = 10;
|
|
|
|
// digits
|
|
while (1) {
|
|
int dig;
|
|
|
|
if (*s >= '0' && *s <= '9')
|
|
dig = *s - '0';
|
|
else if (*s >= 'a' && *s <= 'z')
|
|
dig = *s - 'a' + 10;
|
|
else if (*s >= 'A' && *s <= 'Z')
|
|
dig = *s - 'A' + 10;
|
|
else
|
|
break;
|
|
if (dig >= base)
|
|
break;
|
|
s++, val = (val * base) + dig;
|
|
// we don't properly detect overflow!
|
|
}
|
|
|
|
if (endptr)
|
|
*endptr = (char*)s;
|
|
return (neg ? -val : val);
|
|
}
|
|
|
|
bool str_to_ulong(const char* str, int base, unsigned long* out_value, char** out_endptr) {
|
|
bool overflow_detected = false;
|
|
const char* s = str;
|
|
int conv_status = 0; /* 0: no digits found, 1: valid conversion, -1: int overflow */
|
|
unsigned long val = 0;
|
|
|
|
// gobble initial whitespace
|
|
while (*s == ' ' || *s == '\t')
|
|
s++;
|
|
|
|
// hex or octal base prefix
|
|
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
|
|
s += 2, base = 16;
|
|
else if (base == 0 && s[0] == '0')
|
|
s++, base = 8;
|
|
else if (base == 0)
|
|
base = 10;
|
|
|
|
unsigned long cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
|
|
int cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
|
|
|
|
// digits
|
|
while (1) {
|
|
int dig;
|
|
|
|
if (*s >= '0' && *s <= '9')
|
|
dig = *s - '0';
|
|
else if (*s >= 'a' && *s <= 'z')
|
|
dig = *s - 'a' + 10;
|
|
else if (*s >= 'A' && *s <= 'Z')
|
|
dig = *s - 'A' + 10;
|
|
else
|
|
break;
|
|
|
|
if (dig >= base)
|
|
break;
|
|
|
|
if (conv_status < 0 || val > cutoff || (val == cutoff && dig > cutlim))
|
|
conv_status = -1;
|
|
else
|
|
conv_status = 1, val = (val * base) + dig;
|
|
|
|
s++;
|
|
}
|
|
|
|
if (conv_status < 0) {
|
|
val = ULONG_MAX;
|
|
overflow_detected = true;
|
|
}
|
|
|
|
if (out_value)
|
|
*out_value = val;
|
|
if (out_endptr)
|
|
*out_endptr = (char*)(conv_status ? s : str);
|
|
|
|
return overflow_detected;
|
|
}
|
|
|
|
#ifdef __LP64__
|
|
/* long int == long long int on targets with data model LP64 */
|
|
long long strtoll(const char* s, char** endptr, int base) {
|
|
return (long long)strtol(s, endptr, base);
|
|
}
|
|
#else
|
|
#error "Unsupported architecture (only support data model LP64)"
|
|
#endif
|
|
|
|
/* Convert a string to an int. */
|
|
int atoi(const char* nptr) {
|
|
return (int)strtol(nptr, (char**)NULL, 10);
|
|
}
|
|
|
|
/* Convert a string to an long int. */
|
|
long int atol(const char* nptr) {
|
|
return strtol(nptr, (char**)NULL, 10);
|
|
}
|
|
|
|
/* Parse a size (number with optional "G"/"M"/"K" suffix) into an unsigned long. Returns -1 if
|
|
* cannot parse the size, e.g. if the suffix is wrong. */
|
|
int64_t parse_size_str(const char* str) {
|
|
char* endptr = NULL;
|
|
long size = strtol(str, &endptr, 0);
|
|
|
|
if (endptr[0] == 'G' || endptr[0] == 'g')
|
|
size *= 1024 * 1024 * 1024;
|
|
else if (endptr[0] == 'M' || endptr[0] == 'm')
|
|
size *= 1024 * 1024;
|
|
else if (endptr[0] == 'K' || endptr[0] == 'k')
|
|
size *= 1024;
|
|
else if (endptr[0] != '\0')
|
|
size = -1; /* wrong suffix */
|
|
|
|
return size;
|
|
}
|