From 41ee6b43c89ce67808a684ba67f69e964b0636fa Mon Sep 17 00:00:00 2001 From: aqua Date: Sat, 18 Feb 2023 10:12:24 +0200 Subject: Move C stdlib to lib/libk --- lib/libk/endian.h | 17 ++++++++ lib/libk/endian/little.c | 43 ++++++++++++++++++ lib/libk/stdio.h | 58 +++++++++++++++++++++++++ lib/libk/stdio/fprintf.c | 11 +++++ lib/libk/stdio/printf.c | 11 +++++ lib/libk/stdio/vfprintf.cpp | 54 +++++++++++++++++++++++ lib/libk/stdlib.h | 31 +++++++++++++ lib/libk/stdlib/linked_list_allocator.c | 77 +++++++++++++++++++++++++++++++++ lib/libk/stdlib/memcpy.c | 13 ++++++ lib/libk/stdlib/memset.c | 7 +++ lib/libk/string.h | 28 ++++++++++++ lib/libk/string/itoa.c | 30 +++++++++++++ 12 files changed, 380 insertions(+) create mode 100644 lib/libk/endian.h create mode 100644 lib/libk/endian/little.c create mode 100644 lib/libk/stdio.h create mode 100644 lib/libk/stdio/fprintf.c create mode 100644 lib/libk/stdio/printf.c create mode 100644 lib/libk/stdio/vfprintf.cpp create mode 100644 lib/libk/stdlib.h create mode 100644 lib/libk/stdlib/linked_list_allocator.c create mode 100644 lib/libk/stdlib/memcpy.c create mode 100644 lib/libk/stdlib/memset.c create mode 100644 lib/libk/string.h create mode 100644 lib/libk/string/itoa.c (limited to 'lib/libk') diff --git a/lib/libk/endian.h b/lib/libk/endian.h new file mode 100644 index 0000000..70bc5f7 --- /dev/null +++ b/lib/libk/endian.h @@ -0,0 +1,17 @@ +//===================================================================== +// spdx-license-identifier: ISC +//===================================================================== + +#pragma once + +#include + +// These functions convert the byte encoding of integer values from host byte order to and from little-endian and +// big-endian byte order +uint16_t htole16(uint16_t host_16b); +uint32_t htole32(uint32_t host_32b); +uint64_t htole64(uint64_t host_64b); + +uint16_t htobe16(uint16_t host_16b); +uint32_t htobe32(uint32_t host_32b); +uint64_t htobe64(uint64_t host_64b); diff --git a/lib/libk/endian/little.c b/lib/libk/endian/little.c new file mode 100644 index 0000000..042bb55 --- /dev/null +++ b/lib/libk/endian/little.c @@ -0,0 +1,43 @@ +//===================================================================== +// spdx-license-identifier: ISC +//===================================================================== + +#include "endian.h" + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +#error little.c included in build on big endian target +#endif + +uint16_t +htole16(uint16_t host_16b) +{ + return host_16b; +} + +uint32_t +htole32(uint32_t host_32b) +{ + return host_32b; +} + +uint64_t +htole64(uint64_t host_64b) +{ + return host_64b; +} + +uint16_t +htobe16(uint16_t host_16b) +{ + return __builtin_bswap16(host_16b); +} +uint32_t +htobe32(uint32_t host_32b) +{ + return __builtin_bswap32(host_32b); +} +uint64_t +htobe64(uint64_t host_64b) +{ + return __builtin_bswap64(host_64b); +} diff --git a/lib/libk/stdio.h b/lib/libk/stdio.h new file mode 100644 index 0000000..5ef68f1 --- /dev/null +++ b/lib/libk/stdio.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +///@defgroup libk libk +///@{ +///@defgroup stdio stdio +///@{ + +#ifdef __cplusplus +/** + * An object type used for streams + */ +struct kIoDevice { + /** Function that prints a character to the stream */ + virtual void putc(char) = 0; + /** Function that prints a string to the stream */ + virtual int puts(const char *, int) = 0; + /** Flush write buffers */ + virtual void flush() = 0; +}; +typedef kIoDevice FILE; +#else +typedef void FILE; +#endif + +/** A FILE value corresponding to stdin, the keyboard buffer */ +extern FILE *stdin; +/** A FILE value corresponding to stdout, the display */ +extern FILE *stdout; +/** A FILE value corresponding to stderr, the uart */ +extern FILE *stderr; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Write the formatted string to stdout + * Supports ``%s`` (string), ``%d`` (decimal), ``%u`` (unsigned), ``%x`` (hexadecimal) + * @return number of bytes written + */ +int printf(const char *restrict format, ...); + +/** + * Write the formatted string to stream; see printf + */ +int fprintf(FILE *restrict stream, const char *restrict format, ...); + +/** + * Write the formatted string to stream; see printf + */ +int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); +#ifdef __cplusplus +} +#endif + +///@} +///@} diff --git a/lib/libk/stdio/fprintf.c b/lib/libk/stdio/fprintf.c new file mode 100644 index 0000000..9a96dc6 --- /dev/null +++ b/lib/libk/stdio/fprintf.c @@ -0,0 +1,11 @@ +#include + +int +fprintf(FILE *restrict stream, const char *restrict format, ...) +{ + va_list ap; + va_start(ap, format); + int c = vfprintf(stream, format, ap); + va_end(ap); + return c; +} diff --git a/lib/libk/stdio/printf.c b/lib/libk/stdio/printf.c new file mode 100644 index 0000000..4efc1ac --- /dev/null +++ b/lib/libk/stdio/printf.c @@ -0,0 +1,11 @@ +#include + +int +printf(const char *restrict format, ...) +{ + va_list ap; + va_start(ap, format); + int c = vfprintf(stdout, format, ap); + va_end(ap); + return c; +} diff --git a/lib/libk/stdio/vfprintf.cpp b/lib/libk/stdio/vfprintf.cpp new file mode 100644 index 0000000..aa9256d --- /dev/null +++ b/lib/libk/stdio/vfprintf.cpp @@ -0,0 +1,54 @@ +#include +#include + +static char buffer[3 * sizeof(int) + 2]; + +extern "C" int +vfprintf(FILE *restrict stream, const char *restrict format, va_list params) +{ + int written = 0; + + int s = 0; + int l = 0; + for (int i = 0; format[i] != '\0'; ++i) { + if (format[i] == '%') { + written += stream->puts(&format[s], l); + s = i + 2; + ++i; + + switch (format[i]) { + case 's': { + const char *arg = va_arg(params, const char *); + written += stream->puts(arg, -1); + } break; + case 'c': { + const int arg = va_arg(params, int); + stream->putc(arg); + ++written; + } break; + case 'd': { + const char *arg = itoa(buffer, va_arg(params, int), 10); + written += stream->puts(arg, -1); + } break; + case 'u': { + const char *arg = utoa(buffer, va_arg(params, unsigned int), 10); + written += stream->puts(arg, -1); + } break; + case 'x': { + const char *arg = utoa(buffer, va_arg(params, unsigned int), 16); + written += stream->puts(arg, -1); + } break; + } + + l = 0; + } + + else + ++l; + } + + if (l > 0) { written += stream->puts(&format[s], l); } + + stream->flush(); + return written; +} diff --git a/lib/libk/stdlib.h b/lib/libk/stdlib.h new file mode 100644 index 0000000..84d9b2d --- /dev/null +++ b/lib/libk/stdlib.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +///@defgroup libk libk +///@{ +///@defgroup stdlib stdlib +///@{ + +/** + * Allocate size bytes and return a pointer to the allocated memory + */ +void *malloc(size_t size); + +/** + * Free the memory space pointed to by ptr + */ +void free(void *ptr); + +/** + * Fill the first n bytes of the memory area pointed to by s with the constant byte c. + */ +void *memset(void *s, int c, long unsigned n); + +/** + * Copy n bytes from memory area src to memory area dest. The memory areas must not overlap. + */ +void *memcpy(void *restrict dest, const void *restrict src, long unsigned n); + +///@} +///@} diff --git a/lib/libk/stdlib/linked_list_allocator.c b/lib/libk/stdlib/linked_list_allocator.c new file mode 100644 index 0000000..66c63d1 --- /dev/null +++ b/lib/libk/stdlib/linked_list_allocator.c @@ -0,0 +1,77 @@ +#include +#include + +struct Chunk { + struct Chunk *prev; + struct Chunk *next; + int used; + size_t size; +}; + +void +Chunk_ctor(struct Chunk *self, size_t size) +{ + self->prev = NULL; + self->next = NULL; + self->used = 0; + self->size = size - sizeof(struct Chunk); +} + +static struct Chunk *begin = NULL; + +void +alloc_init(void *mem, size_t size) +{ + if (size < sizeof(struct Chunk)) return; + + begin = (struct Chunk *)mem; + Chunk_ctor(begin, size); +} + +void * +malloc(size_t size) +{ + if (begin == NULL) return NULL; + + // find free chunk that is at least (size + sizeof(struct Chunk)) + for (struct Chunk *iter = begin; iter != NULL; iter = iter->next) { + if (iter->used != 0 || iter->size < size) continue; + + // if there's at least sizeof(struct Chunk) bytes left over, create a new Chunk + if (iter->size >= (size + 2 * sizeof(struct Chunk))) { + struct Chunk *next = (struct Chunk *)((uintptr_t)iter + sizeof(struct Chunk) + size); + Chunk_ctor(next, iter->size - size - sizeof(struct Chunk)); + next->prev = iter; + + iter->size = size; + iter->next = next; + } + + iter->used = 1; + return (void *)((uintptr_t)iter + sizeof(struct Chunk)); + } + + return NULL; +} + +void +free(void *ptr) +{ + if (ptr == NULL) return; + struct Chunk *chunk = (struct Chunk *)((uintptr_t)ptr - sizeof(struct Chunk)); + chunk->used = 0; + + // merge next chunk + if (chunk->next != NULL && chunk->next->used == 0) { + chunk->size += chunk->next->size + sizeof(struct Chunk); + chunk->next = chunk->next->next; + if (chunk->next != NULL) chunk->next->prev = chunk; + } + + // merge into prev chunk + if (chunk->prev != NULL && chunk->prev->used == 0) { + chunk->prev->size += chunk->size + sizeof(struct Chunk); + chunk->prev->next = chunk->next; + if (chunk->next != NULL) chunk->next->prev = chunk->prev; + } +} diff --git a/lib/libk/stdlib/memcpy.c b/lib/libk/stdlib/memcpy.c new file mode 100644 index 0000000..90470d5 --- /dev/null +++ b/lib/libk/stdlib/memcpy.c @@ -0,0 +1,13 @@ +void * +memcpy(void *restrict dest, const void *restrict src, long unsigned n) +{ + char *pDest = (char *)dest; + const char *pSrc = (const char *)src; + + while (n) { + *(pDest++) = *(pSrc++); + --n; + } + + return dest; +} diff --git a/lib/libk/stdlib/memset.c b/lib/libk/stdlib/memset.c new file mode 100644 index 0000000..a16bd05 --- /dev/null +++ b/lib/libk/stdlib/memset.c @@ -0,0 +1,7 @@ +void * +memset(void *s, int c, long unsigned n) +{ + char *pDest = (char *)s; + for (unsigned i = 0; i < n; ++i) pDest[i] = (char)c; + return s; +} diff --git a/lib/libk/string.h b/lib/libk/string.h new file mode 100644 index 0000000..c8196c8 --- /dev/null +++ b/lib/libk/string.h @@ -0,0 +1,28 @@ +#pragma once + +///@defgroup libk libk +///@{ +///@defgroup string string +///@{ + +#define OCTAL 8 +#define DECIMAL 10 +#define HEX 16 + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Convert int into a string + */ +char *itoa(char *p, int x, int base); +/** + * Convert unsigned int into a string + */ +char *utoa(char *p, unsigned x, int base); +#ifdef __cplusplus +} +#endif + +///@} +///@} diff --git a/lib/libk/string/itoa.c b/lib/libk/string/itoa.c new file mode 100644 index 0000000..2db9768 --- /dev/null +++ b/lib/libk/string/itoa.c @@ -0,0 +1,30 @@ +#include +#include + +static const char *numbers = "0123456789abcdef"; + +char * +utoa(char *p, unsigned x, int base) +{ + p += 3 * sizeof(unsigned); + *--p = '\0'; + + do { + *--p = numbers[x % base]; + x /= base; + } while (x); + + return p; +} + +char * +itoa(char *p, int x, int base) +{ + const bool is_negative = (x < 0); + if (is_negative) x = -x; + + p = utoa(p, x, base); + + if (is_negative) *--p = '-'; + return p; +} -- cgit v1.2.1