diff options
-rw-r--r-- | kernel/drivers/keyboard.c | 10 | ||||
-rw-r--r-- | kernel/init/kernel.c | 21 | ||||
-rw-r--r-- | userland/irc/Makefile | 21 | ||||
-rw-r--r-- | userland/irc/irc.c | 503 | ||||
-rw-r--r-- | userland/irc/sb.c | 59 | ||||
-rw-r--r-- | userland/irc/sb.h | 22 | ||||
-rw-r--r-- | userland/irc/sv.c | 102 | ||||
-rw-r--r-- | userland/irc/sv.h | 28 | ||||
-rw-r--r-- | userland/libc/include/dlfcn.h | 0 | ||||
-rw-r--r-- | userland/libgui/libgui.h | 2 | ||||
-rw-r--r-- | userland/terminal/term.c | 7 |
11 files changed, 751 insertions, 24 deletions
diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index 7d35dc1..24ebbb0 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -102,10 +102,11 @@ u8 keyboard_to_ascii(u16 key, u8 capital) { u8 is_shift_down = 0; u8 is_alt_down = 0; +u8 is_ctrl_down = 0; struct KEY_EVENT { char c; - u8 mode; // (shift (0 bit)) (alt (1 bit)) + u8 mode; // (shift (0 bit)) (alt (1 bit)) (ctrl (2 bit)) u8 release; // 0 pressed, 1 released }; @@ -125,6 +126,9 @@ void int_keyboard(reg_t *frame) { case 0x38: is_alt_down = 0; return; + case 0x1D: + is_ctrl_down = 0; + return; } released = 1; } else { @@ -136,6 +140,9 @@ void int_keyboard(reg_t *frame) { case 0x38: is_alt_down = 1; return; + case 0x1D: + is_ctrl_down = 1; + return; } released = 0; } @@ -146,6 +153,7 @@ void int_keyboard(reg_t *frame) { ev.mode = 0; ev.mode |= is_shift_down << 0; ev.mode |= is_alt_down << 1; + ev.mode |= is_ctrl_down << 2; fifo_object_write((u8 *)&ev, 0, sizeof(ev), keyboard_fifo); kb_inode->has_data = keyboard_fifo->has_data; } diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c index db7fb27..ef7cdae 100644 --- a/kernel/init/kernel.c +++ b/kernel/init/kernel.c @@ -98,28 +98,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, add_keyboard(); add_mouse(); - //////// rtl8139_init(); - enable_interrupts(); - - /* - u32 ip = gen_ipv4(10, 0, 2, 2); - int err; - u32 listen_socket = tcp_listen_ipv4(ip, 6000, &err); - assert(!err); - u32 socket = tcp_accept(listen_socket, &err); - assert(!err); - - kprintf("socket: %x\n", socket); - - u64 out; - char buffer[256]; - assert(tcp_read(socket, buffer, 256, &out)); - kprintf("got %x bytes\n", out); - for (int i = 0; i < out; i++) { - kprintf("%c", buffer[i]); - } - */ ipv4_t gateway; gen_ipv4(&gateway, 10, 0, 2, 2); diff --git a/userland/irc/Makefile b/userland/irc/Makefile new file mode 100644 index 0000000..c5f0c3d --- /dev/null +++ b/userland/irc/Makefile @@ -0,0 +1,21 @@ +CC="i686-sb-gcc" +CFLAGS = -ggdb -O2 -Wall -Wextra -Werror -Wno-pointer-sign -Wno-int-conversion -static +LIB=-L../libgui -lgui +INC=-I../libgui +BINS=irc +all: $(BINS) + +sb.o: sb.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +sv.o: sv.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +irc.o: irc.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +irc: irc.o sb.o sv.o + $(CC) $(CFLAGS) -o $@ $^ $(LIB) + +clean: + rm $(BINS) *.o diff --git a/userland/irc/irc.c b/userland/irc/irc.c new file mode 100644 index 0000000..b69e1dd --- /dev/null +++ b/userland/irc/irc.c @@ -0,0 +1,503 @@ +#include "sb.h" +#include "sv.h" +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <libgui.h> +#include <math.h> +#include <poll.h> +#include <pty.h> +#include <socket.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syscall.h> +#include <unistd.h> + +#define TERMINAL_WIDTH 82 +#define TERMINAL_HEIGHT 40 + +struct message { + char name[9]; + size_t name_len; + char text[510]; + size_t text_len; +}; + +struct irc_channel { + struct sv name; + struct message *messages; + size_t messages_num; + size_t messages_cap; + int can_send_message; + struct irc_channel *prev; + struct irc_channel *next; +}; + +struct irc_server { + u32 socket; + struct irc_channel *channels; +}; +struct irc_channel *selected_channel = NULL; +void refresh_screen(void); + +void irc_add_message(struct irc_server *server, struct sv channel_name, + struct sv sender, struct sv msg_text); +void irc_add_message_to_channel(struct irc_channel *chan, struct sv sender, + struct sv msg_text); + +u32 tcp_connect_ipv4(u32 ip, u16 port, int *err) { + return (u32)syscall(SYS_TCP_CONNECT, ip, port, err, 0, 0); +} + +int tcp_write(u32 socket, const u8 *buffer, u64 len, u64 *out) { + return (int)syscall(SYS_TCP_WRITE, socket, buffer, len, out, 0); +} + +int tcp_read(u32 socket, u8 *buffer, u64 buffer_size, u64 *out) { + return (int)syscall(SYS_TCP_READ, socket, buffer, buffer_size, out, 0); +} + +u32 gen_ipv4(u8 i1, u8 i2, u8 i3, u8 i4) { + return i4 << (32 - 8) | i3 << (32 - 16) | i2 << (32 - 24) | i1 << (32 - 32); +} + +struct event { + u8 type; // File descriptor | Socket + u32 internal_id; +}; + +int queue_create(u32 *id) { + return (int)syscall(SYS_QUEUE_CREATE, id, 0, 0, 0, 0); +} + +int queue_add(u32 queue_id, struct event *ev, u32 size) { + return (int)syscall(SYS_QUEUE_ADD, queue_id, ev, size, 0, 0); +} + +int queue_wait(u32 queue_id) { + return (int)syscall(SYS_QUEUE_WAIT, queue_id, 0, 0, 0, 0); +} + +int tcp_fmt(u32 socket, const char *fmt, ...) { + va_list ap; + char cmd_str[512]; + va_start(ap, fmt); + int rc = vsnprintf(cmd_str, 512, fmt, ap); + va_end(ap); + return tcp_write(socket, (u8 *)cmd_str, rc, NULL); +} + +int message_pos_x = 0; +int message_pos_y = 0; + +void enter_raw_mode(void) { + printf("\033[X"); +} + +void clear_screen(void) { + printf("\033[2J"); +} + +void mvcursor(int x, int y) { + printf("\033[%d;%dH", x, y); +} + +void clear_area(int x, int y, int sx, int sy) { + char buffer[sx + 1]; + memset(buffer, ' ', sx); + buffer[sx] = '\0'; + + for (int i = 0; i < sy; i++) { + mvcursor(x, y + i); + printf("%s", buffer); + } +} + +int prompt_x = 0; +int prompt_y = TERMINAL_HEIGHT - 1; + +void msg_sv_print(struct sv s); +void msg_sv_println(struct sv s) { + msg_sv_print(s); + if (0 != message_pos_x && 0 < s.length) { + message_pos_x = 0; + message_pos_y++; + } +} + +void msg_sv_print(struct sv s) { + for (size_t i = 0; i < s.length; i++) { + mvcursor(message_pos_x, message_pos_y); + if ('\n' == s.s[i]) { + message_pos_x = 0; + message_pos_y++; + continue; + } + printf("%c", s.s[i]); + message_pos_x++; + if (message_pos_x > TERMINAL_WIDTH) { + message_pos_x = 0; + message_pos_y++; + } + } + mvcursor(prompt_x, prompt_y); +} + +#define RPL_WELCOME C_TO_SV("001") +#define RPL_YOURHOST C_TO_SV("002") +#define RPL_CREATED C_TO_SV("003") +#define RPL_MYINFO C_TO_SV("004") +#define RPL_BOUNCE C_TO_SV("005") +#define RPL_LUSERCLIENT C_TO_SV("251") +#define RPL_NOTOPIC C_TO_SV("331") +#define RPL_TOPIC C_TO_SV("332") +#define ERR_NOMOTD C_TO_SV("422") + +#define RPL_MOTDSTART C_TO_SV("375") +#define RPL_MOTD C_TO_SV("372") +#define RPL_ENDOFMOTD C_TO_SV("376") + +struct sv server_nick = C_TO_SV("testuser"); + +void handle_msg(struct irc_server *server, struct sv msg) { + struct sv message_origin = C_TO_SV(""); + int has_prefix = (':' == sv_peek(msg)); + if (has_prefix) { + message_origin = sv_split_delim(msg, &msg, ' '); + } + + struct sv command = sv_split_delim(msg, &msg, ' '); + struct sv command_parameters = msg; + +#define START_HANDLE_CMD \ + if (0) { \ + } +#define HANDLE_CMD(_cmd) else if (sv_eq(_cmd, command)) +#define PASSTHROUGH_CMD(_cmd) \ + HANDLE_CMD(_cmd) { \ + struct sv intended_recipient = \ + sv_split_delim(command_parameters, &command_parameters, ' '); \ + if (sv_eq(intended_recipient, server_nick)) { \ + irc_add_message_to_channel(&server->channels[0], C_TO_SV("*"), \ + command_parameters); \ + } \ + } +#define PASSTHROUGH_REPLY_CMD(_cmd) \ + HANDLE_CMD(_cmd) { \ + struct sv intended_recipient = \ + sv_split_delim(command_parameters, &command_parameters, ' '); \ + /* Remove the ':' */ \ + command_parameters = sv_trim_left(command_parameters, 1); \ + if (sv_eq(intended_recipient, server_nick)) { \ + irc_add_message_to_channel(&server->channels[0], C_TO_SV("*"), \ + command_parameters); \ + } \ + } +#define PASSTHROUGH_CHANNEL_CMD(_cmd) \ + HANDLE_CMD(_cmd) { \ + struct sv intended_recipient = \ + sv_split_delim(command_parameters, &command_parameters, ' '); \ + struct sv channel = \ + sv_split_delim(command_parameters, &command_parameters, ' '); \ + /* Remove the ':' */ \ + command_parameters = sv_trim_left(command_parameters, 1); \ + if (sv_eq(intended_recipient, server_nick)) { \ + irc_add_message(server, channel, C_TO_SV("*"), command_parameters); \ + } \ + } +#define END_HANDLE_CMD \ + else { \ + msg_sv_print(C_TO_SV("Unknown command recieved from server: ")); \ + msg_sv_print(command); \ + msg_sv_print(C_TO_SV("\n")); \ + } + + START_HANDLE_CMD + HANDLE_CMD(C_TO_SV("JOIN")) { + struct sv channel = sv_split_space(command_parameters, NULL); + + struct sb join_message; + sb_init(&join_message); + sb_append_sv(&join_message, message_origin); + sb_append(&join_message, " has joined the channel."); + irc_add_message(server, channel, C_TO_SV("*"), SB_TO_SV(join_message)); + sb_free(&join_message); + } + HANDLE_CMD(C_TO_SV("PRIVMSG")) { + struct sv channel = sv_split_delim(command_parameters, &msg, ' '); + struct sv nick = sv_trim_left(message_origin, 1); + nick = sv_split_delim(nick, NULL, '!'); + /* Remove the ':' */ + msg = sv_trim_left(msg, 1); + irc_add_message(server, channel, nick, msg); + } + PASSTHROUGH_CHANNEL_CMD(RPL_NOTOPIC) + PASSTHROUGH_CHANNEL_CMD(RPL_TOPIC) + + PASSTHROUGH_REPLY_CMD(RPL_MOTDSTART) + PASSTHROUGH_REPLY_CMD(RPL_MOTD) + PASSTHROUGH_REPLY_CMD(RPL_ENDOFMOTD) + + PASSTHROUGH_REPLY_CMD(RPL_WELCOME) + PASSTHROUGH_REPLY_CMD(RPL_YOURHOST) + PASSTHROUGH_REPLY_CMD(RPL_CREATED) + PASSTHROUGH_REPLY_CMD(RPL_MYINFO) + PASSTHROUGH_REPLY_CMD(RPL_BOUNCE) + PASSTHROUGH_REPLY_CMD(RPL_LUSERCLIENT) + PASSTHROUGH_REPLY_CMD(ERR_NOMOTD) + END_HANDLE_CMD +} + +void send_message(struct irc_server *server, struct irc_channel *chan, + struct sv msg) { + if (!chan->can_send_message) { + return; + } + struct sb s; + sb_init(&s); + sb_append(&s, "PRIVMSG "); + sb_append_sv(&s, chan->name); + sb_append(&s, " :"); + sb_append_sv(&s, msg); + sb_append(&s, "\n"); + + if (msg.length > 512) { + // TODO I am too lazy to add functionality to split msg right now + assert(0); + } + tcp_write(server->socket, s.string, s.length, NULL); + irc_add_message(server, chan->name, server_nick, msg); + sb_free(&s); +} + +void irc_add_channel(struct irc_server *server, struct sv name) { + struct irc_channel *prev = server->channels; + struct irc_channel *chan; + if (!server->channels) { + server->channels = malloc(sizeof(struct irc_channel)); + chan = server->channels; + } else { + struct irc_channel *t = server->channels; + for (; t->next;) { + t = t->next; + } + prev = t; + t->next = malloc(sizeof(struct irc_channel)); + chan = t->next; + } + + chan->name = sv_clone(name); + chan->messages = malloc(256 * sizeof(struct message)); + chan->messages_cap = 256; + chan->messages_num = 0; + chan->prev = prev; + chan->next = NULL; + chan->can_send_message = 1; +} + +void irc_join_channel(struct irc_server *server, const char *name) { + assert(tcp_fmt(server->socket, "JOIN %s\n", name)); + irc_add_channel(server, C_TO_SV(name)); +} + +void irc_show_channel(struct irc_channel *channel) { + clear_area(0, 0, TERMINAL_WIDTH, prompt_y - 1); + message_pos_x = 0; + message_pos_y = 0; + for (size_t i = 0; i < channel->messages_num; i++) { + struct message *m = &channel->messages[i]; + struct sv nick = { + .s = m->name, + .length = m->name_len, + }; + struct sv msg = { + .s = m->text, + .length = m->text_len, + }; + msg_sv_print(nick); + msg_sv_print(C_TO_SV(": ")); + msg_sv_print(msg); + msg_sv_print(C_TO_SV("\n")); + } +} + +void irc_add_message_to_channel(struct irc_channel *chan, struct sv sender, + struct sv msg_text) { + if (chan->messages_num >= chan->messages_cap - 1) { + chan->messages_cap += 256; + chan->messages = + realloc(chan->messages, chan->messages_cap * sizeof(struct message)); + } + struct message *msg = &chan->messages[chan->messages_num]; + chan->messages_num++; + + assert(sender.length <= 9); + assert(msg_text.length <= 510); + + msg->name_len = sender.length; + msg->text_len = msg_text.length; + memcpy(msg->name, sender.s, sender.length); + memcpy(msg->text, msg_text.s, msg_text.length); + if (selected_channel == chan) { + refresh_screen(); + } +} + +struct irc_channel *irc_get_channel(struct irc_server *server, + struct sv channel_name) { + struct irc_channel *chan = server->channels; + for (; chan; chan = chan->next) { + if (sv_eq(chan->name, channel_name)) { + break; + } + } + if (!chan) { + // If a message was recieved but we have not joined the channel it + // is probably a PRIVMSG that this application turns into a channel + // message where the "channel_name" is the sender. Or the server is + // confused and thinks we already have joined a channel. Either way + // it should be added to the list of joined channels. + irc_add_channel(server, channel_name); + // Recursion as the function should now no longer fail + return irc_get_channel(server, channel_name); + } + return chan; +} + +void irc_add_message(struct irc_server *server, struct sv channel_name, + struct sv sender, struct sv msg_text) { + struct irc_channel *chan = irc_get_channel(server, channel_name); + irc_add_message_to_channel(chan, sender, msg_text); +} + +int irc_connect_server(struct irc_server *server, u32 ip, u16 port) { + int err; + u32 socket = tcp_connect_ipv4(ip, port, &err); + if (err) { + assert(0); + return 0; + } + server->socket = socket; + irc_add_channel(server, C_TO_SV("*")); + server->channels[0].can_send_message = 0; + return 1; +} + +void refresh_screen(void) { + irc_show_channel(selected_channel); +} + +int main(void) { + clear_screen(); + + u32 id; + queue_create(&id); + + struct event fd_ev; + fd_ev.type = 0; + fd_ev.internal_id = 0; + queue_add(id, &fd_ev, 1); + + u32 ip = gen_ipv4(10, 0, 2, 2); + struct irc_server server_ctx; + irc_connect_server(&server_ctx, ip, 6667); + + selected_channel = &server_ctx.channels[0]; + + const char *nick = SV_TO_C(server_nick); + const char *realname = "John Doe"; + assert(tcp_fmt(server_ctx.socket, "NICK %s\n", nick)); + assert(tcp_fmt(server_ctx.socket, "USER %s * * :%s\n", nick, realname)); + irc_join_channel(&server_ctx, "#secretclub"); + + struct event socket_ev; + socket_ev.type = 1; + socket_ev.internal_id = server_ctx.socket; + queue_add(id, &socket_ev, 1); + + struct sb your_msg; + sb_init(&your_msg); + + char current_msg[512]; + u32 msg_usage = 0; + + for (;;) { + queue_wait(id); + { + char buffer[4096]; + int rc = mread(0, buffer, 4096, 0); + for (int i = 0; i < rc; i++) { + char c = buffer[i]; + + if (('n' & 0x1F) == c) { + struct irc_channel *next_channel = selected_channel->next; + if (next_channel) { + selected_channel = next_channel; + refresh_screen(); + } + continue; + } + if (('p' & 0x1F) == c) { + struct irc_channel *prev_channel = selected_channel->prev; + if (prev_channel) { + selected_channel = prev_channel; + refresh_screen(); + } + continue; + } + + if ('\b' == c) { + int n = sb_delete_right(&your_msg, 1); + if (0 == n) { + continue; + } + prompt_x -= n; + mvcursor(prompt_x, prompt_y); + printf(" "); + mvcursor(prompt_x, prompt_y); + continue; + } + + if ('\n' == c) { + send_message(&server_ctx, selected_channel, SB_TO_SV(your_msg)); + prompt_x = 0; + clear_area(0, prompt_y, 50, 1); + mvcursor(prompt_x, prompt_y); + sb_reset(&your_msg); + continue; + } + + mvcursor(prompt_x, prompt_y); + printf("%c", c); + prompt_x++; + + sb_append_char(&your_msg, c); + } + } + { + u64 out; + char buffer[4096]; + if (!tcp_read(server_ctx.socket, buffer, 4096, &out)) { + continue; + } + + for (u64 i = 0; i < out; i++) { + assert(msg_usage < 512); + if ('\n' == buffer[i] && i > 1 && '\r' == buffer[i - 1]) { + handle_msg(&server_ctx, (struct sv){ + .s = current_msg, + .length = msg_usage, + }); + msg_usage = 0; + continue; + } + current_msg[msg_usage] = buffer[i]; + msg_usage++; + } + } + } + return 0; +} diff --git a/userland/irc/sb.c b/userland/irc/sb.c new file mode 100644 index 0000000..b8b8915 --- /dev/null +++ b/userland/irc/sb.c @@ -0,0 +1,59 @@ +#include "sb.h" +#include <math.h> +#include <stdlib.h> +#include <string.h> + +void sb_init(struct sb *ctx) { + ctx->string = malloc(512); + ctx->length = 0; + ctx->capacity = 512; +} + +void sb_free(struct sb *ctx) { + ctx->length = 0; + ctx->capacity = 0; + free(ctx->string); + ctx->string = NULL; +} + +void sb_reset(struct sb *ctx) { + ctx->length = 0; +} + +int sb_isempty(const struct sb *ctx) { + return (0 == ctx->length); +} + +void sb_append_char(struct sb *ctx, char c) { + if (1 > ctx->capacity - ctx->length) { + ctx->capacity += 32; + ctx->string = realloc(ctx->string, ctx->capacity); + } + memcpy(ctx->string + ctx->length, &c, 1); + ctx->length++; +} + +int sb_delete_right(struct sb *ctx, int n) { + n = min(n, ctx->length); + ctx->length -= n; + return n; +} + +void sb_append(struct sb *ctx, const char *s) { + size_t l = strlen(s); + if (l > ctx->capacity - ctx->length) { + ctx->capacity += l; + ctx->string = realloc(ctx->string, ctx->capacity); + } + memcpy(ctx->string + ctx->length, s, l); + ctx->length += l; +} + +void sb_append_sv(struct sb *ctx, struct sv sv) { + if (sv.length > ctx->capacity - ctx->length) { + ctx->capacity += sv.length; + ctx->string = realloc(ctx->string, ctx->capacity); + } + memcpy(ctx->string + ctx->length, sv.s, sv.length); + ctx->length += sv.length; +} diff --git a/userland/irc/sb.h b/userland/irc/sb.h new file mode 100644 index 0000000..aad5806 --- /dev/null +++ b/userland/irc/sb.h @@ -0,0 +1,22 @@ +#ifndef SB_H +#define SB_H +#include "sv.h" +#include <stddef.h> + +struct sb { + char *string; + size_t length; + size_t capacity; +}; + +struct sv; + +void sb_init(struct sb *ctx); +void sb_free(struct sb *ctx); +void sb_reset(struct sb *ctx); +int sb_isempty(const struct sb *ctx); +void sb_append_char(struct sb *ctx, char c); +int sb_delete_right(struct sb *ctx, int n); +void sb_append(struct sb *ctx, const char *s); +void sb_append_sv(struct sb *ctx, struct sv sv); +#endif diff --git a/userland/irc/sv.c b/userland/irc/sv.c new file mode 100644 index 0000000..c29d082 --- /dev/null +++ b/userland/irc/sv.c @@ -0,0 +1,102 @@ +#include "sv.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +char *SV_TO_C(struct sv s) { + char *c_string = malloc(s.length + 1); + memcpy(c_string, s.s, s.length); + c_string[s.length] = '\0'; + return c_string; +} + +struct sv sv_split_space(const struct sv input, struct sv *rest) { + struct sv r = { + .s = input.s, + }; + for (size_t i = 0; i < input.length; i++) { + if (isspace(input.s[i])) { + r.length = i; + if (rest) { + rest->s += i + 1; + rest->length -= (i + 1); + } + return r; + } + } + + if (rest) { + rest->s = NULL; + rest->length = 0; + } + return input; +} + +struct sv sv_split_delim(const struct sv input, struct sv *rest, char delim) { + struct sv r = { + .s = input.s, + }; + for (size_t i = 0; i < input.length; i++) { + if (delim == input.s[i]) { + r.length = i; + if (rest) { + rest->s += i + 1; + rest->length -= (i + 1); + } + return r; + } + } + + if (rest) { + rest->s = NULL; + rest->length = 0; + } + return input; +} + +int sv_isempty(struct sv s) { + return (0 == s.length); +} + +char sv_peek(struct sv s) { + if (0 == s.length) { + return '\0'; + } + return s.s[0]; +} + +int sv_eq(struct sv a, struct sv b) { + if (a.length != b.length) { + return 0; + } + for (size_t i = 0; i < a.length; i++) { + if (a.s[i] != b.s[i]) { + return 0; + } + } + return 1; +} + +struct sv sv_trim_left(struct sv s, size_t n) { + if (s.length < n) { + s.s += s.length; + s.length = 0; + return s; + } + s.s += n; + s.length -= n; + return s; +} + +struct sv sv_clone(struct sv s) { + struct sv new_sv; + new_sv.length = s.length; + char *new_string = malloc(s.length); + memcpy(new_string, s.s, s.length); + new_sv.s = new_string; + return new_sv; +} + +struct sv sv_clone_from_c(const char *s) { + return sv_clone(C_TO_SV(s)); +} diff --git a/userland/irc/sv.h b/userland/irc/sv.h new file mode 100644 index 0000000..615af2c --- /dev/null +++ b/userland/irc/sv.h @@ -0,0 +1,28 @@ +#ifndef SV_H +#define SV_H +#include "sb.h" +#include <stddef.h> + +#define SB_TO_SV(_sb) \ + (struct sv) { \ + .s = (_sb).string, .length = (_sb).length \ + } + +#define C_TO_SV(_c_string) \ + ((struct sv){.length = strlen(_c_string), .s = (_c_string)}) + +struct sv { + const char *s; + size_t length; +}; + +char *SV_TO_C(struct sv s); +struct sv sv_split_delim(const struct sv input, struct sv *rest, char delim); +struct sv sv_split_space(const struct sv input, struct sv *rest); +int sv_isempty(struct sv s); +char sv_peek(struct sv s); +int sv_eq(struct sv a, struct sv b); +struct sv sv_trim_left(struct sv s, size_t n); +struct sv sv_clone(struct sv s); +struct sv sv_clone_from_c(const char *s); +#endif diff --git a/userland/libc/include/dlfcn.h b/userland/libc/include/dlfcn.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/dlfcn.h diff --git a/userland/libgui/libgui.h b/userland/libgui/libgui.h index 07fd3db..cb8d9a7 100644 --- a/userland/libgui/libgui.h +++ b/userland/libgui/libgui.h @@ -19,7 +19,7 @@ typedef struct { // Taken from drivers/keyboard.c struct KEY_EVENT { char c; - uint8_t mode; // (shift (0 bit)) (alt (1 bit)) + uint8_t mode; // (shift (0 bit)) (alt (1 bit)) (ctrl (2 bit)) uint8_t release; // 0 pressed, 1 released }; diff --git a/userland/terminal/term.c b/userland/terminal/term.c index 62aaa55..b734bb5 100644 --- a/userland/terminal/term.c +++ b/userland/terminal/term.c @@ -248,7 +248,12 @@ void run() { if (0 == e.ev.c) { continue; } - write(cmdfd, &e.ev.c, 1); + char c = e.ev.c; + int ctrl_down = (1 == ((e.ev.mode >> 2) & 1)); + if (ctrl_down) { + c &= 0x1f; + } + write(cmdfd, &c, 1); } } } |