1870ce3ddSAntonio Nino Diaz /* 2d5ccb754SAntonio Nino Diaz * Copyright (c) 2017-2018, 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 7*a08a2014SDaniel Boulby #include <assert.h> 8870ce3ddSAntonio Nino Diaz #include <debug.h> 9870ce3ddSAntonio Nino Diaz #include <platform.h> 10870ce3ddSAntonio Nino Diaz #include <stdarg.h> 11870ce3ddSAntonio Nino Diaz 12870ce3ddSAntonio Nino Diaz static void string_print(char **s, size_t n, size_t *chars_printed, 13870ce3ddSAntonio Nino Diaz const char *str) 14870ce3ddSAntonio Nino Diaz { 15d5ccb754SAntonio Nino Diaz while (*str != '\0') { 16d5ccb754SAntonio Nino Diaz if (*chars_printed < n) { 17d5ccb754SAntonio Nino Diaz *(*s) = *str; 18d5ccb754SAntonio Nino Diaz (*s)++; 19d5ccb754SAntonio Nino Diaz } 20d5ccb754SAntonio Nino Diaz 21870ce3ddSAntonio Nino Diaz (*chars_printed)++; 22870ce3ddSAntonio Nino Diaz str++; 23870ce3ddSAntonio Nino Diaz } 24870ce3ddSAntonio Nino Diaz } 25870ce3ddSAntonio Nino Diaz 26870ce3ddSAntonio Nino Diaz static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, 27870ce3ddSAntonio Nino Diaz unsigned int unum) 28870ce3ddSAntonio Nino Diaz { 29870ce3ddSAntonio Nino Diaz /* Enough for a 32-bit unsigned decimal integer (4294967295). */ 30d5ccb754SAntonio Nino Diaz char num_buf[10]; 31d5ccb754SAntonio Nino Diaz int i = 0; 32d5ccb754SAntonio Nino Diaz unsigned int rem; 33870ce3ddSAntonio Nino Diaz 34870ce3ddSAntonio Nino Diaz do { 35d5ccb754SAntonio Nino Diaz rem = unum % 10U; 36870ce3ddSAntonio Nino Diaz num_buf[i++] = '0' + rem; 37d5ccb754SAntonio Nino Diaz unum /= 10U; 38d5ccb754SAntonio Nino Diaz } while (unum > 0U); 39870ce3ddSAntonio Nino Diaz 40870ce3ddSAntonio Nino Diaz while (--i >= 0) { 41d5ccb754SAntonio Nino Diaz if (*chars_printed < n) { 42d5ccb754SAntonio Nino Diaz *(*s) = num_buf[i]; 43d5ccb754SAntonio Nino Diaz (*s)++; 44d5ccb754SAntonio Nino Diaz } 45d5ccb754SAntonio Nino Diaz 46870ce3ddSAntonio Nino Diaz (*chars_printed)++; 47870ce3ddSAntonio Nino Diaz } 48870ce3ddSAntonio Nino Diaz } 49870ce3ddSAntonio Nino Diaz 50870ce3ddSAntonio Nino Diaz /******************************************************************* 51870ce3ddSAntonio Nino Diaz * Reduced snprintf to be used for Trusted firmware. 52870ce3ddSAntonio Nino Diaz * The following type specifiers are supported: 53870ce3ddSAntonio Nino Diaz * 54870ce3ddSAntonio Nino Diaz * %d or %i - signed decimal format 55870ce3ddSAntonio Nino Diaz * %s - string format 56870ce3ddSAntonio Nino Diaz * %u - unsigned decimal format 57870ce3ddSAntonio Nino Diaz * 58870ce3ddSAntonio Nino Diaz * The function panics on all other formats specifiers. 59870ce3ddSAntonio Nino Diaz * 60870ce3ddSAntonio Nino Diaz * It returns the number of characters that would be written if the 61870ce3ddSAntonio Nino Diaz * buffer was big enough. If it returns a value lower than n, the 62870ce3ddSAntonio Nino Diaz * whole string has been written. 63870ce3ddSAntonio Nino Diaz *******************************************************************/ 64870ce3ddSAntonio Nino Diaz int snprintf(char *s, size_t n, const char *fmt, ...) 65870ce3ddSAntonio Nino Diaz { 66870ce3ddSAntonio Nino Diaz va_list args; 67870ce3ddSAntonio Nino Diaz int num; 68870ce3ddSAntonio Nino Diaz unsigned int unum; 69870ce3ddSAntonio Nino Diaz char *str; 70d5ccb754SAntonio Nino Diaz size_t chars_printed = 0U; 71870ce3ddSAntonio Nino Diaz 72d5ccb754SAntonio Nino Diaz if (n == 0U) { 73d5ccb754SAntonio Nino Diaz /* There isn't space for anything. */ 74d5ccb754SAntonio Nino Diaz } else if (n == 1U) { 75870ce3ddSAntonio Nino Diaz /* Buffer is too small to actually write anything else. */ 76870ce3ddSAntonio Nino Diaz *s = '\0'; 77d5ccb754SAntonio Nino Diaz n = 0U; 78d5ccb754SAntonio Nino Diaz } else { 79870ce3ddSAntonio Nino Diaz /* Reserve space for the terminator character. */ 80870ce3ddSAntonio Nino Diaz n--; 81870ce3ddSAntonio Nino Diaz } 82870ce3ddSAntonio Nino Diaz 83870ce3ddSAntonio Nino Diaz va_start(args, fmt); 84d5ccb754SAntonio Nino Diaz while (*fmt != '\0') { 85870ce3ddSAntonio Nino Diaz 86870ce3ddSAntonio Nino Diaz if (*fmt == '%') { 87870ce3ddSAntonio Nino Diaz fmt++; 88870ce3ddSAntonio Nino Diaz /* Check the format specifier. */ 89870ce3ddSAntonio Nino Diaz switch (*fmt) { 90870ce3ddSAntonio Nino Diaz case 'i': 91870ce3ddSAntonio Nino Diaz case 'd': 92870ce3ddSAntonio Nino Diaz num = va_arg(args, int); 93870ce3ddSAntonio Nino Diaz 94870ce3ddSAntonio Nino Diaz if (num < 0) { 95d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 96d5ccb754SAntonio Nino Diaz *s = '-'; 97d5ccb754SAntonio Nino Diaz s++; 98d5ccb754SAntonio Nino Diaz } 99870ce3ddSAntonio Nino Diaz chars_printed++; 100870ce3ddSAntonio Nino Diaz 101870ce3ddSAntonio Nino Diaz unum = (unsigned int)-num; 102870ce3ddSAntonio Nino Diaz } else { 103870ce3ddSAntonio Nino Diaz unum = (unsigned int)num; 104870ce3ddSAntonio Nino Diaz } 105870ce3ddSAntonio Nino Diaz 106870ce3ddSAntonio Nino Diaz unsigned_dec_print(&s, n, &chars_printed, unum); 107870ce3ddSAntonio Nino Diaz break; 108870ce3ddSAntonio Nino Diaz case 's': 109870ce3ddSAntonio Nino Diaz str = va_arg(args, char *); 110870ce3ddSAntonio Nino Diaz string_print(&s, n, &chars_printed, str); 111870ce3ddSAntonio Nino Diaz break; 112870ce3ddSAntonio Nino Diaz case 'u': 113870ce3ddSAntonio Nino Diaz unum = va_arg(args, unsigned int); 114870ce3ddSAntonio Nino Diaz unsigned_dec_print(&s, n, &chars_printed, unum); 115870ce3ddSAntonio Nino Diaz break; 116870ce3ddSAntonio Nino Diaz default: 117870ce3ddSAntonio Nino Diaz /* Panic on any other format specifier. */ 118870ce3ddSAntonio Nino Diaz ERROR("snprintf: specifier with ASCII code '%d' not supported.", 119870ce3ddSAntonio Nino Diaz *fmt); 120870ce3ddSAntonio Nino Diaz plat_panic_handler(); 121*a08a2014SDaniel Boulby assert(0); /* Unreachable */ 122870ce3ddSAntonio Nino Diaz } 123870ce3ddSAntonio Nino Diaz fmt++; 124870ce3ddSAntonio Nino Diaz continue; 125870ce3ddSAntonio Nino Diaz } 126870ce3ddSAntonio Nino Diaz 127d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 128d5ccb754SAntonio Nino Diaz *s = *fmt; 129d5ccb754SAntonio Nino Diaz s++; 130d5ccb754SAntonio Nino Diaz } 131d5ccb754SAntonio Nino Diaz 132870ce3ddSAntonio Nino Diaz fmt++; 133870ce3ddSAntonio Nino Diaz chars_printed++; 134870ce3ddSAntonio Nino Diaz } 135870ce3ddSAntonio Nino Diaz 136870ce3ddSAntonio Nino Diaz va_end(args); 137870ce3ddSAntonio Nino Diaz 138d5ccb754SAntonio Nino Diaz if (n > 0U) 139870ce3ddSAntonio Nino Diaz *s = '\0'; 140870ce3ddSAntonio Nino Diaz 141d5ccb754SAntonio Nino Diaz return (int)chars_printed; 142870ce3ddSAntonio Nino Diaz } 143