161 lines
4.7 KiB
C
161 lines
4.7 KiB
C
//----------------------------------------------------------------------------//
|
|
// OS on Kaleid //
|
|
// //
|
|
// Desc: strto*l() family //
|
|
// //
|
|
// //
|
|
// Copyright © 2018-2021 The OS/K Team //
|
|
// //
|
|
// This file is part of OS/K. //
|
|
// //
|
|
// OS/K is free software: you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation, either version 3 of the License, or //
|
|
// any later version. //
|
|
// //
|
|
// OS/K 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 General Public License for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with OS/K. If not, see <https://www.gnu.org/licenses/>. //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#include <libc.h>
|
|
#include <libbuf.h>
|
|
|
|
long strtol(const char *str, char **endp, int base) {
|
|
ulong n;
|
|
bool neg = 0;
|
|
const char *save, *start = str;
|
|
|
|
assert(str != NULL);
|
|
|
|
char c = *str;
|
|
|
|
// Ignore leading spaces
|
|
while (isspace(c)) {
|
|
c = *str++;
|
|
}
|
|
|
|
// Accept any +/-'s, whatever the base
|
|
// In particular we accept things like "-0xF"
|
|
if (c == '+')
|
|
c = *str++;
|
|
else if (c == '-') {
|
|
c = *str++;
|
|
neg = 1;
|
|
}
|
|
|
|
// Accept 0/0b/0B/0x/0X and guess base if needed
|
|
if (c == '0') {
|
|
c = *str++;
|
|
if ((base == 0 || base == 16) && (c == 'x' || c == 'X')) {
|
|
c = *str++;
|
|
base = 16;
|
|
}
|
|
else if ((base == 0 || base == 2) && (c == 'b' || c == 'B')) {
|
|
c = *str++;
|
|
base = 2;
|
|
}
|
|
|
|
else if (base == 0)
|
|
base = 8;
|
|
}
|
|
|
|
// base==0 but no leading '0' - assume it's decimal
|
|
if (base == 0)
|
|
base = 10;
|
|
|
|
//
|
|
// Extract the number from the string
|
|
// We do not check whether the number actually fits
|
|
// That's why our accumulator 'n' needs to be unsigned, otherwise
|
|
// containing a number too large would cause a signed overflow and UB
|
|
//
|
|
save = str;
|
|
for (n = 0;; c = *str) {
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
|
|
if (c >= base)
|
|
break;
|
|
else {
|
|
str++;
|
|
n = (n * base) + c;
|
|
}
|
|
}
|
|
|
|
// Save where we stopped in *endp (optional)
|
|
// If 'str' is still '== save', no digit were consummed
|
|
if (endp != NULL)
|
|
*endp = (char *)(str == save ? start : str);
|
|
|
|
return neg ? -(long)n : (long)n;
|
|
}
|
|
|
|
|
|
//
|
|
// Made from the code above by removing "neg"
|
|
//
|
|
ulong strtoul(const char *str, char **endp, int base) {
|
|
ulong n;
|
|
const char *save, *start = str;
|
|
|
|
assert(str != NULL);
|
|
|
|
char c = *str;
|
|
|
|
while (isspace(c)) {
|
|
c = *str++;
|
|
}
|
|
|
|
if (c == '+')
|
|
c = *str++;
|
|
|
|
if (c == '0') {
|
|
c = *str++;
|
|
if ((base == 0 || base == 16) && (c == 'x' || c == 'X')) {
|
|
c = *str++;
|
|
base = 16;
|
|
}
|
|
else if ((base == 0 || base == 2) && (c == 'b' || c == 'B')) {
|
|
c = *str++;
|
|
base = 2;
|
|
}
|
|
|
|
else if (base == 0)
|
|
base = 8;
|
|
}
|
|
|
|
if (base == 0)
|
|
base = 10;
|
|
|
|
save = str;
|
|
for (n = 0;; c = *str) {
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
|
|
if (c >= base)
|
|
break;
|
|
else {
|
|
str++;
|
|
n = (n * base) + c;
|
|
}
|
|
}
|
|
if (endp != NULL)
|
|
*endp = (char *)(str == save ? start : str);
|
|
|
|
return (long)n;
|
|
}
|
|
|