diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-04-25 13:09:13 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2022-04-25 13:09:13 -0400 |
commit | 08bdef51c6f550cddba09ba59cb521098149a327 (patch) | |
tree | 27a55306f1aa95868571a38aaea357650febf8ea | |
parent | 8c69628d9527a1fed31289649ef53e732bfdd5e3 (diff) |
Start of %q(%p)shrinker_to_text
-rw-r--r-- | lib/vsprintf.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 3b8129dd374c..dc8e84f99714 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -430,7 +430,8 @@ enum format_type { FORMAT_TYPE_UINT, FORMAT_TYPE_INT, FORMAT_TYPE_SIZE_T, - FORMAT_TYPE_PTRDIFF + FORMAT_TYPE_PTRDIFF, + FORMAT_TYPE_FN, }; struct printf_spec { @@ -2477,6 +2478,16 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return ptr_to_id(buf, end, ptr, spec); } +typedef int (*printf_fn_0)(char *buf, size_t size); +typedef int (*printf_fn_1)(char *buf, size_t size, void *); +typedef int (*printf_fn_2)(char *buf, size_t size, void *, void *); +typedef int (*printf_fn_3)(char *buf, size_t size, void *, void *, void *); +typedef int (*printf_fn_4)(char *buf, size_t size, void *, void *, void *, void *); +typedef int (*printf_fn_5)(char *buf, size_t size, void *, void *, void *, void *, void *); +typedef int (*printf_fn_6)(char *buf, size_t size, void *, void *, void *, void *, void *, void *); +typedef int (*printf_fn_7)(char *buf, size_t size, void *, void *, void *, void *, void *, void *, void *); +typedef int (*printf_fn_8)(char *buf, size_t size, void *, void *, void *, void *, void *, void *, void *, void *); + /* * Helper function to decode printf style format. * Each call decode a token from the format and return the @@ -2614,6 +2625,9 @@ qualifier: case 'p': spec->type = FORMAT_TYPE_PTR; return ++fmt - start; + case 'q': + spec->type = FORMAT_TYPE_FN; + return ++fmt - start; case '%': spec->type = FORMAT_TYPE_PERCENT_CHAR; @@ -2802,6 +2816,62 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) fmt++; break; + case FORMAT_TYPE_FN: { + unsigned nr_args = 0; + void *fn_args[8]; + void *fn = va_arg(args, void *); + + if (*fmt++ != '(') + return 0; + + while (1) { + if (nr_args == ARRAY_SIZE(fn_args)) + return 0; + if (*fmt++ != '%') + return 0; + if (*fmt++ != 'p') + return 0; + fn_args[nr_args++] = va_arg(args, void *); + if (*fmt == ')') + break; + if (*fmt++ != ',') + return 0; + } + + switch (nr_args) { + case 0: + buf += ((printf_fn_0)fn)(buf, size); + break; + case 1: + buf += ((printf_fn_1)fn)(buf, size, fn_args[0]); + break; + case 2: + buf += ((printf_fn_2)fn)(buf, size, fn_args[0], fn_args[1]); + break; + case 3: + buf += ((printf_fn_3)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2]); + break; + case 4: + buf += ((printf_fn_4)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2], fn_args[3]); + break; + case 5: + buf += ((printf_fn_5)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4]); + break; + case 6: + buf += ((printf_fn_6)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5]); + break; + case 7: + buf += ((printf_fn_7)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5], fn_args[6]); + break; + case 8: + buf += ((printf_fn_8)fn)(buf, size, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5], fn_args[6], fn_args[7]); + break; + } + + fmt++; /* past trailing ) */ + break; + } + case FORMAT_TYPE_PERCENT_CHAR: if (str < end) *str = '%'; |