1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright (c) 2020 Johannes Stoelp
#include <fmt.h>
static const char* num2dec(char* buf, unsigned long len, unsigned long long num) {
char* pbuf = buf + len - 1;
*pbuf = '\0';
if (num == 0) {
*(--pbuf) = '0';
}
while (num > 0 && pbuf != buf) {
char d = (char)(num % 10) + '0';
*(--pbuf) = d;
num /= 10;
}
return pbuf;
}
static const char* num2hex(char* buf, unsigned long len, unsigned long long num) {
char* pbuf = buf + len - 1;
*pbuf = '\0';
if (num == 0) {
*(--pbuf) = '0';
}
while (num > 0 && pbuf != buf) {
char d = (num & 0xf);
*(--pbuf) = (char)(d + (d > 9 ? 'a' - 10 : '0'));
num >>= 4;
}
return pbuf;
}
int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) {
unsigned i = 0;
#define put(c) \
{ \
char _c = (c); \
if (i < len) { \
buf[i] = _c; \
} \
++i; \
}
#define puts(s) \
while (*s) { \
put(*s++); \
}
char scratch[32];
int l_cnt = 0;
while (*fmt) {
if (*fmt != '%') {
put(*fmt++);
continue;
}
l_cnt = 0;
continue_fmt:
switch (*(++fmt /* constume '%' */)) {
case 'l':
++l_cnt;
goto continue_fmt;
case 'd': {
long val = l_cnt > 0 ? va_arg(ap, long) : va_arg(ap, int);
if (val < 0) {
val *= -1;
put('-');
}
const char* ptr = num2dec(scratch, sizeof(scratch), (unsigned long)val);
puts(ptr);
} break;
case 'x': {
unsigned long val = l_cnt > 0 ? va_arg(ap, unsigned long) : va_arg(ap, unsigned);
const char* ptr = num2hex(scratch, sizeof(scratch), val);
puts(ptr);
} break;
case 'c': {
char c = va_arg(ap, int); // By C standard, value passed to varg smaller than `sizeof(int)` will be converted to int.
put(c);
} break;
case 's': {
const char* ptr = va_arg(ap, const char*);
puts(ptr);
} break;
case 'p': {
const void* val = va_arg(ap, const void*);
const char* ptr = num2hex(scratch, sizeof(scratch), (unsigned long long)val);
put('0');
put('x');
puts(ptr);
} break;
default:
put(*fmt);
break;
}
++fmt;
}
#undef puts
#undef put
if (buf) {
i < len ? (buf[i] = '\0') : (buf[len - 1] = '\0');
}
return i;
}
int fmt(char* buf, unsigned long len, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = vfmt(buf, len, fmt, ap);
va_end(ap);
return ret;
}
|