From: Lukas Funke <[email protected]>

Forward '%p' format specifier to the underlying format logic in order
to print pointers, especially bitmaps.

Signed-off-by: Lukas Funke <[email protected]>
---

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
-- 
2.30.2

Reply via email to