u-boot/lib/strto.c

190 lines
3.4 KiB
C
Raw Normal View History

/*
* linux/lib/vsprintf.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
#include <common.h>
#include <errno.h>
#include <linux/ctype.h>
/* from lib/kstrtox.c */
static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
{
if (*base == 0) {
if (s[0] == '0') {
if (tolower(s[1]) == 'x' && isxdigit(s[2]))
*base = 16;
else
*base = 8;
} else {
int i = 0;
char var;
*base = 10;
do {
var = tolower(s[i++]);
if (var >= 'a' && var <= 'f') {
*base = 16;
break;
}
lib: strto: Stop detection when invalid char is used This issue has been found when mtd partition are specified. Autodetection code should stop when the first invalid char is found. Here is the example of commands: setenv mtdids nand0=memory-controller@e000e000 setenv mtdparts "mtdparts=nand0:4m(boot),4m(env),64m(kernel),96m(rootfs)" mtd list Before: Zynq> mtd list List of MTD devices: * nand0 - type: NAND flash - block size: 0x20000 bytes - min I/O: 0x800 bytes - OOB size: 64 bytes - OOB available: 16 bytes - ECC strength: 1 bits - ECC step size: 2048 bytes - bitflip threshold: 1 bits - 0x000000000000-0x000010000000 : "nand0" - 0x000000000000-0x000000400000 : "boot" - 0x000000400000-0x000000800000 : "env" - 0x000000800000-0x000006c00000 : "kernel" - 0x000006c00000-0x000010000000 : "rootfs" Where it is visible that kernel partition has 100m instead of 64m After: Zynq> mtd list * nand0 - type: NAND flash - block size: 0x20000 bytes - min I/O: 0x800 bytes - OOB size: 64 bytes - OOB available: 16 bytes - ECC strength: 1 bits - ECC step size: 2048 bytes - bitflip threshold: 1 bits - 0x000000000000-0x000010000000 : "nand0" - 0x000000000000-0x000000400000 : "boot" - 0x000000400000-0x000000800000 : "env" - 0x000000800000-0x000004800000 : "kernel" - 0x000004800000-0x00000a800000 : "rootfs" Signed-off-by: Michal Simek <michal.simek@xilinx.com> Fixes: 0486497e2b5f ("lib: Improve _parse_integer_fixup_radix base 16 detection") Tested-by: Heiko Schocher <hs@denx.de> Tested-by: Pali Rohár <pali@kernel.org>
2020-04-08 08:09:16 +00:00
if (!(var >= '0' && var <= '9'))
break;
} while (var);
}
}
if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
s += 2;
return s;
}
unsigned long simple_strtoul(const char *cp, char **endp,
unsigned int base)
{
unsigned long result = 0;
unsigned long value;
cp = _parse_integer_fixup_radix(cp, &base);
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
? toupper(*cp) : *cp)-'A'+10) < base) {
result = result*base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
{
char *tail;
unsigned long val;
size_t len;
*res = 0;
len = strlen(cp);
if (len == 0)
return -EINVAL;
val = simple_strtoul(cp, &tail, base);
if (tail == cp)
return -EINVAL;
if ((*tail == '\0') ||
((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
*res = val;
return 0;
}
return -EINVAL;
}
long simple_strtol(const char *cp, char **endp, unsigned int base)
{
if (*cp == '-')
return -simple_strtoul(cp + 1, endp, base);
return simple_strtoul(cp, endp, base);
}
unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
{
unsigned long result = simple_strtoul(cp, endp, base);
switch (tolower(**endp)) {
case 'g':
result *= 1024;
/* fall through */
case 'm':
result *= 1024;
/* fall through */
case 'k':
result *= 1024;
(*endp)++;
if (**endp == 'i')
(*endp)++;
if (**endp == 'B')
(*endp)++;
}
return result;
}
unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
{
unsigned long long result = simple_strtoull(cp, endp, base);
switch (tolower(**endp)) {
case 'g':
result *= 1024;
/* fall through */
case 'm':
result *= 1024;
/* fall through */
case 'k':
result *= 1024;
(*endp)++;
if (**endp == 'i')
(*endp)++;
if (**endp == 'B')
(*endp)++;
}
return result;
}
unsigned long long simple_strtoull(const char *cp, char **endp,
unsigned int base)
{
unsigned long long result = 0, value;
cp = _parse_integer_fixup_radix(cp, &base);
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
: (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
result = result * base + value;
cp++;
}
if (endp)
*endp = (char *) cp;
return result;
}
long trailing_strtoln(const char *str, const char *end)
{
const char *p;
if (!end)
end = str + strlen(str);
if (isdigit(end[-1])) {
for (p = end - 1; p > str; p--) {
if (!isdigit(*p))
return simple_strtoul(p + 1, NULL, 10);
}
}
return -1;
}
long trailing_strtol(const char *str)
{
return trailing_strtoln(str, NULL);
}
void str_to_upper(const char *in, char *out, size_t len)
{
for (; len > 0 && *in; len--)
*out++ = toupper(*in++);
if (len)
*out = '\0';
}