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