1870ce3ddSAntonio Nino Diaz /* 2c6546154SHeyi Guo * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. 3870ce3ddSAntonio Nino Diaz * 4870ce3ddSAntonio Nino Diaz * SPDX-License-Identifier: BSD-3-Clause 5870ce3ddSAntonio Nino Diaz */ 6870ce3ddSAntonio Nino Diaz 7a08a2014SDaniel Boulby #include <assert.h> 8870ce3ddSAntonio Nino Diaz #include <stdarg.h> 9870ce3ddSAntonio Nino Diaz 1009d40e0eSAntonio Nino Diaz #include <common/debug.h> 1109d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 1209d40e0eSAntonio Nino Diaz 13*7981c504SHeyi Guo #define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \ 14*7981c504SHeyi Guo do { \ 15*7981c504SHeyi Guo if ((chars_printed) < (size)) { \ 16*7981c504SHeyi Guo *(buf) = (ch); \ 17*7981c504SHeyi Guo (buf)++; \ 18*7981c504SHeyi Guo } \ 19*7981c504SHeyi Guo (chars_printed)++; \ 20*7981c504SHeyi Guo } while (false) 21*7981c504SHeyi Guo 22870ce3ddSAntonio Nino Diaz static void string_print(char **s, size_t n, size_t *chars_printed, 23870ce3ddSAntonio Nino Diaz const char *str) 24870ce3ddSAntonio Nino Diaz { 25d5ccb754SAntonio Nino Diaz while (*str != '\0') { 26*7981c504SHeyi Guo CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str); 27870ce3ddSAntonio Nino Diaz str++; 28870ce3ddSAntonio Nino Diaz } 29870ce3ddSAntonio Nino Diaz } 30870ce3ddSAntonio Nino Diaz 31524eecc6SJavier Almansa Sobrino static void unsigned_num_print(char **s, size_t n, size_t *chars_printed, 32524eecc6SJavier Almansa Sobrino unsigned long long int unum, 33524eecc6SJavier Almansa Sobrino unsigned int radix, char padc, int padn, 34524eecc6SJavier Almansa Sobrino bool capitalise) 35870ce3ddSAntonio Nino Diaz { 36524eecc6SJavier Almansa Sobrino /* Just need enough space to store 64 bit decimal integer */ 37524eecc6SJavier Almansa Sobrino char num_buf[20]; 38d5ccb754SAntonio Nino Diaz int i = 0; 39524eecc6SJavier Almansa Sobrino int width; 40d5ccb754SAntonio Nino Diaz unsigned int rem; 41524eecc6SJavier Almansa Sobrino char ascii_a = capitalise ? 'A' : 'a'; 42870ce3ddSAntonio Nino Diaz 43870ce3ddSAntonio Nino Diaz do { 44524eecc6SJavier Almansa Sobrino rem = unum % radix; 45524eecc6SJavier Almansa Sobrino if (rem < 10U) { 46524eecc6SJavier Almansa Sobrino num_buf[i] = '0' + rem; 47524eecc6SJavier Almansa Sobrino } else { 48524eecc6SJavier Almansa Sobrino num_buf[i] = ascii_a + (rem - 10U); 49524eecc6SJavier Almansa Sobrino } 50524eecc6SJavier Almansa Sobrino i++; 51524eecc6SJavier Almansa Sobrino unum /= radix; 52d5ccb754SAntonio Nino Diaz } while (unum > 0U); 53870ce3ddSAntonio Nino Diaz 54524eecc6SJavier Almansa Sobrino width = i; 55524eecc6SJavier Almansa Sobrino if (padn > width) { 56524eecc6SJavier Almansa Sobrino (*chars_printed) += (size_t)padn; 57524eecc6SJavier Almansa Sobrino } else { 58524eecc6SJavier Almansa Sobrino (*chars_printed) += (size_t)width; 59d5ccb754SAntonio Nino Diaz } 60d5ccb754SAntonio Nino Diaz 61524eecc6SJavier Almansa Sobrino if (*chars_printed < n) { 62524eecc6SJavier Almansa Sobrino 63524eecc6SJavier Almansa Sobrino if (padn > 0) { 64524eecc6SJavier Almansa Sobrino while (width < padn) { 65524eecc6SJavier Almansa Sobrino *(*s)++ = padc; 66524eecc6SJavier Almansa Sobrino padn--; 67524eecc6SJavier Almansa Sobrino } 68524eecc6SJavier Almansa Sobrino } 69524eecc6SJavier Almansa Sobrino 70524eecc6SJavier Almansa Sobrino while (--i >= 0) { 71524eecc6SJavier Almansa Sobrino *(*s)++ = num_buf[i]; 72524eecc6SJavier Almansa Sobrino } 73524eecc6SJavier Almansa Sobrino 74524eecc6SJavier Almansa Sobrino if (padn < 0) { 75524eecc6SJavier Almansa Sobrino while (width < -padn) { 76524eecc6SJavier Almansa Sobrino *(*s)++ = padc; 77524eecc6SJavier Almansa Sobrino padn++; 78524eecc6SJavier Almansa Sobrino } 79524eecc6SJavier Almansa Sobrino } 80870ce3ddSAntonio Nino Diaz } 81870ce3ddSAntonio Nino Diaz } 82870ce3ddSAntonio Nino Diaz 83870ce3ddSAntonio Nino Diaz /******************************************************************* 8477648689SMadhukar Pappireddy * Reduced vsnprintf to be used for Trusted firmware. 85870ce3ddSAntonio Nino Diaz * The following type specifiers are supported: 86870ce3ddSAntonio Nino Diaz * 87524eecc6SJavier Almansa Sobrino * %x (or %X) - hexadecimal format 88870ce3ddSAntonio Nino Diaz * %d or %i - signed decimal format 89870ce3ddSAntonio Nino Diaz * %s - string format 90870ce3ddSAntonio Nino Diaz * %u - unsigned decimal format 91524eecc6SJavier Almansa Sobrino * %p - pointer format 92524eecc6SJavier Almansa Sobrino * 93524eecc6SJavier Almansa Sobrino * The following padding specifiers are supported by this print 94524eecc6SJavier Almansa Sobrino * %0NN - Left-pad the number with 0s (NN is a decimal number) 95524eecc6SJavier Almansa Sobrino * %NN - Left-pad the number or string with spaces (NN is a decimal number) 96524eecc6SJavier Almansa Sobrino * %-NN - Right-pad the number or string with spaces (NN is a decimal number) 97870ce3ddSAntonio Nino Diaz * 98870ce3ddSAntonio Nino Diaz * The function panics on all other formats specifiers. 99870ce3ddSAntonio Nino Diaz * 100870ce3ddSAntonio Nino Diaz * It returns the number of characters that would be written if the 101870ce3ddSAntonio Nino Diaz * buffer was big enough. If it returns a value lower than n, the 102870ce3ddSAntonio Nino Diaz * whole string has been written. 103870ce3ddSAntonio Nino Diaz *******************************************************************/ 10477648689SMadhukar Pappireddy int vsnprintf(char *s, size_t n, const char *fmt, va_list args) 105870ce3ddSAntonio Nino Diaz { 106870ce3ddSAntonio Nino Diaz int num; 107524eecc6SJavier Almansa Sobrino unsigned long long int unum; 108870ce3ddSAntonio Nino Diaz char *str; 109524eecc6SJavier Almansa Sobrino char padc; /* Padding character */ 110524eecc6SJavier Almansa Sobrino int padn; /* Number of characters to pad */ 111524eecc6SJavier Almansa Sobrino bool left; 112524eecc6SJavier Almansa Sobrino bool capitalise; 113d5ccb754SAntonio Nino Diaz size_t chars_printed = 0U; 114870ce3ddSAntonio Nino Diaz 115d5ccb754SAntonio Nino Diaz if (n == 0U) { 116d5ccb754SAntonio Nino Diaz /* There isn't space for anything. */ 117d5ccb754SAntonio Nino Diaz } else if (n == 1U) { 118870ce3ddSAntonio Nino Diaz /* Buffer is too small to actually write anything else. */ 119870ce3ddSAntonio Nino Diaz *s = '\0'; 120d5ccb754SAntonio Nino Diaz n = 0U; 121d5ccb754SAntonio Nino Diaz } else { 122870ce3ddSAntonio Nino Diaz /* Reserve space for the terminator character. */ 123870ce3ddSAntonio Nino Diaz n--; 124870ce3ddSAntonio Nino Diaz } 125870ce3ddSAntonio Nino Diaz 126d5ccb754SAntonio Nino Diaz while (*fmt != '\0') { 127524eecc6SJavier Almansa Sobrino left = false; 128524eecc6SJavier Almansa Sobrino padc ='\0'; 129524eecc6SJavier Almansa Sobrino padn = 0; 130524eecc6SJavier Almansa Sobrino capitalise = false; 131870ce3ddSAntonio Nino Diaz 132870ce3ddSAntonio Nino Diaz if (*fmt == '%') { 133870ce3ddSAntonio Nino Diaz fmt++; 134870ce3ddSAntonio Nino Diaz /* Check the format specifier. */ 135524eecc6SJavier Almansa Sobrino loop: 136870ce3ddSAntonio Nino Diaz switch (*fmt) { 137c6546154SHeyi Guo case '%': 138*7981c504SHeyi Guo CHECK_AND_PUT_CHAR(s, n, chars_printed, '%'); 139c6546154SHeyi Guo break; 140524eecc6SJavier Almansa Sobrino case '0': 141524eecc6SJavier Almansa Sobrino case '1': 142524eecc6SJavier Almansa Sobrino case '2': 143524eecc6SJavier Almansa Sobrino case '3': 144524eecc6SJavier Almansa Sobrino case '4': 145524eecc6SJavier Almansa Sobrino case '5': 146524eecc6SJavier Almansa Sobrino case '6': 147524eecc6SJavier Almansa Sobrino case '7': 148524eecc6SJavier Almansa Sobrino case '8': 149524eecc6SJavier Almansa Sobrino case '9': 150524eecc6SJavier Almansa Sobrino padc = (*fmt == '0') ? '0' : ' '; 151524eecc6SJavier Almansa Sobrino for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) { 152524eecc6SJavier Almansa Sobrino padn = (padn * 10) + (*fmt - '0'); 153524eecc6SJavier Almansa Sobrino } 154524eecc6SJavier Almansa Sobrino if (left) { 155524eecc6SJavier Almansa Sobrino padn = -padn; 156524eecc6SJavier Almansa Sobrino } 157524eecc6SJavier Almansa Sobrino goto loop; 158524eecc6SJavier Almansa Sobrino case '-': 159524eecc6SJavier Almansa Sobrino left = true; 160524eecc6SJavier Almansa Sobrino fmt++; 161524eecc6SJavier Almansa Sobrino goto loop; 162524eecc6SJavier Almansa Sobrino 163870ce3ddSAntonio Nino Diaz case 'i': 164870ce3ddSAntonio Nino Diaz case 'd': 165870ce3ddSAntonio Nino Diaz num = va_arg(args, int); 166870ce3ddSAntonio Nino Diaz 167870ce3ddSAntonio Nino Diaz if (num < 0) { 168*7981c504SHeyi Guo CHECK_AND_PUT_CHAR(s, n, chars_printed, 169*7981c504SHeyi Guo '-'); 170870ce3ddSAntonio Nino Diaz unum = (unsigned int)-num; 171870ce3ddSAntonio Nino Diaz } else { 172870ce3ddSAntonio Nino Diaz unum = (unsigned int)num; 173870ce3ddSAntonio Nino Diaz } 174870ce3ddSAntonio Nino Diaz 175524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 176524eecc6SJavier Almansa Sobrino unum, 10, padc, padn, false); 177870ce3ddSAntonio Nino Diaz break; 178870ce3ddSAntonio Nino Diaz case 's': 179870ce3ddSAntonio Nino Diaz str = va_arg(args, char *); 180870ce3ddSAntonio Nino Diaz string_print(&s, n, &chars_printed, str); 181870ce3ddSAntonio Nino Diaz break; 182870ce3ddSAntonio Nino Diaz case 'u': 183870ce3ddSAntonio Nino Diaz unum = va_arg(args, unsigned int); 184524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 185524eecc6SJavier Almansa Sobrino unum, 10, padc, padn, false); 186870ce3ddSAntonio Nino Diaz break; 187524eecc6SJavier Almansa Sobrino case 'p': 188524eecc6SJavier Almansa Sobrino unum = (uintptr_t)va_arg(args, void *); 189524eecc6SJavier Almansa Sobrino if (unum > 0U) { 190524eecc6SJavier Almansa Sobrino string_print(&s, n, &chars_printed, "0x"); 191524eecc6SJavier Almansa Sobrino padn -= 2; 192524eecc6SJavier Almansa Sobrino } 193524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 194524eecc6SJavier Almansa Sobrino unum, 16, padc, padn, false); 195524eecc6SJavier Almansa Sobrino break; 196524eecc6SJavier Almansa Sobrino case 'X': 197524eecc6SJavier Almansa Sobrino capitalise = true; 198524eecc6SJavier Almansa Sobrino case 'x': 199524eecc6SJavier Almansa Sobrino unum = va_arg(args, unsigned int); 200524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 201524eecc6SJavier Almansa Sobrino unum, 16, padc, padn, 202524eecc6SJavier Almansa Sobrino capitalise); 203524eecc6SJavier Almansa Sobrino break; 204524eecc6SJavier Almansa Sobrino 205870ce3ddSAntonio Nino Diaz default: 206870ce3ddSAntonio Nino Diaz /* Panic on any other format specifier. */ 207870ce3ddSAntonio Nino Diaz ERROR("snprintf: specifier with ASCII code '%d' not supported.", 208870ce3ddSAntonio Nino Diaz *fmt); 209870ce3ddSAntonio Nino Diaz plat_panic_handler(); 210a08a2014SDaniel Boulby assert(0); /* Unreachable */ 211870ce3ddSAntonio Nino Diaz } 212870ce3ddSAntonio Nino Diaz fmt++; 213870ce3ddSAntonio Nino Diaz continue; 214870ce3ddSAntonio Nino Diaz } 215870ce3ddSAntonio Nino Diaz 216*7981c504SHeyi Guo CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt); 217d5ccb754SAntonio Nino Diaz 218870ce3ddSAntonio Nino Diaz fmt++; 219870ce3ddSAntonio Nino Diaz } 220870ce3ddSAntonio Nino Diaz 22177648689SMadhukar Pappireddy if (n > 0U) { 222870ce3ddSAntonio Nino Diaz *s = '\0'; 22377648689SMadhukar Pappireddy } 224870ce3ddSAntonio Nino Diaz 225d5ccb754SAntonio Nino Diaz return (int)chars_printed; 226870ce3ddSAntonio Nino Diaz } 22777648689SMadhukar Pappireddy 22877648689SMadhukar Pappireddy /******************************************************************* 22977648689SMadhukar Pappireddy * Reduced snprintf to be used for Trusted firmware. 23077648689SMadhukar Pappireddy * The following type specifiers are supported: 23177648689SMadhukar Pappireddy * 23277648689SMadhukar Pappireddy * %x (or %X) - hexadecimal format 23377648689SMadhukar Pappireddy * %d or %i - signed decimal format 23477648689SMadhukar Pappireddy * %s - string format 23577648689SMadhukar Pappireddy * %u - unsigned decimal format 23677648689SMadhukar Pappireddy * %p - pointer format 23777648689SMadhukar Pappireddy * 23877648689SMadhukar Pappireddy * The following padding specifiers are supported by this print 23977648689SMadhukar Pappireddy * %0NN - Left-pad the number with 0s (NN is a decimal number) 24077648689SMadhukar Pappireddy * %NN - Left-pad the number or string with spaces (NN is a decimal number) 24177648689SMadhukar Pappireddy * %-NN - Right-pad the number or string with spaces (NN is a decimal number) 24277648689SMadhukar Pappireddy * 24377648689SMadhukar Pappireddy * The function panics on all other formats specifiers. 24477648689SMadhukar Pappireddy * 24577648689SMadhukar Pappireddy * It returns the number of characters that would be written if the 24677648689SMadhukar Pappireddy * buffer was big enough. If it returns a value lower than n, the 24777648689SMadhukar Pappireddy * whole string has been written. 24877648689SMadhukar Pappireddy *******************************************************************/ 24977648689SMadhukar Pappireddy int snprintf(char *s, size_t n, const char *fmt, ...) 25077648689SMadhukar Pappireddy { 25177648689SMadhukar Pappireddy int count; 25277648689SMadhukar Pappireddy va_list all_args; 25377648689SMadhukar Pappireddy 25477648689SMadhukar Pappireddy va_start(all_args, fmt); 25577648689SMadhukar Pappireddy count = vsnprintf(s, n, fmt, all_args); 25677648689SMadhukar Pappireddy va_end(all_args); 25777648689SMadhukar Pappireddy 25877648689SMadhukar Pappireddy return count; 25977648689SMadhukar Pappireddy } 260