summaryrefslogtreecommitdiff
path: root/kernel/lib
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/lib')
-rw-r--r--kernel/lib/atox.c29
-rw-r--r--kernel/lib/bound.c12
-rw-r--r--kernel/lib/btoa.c43
-rw-r--r--kernel/lib/ctoi.c14
-rw-r--r--kernel/lib/fputc.c10
-rw-r--r--kernel/lib/isdigit.c6
-rw-r--r--kernel/lib/isspace.c16
-rw-r--r--kernel/lib/itoc.c10
-rw-r--r--kernel/lib/kalloc.c210
-rw-r--r--kernel/lib/kprintf.c576
-rw-r--r--kernel/lib/memcmp.c9
-rw-r--r--kernel/lib/memcpy.c10
-rw-r--r--kernel/lib/memcpyv.c11
-rw-r--r--kernel/lib/memmove.c20
-rw-r--r--kernel/lib/memmovev.c20
-rw-r--r--kernel/lib/memset.c10
-rw-r--r--kernel/lib/memsetv.c10
-rw-r--r--kernel/lib/panic.c6
-rw-r--r--kernel/lib/stpcpy.c9
-rw-r--r--kernel/lib/stpncpy.c10
-rw-r--r--kernel/lib/strcat.c7
-rw-r--r--kernel/lib/strcpy.c9
-rw-r--r--kernel/lib/strlen.c9
-rw-r--r--kernel/lib/strncmp.c11
-rw-r--r--kernel/lib/strncpy.c10
-rw-r--r--kernel/lib/strtoux.c43
-rw-r--r--kernel/lib/strtox.c52
-rw-r--r--kernel/lib/uxtoa.c27
-rw-r--r--kernel/lib/xtoa.c31
29 files changed, 1227 insertions, 13 deletions
diff --git a/kernel/lib/atox.c b/kernel/lib/atox.c
new file mode 100644
index 0000000..6d3d4cc
--- /dev/null
+++ b/kernel/lib/atox.c
@@ -0,0 +1,29 @@
+#include <lib.h>
+
+#define ATOX(name, type) \
+ type name(const char *s) \
+ { \
+ for (; isspace(*s); s++) \
+ ; \
+ int neg = 0; \
+ switch (*s) { \
+ case '-': \
+ neg = 1; \
+ /* fallthrough */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ type num = 0; \
+ for (; *s == '0'; s++) \
+ ; \
+ for (; isdigit(*s); s++) { \
+ num *= 10; \
+ num += *s - '0'; \
+ } \
+ return num * (neg ? -1 : 1); \
+ }
+
+ATOX(atoi, int)
+ATOX(atol, long int)
+ATOX(atoll, long long int)
diff --git a/kernel/lib/bound.c b/kernel/lib/bound.c
new file mode 100644
index 0000000..5a3c9fa
--- /dev/null
+++ b/kernel/lib/bound.c
@@ -0,0 +1,12 @@
+#include <lib.h>
+
+unsigned int bound(unsigned int min, unsigned int value, unsigned int max)
+{
+ if (value < min) {
+ value = min;
+ }
+ if (value > max) {
+ value = max;
+ }
+ return value;
+}
diff --git a/kernel/lib/btoa.c b/kernel/lib/btoa.c
new file mode 100644
index 0000000..96a60ef
--- /dev/null
+++ b/kernel/lib/btoa.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+static char suffixes[] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };
+
+char *btoa(size_t bytes, char *buf)
+{
+ // no suffix if under 1K, print up to four digits
+ if (bytes < 1024) {
+ ultoa(bytes, buf, 10);
+ return buf;
+ }
+
+ // store one digit of remainder for decimal
+ unsigned int remainder;
+ // power of 1024
+ int power = 0;
+
+ // iterate until remaining bytes fits in three digits
+ while (bytes >= 1000) {
+ remainder = (bytes % 1024) * 10 / 1024;
+ bytes /= 1024;
+ power += 1;
+ }
+
+ // end of number
+ char *end;
+
+ if (bytes >= 10) {
+ // no decimal
+ end = ultoa(bytes, buf, 10);
+ } else {
+ // decimal
+ end = ultoa(bytes, buf, 10);
+ end[0] = '.';
+ end = ultoa(remainder, end + 1, 10);
+ }
+
+ // add suffix
+ end[0] = suffixes[power - 1];
+ end[1] = '\0';
+
+ return buf;
+}
diff --git a/kernel/lib/ctoi.c b/kernel/lib/ctoi.c
new file mode 100644
index 0000000..09a9f10
--- /dev/null
+++ b/kernel/lib/ctoi.c
@@ -0,0 +1,14 @@
+#include <lib.h>
+
+int ctoi(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ return c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
diff --git a/kernel/lib/fputc.c b/kernel/lib/fputc.c
deleted file mode 100644
index 0d47cb5..0000000
--- a/kernel/lib/fputc.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <lib.h>
-#include <comus/drivers/tty.h>
-#include <comus/drivers/uart.h>
-
-void fputc(FILE *stream, char c)
-{
- (void)stream; // TODO: manage stream
- uart_out(c);
- tty_out(c);
-}
diff --git a/kernel/lib/isdigit.c b/kernel/lib/isdigit.c
new file mode 100644
index 0000000..f645093
--- /dev/null
+++ b/kernel/lib/isdigit.c
@@ -0,0 +1,6 @@
+#include <lib.h>
+
+int isdigit(int c)
+{
+ return c >= '0' && c <= '9';
+}
diff --git a/kernel/lib/isspace.c b/kernel/lib/isspace.c
new file mode 100644
index 0000000..5196d0c
--- /dev/null
+++ b/kernel/lib/isspace.c
@@ -0,0 +1,16 @@
+#include <lib.h>
+
+int isspace(int c)
+{
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ case '\n':
+ return 1;
+ default:
+ return 0;
+ }
+}
diff --git a/kernel/lib/itoc.c b/kernel/lib/itoc.c
new file mode 100644
index 0000000..493b66e
--- /dev/null
+++ b/kernel/lib/itoc.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char itoc(int i)
+{
+ if (i < 10) {
+ return '0' + i;
+ } else {
+ return 'a' + (i - 10);
+ }
+}
diff --git a/kernel/lib/kalloc.c b/kernel/lib/kalloc.c
new file mode 100644
index 0000000..9845a62
--- /dev/null
+++ b/kernel/lib/kalloc.c
@@ -0,0 +1,210 @@
+#include <lib.h>
+#include <comus/memory.h>
+
+#define MAGIC 0xBEEFCAFE
+
+struct page_header {
+ struct page_header *next;
+ struct page_header *prev;
+ size_t
+ node_number; // all headers on the same page alloc have the same node number (so they can be merged)
+ size_t
+ free; // free space after the node (if its the last node in the alloc block)
+ size_t used; // how much space this allocation is using
+ uint64_t magic;
+};
+
+static const size_t header_len = sizeof(struct page_header);
+static struct page_header *start_header = NULL;
+static struct page_header *end_header = NULL;
+
+static struct page_header *get_header(void *ptr)
+{
+ struct page_header *header =
+ (struct page_header *)((uintptr_t)ptr - header_len);
+
+ // PERF: do we want to make sure this pointer is paged
+ // before reading it???
+ if (header->magic != MAGIC) {
+ return NULL; // invalid pointer
+ }
+
+ return header;
+}
+
+static void *alloc_new(size_t size)
+{
+ size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
+
+ void *addr = kalloc_pages(pages);
+ void *mem = (char *)addr + header_len;
+
+ size_t total = pages * PAGE_SIZE;
+ size_t free = total - (size + header_len);
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ size_t node;
+ if (end_header != NULL) {
+ node = end_header->node_number + 1;
+ } else {
+ node = 0;
+ }
+
+ struct page_header *header = addr;
+ header->magic = 0xBEEFCAFE;
+ header->used = size;
+ header->free = free;
+ header->prev = end_header;
+ header->next = NULL;
+ header->node_number = node;
+
+ if (start_header == NULL) {
+ start_header = header;
+ }
+
+ if (end_header != NULL) {
+ end_header->next = header;
+ } else {
+ end_header = header;
+ }
+
+ return mem;
+}
+
+static void *alloc_block(size_t size, struct page_header *block)
+{
+ struct page_header *header =
+ (struct page_header *)((char *)block + block->used + header_len);
+
+ size_t free = block->free - (size + header_len);
+ block->free = 0;
+
+ header->magic = MAGIC;
+ header->used = size;
+ header->free = free;
+ header->prev = block;
+ header->next = block->next;
+ block->next = header;
+ header->node_number = block->node_number;
+
+ void *mem = (char *)header + header_len;
+
+ return mem;
+}
+
+void *kalloc(size_t size)
+{
+ struct page_header *header = start_header;
+
+ for (; header != NULL; header = header->next) {
+ size_t free = header->free;
+ if (free < header_len)
+ continue;
+ if (size <=
+ (free - header_len)) { // we must be able to fit data + header
+ break;
+ }
+ }
+
+ if (header != NULL) {
+ return alloc_block(size, header);
+ } else {
+ return alloc_new(size);
+ }
+}
+
+void *krealloc(void *src, size_t dst_len)
+{
+ struct page_header *header;
+ size_t src_len;
+ void *dst;
+
+ // realloc of 0 means free pointer
+ if (dst_len == 0) {
+ kfree(src);
+ return NULL;
+ }
+
+ // NULL src means allocate ptr
+ if (src == NULL) {
+ dst = kalloc(dst_len);
+ return dst;
+ }
+
+ header = get_header(src);
+
+ if (header == NULL)
+ return NULL;
+
+ src_len = header->used;
+
+ if (src_len == 0)
+ return NULL;
+
+ dst = kalloc(dst_len);
+
+ if (dst == NULL)
+ return NULL; // allocation failed
+
+ if (dst_len < src_len)
+ src_len = dst_len;
+
+ memcpy(dst, src, src_len);
+ kfree(src);
+
+ return dst;
+}
+
+void kfree(void *ptr)
+{
+ struct page_header *header;
+
+ if (ptr == NULL)
+ return;
+
+ header = get_header(ptr);
+
+ if (header == NULL)
+ return;
+
+ header->free += header->used;
+ header->used = 0;
+
+ struct page_header *neighbor;
+
+ // merge left
+ for (neighbor = header->prev; neighbor != NULL; neighbor = neighbor->prev) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used && header->used)
+ break;
+ neighbor->free += header->free + header_len;
+ neighbor->next = header->next;
+ header = neighbor;
+ }
+
+ // merge right
+ for (neighbor = header->next; neighbor != NULL; neighbor = neighbor->next) {
+ if (neighbor->node_number != header->node_number)
+ break;
+ if (neighbor->used)
+ break;
+ header->free += neighbor->free + header_len;
+ header->next = neighbor->next;
+ }
+
+ if ((header->next == NULL ||
+ header->next->node_number != header->node_number) &&
+ (header->prev == NULL ||
+ header->prev->node_number != header->node_number) &&
+ header->used == 0) {
+ if (header->next)
+ header->next->prev = header->prev;
+ if (header->prev)
+ header->prev->next = header->next;
+ kfree_pages(header);
+ }
+}
diff --git a/kernel/lib/kprintf.c b/kernel/lib/kprintf.c
new file mode 100644
index 0000000..a76036f
--- /dev/null
+++ b/kernel/lib/kprintf.c
@@ -0,0 +1,576 @@
+#include <lib.h>
+#include <comus/drivers/uart.h>
+#include <comus/drivers/tty.h>
+
+#define PRINTF_NUMERIC_BUF_LEN 50
+
+typedef union {
+ unsigned long long int u;
+ signed long long int i;
+ char *str;
+ char c;
+} data_t;
+
+/// options that can be set inside a specifier
+/// flags, width, precision, length, and data type
+typedef struct {
+ /* flags */
+ /// left justify content
+ uint8_t left : 1;
+ /// force sign (+/-) on numeric output
+ uint8_t sign : 1;
+ /// leave space if no printed sign on numeric output
+ uint8_t space : 1;
+ /// preceed hex/octal output with '0x'
+ uint8_t hash : 1;
+ /// left pads numeric output with zeros
+ uint8_t zero : 1;
+ uint8_t : 3;
+
+ /* width & precision */
+ /// minimum number of characters to be printed (padding if origonal is less)
+ int width;
+ /// digit precision used when printing numerical answers
+ int precision;
+ /// if a fixed minimum width has been provided
+ uint8_t width_set : 1;
+ /// if the provided minimum width is in the next variable argument
+ uint8_t width_varies : 1;
+ /// if a fixed digit precision has been provided
+ uint8_t precision_set : 1;
+ /// if the provided digit precision is in the next variable argument
+ uint8_t precision_varies : 1;
+ uint8_t : 4;
+
+ /* length */
+ /// what size to read argument as
+ enum printf_len {
+ PRINTF_LEN_CHAR,
+ PRINTF_LEN_SHORT_INT,
+ PRINTF_LEN_INT,
+ PRINTF_LEN_LONG_INT,
+ PRINTF_LEN_LONG_LONG_INT,
+ PRINTF_LEN_SIZE_T,
+ } len;
+
+ /* other */
+ /// radix to print the numerical answers as
+ uint8_t radix;
+ /// case to print hexadecimal values as
+ bool is_uppercase;
+} options_t;
+
+typedef struct {
+ /* input */
+ /// the origonal format string
+ const char *format;
+ /// maximum allowed output length
+ size_t max_len;
+ /// if a maximum output length is set
+ bool has_max_len;
+
+ /* output */
+ size_t written_len;
+ bool sprintf;
+ char *sprintf_buf;
+
+ /* pass 2 */
+ char *output;
+} context_t;
+
+static void printf_putc(context_t *ctx, char c)
+{
+ // bounds check
+ if (ctx->has_max_len)
+ if (ctx->written_len >= ctx->max_len)
+ return;
+
+ // write to correct
+ if (ctx->sprintf)
+ *(ctx->sprintf_buf++) = c;
+ else
+ kputc(c);
+
+ ctx->written_len++;
+}
+
+static int parse_flag(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ switch (*(fmt++)) {
+ case '-':
+ opts->left = 1;
+ break;
+ case '+':
+ opts->sign = 1;
+ break;
+ case ' ':
+ opts->space = 1;
+ break;
+ case '#':
+ opts->hash = 1;
+ break;
+ case '0':
+ opts->zero = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ *res = fmt;
+ return 1;
+}
+
+static void parse_width(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->width_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long width = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->width_set = 1;
+ opts->width = width;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_precision(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+ char *end = NULL;
+
+ // check for dot
+ if (*(fmt++) != '.')
+ return;
+
+ // check varies
+ if (*fmt == '*') {
+ opts->precision_varies = true;
+ *res = fmt++;
+ return;
+ }
+
+ // parse num
+ long precision = strtol(fmt, &end, 10);
+ if (end != NULL) {
+ opts->precision_set = 1;
+ opts->precision = precision;
+ *res = end;
+ return;
+ }
+}
+
+static void parse_length(const char **res, options_t *opts)
+{
+ const char *fmt = *res;
+
+ switch (*(fmt++)) {
+ // half
+ case 'h':
+ if (*fmt == 'h') {
+ opts->len = PRINTF_LEN_CHAR;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_SHORT_INT;
+ }
+ break;
+ // long
+ case 'l':
+ if (*fmt == 'l') {
+ opts->len = PRINTF_LEN_LONG_LONG_INT;
+ fmt++;
+ } else {
+ opts->len = PRINTF_LEN_LONG_INT;
+ }
+ break;
+ // size_t
+ case 'z':
+ opts->len = PRINTF_LEN_SIZE_T;
+ break;
+ default:
+ opts->len = PRINTF_LEN_INT;
+ return;
+ }
+
+ *res = fmt;
+}
+
+static void get_radix(char spec, options_t *opts)
+{
+ switch (spec) {
+ case 'x':
+ case 'X':
+ opts->radix = 16;
+ break;
+ case 'o':
+ opts->radix = 8;
+ break;
+ default:
+ opts->radix = 10;
+ break;
+ }
+}
+
+static void get_case(char spec, options_t *opts)
+{
+ if (spec == 'X')
+ opts->is_uppercase = 1;
+}
+
+static char printf_itoc(int uppercase, int i)
+{
+ // decimal
+ if (i < 10) {
+ return i + '0';
+ }
+ // hex
+ if (uppercase) {
+ return (i - 10) + 'A';
+ } else {
+ return (i - 10) + 'a';
+ }
+}
+
+static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
+ unsigned long long int num)
+{
+ int precision = 0;
+ char *start = buf;
+
+ // get width of number
+ int len = 0;
+ unsigned long long int temp = num;
+ if (temp == 0)
+ len = 1;
+ while (temp) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ temp /= opts->radix;
+ len++;
+ }
+ precision = 0;
+
+ // sign
+ if (is_neg) {
+ *(buf++) = '-';
+ } else if (opts->sign) {
+ *(buf++) = '+';
+ } else if (opts->space) {
+ *(buf++) = ' ';
+ }
+
+ // radix specifier
+ if (opts->hash) {
+ if (opts->radix == 8) {
+ *(buf++) = '0';
+ *(buf++) = 'o';
+ }
+ if (opts->radix == 16) {
+ *(buf++) = '0';
+ *(buf++) = 'x';
+ }
+ }
+
+ // print zeros if needed
+ if (opts->width_set && len < opts->width && opts->zero) {
+ while (len++ < opts->width)
+ *(buf++) = '0';
+ }
+
+ // write number
+ if (num == 0) {
+ *(buf++) = '0';
+ }
+ while (num) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ *(buf++) = printf_itoc(opts->is_uppercase, num % opts->radix);
+ num /= opts->radix;
+ }
+ *(buf++) = '\0';
+
+ return buf - start;
+}
+
+static void handle_int_specifier(context_t *ctx, options_t *const opts,
+ bool has_sign_bit, data_t num)
+{
+ bool is_neg = false;
+
+ // get sign if possible neg
+ if (has_sign_bit) {
+ if (num.i < 0) {
+ num.i = -num.i;
+ is_neg = true;
+ }
+ }
+
+ // get length of number and number
+ char buf[PRINTF_NUMERIC_BUF_LEN];
+ int buf_len = printf_lltoa(buf, opts, is_neg, num.u);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (buf_len < opts->width))
+ padding = opts->width - buf_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+ // number
+ for (int i = 0; i < buf_len; i++)
+ printf_putc(ctx, buf[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, opts->zero ? '0' : ' ');
+ }
+}
+
+static void handle_char_specifier(context_t *ctx, data_t c)
+{
+ printf_putc(ctx, c.c);
+}
+
+static void handle_string_specifier(context_t *ctx, options_t *opts,
+ data_t data)
+{
+ char *str = data.str;
+ int str_len = 0;
+
+ // get length of string
+ if (opts->precision_set)
+ str_len = opts->precision;
+ else
+ str_len = strlen(str);
+
+ // get needed padding
+ int padding = 0;
+ if (opts->width_set && (str_len < opts->width))
+ padding = opts->width - str_len;
+
+ /* print */
+ // left padding
+ if (opts->left == 0) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+ // string
+ for (int i = 0; i < str_len; i++)
+ printf_putc(ctx, str[i]);
+ // right padding
+ if (opts->left == 1) {
+ for (int i = 0; i < padding; i++)
+ printf_putc(ctx, ' ');
+ }
+}
+
+static void do_printf(context_t *ctx, va_list args)
+{
+ const char *fmt = ctx->format;
+
+ char c;
+ while (c = *fmt++, c != '\0') {
+ // save start of fmt for current iteration
+ const char *start = fmt - 1;
+
+ // ignore if not %
+ if (c != '%') {
+ printf_putc(ctx, c);
+ continue;
+ }
+
+ // read opts
+ options_t opts = { 0 };
+ while (parse_flag(&fmt, &opts))
+ ;
+ parse_width(&fmt, &opts);
+ parse_precision(&fmt, &opts);
+ parse_length(&fmt, &opts);
+
+ // read specifier
+ char spec = *fmt++;
+ get_radix(spec, &opts);
+ get_case(spec, &opts);
+
+ // read varied width / precision
+ if (opts.width_varies) {
+ opts.width_set = 1;
+ opts.width = va_arg(args, int);
+ }
+ if (opts.precision_varies) {
+ opts.precision_set = 1;
+ opts.precision = va_arg(args, int);
+ }
+ // read data from args
+ data_t data;
+ switch (spec) {
+ case 'p':
+ opts.len = PRINTF_LEN_SIZE_T;
+ opts.width_set = true;
+ opts.radix = 16;
+ opts.hash = true;
+ opts.zero = true;
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ // read number from arg
+ switch (opts.len) {
+ case PRINTF_LEN_CHAR:
+ data.u = va_arg(args, unsigned int); // char
+ break;
+ case PRINTF_LEN_SHORT_INT:
+ data.u = va_arg(args, unsigned int); // short int
+ break;
+ case PRINTF_LEN_INT:
+ data.u = va_arg(args, unsigned int);
+ break;
+ case PRINTF_LEN_LONG_INT:
+ data.u = va_arg(args, unsigned long int);
+ break;
+ case PRINTF_LEN_LONG_LONG_INT:
+ data.u = va_arg(args, unsigned long long int);
+ break;
+ case PRINTF_LEN_SIZE_T:
+ data.u = va_arg(args, size_t);
+ break;
+ }
+ break;
+ // end int
+ case 's':
+ // read string
+ data.str = va_arg(args, void *);
+ break;
+ // end string
+ case 'c':
+ // read char
+ data.c = va_arg(args, int);
+ break;
+ // end char
+ }
+
+ switch (spec) {
+ // signed int
+ case 'd':
+ case 'i':
+ handle_int_specifier(ctx, &opts, true, data);
+ break;
+ // unsigned int
+ case 'p':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ handle_int_specifier(ctx, &opts, false, data);
+ break;
+ // character
+ case 'c':
+ handle_char_specifier(ctx, data);
+ break;
+ // string
+ case 's':
+ handle_string_specifier(ctx, &opts, data);
+ break;
+ // unknown
+ default:
+ // print from % to current
+ for (; start < fmt; start++)
+ printf_putc(ctx, *start);
+ break;
+ }
+ }
+}
+
+void kprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ kvprintf(format, args);
+ va_end(args);
+}
+
+size_t ksprintf(char *restrict s, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsprintf(s, format, args);
+ va_end(args);
+ return amt;
+}
+
+size_t snprintf(char *restrict s, size_t maxlen, const char *format, ...)
+{
+ va_list args;
+ size_t amt;
+ va_start(args, format);
+ amt = kvsnprintf(s, maxlen, format, args);
+ va_end(args);
+ return amt;
+}
+
+void kvprintf(const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // print
+ do_printf(&ctx, args);
+}
+
+size_t kvsprintf(char *restrict s, const char *format, va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+size_t kvsnprintf(char *restrict s, size_t maxlen, const char *format,
+ va_list args)
+{
+ // create context
+ context_t ctx = { 0 };
+ ctx.format = format;
+ // sprintf buffer
+ ctx.sprintf_buf = s;
+ ctx.sprintf = 1;
+ // sprintf max_len
+ ctx.has_max_len = 1;
+ ctx.max_len = maxlen;
+ // print
+ do_printf(&ctx, args);
+ return ctx.written_len;
+}
+
+void kputc(char c)
+{
+ tty_out(c);
+ uart_out(c);
+}
+
+void kputs(const char *str)
+{
+ tty_out_str(str);
+ uart_out_str(str);
+}
diff --git a/kernel/lib/memcmp.c b/kernel/lib/memcmp.c
new file mode 100644
index 0000000..f938d0a
--- /dev/null
+++ b/kernel/lib/memcmp.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+int memcmp(const void *restrict vl, const void *restrict vr, size_t n)
+{
+ const unsigned char *l = vl, *r = vr;
+ for (; n && *l == *r; n--, l++, r++)
+ ;
+ return n ? *l - *r : 0;
+}
diff --git a/kernel/lib/memcpy.c b/kernel/lib/memcpy.c
new file mode 100644
index 0000000..e848cef
--- /dev/null
+++ b/kernel/lib/memcpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+void *memcpy(void *restrict dest, const void *restrict src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+ for (; n; n--)
+ *d++ = *s++;
+ return dest;
+}
diff --git a/kernel/lib/memcpyv.c b/kernel/lib/memcpyv.c
new file mode 100644
index 0000000..bc95807
--- /dev/null
+++ b/kernel/lib/memcpyv.c
@@ -0,0 +1,11 @@
+#include <lib.h>
+
+volatile void *memcpyv(volatile void *restrict dest,
+ const volatile void *restrict src, size_t n)
+{
+ volatile char *d = dest;
+ volatile const char *s = src;
+ for (; n; n--)
+ *d++ = *s++;
+ return dest;
+}
diff --git a/kernel/lib/memmove.c b/kernel/lib/memmove.c
new file mode 100644
index 0000000..55be66d
--- /dev/null
+++ b/kernel/lib/memmove.c
@@ -0,0 +1,20 @@
+#include <lib.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+
+ if (d == s)
+ return d;
+
+ if (d < s) {
+ for (; n; n--)
+ *d++ = *s++;
+ } else {
+ while (n)
+ n--, d[n] = s[n];
+ }
+
+ return dest;
+}
diff --git a/kernel/lib/memmovev.c b/kernel/lib/memmovev.c
new file mode 100644
index 0000000..56684a5
--- /dev/null
+++ b/kernel/lib/memmovev.c
@@ -0,0 +1,20 @@
+#include <lib.h>
+
+volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n)
+{
+ volatile char *d = dest;
+ volatile const char *s = src;
+
+ if (d == s)
+ return d;
+
+ if (d < s) {
+ for (; n; n--)
+ *d++ = *s++;
+ } else {
+ while (n)
+ n--, d[n] = s[n];
+ }
+
+ return dest;
+}
diff --git a/kernel/lib/memset.c b/kernel/lib/memset.c
new file mode 100644
index 0000000..d1c2a5e
--- /dev/null
+++ b/kernel/lib/memset.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+void *memset(void *dest, int c, size_t n)
+{
+ unsigned char *d = dest;
+ for (; n; n--) {
+ *d++ = c;
+ };
+ return dest;
+}
diff --git a/kernel/lib/memsetv.c b/kernel/lib/memsetv.c
new file mode 100644
index 0000000..647847f
--- /dev/null
+++ b/kernel/lib/memsetv.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+volatile void *memsetv(volatile void *dest, int c, size_t n)
+{
+ volatile unsigned char *d = dest;
+ for (; n; n--) {
+ *d++ = c;
+ };
+ return dest;
+}
diff --git a/kernel/lib/panic.c b/kernel/lib/panic.c
index 403418f..5381041 100644
--- a/kernel/lib/panic.c
+++ b/kernel/lib/panic.c
@@ -7,9 +7,9 @@ __attribute__((noreturn)) void panic(const char *format, ...)
cli();
va_list list;
va_start(list, format);
- printf("\n\n!!! PANIC !!!\n");
- vprintf(format, list);
- printf("\n\n");
+ kprintf("\n\n!!! PANIC !!!\n");
+ kvprintf(format, list);
+ kprintf("\n\n");
while (1)
halt();
diff --git a/kernel/lib/stpcpy.c b/kernel/lib/stpcpy.c
new file mode 100644
index 0000000..1a7c5bf
--- /dev/null
+++ b/kernel/lib/stpcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *stpcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return d;
+}
diff --git a/kernel/lib/stpncpy.c b/kernel/lib/stpncpy.c
new file mode 100644
index 0000000..87f9838
--- /dev/null
+++ b/kernel/lib/stpncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return d;
+}
diff --git a/kernel/lib/strcat.c b/kernel/lib/strcat.c
new file mode 100644
index 0000000..fcfa463
--- /dev/null
+++ b/kernel/lib/strcat.c
@@ -0,0 +1,7 @@
+#include <lib.h>
+
+char *strcat(char *restrict dest, const char *restrict src)
+{
+ strcpy(dest + strlen(dest), src);
+ return dest;
+}
diff --git a/kernel/lib/strcpy.c b/kernel/lib/strcpy.c
new file mode 100644
index 0000000..d74e68d
--- /dev/null
+++ b/kernel/lib/strcpy.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+char *strcpy(char *restrict dest, const char *restrict src)
+{
+ char *d = dest;
+ for (; (*d = *src); d++, src++)
+ ;
+ return dest;
+}
diff --git a/kernel/lib/strlen.c b/kernel/lib/strlen.c
new file mode 100644
index 0000000..6d31f2f
--- /dev/null
+++ b/kernel/lib/strlen.c
@@ -0,0 +1,9 @@
+#include <lib.h>
+
+size_t strlen(const char *str)
+{
+ const char *p;
+ for (p = str; *p != 0; p++) {
+ }
+ return p - str;
+}
diff --git a/kernel/lib/strncmp.c b/kernel/lib/strncmp.c
new file mode 100644
index 0000000..0cf5837
--- /dev/null
+++ b/kernel/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <lib.h>
+
+int strncmp(const char *restrict lhs, const char *restrict rhs, size_t n)
+{
+ const unsigned char *l = (void *)lhs, *r = (void *)rhs;
+ if (!n--)
+ return 0;
+ for (; *l && *r && n && *l == *r; l++, r++, n--)
+ ;
+ return *l - *r;
+}
diff --git a/kernel/lib/strncpy.c b/kernel/lib/strncpy.c
new file mode 100644
index 0000000..f691191
--- /dev/null
+++ b/kernel/lib/strncpy.c
@@ -0,0 +1,10 @@
+#include <lib.h>
+
+char *strncpy(char *restrict dest, const char *restrict src, size_t n)
+{
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--)
+ ;
+ memset(d, 0, n);
+ return dest;
+}
diff --git a/kernel/lib/strtoux.c b/kernel/lib/strtoux.c
new file mode 100644
index 0000000..e8f828b
--- /dev/null
+++ b/kernel/lib/strtoux.c
@@ -0,0 +1,43 @@
+#include <lib.h>
+
+#define STRTOUX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return num; \
+ }
+
+STRTOUX(strtoui, unsigned int)
+STRTOUX(strtoul, unsigned long int)
+STRTOUX(strtoull, unsigned long long int)
diff --git a/kernel/lib/strtox.c b/kernel/lib/strtox.c
new file mode 100644
index 0000000..620b8d3
--- /dev/null
+++ b/kernel/lib/strtox.c
@@ -0,0 +1,52 @@
+#include <lib.h>
+
+#define STRTOX(name, type) \
+ type name(const char *restrict s, char **restrict endptr, int radix) \
+ { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++) \
+ ; \
+ \
+ int sign = 0; \
+ switch (*s) { \
+ case '-': \
+ sign = 1; /* fallthrough */ \
+ case '+': \
+ s++; \
+ break; \
+ } \
+ \
+ if ((radix == 0 || radix == 16) && \
+ (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) \
+ break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return sign ? -num : num; \
+ }
+
+STRTOX(strtoi, int)
+STRTOX(strtol, long int)
+STRTOX(strtoll, long long int)
diff --git a/kernel/lib/uxtoa.c b/kernel/lib/uxtoa.c
new file mode 100644
index 0000000..9133d29
--- /dev/null
+++ b/kernel/lib/uxtoa.c
@@ -0,0 +1,27 @@
+#include <lib.h>
+
+#define UXTOA(type, name) \
+ char *name(unsigned type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+UXTOA(int, utoa)
+UXTOA(long int, ultoa)
+UXTOA(long long int, ulltoa)
diff --git a/kernel/lib/xtoa.c b/kernel/lib/xtoa.c
new file mode 100644
index 0000000..bd3a367
--- /dev/null
+++ b/kernel/lib/xtoa.c
@@ -0,0 +1,31 @@
+#include <lib.h>
+
+#define XTOA(type, name) \
+ char *name(type n, char *buffer, int radix) \
+ { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ if (n < 0) { \
+ *buffer++ = '-'; \
+ n = -n; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
+ }
+
+XTOA(int, itoa)
+XTOA(long int, ltoa)
+XTOA(long long int, lltoa)