diff options
author | Alistair Delva <adelva@google.com> | 2021-02-16 21:01:22 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-02-16 21:01:22 +0000 |
commit | efb2826bb8160e2d8e0fcec85133a7468484f9fd (patch) | |
tree | 37a21c69306801ee7cdda5167a30896c8740155b /lib/libc/snprintf.c | |
parent | b00a71fc312c9781fa6f404dccfb55b062b2ccac (diff) | |
parent | faa476c0caaa598afa5a6109d17102db5fe35ec6 (diff) | |
download | platform_external_arm-trusted-firmware-master.tar.gz platform_external_arm-trusted-firmware-master.tar.bz2 platform_external_arm-trusted-firmware-master.zip |
Merge branch 'aosp/upstream-master' into HEAD am: faa476c0caHEADandroid-s-beta-5android-s-beta-4android-s-beta-3android-s-beta-2android-s-beta-1mastermain-cg-testing-releaseandroid-s-beta-5android-s-beta-4
Original change: https://android-review.googlesource.com/c/platform/external/arm-trusted-firmware/+/1589611
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: I3a25534ceed4f8e188510641080d8b8ed49b8f62
Diffstat (limited to 'lib/libc/snprintf.c')
-rw-r--r-- | lib/libc/snprintf.c | 196 |
1 files changed, 156 insertions, 40 deletions
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c index 38ad1c71a..3b175ed6a 100644 --- a/lib/libc/snprintf.c +++ b/lib/libc/snprintf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,51 +10,90 @@ #include <common/debug.h> #include <plat/common/platform.h> +#define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \ + do { \ + if ((chars_printed) < (size)) { \ + *(buf) = (ch); \ + (buf)++; \ + } \ + (chars_printed)++; \ + } while (false) + static void string_print(char **s, size_t n, size_t *chars_printed, const char *str) { while (*str != '\0') { - if (*chars_printed < n) { - *(*s) = *str; - (*s)++; - } - - (*chars_printed)++; + CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str); str++; } } -static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, - unsigned int unum) +static void unsigned_num_print(char **s, size_t n, size_t *chars_printed, + unsigned long long int unum, + unsigned int radix, char padc, int padn, + bool capitalise) { - /* Enough for a 32-bit unsigned decimal integer (4294967295). */ - char num_buf[10]; + /* Just need enough space to store 64 bit decimal integer */ + char num_buf[20]; int i = 0; + int width; unsigned int rem; + char ascii_a = capitalise ? 'A' : 'a'; do { - rem = unum % 10U; - num_buf[i++] = '0' + rem; - unum /= 10U; + rem = unum % radix; + if (rem < 10U) { + num_buf[i] = '0' + rem; + } else { + num_buf[i] = ascii_a + (rem - 10U); + } + i++; + unum /= radix; } while (unum > 0U); - while (--i >= 0) { - if (*chars_printed < n) { - *(*s) = num_buf[i]; - (*s)++; + width = i; + if (padn > width) { + (*chars_printed) += (size_t)padn; + } else { + (*chars_printed) += (size_t)width; + } + + if (*chars_printed < n) { + + if (padn > 0) { + while (width < padn) { + *(*s)++ = padc; + padn--; + } + } + + while (--i >= 0) { + *(*s)++ = num_buf[i]; } - (*chars_printed)++; + if (padn < 0) { + while (width < -padn) { + *(*s)++ = padc; + padn++; + } + } } } /******************************************************************* - * Reduced snprintf to be used for Trusted firmware. + * Reduced vsnprintf to be used for Trusted firmware. * The following type specifiers are supported: * + * %x (or %X) - hexadecimal format * %d or %i - signed decimal format * %s - string format * %u - unsigned decimal format + * %p - pointer format + * + * The following padding specifiers are supported by this print + * %0NN - Left-pad the number with 0s (NN is a decimal number) + * %NN - Left-pad the number or string with spaces (NN is a decimal number) + * %-NN - Right-pad the number or string with spaces (NN is a decimal number) * * The function panics on all other formats specifiers. * @@ -62,12 +101,15 @@ static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, * buffer was big enough. If it returns a value lower than n, the * whole string has been written. *******************************************************************/ -int snprintf(char *s, size_t n, const char *fmt, ...) +int vsnprintf(char *s, size_t n, const char *fmt, va_list args) { - va_list args; int num; - unsigned int unum; + unsigned long long int unum; char *str; + char padc; /* Padding character */ + int padn; /* Number of characters to pad */ + bool left; + bool capitalise; size_t chars_printed = 0U; if (n == 0U) { @@ -81,30 +123,57 @@ int snprintf(char *s, size_t n, const char *fmt, ...) n--; } - va_start(args, fmt); while (*fmt != '\0') { + left = false; + padc ='\0'; + padn = 0; + capitalise = false; if (*fmt == '%') { fmt++; /* Check the format specifier. */ +loop: switch (*fmt) { + case '%': + CHECK_AND_PUT_CHAR(s, n, chars_printed, '%'); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + padc = (*fmt == '0') ? '0' : ' '; + for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) { + padn = (padn * 10) + (*fmt - '0'); + } + if (left) { + padn = -padn; + } + goto loop; + case '-': + left = true; + fmt++; + goto loop; + case 'i': case 'd': num = va_arg(args, int); if (num < 0) { - if (chars_printed < n) { - *s = '-'; - s++; - } - chars_printed++; - + CHECK_AND_PUT_CHAR(s, n, chars_printed, + '-'); unum = (unsigned int)-num; } else { unum = (unsigned int)num; } - unsigned_dec_print(&s, n, &chars_printed, unum); + unsigned_num_print(&s, n, &chars_printed, + unum, 10, padc, padn, false); break; case 's': str = va_arg(args, char *); @@ -112,8 +181,27 @@ int snprintf(char *s, size_t n, const char *fmt, ...) break; case 'u': unum = va_arg(args, unsigned int); - unsigned_dec_print(&s, n, &chars_printed, unum); + unsigned_num_print(&s, n, &chars_printed, + unum, 10, padc, padn, false); + break; + case 'p': + unum = (uintptr_t)va_arg(args, void *); + if (unum > 0U) { + string_print(&s, n, &chars_printed, "0x"); + padn -= 2; + } + unsigned_num_print(&s, n, &chars_printed, + unum, 16, padc, padn, false); + break; + case 'X': + capitalise = true; + case 'x': + unum = va_arg(args, unsigned int); + unsigned_num_print(&s, n, &chars_printed, + unum, 16, padc, padn, + capitalise); break; + default: /* Panic on any other format specifier. */ ERROR("snprintf: specifier with ASCII code '%d' not supported.", @@ -125,19 +213,47 @@ int snprintf(char *s, size_t n, const char *fmt, ...) continue; } - if (chars_printed < n) { - *s = *fmt; - s++; - } + CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt); fmt++; - chars_printed++; } - va_end(args); - - if (n > 0U) + if (n > 0U) { *s = '\0'; + } return (int)chars_printed; } + +/******************************************************************* + * Reduced snprintf to be used for Trusted firmware. + * The following type specifiers are supported: + * + * %x (or %X) - hexadecimal format + * %d or %i - signed decimal format + * %s - string format + * %u - unsigned decimal format + * %p - pointer format + * + * The following padding specifiers are supported by this print + * %0NN - Left-pad the number with 0s (NN is a decimal number) + * %NN - Left-pad the number or string with spaces (NN is a decimal number) + * %-NN - Right-pad the number or string with spaces (NN is a decimal number) + * + * The function panics on all other formats specifiers. + * + * It returns the number of characters that would be written if the + * buffer was big enough. If it returns a value lower than n, the + * whole string has been written. + *******************************************************************/ +int snprintf(char *s, size_t n, const char *fmt, ...) +{ + int count; + va_list all_args; + + va_start(all_args, fmt); + count = vsnprintf(s, n, fmt, all_args); + va_end(all_args); + + return count; +} |