Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
d8c03214
K
Kernel
项目概览
openeuler
/
Kernel
接近 2 年 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
d8c03214
编写于
6月 29, 2021
作者:
P
Petr Mladek
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-5.14-vsprintf-scanf' into for-linus
上级
80ae5529
d327ea15
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
827 addition
and
40 deletion
+827
-40
MAINTAINERS
MAINTAINERS
+1
-0
include/linux/prandom.h
include/linux/prandom.h
+1
-1
lib/Kconfig.debug
lib/Kconfig.debug
+3
-0
lib/Makefile
lib/Makefile
+1
-0
lib/kstrtox.c
lib/kstrtox.c
+10
-3
lib/kstrtox.h
lib/kstrtox.h
+2
-0
lib/test_scanf.c
lib/test_scanf.c
+750
-0
lib/vsprintf.c
lib/vsprintf.c
+53
-35
tools/testing/selftests/lib/Makefile
tools/testing/selftests/lib/Makefile
+1
-1
tools/testing/selftests/lib/config
tools/testing/selftests/lib/config
+1
-0
tools/testing/selftests/lib/scanf.sh
tools/testing/selftests/lib/scanf.sh
+4
-0
未找到文件。
MAINTAINERS
浏览文件 @
d8c03214
...
...
@@ -19395,6 +19395,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
F: Documentation/core-api/printk-formats.rst
F: lib/test_printf.c
F: lib/test_scanf.c
F: lib/vsprintf.c
VT1211 HARDWARE MONITOR DRIVER
...
...
include/linux/prandom.h
浏览文件 @
d8c03214
...
...
@@ -111,7 +111,7 @@ static inline u32 __seed(u32 x, u32 m)
*/
static
inline
void
prandom_seed_state
(
struct
rnd_state
*
state
,
u64
seed
)
{
u32
i
=
(
seed
>>
32
)
^
(
seed
<<
10
)
^
seed
;
u32
i
=
(
(
seed
>>
32
)
^
(
seed
<<
10
)
^
seed
)
&
0xffffffffUL
;
state
->
s1
=
__seed
(
i
,
2U
);
state
->
s2
=
__seed
(
i
,
8U
);
...
...
lib/Kconfig.debug
浏览文件 @
d8c03214
...
...
@@ -2163,6 +2163,9 @@ config TEST_KSTRTOX
config TEST_PRINTF
tristate "Test printf() family of functions at runtime"
config TEST_SCANF
tristate "Test scanf() family of functions at runtime"
config TEST_BITMAP
tristate "Test bitmap_*() family of functions at runtime"
help
...
...
lib/Makefile
浏览文件 @
d8c03214
...
...
@@ -83,6 +83,7 @@ obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
obj-$(CONFIG_TEST_STATIC_KEYS)
+=
test_static_keys.o
obj-$(CONFIG_TEST_STATIC_KEYS)
+=
test_static_key_base.o
obj-$(CONFIG_TEST_PRINTF)
+=
test_printf.o
obj-$(CONFIG_TEST_SCANF)
+=
test_scanf.o
obj-$(CONFIG_TEST_BITMAP)
+=
test_bitmap.o
obj-$(CONFIG_TEST_STRSCPY)
+=
test_strscpy.o
obj-$(CONFIG_TEST_UUID)
+=
test_uuid.o
...
...
lib/kstrtox.c
浏览文件 @
d8c03214
...
...
@@ -39,20 +39,22 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
/*
* Convert non-negative integer string representation in explicitly given radix
* to an integer.
* to an integer. A maximum of max_chars characters will be converted.
*
* Return number of characters consumed maybe or-ed with overflow bit.
* If overflow occurs, result integer (incorrect) is still returned.
*
* Don't you dare use this function.
*/
unsigned
int
_parse_integer
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
p
)
unsigned
int
_parse_integer_limit
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
p
,
size_t
max_chars
)
{
unsigned
long
long
res
;
unsigned
int
rv
;
res
=
0
;
rv
=
0
;
while
(
1
)
{
while
(
max_chars
--
)
{
unsigned
int
c
=
*
s
;
unsigned
int
lc
=
c
|
0x20
;
/* don't tolower() this line */
unsigned
int
val
;
...
...
@@ -82,6 +84,11 @@ unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long
return
rv
;
}
unsigned
int
_parse_integer
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
p
)
{
return
_parse_integer_limit
(
s
,
base
,
p
,
INT_MAX
);
}
static
int
_kstrtoull
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
res
)
{
unsigned
long
long
_res
;
...
...
lib/kstrtox.h
浏览文件 @
d8c03214
...
...
@@ -4,6 +4,8 @@
#define KSTRTOX_OVERFLOW (1U << 31)
const
char
*
_parse_integer_fixup_radix
(
const
char
*
s
,
unsigned
int
*
base
);
unsigned
int
_parse_integer_limit
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
res
,
size_t
max_chars
);
unsigned
int
_parse_integer
(
const
char
*
s
,
unsigned
int
base
,
unsigned
long
long
*
res
);
#endif
lib/test_scanf.c
0 → 100644
浏览文件 @
d8c03214
// SPDX-License-Identifier: GPL-2.0-only
/*
* Test cases for sscanf facility.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/printk.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "../tools/testing/selftests/kselftest_module.h"
#define BUF_SIZE 1024
KSTM_MODULE_GLOBALS
();
static
char
*
test_buffer
__initdata
;
static
char
*
fmt_buffer
__initdata
;
static
struct
rnd_state
rnd_state
__initdata
;
typedef
int
(
*
check_fn
)(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
);
static
void
__scanf
(
4
,
6
)
__init
_test
(
check_fn
fn
,
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
...)
{
va_list
ap
,
ap_copy
;
int
ret
;
total_tests
++
;
va_start
(
ap
,
n_args
);
va_copy
(
ap_copy
,
ap
);
ret
=
vsscanf
(
string
,
fmt
,
ap_copy
);
va_end
(
ap_copy
);
if
(
ret
!=
n_args
)
{
pr_warn
(
"vsscanf(
\"
%s
\"
,
\"
%s
\"
, ...) returned %d expected %d
\n
"
,
string
,
fmt
,
ret
,
n_args
);
goto
fail
;
}
ret
=
(
*
fn
)(
check_data
,
string
,
fmt
,
n_args
,
ap
);
if
(
ret
)
goto
fail
;
va_end
(
ap
);
return
;
fail:
failed_tests
++
;
va_end
(
ap
);
}
#define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap) \
do { \
pr_debug("\"%s\", \"%s\" ->\n", str, fmt); \
for (; n_args > 0; n_args--, expect++) { \
typeof(*expect) got = *va_arg(ap, typeof(expect)); \
pr_debug("\t" arg_fmt "\n", got); \
if (got != *expect) { \
pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
str, fmt, *expect, got); \
return 1; \
} \
} \
return 0; \
} while (0)
static
int
__init
check_ull
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
unsigned
long
long
*
pval
=
check_data
;
_check_numbers_template
(
"%llu"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_ll
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
long
long
*
pval
=
check_data
;
_check_numbers_template
(
"%lld"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_ulong
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
unsigned
long
*
pval
=
check_data
;
_check_numbers_template
(
"%lu"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_long
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
long
*
pval
=
check_data
;
_check_numbers_template
(
"%ld"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_uint
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
unsigned
int
*
pval
=
check_data
;
_check_numbers_template
(
"%u"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_int
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
int
*
pval
=
check_data
;
_check_numbers_template
(
"%d"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_ushort
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
unsigned
short
*
pval
=
check_data
;
_check_numbers_template
(
"%hu"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_short
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
short
*
pval
=
check_data
;
_check_numbers_template
(
"%hd"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_uchar
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
unsigned
char
*
pval
=
check_data
;
_check_numbers_template
(
"%hhu"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
static
int
__init
check_char
(
const
void
*
check_data
,
const
char
*
string
,
const
char
*
fmt
,
int
n_args
,
va_list
ap
)
{
const
signed
char
*
pval
=
check_data
;
_check_numbers_template
(
"%hhd"
,
pval
,
string
,
fmt
,
n_args
,
ap
);
}
/* Selection of interesting numbers to test, copied from test-kstrtox.c */
static
const
unsigned
long
long
numbers
[]
__initconst
=
{
0x0ULL
,
0x1ULL
,
0x7fULL
,
0x80ULL
,
0x81ULL
,
0xffULL
,
0x100ULL
,
0x101ULL
,
0x7fffULL
,
0x8000ULL
,
0x8001ULL
,
0xffffULL
,
0x10000ULL
,
0x10001ULL
,
0x7fffffffULL
,
0x80000000ULL
,
0x80000001ULL
,
0xffffffffULL
,
0x100000000ULL
,
0x100000001ULL
,
0x7fffffffffffffffULL
,
0x8000000000000000ULL
,
0x8000000000000001ULL
,
0xfffffffffffffffeULL
,
0xffffffffffffffffULL
,
};
#define value_representable_in_type(T, val) \
(is_signed_type(T) \
? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \
: ((unsigned long long)(val) <= type_max(T)))
#define test_one_number(T, gen_fmt, scan_fmt, val, fn) \
do { \
const T expect_val = (T)(val); \
T result = ~expect_val;
/* should be overwritten */
\
\
snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \
_test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \
} while (0)
#define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \
do { \
int i; \
\
for (i = 0; i < ARRAY_SIZE(numbers); i++) { \
if (value_representable_in_type(T, numbers[i])) \
test_one_number(T, gen_fmt, scan_fmt, \
numbers[i], fn); \
\
if (value_representable_in_type(T, -numbers[i])) \
test_one_number(T, gen_fmt, scan_fmt, \
-numbers[i], fn); \
} \
} while (0)
static
void
__init
numbers_simple
(
void
)
{
simple_numbers_loop
(
unsigned
long
long
,
"%llu"
,
"llu"
,
check_ull
);
simple_numbers_loop
(
long
long
,
"%lld"
,
"lld"
,
check_ll
);
simple_numbers_loop
(
long
long
,
"%lld"
,
"lli"
,
check_ll
);
simple_numbers_loop
(
unsigned
long
long
,
"%llx"
,
"llx"
,
check_ull
);
simple_numbers_loop
(
long
long
,
"%llx"
,
"llx"
,
check_ll
);
simple_numbers_loop
(
long
long
,
"0x%llx"
,
"lli"
,
check_ll
);
simple_numbers_loop
(
unsigned
long
long
,
"0x%llx"
,
"llx"
,
check_ull
);
simple_numbers_loop
(
long
long
,
"0x%llx"
,
"llx"
,
check_ll
);
simple_numbers_loop
(
unsigned
long
,
"%lu"
,
"lu"
,
check_ulong
);
simple_numbers_loop
(
long
,
"%ld"
,
"ld"
,
check_long
);
simple_numbers_loop
(
long
,
"%ld"
,
"li"
,
check_long
);
simple_numbers_loop
(
unsigned
long
,
"%lx"
,
"lx"
,
check_ulong
);
simple_numbers_loop
(
long
,
"%lx"
,
"lx"
,
check_long
);
simple_numbers_loop
(
long
,
"0x%lx"
,
"li"
,
check_long
);
simple_numbers_loop
(
unsigned
long
,
"0x%lx"
,
"lx"
,
check_ulong
);
simple_numbers_loop
(
long
,
"0x%lx"
,
"lx"
,
check_long
);
simple_numbers_loop
(
unsigned
int
,
"%u"
,
"u"
,
check_uint
);
simple_numbers_loop
(
int
,
"%d"
,
"d"
,
check_int
);
simple_numbers_loop
(
int
,
"%d"
,
"i"
,
check_int
);
simple_numbers_loop
(
unsigned
int
,
"%x"
,
"x"
,
check_uint
);
simple_numbers_loop
(
int
,
"%x"
,
"x"
,
check_int
);
simple_numbers_loop
(
int
,
"0x%x"
,
"i"
,
check_int
);
simple_numbers_loop
(
unsigned
int
,
"0x%x"
,
"x"
,
check_uint
);
simple_numbers_loop
(
int
,
"0x%x"
,
"x"
,
check_int
);
simple_numbers_loop
(
unsigned
short
,
"%hu"
,
"hu"
,
check_ushort
);
simple_numbers_loop
(
short
,
"%hd"
,
"hd"
,
check_short
);
simple_numbers_loop
(
short
,
"%hd"
,
"hi"
,
check_short
);
simple_numbers_loop
(
unsigned
short
,
"%hx"
,
"hx"
,
check_ushort
);
simple_numbers_loop
(
short
,
"%hx"
,
"hx"
,
check_short
);
simple_numbers_loop
(
short
,
"0x%hx"
,
"hi"
,
check_short
);
simple_numbers_loop
(
unsigned
short
,
"0x%hx"
,
"hx"
,
check_ushort
);
simple_numbers_loop
(
short
,
"0x%hx"
,
"hx"
,
check_short
);
simple_numbers_loop
(
unsigned
char
,
"%hhu"
,
"hhu"
,
check_uchar
);
simple_numbers_loop
(
signed
char
,
"%hhd"
,
"hhd"
,
check_char
);
simple_numbers_loop
(
signed
char
,
"%hhd"
,
"hhi"
,
check_char
);
simple_numbers_loop
(
unsigned
char
,
"%hhx"
,
"hhx"
,
check_uchar
);
simple_numbers_loop
(
signed
char
,
"%hhx"
,
"hhx"
,
check_char
);
simple_numbers_loop
(
signed
char
,
"0x%hhx"
,
"hhi"
,
check_char
);
simple_numbers_loop
(
unsigned
char
,
"0x%hhx"
,
"hhx"
,
check_uchar
);
simple_numbers_loop
(
signed
char
,
"0x%hhx"
,
"hhx"
,
check_char
);
}
/*
* This gives a better variety of number "lengths" in a small sample than
* the raw prandom*() functions (Not mathematically rigorous!!).
* Variabilty of length and value is more important than perfect randomness.
*/
static
u32
__init
next_test_random
(
u32
max_bits
)
{
u32
n_bits
=
hweight32
(
prandom_u32_state
(
&
rnd_state
))
%
(
max_bits
+
1
);
return
prandom_u32_state
(
&
rnd_state
)
&
(
UINT_MAX
>>
(
32
-
n_bits
));
}
static
unsigned
long
long
__init
next_test_random_ull
(
void
)
{
u32
rand1
=
prandom_u32_state
(
&
rnd_state
);
u32
n_bits
=
(
hweight32
(
rand1
)
*
3
)
%
64
;
u64
val
=
(
u64
)
prandom_u32_state
(
&
rnd_state
)
*
rand1
;
return
val
&
(
ULLONG_MAX
>>
(
64
-
n_bits
));
}
#define random_for_type(T) \
((T)(sizeof(T) <= sizeof(u32) \
? next_test_random(BITS_PER_TYPE(T)) \
: next_test_random_ull()))
/*
* Define a pattern of negative and positive numbers to ensure we get
* some of both within the small number of samples in a test string.
*/
#define NEGATIVES_PATTERN 0x3246
/* 00110010 01000110 */
#define fill_random_array(arr) \
do { \
unsigned int neg_pattern = NEGATIVES_PATTERN; \
int i; \
\
for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) { \
(arr)[i] = random_for_type(typeof((arr)[0])); \
if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1)) \
(arr)[i] = -(arr)[i]; \
} \
} while (0)
/*
* Convenience wrapper around snprintf() to append at buf_pos in buf,
* updating buf_pos and returning the number of characters appended.
* On error buf_pos is not changed and return value is 0.
*/
static
int
__init
__printf
(
4
,
5
)
append_fmt
(
char
*
buf
,
int
*
buf_pos
,
int
buf_len
,
const
char
*
val_fmt
,
...)
{
va_list
ap
;
int
field_len
;
va_start
(
ap
,
val_fmt
);
field_len
=
vsnprintf
(
buf
+
*
buf_pos
,
buf_len
-
*
buf_pos
,
val_fmt
,
ap
);
va_end
(
ap
);
if
(
field_len
<
0
)
field_len
=
0
;
*
buf_pos
+=
field_len
;
return
field_len
;
}
/*
* Convenience function to append the field delimiter string
* to both the value string and format string buffers.
*/
static
void
__init
append_delim
(
char
*
str_buf
,
int
*
str_buf_pos
,
int
str_buf_len
,
char
*
fmt_buf
,
int
*
fmt_buf_pos
,
int
fmt_buf_len
,
const
char
*
delim_str
)
{
append_fmt
(
str_buf
,
str_buf_pos
,
str_buf_len
,
delim_str
);
append_fmt
(
fmt_buf
,
fmt_buf_pos
,
fmt_buf_len
,
delim_str
);
}
#define test_array_8(fn, check_data, string, fmt, arr) \
do { \
BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \
_test(fn, check_data, string, fmt, 8, \
&(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \
&(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \
} while (0)
#define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn) \
do { \
int i, pos = 0, fmt_pos = 0; \
T expect[8], result[8]; \
\
fill_random_array(expect); \
\
for (i = 0; i < ARRAY_SIZE(expect); i++) { \
if (i != 0) \
append_delim(test_buffer, &pos, BUF_SIZE, \
fmt_buffer, &fmt_pos, BUF_SIZE, \
field_sep); \
\
append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]); \
append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt); \
} \
\
test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
} while (0)
#define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn) \
do { \
char full_fmt[16]; \
\
snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt); \
numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn); \
} while (0)
#define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn) \
do { \
int i, val_len, pos = 0, fmt_pos = 0; \
T expect[8], result[8]; \
\
fill_random_array(expect); \
\
for (i = 0; i < ARRAY_SIZE(expect); i++) { \
if (i != 0) \
append_delim(test_buffer, &pos, BUF_SIZE, \
fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\
\
val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, \
expect[i]); \
append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, \
"%%%u%s", val_len, scan_fmt); \
} \
\
test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
} while (0)
static
void
__init
numbers_list
(
const
char
*
delim
)
{
numbers_list_8
(
unsigned
long
long
,
"%llu"
,
delim
,
"llu"
,
check_ull
);
numbers_list_8
(
long
long
,
"%lld"
,
delim
,
"lld"
,
check_ll
);
numbers_list_8
(
long
long
,
"%lld"
,
delim
,
"lli"
,
check_ll
);
numbers_list_8
(
unsigned
long
long
,
"%llx"
,
delim
,
"llx"
,
check_ull
);
numbers_list_8
(
unsigned
long
long
,
"0x%llx"
,
delim
,
"llx"
,
check_ull
);
numbers_list_8
(
long
long
,
"0x%llx"
,
delim
,
"lli"
,
check_ll
);
numbers_list_8
(
unsigned
long
,
"%lu"
,
delim
,
"lu"
,
check_ulong
);
numbers_list_8
(
long
,
"%ld"
,
delim
,
"ld"
,
check_long
);
numbers_list_8
(
long
,
"%ld"
,
delim
,
"li"
,
check_long
);
numbers_list_8
(
unsigned
long
,
"%lx"
,
delim
,
"lx"
,
check_ulong
);
numbers_list_8
(
unsigned
long
,
"0x%lx"
,
delim
,
"lx"
,
check_ulong
);
numbers_list_8
(
long
,
"0x%lx"
,
delim
,
"li"
,
check_long
);
numbers_list_8
(
unsigned
int
,
"%u"
,
delim
,
"u"
,
check_uint
);
numbers_list_8
(
int
,
"%d"
,
delim
,
"d"
,
check_int
);
numbers_list_8
(
int
,
"%d"
,
delim
,
"i"
,
check_int
);
numbers_list_8
(
unsigned
int
,
"%x"
,
delim
,
"x"
,
check_uint
);
numbers_list_8
(
unsigned
int
,
"0x%x"
,
delim
,
"x"
,
check_uint
);
numbers_list_8
(
int
,
"0x%x"
,
delim
,
"i"
,
check_int
);
numbers_list_8
(
unsigned
short
,
"%hu"
,
delim
,
"hu"
,
check_ushort
);
numbers_list_8
(
short
,
"%hd"
,
delim
,
"hd"
,
check_short
);
numbers_list_8
(
short
,
"%hd"
,
delim
,
"hi"
,
check_short
);
numbers_list_8
(
unsigned
short
,
"%hx"
,
delim
,
"hx"
,
check_ushort
);
numbers_list_8
(
unsigned
short
,
"0x%hx"
,
delim
,
"hx"
,
check_ushort
);
numbers_list_8
(
short
,
"0x%hx"
,
delim
,
"hi"
,
check_short
);
numbers_list_8
(
unsigned
char
,
"%hhu"
,
delim
,
"hhu"
,
check_uchar
);
numbers_list_8
(
signed
char
,
"%hhd"
,
delim
,
"hhd"
,
check_char
);
numbers_list_8
(
signed
char
,
"%hhd"
,
delim
,
"hhi"
,
check_char
);
numbers_list_8
(
unsigned
char
,
"%hhx"
,
delim
,
"hhx"
,
check_uchar
);
numbers_list_8
(
unsigned
char
,
"0x%hhx"
,
delim
,
"hhx"
,
check_uchar
);
numbers_list_8
(
signed
char
,
"0x%hhx"
,
delim
,
"hhi"
,
check_char
);
}
/*
* List of numbers separated by delim. Each field width specifier is the
* maximum possible digits for the given type and base.
*/
static
void
__init
numbers_list_field_width_typemax
(
const
char
*
delim
)
{
numbers_list_fix_width
(
unsigned
long
long
,
"%llu"
,
delim
,
20
,
"llu"
,
check_ull
);
numbers_list_fix_width
(
long
long
,
"%lld"
,
delim
,
20
,
"lld"
,
check_ll
);
numbers_list_fix_width
(
long
long
,
"%lld"
,
delim
,
20
,
"lli"
,
check_ll
);
numbers_list_fix_width
(
unsigned
long
long
,
"%llx"
,
delim
,
16
,
"llx"
,
check_ull
);
numbers_list_fix_width
(
unsigned
long
long
,
"0x%llx"
,
delim
,
18
,
"llx"
,
check_ull
);
numbers_list_fix_width
(
long
long
,
"0x%llx"
,
delim
,
18
,
"lli"
,
check_ll
);
#if BITS_PER_LONG == 64
numbers_list_fix_width
(
unsigned
long
,
"%lu"
,
delim
,
20
,
"lu"
,
check_ulong
);
numbers_list_fix_width
(
long
,
"%ld"
,
delim
,
20
,
"ld"
,
check_long
);
numbers_list_fix_width
(
long
,
"%ld"
,
delim
,
20
,
"li"
,
check_long
);
numbers_list_fix_width
(
unsigned
long
,
"%lx"
,
delim
,
16
,
"lx"
,
check_ulong
);
numbers_list_fix_width
(
unsigned
long
,
"0x%lx"
,
delim
,
18
,
"lx"
,
check_ulong
);
numbers_list_fix_width
(
long
,
"0x%lx"
,
delim
,
18
,
"li"
,
check_long
);
#else
numbers_list_fix_width
(
unsigned
long
,
"%lu"
,
delim
,
10
,
"lu"
,
check_ulong
);
numbers_list_fix_width
(
long
,
"%ld"
,
delim
,
11
,
"ld"
,
check_long
);
numbers_list_fix_width
(
long
,
"%ld"
,
delim
,
11
,
"li"
,
check_long
);
numbers_list_fix_width
(
unsigned
long
,
"%lx"
,
delim
,
8
,
"lx"
,
check_ulong
);
numbers_list_fix_width
(
unsigned
long
,
"0x%lx"
,
delim
,
10
,
"lx"
,
check_ulong
);
numbers_list_fix_width
(
long
,
"0x%lx"
,
delim
,
10
,
"li"
,
check_long
);
#endif
numbers_list_fix_width
(
unsigned
int
,
"%u"
,
delim
,
10
,
"u"
,
check_uint
);
numbers_list_fix_width
(
int
,
"%d"
,
delim
,
11
,
"d"
,
check_int
);
numbers_list_fix_width
(
int
,
"%d"
,
delim
,
11
,
"i"
,
check_int
);
numbers_list_fix_width
(
unsigned
int
,
"%x"
,
delim
,
8
,
"x"
,
check_uint
);
numbers_list_fix_width
(
unsigned
int
,
"0x%x"
,
delim
,
10
,
"x"
,
check_uint
);
numbers_list_fix_width
(
int
,
"0x%x"
,
delim
,
10
,
"i"
,
check_int
);
numbers_list_fix_width
(
unsigned
short
,
"%hu"
,
delim
,
5
,
"hu"
,
check_ushort
);
numbers_list_fix_width
(
short
,
"%hd"
,
delim
,
6
,
"hd"
,
check_short
);
numbers_list_fix_width
(
short
,
"%hd"
,
delim
,
6
,
"hi"
,
check_short
);
numbers_list_fix_width
(
unsigned
short
,
"%hx"
,
delim
,
4
,
"hx"
,
check_ushort
);
numbers_list_fix_width
(
unsigned
short
,
"0x%hx"
,
delim
,
6
,
"hx"
,
check_ushort
);
numbers_list_fix_width
(
short
,
"0x%hx"
,
delim
,
6
,
"hi"
,
check_short
);
numbers_list_fix_width
(
unsigned
char
,
"%hhu"
,
delim
,
3
,
"hhu"
,
check_uchar
);
numbers_list_fix_width
(
signed
char
,
"%hhd"
,
delim
,
4
,
"hhd"
,
check_char
);
numbers_list_fix_width
(
signed
char
,
"%hhd"
,
delim
,
4
,
"hhi"
,
check_char
);
numbers_list_fix_width
(
unsigned
char
,
"%hhx"
,
delim
,
2
,
"hhx"
,
check_uchar
);
numbers_list_fix_width
(
unsigned
char
,
"0x%hhx"
,
delim
,
4
,
"hhx"
,
check_uchar
);
numbers_list_fix_width
(
signed
char
,
"0x%hhx"
,
delim
,
4
,
"hhi"
,
check_char
);
}
/*
* List of numbers separated by delim. Each field width specifier is the
* exact length of the corresponding value digits in the string being scanned.
*/
static
void
__init
numbers_list_field_width_val_width
(
const
char
*
delim
)
{
numbers_list_val_width
(
unsigned
long
long
,
"%llu"
,
delim
,
"llu"
,
check_ull
);
numbers_list_val_width
(
long
long
,
"%lld"
,
delim
,
"lld"
,
check_ll
);
numbers_list_val_width
(
long
long
,
"%lld"
,
delim
,
"lli"
,
check_ll
);
numbers_list_val_width
(
unsigned
long
long
,
"%llx"
,
delim
,
"llx"
,
check_ull
);
numbers_list_val_width
(
unsigned
long
long
,
"0x%llx"
,
delim
,
"llx"
,
check_ull
);
numbers_list_val_width
(
long
long
,
"0x%llx"
,
delim
,
"lli"
,
check_ll
);
numbers_list_val_width
(
unsigned
long
,
"%lu"
,
delim
,
"lu"
,
check_ulong
);
numbers_list_val_width
(
long
,
"%ld"
,
delim
,
"ld"
,
check_long
);
numbers_list_val_width
(
long
,
"%ld"
,
delim
,
"li"
,
check_long
);
numbers_list_val_width
(
unsigned
long
,
"%lx"
,
delim
,
"lx"
,
check_ulong
);
numbers_list_val_width
(
unsigned
long
,
"0x%lx"
,
delim
,
"lx"
,
check_ulong
);
numbers_list_val_width
(
long
,
"0x%lx"
,
delim
,
"li"
,
check_long
);
numbers_list_val_width
(
unsigned
int
,
"%u"
,
delim
,
"u"
,
check_uint
);
numbers_list_val_width
(
int
,
"%d"
,
delim
,
"d"
,
check_int
);
numbers_list_val_width
(
int
,
"%d"
,
delim
,
"i"
,
check_int
);
numbers_list_val_width
(
unsigned
int
,
"%x"
,
delim
,
"x"
,
check_uint
);
numbers_list_val_width
(
unsigned
int
,
"0x%x"
,
delim
,
"x"
,
check_uint
);
numbers_list_val_width
(
int
,
"0x%x"
,
delim
,
"i"
,
check_int
);
numbers_list_val_width
(
unsigned
short
,
"%hu"
,
delim
,
"hu"
,
check_ushort
);
numbers_list_val_width
(
short
,
"%hd"
,
delim
,
"hd"
,
check_short
);
numbers_list_val_width
(
short
,
"%hd"
,
delim
,
"hi"
,
check_short
);
numbers_list_val_width
(
unsigned
short
,
"%hx"
,
delim
,
"hx"
,
check_ushort
);
numbers_list_val_width
(
unsigned
short
,
"0x%hx"
,
delim
,
"hx"
,
check_ushort
);
numbers_list_val_width
(
short
,
"0x%hx"
,
delim
,
"hi"
,
check_short
);
numbers_list_val_width
(
unsigned
char
,
"%hhu"
,
delim
,
"hhu"
,
check_uchar
);
numbers_list_val_width
(
signed
char
,
"%hhd"
,
delim
,
"hhd"
,
check_char
);
numbers_list_val_width
(
signed
char
,
"%hhd"
,
delim
,
"hhi"
,
check_char
);
numbers_list_val_width
(
unsigned
char
,
"%hhx"
,
delim
,
"hhx"
,
check_uchar
);
numbers_list_val_width
(
unsigned
char
,
"0x%hhx"
,
delim
,
"hhx"
,
check_uchar
);
numbers_list_val_width
(
signed
char
,
"0x%hhx"
,
delim
,
"hhi"
,
check_char
);
}
/*
* Slice a continuous string of digits without field delimiters, containing
* numbers of varying length, using the field width to extract each group
* of digits. For example the hex values c0,3,bf01,303 would have a
* string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
*/
static
void
__init
numbers_slice
(
void
)
{
numbers_list_field_width_val_width
(
""
);
}
#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \
do { \
const T expect[2] = { expect0, expect1 }; \
T result[2] = {~expect[0], ~expect[1]}; \
\
_test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \
} while (0)
/*
* Number prefix is >= field width.
* Expected behaviour is derived from testing userland sscanf.
*/
static
void
__init
numbers_prefix_overflow
(
void
)
{
/*
* Negative decimal with a field of width 1, should quit scanning
* and return 0.
*/
test_number_prefix
(
long
long
,
"-1 1"
,
"%1lld %lld"
,
0
,
0
,
0
,
check_ll
);
test_number_prefix
(
long
,
"-1 1"
,
"%1ld %ld"
,
0
,
0
,
0
,
check_long
);
test_number_prefix
(
int
,
"-1 1"
,
"%1d %d"
,
0
,
0
,
0
,
check_int
);
test_number_prefix
(
short
,
"-1 1"
,
"%1hd %hd"
,
0
,
0
,
0
,
check_short
);
test_number_prefix
(
signed
char
,
"-1 1"
,
"%1hhd %hhd"
,
0
,
0
,
0
,
check_char
);
test_number_prefix
(
long
long
,
"-1 1"
,
"%1lli %lli"
,
0
,
0
,
0
,
check_ll
);
test_number_prefix
(
long
,
"-1 1"
,
"%1li %li"
,
0
,
0
,
0
,
check_long
);
test_number_prefix
(
int
,
"-1 1"
,
"%1i %i"
,
0
,
0
,
0
,
check_int
);
test_number_prefix
(
short
,
"-1 1"
,
"%1hi %hi"
,
0
,
0
,
0
,
check_short
);
test_number_prefix
(
signed
char
,
"-1 1"
,
"%1hhi %hhi"
,
0
,
0
,
0
,
check_char
);
/*
* 0x prefix in a field of width 1: 0 is a valid digit so should
* convert. Next field scan starts at the 'x' which isn't a digit so
* scan quits with one field converted.
*/
test_number_prefix
(
unsigned
long
long
,
"0xA7"
,
"%1llx%llx"
,
0
,
0
,
1
,
check_ull
);
test_number_prefix
(
unsigned
long
,
"0xA7"
,
"%1lx%lx"
,
0
,
0
,
1
,
check_ulong
);
test_number_prefix
(
unsigned
int
,
"0xA7"
,
"%1x%x"
,
0
,
0
,
1
,
check_uint
);
test_number_prefix
(
unsigned
short
,
"0xA7"
,
"%1hx%hx"
,
0
,
0
,
1
,
check_ushort
);
test_number_prefix
(
unsigned
char
,
"0xA7"
,
"%1hhx%hhx"
,
0
,
0
,
1
,
check_uchar
);
test_number_prefix
(
long
long
,
"0xA7"
,
"%1lli%llx"
,
0
,
0
,
1
,
check_ll
);
test_number_prefix
(
long
,
"0xA7"
,
"%1li%lx"
,
0
,
0
,
1
,
check_long
);
test_number_prefix
(
int
,
"0xA7"
,
"%1i%x"
,
0
,
0
,
1
,
check_int
);
test_number_prefix
(
short
,
"0xA7"
,
"%1hi%hx"
,
0
,
0
,
1
,
check_short
);
test_number_prefix
(
char
,
"0xA7"
,
"%1hhi%hhx"
,
0
,
0
,
1
,
check_char
);
/*
* 0x prefix in a field of width 2 using %x conversion: first field
* converts to 0. Next field scan starts at the character after "0x".
* Both fields will convert.
*/
test_number_prefix
(
unsigned
long
long
,
"0xA7"
,
"%2llx%llx"
,
0
,
0xa7
,
2
,
check_ull
);
test_number_prefix
(
unsigned
long
,
"0xA7"
,
"%2lx%lx"
,
0
,
0xa7
,
2
,
check_ulong
);
test_number_prefix
(
unsigned
int
,
"0xA7"
,
"%2x%x"
,
0
,
0xa7
,
2
,
check_uint
);
test_number_prefix
(
unsigned
short
,
"0xA7"
,
"%2hx%hx"
,
0
,
0xa7
,
2
,
check_ushort
);
test_number_prefix
(
unsigned
char
,
"0xA7"
,
"%2hhx%hhx"
,
0
,
0xa7
,
2
,
check_uchar
);
/*
* 0x prefix in a field of width 2 using %i conversion: first field
* converts to 0. Next field scan starts at the character after "0x",
* which will convert if can be intepreted as decimal but will fail
* if it contains any hex digits (since no 0x prefix).
*/
test_number_prefix
(
long
long
,
"0x67"
,
"%2lli%lli"
,
0
,
67
,
2
,
check_ll
);
test_number_prefix
(
long
,
"0x67"
,
"%2li%li"
,
0
,
67
,
2
,
check_long
);
test_number_prefix
(
int
,
"0x67"
,
"%2i%i"
,
0
,
67
,
2
,
check_int
);
test_number_prefix
(
short
,
"0x67"
,
"%2hi%hi"
,
0
,
67
,
2
,
check_short
);
test_number_prefix
(
char
,
"0x67"
,
"%2hhi%hhi"
,
0
,
67
,
2
,
check_char
);
test_number_prefix
(
long
long
,
"0xA7"
,
"%2lli%lli"
,
0
,
0
,
1
,
check_ll
);
test_number_prefix
(
long
,
"0xA7"
,
"%2li%li"
,
0
,
0
,
1
,
check_long
);
test_number_prefix
(
int
,
"0xA7"
,
"%2i%i"
,
0
,
0
,
1
,
check_int
);
test_number_prefix
(
short
,
"0xA7"
,
"%2hi%hi"
,
0
,
0
,
1
,
check_short
);
test_number_prefix
(
char
,
"0xA7"
,
"%2hhi%hhi"
,
0
,
0
,
1
,
check_char
);
}
#define _test_simple_strtoxx(T, fn, gen_fmt, expect, base) \
do { \
T got; \
char *endp; \
int len; \
bool fail = false; \
\
total_tests++; \
len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \
got = (fn)(test_buffer, &endp, base); \
pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got); \
if (got != (expect)) { \
fail = true; \
pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
test_buffer, base, got, expect); \
} else if (endp != test_buffer + len) { \
fail = true; \
pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
test_buffer, base, test_buffer, \
test_buffer + len, endp); \
} \
\
if (fail) \
failed_tests++; \
} while (0)
#define test_simple_strtoxx(T, fn, gen_fmt, base) \
do { \
int i; \
\
for (i = 0; i < ARRAY_SIZE(numbers); i++) { \
_test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base); \
\
if (is_signed_type(T)) \
_test_simple_strtoxx(T, fn, gen_fmt, \
-(T)numbers[i], base); \
} \
} while (0)
static
void
__init
test_simple_strtoull
(
void
)
{
test_simple_strtoxx
(
unsigned
long
long
,
simple_strtoull
,
"%llu"
,
10
);
test_simple_strtoxx
(
unsigned
long
long
,
simple_strtoull
,
"%llu"
,
0
);
test_simple_strtoxx
(
unsigned
long
long
,
simple_strtoull
,
"%llx"
,
16
);
test_simple_strtoxx
(
unsigned
long
long
,
simple_strtoull
,
"0x%llx"
,
16
);
test_simple_strtoxx
(
unsigned
long
long
,
simple_strtoull
,
"0x%llx"
,
0
);
}
static
void
__init
test_simple_strtoll
(
void
)
{
test_simple_strtoxx
(
long
long
,
simple_strtoll
,
"%lld"
,
10
);
test_simple_strtoxx
(
long
long
,
simple_strtoll
,
"%lld"
,
0
);
test_simple_strtoxx
(
long
long
,
simple_strtoll
,
"%llx"
,
16
);
test_simple_strtoxx
(
long
long
,
simple_strtoll
,
"0x%llx"
,
16
);
test_simple_strtoxx
(
long
long
,
simple_strtoll
,
"0x%llx"
,
0
);
}
static
void
__init
test_simple_strtoul
(
void
)
{
test_simple_strtoxx
(
unsigned
long
,
simple_strtoul
,
"%lu"
,
10
);
test_simple_strtoxx
(
unsigned
long
,
simple_strtoul
,
"%lu"
,
0
);
test_simple_strtoxx
(
unsigned
long
,
simple_strtoul
,
"%lx"
,
16
);
test_simple_strtoxx
(
unsigned
long
,
simple_strtoul
,
"0x%lx"
,
16
);
test_simple_strtoxx
(
unsigned
long
,
simple_strtoul
,
"0x%lx"
,
0
);
}
static
void
__init
test_simple_strtol
(
void
)
{
test_simple_strtoxx
(
long
,
simple_strtol
,
"%ld"
,
10
);
test_simple_strtoxx
(
long
,
simple_strtol
,
"%ld"
,
0
);
test_simple_strtoxx
(
long
,
simple_strtol
,
"%lx"
,
16
);
test_simple_strtoxx
(
long
,
simple_strtol
,
"0x%lx"
,
16
);
test_simple_strtoxx
(
long
,
simple_strtol
,
"0x%lx"
,
0
);
}
/* Selection of common delimiters/separators between numbers in a string. */
static
const
char
*
const
number_delimiters
[]
__initconst
=
{
" "
,
":"
,
","
,
"-"
,
"/"
,
};
static
void
__init
test_numbers
(
void
)
{
int
i
;
/* String containing only one number. */
numbers_simple
();
/* String with multiple numbers separated by delimiter. */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
number_delimiters
);
i
++
)
{
numbers_list
(
number_delimiters
[
i
]);
/* Field width may be longer than actual field digits. */
numbers_list_field_width_typemax
(
number_delimiters
[
i
]);
/* Each field width exactly length of actual field digits. */
numbers_list_field_width_val_width
(
number_delimiters
[
i
]);
}
/* Slice continuous sequence of digits using field widths. */
numbers_slice
();
numbers_prefix_overflow
();
}
static
void
__init
selftest
(
void
)
{
test_buffer
=
kmalloc
(
BUF_SIZE
,
GFP_KERNEL
);
if
(
!
test_buffer
)
return
;
fmt_buffer
=
kmalloc
(
BUF_SIZE
,
GFP_KERNEL
);
if
(
!
fmt_buffer
)
{
kfree
(
test_buffer
);
return
;
}
prandom_seed_state
(
&
rnd_state
,
3141592653589793238ULL
);
test_numbers
();
test_simple_strtoull
();
test_simple_strtoll
();
test_simple_strtoul
();
test_simple_strtol
();
kfree
(
fmt_buffer
);
kfree
(
test_buffer
);
}
KSTM_MODULE_LOADERS
(
test_scanf
);
MODULE_AUTHOR
(
"Richard Fitzgerald <rf@opensource.cirrus.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
lib/vsprintf.c
浏览文件 @
d8c03214
...
...
@@ -53,6 +53,31 @@
#include <linux/string_helpers.h>
#include "kstrtox.h"
static
unsigned
long
long
simple_strntoull
(
const
char
*
startp
,
size_t
max_chars
,
char
**
endp
,
unsigned
int
base
)
{
const
char
*
cp
;
unsigned
long
long
result
=
0ULL
;
size_t
prefix_chars
;
unsigned
int
rv
;
cp
=
_parse_integer_fixup_radix
(
startp
,
&
base
);
prefix_chars
=
cp
-
startp
;
if
(
prefix_chars
<
max_chars
)
{
rv
=
_parse_integer_limit
(
cp
,
base
,
&
result
,
max_chars
-
prefix_chars
);
/* FIXME */
cp
+=
(
rv
&
~
KSTRTOX_OVERFLOW
);
}
else
{
/* Field too short for prefix + digit, skip over without converting */
cp
=
startp
+
max_chars
;
}
if
(
endp
)
*
endp
=
(
char
*
)
cp
;
return
result
;
}
/**
* simple_strtoull - convert a string to an unsigned long long
* @cp: The start of the string
...
...
@@ -63,18 +88,7 @@
*/
unsigned
long
long
simple_strtoull
(
const
char
*
cp
,
char
**
endp
,
unsigned
int
base
)
{
unsigned
long
long
result
;
unsigned
int
rv
;
cp
=
_parse_integer_fixup_radix
(
cp
,
&
base
);
rv
=
_parse_integer
(
cp
,
base
,
&
result
);
/* FIXME */
cp
+=
(
rv
&
~
KSTRTOX_OVERFLOW
);
if
(
endp
)
*
endp
=
(
char
*
)
cp
;
return
result
;
return
simple_strntoull
(
cp
,
INT_MAX
,
endp
,
base
);
}
EXPORT_SYMBOL
(
simple_strtoull
);
...
...
@@ -109,6 +123,21 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
}
EXPORT_SYMBOL
(
simple_strtol
);
static
long
long
simple_strntoll
(
const
char
*
cp
,
size_t
max_chars
,
char
**
endp
,
unsigned
int
base
)
{
/*
* simple_strntoull() safely handles receiving max_chars==0 in the
* case cp[0] == '-' && max_chars == 1.
* If max_chars == 0 we can drop through and pass it to simple_strntoull()
* and the content of *cp is irrelevant.
*/
if
(
*
cp
==
'-'
&&
max_chars
>
0
)
return
-
simple_strntoull
(
cp
+
1
,
max_chars
-
1
,
endp
,
base
);
return
simple_strntoull
(
cp
,
max_chars
,
endp
,
base
);
}
/**
* simple_strtoll - convert a string to a signed long long
* @cp: The start of the string
...
...
@@ -119,10 +148,7 @@ EXPORT_SYMBOL(simple_strtol);
*/
long
long
simple_strtoll
(
const
char
*
cp
,
char
**
endp
,
unsigned
int
base
)
{
if
(
*
cp
==
'-'
)
return
-
simple_strtoull
(
cp
+
1
,
endp
,
base
);
return
simple_strtoull
(
cp
,
endp
,
base
);
return
simple_strntoll
(
cp
,
INT_MAX
,
endp
,
base
);
}
EXPORT_SYMBOL
(
simple_strtoll
);
...
...
@@ -3538,8 +3564,12 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
str
=
skip_spaces
(
str
);
digit
=
*
str
;
if
(
is_sign
&&
digit
==
'-'
)
if
(
is_sign
&&
digit
==
'-'
)
{
if
(
field_width
==
1
)
break
;
digit
=
*
(
str
+
1
);
}
if
(
!
digit
||
(
base
==
16
&&
!
isxdigit
(
digit
))
...
...
@@ -3549,25 +3579,13 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
break
;
if
(
is_sign
)
val
.
s
=
qualifier
!=
'L'
?
simple_strtol
(
str
,
&
next
,
base
)
:
simple_strtoll
(
str
,
&
next
,
base
);
val
.
s
=
simple_strntoll
(
str
,
field_width
>=
0
?
field_width
:
INT_MAX
,
&
next
,
base
);
else
val
.
u
=
qualifier
!=
'L'
?
simple_strtoul
(
str
,
&
next
,
base
)
:
simple_strtoull
(
str
,
&
next
,
base
);
if
(
field_width
>
0
&&
next
-
str
>
field_width
)
{
if
(
base
==
0
)
_parse_integer_fixup_radix
(
str
,
&
base
);
while
(
next
-
str
>
field_width
)
{
if
(
is_sign
)
val
.
s
=
div_s64
(
val
.
s
,
base
);
else
val
.
u
=
div_u64
(
val
.
u
,
base
);
--
next
;
}
}
val
.
u
=
simple_strntoull
(
str
,
field_width
>=
0
?
field_width
:
INT_MAX
,
&
next
,
base
);
switch
(
qualifier
)
{
case
'H'
:
/* that's 'hh' in format */
...
...
tools/testing/selftests/lib/Makefile
浏览文件 @
d8c03214
...
...
@@ -4,6 +4,6 @@
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
all
:
TEST_PROGS
:=
printf.sh bitmap.sh prime_numbers.sh strscpy.sh
TEST_PROGS
:=
printf.sh bitmap.sh prime_numbers.sh s
canf.sh s
trscpy.sh
include
../lib.mk
tools/testing/selftests/lib/config
浏览文件 @
d8c03214
CONFIG_TEST_PRINTF=m
CONFIG_TEST_SCANF=m
CONFIG_TEST_BITMAP=m
CONFIG_PRIME_NUMBERS=m
CONFIG_TEST_STRSCPY=m
...
...
tools/testing/selftests/lib/scanf.sh
0 → 100755
浏览文件 @
d8c03214
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Tests the scanf infrastructure using test_scanf kernel module.
$(
dirname
$0
)
/../kselftest/module.sh
"scanf"
test_scanf
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录