1870ce3ddSAntonio Nino Diaz /* 2*d5ccb754SAntonio 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 7870ce3ddSAntonio Nino Diaz #include <debug.h> 8870ce3ddSAntonio Nino Diaz #include <platform.h> 9870ce3ddSAntonio Nino Diaz #include <stdarg.h> 10870ce3ddSAntonio Nino Diaz 11870ce3ddSAntonio Nino Diaz static void string_print(char **s, size_t n, size_t *chars_printed, 12870ce3ddSAntonio Nino Diaz const char *str) 13870ce3ddSAntonio Nino Diaz { 14*d5ccb754SAntonio Nino Diaz while (*str != '\0') { 15*d5ccb754SAntonio Nino Diaz if (*chars_printed < n) { 16*d5ccb754SAntonio Nino Diaz *(*s) = *str; 17*d5ccb754SAntonio Nino Diaz (*s)++; 18*d5ccb754SAntonio Nino Diaz } 19*d5ccb754SAntonio Nino Diaz 20870ce3ddSAntonio Nino Diaz (*chars_printed)++; 21870ce3ddSAntonio Nino Diaz str++; 22870ce3ddSAntonio Nino Diaz } 23870ce3ddSAntonio Nino Diaz } 24870ce3ddSAntonio Nino Diaz 25870ce3ddSAntonio Nino Diaz static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, 26870ce3ddSAntonio Nino Diaz unsigned int unum) 27870ce3ddSAntonio Nino Diaz { 28870ce3ddSAntonio Nino Diaz /* Enough for a 32-bit unsigned decimal integer (4294967295). */ 29*d5ccb754SAntonio Nino Diaz char num_buf[10]; 30*d5ccb754SAntonio Nino Diaz int i = 0; 31*d5ccb754SAntonio Nino Diaz unsigned int rem; 32870ce3ddSAntonio Nino Diaz 33870ce3ddSAntonio Nino Diaz do { 34*d5ccb754SAntonio Nino Diaz rem = unum % 10U; 35870ce3ddSAntonio Nino Diaz num_buf[i++] = '0' + rem; 36*d5ccb754SAntonio Nino Diaz unum /= 10U; 37*d5ccb754SAntonio Nino Diaz } while (unum > 0U); 38870ce3ddSAntonio Nino Diaz 39870ce3ddSAntonio Nino Diaz while (--i >= 0) { 40*d5ccb754SAntonio Nino Diaz if (*chars_printed < n) { 41*d5ccb754SAntonio Nino Diaz *(*s) = num_buf[i]; 42*d5ccb754SAntonio Nino Diaz (*s)++; 43*d5ccb754SAntonio Nino Diaz } 44*d5ccb754SAntonio Nino Diaz 45870ce3ddSAntonio Nino Diaz (*chars_printed)++; 46870ce3ddSAntonio Nino Diaz } 47870ce3ddSAntonio Nino Diaz } 48870ce3ddSAntonio Nino Diaz 49870ce3ddSAntonio Nino Diaz /******************************************************************* 50870ce3ddSAntonio Nino Diaz * Reduced snprintf to be used for Trusted firmware. 51870ce3ddSAntonio Nino Diaz * The following type specifiers are supported: 52870ce3ddSAntonio Nino Diaz * 53870ce3ddSAntonio Nino Diaz * %d or %i - signed decimal format 54870ce3ddSAntonio Nino Diaz * %s - string format 55870ce3ddSAntonio Nino Diaz * %u - unsigned decimal format 56870ce3ddSAntonio Nino Diaz * 57870ce3ddSAntonio Nino Diaz * The function panics on all other formats specifiers. 58870ce3ddSAntonio Nino Diaz * 59870ce3ddSAntonio Nino Diaz * It returns the number of characters that would be written if the 60870ce3ddSAntonio Nino Diaz * buffer was big enough. If it returns a value lower than n, the 61870ce3ddSAntonio Nino Diaz * whole string has been written. 62870ce3ddSAntonio Nino Diaz *******************************************************************/ 63870ce3ddSAntonio Nino Diaz int snprintf(char *s, size_t n, const char *fmt, ...) 64870ce3ddSAntonio Nino Diaz { 65870ce3ddSAntonio Nino Diaz va_list args; 66870ce3ddSAntonio Nino Diaz int num; 67870ce3ddSAntonio Nino Diaz unsigned int unum; 68870ce3ddSAntonio Nino Diaz char *str; 69*d5ccb754SAntonio Nino Diaz size_t chars_printed = 0U; 70870ce3ddSAntonio Nino Diaz 71*d5ccb754SAntonio Nino Diaz if (n == 0U) { 72*d5ccb754SAntonio Nino Diaz /* There isn't space for anything. */ 73*d5ccb754SAntonio Nino Diaz } else if (n == 1U) { 74870ce3ddSAntonio Nino Diaz /* Buffer is too small to actually write anything else. */ 75870ce3ddSAntonio Nino Diaz *s = '\0'; 76*d5ccb754SAntonio Nino Diaz n = 0U; 77*d5ccb754SAntonio Nino Diaz } else { 78870ce3ddSAntonio Nino Diaz /* Reserve space for the terminator character. */ 79870ce3ddSAntonio Nino Diaz n--; 80870ce3ddSAntonio Nino Diaz } 81870ce3ddSAntonio Nino Diaz 82870ce3ddSAntonio Nino Diaz va_start(args, fmt); 83*d5ccb754SAntonio Nino Diaz while (*fmt != '\0') { 84870ce3ddSAntonio Nino Diaz 85870ce3ddSAntonio Nino Diaz if (*fmt == '%') { 86870ce3ddSAntonio Nino Diaz fmt++; 87870ce3ddSAntonio Nino Diaz /* Check the format specifier. */ 88870ce3ddSAntonio Nino Diaz switch (*fmt) { 89870ce3ddSAntonio Nino Diaz case 'i': 90870ce3ddSAntonio Nino Diaz case 'd': 91870ce3ddSAntonio Nino Diaz num = va_arg(args, int); 92870ce3ddSAntonio Nino Diaz 93870ce3ddSAntonio Nino Diaz if (num < 0) { 94*d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 95*d5ccb754SAntonio Nino Diaz *s = '-'; 96*d5ccb754SAntonio Nino Diaz s++; 97*d5ccb754SAntonio Nino Diaz } 98870ce3ddSAntonio Nino Diaz chars_printed++; 99870ce3ddSAntonio Nino Diaz 100870ce3ddSAntonio Nino Diaz unum = (unsigned int)-num; 101870ce3ddSAntonio Nino Diaz } else { 102870ce3ddSAntonio Nino Diaz unum = (unsigned int)num; 103870ce3ddSAntonio Nino Diaz } 104870ce3ddSAntonio Nino Diaz 105870ce3ddSAntonio Nino Diaz unsigned_dec_print(&s, n, &chars_printed, unum); 106870ce3ddSAntonio Nino Diaz break; 107870ce3ddSAntonio Nino Diaz case 's': 108870ce3ddSAntonio Nino Diaz str = va_arg(args, char *); 109870ce3ddSAntonio Nino Diaz string_print(&s, n, &chars_printed, str); 110870ce3ddSAntonio Nino Diaz break; 111870ce3ddSAntonio Nino Diaz case 'u': 112870ce3ddSAntonio Nino Diaz unum = va_arg(args, unsigned int); 113870ce3ddSAntonio Nino Diaz unsigned_dec_print(&s, n, &chars_printed, unum); 114870ce3ddSAntonio Nino Diaz break; 115870ce3ddSAntonio Nino Diaz default: 116870ce3ddSAntonio Nino Diaz /* Panic on any other format specifier. */ 117870ce3ddSAntonio Nino Diaz ERROR("snprintf: specifier with ASCII code '%d' not supported.", 118870ce3ddSAntonio Nino Diaz *fmt); 119870ce3ddSAntonio Nino Diaz plat_panic_handler(); 120870ce3ddSAntonio Nino Diaz } 121870ce3ddSAntonio Nino Diaz fmt++; 122870ce3ddSAntonio Nino Diaz continue; 123870ce3ddSAntonio Nino Diaz } 124870ce3ddSAntonio Nino Diaz 125*d5ccb754SAntonio Nino Diaz if (chars_printed < n) { 126*d5ccb754SAntonio Nino Diaz *s = *fmt; 127*d5ccb754SAntonio Nino Diaz s++; 128*d5ccb754SAntonio Nino Diaz } 129*d5ccb754SAntonio Nino Diaz 130870ce3ddSAntonio Nino Diaz fmt++; 131870ce3ddSAntonio Nino Diaz chars_printed++; 132870ce3ddSAntonio Nino Diaz } 133870ce3ddSAntonio Nino Diaz 134870ce3ddSAntonio Nino Diaz va_end(args); 135870ce3ddSAntonio Nino Diaz 136*d5ccb754SAntonio Nino Diaz if (n > 0U) 137870ce3ddSAntonio Nino Diaz *s = '\0'; 138870ce3ddSAntonio Nino Diaz 139*d5ccb754SAntonio Nino Diaz return (int)chars_printed; 140870ce3ddSAntonio Nino Diaz } 141