summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2026-05-26 21:32:27 +0000
committerAda Christine <adachristine18@gmail.com>2026-05-26 21:32:27 +0000
commita10aabfcd52f702057316018cd7847ab2bfe4aa1 (patch)
treecc4652d2b602798934e8a48b4939cfb20eda1989 /lib
parent90c29fdde317c39384011a6ba97077c138f13ad6 (diff)
we're bringing kjarna back and not doing the crazy stuff with trying to have task management during efi. that was a bit extra.kjarna
Diffstat (limited to 'lib')
-rw-r--r--lib/api/libc/stdio.h20
-rw-r--r--lib/api/libc/stdlib.h9
-rw-r--r--lib/api/libc/string.h14
-rw-r--r--lib/api/libc/wchar.h6
-rw-r--r--lib/elf64.c6
-rw-r--r--lib/heap.c154
-rw-r--r--lib/kprintf.c653
-rw-r--r--lib/libc/memcmp.c (renamed from lib/memcmp.c)0
-rw-r--r--lib/libc/memcpy.c (renamed from lib/memcpy.c)0
-rw-r--r--lib/libc/memmove.c (renamed from lib/memmove.c)0
-rw-r--r--lib/libc/memset.c (renamed from lib/memset.c)0
-rw-r--r--lib/libc/printf.c (renamed from lib/printf.c)86
-rw-r--r--lib/libc/stdio.c (renamed from lib/stdio.c)0
-rw-r--r--lib/libc/string.c (renamed from lib/string.c)0
14 files changed, 274 insertions, 674 deletions
diff --git a/lib/api/libc/stdio.h b/lib/api/libc/stdio.h
new file mode 100644
index 0000000..81ee462
--- /dev/null
+++ b/lib/api/libc/stdio.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <libc/string.h>
+
+#include <stdarg.h>
+
+typedef struct FILE FILE;
+
+extern FILE *stdout;
+extern FILE *stderr;
+
+extern int fputc(int c, FILE *f);
+
+int vfprintf(FILE *f, const char *restrict format, va_list arguments);
+int fprintf(FILE *f, const char *restrict format, ...);
+int vprintf(const char *restrict format, va_list arguments);
+int printf(const char *restrict format, ...);
+int vsprintf(char *s, const char *restrict format, va_list arguments);
+int sprintf(char *s, const char *restrict format, ...);
+
diff --git a/lib/api/libc/stdlib.h b/lib/api/libc/stdlib.h
new file mode 100644
index 0000000..d1f3d3b
--- /dev/null
+++ b/lib/api/libc/stdlib.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stddef.h>
+
+size_t mbstowcs(wchar_t *dst, const char *src, size_t length);
+void *malloc(size_t size);
+void *calloc(size_t count, size_t size);
+void free(void *block);
+
diff --git a/lib/api/libc/string.h b/lib/api/libc/string.h
new file mode 100644
index 0000000..c28e17c
--- /dev/null
+++ b/lib/api/libc/string.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <stddef.h>
+
+void *memcpy(void *dest, const void *src, size_t size);
+void *memmove(void *dest, const void *src, size_t size);
+void *memset(void *dest, int val, size_t size);
+int memcmp(const void *str1, const void *str2, size_t count);
+size_t strlen(const char *s);
+unsigned long long strtoull(
+ const char *restrict begin,
+ char **restrict end,
+ int base);
+
diff --git a/lib/api/libc/wchar.h b/lib/api/libc/wchar.h
new file mode 100644
index 0000000..350c209
--- /dev/null
+++ b/lib/api/libc/wchar.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <stddef.h>
+
+size_t wcslen(const wchar_t *s);
+wchar_t *wcsdup(const wchar_t *s);
diff --git a/lib/elf64.c b/lib/elf64.c
index b5afc18..38cfc11 100644
--- a/lib/elf64.c
+++ b/lib/elf64.c
@@ -79,7 +79,7 @@ bool elf64_validate_fd(int fd, unsigned type, unsigned machine)
return elf64_validate(&ehdr, type, machine);
}
-static bool is_loadable(Elf64_Phdr const *phdr)
+static bool segment_is_loadable(Elf64_Phdr const *phdr)
{
return phdr != nullptr && phdr->p_type == PT_LOAD;
}
@@ -92,7 +92,7 @@ static size_t aligned_size(Elf64_Phdr const *phdr)
static size_t segment_memsz(Elf64_Phdr const *phdr)
{
- return is_loadable(phdr) ? aligned_size(phdr) : 0;
+ return segment_is_loadable(phdr) ? aligned_size(phdr) : 0;
}
size_t elf64_size(Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs)
@@ -168,7 +168,7 @@ uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type)
static ssize_t load_segment(int fd, Elf64_Phdr *phdr, size_t buffer_size, char buffer[buffer_size])
{
- if (!is_loadable(phdr))
+ if (!segment_is_loadable(phdr))
{
return 0;
}
diff --git a/lib/heap.c b/lib/heap.c
index 8331a17..03d5425 100644
--- a/lib/heap.c
+++ b/lib/heap.c
@@ -1,23 +1,143 @@
#include <string.h>
#include <stdlib.h>
+#include <sys/mman.h>
+
+#include "config.h"
struct heap_node
{
- struct heap_node *next;
size_t size;
+ union
+ {
+ struct
+ {
+ struct heap_node *prev;
+ struct heap_node *next;
+ };
+ struct
+ {
+ char block;
+ };
+ };
};
struct heap_head
{
- struct heap_node *first;
- size_t total_bytes;
- size_t ready_bytes;
+ size_t allocated_size;
+ size_t maximum_size;
+ size_t minimum_alloc;
+ struct heap_node *root;
};
+struct heap_head *heap;
+
+void *allocate_superblock(void)
+{
+ return mmap(nullptr, HEAP_SEGMENT_SIZE, 0, 0, -1, 0);
+}
+
+static struct heap_node *try_create_heap()
+{
+ if (heap != nullptr) return heap->root;
+
+ char *superblock = allocate_superblock();
+
+ heap = (struct heap_head *)superblock;
+ heap->root = (struct heap_node *)(superblock + sizeof(struct heap_head));
+
+ heap->allocated_size = HEAP_SEGMENT_SIZE;
+ heap->maximum_size = HEAP_MAX_SIZE;
+ heap->minimum_alloc = sizeof(heap->root);
+
+ heap->root->next = nullptr;
+ heap->root->prev = nullptr;
+ heap->root->size = HEAP_SEGMENT_SIZE - sizeof(superblock) - sizeof(heap->root->size);
+
+ return heap->root;
+}
+
+static struct heap_node *try_grow_heap(struct heap_node *prev)
+{
+ if (heap->allocated_size >= heap->maximum_size)
+ {
+ return nullptr;
+ }
+
+ struct heap_node *node = allocate_superblock();
+
+ if (node == nullptr)
+ {
+ return nullptr;
+ }
+
+ node->size = HEAP_SEGMENT_SIZE - sizeof(node->size);
+ node->prev = prev;
+ prev->next = node;
+
+ return node;
+}
+
+static inline size_t get_node_size(size_t size)
+{
+ return size + sizeof(size);
+}
+
+static inline bool can_divide_node(struct heap_node *parent)
+{
+ return parent->size <= heap->minimum_alloc + sizeof(struct heap_node);
+}
+
+static inline void *new_node_address(struct heap_node *parent, size_t size)
+{
+ return &parent->block + parent->size - get_node_size(size);
+}
+
+static inline struct heap_node *divide_node(struct heap_node *parent, size_t size)
+{
+ struct heap_node *child = new_node_address(parent, size);
+
+ parent->size -= get_node_size(size);
+ child->size = size;
+
+ return child;
+}
+
+static inline struct heap_node *try_divide_node(struct heap_node *node, size_t size)
+{
+ return can_divide_node(node) ? divide_node(node, size) : node;
+}
+
+static inline struct heap_node *allocate_node(size_t size)
+{
+ struct heap_node *node = try_create_heap();
+
+ while(node != nullptr)
+ {
+ if (node->size > size)
+ {
+ break;
+ }
+
+ node = node->next
+ ? node->next
+ : try_grow_heap(node);
+ }
+
+ return node;
+}
+
void *malloc(size_t size)
{
- (void)size;
- return nullptr;
+ // TODO: min(heap->minimum_alloc, size);
+ size = size >= heap->minimum_alloc
+ ? size
+ : heap->minimum_alloc;
+
+ struct heap_node *node = try_divide_node(allocate_node(size), size);
+
+ return node != nullptr
+ ? &node->block
+ : nullptr;
}
void *calloc(size_t count, size_t size)
@@ -32,8 +152,28 @@ void *calloc(size_t count, size_t size)
return block;
}
+static inline struct heap_node *block_to_node(char *block)
+{
+ return (struct heap_node *)(block - sizeof(size_t));
+}
+
void free(void *block)
{
- (void)block;
+ // TODO: insertion sort by address of node
+ // TODO: coalesce adjacent nodes
+ if (block == nullptr)
+ {
+ return;
+ }
+
+ struct heap_node *node = block_to_node(block);
+ node->prev = nullptr;
+ node->next = heap->root;
+ heap->root = node;
+
+ if (node->next != nullptr)
+ {
+ node->next->prev = node;
+ }
}
diff --git a/lib/kprintf.c b/lib/kprintf.c
deleted file mode 100644
index 3d803f6..0000000
--- a/lib/kprintf.c
+++ /dev/null
@@ -1,653 +0,0 @@
-#include <lib/kstdio.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-enum specifier_type
-{
- INVALID_PRINT,
- CHARACTER_PRINT,
- STRING_PRINT,
- INTEGER_PRINT,
- COUNT_PRINT
-};
-
-enum specifier_flags
-{
- INVALID_FLAGS,
- LEFT_JUSTIFY_FLAG = 0x1,
- EXPLICIT_SIGN_FLAG = 0x2,
- PAD_SIGN_FLAG = 0x4,
- SIGNED_TYPE_FLAG = 0x8,
- SIGN_FLAG_MASK = 0x6,
- ALTERNATE_FORM_FLAG = 0x10,
- ZERO_PAD_FLAG = 0x20,
-};
-
-enum specifier_integer_base
-{
- INVALID_BASE,
- BIN_BASE = 2,
- OCT_BASE = 8,
- DEC_BASE = 10,
- HEX_BASE = 16
-};
-
-enum specifier_integer_width
-{
- INVALID_WIDTH,
- BYTE_WIDTH = 8,
- SHORT_WIDTH = 16,
- INT_WIDTH = 32,
- LONG_WIDTH = 64
-};
-
-struct method
-{
- int (*write_character)(struct method *m, char c);
- int (*write_wcharacter)(struct method *m, wchar_t c);
- int (*write_string)(struct method *m, const char *s);
- int (*write_wstring)(struct method *m, const wchar_t *s);
- void *output;
- int count;
-};
-
-struct specifier
-{
- enum specifier_type type;
- enum specifier_flags flags;
- enum specifier_integer_width integer_width;
- enum specifier_integer_base integer_base;
- int field_width;
- int field_precision;
- size_t length;
-};
-
-static struct specifier parse_specifier(const char *format, va_list *arguments)
-{
- struct specifier result =
- {
- INVALID_PRINT,
- INVALID_FLAGS,
- INVALID_WIDTH,
- INVALID_BASE,
- 0,
- 0,
- 0
- };
-
- // keep a pointer to the beginning of the specifier
- const char *begin = format;
-
- // step 1: scan for flags
- bool flags_parsed = false;
-
- while (!flags_parsed)
- {
- switch (*begin)
- {
- case 0:
- result.type = INVALID_PRINT;
- return result;
- case '-':
- result.flags |= LEFT_JUSTIFY_FLAG;
- begin++;
- break;
- case '+':
- result.flags |= EXPLICIT_SIGN_FLAG;
- begin++;
- break;
- case ' ':
- result.flags |= PAD_SIGN_FLAG;
- begin++;
- break;
- case '#':
- result.flags |= ALTERNATE_FORM_FLAG;
- begin++;
- break;
- case '0':
- result.flags |= ZERO_PAD_FLAG;
- begin++;
- break;
- default:
- flags_parsed = true;
- }
- }
-
- // step 2: parse field width and precision
- // TODO: parse field width and precision
- /* procedure:
- * 1. check if next character is * or .
- * a. if *, field width is the value pointed to by the next item in
- * arguments list
- * b. if ., field width will be set to 0, proceed to 3.
- * 2. if above check is false, check for numeric character
- * a. if is numeric character, parse field width via strtoul, add length
- * of numeric string to begin.
- * b. if is not a numeric character, skip check for width and precision
- * entirely
- * 3. check if next character is * or numeric
- * a. if *, field precision is the value pointed to by the next item
- * in arguments list.
- * b. if is numeric character, parse field precision via strtoul, add
- * length of numeric string to begin.
- */
- bool field_width_parsed = false;
- bool field_precision_parsed = false;
-
- while (!field_width_parsed || !field_precision_parsed)
- {
- switch (*begin)
- {
- case '.':
- if (!field_width_parsed)
- {
- result.field_width = 0;
- field_width_parsed = true;
- begin++;
- }
- else
- {
- // the specifier is invalid!
- result.type = INVALID_PRINT;
- }
- break;
- case '*':
- {
- int w = *va_arg(*arguments, int *);
- if (!field_width_parsed)
- {
- result.field_width = w;
- field_width_parsed = true;
- }
- else
- {
- result.field_precision = w;
- field_precision_parsed = true;
- }
- begin++;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- {
- char *next;
- unsigned long long w = strtoull(begin, &next, 10);
- if (!field_width_parsed)
- {
- result.field_width = (int)w;
- field_width_parsed = true;
- }
- else if (!field_precision_parsed)
- {
- result.field_precision = (int)w;
- field_precision_parsed = true;
- }
- if (next > begin)
- {
- begin = next;
- }
- }
- break;
- default:
- field_width_parsed = true;
- field_precision_parsed = true;
- }
- }
-
- // step 3: check for type width arguments
- switch (*begin)
- {
- case 0: // unexpected eos
- result.type = INVALID_PRINT;
- return result;
- case 'h':
- {
- if (begin[0] == begin[1])
- {
- result.integer_width = BYTE_WIDTH;
- begin += 2;
- }
- else
- {
- result.integer_width = SHORT_WIDTH;
- begin++;
- }
- break;
- }
- case 'l':
- {
- // TODO: deal with LLP64? idk.
- if (begin[0] == begin[1])
- {
- begin += 2;
- }
- else
- {
- begin++;
- }
- result.integer_width = LONG_WIDTH;
- break;
- }
- case 'j':
- // TODO: use INTMAX_T_WIDTH
- result.integer_width = 64;
- begin++;
- break;
- case 'z':
- // TODO: use SIZE_T_WIDTH?
- result.integer_width = 64;
- begin++;
- break;
- case 't':
- // TODO: use PTRDIFF_T_WIDTH?
- result.integer_width = 32;
- begin++;
- break;
- default:
- // there is no width argument to be found.
- result.integer_width = INT_WIDTH;
- break;
- }
-
- // step 4: parse field type
- switch (*begin)
- {
- // unexpected EOS
- case 0:
- result.type = INVALID_PRINT;
- return result;
- case 'c':
- result.type = CHARACTER_PRINT;
- break;
- case 's':
- result.type = STRING_PRINT;
- break;
- case 'd':
- case 'i':
- result.type = INTEGER_PRINT;
- result.flags |= SIGNED_TYPE_FLAG;
- result.integer_base = DEC_BASE;
- break;
- case 'u':
- result.type = INTEGER_PRINT;
- result.integer_base = DEC_BASE;
- break;
- case 'b':
- result.type = INTEGER_PRINT;
- result.integer_base = BIN_BASE;
- break;
- case 'o':
- result.type = INTEGER_PRINT;
- result.integer_base = OCT_BASE;
- break;
- case 'x':
- result.type = INTEGER_PRINT;
- result.integer_base = HEX_BASE;
- break;
- case 'p':
- // TODO: use UINTPTR_T_WIDTH here?
- // pointer type overrides all flags
- // i can do what i want it says "implementation-defined" in the spec
- result.field_precision = 16;
- result.type = INTEGER_PRINT;
- result.integer_base = HEX_BASE;
- result.integer_width = LONG_WIDTH;
- result.flags = ALTERNATE_FORM_FLAG|ZERO_PAD_FLAG;
- break;
- case 'n':
- // all flags are invalid/ignored and the current count will be
- // stored in the value pointed to by the argument
- result.type = COUNT_PRINT;
- result.flags = INVALID_FLAGS;
- result.integer_width = INVALID_WIDTH;
- result.field_width = 0;
- result.field_precision = 0;
- break;
- default:
- // this byte of the specifier _must_ be valid. if not,
- // the procedure to print should not proceed as it might
- // output garbage.
- // TODO: specify somehow in the output that the format is bad?
- result.type = INVALID_PRINT;
- return result;
- }
-
- begin++;
-
- result.length = begin - format;
- return result;
-}
-
-static char *convert_integer(
- uint64_t value,
- unsigned base,
- int zpadding,
- char *buffer,
- size_t bufsz)
-{
- static const char *stringdigits = "0123456789abcdef";
-
- // 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
-
- // cannot currently work with a base > 16
- if (base > 16)
- {
- return NULL;
- }
-
- // make absolutely sure there are no excess bits
-
- // 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 underflow
-
- do
- {
- *--result = stringdigits[value % base];
- zpadding--;
- value /= base;
- }
- while (value > 0 && result >= buffer);
-
- while (zpadding-- > 0 && result >= buffer)
- {
- *--result = '0';
- }
-
- return result;
-}
-
-static int print_character(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- (void)spec;
- // all specifier flags and etc. are ignored.
- return m->write_character(m, va_arg(*arguments, int));
-}
-
-static int print_string(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- // TODO: respect field width
- if (spec->integer_width == LONG_WIDTH)
- {
- return m->write_wstring(m, va_arg(*arguments, const wchar_t *));
- }
- return m->write_string(m, va_arg(*arguments, const char *));
-}
-
-static inline bool is_negative(uint64_t value, unsigned width)
-{
- switch (width)
- {
- case BYTE_WIDTH:
- return ((int8_t)value) < 0;
- case SHORT_WIDTH:
- return ((int16_t)value) < 0;
- case INT_WIDTH:
- return ((int32_t)value) < 0;
- case LONG_WIDTH:
- return ((int64_t)value) < 0;
- default:
- return false;
- }
-}
-
-static int print_integer(
- struct method *m,
- struct specifier *spec,
- va_list *arguments)
-{
- // 65 bytes is the maximum length that convert_integer will need
- // i.e. conversion of uintmax_t to binary plus NUL terminator
- // TODO: use UINTMAX_T_WIDTH + 1?
- char buffer[65] = {0};
- char *s;
- bool negative = false;
- uint64_t value = 0;
- int r = 0;
- unsigned zpad = 0;
-
- switch (spec->integer_width)
- {
- case BYTE_WIDTH:
- case SHORT_WIDTH:
- case INT_WIDTH:
- value = va_arg(*arguments, unsigned int);
- break;
- case LONG_WIDTH:
- value = va_arg(*arguments, uint64_t);
- break;
- default:
- return -1;
- }
-
- // check if we need to bother with signs
- if (spec->flags & SIGNED_TYPE_FLAG)
- {
- if ((negative = is_negative(value, spec->integer_width)))
- {
- value = ~value + 1;
- }
-
- if (negative)
- {
- r = m->write_character(m, '-');
- }
-
- else if (!negative && (spec->flags & SIGN_FLAG_MASK))
- {
- if (spec->flags & EXPLICIT_SIGN_FLAG)
- {
- r = m->write_character(m, '+');
- }
- else
- {
- r = m->write_character(m, ' ');
- }
- }
- }
-
- // zero all the unnecessary bits
- value &= (2ULL << (spec->integer_width - 1)) - 1;
-
- switch (spec->integer_base)
- {
- case BIN_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_string(m, "0b");
- }
- break;
- case OCT_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_character(m, '0');
- }
- break;
- case HEX_BASE:
- if (spec->flags & ALTERNATE_FORM_FLAG)
- {
- r = m->write_string(m, "0x");
- }
- break;
- default:
- break;
- }
-
- if (spec->flags & ZERO_PAD_FLAG)
- {
- zpad = spec->field_precision;
- }
- s = convert_integer(value, spec->integer_base, zpad, buffer, sizeof(buffer));
-
- if (s)
- {
- m->write_string(m, s);
- }
- else
- {
- m->write_string(m, "(INVALID)");
- r = -1;
- }
-
- return r;
-}
-
-static int printf_internal(
- struct method *m,
- const char *restrict format,
- va_list *arguments)
-{
- int r = 0;
-
- while (*format && !r)
- {
- // case 1: not a format specification
- if (*format != '%')
- {
- r = m->write_character(m, *format++);
- continue;
- }
-
- // case 2: looks like a format specification, but isn't
- else if (*format == '%' && format[0] == format[1])
- {
- r = m->write_character(m, '%');
- format += 2;
- continue;
- }
-
- // case 3: is a format specification. parse it
- struct specifier spec = parse_specifier(++format, arguments);
-
- switch (spec.type)
- {
- case CHARACTER_PRINT:
- r = print_character(m, &spec, arguments);
- break;
- case STRING_PRINT:
- r = print_string(m, &spec, arguments);
- break;
- case INTEGER_PRINT:
- r = print_integer(m, &spec, arguments);
- break;
- default:
- r = m->write_string(m, "(INVALID)");
- return -1;
- }
- format += spec.length;
- }
-
- return r;
-}
-
-static int kfp_write_character(struct method *m, char c)
-{
- kfputc((int)c, (FILE *)m->output);
- m->count++;
- return 0;
-}
-
-static int kfp_write_wcharacter(struct method *m, wchar_t c)
-{
- kfputc((int)c, (FILE *)m->output);
- m->count++;
- return 0;
-}
-
-static int kfp_write_string(struct method *m, const char *c)
-{
- while (*c)
- {
- m->write_character(m, *c++);
- }
- return 0;
-}
-
-static int kfp_write_wstring(struct method *m, const wchar_t *s)
-{
- while (*s)
- {
- m->write_wcharacter(m, *s++);
- }
- return 0;
-}
-
-int kvfprintf(FILE *f, const char *restrict format, va_list arguments)
-{
- struct method m = {
- kfp_write_character,
- kfp_write_wcharacter,
- kfp_write_string,
- kfp_write_wstring,
- (void *)f,
- 0};
- va_list acopy;
- va_copy(acopy, arguments);
- int r = printf_internal(&m, format, &acopy);
- va_end(acopy);
-
- if (!r)
- {
- return m.count;
- }
- else
- {
- return -1;
- }
-}
-
-int kfprintf(FILE *f, const char *restrict format, ...)
-{
- va_list arguments;
- va_start(arguments, format);
-
- int count = kvfprintf(f, format, arguments);
-
- va_end(arguments);
-
- return count;
-}
-
-int kvprintf(const char *restrict format, va_list arguments)
-{
- va_list acopy;
- va_copy(acopy, arguments);
-
- int count = kvfprintf(kstdout, format, arguments);
-
- va_end(acopy);
-
- return count;
-}
-
-int kprintf(const char *restrict format, ...)
-{
- va_list arguments;
- va_start(arguments, format);
-
- int count = kvprintf(format, arguments);
-
- va_end(arguments);
-
- return count;
-}
-
diff --git a/lib/memcmp.c b/lib/libc/memcmp.c
index 2348afe..2348afe 100644
--- a/lib/memcmp.c
+++ b/lib/libc/memcmp.c
diff --git a/lib/memcpy.c b/lib/libc/memcpy.c
index 58b1e40..58b1e40 100644
--- a/lib/memcpy.c
+++ b/lib/libc/memcpy.c
diff --git a/lib/memmove.c b/lib/libc/memmove.c
index fd06bb6..fd06bb6 100644
--- a/lib/memmove.c
+++ b/lib/libc/memmove.c
diff --git a/lib/memset.c b/lib/libc/memset.c
index 3e7025e..3e7025e 100644
--- a/lib/memset.c
+++ b/lib/libc/memset.c
diff --git a/lib/printf.c b/lib/libc/printf.c
index 4fd14e9..fa68bcc 100644
--- a/lib/printf.c
+++ b/lib/libc/printf.c
@@ -568,22 +568,43 @@ static int kfp_write_character(struct method *m, char c)
static int kfp_write_wcharacter(struct method *m, wchar_t c)
{
- (void)m;
- (void)c;
- return -1;
+ fputc((int)c, (FILE *)m->output);
+ m->count++;
+ return 0;
+}
+
+static int naive_write_string(struct method *m, const char *c)
+{
+ while (*c)
+ {
+ m->write_character(m, *c++);
+ }
+ return 0;
}
-static int kfp_write_string(struct method *m, const char *s)
+static int naive_write_wstring(struct method *m, const wchar_t *s)
{
- m->count += fputs(s, (FILE *)m->output);
+ while (*s)
+ {
+ m->write_wcharacter(m, *s++);
+ }
return 0;
}
-static int kfp_write_wstring(struct method *m, const wchar_t *s)
+static int ss_write_char(struct method *m, const char c)
+{
+ char *s = (char *)m->output;
+ *s++ = c;
+ m->count++;
+ return 0;
+}
+
+static int ss_write_wchar(struct method *m, const wchar_t c)
{
- (void)m;
- (void)s;
- return -1;
+ wchar_t *s = (wchar_t *)m->output;
+ *s++ = c;
+ m->count++;
+ return 0;
}
int vfprintf(FILE *f, const char *restrict format, va_list arguments)
@@ -591,8 +612,8 @@ int vfprintf(FILE *f, const char *restrict format, va_list arguments)
struct method m = {
kfp_write_character,
kfp_write_wcharacter,
- kfp_write_string,
- kfp_write_wstring,
+ naive_write_string,
+ naive_write_wstring,
(void *)f,
0};
va_list acopy;
@@ -646,3 +667,46 @@ int printf(const char *restrict format, ...)
return count;
}
+int vsprintf(char *s, const char *restrict format, va_list arguments)
+{
+ va_list acopy;
+ va_copy(acopy, arguments);
+
+ struct method m =
+ {
+ ss_write_char,
+ ss_write_wchar,
+ naive_write_string,
+ naive_write_wstring,
+ (void *)s,
+ 0
+ };
+
+ int r = printf_internal(&m, format, &acopy);
+ va_end(acopy);
+
+ if (!r)
+ {
+ return m.count;
+ }
+ else
+ {
+ return -1;
+ }
+
+ return r;
+}
+
+int sprintf(char *s, const char *restrict format, ...)
+{
+ va_list arguments;
+ va_start(arguments, format);
+
+ int count = vsprintf(s, format, arguments);
+
+ va_end(arguments);
+
+ return count;
+}
+
+
diff --git a/lib/stdio.c b/lib/libc/stdio.c
index 70cc685..70cc685 100644
--- a/lib/stdio.c
+++ b/lib/libc/stdio.c
diff --git a/lib/string.c b/lib/libc/string.c
index 2da2070..2da2070 100644
--- a/lib/string.c
+++ b/lib/libc/string.c