tiny-printf.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Tiny printf version for SPL
  3. *
  4. * Copied from:
  5. * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
  6. *
  7. * Copyright (C) 2004,2008 Kustaa Nyholm
  8. *
  9. * SPDX-License-Identifier: LGPL-2.1+
  10. */
  11. #include <common.h>
  12. #include <stdarg.h>
  13. #include <serial.h>
  14. /*
  15. * This code in here may execute before the DRAM is initialised, so
  16. * we should make sure that it doesn't touch BSS, which some boards
  17. * put in DRAM.
  18. */
  19. static char *bf __attribute__ ((section(".data")));
  20. static char zs __attribute__ ((section(".data")));
  21. /* Current position in sprintf() output string */
  22. static char *outstr __attribute__ ((section(".data")));
  23. static void out(char c)
  24. {
  25. *bf++ = c;
  26. }
  27. static void out_dgt(char dgt)
  28. {
  29. out(dgt + (dgt < 10 ? '0' : 'a' - 10));
  30. zs = 1;
  31. }
  32. static void div_out(unsigned int *num, unsigned int div)
  33. {
  34. unsigned char dgt = 0;
  35. while (*num >= div) {
  36. *num -= div;
  37. dgt++;
  38. }
  39. if (zs || dgt > 0)
  40. out_dgt(dgt);
  41. }
  42. int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
  43. {
  44. char ch;
  45. char *p;
  46. unsigned int num;
  47. char buf[12];
  48. unsigned int div;
  49. while ((ch = *(fmt++))) {
  50. if (ch != '%') {
  51. putc(ch);
  52. } else {
  53. bool lz = false;
  54. int width = 0;
  55. ch = *(fmt++);
  56. if (ch == '0') {
  57. ch = *(fmt++);
  58. lz = 1;
  59. }
  60. if (ch >= '0' && ch <= '9') {
  61. width = 0;
  62. while (ch >= '0' && ch <= '9') {
  63. width = (width * 10) + ch - '0';
  64. ch = *fmt++;
  65. }
  66. }
  67. bf = buf;
  68. p = bf;
  69. zs = 0;
  70. switch (ch) {
  71. case '\0':
  72. goto abort;
  73. case 'u':
  74. case 'd':
  75. num = va_arg(va, unsigned int);
  76. if (ch == 'd' && (int)num < 0) {
  77. num = -(int)num;
  78. out('-');
  79. }
  80. if (!num) {
  81. out_dgt(0);
  82. } else {
  83. for (div = 1000000000; div; div /= 10)
  84. div_out(&num, div);
  85. }
  86. break;
  87. case 'x':
  88. num = va_arg(va, unsigned int);
  89. if (!num) {
  90. out_dgt(0);
  91. } else {
  92. for (div = 0x10000000; div; div /= 0x10)
  93. div_out(&num, div);
  94. }
  95. break;
  96. case 'c':
  97. out((char)(va_arg(va, int)));
  98. break;
  99. case 's':
  100. p = va_arg(va, char*);
  101. break;
  102. case '%':
  103. out('%');
  104. default:
  105. break;
  106. }
  107. *bf = 0;
  108. bf = p;
  109. while (*bf++ && width > 0)
  110. width--;
  111. while (width-- > 0)
  112. putc(lz ? '0' : ' ');
  113. if (p) {
  114. while ((ch = *p++))
  115. putc(ch);
  116. }
  117. }
  118. }
  119. abort:
  120. return 0;
  121. }
  122. int vprintf(const char *fmt, va_list va)
  123. {
  124. return _vprintf(fmt, va, putc);
  125. }
  126. int printf(const char *fmt, ...)
  127. {
  128. va_list va;
  129. int ret;
  130. va_start(va, fmt);
  131. ret = _vprintf(fmt, va, putc);
  132. va_end(va);
  133. return ret;
  134. }
  135. static void putc_outstr(char ch)
  136. {
  137. *outstr++ = ch;
  138. }
  139. int sprintf(char *buf, const char *fmt, ...)
  140. {
  141. va_list va;
  142. int ret;
  143. va_start(va, fmt);
  144. outstr = buf;
  145. ret = _vprintf(fmt, va, putc_outstr);
  146. va_end(va);
  147. *outstr = '\0';
  148. return ret;
  149. }
  150. /* Note that size is ignored */
  151. int snprintf(char *buf, size_t size, const char *fmt, ...)
  152. {
  153. va_list va;
  154. int ret;
  155. va_start(va, fmt);
  156. outstr = buf;
  157. ret = _vprintf(fmt, va, putc_outstr);
  158. va_end(va);
  159. *outstr = '\0';
  160. return ret;
  161. }