stdio.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include <kernel/stdio.h>
  2. #include <types/stdint.h>
  3. // where n is in the range of [0, 9]
  4. static inline char d_to_c(int32_t n)
  5. {
  6. return '0' + n;
  7. }
  8. // this will check if there is still free space
  9. // in the buffer. if so, push the char into it,
  10. // change the value of buf_size and move pointer
  11. // forward
  12. //
  13. // x: char* buf
  14. // y: size_t buf_size
  15. // z: char c
  16. #define do_write_if_free(x, y, z) \
  17. if ((y) > 1) { \
  18. *((x)++) = (z); \
  19. --(y); \
  20. }
  21. // TODO: print negative numbers
  22. size_t
  23. snprint_decimal(
  24. char* buf,
  25. size_t buf_size,
  26. int32_t num)
  27. {
  28. size_t n_write = 0;
  29. char* orig_buf = buf;
  30. do {
  31. do_write_if_free(buf, buf_size, d_to_c(num % 10));
  32. num /= 10;
  33. ++n_write;
  34. } while (num != 0);
  35. // prepend trailing '\0'
  36. if (buf_size > 0)
  37. *buf = 0x00;
  38. // move buf pointer to the last digit of number
  39. --buf;
  40. // reverse output
  41. while (orig_buf < buf) {
  42. char c = *buf;
  43. *buf = *orig_buf;
  44. *orig_buf = c;
  45. --buf;
  46. ++orig_buf;
  47. }
  48. return n_write;
  49. }
  50. static inline size_t
  51. snprint_char(
  52. char* buf,
  53. size_t buf_size,
  54. char c)
  55. {
  56. if (buf_size > 1)
  57. *buf = c;
  58. return sizeof(c);
  59. }
  60. size_t
  61. snprintf(
  62. char* buf,
  63. size_t buf_size,
  64. const char* fmt,
  65. ...)
  66. {
  67. size_t n_write = 0;
  68. void* arg_ptr = ((void*)&buf) + sizeof(char*) + sizeof(size_t) + sizeof(const char*);
  69. for (char c; (c = *fmt) != 0x00; ++fmt) {
  70. if (c == '%') {
  71. size_t n_tmp_write = 0;
  72. switch (*(++fmt)) {
  73. // int32 decimal
  74. case 'd':
  75. n_tmp_write = snprint_decimal(buf, buf_size, *(int32_t*)arg_ptr);
  76. arg_ptr += sizeof(int32_t);
  77. break;
  78. // c string
  79. case 's':
  80. n_tmp_write = snprintf(buf, buf_size, *(const char**)arg_ptr);
  81. arg_ptr += sizeof(const char*);
  82. break;
  83. // int8 char
  84. case 'c':
  85. n_tmp_write = snprint_char(buf, buf_size, *(char*)arg_ptr);
  86. arg_ptr += sizeof(char);
  87. break;
  88. default:
  89. n_tmp_write = snprint_char(buf, buf_size, *(fmt - 1));
  90. break;
  91. }
  92. n_write += n_tmp_write;
  93. if (buf_size > 1) {
  94. if (buf_size > n_tmp_write) {
  95. buf += n_tmp_write;
  96. buf_size -= n_tmp_write;
  97. } else {
  98. // no enough space
  99. // shrink buf_size to one
  100. buf += (buf_size - 1);
  101. buf_size = 1;
  102. }
  103. }
  104. } else {
  105. ++n_write;
  106. do_write_if_free(buf, buf_size, c);
  107. }
  108. }
  109. if (buf_size > 0)
  110. *buf = 0x00;
  111. return n_write;
  112. }