-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel_stdio.c
More file actions
243 lines (203 loc) · 7.14 KB
/
Copy pathkernel_stdio.c
File metadata and controls
243 lines (203 loc) · 7.14 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#include "kernel_stdio.h"
#include "tty.h"
#include "util.h"
#include "string.h"
#include "terminal.h"
#include "shell.h"
#include "instruction_wrappers.h"
#include "poors_man_VGA_driver.h"
#include "poors_man_keyboard_driver.h"
static terminal_contex_t shell_terminal;
static terminal_contex_t log_terminal;
void kernel_stdio_init(void)
{
// Draw screen outline
unsigned char klog_header[] = "--------------------------------/ KERNEL LOG /---------------------------------";
print_string_to_VGA_display_buffer(19 * 80, klog_header, sizeof(klog_header)-1);
// New terminal
terminal_init(&shell_terminal, 0, 17, ENABLE_INPUT_LINE);
terminal_init(&log_terminal, 20, 5, DISABLE_INPUT_LINE);
}
// TODO: Decouple logging with a queue to avoid circular calls to LOG
// Prints to display in Log "window"
// TODO: Depricated, need to remove this, along with the "terminal" code
void LOG(const unsigned char* const message)
{
int timestamp = get_timestamp();
char str_with_timestamp[TERMINAL_MAX_X] = "AbcdAbcd: ";
long_to_hex(timestamp, str_with_timestamp, 8, 16);
int message_size = strlen_unsafe_logless(message);
// TODO: Add terminal_print() (without new line) so we can skip appending
append_string(str_with_timestamp, sizeof(str_with_timestamp), message, message_size+1); // TODO: +1 because append didn't null-terminate. Fix it
terminal_printline(&log_terminal, str_with_timestamp);
}
static void kernel_print(const unsigned char* const message)
{
terminal_print(&shell_terminal, message);
for (int i = 0; true; i++)
{
if (message[i] == 0) break;
tty_write(message[i]);
}
}
// Prints to display in Shell "window"
void kernel_println(const unsigned char* const message)
{
kernel_print(message);
kernel_print("\n");
}
static void print_decimal(int val, char* buffer, int* buf_i, int maxlen, int width, int zero_pad)
{
char numbuf[16];
int num_i = 0;
int is_negative = 0;
if (val < 0) {
is_negative = 1;
val = -val;
}
do {
numbuf[num_i++] = '0' + (val % 10);
val /= 10;
} while (val && num_i < (int)sizeof(numbuf));
// Apply zero-padding if specified (but not for negative numbers)
if (zero_pad && width > num_i && !is_negative) {
int padding = width - num_i;
while (padding-- > 0 && *buf_i < maxlen - 1) {
buffer[(*buf_i)++] = '0';
}
}
if (is_negative && *buf_i < maxlen - 1)
buffer[(*buf_i)++] = '-';
while (num_i-- > 0 && *buf_i < maxlen - 1)
buffer[(*buf_i)++] = numbuf[num_i];
}
static void print_hex(unsigned int val, char* buffer, int* buf_i, int maxlen, int width, int zero_pad, int uppercase)
{
char numbuf[16];
int num_i = 0;
do {
unsigned int digit = val % 16;
if (uppercase) {
numbuf[num_i++] = (digit < 10) ? ('0' + digit) : ('A' + digit - 10);
} else {
numbuf[num_i++] = (digit < 10) ? ('0' + digit) : ('a' + digit - 10);
}
val /= 16;
} while (val && num_i < (int)sizeof(numbuf));
// Apply zero-padding if specified
if (zero_pad && width > num_i) {
int padding = width - num_i;
while (padding-- > 0 && *buf_i < maxlen - 1) {
buffer[(*buf_i)++] = '0';
}
}
while (num_i-- > 0 && *buf_i < maxlen - 1)
buffer[(*buf_i)++] = numbuf[num_i];
}
void kernel_printf(const char* format, ...)
{
char buffer[256];
int buf_i = 0;
// Get pointer to first argument after format
unsigned int* arg_ptr = (unsigned int*)(&format + 1);
int arg_index = 0;
for (int i = 0; format[i] != '\0' && buf_i < (int)(sizeof(buffer) - 1); i++)
{
if (format[i] == '%')
{
i++;
// Parse flags and width
int width = 0;
int zero_pad = 0;
// Check for zero-padding flag
if (format[i] == '0')
{
zero_pad = 1;
i++;
}
// Parse width (simple integer parsing)
while (format[i] >= '0' && format[i] <= '9')
{
width = width * 10 + (format[i] - '0');
i++;
}
if (format[i] == 's')
{
const char* str = (const char*)arg_ptr[arg_index++];
if (str != NULL)
{
for (; *str && buf_i < (int)(sizeof(buffer) - 1); str++)
buffer[buf_i++] = *str;
}
}
else if (format[i] == 'd')
{
int val = (int)arg_ptr[arg_index++];
print_decimal(val, buffer, &buf_i, sizeof(buffer), width, zero_pad);
}
else if (format[i] == 'x')
{
unsigned int val = (unsigned int)arg_ptr[arg_index++];
print_hex(val, buffer, &buf_i, sizeof(buffer), width, zero_pad, 0);
}
else if (format[i] == 'X')
{
unsigned int val = (unsigned int)arg_ptr[arg_index++];
print_hex(val, buffer, &buf_i, sizeof(buffer), width, zero_pad, 1);
}
else if (format[i] == 'c')
{
char c = (char)arg_ptr[arg_index++];
buffer[buf_i++] = c;
}
else
{
// Unknown format, just print it
buffer[buf_i++] = '%';
if (format[i] != '\0' && buf_i < (int)(sizeof(buffer) - 1))
buffer[buf_i++] = format[i];
}
}
else
{
buffer[buf_i++] = format[i];
}
}
buffer[buf_i] = '\0';
kernel_print((const unsigned char*)buffer);
//return buf_i;
}
void kernel_putchar(const char new_char)
{
terminal_putchar(&shell_terminal, new_char);
terminal_render_to_VGA(&shell_terminal); // Otherwise the output would be refreshed only after pressing enter
// Not a best place to do this, but will consolidate later
// TODO/BUG: This will also delete the shell prompt, but I will deal with this when implementing a proper solution
// Basically, VGA terminal code needs to emulate a terminal, while tty code needs to communicate with a terminal
// (with both VGA term and tty term), but both of these roles are just hacked together at the moment
if (new_char == 8 || new_char == 0x7f) // Del char
{
// Delete one char in the terminal
tty_write('\b'); // Move cursor left
tty_write(' '); // Overwrite the character
tty_write('\b'); // Move back left
}
else
{
tty_write(new_char);
}
}
/*******************************************************************************
* Integration callbacks *
*******************************************************************************/
// TODO: Move this into callbacks/integration file
void event_on_keypress(u8 key)
{
shell_on_input(key);
#if 0
char string[] = "Key is pressed: ";
string[sizeof(string) -2] = key;
terminal_printline(&shell_terminal, string);
//LOG(string);
#endif
}