18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- *
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *   Copyright (C) 1991, 1992 Linus Torvalds
58c2ecf20Sopenharmony_ci *   Copyright 2007 rPath, Inc. - All Rights Reserved
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * ----------------------------------------------------------------------- */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/*
108c2ecf20Sopenharmony_ci * Very basic string functions
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/compiler.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/limits.h>
178c2ecf20Sopenharmony_ci#include <asm/asm.h>
188c2ecf20Sopenharmony_ci#include "ctype.h"
198c2ecf20Sopenharmony_ci#include "string.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define KSTRTOX_OVERFLOW       (1U << 31)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * Undef these macros so that the functions that we provide
258c2ecf20Sopenharmony_ci * here will have the correct names regardless of how string.h
268c2ecf20Sopenharmony_ci * may have chosen to #define them.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#undef memcpy
298c2ecf20Sopenharmony_ci#undef memset
308c2ecf20Sopenharmony_ci#undef memcmp
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciint memcmp(const void *s1, const void *s2, size_t len)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	bool diff;
358c2ecf20Sopenharmony_ci	asm("repe; cmpsb" CC_SET(nz)
368c2ecf20Sopenharmony_ci	    : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len));
378c2ecf20Sopenharmony_ci	return diff;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * Clang may lower `memcmp == 0` to `bcmp == 0`.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ciint bcmp(const void *s1, const void *s2, size_t len)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return memcmp(s1, s2, len);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint strcmp(const char *str1, const char *str2)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	const unsigned char *s1 = (const unsigned char *)str1;
518c2ecf20Sopenharmony_ci	const unsigned char *s2 = (const unsigned char *)str2;
528c2ecf20Sopenharmony_ci	int delta = 0;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	while (*s1 || *s2) {
558c2ecf20Sopenharmony_ci		delta = *s1 - *s2;
568c2ecf20Sopenharmony_ci		if (delta)
578c2ecf20Sopenharmony_ci			return delta;
588c2ecf20Sopenharmony_ci		s1++;
598c2ecf20Sopenharmony_ci		s2++;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci	return 0;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciint strncmp(const char *cs, const char *ct, size_t count)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned char c1, c2;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	while (count) {
698c2ecf20Sopenharmony_ci		c1 = *cs++;
708c2ecf20Sopenharmony_ci		c2 = *ct++;
718c2ecf20Sopenharmony_ci		if (c1 != c2)
728c2ecf20Sopenharmony_ci			return c1 < c2 ? -1 : 1;
738c2ecf20Sopenharmony_ci		if (!c1)
748c2ecf20Sopenharmony_ci			break;
758c2ecf20Sopenharmony_ci		count--;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cisize_t strnlen(const char *s, size_t maxlen)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	const char *es = s;
838c2ecf20Sopenharmony_ci	while (*es && maxlen) {
848c2ecf20Sopenharmony_ci		es++;
858c2ecf20Sopenharmony_ci		maxlen--;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return (es - s);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciunsigned int atou(const char *s)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	unsigned int i = 0;
948c2ecf20Sopenharmony_ci	while (isdigit(*s))
958c2ecf20Sopenharmony_ci		i = i * 10 + (*s++ - '0');
968c2ecf20Sopenharmony_ci	return i;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* Works only for digits and letters, but small and fast */
1008c2ecf20Sopenharmony_ci#define TOLOWER(x) ((x) | 0x20)
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic unsigned int simple_guess_base(const char *cp)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	if (cp[0] == '0') {
1058c2ecf20Sopenharmony_ci		if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
1068c2ecf20Sopenharmony_ci			return 16;
1078c2ecf20Sopenharmony_ci		else
1088c2ecf20Sopenharmony_ci			return 8;
1098c2ecf20Sopenharmony_ci	} else {
1108c2ecf20Sopenharmony_ci		return 10;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/**
1158c2ecf20Sopenharmony_ci * simple_strtoull - convert a string to an unsigned long long
1168c2ecf20Sopenharmony_ci * @cp: The start of the string
1178c2ecf20Sopenharmony_ci * @endp: A pointer to the end of the parsed string will be placed here
1188c2ecf20Sopenharmony_ci * @base: The number base to use
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_ciunsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	unsigned long long result = 0;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (!base)
1258c2ecf20Sopenharmony_ci		base = simple_guess_base(cp);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
1288c2ecf20Sopenharmony_ci		cp += 2;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	while (isxdigit(*cp)) {
1318c2ecf20Sopenharmony_ci		unsigned int value;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
1348c2ecf20Sopenharmony_ci		if (value >= base)
1358c2ecf20Sopenharmony_ci			break;
1368c2ecf20Sopenharmony_ci		result = result * base + value;
1378c2ecf20Sopenharmony_ci		cp++;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	if (endp)
1408c2ecf20Sopenharmony_ci		*endp = (char *)cp;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return result;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cilong simple_strtol(const char *cp, char **endp, unsigned int base)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	if (*cp == '-')
1488c2ecf20Sopenharmony_ci		return -simple_strtoull(cp + 1, endp, base);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return simple_strtoull(cp, endp, base);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/**
1548c2ecf20Sopenharmony_ci * strlen - Find the length of a string
1558c2ecf20Sopenharmony_ci * @s: The string to be sized
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cisize_t strlen(const char *s)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	const char *sc;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	for (sc = s; *sc != '\0'; ++sc)
1628c2ecf20Sopenharmony_ci		/* nothing */;
1638c2ecf20Sopenharmony_ci	return sc - s;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/**
1678c2ecf20Sopenharmony_ci * strstr - Find the first substring in a %NUL terminated string
1688c2ecf20Sopenharmony_ci * @s1: The string to be searched
1698c2ecf20Sopenharmony_ci * @s2: The string to search for
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_cichar *strstr(const char *s1, const char *s2)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	size_t l1, l2;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	l2 = strlen(s2);
1768c2ecf20Sopenharmony_ci	if (!l2)
1778c2ecf20Sopenharmony_ci		return (char *)s1;
1788c2ecf20Sopenharmony_ci	l1 = strlen(s1);
1798c2ecf20Sopenharmony_ci	while (l1 >= l2) {
1808c2ecf20Sopenharmony_ci		l1--;
1818c2ecf20Sopenharmony_ci		if (!memcmp(s1, s2, l2))
1828c2ecf20Sopenharmony_ci			return (char *)s1;
1838c2ecf20Sopenharmony_ci		s1++;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	return NULL;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci * strchr - Find the first occurrence of the character c in the string s.
1908c2ecf20Sopenharmony_ci * @s: the string to be searched
1918c2ecf20Sopenharmony_ci * @c: the character to search for
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_cichar *strchr(const char *s, int c)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	while (*s != (char)c)
1968c2ecf20Sopenharmony_ci		if (*s++ == '\0')
1978c2ecf20Sopenharmony_ci			return NULL;
1988c2ecf20Sopenharmony_ci	return (char *)s;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic inline u64 __div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	union {
2048c2ecf20Sopenharmony_ci		u64 v64;
2058c2ecf20Sopenharmony_ci		u32 v32[2];
2068c2ecf20Sopenharmony_ci	} d = { dividend };
2078c2ecf20Sopenharmony_ci	u32 upper;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	upper = d.v32[1];
2108c2ecf20Sopenharmony_ci	d.v32[1] = 0;
2118c2ecf20Sopenharmony_ci	if (upper >= divisor) {
2128c2ecf20Sopenharmony_ci		d.v32[1] = upper / divisor;
2138c2ecf20Sopenharmony_ci		upper %= divisor;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci	asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
2168c2ecf20Sopenharmony_ci		"rm" (divisor), "0" (d.v32[0]), "1" (upper));
2178c2ecf20Sopenharmony_ci	return d.v64;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic inline u64 __div_u64(u64 dividend, u32 divisor)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	u32 remainder;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return __div_u64_rem(dividend, divisor, &remainder);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic inline char _tolower(const char c)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	return c | 0x20;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	if (*base == 0) {
2358c2ecf20Sopenharmony_ci		if (s[0] == '0') {
2368c2ecf20Sopenharmony_ci			if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
2378c2ecf20Sopenharmony_ci				*base = 16;
2388c2ecf20Sopenharmony_ci			else
2398c2ecf20Sopenharmony_ci				*base = 8;
2408c2ecf20Sopenharmony_ci		} else
2418c2ecf20Sopenharmony_ci			*base = 10;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
2448c2ecf20Sopenharmony_ci		s += 2;
2458c2ecf20Sopenharmony_ci	return s;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/*
2498c2ecf20Sopenharmony_ci * Convert non-negative integer string representation in explicitly given radix
2508c2ecf20Sopenharmony_ci * to an integer.
2518c2ecf20Sopenharmony_ci * Return number of characters consumed maybe or-ed with overflow bit.
2528c2ecf20Sopenharmony_ci * If overflow occurs, result integer (incorrect) is still returned.
2538c2ecf20Sopenharmony_ci *
2548c2ecf20Sopenharmony_ci * Don't you dare use this function.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_cistatic unsigned int _parse_integer(const char *s,
2578c2ecf20Sopenharmony_ci				   unsigned int base,
2588c2ecf20Sopenharmony_ci				   unsigned long long *p)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	unsigned long long res;
2618c2ecf20Sopenharmony_ci	unsigned int rv;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	res = 0;
2648c2ecf20Sopenharmony_ci	rv = 0;
2658c2ecf20Sopenharmony_ci	while (1) {
2668c2ecf20Sopenharmony_ci		unsigned int c = *s;
2678c2ecf20Sopenharmony_ci		unsigned int lc = c | 0x20; /* don't tolower() this line */
2688c2ecf20Sopenharmony_ci		unsigned int val;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		if ('0' <= c && c <= '9')
2718c2ecf20Sopenharmony_ci			val = c - '0';
2728c2ecf20Sopenharmony_ci		else if ('a' <= lc && lc <= 'f')
2738c2ecf20Sopenharmony_ci			val = lc - 'a' + 10;
2748c2ecf20Sopenharmony_ci		else
2758c2ecf20Sopenharmony_ci			break;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		if (val >= base)
2788c2ecf20Sopenharmony_ci			break;
2798c2ecf20Sopenharmony_ci		/*
2808c2ecf20Sopenharmony_ci		 * Check for overflow only if we are within range of
2818c2ecf20Sopenharmony_ci		 * it in the max base we support (16)
2828c2ecf20Sopenharmony_ci		 */
2838c2ecf20Sopenharmony_ci		if (unlikely(res & (~0ull << 60))) {
2848c2ecf20Sopenharmony_ci			if (res > __div_u64(ULLONG_MAX - val, base))
2858c2ecf20Sopenharmony_ci				rv |= KSTRTOX_OVERFLOW;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci		res = res * base + val;
2888c2ecf20Sopenharmony_ci		rv++;
2898c2ecf20Sopenharmony_ci		s++;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci	*p = res;
2928c2ecf20Sopenharmony_ci	return rv;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	unsigned long long _res;
2988c2ecf20Sopenharmony_ci	unsigned int rv;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	s = _parse_integer_fixup_radix(s, &base);
3018c2ecf20Sopenharmony_ci	rv = _parse_integer(s, base, &_res);
3028c2ecf20Sopenharmony_ci	if (rv & KSTRTOX_OVERFLOW)
3038c2ecf20Sopenharmony_ci		return -ERANGE;
3048c2ecf20Sopenharmony_ci	if (rv == 0)
3058c2ecf20Sopenharmony_ci		return -EINVAL;
3068c2ecf20Sopenharmony_ci	s += rv;
3078c2ecf20Sopenharmony_ci	if (*s == '\n')
3088c2ecf20Sopenharmony_ci		s++;
3098c2ecf20Sopenharmony_ci	if (*s)
3108c2ecf20Sopenharmony_ci		return -EINVAL;
3118c2ecf20Sopenharmony_ci	*res = _res;
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/**
3168c2ecf20Sopenharmony_ci * kstrtoull - convert a string to an unsigned long long
3178c2ecf20Sopenharmony_ci * @s: The start of the string. The string must be null-terminated, and may also
3188c2ecf20Sopenharmony_ci *  include a single newline before its terminating null. The first character
3198c2ecf20Sopenharmony_ci *  may also be a plus sign, but not a minus sign.
3208c2ecf20Sopenharmony_ci * @base: The number base to use. The maximum supported base is 16. If base is
3218c2ecf20Sopenharmony_ci *  given as 0, then the base of the string is automatically detected with the
3228c2ecf20Sopenharmony_ci *  conventional semantics - If it begins with 0x the number will be parsed as a
3238c2ecf20Sopenharmony_ci *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
3248c2ecf20Sopenharmony_ci *  parsed as an octal number. Otherwise it will be parsed as a decimal.
3258c2ecf20Sopenharmony_ci * @res: Where to write the result of the conversion on success.
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
3288c2ecf20Sopenharmony_ci * Used as a replacement for the obsolete simple_strtoull. Return code must
3298c2ecf20Sopenharmony_ci * be checked.
3308c2ecf20Sopenharmony_ci */
3318c2ecf20Sopenharmony_ciint kstrtoull(const char *s, unsigned int base, unsigned long long *res)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	if (s[0] == '+')
3348c2ecf20Sopenharmony_ci		s++;
3358c2ecf20Sopenharmony_ci	return _kstrtoull(s, base, res);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	unsigned long long tmp;
3418c2ecf20Sopenharmony_ci	int rv;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	rv = kstrtoull(s, base, &tmp);
3448c2ecf20Sopenharmony_ci	if (rv < 0)
3458c2ecf20Sopenharmony_ci		return rv;
3468c2ecf20Sopenharmony_ci	if (tmp != (unsigned long)tmp)
3478c2ecf20Sopenharmony_ci		return -ERANGE;
3488c2ecf20Sopenharmony_ci	*res = tmp;
3498c2ecf20Sopenharmony_ci	return 0;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci/**
3538c2ecf20Sopenharmony_ci * kstrtoul - convert a string to an unsigned long
3548c2ecf20Sopenharmony_ci * @s: The start of the string. The string must be null-terminated, and may also
3558c2ecf20Sopenharmony_ci *  include a single newline before its terminating null. The first character
3568c2ecf20Sopenharmony_ci *  may also be a plus sign, but not a minus sign.
3578c2ecf20Sopenharmony_ci * @base: The number base to use. The maximum supported base is 16. If base is
3588c2ecf20Sopenharmony_ci *  given as 0, then the base of the string is automatically detected with the
3598c2ecf20Sopenharmony_ci *  conventional semantics - If it begins with 0x the number will be parsed as a
3608c2ecf20Sopenharmony_ci *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
3618c2ecf20Sopenharmony_ci *  parsed as an octal number. Otherwise it will be parsed as a decimal.
3628c2ecf20Sopenharmony_ci * @res: Where to write the result of the conversion on success.
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
3658c2ecf20Sopenharmony_ci * Used as a replacement for the simple_strtoull.
3668c2ecf20Sopenharmony_ci */
3678c2ecf20Sopenharmony_ciint boot_kstrtoul(const char *s, unsigned int base, unsigned long *res)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * We want to shortcut function call, but
3718c2ecf20Sopenharmony_ci	 * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
3728c2ecf20Sopenharmony_ci	 */
3738c2ecf20Sopenharmony_ci	if (sizeof(unsigned long) == sizeof(unsigned long long) &&
3748c2ecf20Sopenharmony_ci	    __alignof__(unsigned long) == __alignof__(unsigned long long))
3758c2ecf20Sopenharmony_ci		return kstrtoull(s, base, (unsigned long long *)res);
3768c2ecf20Sopenharmony_ci	else
3778c2ecf20Sopenharmony_ci		return _kstrtoul(s, base, res);
3788c2ecf20Sopenharmony_ci}
379