tiny-printf.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 long *num,
  35. unsigned long 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 long num;
  50. char buf[12];
  51. unsigned long div;
  52. while ((ch = *(fmt++))) {
  53. if (ch != '%') {
  54. info->putc(info, ch);
  55. } else {
  56. bool lz = false;
  57. int width = 0;
  58. bool islong = false;
  59. ch = *(fmt++);
  60. if (ch == '-')
  61. ch = *(fmt++);
  62. if (ch == '0') {
  63. ch = *(fmt++);
  64. lz = 1;
  65. }
  66. if (ch >= '0' && ch <= '9') {
  67. width = 0;
  68. while (ch >= '0' && ch <= '9') {
  69. width = (width * 10) + ch - '0';
  70. ch = *fmt++;
  71. }
  72. }
  73. if (ch == 'l') {
  74. ch = *(fmt++);
  75. islong = true;
  76. }
  77. info->bf = buf;
  78. p = info->bf;
  79. info->zs = 0;
  80. switch (ch) {
  81. case '\0':
  82. goto abort;
  83. case 'u':
  84. case 'd':
  85. div = 1000000000;
  86. if (islong) {
  87. num = va_arg(va, unsigned long);
  88. if (sizeof(long) > 4)
  89. div *= div * 10;
  90. } else {
  91. num = va_arg(va, unsigned int);
  92. }
  93. if (ch == 'd') {
  94. if (islong && (long)num < 0) {
  95. num = -(long)num;
  96. out(info, '-');
  97. } else if (!islong && (int)num < 0) {
  98. num = -(int)num;
  99. out(info, '-');
  100. }
  101. }
  102. if (!num) {
  103. out_dgt(info, 0);
  104. } else {
  105. for (; div; div /= 10)
  106. div_out(info, &num, div);
  107. }
  108. break;
  109. case 'x':
  110. if (islong) {
  111. num = va_arg(va, unsigned long);
  112. div = 1UL << (sizeof(long) * 8 - 4);
  113. } else {
  114. num = va_arg(va, unsigned int);
  115. div = 0x10000000;
  116. }
  117. if (!num) {
  118. out_dgt(info, 0);
  119. } else {
  120. for (; div; div /= 0x10)
  121. div_out(info, &num, div);
  122. }
  123. break;
  124. case 'c':
  125. out(info, (char)(va_arg(va, int)));
  126. break;
  127. case 's':
  128. p = va_arg(va, char*);
  129. break;
  130. case '%':
  131. out(info, '%');
  132. default:
  133. break;
  134. }
  135. *info->bf = 0;
  136. info->bf = p;
  137. while (*info->bf++ && width > 0)
  138. width--;
  139. while (width-- > 0)
  140. info->putc(info, lz ? '0' : ' ');
  141. if (p) {
  142. while ((ch = *p++))
  143. info->putc(info, ch);
  144. }
  145. }
  146. }
  147. abort:
  148. return 0;
  149. }
  150. int vprintf(const char *fmt, va_list va)
  151. {
  152. struct printf_info info;
  153. info.putc = putc_normal;
  154. return _vprintf(&info, fmt, va);
  155. }
  156. int printf(const char *fmt, ...)
  157. {
  158. struct printf_info info;
  159. va_list va;
  160. int ret;
  161. info.putc = putc_normal;
  162. va_start(va, fmt);
  163. ret = _vprintf(&info, fmt, va);
  164. va_end(va);
  165. return ret;
  166. }
  167. static void putc_outstr(struct printf_info *info, char ch)
  168. {
  169. *info->outstr++ = ch;
  170. }
  171. int sprintf(char *buf, const char *fmt, ...)
  172. {
  173. struct printf_info info;
  174. va_list va;
  175. int ret;
  176. va_start(va, fmt);
  177. info.outstr = buf;
  178. info.putc = putc_outstr;
  179. ret = _vprintf(&info, fmt, va);
  180. va_end(va);
  181. *info.outstr = '\0';
  182. return ret;
  183. }
  184. /* Note that size is ignored */
  185. int snprintf(char *buf, size_t size, const char *fmt, ...)
  186. {
  187. struct printf_info info;
  188. va_list va;
  189. int ret;
  190. va_start(va, fmt);
  191. info.outstr = buf;
  192. info.putc = putc_outstr;
  193. ret = _vprintf(&info, fmt, va);
  194. va_end(va);
  195. *info.outstr = '\0';
  196. return ret;
  197. }
  198. void __assert_fail(const char *assertion, const char *file, unsigned line,
  199. const char *function)
  200. {
  201. /* This will not return */
  202. printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
  203. assertion);
  204. hang();
  205. }