123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- #include <devutil.h>
- #include <stdint.h>
- #include <stdarg.h>
- // where n is in the range of [0, 9]
- static inline char d_to_c(int32_t n)
- {
- return '0' + n;
- }
- // where n is between 0 and 15
- // base is either 'a' of 'A',
- // depending on you want capitalized
- // or not
- static inline char hex_to_c(int32_t n, char base)
- {
- if (n < 10) {
- // n belongs to [0, 9]
- return d_to_c(n);
- } else {
- // n belongs to [10, 15]
- return base + (n - 10);
- }
- }
- static inline char x_to_c(int32_t n)
- {
- return hex_to_c(n, 'a');
- }
- static inline char X_to_c(int32_t n)
- {
- return hex_to_c(n, 'A');
- }
- // this will check if there is still free space
- // in the buffer. if so, push the char into it,
- // change the value of buf_size and move pointer
- // forward
- //
- // x: char* buf
- // y: size_t buf_size
- // z: char c
- #define do_write_if_free(x, y, z) \
- if ((y) > 1) { \
- *((x)++) = (z); \
- --(y); \
- }
- static inline ssize_t
- snprint_decimal32(
- char* buf,
- size_t buf_size,
- int32_t num)
- {
- ssize_t n_write = 0;
- if (num < 0) {
- do_write_if_free(buf, buf_size, '-');
- ++n_write;
- num *= (-1);
- }
- char* orig_buf = buf;
- do {
- do_write_if_free(buf, buf_size, d_to_c(num % 10));
- num /= 10;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_decimal64(
- char* buf,
- size_t buf_size,
- int64_t num)
- {
- ssize_t n_write = 0;
- if (num < 0) {
- do_write_if_free(buf, buf_size, '-');
- ++n_write;
- num *= (-1);
- }
- char* orig_buf = buf;
- do {
- do_write_if_free(buf, buf_size, d_to_c(num % 10));
- num /= 10;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_hex32(
- char* buf,
- size_t buf_size,
- uint32_t num,
- int32_t capitalized)
- {
- ssize_t n_write = 0;
- do_write_if_free(buf, buf_size, '0');
- if (capitalized) {
- do_write_if_free(buf, buf_size, 'X');
- } else {
- do_write_if_free(buf, buf_size, 'x');
- }
- n_write += 2;
- char* orig_buf = buf;
- do {
- if (capitalized) {
- do_write_if_free(buf, buf_size, X_to_c(num % 16));
- } else {
- do_write_if_free(buf, buf_size, x_to_c(num % 16));
- }
- num /= 16;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_hex64(
- char* buf,
- size_t buf_size,
- uint64_t num,
- int32_t capitalized)
- {
- ssize_t n_write = 0;
- do_write_if_free(buf, buf_size, '0');
- if (capitalized) {
- do_write_if_free(buf, buf_size, 'X');
- } else {
- do_write_if_free(buf, buf_size, 'x');
- }
- n_write += 2;
- char* orig_buf = buf;
- do {
- if (capitalized) {
- do_write_if_free(buf, buf_size, X_to_c(num % 16));
- } else {
- do_write_if_free(buf, buf_size, x_to_c(num % 16));
- }
- num /= 16;
- ++n_write;
- } while (num != 0);
- // prepend trailing '\0'
- if (buf_size > 0)
- *buf = 0x00;
- // move buf pointer to the last digit of number
- --buf;
- // reverse output
- while (orig_buf < buf) {
- char c = *buf;
- *buf = *orig_buf;
- *orig_buf = c;
- --buf;
- ++orig_buf;
- }
- return n_write;
- }
- static inline ssize_t
- snprint_char(
- char* buf,
- size_t buf_size,
- char c)
- {
- if (buf_size > 1)
- *buf = c;
- return sizeof(c);
- }
- int snprintf(char* buf, size_t buf_size, const char* fmt, ...)
- {
- ssize_t n_write = 0;
- va_list arg;
- va_start(arg, fmt);
- for (char c; (c = *fmt) != 0x00; ++fmt) {
- if (c == '%') {
- size_t n_tmp_write = 0;
- switch (*(++fmt)) {
- // int
- case 'd':
- n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, int));
- break;
- case 'x':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned int), 1);
- break;
- // long decimal
- case 'l':
- switch (*(++fmt)) {
- // long long aka int64
- case 'l':
- switch (*(++fmt)) {
- case 'd':
- n_tmp_write = snprint_decimal64(buf, buf_size, va_arg(arg, long long));
- break;
- case 'x':
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, unsigned long long), 1);
- break;
- }
- break;
- // long int aka int32
- case 'd':
- n_tmp_write = snprint_decimal32(buf, buf_size, va_arg(arg, long));
- break;
- case 'x':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 0);
- break;
- case 'X':
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, unsigned long), 1);
- break;
- }
- break;
- // c string
- case 's':
- n_tmp_write = snprintf(buf, buf_size, va_arg(arg, const char*));
- break;
- // int8 char
- case 'c':
- n_tmp_write = snprint_char(buf, buf_size, va_arg(arg, int));
- break;
- // pointer
- case 'p':
- #ifdef __32bit_system
- n_tmp_write = snprint_hex32(buf, buf_size, va_arg(arg, size_t), 0);
- #else
- n_tmp_write = snprint_hex64(buf, buf_size, va_arg(arg, size_t), 0);
- #endif
- break;
- default:
- n_tmp_write = snprint_char(buf, buf_size, *(fmt - 1));
- break;
- }
- n_write += n_tmp_write;
- if (buf_size > 1) {
- if (buf_size > n_tmp_write) {
- buf += n_tmp_write;
- buf_size -= n_tmp_write;
- } else {
- // no enough space
- // shrink buf_size to one
- buf += (buf_size - 1);
- buf_size = 1;
- }
- }
- } else {
- ++n_write;
- do_write_if_free(buf, buf_size, c);
- }
- }
- if (buf_size > 0)
- *buf = 0x00;
- va_end(arg);
- return n_write;
- }
|