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