printf.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * libc printf and friends
  3. *
  4. * This code is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU Library General Public License version 2.
  6. */
  7. #include "libcflat.h"
  8. #define BUFSZ 2000
  9. typedef struct pstream {
  10. char *buffer;
  11. int remain;
  12. int added;
  13. } pstream_t;
  14. typedef struct strprops {
  15. char pad;
  16. int npad;
  17. bool alternate;
  18. } strprops_t;
  19. static void addchar(pstream_t *p, char c)
  20. {
  21. if (p->remain) {
  22. *p->buffer++ = c;
  23. --p->remain;
  24. }
  25. ++p->added;
  26. }
  27. static void print_str(pstream_t *p, const char *s, strprops_t props)
  28. {
  29. const char *s_orig = s;
  30. int npad = props.npad;
  31. if (npad > 0) {
  32. npad -= strlen(s_orig);
  33. while (npad > 0) {
  34. addchar(p, props.pad);
  35. --npad;
  36. }
  37. }
  38. while (*s)
  39. addchar(p, *s++);
  40. if (npad < 0) {
  41. props.pad = ' '; /* ignore '0' flag with '-' flag */
  42. npad += strlen(s_orig);
  43. while (npad < 0) {
  44. addchar(p, props.pad);
  45. ++npad;
  46. }
  47. }
  48. }
  49. static char digits[16] = "0123456789abcdef";
  50. static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
  51. {
  52. char buf[sizeof(long) * 3 + 2], *p = buf;
  53. int s = 0, i;
  54. if (n < 0) {
  55. n = -n;
  56. s = 1;
  57. }
  58. while (n) {
  59. *p++ = digits[n % base];
  60. n /= base;
  61. }
  62. if (s)
  63. *p++ = '-';
  64. if (p == buf)
  65. *p++ = '0';
  66. for (i = 0; i < (p - buf) / 2; ++i) {
  67. char tmp;
  68. tmp = buf[i];
  69. buf[i] = p[-1-i];
  70. p[-1-i] = tmp;
  71. }
  72. *p = 0;
  73. print_str(ps, buf, props);
  74. }
  75. static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
  76. strprops_t props)
  77. {
  78. char buf[sizeof(long) * 3 + 3], *p = buf;
  79. int i;
  80. while (n) {
  81. *p++ = digits[n % base];
  82. n /= base;
  83. }
  84. if (p == buf)
  85. *p++ = '0';
  86. else if (props.alternate && base == 16) {
  87. if (props.pad == '0') {
  88. addchar(ps, '0');
  89. addchar(ps, 'x');
  90. if (props.npad > 0)
  91. props.npad = MAX(props.npad - 2, 0);
  92. } else {
  93. *p++ = 'x';
  94. *p++ = '0';
  95. }
  96. }
  97. for (i = 0; i < (p - buf) / 2; ++i) {
  98. char tmp;
  99. tmp = buf[i];
  100. buf[i] = p[-1-i];
  101. p[-1-i] = tmp;
  102. }
  103. *p = 0;
  104. print_str(ps, buf, props);
  105. }
  106. static int fmtnum(const char **fmt)
  107. {
  108. const char *f = *fmt;
  109. int len = 0, num;
  110. if (*f == '-')
  111. ++f, ++len;
  112. while (*f >= '0' && *f <= '9')
  113. ++f, ++len;
  114. num = atol(*fmt);
  115. *fmt += len;
  116. return num;
  117. }
  118. int vsnprintf(char *buf, int size, const char *fmt, va_list va)
  119. {
  120. pstream_t s;
  121. s.buffer = buf;
  122. s.remain = size - 1;
  123. s.added = 0;
  124. while (*fmt) {
  125. char f = *fmt++;
  126. int nlong = 0;
  127. strprops_t props;
  128. memset(&props, 0, sizeof(props));
  129. props.pad = ' ';
  130. if (f != '%') {
  131. addchar(&s, f);
  132. continue;
  133. }
  134. morefmt:
  135. f = *fmt++;
  136. switch (f) {
  137. case '%':
  138. addchar(&s, '%');
  139. break;
  140. case 'c':
  141. addchar(&s, va_arg(va, int));
  142. break;
  143. case '\0':
  144. --fmt;
  145. break;
  146. case '#':
  147. props.alternate = true;
  148. goto morefmt;
  149. case '0':
  150. props.pad = '0';
  151. ++fmt;
  152. /* fall through */
  153. case '1'...'9':
  154. case '-':
  155. --fmt;
  156. props.npad = fmtnum(&fmt);
  157. goto morefmt;
  158. case 'l':
  159. ++nlong;
  160. goto morefmt;
  161. case 't':
  162. case 'z':
  163. /* Here we only care that sizeof(size_t) == sizeof(long).
  164. * On a 32-bit platform it doesn't matter that size_t is
  165. * typedef'ed to int or long; va_arg will work either way.
  166. * Same for ptrdiff_t (%td).
  167. */
  168. nlong = 1;
  169. goto morefmt;
  170. case 'd':
  171. switch (nlong) {
  172. case 0:
  173. print_int(&s, va_arg(va, int), 10, props);
  174. break;
  175. case 1:
  176. print_int(&s, va_arg(va, long), 10, props);
  177. break;
  178. default:
  179. print_int(&s, va_arg(va, long long), 10, props);
  180. break;
  181. }
  182. break;
  183. case 'u':
  184. switch (nlong) {
  185. case 0:
  186. print_unsigned(&s, va_arg(va, unsigned), 10, props);
  187. break;
  188. case 1:
  189. print_unsigned(&s, va_arg(va, unsigned long), 10, props);
  190. break;
  191. default:
  192. print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
  193. break;
  194. }
  195. break;
  196. case 'x':
  197. switch (nlong) {
  198. case 0:
  199. print_unsigned(&s, va_arg(va, unsigned), 16, props);
  200. break;
  201. case 1:
  202. print_unsigned(&s, va_arg(va, unsigned long), 16, props);
  203. break;
  204. default:
  205. print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
  206. break;
  207. }
  208. break;
  209. case 'p':
  210. props.alternate = true;
  211. print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
  212. break;
  213. case 's':
  214. print_str(&s, va_arg(va, const char *), props);
  215. break;
  216. default:
  217. addchar(&s, f);
  218. break;
  219. }
  220. }
  221. *s.buffer = 0;
  222. return s.added;
  223. }
  224. int snprintf(char *buf, int size, const char *fmt, ...)
  225. {
  226. va_list va;
  227. int r;
  228. va_start(va, fmt);
  229. r = vsnprintf(buf, size, fmt, va);
  230. va_end(va);
  231. return r;
  232. }
  233. int vprintf(const char *fmt, va_list va)
  234. {
  235. char buf[BUFSZ];
  236. int r;
  237. r = vsnprintf(buf, sizeof(buf), fmt, va);
  238. puts(buf);
  239. return r;
  240. }
  241. int printf(const char *fmt, ...)
  242. {
  243. va_list va;
  244. char buf[BUFSZ];
  245. int r;
  246. va_start(va, fmt);
  247. r = vsnprintf(buf, sizeof buf, fmt, va);
  248. va_end(va);
  249. puts(buf);
  250. return r;
  251. }
  252. void binstr(unsigned long x, char out[BINSTR_SZ])
  253. {
  254. int i;
  255. char *c;
  256. int n;
  257. n = sizeof(unsigned long) * 8;
  258. i = 0;
  259. c = &out[0];
  260. for (;;) {
  261. *c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
  262. i++;
  263. if (i == n) {
  264. *c = '\0';
  265. break;
  266. }
  267. if (i % 4 == 0)
  268. *c++ = '\'';
  269. }
  270. assert(c + 1 - &out[0] == BINSTR_SZ);
  271. }
  272. void print_binstr(unsigned long x)
  273. {
  274. char out[BINSTR_SZ];
  275. binstr(x, out);
  276. printf("%s", out);
  277. }