blob: dd785728543bcb71d44b9f23048c57ddb2bb78e0 (
plain) (
blame)
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
122
123
124
|
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <ctype.h>
#define VSNPRINTF_PUTC(c) if(size > written) str[written++] = c; else written++
int
vsnprintf(char *restrict str, size_t size, const char *restrict format, va_list ap)
{
int written = 0;
for(int fmti = 0; format[fmti] != 0; fmti++) {
char fmtc = format[fmti];
if(fmtc != '%') {
VSNPRINTF_PUTC(fmtc);
continue;
}
/* Flags */
bool alternate = false;
bool zeropad = false;
bool leftadj = false;
bool signspace = false;
bool showplus = false;
fmtc = format[++fmti];
switch(fmtc) {
case '#': alternate = true; fmti++; break;
case '0': zeropad = true; fmti++; break;
case '-': leftadj = true; fmti++; break;
case ' ': signspace = true; fmti++; break;
case '+': showplus = true; fmti++; break;
default: break;
}
/* Field width. */
fmtc = format[fmti];
//TODO: Implement field width
/* Precision. */
fmtc = format[fmti];
//TODO: Implement precision
/* Length modifier */
fmtc = format[fmti];
//TODO: Implement length modifier.
/* Conversion specifier. */
bool is_signed = true;
bool is_caps = false;
int radix = 10;
fmtc = format[fmti];
switch(fmtc)
{
case 'X':
is_caps = true;
case 'x':
radix = 16;
case 'u':
is_signed = false;
case 'd':
case 'i':
goto conversion_int;
case 'p':
alternate = true;
radix = 16;
is_signed = false;
is_caps = true;
goto conversion_int;
case '%':
VSNPRINTF_PUTC('%');
break;
}
continue;
conversion_int:
{
uintmax_t value = va_arg(ap, uintmax_t);
bool negative = is_signed && (intmax_t)value < 0;
if(negative) value = (uintmax_t)(-(intmax_t)value);
size_t numc = 0;
/*Count the number of characters to put in the buffer to represent
* the value in ASCII.*/
for(uintmax_t v = value; v != 0; v /= radix, numc++);
if(numc == 0) numc++;
/* Reserve space for alternate repersentation.*/
if(showplus && !negative) { VSNPRINTF_PUTC('+'); }
if(negative) { VSNPRINTF_PUTC('-'); }
if(signspace && !negative) { VSNPRINTF_PUTC(' '); }
if(alternate) {
VSNPRINTF_PUTC('0');
if(radix == 16) {
VSNPRINTF_PUTC('x');
}
if(alternate && radix == 2) {
VSNPRINTF_PUTC('b');
}
}
/* Try to put characters into the buffer*/
if(value == 0) {
VSNPRINTF_PUTC('0');
}
else {
for(uintmax_t v = value, i = numc - 1; v != 0; v /= radix, i--) {
if(written + i >= size) continue;
int digit = v % radix;
char c = digit >= 10 ? (digit + 'a' - 10) : (digit + '0');
if(is_caps) c = toupper(c);
str[written + i] = c;
}
written += numc;
}
continue;
}
}
VSNPRINTF_PUTC(0);
return written - 1;
}
|