1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdarg.h> 9 10 #include <common/debug.h> 11 #include <plat/common/platform.h> 12 13 static void string_print(char **s, size_t n, size_t *chars_printed, 14 const char *str) 15 { 16 while (*str != '\0') { 17 if (*chars_printed < n) { 18 *(*s) = *str; 19 (*s)++; 20 } 21 22 (*chars_printed)++; 23 str++; 24 } 25 } 26 27 static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, 28 unsigned int unum) 29 { 30 /* Enough for a 32-bit unsigned decimal integer (4294967295). */ 31 char num_buf[10]; 32 int i = 0; 33 unsigned int rem; 34 35 do { 36 rem = unum % 10U; 37 num_buf[i++] = '0' + rem; 38 unum /= 10U; 39 } while (unum > 0U); 40 41 while (--i >= 0) { 42 if (*chars_printed < n) { 43 *(*s) = num_buf[i]; 44 (*s)++; 45 } 46 47 (*chars_printed)++; 48 } 49 } 50 51 /******************************************************************* 52 * Reduced snprintf to be used for Trusted firmware. 53 * The following type specifiers are supported: 54 * 55 * %d or %i - signed decimal format 56 * %s - string format 57 * %u - unsigned decimal format 58 * 59 * The function panics on all other formats specifiers. 60 * 61 * It returns the number of characters that would be written if the 62 * buffer was big enough. If it returns a value lower than n, the 63 * whole string has been written. 64 *******************************************************************/ 65 int snprintf(char *s, size_t n, const char *fmt, ...) 66 { 67 va_list args; 68 int num; 69 unsigned int unum; 70 char *str; 71 size_t chars_printed = 0U; 72 73 if (n == 0U) { 74 /* There isn't space for anything. */ 75 } else if (n == 1U) { 76 /* Buffer is too small to actually write anything else. */ 77 *s = '\0'; 78 n = 0U; 79 } else { 80 /* Reserve space for the terminator character. */ 81 n--; 82 } 83 84 va_start(args, fmt); 85 while (*fmt != '\0') { 86 87 if (*fmt == '%') { 88 fmt++; 89 /* Check the format specifier. */ 90 switch (*fmt) { 91 case 'i': 92 case 'd': 93 num = va_arg(args, int); 94 95 if (num < 0) { 96 if (chars_printed < n) { 97 *s = '-'; 98 s++; 99 } 100 chars_printed++; 101 102 unum = (unsigned int)-num; 103 } else { 104 unum = (unsigned int)num; 105 } 106 107 unsigned_dec_print(&s, n, &chars_printed, unum); 108 break; 109 case 's': 110 str = va_arg(args, char *); 111 string_print(&s, n, &chars_printed, str); 112 break; 113 case 'u': 114 unum = va_arg(args, unsigned int); 115 unsigned_dec_print(&s, n, &chars_printed, unum); 116 break; 117 default: 118 /* Panic on any other format specifier. */ 119 ERROR("snprintf: specifier with ASCII code '%d' not supported.", 120 *fmt); 121 plat_panic_handler(); 122 assert(0); /* Unreachable */ 123 } 124 fmt++; 125 continue; 126 } 127 128 if (chars_printed < n) { 129 *s = *fmt; 130 s++; 131 } 132 133 fmt++; 134 chars_printed++; 135 } 136 137 va_end(args); 138 139 if (n > 0U) 140 *s = '\0'; 141 142 return (int)chars_printed; 143 } 144