150f530e1SRichard Fitzgerald // SPDX-License-Identifier: GPL-2.0-only
250f530e1SRichard Fitzgerald /*
350f530e1SRichard Fitzgerald * Test cases for sscanf facility.
450f530e1SRichard Fitzgerald */
550f530e1SRichard Fitzgerald
650f530e1SRichard Fitzgerald #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
750f530e1SRichard Fitzgerald
850f530e1SRichard Fitzgerald #include <linux/bitops.h>
950f530e1SRichard Fitzgerald #include <linux/init.h>
1050f530e1SRichard Fitzgerald #include <linux/kernel.h>
1150f530e1SRichard Fitzgerald #include <linux/module.h>
1250f530e1SRichard Fitzgerald #include <linux/overflow.h>
1350f530e1SRichard Fitzgerald #include <linux/printk.h>
1450f530e1SRichard Fitzgerald #include <linux/random.h>
1550f530e1SRichard Fitzgerald #include <linux/slab.h>
1650f530e1SRichard Fitzgerald #include <linux/string.h>
1750f530e1SRichard Fitzgerald
1850f530e1SRichard Fitzgerald #include "../tools/testing/selftests/kselftest_module.h"
1950f530e1SRichard Fitzgerald
2050f530e1SRichard Fitzgerald #define BUF_SIZE 1024
2150f530e1SRichard Fitzgerald
2250f530e1SRichard Fitzgerald KSTM_MODULE_GLOBALS();
2350f530e1SRichard Fitzgerald static char *test_buffer __initdata;
2450f530e1SRichard Fitzgerald static char *fmt_buffer __initdata;
2550f530e1SRichard Fitzgerald static struct rnd_state rnd_state __initdata;
2650f530e1SRichard Fitzgerald
2750f530e1SRichard Fitzgerald typedef int (*check_fn)(const void *check_data, const char *string,
2850f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap);
2950f530e1SRichard Fitzgerald
3050f530e1SRichard Fitzgerald static void __scanf(4, 6) __init
_test(check_fn fn,const void * check_data,const char * string,const char * fmt,int n_args,...)3150f530e1SRichard Fitzgerald _test(check_fn fn, const void *check_data, const char *string, const char *fmt,
3250f530e1SRichard Fitzgerald int n_args, ...)
3350f530e1SRichard Fitzgerald {
3450f530e1SRichard Fitzgerald va_list ap, ap_copy;
3550f530e1SRichard Fitzgerald int ret;
3650f530e1SRichard Fitzgerald
3750f530e1SRichard Fitzgerald total_tests++;
3850f530e1SRichard Fitzgerald
3950f530e1SRichard Fitzgerald va_start(ap, n_args);
4050f530e1SRichard Fitzgerald va_copy(ap_copy, ap);
4150f530e1SRichard Fitzgerald ret = vsscanf(string, fmt, ap_copy);
4250f530e1SRichard Fitzgerald va_end(ap_copy);
4350f530e1SRichard Fitzgerald
4450f530e1SRichard Fitzgerald if (ret != n_args) {
4550f530e1SRichard Fitzgerald pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n",
4650f530e1SRichard Fitzgerald string, fmt, ret, n_args);
4750f530e1SRichard Fitzgerald goto fail;
4850f530e1SRichard Fitzgerald }
4950f530e1SRichard Fitzgerald
5050f530e1SRichard Fitzgerald ret = (*fn)(check_data, string, fmt, n_args, ap);
5150f530e1SRichard Fitzgerald if (ret)
5250f530e1SRichard Fitzgerald goto fail;
5350f530e1SRichard Fitzgerald
5450f530e1SRichard Fitzgerald va_end(ap);
5550f530e1SRichard Fitzgerald
5650f530e1SRichard Fitzgerald return;
5750f530e1SRichard Fitzgerald
5850f530e1SRichard Fitzgerald fail:
5950f530e1SRichard Fitzgerald failed_tests++;
6050f530e1SRichard Fitzgerald va_end(ap);
6150f530e1SRichard Fitzgerald }
6250f530e1SRichard Fitzgerald
6350f530e1SRichard Fitzgerald #define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap) \
6450f530e1SRichard Fitzgerald do { \
6550f530e1SRichard Fitzgerald pr_debug("\"%s\", \"%s\" ->\n", str, fmt); \
6650f530e1SRichard Fitzgerald for (; n_args > 0; n_args--, expect++) { \
6750f530e1SRichard Fitzgerald typeof(*expect) got = *va_arg(ap, typeof(expect)); \
6850f530e1SRichard Fitzgerald pr_debug("\t" arg_fmt "\n", got); \
6950f530e1SRichard Fitzgerald if (got != *expect) { \
7050f530e1SRichard Fitzgerald pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
7150f530e1SRichard Fitzgerald str, fmt, *expect, got); \
7250f530e1SRichard Fitzgerald return 1; \
7350f530e1SRichard Fitzgerald } \
7450f530e1SRichard Fitzgerald } \
7550f530e1SRichard Fitzgerald return 0; \
7650f530e1SRichard Fitzgerald } while (0)
7750f530e1SRichard Fitzgerald
check_ull(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)7850f530e1SRichard Fitzgerald static int __init check_ull(const void *check_data, const char *string,
7950f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
8050f530e1SRichard Fitzgerald {
8150f530e1SRichard Fitzgerald const unsigned long long *pval = check_data;
8250f530e1SRichard Fitzgerald
8350f530e1SRichard Fitzgerald _check_numbers_template("%llu", pval, string, fmt, n_args, ap);
8450f530e1SRichard Fitzgerald }
8550f530e1SRichard Fitzgerald
check_ll(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)8650f530e1SRichard Fitzgerald static int __init check_ll(const void *check_data, const char *string,
8750f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
8850f530e1SRichard Fitzgerald {
8950f530e1SRichard Fitzgerald const long long *pval = check_data;
9050f530e1SRichard Fitzgerald
9150f530e1SRichard Fitzgerald _check_numbers_template("%lld", pval, string, fmt, n_args, ap);
9250f530e1SRichard Fitzgerald }
9350f530e1SRichard Fitzgerald
check_ulong(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)9450f530e1SRichard Fitzgerald static int __init check_ulong(const void *check_data, const char *string,
9550f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
9650f530e1SRichard Fitzgerald {
9750f530e1SRichard Fitzgerald const unsigned long *pval = check_data;
9850f530e1SRichard Fitzgerald
9950f530e1SRichard Fitzgerald _check_numbers_template("%lu", pval, string, fmt, n_args, ap);
10050f530e1SRichard Fitzgerald }
10150f530e1SRichard Fitzgerald
check_long(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)10250f530e1SRichard Fitzgerald static int __init check_long(const void *check_data, const char *string,
10350f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
10450f530e1SRichard Fitzgerald {
10550f530e1SRichard Fitzgerald const long *pval = check_data;
10650f530e1SRichard Fitzgerald
10750f530e1SRichard Fitzgerald _check_numbers_template("%ld", pval, string, fmt, n_args, ap);
10850f530e1SRichard Fitzgerald }
10950f530e1SRichard Fitzgerald
check_uint(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)11050f530e1SRichard Fitzgerald static int __init check_uint(const void *check_data, const char *string,
11150f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
11250f530e1SRichard Fitzgerald {
11350f530e1SRichard Fitzgerald const unsigned int *pval = check_data;
11450f530e1SRichard Fitzgerald
11550f530e1SRichard Fitzgerald _check_numbers_template("%u", pval, string, fmt, n_args, ap);
11650f530e1SRichard Fitzgerald }
11750f530e1SRichard Fitzgerald
check_int(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)11850f530e1SRichard Fitzgerald static int __init check_int(const void *check_data, const char *string,
11950f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
12050f530e1SRichard Fitzgerald {
12150f530e1SRichard Fitzgerald const int *pval = check_data;
12250f530e1SRichard Fitzgerald
12350f530e1SRichard Fitzgerald _check_numbers_template("%d", pval, string, fmt, n_args, ap);
12450f530e1SRichard Fitzgerald }
12550f530e1SRichard Fitzgerald
check_ushort(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)12650f530e1SRichard Fitzgerald static int __init check_ushort(const void *check_data, const char *string,
12750f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
12850f530e1SRichard Fitzgerald {
12950f530e1SRichard Fitzgerald const unsigned short *pval = check_data;
13050f530e1SRichard Fitzgerald
13150f530e1SRichard Fitzgerald _check_numbers_template("%hu", pval, string, fmt, n_args, ap);
13250f530e1SRichard Fitzgerald }
13350f530e1SRichard Fitzgerald
check_short(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)13450f530e1SRichard Fitzgerald static int __init check_short(const void *check_data, const char *string,
13550f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
13650f530e1SRichard Fitzgerald {
13750f530e1SRichard Fitzgerald const short *pval = check_data;
13850f530e1SRichard Fitzgerald
13950f530e1SRichard Fitzgerald _check_numbers_template("%hd", pval, string, fmt, n_args, ap);
14050f530e1SRichard Fitzgerald }
14150f530e1SRichard Fitzgerald
check_uchar(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)14250f530e1SRichard Fitzgerald static int __init check_uchar(const void *check_data, const char *string,
14350f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
14450f530e1SRichard Fitzgerald {
14550f530e1SRichard Fitzgerald const unsigned char *pval = check_data;
14650f530e1SRichard Fitzgerald
14750f530e1SRichard Fitzgerald _check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
14850f530e1SRichard Fitzgerald }
14950f530e1SRichard Fitzgerald
check_char(const void * check_data,const char * string,const char * fmt,int n_args,va_list ap)15050f530e1SRichard Fitzgerald static int __init check_char(const void *check_data, const char *string,
15150f530e1SRichard Fitzgerald const char *fmt, int n_args, va_list ap)
15250f530e1SRichard Fitzgerald {
15350f530e1SRichard Fitzgerald const signed char *pval = check_data;
15450f530e1SRichard Fitzgerald
15550f530e1SRichard Fitzgerald _check_numbers_template("%hhd", pval, string, fmt, n_args, ap);
15650f530e1SRichard Fitzgerald }
15750f530e1SRichard Fitzgerald
15850f530e1SRichard Fitzgerald /* Selection of interesting numbers to test, copied from test-kstrtox.c */
15950f530e1SRichard Fitzgerald static const unsigned long long numbers[] __initconst = {
16050f530e1SRichard Fitzgerald 0x0ULL,
16150f530e1SRichard Fitzgerald 0x1ULL,
16250f530e1SRichard Fitzgerald 0x7fULL,
16350f530e1SRichard Fitzgerald 0x80ULL,
16450f530e1SRichard Fitzgerald 0x81ULL,
16550f530e1SRichard Fitzgerald 0xffULL,
16650f530e1SRichard Fitzgerald 0x100ULL,
16750f530e1SRichard Fitzgerald 0x101ULL,
16850f530e1SRichard Fitzgerald 0x7fffULL,
16950f530e1SRichard Fitzgerald 0x8000ULL,
17050f530e1SRichard Fitzgerald 0x8001ULL,
17150f530e1SRichard Fitzgerald 0xffffULL,
17250f530e1SRichard Fitzgerald 0x10000ULL,
17350f530e1SRichard Fitzgerald 0x10001ULL,
17450f530e1SRichard Fitzgerald 0x7fffffffULL,
17550f530e1SRichard Fitzgerald 0x80000000ULL,
17650f530e1SRichard Fitzgerald 0x80000001ULL,
17750f530e1SRichard Fitzgerald 0xffffffffULL,
17850f530e1SRichard Fitzgerald 0x100000000ULL,
17950f530e1SRichard Fitzgerald 0x100000001ULL,
18050f530e1SRichard Fitzgerald 0x7fffffffffffffffULL,
18150f530e1SRichard Fitzgerald 0x8000000000000000ULL,
18250f530e1SRichard Fitzgerald 0x8000000000000001ULL,
18350f530e1SRichard Fitzgerald 0xfffffffffffffffeULL,
18450f530e1SRichard Fitzgerald 0xffffffffffffffffULL,
18550f530e1SRichard Fitzgerald };
18650f530e1SRichard Fitzgerald
18750f530e1SRichard Fitzgerald #define value_representable_in_type(T, val) \
18850f530e1SRichard Fitzgerald (is_signed_type(T) \
18950f530e1SRichard Fitzgerald ? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \
1901b932689SRichard Fitzgerald : ((unsigned long long)(val) <= type_max(T)))
1911b932689SRichard Fitzgerald
19250f530e1SRichard Fitzgerald
19350f530e1SRichard Fitzgerald #define test_one_number(T, gen_fmt, scan_fmt, val, fn) \
19450f530e1SRichard Fitzgerald do { \
19550f530e1SRichard Fitzgerald const T expect_val = (T)(val); \
19650f530e1SRichard Fitzgerald T result = ~expect_val; /* should be overwritten */ \
19750f530e1SRichard Fitzgerald \
19850f530e1SRichard Fitzgerald snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \
19950f530e1SRichard Fitzgerald _test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \
20050f530e1SRichard Fitzgerald } while (0)
20150f530e1SRichard Fitzgerald
20250f530e1SRichard Fitzgerald #define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \
20350f530e1SRichard Fitzgerald do { \
20450f530e1SRichard Fitzgerald int i; \
20550f530e1SRichard Fitzgerald \
20650f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(numbers); i++) { \
2071b932689SRichard Fitzgerald if (value_representable_in_type(T, numbers[i])) \
2081b932689SRichard Fitzgerald test_one_number(T, gen_fmt, scan_fmt, \
2091b932689SRichard Fitzgerald numbers[i], fn); \
21050f530e1SRichard Fitzgerald \
2111b932689SRichard Fitzgerald if (value_representable_in_type(T, -numbers[i])) \
21250f530e1SRichard Fitzgerald test_one_number(T, gen_fmt, scan_fmt, \
21350f530e1SRichard Fitzgerald -numbers[i], fn); \
21450f530e1SRichard Fitzgerald } \
21550f530e1SRichard Fitzgerald } while (0)
21650f530e1SRichard Fitzgerald
numbers_simple(void)21750f530e1SRichard Fitzgerald static void __init numbers_simple(void)
21850f530e1SRichard Fitzgerald {
21950f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long long, "%llu", "llu", check_ull);
22050f530e1SRichard Fitzgerald simple_numbers_loop(long long, "%lld", "lld", check_ll);
22150f530e1SRichard Fitzgerald simple_numbers_loop(long long, "%lld", "lli", check_ll);
22250f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long long, "%llx", "llx", check_ull);
22350f530e1SRichard Fitzgerald simple_numbers_loop(long long, "%llx", "llx", check_ll);
22450f530e1SRichard Fitzgerald simple_numbers_loop(long long, "0x%llx", "lli", check_ll);
22550f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long long, "0x%llx", "llx", check_ull);
22650f530e1SRichard Fitzgerald simple_numbers_loop(long long, "0x%llx", "llx", check_ll);
22750f530e1SRichard Fitzgerald
22850f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long, "%lu", "lu", check_ulong);
22950f530e1SRichard Fitzgerald simple_numbers_loop(long, "%ld", "ld", check_long);
23050f530e1SRichard Fitzgerald simple_numbers_loop(long, "%ld", "li", check_long);
23150f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long, "%lx", "lx", check_ulong);
23250f530e1SRichard Fitzgerald simple_numbers_loop(long, "%lx", "lx", check_long);
23350f530e1SRichard Fitzgerald simple_numbers_loop(long, "0x%lx", "li", check_long);
23450f530e1SRichard Fitzgerald simple_numbers_loop(unsigned long, "0x%lx", "lx", check_ulong);
23550f530e1SRichard Fitzgerald simple_numbers_loop(long, "0x%lx", "lx", check_long);
23650f530e1SRichard Fitzgerald
23750f530e1SRichard Fitzgerald simple_numbers_loop(unsigned int, "%u", "u", check_uint);
23850f530e1SRichard Fitzgerald simple_numbers_loop(int, "%d", "d", check_int);
23950f530e1SRichard Fitzgerald simple_numbers_loop(int, "%d", "i", check_int);
24050f530e1SRichard Fitzgerald simple_numbers_loop(unsigned int, "%x", "x", check_uint);
24150f530e1SRichard Fitzgerald simple_numbers_loop(int, "%x", "x", check_int);
24250f530e1SRichard Fitzgerald simple_numbers_loop(int, "0x%x", "i", check_int);
24350f530e1SRichard Fitzgerald simple_numbers_loop(unsigned int, "0x%x", "x", check_uint);
24450f530e1SRichard Fitzgerald simple_numbers_loop(int, "0x%x", "x", check_int);
24550f530e1SRichard Fitzgerald
24650f530e1SRichard Fitzgerald simple_numbers_loop(unsigned short, "%hu", "hu", check_ushort);
24750f530e1SRichard Fitzgerald simple_numbers_loop(short, "%hd", "hd", check_short);
24850f530e1SRichard Fitzgerald simple_numbers_loop(short, "%hd", "hi", check_short);
24950f530e1SRichard Fitzgerald simple_numbers_loop(unsigned short, "%hx", "hx", check_ushort);
25050f530e1SRichard Fitzgerald simple_numbers_loop(short, "%hx", "hx", check_short);
25150f530e1SRichard Fitzgerald simple_numbers_loop(short, "0x%hx", "hi", check_short);
25250f530e1SRichard Fitzgerald simple_numbers_loop(unsigned short, "0x%hx", "hx", check_ushort);
25350f530e1SRichard Fitzgerald simple_numbers_loop(short, "0x%hx", "hx", check_short);
25450f530e1SRichard Fitzgerald
25550f530e1SRichard Fitzgerald simple_numbers_loop(unsigned char, "%hhu", "hhu", check_uchar);
25650f530e1SRichard Fitzgerald simple_numbers_loop(signed char, "%hhd", "hhd", check_char);
25750f530e1SRichard Fitzgerald simple_numbers_loop(signed char, "%hhd", "hhi", check_char);
25850f530e1SRichard Fitzgerald simple_numbers_loop(unsigned char, "%hhx", "hhx", check_uchar);
25950f530e1SRichard Fitzgerald simple_numbers_loop(signed char, "%hhx", "hhx", check_char);
26050f530e1SRichard Fitzgerald simple_numbers_loop(signed char, "0x%hhx", "hhi", check_char);
26150f530e1SRichard Fitzgerald simple_numbers_loop(unsigned char, "0x%hhx", "hhx", check_uchar);
26250f530e1SRichard Fitzgerald simple_numbers_loop(signed char, "0x%hhx", "hhx", check_char);
26350f530e1SRichard Fitzgerald }
26450f530e1SRichard Fitzgerald
26550f530e1SRichard Fitzgerald /*
26650f530e1SRichard Fitzgerald * This gives a better variety of number "lengths" in a small sample than
26750f530e1SRichard Fitzgerald * the raw prandom*() functions (Not mathematically rigorous!!).
26850f530e1SRichard Fitzgerald * Variabilty of length and value is more important than perfect randomness.
26950f530e1SRichard Fitzgerald */
next_test_random(u32 max_bits)27050f530e1SRichard Fitzgerald static u32 __init next_test_random(u32 max_bits)
27150f530e1SRichard Fitzgerald {
27250f530e1SRichard Fitzgerald u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
27350f530e1SRichard Fitzgerald
274fe8e3ee0SAndy Shevchenko return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0);
27550f530e1SRichard Fitzgerald }
27650f530e1SRichard Fitzgerald
next_test_random_ull(void)27750f530e1SRichard Fitzgerald static unsigned long long __init next_test_random_ull(void)
27850f530e1SRichard Fitzgerald {
27950f530e1SRichard Fitzgerald u32 rand1 = prandom_u32_state(&rnd_state);
28050f530e1SRichard Fitzgerald u32 n_bits = (hweight32(rand1) * 3) % 64;
28150f530e1SRichard Fitzgerald u64 val = (u64)prandom_u32_state(&rnd_state) * rand1;
28250f530e1SRichard Fitzgerald
283fe8e3ee0SAndy Shevchenko return val & GENMASK_ULL(n_bits, 0);
28450f530e1SRichard Fitzgerald }
28550f530e1SRichard Fitzgerald
28650f530e1SRichard Fitzgerald #define random_for_type(T) \
28750f530e1SRichard Fitzgerald ((T)(sizeof(T) <= sizeof(u32) \
28850f530e1SRichard Fitzgerald ? next_test_random(BITS_PER_TYPE(T)) \
28950f530e1SRichard Fitzgerald : next_test_random_ull()))
29050f530e1SRichard Fitzgerald
29150f530e1SRichard Fitzgerald /*
29250f530e1SRichard Fitzgerald * Define a pattern of negative and positive numbers to ensure we get
29350f530e1SRichard Fitzgerald * some of both within the small number of samples in a test string.
29450f530e1SRichard Fitzgerald */
29550f530e1SRichard Fitzgerald #define NEGATIVES_PATTERN 0x3246 /* 00110010 01000110 */
29650f530e1SRichard Fitzgerald
29750f530e1SRichard Fitzgerald #define fill_random_array(arr) \
29850f530e1SRichard Fitzgerald do { \
29950f530e1SRichard Fitzgerald unsigned int neg_pattern = NEGATIVES_PATTERN; \
30050f530e1SRichard Fitzgerald int i; \
30150f530e1SRichard Fitzgerald \
30250f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) { \
30350f530e1SRichard Fitzgerald (arr)[i] = random_for_type(typeof((arr)[0])); \
30450f530e1SRichard Fitzgerald if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1)) \
30550f530e1SRichard Fitzgerald (arr)[i] = -(arr)[i]; \
30650f530e1SRichard Fitzgerald } \
30750f530e1SRichard Fitzgerald } while (0)
30850f530e1SRichard Fitzgerald
30950f530e1SRichard Fitzgerald /*
31050f530e1SRichard Fitzgerald * Convenience wrapper around snprintf() to append at buf_pos in buf,
31150f530e1SRichard Fitzgerald * updating buf_pos and returning the number of characters appended.
31250f530e1SRichard Fitzgerald * On error buf_pos is not changed and return value is 0.
31350f530e1SRichard Fitzgerald */
31450f530e1SRichard Fitzgerald static int __init __printf(4, 5)
append_fmt(char * buf,int * buf_pos,int buf_len,const char * val_fmt,...)31550f530e1SRichard Fitzgerald append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
31650f530e1SRichard Fitzgerald {
31750f530e1SRichard Fitzgerald va_list ap;
31850f530e1SRichard Fitzgerald int field_len;
31950f530e1SRichard Fitzgerald
32050f530e1SRichard Fitzgerald va_start(ap, val_fmt);
32150f530e1SRichard Fitzgerald field_len = vsnprintf(buf + *buf_pos, buf_len - *buf_pos, val_fmt, ap);
32250f530e1SRichard Fitzgerald va_end(ap);
32350f530e1SRichard Fitzgerald
32450f530e1SRichard Fitzgerald if (field_len < 0)
32550f530e1SRichard Fitzgerald field_len = 0;
32650f530e1SRichard Fitzgerald
32750f530e1SRichard Fitzgerald *buf_pos += field_len;
32850f530e1SRichard Fitzgerald
32950f530e1SRichard Fitzgerald return field_len;
33050f530e1SRichard Fitzgerald }
33150f530e1SRichard Fitzgerald
33250f530e1SRichard Fitzgerald /*
33350f530e1SRichard Fitzgerald * Convenience function to append the field delimiter string
33450f530e1SRichard Fitzgerald * to both the value string and format string buffers.
33550f530e1SRichard Fitzgerald */
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)33650f530e1SRichard Fitzgerald static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
33750f530e1SRichard Fitzgerald char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
33850f530e1SRichard Fitzgerald const char *delim_str)
33950f530e1SRichard Fitzgerald {
34050f530e1SRichard Fitzgerald append_fmt(str_buf, str_buf_pos, str_buf_len, delim_str);
34150f530e1SRichard Fitzgerald append_fmt(fmt_buf, fmt_buf_pos, fmt_buf_len, delim_str);
34250f530e1SRichard Fitzgerald }
34350f530e1SRichard Fitzgerald
34450f530e1SRichard Fitzgerald #define test_array_8(fn, check_data, string, fmt, arr) \
34550f530e1SRichard Fitzgerald do { \
34650f530e1SRichard Fitzgerald BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \
34750f530e1SRichard Fitzgerald _test(fn, check_data, string, fmt, 8, \
34850f530e1SRichard Fitzgerald &(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \
34950f530e1SRichard Fitzgerald &(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \
35050f530e1SRichard Fitzgerald } while (0)
35150f530e1SRichard Fitzgerald
35250f530e1SRichard Fitzgerald #define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn) \
35350f530e1SRichard Fitzgerald do { \
35450f530e1SRichard Fitzgerald int i, pos = 0, fmt_pos = 0; \
35550f530e1SRichard Fitzgerald T expect[8], result[8]; \
35650f530e1SRichard Fitzgerald \
35750f530e1SRichard Fitzgerald fill_random_array(expect); \
35850f530e1SRichard Fitzgerald \
35950f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(expect); i++) { \
36050f530e1SRichard Fitzgerald if (i != 0) \
36150f530e1SRichard Fitzgerald append_delim(test_buffer, &pos, BUF_SIZE, \
36250f530e1SRichard Fitzgerald fmt_buffer, &fmt_pos, BUF_SIZE, \
36350f530e1SRichard Fitzgerald field_sep); \
36450f530e1SRichard Fitzgerald \
36550f530e1SRichard Fitzgerald append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]); \
36650f530e1SRichard Fitzgerald append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt); \
36750f530e1SRichard Fitzgerald } \
36850f530e1SRichard Fitzgerald \
36950f530e1SRichard Fitzgerald test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
37050f530e1SRichard Fitzgerald } while (0)
37150f530e1SRichard Fitzgerald
37250f530e1SRichard Fitzgerald #define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn) \
37350f530e1SRichard Fitzgerald do { \
37450f530e1SRichard Fitzgerald char full_fmt[16]; \
37550f530e1SRichard Fitzgerald \
37650f530e1SRichard Fitzgerald snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt); \
37750f530e1SRichard Fitzgerald numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn); \
37850f530e1SRichard Fitzgerald } while (0)
37950f530e1SRichard Fitzgerald
38050f530e1SRichard Fitzgerald #define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn) \
38150f530e1SRichard Fitzgerald do { \
38250f530e1SRichard Fitzgerald int i, val_len, pos = 0, fmt_pos = 0; \
38350f530e1SRichard Fitzgerald T expect[8], result[8]; \
38450f530e1SRichard Fitzgerald \
38550f530e1SRichard Fitzgerald fill_random_array(expect); \
38650f530e1SRichard Fitzgerald \
38750f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(expect); i++) { \
38850f530e1SRichard Fitzgerald if (i != 0) \
38950f530e1SRichard Fitzgerald append_delim(test_buffer, &pos, BUF_SIZE, \
39050f530e1SRichard Fitzgerald fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\
39150f530e1SRichard Fitzgerald \
39250f530e1SRichard Fitzgerald val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, \
39350f530e1SRichard Fitzgerald expect[i]); \
39450f530e1SRichard Fitzgerald append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, \
39550f530e1SRichard Fitzgerald "%%%u%s", val_len, scan_fmt); \
39650f530e1SRichard Fitzgerald } \
39750f530e1SRichard Fitzgerald \
39850f530e1SRichard Fitzgerald test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
39950f530e1SRichard Fitzgerald } while (0)
40050f530e1SRichard Fitzgerald
numbers_list_ll(const char * delim)401ba7b1f86SLinus Torvalds static void __init numbers_list_ll(const char *delim)
40250f530e1SRichard Fitzgerald {
40350f530e1SRichard Fitzgerald numbers_list_8(unsigned long long, "%llu", delim, "llu", check_ull);
40450f530e1SRichard Fitzgerald numbers_list_8(long long, "%lld", delim, "lld", check_ll);
40550f530e1SRichard Fitzgerald numbers_list_8(long long, "%lld", delim, "lli", check_ll);
40650f530e1SRichard Fitzgerald numbers_list_8(unsigned long long, "%llx", delim, "llx", check_ull);
40750f530e1SRichard Fitzgerald numbers_list_8(unsigned long long, "0x%llx", delim, "llx", check_ull);
40850f530e1SRichard Fitzgerald numbers_list_8(long long, "0x%llx", delim, "lli", check_ll);
409ba7b1f86SLinus Torvalds }
41050f530e1SRichard Fitzgerald
numbers_list_l(const char * delim)411ba7b1f86SLinus Torvalds static void __init numbers_list_l(const char *delim)
412ba7b1f86SLinus Torvalds {
41350f530e1SRichard Fitzgerald numbers_list_8(unsigned long, "%lu", delim, "lu", check_ulong);
41450f530e1SRichard Fitzgerald numbers_list_8(long, "%ld", delim, "ld", check_long);
41550f530e1SRichard Fitzgerald numbers_list_8(long, "%ld", delim, "li", check_long);
41650f530e1SRichard Fitzgerald numbers_list_8(unsigned long, "%lx", delim, "lx", check_ulong);
41750f530e1SRichard Fitzgerald numbers_list_8(unsigned long, "0x%lx", delim, "lx", check_ulong);
41850f530e1SRichard Fitzgerald numbers_list_8(long, "0x%lx", delim, "li", check_long);
419ba7b1f86SLinus Torvalds }
42050f530e1SRichard Fitzgerald
numbers_list_d(const char * delim)421ba7b1f86SLinus Torvalds static void __init numbers_list_d(const char *delim)
422ba7b1f86SLinus Torvalds {
42350f530e1SRichard Fitzgerald numbers_list_8(unsigned int, "%u", delim, "u", check_uint);
42450f530e1SRichard Fitzgerald numbers_list_8(int, "%d", delim, "d", check_int);
42550f530e1SRichard Fitzgerald numbers_list_8(int, "%d", delim, "i", check_int);
42650f530e1SRichard Fitzgerald numbers_list_8(unsigned int, "%x", delim, "x", check_uint);
42750f530e1SRichard Fitzgerald numbers_list_8(unsigned int, "0x%x", delim, "x", check_uint);
42850f530e1SRichard Fitzgerald numbers_list_8(int, "0x%x", delim, "i", check_int);
429ba7b1f86SLinus Torvalds }
43050f530e1SRichard Fitzgerald
numbers_list_h(const char * delim)431ba7b1f86SLinus Torvalds static void __init numbers_list_h(const char *delim)
432ba7b1f86SLinus Torvalds {
43350f530e1SRichard Fitzgerald numbers_list_8(unsigned short, "%hu", delim, "hu", check_ushort);
43450f530e1SRichard Fitzgerald numbers_list_8(short, "%hd", delim, "hd", check_short);
43550f530e1SRichard Fitzgerald numbers_list_8(short, "%hd", delim, "hi", check_short);
43650f530e1SRichard Fitzgerald numbers_list_8(unsigned short, "%hx", delim, "hx", check_ushort);
43750f530e1SRichard Fitzgerald numbers_list_8(unsigned short, "0x%hx", delim, "hx", check_ushort);
43850f530e1SRichard Fitzgerald numbers_list_8(short, "0x%hx", delim, "hi", check_short);
439ba7b1f86SLinus Torvalds }
44050f530e1SRichard Fitzgerald
numbers_list_hh(const char * delim)441ba7b1f86SLinus Torvalds static void __init numbers_list_hh(const char *delim)
442ba7b1f86SLinus Torvalds {
44350f530e1SRichard Fitzgerald numbers_list_8(unsigned char, "%hhu", delim, "hhu", check_uchar);
44450f530e1SRichard Fitzgerald numbers_list_8(signed char, "%hhd", delim, "hhd", check_char);
44550f530e1SRichard Fitzgerald numbers_list_8(signed char, "%hhd", delim, "hhi", check_char);
44650f530e1SRichard Fitzgerald numbers_list_8(unsigned char, "%hhx", delim, "hhx", check_uchar);
44750f530e1SRichard Fitzgerald numbers_list_8(unsigned char, "0x%hhx", delim, "hhx", check_uchar);
44850f530e1SRichard Fitzgerald numbers_list_8(signed char, "0x%hhx", delim, "hhi", check_char);
44950f530e1SRichard Fitzgerald }
45050f530e1SRichard Fitzgerald
numbers_list(const char * delim)451ba7b1f86SLinus Torvalds static void __init numbers_list(const char *delim)
452ba7b1f86SLinus Torvalds {
453ba7b1f86SLinus Torvalds numbers_list_ll(delim);
454ba7b1f86SLinus Torvalds numbers_list_l(delim);
455ba7b1f86SLinus Torvalds numbers_list_d(delim);
456ba7b1f86SLinus Torvalds numbers_list_h(delim);
457ba7b1f86SLinus Torvalds numbers_list_hh(delim);
458ba7b1f86SLinus Torvalds }
459ba7b1f86SLinus Torvalds
numbers_list_field_width_ll(const char * delim)460ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_ll(const char *delim)
46150f530e1SRichard Fitzgerald {
46250f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long long, "%llu", delim, 20, "llu", check_ull);
46350f530e1SRichard Fitzgerald numbers_list_fix_width(long long, "%lld", delim, 20, "lld", check_ll);
46450f530e1SRichard Fitzgerald numbers_list_fix_width(long long, "%lld", delim, 20, "lli", check_ll);
46550f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long long, "%llx", delim, 16, "llx", check_ull);
46650f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long long, "0x%llx", delim, 18, "llx", check_ull);
46750f530e1SRichard Fitzgerald numbers_list_fix_width(long long, "0x%llx", delim, 18, "lli", check_ll);
468ba7b1f86SLinus Torvalds }
46950f530e1SRichard Fitzgerald
numbers_list_field_width_l(const char * delim)470ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_l(const char *delim)
471ba7b1f86SLinus Torvalds {
47250f530e1SRichard Fitzgerald #if BITS_PER_LONG == 64
47350f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "%lu", delim, 20, "lu", check_ulong);
47450f530e1SRichard Fitzgerald numbers_list_fix_width(long, "%ld", delim, 20, "ld", check_long);
47550f530e1SRichard Fitzgerald numbers_list_fix_width(long, "%ld", delim, 20, "li", check_long);
47650f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "%lx", delim, 16, "lx", check_ulong);
47750f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "0x%lx", delim, 18, "lx", check_ulong);
47850f530e1SRichard Fitzgerald numbers_list_fix_width(long, "0x%lx", delim, 18, "li", check_long);
47950f530e1SRichard Fitzgerald #else
48050f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "%lu", delim, 10, "lu", check_ulong);
48150f530e1SRichard Fitzgerald numbers_list_fix_width(long, "%ld", delim, 11, "ld", check_long);
48250f530e1SRichard Fitzgerald numbers_list_fix_width(long, "%ld", delim, 11, "li", check_long);
48350f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "%lx", delim, 8, "lx", check_ulong);
48450f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned long, "0x%lx", delim, 10, "lx", check_ulong);
48550f530e1SRichard Fitzgerald numbers_list_fix_width(long, "0x%lx", delim, 10, "li", check_long);
48650f530e1SRichard Fitzgerald #endif
487ba7b1f86SLinus Torvalds }
48850f530e1SRichard Fitzgerald
numbers_list_field_width_d(const char * delim)489ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_d(const char *delim)
490ba7b1f86SLinus Torvalds {
49150f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned int, "%u", delim, 10, "u", check_uint);
49250f530e1SRichard Fitzgerald numbers_list_fix_width(int, "%d", delim, 11, "d", check_int);
49350f530e1SRichard Fitzgerald numbers_list_fix_width(int, "%d", delim, 11, "i", check_int);
49450f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned int, "%x", delim, 8, "x", check_uint);
49550f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned int, "0x%x", delim, 10, "x", check_uint);
49650f530e1SRichard Fitzgerald numbers_list_fix_width(int, "0x%x", delim, 10, "i", check_int);
497ba7b1f86SLinus Torvalds }
49850f530e1SRichard Fitzgerald
numbers_list_field_width_h(const char * delim)499ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_h(const char *delim)
500ba7b1f86SLinus Torvalds {
50150f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned short, "%hu", delim, 5, "hu", check_ushort);
50250f530e1SRichard Fitzgerald numbers_list_fix_width(short, "%hd", delim, 6, "hd", check_short);
50350f530e1SRichard Fitzgerald numbers_list_fix_width(short, "%hd", delim, 6, "hi", check_short);
50450f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned short, "%hx", delim, 4, "hx", check_ushort);
50550f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned short, "0x%hx", delim, 6, "hx", check_ushort);
50650f530e1SRichard Fitzgerald numbers_list_fix_width(short, "0x%hx", delim, 6, "hi", check_short);
507ba7b1f86SLinus Torvalds }
50850f530e1SRichard Fitzgerald
numbers_list_field_width_hh(const char * delim)509ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_hh(const char *delim)
510ba7b1f86SLinus Torvalds {
51150f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned char, "%hhu", delim, 3, "hhu", check_uchar);
51250f530e1SRichard Fitzgerald numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhd", check_char);
51350f530e1SRichard Fitzgerald numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhi", check_char);
51450f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned char, "%hhx", delim, 2, "hhx", check_uchar);
51550f530e1SRichard Fitzgerald numbers_list_fix_width(unsigned char, "0x%hhx", delim, 4, "hhx", check_uchar);
51650f530e1SRichard Fitzgerald numbers_list_fix_width(signed char, "0x%hhx", delim, 4, "hhi", check_char);
51750f530e1SRichard Fitzgerald }
51850f530e1SRichard Fitzgerald
51950f530e1SRichard Fitzgerald /*
52050f530e1SRichard Fitzgerald * List of numbers separated by delim. Each field width specifier is the
521ba7b1f86SLinus Torvalds * maximum possible digits for the given type and base.
52250f530e1SRichard Fitzgerald */
numbers_list_field_width_typemax(const char * delim)523ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_typemax(const char *delim)
524ba7b1f86SLinus Torvalds {
525ba7b1f86SLinus Torvalds numbers_list_field_width_ll(delim);
526ba7b1f86SLinus Torvalds numbers_list_field_width_l(delim);
527ba7b1f86SLinus Torvalds numbers_list_field_width_d(delim);
528ba7b1f86SLinus Torvalds numbers_list_field_width_h(delim);
529ba7b1f86SLinus Torvalds numbers_list_field_width_hh(delim);
530ba7b1f86SLinus Torvalds }
531ba7b1f86SLinus Torvalds
numbers_list_field_width_val_ll(const char * delim)532ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_ll(const char *delim)
53350f530e1SRichard Fitzgerald {
53450f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long long, "%llu", delim, "llu", check_ull);
53550f530e1SRichard Fitzgerald numbers_list_val_width(long long, "%lld", delim, "lld", check_ll);
53650f530e1SRichard Fitzgerald numbers_list_val_width(long long, "%lld", delim, "lli", check_ll);
53750f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long long, "%llx", delim, "llx", check_ull);
53850f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long long, "0x%llx", delim, "llx", check_ull);
53950f530e1SRichard Fitzgerald numbers_list_val_width(long long, "0x%llx", delim, "lli", check_ll);
540ba7b1f86SLinus Torvalds }
54150f530e1SRichard Fitzgerald
numbers_list_field_width_val_l(const char * delim)542ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_l(const char *delim)
543ba7b1f86SLinus Torvalds {
54450f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long, "%lu", delim, "lu", check_ulong);
54550f530e1SRichard Fitzgerald numbers_list_val_width(long, "%ld", delim, "ld", check_long);
54650f530e1SRichard Fitzgerald numbers_list_val_width(long, "%ld", delim, "li", check_long);
54750f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long, "%lx", delim, "lx", check_ulong);
54850f530e1SRichard Fitzgerald numbers_list_val_width(unsigned long, "0x%lx", delim, "lx", check_ulong);
54950f530e1SRichard Fitzgerald numbers_list_val_width(long, "0x%lx", delim, "li", check_long);
550ba7b1f86SLinus Torvalds }
55150f530e1SRichard Fitzgerald
numbers_list_field_width_val_d(const char * delim)552ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_d(const char *delim)
553ba7b1f86SLinus Torvalds {
55450f530e1SRichard Fitzgerald numbers_list_val_width(unsigned int, "%u", delim, "u", check_uint);
55550f530e1SRichard Fitzgerald numbers_list_val_width(int, "%d", delim, "d", check_int);
55650f530e1SRichard Fitzgerald numbers_list_val_width(int, "%d", delim, "i", check_int);
55750f530e1SRichard Fitzgerald numbers_list_val_width(unsigned int, "%x", delim, "x", check_uint);
55850f530e1SRichard Fitzgerald numbers_list_val_width(unsigned int, "0x%x", delim, "x", check_uint);
55950f530e1SRichard Fitzgerald numbers_list_val_width(int, "0x%x", delim, "i", check_int);
560ba7b1f86SLinus Torvalds }
56150f530e1SRichard Fitzgerald
numbers_list_field_width_val_h(const char * delim)562ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_h(const char *delim)
563ba7b1f86SLinus Torvalds {
56450f530e1SRichard Fitzgerald numbers_list_val_width(unsigned short, "%hu", delim, "hu", check_ushort);
56550f530e1SRichard Fitzgerald numbers_list_val_width(short, "%hd", delim, "hd", check_short);
56650f530e1SRichard Fitzgerald numbers_list_val_width(short, "%hd", delim, "hi", check_short);
56750f530e1SRichard Fitzgerald numbers_list_val_width(unsigned short, "%hx", delim, "hx", check_ushort);
56850f530e1SRichard Fitzgerald numbers_list_val_width(unsigned short, "0x%hx", delim, "hx", check_ushort);
56950f530e1SRichard Fitzgerald numbers_list_val_width(short, "0x%hx", delim, "hi", check_short);
570ba7b1f86SLinus Torvalds }
57150f530e1SRichard Fitzgerald
numbers_list_field_width_val_hh(const char * delim)572ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_hh(const char *delim)
573ba7b1f86SLinus Torvalds {
57450f530e1SRichard Fitzgerald numbers_list_val_width(unsigned char, "%hhu", delim, "hhu", check_uchar);
57550f530e1SRichard Fitzgerald numbers_list_val_width(signed char, "%hhd", delim, "hhd", check_char);
57650f530e1SRichard Fitzgerald numbers_list_val_width(signed char, "%hhd", delim, "hhi", check_char);
57750f530e1SRichard Fitzgerald numbers_list_val_width(unsigned char, "%hhx", delim, "hhx", check_uchar);
57850f530e1SRichard Fitzgerald numbers_list_val_width(unsigned char, "0x%hhx", delim, "hhx", check_uchar);
57950f530e1SRichard Fitzgerald numbers_list_val_width(signed char, "0x%hhx", delim, "hhi", check_char);
58050f530e1SRichard Fitzgerald }
58150f530e1SRichard Fitzgerald
58250f530e1SRichard Fitzgerald /*
583ba7b1f86SLinus Torvalds * List of numbers separated by delim. Each field width specifier is the
584ba7b1f86SLinus Torvalds * exact length of the corresponding value digits in the string being scanned.
585ba7b1f86SLinus Torvalds */
numbers_list_field_width_val_width(const char * delim)586ba7b1f86SLinus Torvalds static void __init numbers_list_field_width_val_width(const char *delim)
587ba7b1f86SLinus Torvalds {
588ba7b1f86SLinus Torvalds numbers_list_field_width_val_ll(delim);
589ba7b1f86SLinus Torvalds numbers_list_field_width_val_l(delim);
590ba7b1f86SLinus Torvalds numbers_list_field_width_val_d(delim);
591ba7b1f86SLinus Torvalds numbers_list_field_width_val_h(delim);
592ba7b1f86SLinus Torvalds numbers_list_field_width_val_hh(delim);
593ba7b1f86SLinus Torvalds }
594ba7b1f86SLinus Torvalds
595ba7b1f86SLinus Torvalds /*
59650f530e1SRichard Fitzgerald * Slice a continuous string of digits without field delimiters, containing
59750f530e1SRichard Fitzgerald * numbers of varying length, using the field width to extract each group
59850f530e1SRichard Fitzgerald * of digits. For example the hex values c0,3,bf01,303 would have a
59950f530e1SRichard Fitzgerald * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
60050f530e1SRichard Fitzgerald */
numbers_slice(void)60150f530e1SRichard Fitzgerald static void __init numbers_slice(void)
60250f530e1SRichard Fitzgerald {
60350f530e1SRichard Fitzgerald numbers_list_field_width_val_width("");
60450f530e1SRichard Fitzgerald }
60550f530e1SRichard Fitzgerald
60650f530e1SRichard Fitzgerald #define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \
60750f530e1SRichard Fitzgerald do { \
60850f530e1SRichard Fitzgerald const T expect[2] = { expect0, expect1 }; \
60992382d74SNathan Chancellor T result[2] = { (T)~expect[0], (T)~expect[1] }; \
61050f530e1SRichard Fitzgerald \
61150f530e1SRichard Fitzgerald _test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \
61250f530e1SRichard Fitzgerald } while (0)
61350f530e1SRichard Fitzgerald
61450f530e1SRichard Fitzgerald /*
61550f530e1SRichard Fitzgerald * Number prefix is >= field width.
61650f530e1SRichard Fitzgerald * Expected behaviour is derived from testing userland sscanf.
61750f530e1SRichard Fitzgerald */
numbers_prefix_overflow(void)61850f530e1SRichard Fitzgerald static void __init numbers_prefix_overflow(void)
61950f530e1SRichard Fitzgerald {
62050f530e1SRichard Fitzgerald /*
62150f530e1SRichard Fitzgerald * Negative decimal with a field of width 1, should quit scanning
62250f530e1SRichard Fitzgerald * and return 0.
62350f530e1SRichard Fitzgerald */
62450f530e1SRichard Fitzgerald test_number_prefix(long long, "-1 1", "%1lld %lld", 0, 0, 0, check_ll);
62550f530e1SRichard Fitzgerald test_number_prefix(long, "-1 1", "%1ld %ld", 0, 0, 0, check_long);
62650f530e1SRichard Fitzgerald test_number_prefix(int, "-1 1", "%1d %d", 0, 0, 0, check_int);
62750f530e1SRichard Fitzgerald test_number_prefix(short, "-1 1", "%1hd %hd", 0, 0, 0, check_short);
62850f530e1SRichard Fitzgerald test_number_prefix(signed char, "-1 1", "%1hhd %hhd", 0, 0, 0, check_char);
62950f530e1SRichard Fitzgerald
63050f530e1SRichard Fitzgerald test_number_prefix(long long, "-1 1", "%1lli %lli", 0, 0, 0, check_ll);
63150f530e1SRichard Fitzgerald test_number_prefix(long, "-1 1", "%1li %li", 0, 0, 0, check_long);
63250f530e1SRichard Fitzgerald test_number_prefix(int, "-1 1", "%1i %i", 0, 0, 0, check_int);
63350f530e1SRichard Fitzgerald test_number_prefix(short, "-1 1", "%1hi %hi", 0, 0, 0, check_short);
63450f530e1SRichard Fitzgerald test_number_prefix(signed char, "-1 1", "%1hhi %hhi", 0, 0, 0, check_char);
63550f530e1SRichard Fitzgerald
63650f530e1SRichard Fitzgerald /*
63750f530e1SRichard Fitzgerald * 0x prefix in a field of width 1: 0 is a valid digit so should
63850f530e1SRichard Fitzgerald * convert. Next field scan starts at the 'x' which isn't a digit so
63950f530e1SRichard Fitzgerald * scan quits with one field converted.
64050f530e1SRichard Fitzgerald */
64150f530e1SRichard Fitzgerald test_number_prefix(unsigned long long, "0xA7", "%1llx%llx", 0, 0, 1, check_ull);
64250f530e1SRichard Fitzgerald test_number_prefix(unsigned long, "0xA7", "%1lx%lx", 0, 0, 1, check_ulong);
64350f530e1SRichard Fitzgerald test_number_prefix(unsigned int, "0xA7", "%1x%x", 0, 0, 1, check_uint);
64450f530e1SRichard Fitzgerald test_number_prefix(unsigned short, "0xA7", "%1hx%hx", 0, 0, 1, check_ushort);
64550f530e1SRichard Fitzgerald test_number_prefix(unsigned char, "0xA7", "%1hhx%hhx", 0, 0, 1, check_uchar);
64650f530e1SRichard Fitzgerald test_number_prefix(long long, "0xA7", "%1lli%llx", 0, 0, 1, check_ll);
64750f530e1SRichard Fitzgerald test_number_prefix(long, "0xA7", "%1li%lx", 0, 0, 1, check_long);
64850f530e1SRichard Fitzgerald test_number_prefix(int, "0xA7", "%1i%x", 0, 0, 1, check_int);
64950f530e1SRichard Fitzgerald test_number_prefix(short, "0xA7", "%1hi%hx", 0, 0, 1, check_short);
65050f530e1SRichard Fitzgerald test_number_prefix(char, "0xA7", "%1hhi%hhx", 0, 0, 1, check_char);
65150f530e1SRichard Fitzgerald
65250f530e1SRichard Fitzgerald /*
65350f530e1SRichard Fitzgerald * 0x prefix in a field of width 2 using %x conversion: first field
65450f530e1SRichard Fitzgerald * converts to 0. Next field scan starts at the character after "0x".
65550f530e1SRichard Fitzgerald * Both fields will convert.
65650f530e1SRichard Fitzgerald */
65750f530e1SRichard Fitzgerald test_number_prefix(unsigned long long, "0xA7", "%2llx%llx", 0, 0xa7, 2, check_ull);
65850f530e1SRichard Fitzgerald test_number_prefix(unsigned long, "0xA7", "%2lx%lx", 0, 0xa7, 2, check_ulong);
65950f530e1SRichard Fitzgerald test_number_prefix(unsigned int, "0xA7", "%2x%x", 0, 0xa7, 2, check_uint);
66050f530e1SRichard Fitzgerald test_number_prefix(unsigned short, "0xA7", "%2hx%hx", 0, 0xa7, 2, check_ushort);
66150f530e1SRichard Fitzgerald test_number_prefix(unsigned char, "0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar);
66250f530e1SRichard Fitzgerald
66350f530e1SRichard Fitzgerald /*
66450f530e1SRichard Fitzgerald * 0x prefix in a field of width 2 using %i conversion: first field
66550f530e1SRichard Fitzgerald * converts to 0. Next field scan starts at the character after "0x",
66653b0fe36SZhen Lei * which will convert if can be interpreted as decimal but will fail
66750f530e1SRichard Fitzgerald * if it contains any hex digits (since no 0x prefix).
66850f530e1SRichard Fitzgerald */
66950f530e1SRichard Fitzgerald test_number_prefix(long long, "0x67", "%2lli%lli", 0, 67, 2, check_ll);
67050f530e1SRichard Fitzgerald test_number_prefix(long, "0x67", "%2li%li", 0, 67, 2, check_long);
67150f530e1SRichard Fitzgerald test_number_prefix(int, "0x67", "%2i%i", 0, 67, 2, check_int);
67250f530e1SRichard Fitzgerald test_number_prefix(short, "0x67", "%2hi%hi", 0, 67, 2, check_short);
67350f530e1SRichard Fitzgerald test_number_prefix(char, "0x67", "%2hhi%hhi", 0, 67, 2, check_char);
67450f530e1SRichard Fitzgerald
67550f530e1SRichard Fitzgerald test_number_prefix(long long, "0xA7", "%2lli%lli", 0, 0, 1, check_ll);
67650f530e1SRichard Fitzgerald test_number_prefix(long, "0xA7", "%2li%li", 0, 0, 1, check_long);
67750f530e1SRichard Fitzgerald test_number_prefix(int, "0xA7", "%2i%i", 0, 0, 1, check_int);
67850f530e1SRichard Fitzgerald test_number_prefix(short, "0xA7", "%2hi%hi", 0, 0, 1, check_short);
67950f530e1SRichard Fitzgerald test_number_prefix(char, "0xA7", "%2hhi%hhi", 0, 0, 1, check_char);
68050f530e1SRichard Fitzgerald }
68150f530e1SRichard Fitzgerald
68250f530e1SRichard Fitzgerald #define _test_simple_strtoxx(T, fn, gen_fmt, expect, base) \
68350f530e1SRichard Fitzgerald do { \
68450f530e1SRichard Fitzgerald T got; \
68550f530e1SRichard Fitzgerald char *endp; \
68650f530e1SRichard Fitzgerald int len; \
68750f530e1SRichard Fitzgerald bool fail = false; \
68850f530e1SRichard Fitzgerald \
68950f530e1SRichard Fitzgerald total_tests++; \
69050f530e1SRichard Fitzgerald len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \
69150f530e1SRichard Fitzgerald got = (fn)(test_buffer, &endp, base); \
69250f530e1SRichard Fitzgerald pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got); \
69350f530e1SRichard Fitzgerald if (got != (expect)) { \
69450f530e1SRichard Fitzgerald fail = true; \
69550f530e1SRichard Fitzgerald pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
69650f530e1SRichard Fitzgerald test_buffer, base, got, expect); \
69750f530e1SRichard Fitzgerald } else if (endp != test_buffer + len) { \
69850f530e1SRichard Fitzgerald fail = true; \
69950f530e1SRichard Fitzgerald pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
70050f530e1SRichard Fitzgerald test_buffer, base, test_buffer, \
70150f530e1SRichard Fitzgerald test_buffer + len, endp); \
70250f530e1SRichard Fitzgerald } \
70350f530e1SRichard Fitzgerald \
70450f530e1SRichard Fitzgerald if (fail) \
70550f530e1SRichard Fitzgerald failed_tests++; \
70650f530e1SRichard Fitzgerald } while (0)
70750f530e1SRichard Fitzgerald
70850f530e1SRichard Fitzgerald #define test_simple_strtoxx(T, fn, gen_fmt, base) \
70950f530e1SRichard Fitzgerald do { \
71050f530e1SRichard Fitzgerald int i; \
71150f530e1SRichard Fitzgerald \
71250f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(numbers); i++) { \
71350f530e1SRichard Fitzgerald _test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base); \
71450f530e1SRichard Fitzgerald \
71550f530e1SRichard Fitzgerald if (is_signed_type(T)) \
71650f530e1SRichard Fitzgerald _test_simple_strtoxx(T, fn, gen_fmt, \
71750f530e1SRichard Fitzgerald -(T)numbers[i], base); \
71850f530e1SRichard Fitzgerald } \
71950f530e1SRichard Fitzgerald } while (0)
72050f530e1SRichard Fitzgerald
test_simple_strtoull(void)72150f530e1SRichard Fitzgerald static void __init test_simple_strtoull(void)
72250f530e1SRichard Fitzgerald {
72350f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 10);
72450f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 0);
72550f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long long, simple_strtoull, "%llx", 16);
72650f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 16);
72750f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
72850f530e1SRichard Fitzgerald }
72950f530e1SRichard Fitzgerald
test_simple_strtoll(void)73050f530e1SRichard Fitzgerald static void __init test_simple_strtoll(void)
73150f530e1SRichard Fitzgerald {
73250f530e1SRichard Fitzgerald test_simple_strtoxx(long long, simple_strtoll, "%lld", 10);
73350f530e1SRichard Fitzgerald test_simple_strtoxx(long long, simple_strtoll, "%lld", 0);
73450f530e1SRichard Fitzgerald test_simple_strtoxx(long long, simple_strtoll, "%llx", 16);
73550f530e1SRichard Fitzgerald test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 16);
73650f530e1SRichard Fitzgerald test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
73750f530e1SRichard Fitzgerald }
73850f530e1SRichard Fitzgerald
test_simple_strtoul(void)73950f530e1SRichard Fitzgerald static void __init test_simple_strtoul(void)
74050f530e1SRichard Fitzgerald {
74150f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 10);
74250f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 0);
74350f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long, simple_strtoul, "%lx", 16);
74450f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 16);
74550f530e1SRichard Fitzgerald test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
74650f530e1SRichard Fitzgerald }
74750f530e1SRichard Fitzgerald
test_simple_strtol(void)74850f530e1SRichard Fitzgerald static void __init test_simple_strtol(void)
74950f530e1SRichard Fitzgerald {
75050f530e1SRichard Fitzgerald test_simple_strtoxx(long, simple_strtol, "%ld", 10);
75150f530e1SRichard Fitzgerald test_simple_strtoxx(long, simple_strtol, "%ld", 0);
75250f530e1SRichard Fitzgerald test_simple_strtoxx(long, simple_strtol, "%lx", 16);
75350f530e1SRichard Fitzgerald test_simple_strtoxx(long, simple_strtol, "0x%lx", 16);
75450f530e1SRichard Fitzgerald test_simple_strtoxx(long, simple_strtol, "0x%lx", 0);
75550f530e1SRichard Fitzgerald }
75650f530e1SRichard Fitzgerald
75750f530e1SRichard Fitzgerald /* Selection of common delimiters/separators between numbers in a string. */
75850f530e1SRichard Fitzgerald static const char * const number_delimiters[] __initconst = {
75950f530e1SRichard Fitzgerald " ", ":", ",", "-", "/",
76050f530e1SRichard Fitzgerald };
76150f530e1SRichard Fitzgerald
test_numbers(void)76250f530e1SRichard Fitzgerald static void __init test_numbers(void)
76350f530e1SRichard Fitzgerald {
76450f530e1SRichard Fitzgerald int i;
76550f530e1SRichard Fitzgerald
76650f530e1SRichard Fitzgerald /* String containing only one number. */
76750f530e1SRichard Fitzgerald numbers_simple();
76850f530e1SRichard Fitzgerald
76950f530e1SRichard Fitzgerald /* String with multiple numbers separated by delimiter. */
77050f530e1SRichard Fitzgerald for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) {
77150f530e1SRichard Fitzgerald numbers_list(number_delimiters[i]);
77250f530e1SRichard Fitzgerald
77350f530e1SRichard Fitzgerald /* Field width may be longer than actual field digits. */
77450f530e1SRichard Fitzgerald numbers_list_field_width_typemax(number_delimiters[i]);
77550f530e1SRichard Fitzgerald
77650f530e1SRichard Fitzgerald /* Each field width exactly length of actual field digits. */
77750f530e1SRichard Fitzgerald numbers_list_field_width_val_width(number_delimiters[i]);
77850f530e1SRichard Fitzgerald }
77950f530e1SRichard Fitzgerald
78050f530e1SRichard Fitzgerald /* Slice continuous sequence of digits using field widths. */
78150f530e1SRichard Fitzgerald numbers_slice();
78250f530e1SRichard Fitzgerald
78350f530e1SRichard Fitzgerald numbers_prefix_overflow();
78450f530e1SRichard Fitzgerald }
78550f530e1SRichard Fitzgerald
selftest(void)78650f530e1SRichard Fitzgerald static void __init selftest(void)
78750f530e1SRichard Fitzgerald {
78850f530e1SRichard Fitzgerald test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
78950f530e1SRichard Fitzgerald if (!test_buffer)
79050f530e1SRichard Fitzgerald return;
79150f530e1SRichard Fitzgerald
79250f530e1SRichard Fitzgerald fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
79350f530e1SRichard Fitzgerald if (!fmt_buffer) {
79450f530e1SRichard Fitzgerald kfree(test_buffer);
79550f530e1SRichard Fitzgerald return;
79650f530e1SRichard Fitzgerald }
79750f530e1SRichard Fitzgerald
79850f530e1SRichard Fitzgerald prandom_seed_state(&rnd_state, 3141592653589793238ULL);
79950f530e1SRichard Fitzgerald
80050f530e1SRichard Fitzgerald test_numbers();
80150f530e1SRichard Fitzgerald
80250f530e1SRichard Fitzgerald test_simple_strtoull();
80350f530e1SRichard Fitzgerald test_simple_strtoll();
80450f530e1SRichard Fitzgerald test_simple_strtoul();
80550f530e1SRichard Fitzgerald test_simple_strtol();
80650f530e1SRichard Fitzgerald
80750f530e1SRichard Fitzgerald kfree(fmt_buffer);
80850f530e1SRichard Fitzgerald kfree(test_buffer);
80950f530e1SRichard Fitzgerald }
81050f530e1SRichard Fitzgerald
81150f530e1SRichard Fitzgerald KSTM_MODULE_LOADERS(test_scanf);
81250f530e1SRichard Fitzgerald MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
813*a930fde9SJeff Johnson MODULE_DESCRIPTION("Test cases for sscanf facility");
81450f530e1SRichard Fitzgerald MODULE_LICENSE("GPL v2");
815