vsprintf.c 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include <stdarg.h>
  2. #include "if_ether.h" /* for ETH_ALEN */
  3. #include "limits.h" /* for CHAR_BIT */
  4. #include "console.h"
  5. #include "errno.h"
  6. #include "vsprintf.h"
  7. #define LONG_SHIFT ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
  8. #define INT_SHIFT ((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
  9. #define SHRT_SHIFT ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
  10. #define CHAR_SHIFT ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
  11. /** @file
  12. *
  13. * printf and friends.
  14. *
  15. * Etherboot's printf() functions understand the following format
  16. * specifiers:
  17. *
  18. * - Hexadecimal integers
  19. * - @c %[#]x - 4 bytes int (8 hex digits, lower case)
  20. * - @c %[#]X - 4 bytes int (8 hex digits, upper case)
  21. * - @c %[#]lx - 8 bytes long (16 hex digits, lower case)
  22. * - @c %[#]lX - 8 bytes long (16 hex digits, upper case)
  23. * - @c %[#]hx - 2 bytes int (4 hex digits, lower case)
  24. * - @c %[#]hX - 2 bytes int (4 hex digits, upper case)
  25. * - @c %[#]hhx - 1 byte int (2 hex digits, lower case)
  26. * - @c %[#]hhX - 1 byte int (2 hex digits, upper case)
  27. * .
  28. * If the optional # prefix is specified, the output will
  29. * be prefixed with 0x (or 0X).
  30. *
  31. * - Other integers
  32. * - @c %d - decimal int
  33. * .
  34. * Note that any width specification (e.g. the @c 02 in @c %02x)
  35. * will be accepted but ignored.
  36. *
  37. * - Strings and characters
  38. * - @c %c - char
  39. * - @c %s - string
  40. * - @c %m - error message text (i.e. strerror(errno))
  41. *
  42. * - Etherboot-specific specifiers
  43. * - @c %@ - IP in ddd.ddd.ddd.ddd notation
  44. * - @c %! - MAC address in xx:xx:xx:xx:xx:xx notation
  45. *
  46. */
  47. /**
  48. * Write a formatted string to a buffer.
  49. *
  50. * @v buf Buffer into which to write the string, or NULL
  51. * @v fmt Format string
  52. * @v args Arguments corresponding to the format string
  53. * @ret len Length of string written to buffer (if buf != NULL)
  54. * @ret 0 (if buf == NULL)
  55. * @err None
  56. *
  57. * If @c buf==NULL, then the string will be written to the console
  58. * directly using putchar().
  59. *
  60. */
  61. static int vsprintf(char *buf, const char *fmt, va_list args)
  62. {
  63. const char *p;
  64. char *s;
  65. s = buf;
  66. for ( ; *fmt != '\0'; ++fmt) {
  67. if (*fmt != '%') {
  68. buf ? *s++ = *fmt : putchar(*fmt);
  69. continue;
  70. }
  71. /* skip width specs */
  72. fmt++;
  73. while (*fmt >= '0' && *fmt <= '9')
  74. fmt++;
  75. if (*fmt == '.')
  76. fmt++;
  77. while (*fmt >= '0' && *fmt <= '9')
  78. fmt++;
  79. if (*fmt == 's') {
  80. for(p = va_arg(args, char *); *p != '\0'; p++)
  81. buf ? *s++ = *p : putchar(*p);
  82. } else if (*fmt == 'm') {
  83. for(p = strerror(errno); *p != '\0'; p++)
  84. buf ? *s++ = *p : putchar(*p);
  85. } else { /* Length of item is bounded */
  86. char tmp[40], *q = tmp;
  87. int alt = 0;
  88. int shift = INT_SHIFT;
  89. if (*fmt == '#') {
  90. alt = 1;
  91. fmt++;
  92. }
  93. if (*fmt == 'l') {
  94. shift = LONG_SHIFT;
  95. fmt++;
  96. }
  97. else if (*fmt == 'h') {
  98. shift = SHRT_SHIFT;
  99. fmt++;
  100. if (*fmt == 'h') {
  101. shift = CHAR_SHIFT;
  102. fmt++;
  103. }
  104. }
  105. /*
  106. * Before each format q points to tmp buffer
  107. * After each format q points past end of item
  108. */
  109. if ((*fmt | 0x20) == 'x') {
  110. /* With x86 gcc, sizeof(long) == sizeof(int) */
  111. unsigned long h;
  112. int ncase;
  113. if (shift > INT_SHIFT) {
  114. h = va_arg(args, unsigned long);
  115. } else {
  116. h = va_arg(args, unsigned int);
  117. }
  118. ncase = (*fmt & 0x20);
  119. if (alt) {
  120. *q++ = '0';
  121. *q++ = 'X' | ncase;
  122. }
  123. for ( ; shift >= 0; shift -= 4)
  124. *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
  125. }
  126. else if (*fmt == 'd') {
  127. char *r, *t;
  128. long i;
  129. if (shift > INT_SHIFT) {
  130. i = va_arg(args, long);
  131. } else {
  132. i = va_arg(args, int);
  133. }
  134. if (i < 0) {
  135. *q++ = '-';
  136. i = -i;
  137. }
  138. t = q; /* save beginning of digits */
  139. do {
  140. *q++ = '0' + (i % 10);
  141. i /= 10;
  142. } while (i);
  143. /* reverse digits, stop in middle */
  144. r = q; /* don't alter q */
  145. while (--r > t) {
  146. i = *r;
  147. *r = *t;
  148. *t++ = i;
  149. }
  150. }
  151. else if (*fmt == '@') {
  152. unsigned char *r;
  153. union {
  154. uint32_t l;
  155. unsigned char c[4];
  156. } u;
  157. u.l = va_arg(args, uint32_t);
  158. for (r = &u.c[0]; r < &u.c[4]; ++r)
  159. q += sprintf(q, "%d.", *r);
  160. --q;
  161. }
  162. else if (*fmt == '!') {
  163. const char *r;
  164. p = va_arg(args, char *);
  165. for (r = p + ETH_ALEN; p < r; ++p)
  166. q += sprintf(q, "%hhX:", *p);
  167. --q;
  168. }
  169. else if (*fmt == 'c')
  170. *q++ = va_arg(args, int);
  171. else
  172. *q++ = *fmt;
  173. /* now output the saved string */
  174. for (p = tmp; p < q; ++p)
  175. buf ? *s++ = *p : putchar(*p);
  176. }
  177. }
  178. if (buf)
  179. *s = '\0';
  180. return (s - buf);
  181. }
  182. /**
  183. * Write a formatted string to a buffer.
  184. *
  185. * @v buf Buffer into which to write the string, or NULL
  186. * @v fmt Format string
  187. * @v ... Arguments corresponding to the format string
  188. * @ret len Length of string written to buffer (if buf != NULL)
  189. * @ret 0 (if buf == NULL)
  190. * @err None
  191. *
  192. * If @c buf==NULL, then the string will be written to the console
  193. * directly using putchar().
  194. *
  195. */
  196. int sprintf(char *buf, const char *fmt, ...)
  197. {
  198. va_list args;
  199. int i;
  200. va_start(args, fmt);
  201. i=vsprintf(buf, fmt, args);
  202. va_end(args);
  203. return i;
  204. }
  205. /**
  206. * Write a formatted string to the console.
  207. *
  208. * @v fmt Format string
  209. * @v ... Arguments corresponding to the format string
  210. * @ret None
  211. * @err None
  212. *
  213. */
  214. void printf(const char *fmt, ...)
  215. {
  216. va_list args;
  217. int i;
  218. va_start(args, fmt);
  219. i=vsprintf(0, fmt, args);
  220. va_end(args);
  221. }