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
125
126
127
128
129
130
131
132
133
|
#include "kprint.h"
#include "serial.h"
#include <kc/lib.h>
#include <stdint.h>
__attribute__((optimize("O3")))
int kputchar(int c)
{
return serial_putchar(c);
}
__attribute__((optimize("O3")))
int kputs(const char *s)
{
while (*s)
{
kputchar(*s++);
}
return 0;
}
static char *convert_scalar(
uint64_t value,
unsigned base,
char *buffer,
size_t bufsz)
{
static const char *stringdigits = "0123456789abcdef";
// we cannot use a base > 16 currently
if (base > 16)
{
return NULL;
}
// the string will be built from the lower-to-higher value, and the
// result pointer will point to the first character of the string in
// the supplied buffer
// gotta zero the buffer
memset(buffer, 0, bufsz);
// the string is being built backwards, so the pointer needs to be
// at the last byte of the string
char *result = buffer + bufsz - 1;
// result >= buffer condition ensures we don't overflow
while (value > 0 && result >= buffer)
{
*--result = stringdigits[value % base];
value /= base;
}
return result;
}
static inline int print_scalar(uint64_t value, int base)
{
char buffer[65];
char *s = convert_scalar(
value,
base,
buffer,
sizeof(buffer));
kputs(s);
return strlen(s);
}
int kvprintf(const char *restrict format, va_list arguments)
{
int count = 0;
while (*format)
{
if (*format != '%')
{
kputchar(*format++);
count++;
continue;
}
switch (*++format)
{
case 0:
return count;
case '%':
count++;
kputchar('%');
break;
case 's':
{
const char *s = va_arg(arguments, const char *);
count += strlen(s);
kputs(s);
break;
}
case 'x':
print_scalar(va_arg(arguments, uint64_t), 16);
break;
case 'd':
print_scalar(va_arg(arguments, uint64_t), 10);
break;
case 'o':
print_scalar(va_arg(arguments, uint64_t), 8);
break;
case 'b':
print_scalar(va_arg(arguments, uint64_t), 2);
break;
default:
break;
}
format++;
}
va_end(arguments);
return count;
}
int kprintf(const char *restrict format, ...)
{
va_list arguments;
va_start (arguments, format);
return kvprintf(format, arguments);
}
|