printf.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /* Small, noncompliant, not-full-featured printf implementation
  2. *
  3. *
  4. * Copyright (c) 2010, Ingo Korb
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ingo Korb nor the
  15. * names of the contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. *
  30. * FIXME: Selection of output function should be more flexible
  31. */
  32. #include <stdio.h>
  33. #include <stdarg.h>
  34. #include <string.h>
  35. #include "config.h"
  36. #include "uart.h"
  37. #define outfunc(x) uart_putc(x)
  38. #define FLAG_ZEROPAD 1
  39. #define FLAG_LEFTADJ 2
  40. #define FLAG_BLANK 4
  41. #define FLAG_FORCESIGN 8
  42. #define FLAG_WIDTH 16
  43. #define FLAG_LONG 32
  44. #define FLAG_UNSIGNED 64
  45. #define FLAG_NEGATIVE 128
  46. /* Digits used for conversion */
  47. static const char hexdigits[] = "0123456789abcdef";
  48. /* Temporary buffer used for numbers - just large enough for 32 bit in octal */
  49. static char buffer[12];
  50. /* Output string length */
  51. static unsigned int outlength;
  52. /* Output pointer */
  53. static char *outptr;
  54. static int maxlen;
  55. /* printf */
  56. static void outchar(char x) {
  57. if (maxlen) {
  58. maxlen--;
  59. outfunc(x);
  60. outlength++;
  61. }
  62. }
  63. /* sprintf */
  64. static void outstr(char x) {
  65. if (maxlen) {
  66. maxlen--;
  67. *outptr++ = x;
  68. outlength++;
  69. }
  70. }
  71. static int internal_nprintf(void (*output_function)(char c), const char *fmt, va_list ap) {
  72. unsigned int width;
  73. unsigned int flags;
  74. unsigned int base = 0;
  75. char *ptr = NULL;
  76. outlength = 0;
  77. while (*fmt) {
  78. while (1) {
  79. if (*fmt == 0)
  80. goto end;
  81. if (*fmt == '%') {
  82. fmt++;
  83. if (*fmt != '%')
  84. break;
  85. }
  86. output_function(*fmt++);
  87. }
  88. flags = 0;
  89. width = 0;
  90. /* read all flags */
  91. do {
  92. if (flags < FLAG_WIDTH) {
  93. switch (*fmt) {
  94. case '0':
  95. flags |= FLAG_ZEROPAD;
  96. continue;
  97. case '-':
  98. flags |= FLAG_LEFTADJ;
  99. continue;
  100. case ' ':
  101. flags |= FLAG_BLANK;
  102. continue;
  103. case '+':
  104. flags |= FLAG_FORCESIGN;
  105. continue;
  106. }
  107. }
  108. if (flags < FLAG_LONG) {
  109. if (*fmt >= '0' && *fmt <= '9') {
  110. unsigned char tmp = *fmt - '0';
  111. width = 10*width + tmp;
  112. flags |= FLAG_WIDTH;
  113. continue;
  114. }
  115. if (*fmt == 'h')
  116. continue;
  117. if (*fmt == 'l') {
  118. flags |= FLAG_LONG;
  119. continue;
  120. }
  121. }
  122. break;
  123. } while (*fmt++);
  124. /* Strings */
  125. if (*fmt == 'c' || *fmt == 's') {
  126. switch (*fmt) {
  127. case 'c':
  128. buffer[0] = va_arg(ap, int);
  129. ptr = buffer;
  130. break;
  131. case 's':
  132. ptr = va_arg(ap, char *);
  133. break;
  134. }
  135. goto output;
  136. }
  137. /* Numbers */
  138. switch (*fmt) {
  139. case 'u':
  140. flags |= FLAG_UNSIGNED;
  141. case 'd':
  142. base = 10;
  143. break;
  144. case 'o':
  145. base = 8;
  146. flags |= FLAG_UNSIGNED;
  147. break;
  148. case 'p': // pointer
  149. output_function('0');
  150. output_function('x');
  151. width -= 2;
  152. case 'x':
  153. case 'X':
  154. base = 16;
  155. flags |= FLAG_UNSIGNED;
  156. break;
  157. }
  158. unsigned int num;
  159. if (!(flags & FLAG_UNSIGNED)) {
  160. int tmp = va_arg(ap, int);
  161. if (tmp < 0) {
  162. num = -tmp;
  163. flags |= FLAG_NEGATIVE;
  164. } else
  165. num = tmp;
  166. } else {
  167. num = va_arg(ap, unsigned int);
  168. }
  169. /* Convert number into buffer */
  170. ptr = buffer + sizeof(buffer);
  171. *--ptr = 0;
  172. do {
  173. *--ptr = hexdigits[num % base];
  174. num /= base;
  175. } while (num != 0);
  176. /* Sign */
  177. if (flags & FLAG_NEGATIVE) {
  178. output_function('-');
  179. width--;
  180. } else if (flags & FLAG_FORCESIGN) {
  181. output_function('+');
  182. width--;
  183. } else if (flags & FLAG_BLANK) {
  184. output_function(' ');
  185. width--;
  186. }
  187. output:
  188. /* left padding */
  189. if ((flags & FLAG_WIDTH) && !(flags & FLAG_LEFTADJ)) {
  190. while (strlen(ptr) < width) {
  191. if (flags & FLAG_ZEROPAD)
  192. output_function('0');
  193. else
  194. output_function(' ');
  195. width--;
  196. }
  197. }
  198. /* data */
  199. while (*ptr) {
  200. output_function(*ptr++);
  201. if (width)
  202. width--;
  203. }
  204. /* right padding */
  205. if (flags & FLAG_WIDTH) {
  206. while (width) {
  207. output_function(' ');
  208. width--;
  209. }
  210. }
  211. fmt++;
  212. }
  213. end:
  214. return outlength;
  215. }
  216. int printf(const char *format, ...) {
  217. va_list ap;
  218. int res;
  219. maxlen = -1;
  220. va_start(ap, format);
  221. res = internal_nprintf(outchar, format, ap);
  222. va_end(ap);
  223. return res;
  224. }
  225. int snprintf(char *str, size_t size, const char *format, ...) {
  226. va_list ap;
  227. int res;
  228. maxlen = size;
  229. outptr = str;
  230. va_start(ap, format);
  231. res = internal_nprintf(outstr, format, ap);
  232. va_end(ap);
  233. if (res < size)
  234. str[res] = 0;
  235. return res;
  236. }
  237. /* Required for gcc compatibility */
  238. int puts(const char *str) {
  239. uart_puts(str);
  240. uart_putc('\n');
  241. return 0;
  242. }
  243. #undef putchar
  244. int putchar(int c) {
  245. uart_putc(c);
  246. return 0;
  247. }