stdio.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include <devutil.h>
  2. #include <stdint.h>
  3. #include <stdarg.h>
  4. // where n is in the range of [0, 9]
  5. static inline char d_to_c(int32_t n)
  6. {
  7. return '0' + n;
  8. }
  9. // where n is between 0 and 15
  10. // base is either 'a' of 'A',
  11. // depending on you want capitalized
  12. // or not
  13. static inline char hex_to_c(int32_t n, char base)
  14. {
  15. if (n < 10) {
  16. // n belongs to [0, 9]
  17. return d_to_c(n);
  18. } else {
  19. // n belongs to [10, 15]
  20. return base + (n - 10);
  21. }
  22. }
  23. static inline char x_to_c(int32_t n)
  24. {
  25. return hex_to_c(n, 'a');
  26. }
  27. static inline char X_to_c(int32_t n)
  28. {
  29. return hex_to_c(n, 'A');
  30. }
  31. // this will check if there is still free space
  32. // in the buffer. if so, push the char into it,
  33. // change the value of buf_size and move pointer
  34. // forward
  35. //
  36. // x: char* buf
  37. // y: size_t buf_size
  38. // z: char c
  39. #define do_write_if_free(x, y, z) \
  40. if ((y) > 1) { \
  41. *((x)++) = (z); \
  42. --(y); \
  43. }
  44. static inline ssize_t
  45. snprint_decimal32(
  46. char* buf,
  47. size_t buf_size,
  48. int32_t num)
  49. {
  50. ssize_t n_write = 0;
  51. if (num < 0) {
  52. do_write_if_free(buf, buf_size, '-');
  53. ++n_write;
  54. num *= (-1);
  55. }
  56. char* orig_buf = buf;
  57. do {
  58. do_write_if_free(buf, buf_size, d_to_c(num % 10));
  59. num /= 10;
  60. ++n_write;
  61. } while (num != 0);
  62. // prepend trailing '\0'
  63. if (buf_size > 0)
  64. *buf = 0x00;
  65. // move buf pointer to the last digit of number
  66. --buf;
  67. // reverse output
  68. while (orig_buf < buf) {
  69. char c = *buf;
  70. *buf = *orig_buf;
  71. *orig_buf = c;
  72. --buf;
  73. ++orig_buf;
  74. }
  75. return n_write;
  76. }
  77. static inline ssize_t
  78. snprint_decimal64(
  79. char* buf,
  80. size_t buf_size,
  81. int64_t num)
  82. {
  83. ssize_t n_write = 0;
  84. if (num < 0) {
  85. do_write_if_free(buf, buf_size, '-');
  86. ++n_write;
  87. num *= (-1);
  88. }
  89. char* orig_buf = buf;
  90. do {
  91. do_write_if_free(buf, buf_size, d_to_c(num % 10));
  92. num /= 10;
  93. ++n_write;
  94. } while (num != 0);
  95. // prepend trailing '\0'
  96. if (buf_size > 0)
  97. *buf = 0x00;
  98. // move buf pointer to the last digit of number
  99. --buf;
  100. // reverse output
  101. while (orig_buf < buf) {
  102. char c = *buf;
  103. *buf = *orig_buf;
  104. *orig_buf = c;
  105. --buf;
  106. ++orig_buf;
  107. }
  108. return n_write;
  109. }
  110. static inline ssize_t
  111. snprint_hex32(
  112. char* buf,
  113. size_t buf_size,
  114. uint32_t num,
  115. int32_t capitalized)
  116. {
  117. ssize_t n_write = 0;
  118. do_write_if_free(buf, buf_size, '0');
  119. if (capitalized) {
  120. do_write_if_free(buf, buf_size, 'X');
  121. } else {
  122. do_write_if_free(buf, buf_size, 'x');
  123. }
  124. n_write += 2;
  125. char* orig_buf = buf;
  126. do {
  127. if (capitalized) {
  128. do_write_if_free(buf, buf_size, X_to_c(num % 16));
  129. } else {
  130. do_write_if_free(buf, buf_size, x_to_c(num % 16));
  131. }
  132. num /= 16;
  133. ++n_write;
  134. } while (num != 0);
  135. // prepend trailing '\0'
  136. if (buf_size > 0)
  137. *buf = 0x00;
  138. // move buf pointer to the last digit of number
  139. --buf;
  140. // reverse output
  141. while (orig_buf < buf) {
  142. char c = *buf;
  143. *buf = *orig_buf;
  144. *orig_buf = c;
  145. --buf;
  146. ++orig_buf;
  147. }
  148. return n_write;
  149. }
  150. static inline ssize_t
  151. snprint_hex64(
  152. char* buf,
  153. size_t buf_size,
  154. uint64_t num,
  155. int32_t capitalized)
  156. {
  157. ssize_t n_write = 0;
  158. do_write_if_free(buf, buf_size, '0');
  159. if (capitalized) {
  160. do_write_if_free(buf, buf_size, 'X');
  161. } else {
  162. do_write_if_free(buf, buf_size, 'x');
  163. }
  164. n_write += 2;
  165. char* orig_buf = buf;
  166. do {
  167. if (capitalized) {
  168. do_write_if_free(buf, buf_size, X_to_c(num % 16));
  169. } else {
  170. do_write_if_free(buf, buf_size, x_to_c(num % 16));
  171. }
  172. num /= 16;
  173. ++n_write;
  174. } while (num != 0);
  175. // prepend trailing '\0'
  176. if (buf_size > 0)
  177. *buf = 0x00;
  178. // move buf pointer to the last digit of number
  179. --buf;
  180. // reverse output
  181. while (orig_buf < buf) {
  182. char c = *buf;
  183. *buf = *orig_buf;
  184. *orig_buf = c;
  185. --buf;
  186. ++orig_buf;
  187. }
  188. return n_write;
  189. }
  190. static inline ssize_t
  191. snprint_char(
  192. char* buf,
  193. size_t buf_size,
  194. char c)
  195. {
  196. if (buf_size > 1)
  197. *buf = c;
  198. return sizeof(c);
  199. }
  200. int snprintf(char* buf, size_t buf_size, const char* fmt, ...)
  201. {
  202. ssize_t n_write = 0;
  203. va_list arg;
  204. va_start(arg, fmt);
  205. for (char c; (c = *fmt) != 0x00; ++fmt) {
  206. if (c == '%') {
  207. size_t n_tmp_write = 0;
  208. switch (*(++fmt)) {
  209. // int
  210. case 'd':
  211. n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, int));
  212. break;
  213. case 'x':
  214. n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 0);
  215. break;
  216. case 'X':
  217. n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 1);
  218. break;
  219. // long decimal
  220. case 'l':
  221. switch (*(++fmt)) {
  222. // long long aka int64
  223. case 'l':
  224. switch (*(++fmt)) {
  225. case 'd':
  226. n_tmp_write = snprint_decimal64(buf, buf_size, va_arg(arg, long long));
  227. break;
  228. case 'x':
  229. n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 0);
  230. break;
  231. case 'X':
  232. n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 1);
  233. break;
  234. }
  235. break;
  236. // long int aka int32
  237. case 'd':
  238. n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, long));
  239. break;
  240. case 'x':
  241. n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 0);
  242. break;
  243. case 'X':
  244. n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 1);
  245. break;
  246. }
  247. break;
  248. // c string
  249. case 's':
  250. n_tmp_write = snprintf(buf, buf_size, va_arg(arg, const char*));
  251. break;
  252. // int8 char
  253. case 'c':
  254. n_tmp_write = snprint_char(buf, buf_size, va_arg(arg, int));
  255. break;
  256. // pointer
  257. case 'p':
  258. #ifdef __32bit_system
  259. n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, size_t), 0);
  260. #else
  261. n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, size_t), 0);
  262. #endif
  263. break;
  264. default:
  265. n_tmp_write = snprint_char(buf, buf_size, *(fmt - 1));
  266. break;
  267. }
  268. n_write += n_tmp_write;
  269. if (buf_size > 1) {
  270. if (buf_size > n_tmp_write) {
  271. buf += n_tmp_write;
  272. buf_size -= n_tmp_write;
  273. } else {
  274. // no enough space
  275. // shrink buf_size to one
  276. buf += (buf_size - 1);
  277. buf_size = 1;
  278. }
  279. }
  280. } else {
  281. ++n_write;
  282. do_write_if_free(buf, buf_size, c);
  283. }
  284. }
  285. if (buf_size > 0)
  286. *buf = 0x00;
  287. va_end(arg);
  288. return n_write;
  289. }