
From: Lukas Funke lukas.funke@weidmueller.com
Forward '%p' format specifier to the underlying format logic in order to print pointers, especially bitmaps.
Signed-off-by: Lukas Funke lukas.funke@weidmueller.com ---
Changes in v3: - Dereference pointer argument (i.e. *value) in the 'setexpr name fmt <format> value' case. This is currently only supported in the 'setexptr <name> [*]<value>' and 'setexptr <name> [*]<value> <op> [*]<value2>' case
cmd/printf.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
diff --git a/cmd/printf.c b/cmd/printf.c index f56543b79e..2e54faf339 100644 --- a/cmd/printf.c +++ b/cmd/printf.c @@ -85,11 +85,13 @@ */
#include <common.h> +#include <command.h> #include <ctype.h> #include <errno.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> +#include <linux/bitmap.h>
#define WANT_HEX_ESCAPES 0 #define PRINT_CONVERSION_ERROR 1 @@ -476,6 +478,38 @@ static int get_width_prec(const char *str) return (int)v; }
+static int print_pointer(struct print_inf *inf, char *format, + unsigned int fmt_length, int field_width, + int precision, const char *argument) +{ + struct expr_arg aval; + + if (setexpr_get_arg(skip_whitespace(argument), field_width >> 3, &aval)) + return CMD_RET_FAILURE; + + if (field_width > BITS_PER_LONG) { + printf_str(inf, format, aval.bmap); + free(aval.bmap); + } else { + printf_str(inf, format, &aval.ival); + } + + switch (inf->error) { + case 0: + return 0; + case PRINT_SIZE_ERROR: + printf("printf: size error\n"); break; + case PRINT_CONVERSION_ERROR: + printf("printf: conversion error\n"); break; + case PRINT_TRUNCATED_ERROR: + printf("printf: output truncated\n"); break; + default: + printf("printf: unknown error\n"); + } + + return -1; +} + /* Print the text in FORMAT, using ARGV for arguments to any '%' directives. * Return advanced ARGV. */ @@ -536,6 +570,23 @@ static char **print_formatted(struct print_inf *inf, char *f, char **argv, int * } } } + if (*f == 'p') { + static const char ptr_format_chars[] = "bl"; + ++f; + ++direc_length; + char *p = strchr(ptr_format_chars, *f); + /* consume whole format token */ + while (*f != '\0' && *(p++) == *f) { + ++f; + ++direc_length; + } + if (print_pointer(inf, direc_start, direc_length, + field_width, precision, *argv++)) { + return saved_argv - 1; + } + f--; + break; + }
/* Remove "lLhz" size modifiers, repeatedly. * bash does not like "%lld", but coreutils