:: limine / common / lib / print.s2.c 5.8 KB raw

1
#include <stdarg.h>
2
#include <stddef.h>
3
#include <stdint.h>
4
#include <lib/print.h>
5
#include <lib/misc.h>
6
#include <lib/term.h>
7
#include <lib/libc.h>
8
#if defined (BIOS)
9
#include <lib/real.h>
10
#endif
11
#include <sys/cpu.h>
12
#include <drivers/serial.h>
13
14
#if defined (BIOS)
15
static void s2_print(const char *s, size_t len) {
16
    for (size_t i = 0; i < len; i++) {
17
        struct rm_regs r = {0};
18
        r.eax = 0x0e00 | s[i];
19
        rm_int(0x10, &r, &r);
20
    }
21
}
22
#endif
23
24
static const char *base_digits = "0123456789abcdef";
25
26
#define PRINT_BUF_MAX 4096
27
28
static void prn_char(char *print_buf, size_t *print_buf_i, char c) {
29
    if (c == '\n') {
30
        prn_char(print_buf, print_buf_i, '\r');
31
    }
32
33
    if (*print_buf_i < (PRINT_BUF_MAX - 1)) {
34
        print_buf[(*print_buf_i)++] = c;
35
    }
36
37
    print_buf[*print_buf_i] = 0;
38
}
39
40
static void prn_str(char *print_buf, size_t *print_buf_i, const char *string) {
41
    size_t i;
42
43
    for (i = 0; string[i]; i++) {
44
        prn_char(print_buf, print_buf_i, string[i]);
45
    }
46
}
47
48
static void prn_nstr(char *print_buf, size_t *print_buf_i, const char *string, size_t len) {
49
    size_t i;
50
51
    for (i = 0; i < len; i++) {
52
        prn_char(print_buf, print_buf_i, string[i]);
53
    }
54
}
55
56
static void prn_i(char *print_buf, size_t *print_buf_i, int64_t x) {
57
    int i;
58
    char buf[21] = {0};
59
60
    if (!x) {
61
        prn_char(print_buf, print_buf_i, '0');
62
        return;
63
    }
64
65
    int sign = x < 0;
66
    uint64_t ux = sign ? (uint64_t)0 - (uint64_t)x : (uint64_t)x;
67
68
    for (i = 19; ux; i--) {
69
        buf[i] = (ux % 10) + 0x30;
70
        ux = ux / 10;
71
    }
72
    if (sign)
73
        buf[i] = '-';
74
    else
75
        i++;
76
77
    prn_str(print_buf, print_buf_i, buf + i);
78
}
79
80
static void prn_ui(char *print_buf, size_t *print_buf_i, uint64_t x) {
81
    int i;
82
    char buf[21] = {0};
83
84
    if (!x) {
85
        prn_char(print_buf, print_buf_i, '0');
86
        return;
87
    }
88
89
    for (i = 19; x; i--) {
90
        buf[i] = (x % 10) + 0x30;
91
        x = x / 10;
92
    }
93
94
    i++;
95
    prn_str(print_buf, print_buf_i, buf + i);
96
}
97
98
static void prn_x(char *print_buf, size_t *print_buf_i, uint64_t x) {
99
    int i;
100
    char buf[17] = {0};
101
102
    if (!x) {
103
        prn_str(print_buf, print_buf_i, "0x0");
104
        return;
105
    }
106
107
    for (i = 15; x; i--) {
108
        buf[i] = base_digits[(x % 16)];
109
        x = x / 16;
110
    }
111
112
    i++;
113
    prn_str(print_buf, print_buf_i, "0x");
114
    prn_str(print_buf, print_buf_i, buf + i);
115
}
116
117
void print(const char *fmt, ...) {
118
    va_list args;
119
120
    va_start(args, fmt);
121
    vprint(fmt, args);
122
    va_end(args);
123
}
124
125
static char print_buf[PRINT_BUF_MAX];
126
127
void vprint(const char *fmt, va_list args) {
128
    size_t print_buf_i = 0;
129
130
    for (;;) {
131
        while (*fmt && *fmt != '%') {
132
            prn_char(print_buf, &print_buf_i, *fmt++);
133
        }
134
135
        if (!*fmt++)
136
            goto out;
137
138
        switch (*fmt++) {
139
            case 's': {
140
                char *str = (char *)va_arg(args, const char *);
141
                if (!str)
142
                    prn_str(print_buf, &print_buf_i, "(null)");
143
                else
144
                    prn_str(print_buf, &print_buf_i, str); }
145
                break;
146
            case 'S': {
147
                char *str = (char *)va_arg(args, const char *);
148
                size_t str_len = va_arg(args, size_t);
149
                if (!str)
150
                    prn_str(print_buf, &print_buf_i, "(null)");
151
                else
152
                    prn_nstr(print_buf, &print_buf_i, str, str_len); }
153
                break;
154
            case 'd':
155
                prn_i(print_buf, &print_buf_i, (int64_t)va_arg(args, int32_t));
156
                break;
157
            case 'u':
158
                prn_ui(print_buf, &print_buf_i, (uint64_t)va_arg(args, uint32_t));
159
                break;
160
            case 'x':
161
                prn_x(print_buf, &print_buf_i, (uint64_t)va_arg(args, uint32_t));
162
                break;
163
            case 'D':
164
                prn_i(print_buf, &print_buf_i, va_arg(args, int64_t));
165
                break;
166
            case 'U':
167
                prn_ui(print_buf, &print_buf_i, va_arg(args, uint64_t));
168
                break;
169
            case 'X':
170
                prn_x(print_buf, &print_buf_i, va_arg(args, uint64_t));
171
                break;
172
            case 'p':
173
                prn_x(print_buf, &print_buf_i, va_arg(args, uintptr_t));
174
                break;
175
            case 'c': {
176
                char c = (char)va_arg(args, int);
177
                prn_char(print_buf, &print_buf_i, c); }
178
                break;
179
            case '#': {
180
                bool printed = false;
181
                char *str = (char *)va_arg(args, const char *);
182
                for (int i = (int)strlen(str) - 1; i >= 0; i--) {
183
                    if (str[i] != '#') {
184
                        continue;
185
                    }
186
187
                    prn_nstr(print_buf, &print_buf_i, str, i);
188
                    printed = true;
189
                    break;
190
                }
191
192
                if (!printed) {
193
                    prn_str(print_buf, &print_buf_i, str);
194
                }
195
196
                break;
197
            }
198
            default:
199
                prn_char(print_buf, &print_buf_i, '?');
200
                break;
201
        }
202
    }
203
204
out:
205
    if (!quiet) {
206
#if defined (BIOS)
207
        if (stage3_loaded) {
208
#endif
209
            FOR_TERM(flanterm_write(TERM, print_buf, print_buf_i));
210
#if defined (BIOS)
211
        } else {
212
            s2_print(print_buf, print_buf_i);
213
        }
214
#endif
215
    }
216
217
    for (size_t i = 0; i < print_buf_i; i++) {
218
#if defined (__x86_64__) || defined (__i386__)
219
        if (E9_OUTPUT) {
220
            outb(0xe9, print_buf[i]);
221
        }
222
#endif
223
#if defined (BIOS)
224
        if (stage3_loaded && ((!quiet && serial) || COM_OUTPUT)) {
225
            if (!isprint(print_buf[i])) {
226
                switch (print_buf[i]) {
227
                    case '\r': case '\n': case '\e': break;
228
                    default: continue;
229
                }
230
            }
231
            serial_out(print_buf[i]);
232
        }
233
#endif
234
    }
235
}
tab: 248 wrap: offon