printf.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <stdarg.h>
  8. #include <stdbool.h>
  9. #include <stddef.h>
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #define get_num_va_args(_args, _lcount) \
  13. (((_lcount) > 1) ? va_arg(_args, long long int) : \
  14. (((_lcount) == 1) ? va_arg(_args, long int) : \
  15. va_arg(_args, int)))
  16. #define get_unum_va_args(_args, _lcount) \
  17. (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \
  18. (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \
  19. va_arg(_args, unsigned int)))
  20. static int string_print(const char *str)
  21. {
  22. int count = 0;
  23. assert(str != NULL);
  24. for ( ; *str != '\0'; str++) {
  25. (void)putchar(*str);
  26. count++;
  27. }
  28. return count;
  29. }
  30. static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
  31. char padc, int padn, bool uppercase)
  32. {
  33. /* Just need enough space to store 64 bit decimal integer */
  34. char num_buf[20];
  35. int i = 0, count = 0;
  36. unsigned int rem;
  37. /* num_buf is only large enough for radix >= 10 */
  38. if (radix < 10) {
  39. assert(0);
  40. return 0;
  41. }
  42. do {
  43. rem = unum % radix;
  44. if (rem < 0xa) {
  45. num_buf[i] = '0' + rem;
  46. } else if (uppercase) {
  47. num_buf[i] = 'A' + (rem - 0xa);
  48. } else {
  49. num_buf[i] = 'a' + (rem - 0xa);
  50. }
  51. i++;
  52. unum /= radix;
  53. } while (unum > 0U);
  54. if (padn > 0) {
  55. while (i < padn) {
  56. (void)putchar(padc);
  57. count++;
  58. padn--;
  59. }
  60. }
  61. while (--i >= 0) {
  62. (void)putchar(num_buf[i]);
  63. count++;
  64. }
  65. return count;
  66. }
  67. /*******************************************************************
  68. * Reduced format print for Trusted firmware.
  69. * The following type specifiers are supported by this print
  70. * %x - hexadecimal format
  71. * %s - string format
  72. * %d or %i - signed decimal format
  73. * %c - character format
  74. * %u - unsigned decimal format
  75. * %p - pointer format
  76. *
  77. * The following length specifiers are supported by this print
  78. * %l - long int (64-bit on AArch64)
  79. * %ll - long long int (64-bit on AArch64)
  80. * %z - size_t sized integer formats (64 bit on AArch64)
  81. *
  82. * The following padding specifiers are supported by this print
  83. * %0NN - Left-pad the number with 0s (NN is a decimal number)
  84. * %NN - Left-pad the number with spaces (NN is a decimal number)
  85. *
  86. * The print exits on all other formats specifiers other than valid
  87. * combinations of the above specifiers.
  88. *******************************************************************/
  89. int vprintf(const char *fmt, va_list args)
  90. {
  91. int l_count;
  92. long long int num;
  93. unsigned long long int unum;
  94. char *str;
  95. char padc = '\0'; /* Padding character */
  96. int padn; /* Number of characters to pad */
  97. int count = 0; /* Number of printed characters */
  98. bool uppercase; /* Print characters in uppercase */
  99. while (*fmt != '\0') {
  100. uppercase = false;
  101. l_count = 0;
  102. padn = 0;
  103. if (*fmt == '%') {
  104. fmt++;
  105. /* Check the format specifier */
  106. loop:
  107. switch (*fmt) {
  108. case '%':
  109. (void)putchar('%');
  110. break;
  111. case 'i': /* Fall through to next one */
  112. case 'd':
  113. num = get_num_va_args(args, l_count);
  114. if (num < 0) {
  115. (void)putchar('-');
  116. unum = (unsigned long long int)-num;
  117. padn--;
  118. } else
  119. unum = (unsigned long long int)num;
  120. count += unsigned_num_print(unum, 10,
  121. padc, padn, uppercase);
  122. break;
  123. case 'c':
  124. (void)putchar(va_arg(args, int));
  125. count++;
  126. break;
  127. case 's':
  128. str = va_arg(args, char *);
  129. count += string_print(str);
  130. break;
  131. case 'p':
  132. unum = (uintptr_t)va_arg(args, void *);
  133. if (unum > 0U) {
  134. count += string_print("0x");
  135. padn -= 2;
  136. }
  137. count += unsigned_num_print(unum, 16,
  138. padc, padn, uppercase);
  139. break;
  140. case 'X':
  141. uppercase = true;
  142. // fall through
  143. case 'x':
  144. unum = get_unum_va_args(args, l_count);
  145. count += unsigned_num_print(unum, 16,
  146. padc, padn, uppercase);
  147. break;
  148. case 'z':
  149. if (sizeof(size_t) == 8U)
  150. l_count = 2;
  151. fmt++;
  152. goto loop;
  153. case 'l':
  154. l_count++;
  155. fmt++;
  156. goto loop;
  157. case 'u':
  158. unum = get_unum_va_args(args, l_count);
  159. count += unsigned_num_print(unum, 10,
  160. padc, padn, uppercase);
  161. break;
  162. case '0':
  163. padc = '0';
  164. padn = 0;
  165. fmt++;
  166. for (;;) {
  167. char ch = *fmt;
  168. if ((ch < '0') || (ch > '9')) {
  169. goto loop;
  170. }
  171. padn = (padn * 10) + (ch - '0');
  172. fmt++;
  173. }
  174. assert(0); /* Unreachable */
  175. case '1':
  176. case '2':
  177. case '3':
  178. case '4':
  179. case '5':
  180. case '6':
  181. case '7':
  182. case '8':
  183. case '9':
  184. padc = ' ';
  185. padn = 0;
  186. for (;;) {
  187. char ch = *fmt;
  188. if ((ch < '0') || (ch > '9')) {
  189. goto loop;
  190. }
  191. padn = (padn * 10) + (ch - '0');
  192. fmt++;
  193. }
  194. assert(0); /* Unreachable */
  195. default:
  196. /* Exit on any other format specifier */
  197. return -1;
  198. }
  199. fmt++;
  200. continue;
  201. }
  202. (void)putchar(*fmt);
  203. fmt++;
  204. count++;
  205. }
  206. return count;
  207. }
  208. int printf(const char *fmt, ...)
  209. {
  210. int count;
  211. va_list va;
  212. va_start(va, fmt);
  213. count = vprintf(fmt, va);
  214. va_end(va);
  215. return count;
  216. }