1870ce3ddSAntonio Nino Diaz /* 2524eecc6SJavier Almansa Sobrino * Copyright (c) 2017-2020, 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 13870ce3ddSAntonio Nino Diaz static void string_print(char **s, size_t n, size_t *chars_printed, 14870ce3ddSAntonio Nino Diaz const char *str) 15870ce3ddSAntonio Nino Diaz { 16d5ccb754SAntonio Nino Diaz while (*str != '\0') { 17d5ccb754SAntonio Nino Diaz if (*chars_printed < n) { 18d5ccb754SAntonio Nino Diaz *(*s) = *str; 19d5ccb754SAntonio Nino Diaz (*s)++; 20d5ccb754SAntonio Nino Diaz } 21d5ccb754SAntonio Nino Diaz 22870ce3ddSAntonio Nino Diaz (*chars_printed)++; 23870ce3ddSAntonio Nino Diaz str++; 24870ce3ddSAntonio Nino Diaz } 25870ce3ddSAntonio Nino Diaz } 26870ce3ddSAntonio Nino Diaz 27524eecc6SJavier Almansa Sobrino static void unsigned_num_print(char **s, size_t n, size_t *chars_printed, 28524eecc6SJavier Almansa Sobrino unsigned long long int unum, 29524eecc6SJavier Almansa Sobrino unsigned int radix, char padc, int padn, 30524eecc6SJavier Almansa Sobrino bool capitalise) 31870ce3ddSAntonio Nino Diaz { 32524eecc6SJavier Almansa Sobrino /* Just need enough space to store 64 bit decimal integer */ 33524eecc6SJavier Almansa Sobrino char num_buf[20]; 34d5ccb754SAntonio Nino Diaz int i = 0; 35524eecc6SJavier Almansa Sobrino int width; 36d5ccb754SAntonio Nino Diaz unsigned int rem; 37524eecc6SJavier Almansa Sobrino char ascii_a = capitalise ? 'A' : 'a'; 38870ce3ddSAntonio Nino Diaz 39870ce3ddSAntonio Nino Diaz do { 40524eecc6SJavier Almansa Sobrino rem = unum % radix; 41524eecc6SJavier Almansa Sobrino if (rem < 10U) { 42524eecc6SJavier Almansa Sobrino num_buf[i] = '0' + rem; 43524eecc6SJavier Almansa Sobrino } else { 44524eecc6SJavier Almansa Sobrino num_buf[i] = ascii_a + (rem - 10U); 45524eecc6SJavier Almansa Sobrino } 46524eecc6SJavier Almansa Sobrino i++; 47524eecc6SJavier Almansa Sobrino unum /= radix; 48d5ccb754SAntonio Nino Diaz } while (unum > 0U); 49870ce3ddSAntonio Nino Diaz 50524eecc6SJavier Almansa Sobrino width = i; 51524eecc6SJavier Almansa Sobrino if (padn > width) { 52524eecc6SJavier Almansa Sobrino (*chars_printed) += (size_t)padn; 53524eecc6SJavier Almansa Sobrino } else { 54524eecc6SJavier Almansa Sobrino (*chars_printed) += (size_t)width; 55d5ccb754SAntonio Nino Diaz } 56d5ccb754SAntonio Nino Diaz 57524eecc6SJavier Almansa Sobrino if (*chars_printed < n) { 58524eecc6SJavier Almansa Sobrino 59524eecc6SJavier Almansa Sobrino if (padn > 0) { 60524eecc6SJavier Almansa Sobrino while (width < padn) { 61524eecc6SJavier Almansa Sobrino *(*s)++ = padc; 62524eecc6SJavier Almansa Sobrino padn--; 63524eecc6SJavier Almansa Sobrino } 64524eecc6SJavier Almansa Sobrino } 65524eecc6SJavier Almansa Sobrino 66524eecc6SJavier Almansa Sobrino while (--i >= 0) { 67524eecc6SJavier Almansa Sobrino *(*s)++ = num_buf[i]; 68524eecc6SJavier Almansa Sobrino } 69524eecc6SJavier Almansa Sobrino 70524eecc6SJavier Almansa Sobrino if (padn < 0) { 71524eecc6SJavier Almansa Sobrino while (width < -padn) { 72524eecc6SJavier Almansa Sobrino *(*s)++ = padc; 73524eecc6SJavier Almansa Sobrino padn++; 74524eecc6SJavier Almansa Sobrino } 75524eecc6SJavier Almansa Sobrino } 76870ce3ddSAntonio Nino Diaz } 77870ce3ddSAntonio Nino Diaz } 78870ce3ddSAntonio Nino Diaz 79870ce3ddSAntonio Nino Diaz /******************************************************************* 80*77648689SMadhukar Pappireddy * Reduced vsnprintf to be used for Trusted firmware. 81870ce3ddSAntonio Nino Diaz * The following type specifiers are supported: 82870ce3ddSAntonio Nino Diaz * 83524eecc6SJavier Almansa Sobrino * %x (or %X) - hexadecimal format 84870ce3ddSAntonio Nino Diaz * %d or %i - signed decimal format 85870ce3ddSAntonio Nino Diaz * %s - string format 86870ce3ddSAntonio Nino Diaz * %u - unsigned decimal format 87524eecc6SJavier Almansa Sobrino * %p - pointer format 88524eecc6SJavier Almansa Sobrino * 89524eecc6SJavier Almansa Sobrino * The following padding specifiers are supported by this print 90524eecc6SJavier Almansa Sobrino * %0NN - Left-pad the number with 0s (NN is a decimal number) 91524eecc6SJavier Almansa Sobrino * %NN - Left-pad the number or string with spaces (NN is a decimal number) 92524eecc6SJavier Almansa Sobrino * %-NN - Right-pad the number or string with spaces (NN is a decimal number) 93870ce3ddSAntonio Nino Diaz * 94870ce3ddSAntonio Nino Diaz * The function panics on all other formats specifiers. 95870ce3ddSAntonio Nino Diaz * 96870ce3ddSAntonio Nino Diaz * It returns the number of characters that would be written if the 97870ce3ddSAntonio Nino Diaz * buffer was big enough. If it returns a value lower than n, the 98870ce3ddSAntonio Nino Diaz * whole string has been written. 99870ce3ddSAntonio Nino Diaz *******************************************************************/ 100*77648689SMadhukar Pappireddy int vsnprintf(char *s, size_t n, const char *fmt, va_list args) 101870ce3ddSAntonio Nino Diaz { 102870ce3ddSAntonio Nino Diaz int num; 103524eecc6SJavier Almansa Sobrino unsigned long long int unum; 104870ce3ddSAntonio Nino Diaz char *str; 105524eecc6SJavier Almansa Sobrino char padc; /* Padding character */ 106524eecc6SJavier Almansa Sobrino int padn; /* Number of characters to pad */ 107524eecc6SJavier Almansa Sobrino bool left; 108524eecc6SJavier Almansa Sobrino bool capitalise; 109d5ccb754SAntonio Nino Diaz size_t chars_printed = 0U; 110870ce3ddSAntonio Nino Diaz 111d5ccb754SAntonio Nino Diaz if (n == 0U) { 112d5ccb754SAntonio Nino Diaz /* There isn't space for anything. */ 113d5ccb754SAntonio Nino Diaz } else if (n == 1U) { 114870ce3ddSAntonio Nino Diaz /* Buffer is too small to actually write anything else. */ 115870ce3ddSAntonio Nino Diaz *s = '\0'; 116d5ccb754SAntonio Nino Diaz n = 0U; 117d5ccb754SAntonio Nino Diaz } else { 118870ce3ddSAntonio Nino Diaz /* Reserve space for the terminator character. */ 119870ce3ddSAntonio Nino Diaz n--; 120870ce3ddSAntonio Nino Diaz } 121870ce3ddSAntonio Nino Diaz 122d5ccb754SAntonio Nino Diaz while (*fmt != '\0') { 123524eecc6SJavier Almansa Sobrino left = false; 124524eecc6SJavier Almansa Sobrino padc ='\0'; 125524eecc6SJavier Almansa Sobrino padn = 0; 126524eecc6SJavier Almansa Sobrino capitalise = false; 127870ce3ddSAntonio Nino Diaz 128870ce3ddSAntonio Nino Diaz if (*fmt == '%') { 129870ce3ddSAntonio Nino Diaz fmt++; 130870ce3ddSAntonio Nino Diaz /* Check the format specifier. */ 131524eecc6SJavier Almansa Sobrino loop: 132870ce3ddSAntonio Nino Diaz switch (*fmt) { 133524eecc6SJavier Almansa Sobrino case '0': 134524eecc6SJavier Almansa Sobrino case '1': 135524eecc6SJavier Almansa Sobrino case '2': 136524eecc6SJavier Almansa Sobrino case '3': 137524eecc6SJavier Almansa Sobrino case '4': 138524eecc6SJavier Almansa Sobrino case '5': 139524eecc6SJavier Almansa Sobrino case '6': 140524eecc6SJavier Almansa Sobrino case '7': 141524eecc6SJavier Almansa Sobrino case '8': 142524eecc6SJavier Almansa Sobrino case '9': 143524eecc6SJavier Almansa Sobrino padc = (*fmt == '0') ? '0' : ' '; 144524eecc6SJavier Almansa Sobrino for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) { 145524eecc6SJavier Almansa Sobrino padn = (padn * 10) + (*fmt - '0'); 146524eecc6SJavier Almansa Sobrino } 147524eecc6SJavier Almansa Sobrino if (left) { 148524eecc6SJavier Almansa Sobrino padn = -padn; 149524eecc6SJavier Almansa Sobrino } 150524eecc6SJavier Almansa Sobrino goto loop; 151524eecc6SJavier Almansa Sobrino case '-': 152524eecc6SJavier Almansa Sobrino left = true; 153524eecc6SJavier Almansa Sobrino fmt++; 154524eecc6SJavier Almansa Sobrino goto loop; 155524eecc6SJavier Almansa Sobrino 156870ce3ddSAntonio Nino Diaz case 'i': 157870ce3ddSAntonio Nino Diaz case 'd': 158870ce3ddSAntonio Nino Diaz num = va_arg(args, int); 159870ce3ddSAntonio Nino Diaz 160870ce3ddSAntonio Nino Diaz if (num < 0) { 161d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 162d5ccb754SAntonio Nino Diaz *s = '-'; 163d5ccb754SAntonio Nino Diaz s++; 164d5ccb754SAntonio Nino Diaz } 165870ce3ddSAntonio Nino Diaz chars_printed++; 166870ce3ddSAntonio Nino Diaz 167870ce3ddSAntonio Nino Diaz unum = (unsigned int)-num; 168870ce3ddSAntonio Nino Diaz } else { 169870ce3ddSAntonio Nino Diaz unum = (unsigned int)num; 170870ce3ddSAntonio Nino Diaz } 171870ce3ddSAntonio Nino Diaz 172524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 173524eecc6SJavier Almansa Sobrino unum, 10, padc, padn, false); 174870ce3ddSAntonio Nino Diaz break; 175870ce3ddSAntonio Nino Diaz case 's': 176870ce3ddSAntonio Nino Diaz str = va_arg(args, char *); 177870ce3ddSAntonio Nino Diaz string_print(&s, n, &chars_printed, str); 178870ce3ddSAntonio Nino Diaz break; 179870ce3ddSAntonio Nino Diaz case 'u': 180870ce3ddSAntonio Nino Diaz unum = va_arg(args, unsigned int); 181524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 182524eecc6SJavier Almansa Sobrino unum, 10, padc, padn, false); 183870ce3ddSAntonio Nino Diaz break; 184524eecc6SJavier Almansa Sobrino case 'p': 185524eecc6SJavier Almansa Sobrino unum = (uintptr_t)va_arg(args, void *); 186524eecc6SJavier Almansa Sobrino if (unum > 0U) { 187524eecc6SJavier Almansa Sobrino string_print(&s, n, &chars_printed, "0x"); 188524eecc6SJavier Almansa Sobrino padn -= 2; 189524eecc6SJavier Almansa Sobrino } 190524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 191524eecc6SJavier Almansa Sobrino unum, 16, padc, padn, false); 192524eecc6SJavier Almansa Sobrino break; 193524eecc6SJavier Almansa Sobrino case 'X': 194524eecc6SJavier Almansa Sobrino capitalise = true; 195524eecc6SJavier Almansa Sobrino case 'x': 196524eecc6SJavier Almansa Sobrino unum = va_arg(args, unsigned int); 197524eecc6SJavier Almansa Sobrino unsigned_num_print(&s, n, &chars_printed, 198524eecc6SJavier Almansa Sobrino unum, 16, padc, padn, 199524eecc6SJavier Almansa Sobrino capitalise); 200524eecc6SJavier Almansa Sobrino break; 201524eecc6SJavier Almansa Sobrino 202870ce3ddSAntonio Nino Diaz default: 203870ce3ddSAntonio Nino Diaz /* Panic on any other format specifier. */ 204870ce3ddSAntonio Nino Diaz ERROR("snprintf: specifier with ASCII code '%d' not supported.", 205870ce3ddSAntonio Nino Diaz *fmt); 206870ce3ddSAntonio Nino Diaz plat_panic_handler(); 207a08a2014SDaniel Boulby assert(0); /* Unreachable */ 208870ce3ddSAntonio Nino Diaz } 209870ce3ddSAntonio Nino Diaz fmt++; 210870ce3ddSAntonio Nino Diaz continue; 211870ce3ddSAntonio Nino Diaz } 212870ce3ddSAntonio Nino Diaz 213d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 214d5ccb754SAntonio Nino Diaz *s = *fmt; 215d5ccb754SAntonio Nino Diaz s++; 216d5ccb754SAntonio Nino Diaz } 217d5ccb754SAntonio Nino Diaz 218870ce3ddSAntonio Nino Diaz fmt++; 219870ce3ddSAntonio Nino Diaz chars_printed++; 220870ce3ddSAntonio Nino Diaz } 221870ce3ddSAntonio Nino Diaz 222*77648689SMadhukar Pappireddy if (n > 0U) { 223870ce3ddSAntonio Nino Diaz *s = '\0'; 224*77648689SMadhukar Pappireddy } 225870ce3ddSAntonio Nino Diaz 226d5ccb754SAntonio Nino Diaz return (int)chars_printed; 227870ce3ddSAntonio Nino Diaz } 228*77648689SMadhukar Pappireddy 229*77648689SMadhukar Pappireddy /******************************************************************* 230*77648689SMadhukar Pappireddy * Reduced snprintf to be used for Trusted firmware. 231*77648689SMadhukar Pappireddy * The following type specifiers are supported: 232*77648689SMadhukar Pappireddy * 233*77648689SMadhukar Pappireddy * %x (or %X) - hexadecimal format 234*77648689SMadhukar Pappireddy * %d or %i - signed decimal format 235*77648689SMadhukar Pappireddy * %s - string format 236*77648689SMadhukar Pappireddy * %u - unsigned decimal format 237*77648689SMadhukar Pappireddy * %p - pointer format 238*77648689SMadhukar Pappireddy * 239*77648689SMadhukar Pappireddy * The following padding specifiers are supported by this print 240*77648689SMadhukar Pappireddy * %0NN - Left-pad the number with 0s (NN is a decimal number) 241*77648689SMadhukar Pappireddy * %NN - Left-pad the number or string with spaces (NN is a decimal number) 242*77648689SMadhukar Pappireddy * %-NN - Right-pad the number or string with spaces (NN is a decimal number) 243*77648689SMadhukar Pappireddy * 244*77648689SMadhukar Pappireddy * The function panics on all other formats specifiers. 245*77648689SMadhukar Pappireddy * 246*77648689SMadhukar Pappireddy * It returns the number of characters that would be written if the 247*77648689SMadhukar Pappireddy * buffer was big enough. If it returns a value lower than n, the 248*77648689SMadhukar Pappireddy * whole string has been written. 249*77648689SMadhukar Pappireddy *******************************************************************/ 250*77648689SMadhukar Pappireddy int snprintf(char *s, size_t n, const char *fmt, ...) 251*77648689SMadhukar Pappireddy { 252*77648689SMadhukar Pappireddy int count; 253*77648689SMadhukar Pappireddy va_list all_args; 254*77648689SMadhukar Pappireddy 255*77648689SMadhukar Pappireddy va_start(all_args, fmt); 256*77648689SMadhukar Pappireddy count = vsnprintf(s, n, fmt, all_args); 257*77648689SMadhukar Pappireddy va_end(all_args); 258*77648689SMadhukar Pappireddy 259*77648689SMadhukar Pappireddy return count; 260*77648689SMadhukar Pappireddy } 261