162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Test cases for sscanf facility. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/overflow.h> 1362306a36Sopenharmony_ci#include <linux/printk.h> 1462306a36Sopenharmony_ci#include <linux/random.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "../tools/testing/selftests/kselftest_module.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define BUF_SIZE 1024 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciKSTM_MODULE_GLOBALS(); 2362306a36Sopenharmony_cistatic char *test_buffer __initdata; 2462306a36Sopenharmony_cistatic char *fmt_buffer __initdata; 2562306a36Sopenharmony_cistatic struct rnd_state rnd_state __initdata; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_citypedef int (*check_fn)(const void *check_data, const char *string, 2862306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void __scanf(4, 6) __init 3162306a36Sopenharmony_ci_test(check_fn fn, const void *check_data, const char *string, const char *fmt, 3262306a36Sopenharmony_ci int n_args, ...) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci va_list ap, ap_copy; 3562306a36Sopenharmony_ci int ret; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci total_tests++; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci va_start(ap, n_args); 4062306a36Sopenharmony_ci va_copy(ap_copy, ap); 4162306a36Sopenharmony_ci ret = vsscanf(string, fmt, ap_copy); 4262306a36Sopenharmony_ci va_end(ap_copy); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (ret != n_args) { 4562306a36Sopenharmony_ci pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n", 4662306a36Sopenharmony_ci string, fmt, ret, n_args); 4762306a36Sopenharmony_ci goto fail; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ret = (*fn)(check_data, string, fmt, n_args, ap); 5162306a36Sopenharmony_ci if (ret) 5262306a36Sopenharmony_ci goto fail; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci va_end(ap); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cifail: 5962306a36Sopenharmony_ci failed_tests++; 6062306a36Sopenharmony_ci va_end(ap); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap) \ 6462306a36Sopenharmony_cido { \ 6562306a36Sopenharmony_ci pr_debug("\"%s\", \"%s\" ->\n", str, fmt); \ 6662306a36Sopenharmony_ci for (; n_args > 0; n_args--, expect++) { \ 6762306a36Sopenharmony_ci typeof(*expect) got = *va_arg(ap, typeof(expect)); \ 6862306a36Sopenharmony_ci pr_debug("\t" arg_fmt "\n", got); \ 6962306a36Sopenharmony_ci if (got != *expect) { \ 7062306a36Sopenharmony_ci pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \ 7162306a36Sopenharmony_ci str, fmt, *expect, got); \ 7262306a36Sopenharmony_ci return 1; \ 7362306a36Sopenharmony_ci } \ 7462306a36Sopenharmony_ci } \ 7562306a36Sopenharmony_ci return 0; \ 7662306a36Sopenharmony_ci} while (0) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int __init check_ull(const void *check_data, const char *string, 7962306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci const unsigned long long *pval = check_data; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci _check_numbers_template("%llu", pval, string, fmt, n_args, ap); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int __init check_ll(const void *check_data, const char *string, 8762306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci const long long *pval = check_data; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci _check_numbers_template("%lld", pval, string, fmt, n_args, ap); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int __init check_ulong(const void *check_data, const char *string, 9562306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci const unsigned long *pval = check_data; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci _check_numbers_template("%lu", pval, string, fmt, n_args, ap); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int __init check_long(const void *check_data, const char *string, 10362306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci const long *pval = check_data; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci _check_numbers_template("%ld", pval, string, fmt, n_args, ap); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int __init check_uint(const void *check_data, const char *string, 11162306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci const unsigned int *pval = check_data; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci _check_numbers_template("%u", pval, string, fmt, n_args, ap); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int __init check_int(const void *check_data, const char *string, 11962306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci const int *pval = check_data; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci _check_numbers_template("%d", pval, string, fmt, n_args, ap); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int __init check_ushort(const void *check_data, const char *string, 12762306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci const unsigned short *pval = check_data; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci _check_numbers_template("%hu", pval, string, fmt, n_args, ap); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int __init check_short(const void *check_data, const char *string, 13562306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci const short *pval = check_data; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci _check_numbers_template("%hd", pval, string, fmt, n_args, ap); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int __init check_uchar(const void *check_data, const char *string, 14362306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci const unsigned char *pval = check_data; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci _check_numbers_template("%hhu", pval, string, fmt, n_args, ap); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int __init check_char(const void *check_data, const char *string, 15162306a36Sopenharmony_ci const char *fmt, int n_args, va_list ap) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci const signed char *pval = check_data; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci _check_numbers_template("%hhd", pval, string, fmt, n_args, ap); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* Selection of interesting numbers to test, copied from test-kstrtox.c */ 15962306a36Sopenharmony_cistatic const unsigned long long numbers[] __initconst = { 16062306a36Sopenharmony_ci 0x0ULL, 16162306a36Sopenharmony_ci 0x1ULL, 16262306a36Sopenharmony_ci 0x7fULL, 16362306a36Sopenharmony_ci 0x80ULL, 16462306a36Sopenharmony_ci 0x81ULL, 16562306a36Sopenharmony_ci 0xffULL, 16662306a36Sopenharmony_ci 0x100ULL, 16762306a36Sopenharmony_ci 0x101ULL, 16862306a36Sopenharmony_ci 0x7fffULL, 16962306a36Sopenharmony_ci 0x8000ULL, 17062306a36Sopenharmony_ci 0x8001ULL, 17162306a36Sopenharmony_ci 0xffffULL, 17262306a36Sopenharmony_ci 0x10000ULL, 17362306a36Sopenharmony_ci 0x10001ULL, 17462306a36Sopenharmony_ci 0x7fffffffULL, 17562306a36Sopenharmony_ci 0x80000000ULL, 17662306a36Sopenharmony_ci 0x80000001ULL, 17762306a36Sopenharmony_ci 0xffffffffULL, 17862306a36Sopenharmony_ci 0x100000000ULL, 17962306a36Sopenharmony_ci 0x100000001ULL, 18062306a36Sopenharmony_ci 0x7fffffffffffffffULL, 18162306a36Sopenharmony_ci 0x8000000000000000ULL, 18262306a36Sopenharmony_ci 0x8000000000000001ULL, 18362306a36Sopenharmony_ci 0xfffffffffffffffeULL, 18462306a36Sopenharmony_ci 0xffffffffffffffffULL, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci#define value_representable_in_type(T, val) \ 18862306a36Sopenharmony_ci(is_signed_type(T) \ 18962306a36Sopenharmony_ci ? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \ 19062306a36Sopenharmony_ci : ((unsigned long long)(val) <= type_max(T))) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define test_one_number(T, gen_fmt, scan_fmt, val, fn) \ 19462306a36Sopenharmony_cido { \ 19562306a36Sopenharmony_ci const T expect_val = (T)(val); \ 19662306a36Sopenharmony_ci T result = ~expect_val; /* should be overwritten */ \ 19762306a36Sopenharmony_ci \ 19862306a36Sopenharmony_ci snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \ 19962306a36Sopenharmony_ci _test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \ 20062306a36Sopenharmony_ci} while (0) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \ 20362306a36Sopenharmony_cido { \ 20462306a36Sopenharmony_ci int i; \ 20562306a36Sopenharmony_ci \ 20662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(numbers); i++) { \ 20762306a36Sopenharmony_ci if (value_representable_in_type(T, numbers[i])) \ 20862306a36Sopenharmony_ci test_one_number(T, gen_fmt, scan_fmt, \ 20962306a36Sopenharmony_ci numbers[i], fn); \ 21062306a36Sopenharmony_ci \ 21162306a36Sopenharmony_ci if (value_representable_in_type(T, -numbers[i])) \ 21262306a36Sopenharmony_ci test_one_number(T, gen_fmt, scan_fmt, \ 21362306a36Sopenharmony_ci -numbers[i], fn); \ 21462306a36Sopenharmony_ci } \ 21562306a36Sopenharmony_ci} while (0) 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void __init numbers_simple(void) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci simple_numbers_loop(unsigned long long, "%llu", "llu", check_ull); 22062306a36Sopenharmony_ci simple_numbers_loop(long long, "%lld", "lld", check_ll); 22162306a36Sopenharmony_ci simple_numbers_loop(long long, "%lld", "lli", check_ll); 22262306a36Sopenharmony_ci simple_numbers_loop(unsigned long long, "%llx", "llx", check_ull); 22362306a36Sopenharmony_ci simple_numbers_loop(long long, "%llx", "llx", check_ll); 22462306a36Sopenharmony_ci simple_numbers_loop(long long, "0x%llx", "lli", check_ll); 22562306a36Sopenharmony_ci simple_numbers_loop(unsigned long long, "0x%llx", "llx", check_ull); 22662306a36Sopenharmony_ci simple_numbers_loop(long long, "0x%llx", "llx", check_ll); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci simple_numbers_loop(unsigned long, "%lu", "lu", check_ulong); 22962306a36Sopenharmony_ci simple_numbers_loop(long, "%ld", "ld", check_long); 23062306a36Sopenharmony_ci simple_numbers_loop(long, "%ld", "li", check_long); 23162306a36Sopenharmony_ci simple_numbers_loop(unsigned long, "%lx", "lx", check_ulong); 23262306a36Sopenharmony_ci simple_numbers_loop(long, "%lx", "lx", check_long); 23362306a36Sopenharmony_ci simple_numbers_loop(long, "0x%lx", "li", check_long); 23462306a36Sopenharmony_ci simple_numbers_loop(unsigned long, "0x%lx", "lx", check_ulong); 23562306a36Sopenharmony_ci simple_numbers_loop(long, "0x%lx", "lx", check_long); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci simple_numbers_loop(unsigned int, "%u", "u", check_uint); 23862306a36Sopenharmony_ci simple_numbers_loop(int, "%d", "d", check_int); 23962306a36Sopenharmony_ci simple_numbers_loop(int, "%d", "i", check_int); 24062306a36Sopenharmony_ci simple_numbers_loop(unsigned int, "%x", "x", check_uint); 24162306a36Sopenharmony_ci simple_numbers_loop(int, "%x", "x", check_int); 24262306a36Sopenharmony_ci simple_numbers_loop(int, "0x%x", "i", check_int); 24362306a36Sopenharmony_ci simple_numbers_loop(unsigned int, "0x%x", "x", check_uint); 24462306a36Sopenharmony_ci simple_numbers_loop(int, "0x%x", "x", check_int); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci simple_numbers_loop(unsigned short, "%hu", "hu", check_ushort); 24762306a36Sopenharmony_ci simple_numbers_loop(short, "%hd", "hd", check_short); 24862306a36Sopenharmony_ci simple_numbers_loop(short, "%hd", "hi", check_short); 24962306a36Sopenharmony_ci simple_numbers_loop(unsigned short, "%hx", "hx", check_ushort); 25062306a36Sopenharmony_ci simple_numbers_loop(short, "%hx", "hx", check_short); 25162306a36Sopenharmony_ci simple_numbers_loop(short, "0x%hx", "hi", check_short); 25262306a36Sopenharmony_ci simple_numbers_loop(unsigned short, "0x%hx", "hx", check_ushort); 25362306a36Sopenharmony_ci simple_numbers_loop(short, "0x%hx", "hx", check_short); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci simple_numbers_loop(unsigned char, "%hhu", "hhu", check_uchar); 25662306a36Sopenharmony_ci simple_numbers_loop(signed char, "%hhd", "hhd", check_char); 25762306a36Sopenharmony_ci simple_numbers_loop(signed char, "%hhd", "hhi", check_char); 25862306a36Sopenharmony_ci simple_numbers_loop(unsigned char, "%hhx", "hhx", check_uchar); 25962306a36Sopenharmony_ci simple_numbers_loop(signed char, "%hhx", "hhx", check_char); 26062306a36Sopenharmony_ci simple_numbers_loop(signed char, "0x%hhx", "hhi", check_char); 26162306a36Sopenharmony_ci simple_numbers_loop(unsigned char, "0x%hhx", "hhx", check_uchar); 26262306a36Sopenharmony_ci simple_numbers_loop(signed char, "0x%hhx", "hhx", check_char); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* 26662306a36Sopenharmony_ci * This gives a better variety of number "lengths" in a small sample than 26762306a36Sopenharmony_ci * the raw prandom*() functions (Not mathematically rigorous!!). 26862306a36Sopenharmony_ci * Variabilty of length and value is more important than perfect randomness. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic u32 __init next_test_random(u32 max_bits) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic unsigned long long __init next_test_random_ull(void) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci u32 rand1 = prandom_u32_state(&rnd_state); 28062306a36Sopenharmony_ci u32 n_bits = (hweight32(rand1) * 3) % 64; 28162306a36Sopenharmony_ci u64 val = (u64)prandom_u32_state(&rnd_state) * rand1; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return val & GENMASK_ULL(n_bits, 0); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci#define random_for_type(T) \ 28762306a36Sopenharmony_ci ((T)(sizeof(T) <= sizeof(u32) \ 28862306a36Sopenharmony_ci ? next_test_random(BITS_PER_TYPE(T)) \ 28962306a36Sopenharmony_ci : next_test_random_ull())) 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * Define a pattern of negative and positive numbers to ensure we get 29362306a36Sopenharmony_ci * some of both within the small number of samples in a test string. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci#define NEGATIVES_PATTERN 0x3246 /* 00110010 01000110 */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#define fill_random_array(arr) \ 29862306a36Sopenharmony_cido { \ 29962306a36Sopenharmony_ci unsigned int neg_pattern = NEGATIVES_PATTERN; \ 30062306a36Sopenharmony_ci int i; \ 30162306a36Sopenharmony_ci \ 30262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) { \ 30362306a36Sopenharmony_ci (arr)[i] = random_for_type(typeof((arr)[0])); \ 30462306a36Sopenharmony_ci if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1)) \ 30562306a36Sopenharmony_ci (arr)[i] = -(arr)[i]; \ 30662306a36Sopenharmony_ci } \ 30762306a36Sopenharmony_ci} while (0) 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* 31062306a36Sopenharmony_ci * Convenience wrapper around snprintf() to append at buf_pos in buf, 31162306a36Sopenharmony_ci * updating buf_pos and returning the number of characters appended. 31262306a36Sopenharmony_ci * On error buf_pos is not changed and return value is 0. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cistatic int __init __printf(4, 5) 31562306a36Sopenharmony_ciappend_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci va_list ap; 31862306a36Sopenharmony_ci int field_len; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci va_start(ap, val_fmt); 32162306a36Sopenharmony_ci field_len = vsnprintf(buf + *buf_pos, buf_len - *buf_pos, val_fmt, ap); 32262306a36Sopenharmony_ci va_end(ap); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (field_len < 0) 32562306a36Sopenharmony_ci field_len = 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci *buf_pos += field_len; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return field_len; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* 33362306a36Sopenharmony_ci * Convenience function to append the field delimiter string 33462306a36Sopenharmony_ci * to both the value string and format string buffers. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_cistatic void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len, 33762306a36Sopenharmony_ci char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len, 33862306a36Sopenharmony_ci const char *delim_str) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci append_fmt(str_buf, str_buf_pos, str_buf_len, delim_str); 34162306a36Sopenharmony_ci append_fmt(fmt_buf, fmt_buf_pos, fmt_buf_len, delim_str); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci#define test_array_8(fn, check_data, string, fmt, arr) \ 34562306a36Sopenharmony_cido { \ 34662306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \ 34762306a36Sopenharmony_ci _test(fn, check_data, string, fmt, 8, \ 34862306a36Sopenharmony_ci &(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \ 34962306a36Sopenharmony_ci &(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \ 35062306a36Sopenharmony_ci} while (0) 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci#define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn) \ 35362306a36Sopenharmony_cido { \ 35462306a36Sopenharmony_ci int i, pos = 0, fmt_pos = 0; \ 35562306a36Sopenharmony_ci T expect[8], result[8]; \ 35662306a36Sopenharmony_ci \ 35762306a36Sopenharmony_ci fill_random_array(expect); \ 35862306a36Sopenharmony_ci \ 35962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(expect); i++) { \ 36062306a36Sopenharmony_ci if (i != 0) \ 36162306a36Sopenharmony_ci append_delim(test_buffer, &pos, BUF_SIZE, \ 36262306a36Sopenharmony_ci fmt_buffer, &fmt_pos, BUF_SIZE, \ 36362306a36Sopenharmony_ci field_sep); \ 36462306a36Sopenharmony_ci \ 36562306a36Sopenharmony_ci append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]); \ 36662306a36Sopenharmony_ci append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt); \ 36762306a36Sopenharmony_ci } \ 36862306a36Sopenharmony_ci \ 36962306a36Sopenharmony_ci test_array_8(fn, expect, test_buffer, fmt_buffer, result); \ 37062306a36Sopenharmony_ci} while (0) 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci#define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn) \ 37362306a36Sopenharmony_cido { \ 37462306a36Sopenharmony_ci char full_fmt[16]; \ 37562306a36Sopenharmony_ci \ 37662306a36Sopenharmony_ci snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt); \ 37762306a36Sopenharmony_ci numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn); \ 37862306a36Sopenharmony_ci} while (0) 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci#define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn) \ 38162306a36Sopenharmony_cido { \ 38262306a36Sopenharmony_ci int i, val_len, pos = 0, fmt_pos = 0; \ 38362306a36Sopenharmony_ci T expect[8], result[8]; \ 38462306a36Sopenharmony_ci \ 38562306a36Sopenharmony_ci fill_random_array(expect); \ 38662306a36Sopenharmony_ci \ 38762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(expect); i++) { \ 38862306a36Sopenharmony_ci if (i != 0) \ 38962306a36Sopenharmony_ci append_delim(test_buffer, &pos, BUF_SIZE, \ 39062306a36Sopenharmony_ci fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\ 39162306a36Sopenharmony_ci \ 39262306a36Sopenharmony_ci val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, \ 39362306a36Sopenharmony_ci expect[i]); \ 39462306a36Sopenharmony_ci append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, \ 39562306a36Sopenharmony_ci "%%%u%s", val_len, scan_fmt); \ 39662306a36Sopenharmony_ci } \ 39762306a36Sopenharmony_ci \ 39862306a36Sopenharmony_ci test_array_8(fn, expect, test_buffer, fmt_buffer, result); \ 39962306a36Sopenharmony_ci} while (0) 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void __init numbers_list_ll(const char *delim) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci numbers_list_8(unsigned long long, "%llu", delim, "llu", check_ull); 40462306a36Sopenharmony_ci numbers_list_8(long long, "%lld", delim, "lld", check_ll); 40562306a36Sopenharmony_ci numbers_list_8(long long, "%lld", delim, "lli", check_ll); 40662306a36Sopenharmony_ci numbers_list_8(unsigned long long, "%llx", delim, "llx", check_ull); 40762306a36Sopenharmony_ci numbers_list_8(unsigned long long, "0x%llx", delim, "llx", check_ull); 40862306a36Sopenharmony_ci numbers_list_8(long long, "0x%llx", delim, "lli", check_ll); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic void __init numbers_list_l(const char *delim) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci numbers_list_8(unsigned long, "%lu", delim, "lu", check_ulong); 41462306a36Sopenharmony_ci numbers_list_8(long, "%ld", delim, "ld", check_long); 41562306a36Sopenharmony_ci numbers_list_8(long, "%ld", delim, "li", check_long); 41662306a36Sopenharmony_ci numbers_list_8(unsigned long, "%lx", delim, "lx", check_ulong); 41762306a36Sopenharmony_ci numbers_list_8(unsigned long, "0x%lx", delim, "lx", check_ulong); 41862306a36Sopenharmony_ci numbers_list_8(long, "0x%lx", delim, "li", check_long); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void __init numbers_list_d(const char *delim) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci numbers_list_8(unsigned int, "%u", delim, "u", check_uint); 42462306a36Sopenharmony_ci numbers_list_8(int, "%d", delim, "d", check_int); 42562306a36Sopenharmony_ci numbers_list_8(int, "%d", delim, "i", check_int); 42662306a36Sopenharmony_ci numbers_list_8(unsigned int, "%x", delim, "x", check_uint); 42762306a36Sopenharmony_ci numbers_list_8(unsigned int, "0x%x", delim, "x", check_uint); 42862306a36Sopenharmony_ci numbers_list_8(int, "0x%x", delim, "i", check_int); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void __init numbers_list_h(const char *delim) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci numbers_list_8(unsigned short, "%hu", delim, "hu", check_ushort); 43462306a36Sopenharmony_ci numbers_list_8(short, "%hd", delim, "hd", check_short); 43562306a36Sopenharmony_ci numbers_list_8(short, "%hd", delim, "hi", check_short); 43662306a36Sopenharmony_ci numbers_list_8(unsigned short, "%hx", delim, "hx", check_ushort); 43762306a36Sopenharmony_ci numbers_list_8(unsigned short, "0x%hx", delim, "hx", check_ushort); 43862306a36Sopenharmony_ci numbers_list_8(short, "0x%hx", delim, "hi", check_short); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void __init numbers_list_hh(const char *delim) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci numbers_list_8(unsigned char, "%hhu", delim, "hhu", check_uchar); 44462306a36Sopenharmony_ci numbers_list_8(signed char, "%hhd", delim, "hhd", check_char); 44562306a36Sopenharmony_ci numbers_list_8(signed char, "%hhd", delim, "hhi", check_char); 44662306a36Sopenharmony_ci numbers_list_8(unsigned char, "%hhx", delim, "hhx", check_uchar); 44762306a36Sopenharmony_ci numbers_list_8(unsigned char, "0x%hhx", delim, "hhx", check_uchar); 44862306a36Sopenharmony_ci numbers_list_8(signed char, "0x%hhx", delim, "hhi", check_char); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void __init numbers_list(const char *delim) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci numbers_list_ll(delim); 45462306a36Sopenharmony_ci numbers_list_l(delim); 45562306a36Sopenharmony_ci numbers_list_d(delim); 45662306a36Sopenharmony_ci numbers_list_h(delim); 45762306a36Sopenharmony_ci numbers_list_hh(delim); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void __init numbers_list_field_width_ll(const char *delim) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci numbers_list_fix_width(unsigned long long, "%llu", delim, 20, "llu", check_ull); 46362306a36Sopenharmony_ci numbers_list_fix_width(long long, "%lld", delim, 20, "lld", check_ll); 46462306a36Sopenharmony_ci numbers_list_fix_width(long long, "%lld", delim, 20, "lli", check_ll); 46562306a36Sopenharmony_ci numbers_list_fix_width(unsigned long long, "%llx", delim, 16, "llx", check_ull); 46662306a36Sopenharmony_ci numbers_list_fix_width(unsigned long long, "0x%llx", delim, 18, "llx", check_ull); 46762306a36Sopenharmony_ci numbers_list_fix_width(long long, "0x%llx", delim, 18, "lli", check_ll); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic void __init numbers_list_field_width_l(const char *delim) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci#if BITS_PER_LONG == 64 47362306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "%lu", delim, 20, "lu", check_ulong); 47462306a36Sopenharmony_ci numbers_list_fix_width(long, "%ld", delim, 20, "ld", check_long); 47562306a36Sopenharmony_ci numbers_list_fix_width(long, "%ld", delim, 20, "li", check_long); 47662306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "%lx", delim, 16, "lx", check_ulong); 47762306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "0x%lx", delim, 18, "lx", check_ulong); 47862306a36Sopenharmony_ci numbers_list_fix_width(long, "0x%lx", delim, 18, "li", check_long); 47962306a36Sopenharmony_ci#else 48062306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "%lu", delim, 10, "lu", check_ulong); 48162306a36Sopenharmony_ci numbers_list_fix_width(long, "%ld", delim, 11, "ld", check_long); 48262306a36Sopenharmony_ci numbers_list_fix_width(long, "%ld", delim, 11, "li", check_long); 48362306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "%lx", delim, 8, "lx", check_ulong); 48462306a36Sopenharmony_ci numbers_list_fix_width(unsigned long, "0x%lx", delim, 10, "lx", check_ulong); 48562306a36Sopenharmony_ci numbers_list_fix_width(long, "0x%lx", delim, 10, "li", check_long); 48662306a36Sopenharmony_ci#endif 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void __init numbers_list_field_width_d(const char *delim) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci numbers_list_fix_width(unsigned int, "%u", delim, 10, "u", check_uint); 49262306a36Sopenharmony_ci numbers_list_fix_width(int, "%d", delim, 11, "d", check_int); 49362306a36Sopenharmony_ci numbers_list_fix_width(int, "%d", delim, 11, "i", check_int); 49462306a36Sopenharmony_ci numbers_list_fix_width(unsigned int, "%x", delim, 8, "x", check_uint); 49562306a36Sopenharmony_ci numbers_list_fix_width(unsigned int, "0x%x", delim, 10, "x", check_uint); 49662306a36Sopenharmony_ci numbers_list_fix_width(int, "0x%x", delim, 10, "i", check_int); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void __init numbers_list_field_width_h(const char *delim) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci numbers_list_fix_width(unsigned short, "%hu", delim, 5, "hu", check_ushort); 50262306a36Sopenharmony_ci numbers_list_fix_width(short, "%hd", delim, 6, "hd", check_short); 50362306a36Sopenharmony_ci numbers_list_fix_width(short, "%hd", delim, 6, "hi", check_short); 50462306a36Sopenharmony_ci numbers_list_fix_width(unsigned short, "%hx", delim, 4, "hx", check_ushort); 50562306a36Sopenharmony_ci numbers_list_fix_width(unsigned short, "0x%hx", delim, 6, "hx", check_ushort); 50662306a36Sopenharmony_ci numbers_list_fix_width(short, "0x%hx", delim, 6, "hi", check_short); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void __init numbers_list_field_width_hh(const char *delim) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci numbers_list_fix_width(unsigned char, "%hhu", delim, 3, "hhu", check_uchar); 51262306a36Sopenharmony_ci numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhd", check_char); 51362306a36Sopenharmony_ci numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhi", check_char); 51462306a36Sopenharmony_ci numbers_list_fix_width(unsigned char, "%hhx", delim, 2, "hhx", check_uchar); 51562306a36Sopenharmony_ci numbers_list_fix_width(unsigned char, "0x%hhx", delim, 4, "hhx", check_uchar); 51662306a36Sopenharmony_ci numbers_list_fix_width(signed char, "0x%hhx", delim, 4, "hhi", check_char); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* 52062306a36Sopenharmony_ci * List of numbers separated by delim. Each field width specifier is the 52162306a36Sopenharmony_ci * maximum possible digits for the given type and base. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic void __init numbers_list_field_width_typemax(const char *delim) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci numbers_list_field_width_ll(delim); 52662306a36Sopenharmony_ci numbers_list_field_width_l(delim); 52762306a36Sopenharmony_ci numbers_list_field_width_d(delim); 52862306a36Sopenharmony_ci numbers_list_field_width_h(delim); 52962306a36Sopenharmony_ci numbers_list_field_width_hh(delim); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_ll(const char *delim) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci numbers_list_val_width(unsigned long long, "%llu", delim, "llu", check_ull); 53562306a36Sopenharmony_ci numbers_list_val_width(long long, "%lld", delim, "lld", check_ll); 53662306a36Sopenharmony_ci numbers_list_val_width(long long, "%lld", delim, "lli", check_ll); 53762306a36Sopenharmony_ci numbers_list_val_width(unsigned long long, "%llx", delim, "llx", check_ull); 53862306a36Sopenharmony_ci numbers_list_val_width(unsigned long long, "0x%llx", delim, "llx", check_ull); 53962306a36Sopenharmony_ci numbers_list_val_width(long long, "0x%llx", delim, "lli", check_ll); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_l(const char *delim) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci numbers_list_val_width(unsigned long, "%lu", delim, "lu", check_ulong); 54562306a36Sopenharmony_ci numbers_list_val_width(long, "%ld", delim, "ld", check_long); 54662306a36Sopenharmony_ci numbers_list_val_width(long, "%ld", delim, "li", check_long); 54762306a36Sopenharmony_ci numbers_list_val_width(unsigned long, "%lx", delim, "lx", check_ulong); 54862306a36Sopenharmony_ci numbers_list_val_width(unsigned long, "0x%lx", delim, "lx", check_ulong); 54962306a36Sopenharmony_ci numbers_list_val_width(long, "0x%lx", delim, "li", check_long); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_d(const char *delim) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci numbers_list_val_width(unsigned int, "%u", delim, "u", check_uint); 55562306a36Sopenharmony_ci numbers_list_val_width(int, "%d", delim, "d", check_int); 55662306a36Sopenharmony_ci numbers_list_val_width(int, "%d", delim, "i", check_int); 55762306a36Sopenharmony_ci numbers_list_val_width(unsigned int, "%x", delim, "x", check_uint); 55862306a36Sopenharmony_ci numbers_list_val_width(unsigned int, "0x%x", delim, "x", check_uint); 55962306a36Sopenharmony_ci numbers_list_val_width(int, "0x%x", delim, "i", check_int); 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_h(const char *delim) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci numbers_list_val_width(unsigned short, "%hu", delim, "hu", check_ushort); 56562306a36Sopenharmony_ci numbers_list_val_width(short, "%hd", delim, "hd", check_short); 56662306a36Sopenharmony_ci numbers_list_val_width(short, "%hd", delim, "hi", check_short); 56762306a36Sopenharmony_ci numbers_list_val_width(unsigned short, "%hx", delim, "hx", check_ushort); 56862306a36Sopenharmony_ci numbers_list_val_width(unsigned short, "0x%hx", delim, "hx", check_ushort); 56962306a36Sopenharmony_ci numbers_list_val_width(short, "0x%hx", delim, "hi", check_short); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_hh(const char *delim) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci numbers_list_val_width(unsigned char, "%hhu", delim, "hhu", check_uchar); 57562306a36Sopenharmony_ci numbers_list_val_width(signed char, "%hhd", delim, "hhd", check_char); 57662306a36Sopenharmony_ci numbers_list_val_width(signed char, "%hhd", delim, "hhi", check_char); 57762306a36Sopenharmony_ci numbers_list_val_width(unsigned char, "%hhx", delim, "hhx", check_uchar); 57862306a36Sopenharmony_ci numbers_list_val_width(unsigned char, "0x%hhx", delim, "hhx", check_uchar); 57962306a36Sopenharmony_ci numbers_list_val_width(signed char, "0x%hhx", delim, "hhi", check_char); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/* 58362306a36Sopenharmony_ci * List of numbers separated by delim. Each field width specifier is the 58462306a36Sopenharmony_ci * exact length of the corresponding value digits in the string being scanned. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_cistatic void __init numbers_list_field_width_val_width(const char *delim) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci numbers_list_field_width_val_ll(delim); 58962306a36Sopenharmony_ci numbers_list_field_width_val_l(delim); 59062306a36Sopenharmony_ci numbers_list_field_width_val_d(delim); 59162306a36Sopenharmony_ci numbers_list_field_width_val_h(delim); 59262306a36Sopenharmony_ci numbers_list_field_width_val_hh(delim); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* 59662306a36Sopenharmony_ci * Slice a continuous string of digits without field delimiters, containing 59762306a36Sopenharmony_ci * numbers of varying length, using the field width to extract each group 59862306a36Sopenharmony_ci * of digits. For example the hex values c0,3,bf01,303 would have a 59962306a36Sopenharmony_ci * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x". 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_cistatic void __init numbers_slice(void) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci numbers_list_field_width_val_width(""); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \ 60762306a36Sopenharmony_cido { \ 60862306a36Sopenharmony_ci const T expect[2] = { expect0, expect1 }; \ 60962306a36Sopenharmony_ci T result[2] = { (T)~expect[0], (T)~expect[1] }; \ 61062306a36Sopenharmony_ci \ 61162306a36Sopenharmony_ci _test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \ 61262306a36Sopenharmony_ci} while (0) 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * Number prefix is >= field width. 61662306a36Sopenharmony_ci * Expected behaviour is derived from testing userland sscanf. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic void __init numbers_prefix_overflow(void) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * Negative decimal with a field of width 1, should quit scanning 62262306a36Sopenharmony_ci * and return 0. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci test_number_prefix(long long, "-1 1", "%1lld %lld", 0, 0, 0, check_ll); 62562306a36Sopenharmony_ci test_number_prefix(long, "-1 1", "%1ld %ld", 0, 0, 0, check_long); 62662306a36Sopenharmony_ci test_number_prefix(int, "-1 1", "%1d %d", 0, 0, 0, check_int); 62762306a36Sopenharmony_ci test_number_prefix(short, "-1 1", "%1hd %hd", 0, 0, 0, check_short); 62862306a36Sopenharmony_ci test_number_prefix(signed char, "-1 1", "%1hhd %hhd", 0, 0, 0, check_char); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci test_number_prefix(long long, "-1 1", "%1lli %lli", 0, 0, 0, check_ll); 63162306a36Sopenharmony_ci test_number_prefix(long, "-1 1", "%1li %li", 0, 0, 0, check_long); 63262306a36Sopenharmony_ci test_number_prefix(int, "-1 1", "%1i %i", 0, 0, 0, check_int); 63362306a36Sopenharmony_ci test_number_prefix(short, "-1 1", "%1hi %hi", 0, 0, 0, check_short); 63462306a36Sopenharmony_ci test_number_prefix(signed char, "-1 1", "%1hhi %hhi", 0, 0, 0, check_char); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * 0x prefix in a field of width 1: 0 is a valid digit so should 63862306a36Sopenharmony_ci * convert. Next field scan starts at the 'x' which isn't a digit so 63962306a36Sopenharmony_ci * scan quits with one field converted. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci test_number_prefix(unsigned long long, "0xA7", "%1llx%llx", 0, 0, 1, check_ull); 64262306a36Sopenharmony_ci test_number_prefix(unsigned long, "0xA7", "%1lx%lx", 0, 0, 1, check_ulong); 64362306a36Sopenharmony_ci test_number_prefix(unsigned int, "0xA7", "%1x%x", 0, 0, 1, check_uint); 64462306a36Sopenharmony_ci test_number_prefix(unsigned short, "0xA7", "%1hx%hx", 0, 0, 1, check_ushort); 64562306a36Sopenharmony_ci test_number_prefix(unsigned char, "0xA7", "%1hhx%hhx", 0, 0, 1, check_uchar); 64662306a36Sopenharmony_ci test_number_prefix(long long, "0xA7", "%1lli%llx", 0, 0, 1, check_ll); 64762306a36Sopenharmony_ci test_number_prefix(long, "0xA7", "%1li%lx", 0, 0, 1, check_long); 64862306a36Sopenharmony_ci test_number_prefix(int, "0xA7", "%1i%x", 0, 0, 1, check_int); 64962306a36Sopenharmony_ci test_number_prefix(short, "0xA7", "%1hi%hx", 0, 0, 1, check_short); 65062306a36Sopenharmony_ci test_number_prefix(char, "0xA7", "%1hhi%hhx", 0, 0, 1, check_char); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* 65362306a36Sopenharmony_ci * 0x prefix in a field of width 2 using %x conversion: first field 65462306a36Sopenharmony_ci * converts to 0. Next field scan starts at the character after "0x". 65562306a36Sopenharmony_ci * Both fields will convert. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci test_number_prefix(unsigned long long, "0xA7", "%2llx%llx", 0, 0xa7, 2, check_ull); 65862306a36Sopenharmony_ci test_number_prefix(unsigned long, "0xA7", "%2lx%lx", 0, 0xa7, 2, check_ulong); 65962306a36Sopenharmony_ci test_number_prefix(unsigned int, "0xA7", "%2x%x", 0, 0xa7, 2, check_uint); 66062306a36Sopenharmony_ci test_number_prefix(unsigned short, "0xA7", "%2hx%hx", 0, 0xa7, 2, check_ushort); 66162306a36Sopenharmony_ci test_number_prefix(unsigned char, "0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * 0x prefix in a field of width 2 using %i conversion: first field 66562306a36Sopenharmony_ci * converts to 0. Next field scan starts at the character after "0x", 66662306a36Sopenharmony_ci * which will convert if can be interpreted as decimal but will fail 66762306a36Sopenharmony_ci * if it contains any hex digits (since no 0x prefix). 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci test_number_prefix(long long, "0x67", "%2lli%lli", 0, 67, 2, check_ll); 67062306a36Sopenharmony_ci test_number_prefix(long, "0x67", "%2li%li", 0, 67, 2, check_long); 67162306a36Sopenharmony_ci test_number_prefix(int, "0x67", "%2i%i", 0, 67, 2, check_int); 67262306a36Sopenharmony_ci test_number_prefix(short, "0x67", "%2hi%hi", 0, 67, 2, check_short); 67362306a36Sopenharmony_ci test_number_prefix(char, "0x67", "%2hhi%hhi", 0, 67, 2, check_char); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci test_number_prefix(long long, "0xA7", "%2lli%lli", 0, 0, 1, check_ll); 67662306a36Sopenharmony_ci test_number_prefix(long, "0xA7", "%2li%li", 0, 0, 1, check_long); 67762306a36Sopenharmony_ci test_number_prefix(int, "0xA7", "%2i%i", 0, 0, 1, check_int); 67862306a36Sopenharmony_ci test_number_prefix(short, "0xA7", "%2hi%hi", 0, 0, 1, check_short); 67962306a36Sopenharmony_ci test_number_prefix(char, "0xA7", "%2hhi%hhi", 0, 0, 1, check_char); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci#define _test_simple_strtoxx(T, fn, gen_fmt, expect, base) \ 68362306a36Sopenharmony_cido { \ 68462306a36Sopenharmony_ci T got; \ 68562306a36Sopenharmony_ci char *endp; \ 68662306a36Sopenharmony_ci int len; \ 68762306a36Sopenharmony_ci bool fail = false; \ 68862306a36Sopenharmony_ci \ 68962306a36Sopenharmony_ci total_tests++; \ 69062306a36Sopenharmony_ci len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \ 69162306a36Sopenharmony_ci got = (fn)(test_buffer, &endp, base); \ 69262306a36Sopenharmony_ci pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got); \ 69362306a36Sopenharmony_ci if (got != (expect)) { \ 69462306a36Sopenharmony_ci fail = true; \ 69562306a36Sopenharmony_ci pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \ 69662306a36Sopenharmony_ci test_buffer, base, got, expect); \ 69762306a36Sopenharmony_ci } else if (endp != test_buffer + len) { \ 69862306a36Sopenharmony_ci fail = true; \ 69962306a36Sopenharmony_ci pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \ 70062306a36Sopenharmony_ci test_buffer, base, test_buffer, \ 70162306a36Sopenharmony_ci test_buffer + len, endp); \ 70262306a36Sopenharmony_ci } \ 70362306a36Sopenharmony_ci \ 70462306a36Sopenharmony_ci if (fail) \ 70562306a36Sopenharmony_ci failed_tests++; \ 70662306a36Sopenharmony_ci} while (0) 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci#define test_simple_strtoxx(T, fn, gen_fmt, base) \ 70962306a36Sopenharmony_cido { \ 71062306a36Sopenharmony_ci int i; \ 71162306a36Sopenharmony_ci \ 71262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(numbers); i++) { \ 71362306a36Sopenharmony_ci _test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base); \ 71462306a36Sopenharmony_ci \ 71562306a36Sopenharmony_ci if (is_signed_type(T)) \ 71662306a36Sopenharmony_ci _test_simple_strtoxx(T, fn, gen_fmt, \ 71762306a36Sopenharmony_ci -(T)numbers[i], base); \ 71862306a36Sopenharmony_ci } \ 71962306a36Sopenharmony_ci} while (0) 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void __init test_simple_strtoull(void) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 10); 72462306a36Sopenharmony_ci test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 0); 72562306a36Sopenharmony_ci test_simple_strtoxx(unsigned long long, simple_strtoull, "%llx", 16); 72662306a36Sopenharmony_ci test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 16); 72762306a36Sopenharmony_ci test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic void __init test_simple_strtoll(void) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci test_simple_strtoxx(long long, simple_strtoll, "%lld", 10); 73362306a36Sopenharmony_ci test_simple_strtoxx(long long, simple_strtoll, "%lld", 0); 73462306a36Sopenharmony_ci test_simple_strtoxx(long long, simple_strtoll, "%llx", 16); 73562306a36Sopenharmony_ci test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 16); 73662306a36Sopenharmony_ci test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic void __init test_simple_strtoul(void) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 10); 74262306a36Sopenharmony_ci test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 0); 74362306a36Sopenharmony_ci test_simple_strtoxx(unsigned long, simple_strtoul, "%lx", 16); 74462306a36Sopenharmony_ci test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 16); 74562306a36Sopenharmony_ci test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0); 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic void __init test_simple_strtol(void) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci test_simple_strtoxx(long, simple_strtol, "%ld", 10); 75162306a36Sopenharmony_ci test_simple_strtoxx(long, simple_strtol, "%ld", 0); 75262306a36Sopenharmony_ci test_simple_strtoxx(long, simple_strtol, "%lx", 16); 75362306a36Sopenharmony_ci test_simple_strtoxx(long, simple_strtol, "0x%lx", 16); 75462306a36Sopenharmony_ci test_simple_strtoxx(long, simple_strtol, "0x%lx", 0); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/* Selection of common delimiters/separators between numbers in a string. */ 75862306a36Sopenharmony_cistatic const char * const number_delimiters[] __initconst = { 75962306a36Sopenharmony_ci " ", ":", ",", "-", "/", 76062306a36Sopenharmony_ci}; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void __init test_numbers(void) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci int i; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* String containing only one number. */ 76762306a36Sopenharmony_ci numbers_simple(); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* String with multiple numbers separated by delimiter. */ 77062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) { 77162306a36Sopenharmony_ci numbers_list(number_delimiters[i]); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Field width may be longer than actual field digits. */ 77462306a36Sopenharmony_ci numbers_list_field_width_typemax(number_delimiters[i]); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Each field width exactly length of actual field digits. */ 77762306a36Sopenharmony_ci numbers_list_field_width_val_width(number_delimiters[i]); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* Slice continuous sequence of digits using field widths. */ 78162306a36Sopenharmony_ci numbers_slice(); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci numbers_prefix_overflow(); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic void __init selftest(void) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); 78962306a36Sopenharmony_ci if (!test_buffer) 79062306a36Sopenharmony_ci return; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); 79362306a36Sopenharmony_ci if (!fmt_buffer) { 79462306a36Sopenharmony_ci kfree(test_buffer); 79562306a36Sopenharmony_ci return; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci prandom_seed_state(&rnd_state, 3141592653589793238ULL); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci test_numbers(); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci test_simple_strtoull(); 80362306a36Sopenharmony_ci test_simple_strtoll(); 80462306a36Sopenharmony_ci test_simple_strtoul(); 80562306a36Sopenharmony_ci test_simple_strtol(); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci kfree(fmt_buffer); 80862306a36Sopenharmony_ci kfree(test_buffer); 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ciKSTM_MODULE_LOADERS(test_scanf); 81262306a36Sopenharmony_ciMODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); 81362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 814