printf.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. typedef unsigned char byte;
  2. typedef unsigned short word;
  3. typedef unsigned int dword;
  4. [[gnu::always_inline]] inline size_t strlen(const char* str)
  5. {
  6. size_t len = 0;
  7. while (*(str++))
  8. ++len;
  9. return len;
  10. }
  11. static constexpr const char* h = "0123456789abcdef";
  12. template<typename PutChFunc>
  13. [[gnu::always_inline]] inline int print_hex(PutChFunc putch, char*& bufptr, dword number, byte fields)
  14. {
  15. int ret = 0;
  16. byte shr_count = fields * 4;
  17. while (shr_count) {
  18. shr_count -= 4;
  19. putch(bufptr, h[(number >> shr_count) & 0x0F]);
  20. ++ret;
  21. }
  22. return ret;
  23. }
  24. template<typename PutChFunc>
  25. [[gnu::always_inline]] inline int print_number(PutChFunc putch, char*& bufptr, dword number, bool leftPad, bool zeroPad, dword fieldWidth)
  26. {
  27. dword divisor = 1000000000;
  28. char ch;
  29. char padding = 1;
  30. char buf[16];
  31. char* p = buf;
  32. for (;;) {
  33. ch = '0' + (number / divisor);
  34. number %= divisor;
  35. if (ch != '0')
  36. padding = 0;
  37. if (!padding || divisor == 1)
  38. *(p++) = ch;
  39. if (divisor == 1)
  40. break;
  41. divisor /= 10;
  42. }
  43. size_t numlen = p - buf;
  44. if (!fieldWidth || fieldWidth < numlen)
  45. fieldWidth = numlen;
  46. if (!leftPad) {
  47. for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
  48. putch(bufptr, zeroPad ? '0' : ' ');
  49. }
  50. }
  51. for (unsigned i = 0; i < numlen; ++i) {
  52. putch(bufptr, buf[i]);
  53. }
  54. if (leftPad) {
  55. for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
  56. putch(bufptr, ' ');
  57. }
  58. }
  59. return fieldWidth;
  60. }
  61. template<typename PutChFunc>
  62. [[gnu::always_inline]] inline int print_octal_number(PutChFunc putch, char*& bufptr, dword number, bool leftPad, bool zeroPad, dword fieldWidth)
  63. {
  64. dword divisor = 134217728;
  65. char ch;
  66. char padding = 1;
  67. char buf[32];
  68. char* p = buf;
  69. for (;;) {
  70. ch = '0' + (number / divisor);
  71. number %= divisor;
  72. if (ch != '0')
  73. padding = 0;
  74. if (!padding || divisor == 1)
  75. *(p++) = ch;
  76. if (divisor == 1)
  77. break;
  78. divisor /= 8;
  79. }
  80. size_t numlen = p - buf;
  81. if (!fieldWidth || fieldWidth < numlen)
  82. fieldWidth = numlen;
  83. if (!leftPad) {
  84. for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
  85. putch(bufptr, zeroPad ? '0' : ' ');
  86. }
  87. }
  88. for (unsigned i = 0; i < numlen; ++i) {
  89. putch(bufptr, buf[i]);
  90. }
  91. if (leftPad) {
  92. for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
  93. putch(bufptr, ' ');
  94. }
  95. }
  96. return fieldWidth;
  97. }
  98. template<typename PutChFunc>
  99. [[gnu::always_inline]] inline int print_string(PutChFunc putch, char*& bufptr, const char* str, bool leftPad, dword fieldWidth)
  100. {
  101. size_t len = strlen(str);
  102. if (!fieldWidth || fieldWidth < len)
  103. fieldWidth = len;
  104. if (!leftPad) {
  105. for (unsigned i = 0; i < fieldWidth - len; ++i)
  106. putch(bufptr, ' ');
  107. }
  108. for (unsigned i = 0; i < len; ++i) {
  109. putch(bufptr, str[i]);
  110. }
  111. if (leftPad) {
  112. for (unsigned i = 0; i < fieldWidth - len; ++i)
  113. putch(bufptr, ' ');
  114. }
  115. return fieldWidth;
  116. }
  117. template<typename PutChFunc>
  118. [[gnu::always_inline]] inline int print_signed_number(PutChFunc putch, char*& bufptr, int number, bool leftPad, bool zeroPad, dword fieldWidth)
  119. {
  120. if (number < 0) {
  121. putch(bufptr, '-');
  122. return print_number(putch, bufptr, 0 - number, leftPad, zeroPad, fieldWidth) + 1;
  123. }
  124. return print_number(putch, bufptr, number, leftPad, zeroPad, fieldWidth);
  125. }
  126. template<typename PutChFunc>
  127. [[gnu::always_inline]] inline int printf_internal(PutChFunc putch, char* buffer, const char*& fmt, char*& ap)
  128. {
  129. const char *p;
  130. int ret = 0;
  131. char* bufptr = buffer;
  132. for (p = fmt; *p; ++p) {
  133. bool leftPad = false;
  134. bool zeroPad = false;
  135. unsigned fieldWidth = 0;
  136. if (*p == '%' && *(p + 1)) {
  137. one_more:
  138. ++p;
  139. if (*p == ' ') {
  140. leftPad = true;
  141. if (*(p + 1))
  142. goto one_more;
  143. }
  144. if (!zeroPad && !fieldWidth && *p == '0') {
  145. zeroPad = true;
  146. if (*(p + 1))
  147. goto one_more;
  148. }
  149. if (*p >= '0' && *p <= '9') {
  150. fieldWidth *= 10;
  151. fieldWidth += *p - '0';
  152. if (*(p + 1))
  153. goto one_more;
  154. }
  155. switch( *p )
  156. {
  157. case 's':
  158. {
  159. const char* sp = va_arg(ap, const char*);
  160. ret += print_string(putch, bufptr, sp ? sp : "(null)", leftPad, fieldWidth);
  161. }
  162. break;
  163. case 'd':
  164. ret += print_signed_number(putch, bufptr, va_arg(ap, int), leftPad, zeroPad, fieldWidth);
  165. break;
  166. case 'u':
  167. ret += print_number(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth);
  168. break;
  169. case 'o':
  170. ret += print_octal_number(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth);
  171. break;
  172. case 'x':
  173. ret += print_hex(putch, bufptr, va_arg(ap, dword), 8);
  174. break;
  175. case 'w':
  176. ret += print_hex(putch, bufptr, va_arg(ap, int), 4);
  177. break;
  178. case 'b':
  179. ret += print_hex(putch, bufptr, va_arg(ap, int), 2);
  180. break;
  181. case 'c':
  182. putch(bufptr, (char)va_arg(ap, int));
  183. ++ret;
  184. break;
  185. case 'p':
  186. putch(bufptr, '0');
  187. putch(bufptr, 'x');
  188. ret += 2;
  189. ret += print_hex(putch, bufptr, va_arg(ap, dword), 8);
  190. break;
  191. }
  192. }
  193. else {
  194. putch(bufptr, *p);
  195. ++ret;
  196. }
  197. }
  198. return ret;
  199. }