tiny-printf.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. struct printf_info {
  15. char *bf; /* Digit buffer */
  16. char zs; /* non-zero if a digit has been written */
  17. char *outstr; /* Next output position for sprintf() */
  18. /* Output a character */
  19. void (*putc)(struct printf_info *info, char ch);
  20. };
  21. void putc_normal(struct printf_info *info, char ch)
  22. {
  23. putc(ch);
  24. }
  25. static void out(struct printf_info *info, char c)
  26. {
  27. *info->bf++ = c;
  28. }
  29. static void out_dgt(struct printf_info *info, char dgt)
  30. {
  31. out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
  32. info->zs = 1;
  33. }
  34. static void div_out(struct printf_info *info, unsigned int *num,
  35. unsigned int div)
  36. {
  37. unsigned char dgt = 0;
  38. while (*num >= div) {
  39. *num -= div;
  40. dgt++;
  41. }
  42. if (info->zs || dgt > 0)
  43. out_dgt(info, dgt);
  44. }
  45. int _vprintf(struct printf_info *info, const char *fmt, va_list va)
  46. {
  47. char ch;
  48. char *p;
  49. unsigned int num;
  50. char buf[12];
  51. unsigned int div;
  52. while ((ch = *(fmt++))) {
  53. if (ch != '%') {
  54. info->putc(info, ch);
  55. } else {
  56. bool lz = false;
  57. int width = 0;
  58. ch = *(fmt++);
  59. if (ch == '0') {
  60. ch = *(fmt++);
  61. lz = 1;
  62. }
  63. if (ch >= '0' && ch <= '9') {
  64. width = 0;
  65. while (ch >= '0' && ch <= '9') {
  66. width = (width * 10) + ch - '0';
  67. ch = *fmt++;
  68. }
  69. }
  70. info->bf = buf;
  71. p = info->bf;
  72. info->zs = 0;
  73. switch (ch) {
  74. case '\0':
  75. goto abort;
  76. case 'u':
  77. case 'd':
  78. num = va_arg(va, unsigned int);
  79. if (ch == 'd' && (int)num < 0) {
  80. num = -(int)num;
  81. out(info, '-');
  82. }
  83. if (!num) {
  84. out_dgt(info, 0);
  85. } else {
  86. for (div = 1000000000; div; div /= 10)
  87. div_out(info, &num, div);
  88. }
  89. break;
  90. case 'x':
  91. num = va_arg(va, unsigned int);
  92. if (!num) {
  93. out_dgt(info, 0);
  94. } else {
  95. for (div = 0x10000000; div; div /= 0x10)
  96. div_out(info, &num, div);
  97. }
  98. break;
  99. case 'c':
  100. out(info, (char)(va_arg(va, int)));
  101. break;
  102. case 's':
  103. p = va_arg(va, char*);
  104. break;
  105. case '%':
  106. out(info, '%');
  107. default:
  108. break;
  109. }
  110. *info->bf = 0;
  111. info->bf = p;
  112. while (*info->bf++ && width > 0)
  113. width--;
  114. while (width-- > 0)
  115. info->putc(info, lz ? '0' : ' ');
  116. if (p) {
  117. while ((ch = *p++))
  118. info->putc(info, ch);
  119. }
  120. }
  121. }
  122. abort:
  123. return 0;
  124. }
  125. int vprintf(const char *fmt, va_list va)
  126. {
  127. struct printf_info info;
  128. info.putc = putc_normal;
  129. return _vprintf(&info, fmt, va);
  130. }
  131. int printf(const char *fmt, ...)
  132. {
  133. struct printf_info info;
  134. va_list va;
  135. int ret;
  136. info.putc = putc_normal;
  137. va_start(va, fmt);
  138. ret = _vprintf(&info, fmt, va);
  139. va_end(va);
  140. return ret;
  141. }
  142. static void putc_outstr(struct printf_info *info, char ch)
  143. {
  144. *info->outstr++ = ch;
  145. }
  146. int sprintf(char *buf, const char *fmt, ...)
  147. {
  148. struct printf_info info;
  149. va_list va;
  150. int ret;
  151. va_start(va, fmt);
  152. info.outstr = buf;
  153. info.putc = putc_outstr;
  154. ret = _vprintf(&info, fmt, va);
  155. va_end(va);
  156. *info.outstr = '\0';
  157. return ret;
  158. }
  159. /* Note that size is ignored */
  160. int snprintf(char *buf, size_t size, const char *fmt, ...)
  161. {
  162. struct printf_info info;
  163. va_list va;
  164. int ret;
  165. va_start(va, fmt);
  166. info.outstr = buf;
  167. info.putc = putc_outstr;
  168. ret = _vprintf(&info, fmt, va);
  169. va_end(va);
  170. *info.outstr = '\0';
  171. return ret;
  172. }
  173. void __assert_fail(const char *assertion, const char *file, unsigned line,
  174. const char *function)
  175. {
  176. /* This will not return */
  177. printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
  178. assertion);
  179. hang();
  180. }