tiny-printf.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. static char *bf;
  15. static char zs;
  16. /* Current position in sprintf() output string */
  17. static char *outstr;
  18. static void out(char c)
  19. {
  20. *bf++ = c;
  21. }
  22. static void out_dgt(char dgt)
  23. {
  24. out(dgt + (dgt < 10 ? '0' : 'a' - 10));
  25. zs = 1;
  26. }
  27. static void div_out(unsigned int *num, unsigned int div)
  28. {
  29. unsigned char dgt = 0;
  30. while (*num >= div) {
  31. *num -= div;
  32. dgt++;
  33. }
  34. if (zs || dgt > 0)
  35. out_dgt(dgt);
  36. }
  37. int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
  38. {
  39. char ch;
  40. char *p;
  41. unsigned int num;
  42. char buf[12];
  43. unsigned int div;
  44. while ((ch = *(fmt++))) {
  45. if (ch != '%') {
  46. putc(ch);
  47. } else {
  48. bool lz = false;
  49. int width = 0;
  50. ch = *(fmt++);
  51. if (ch == '0') {
  52. ch = *(fmt++);
  53. lz = 1;
  54. }
  55. if (ch >= '0' && ch <= '9') {
  56. width = 0;
  57. while (ch >= '0' && ch <= '9') {
  58. width = (width * 10) + ch - '0';
  59. ch = *fmt++;
  60. }
  61. }
  62. bf = buf;
  63. p = bf;
  64. zs = 0;
  65. switch (ch) {
  66. case '\0':
  67. goto abort;
  68. case 'u':
  69. case 'd':
  70. num = va_arg(va, unsigned int);
  71. if (ch == 'd' && (int)num < 0) {
  72. num = -(int)num;
  73. out('-');
  74. }
  75. if (!num) {
  76. out_dgt(0);
  77. } else {
  78. for (div = 1000000000; div; div /= 10)
  79. div_out(&num, div);
  80. }
  81. break;
  82. case 'x':
  83. num = va_arg(va, unsigned int);
  84. if (!num) {
  85. out_dgt(0);
  86. } else {
  87. for (div = 0x10000000; div; div /= 0x10)
  88. div_out(&num, div);
  89. }
  90. break;
  91. case 'c':
  92. out((char)(va_arg(va, int)));
  93. break;
  94. case 's':
  95. p = va_arg(va, char*);
  96. break;
  97. case '%':
  98. out('%');
  99. default:
  100. break;
  101. }
  102. *bf = 0;
  103. bf = p;
  104. while (*bf++ && width > 0)
  105. width--;
  106. while (width-- > 0)
  107. putc(lz ? '0' : ' ');
  108. if (p) {
  109. while ((ch = *p++))
  110. putc(ch);
  111. }
  112. }
  113. }
  114. abort:
  115. return 0;
  116. }
  117. int printf(const char *fmt, ...)
  118. {
  119. va_list va;
  120. int ret;
  121. va_start(va, fmt);
  122. ret = _vprintf(fmt, va, putc);
  123. va_end(va);
  124. return ret;
  125. }
  126. static void putc_outstr(char ch)
  127. {
  128. *outstr++ = ch;
  129. }
  130. int sprintf(char *buf, const char *fmt, ...)
  131. {
  132. va_list va;
  133. int ret;
  134. va_start(va, fmt);
  135. outstr = buf;
  136. ret = _vprintf(fmt, va, putc_outstr);
  137. va_end(va);
  138. *outstr = '\0';
  139. return ret;
  140. }
  141. /* Note that size is ignored */
  142. int snprintf(char *buf, size_t size, const char *fmt, ...)
  143. {
  144. va_list va;
  145. int ret;
  146. va_start(va, fmt);
  147. outstr = buf;
  148. ret = _vprintf(fmt, va, putc_outstr);
  149. va_end(va);
  150. *outstr = '\0';
  151. return ret;
  152. }