From dadc3e570b81c129316d664a30af6a5ec72b9b77 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 19 Nov 2022 15:43:09 +0100 Subject: [PATCH] Move a few functions out of line --- CMakeLists.txt | 1 + kernel/CMakeLists.txt | 3 +- luna/CMakeLists.txt | 35 +++ luna/Format.cpp | 480 ++++++++++++++++++++++++++++++++++++++++ luna/Format.h | 487 +---------------------------------------- luna/NumberParsing.cpp | 153 +++++++++++++ luna/NumberParsing.h | 153 +------------ luna/String.cpp | 47 ++++ luna/String.h | 75 +------ 9 files changed, 728 insertions(+), 706 deletions(-) create mode 100644 luna/CMakeLists.txt create mode 100644 luna/Format.cpp create mode 100644 luna/NumberParsing.cpp create mode 100644 luna/String.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 576771e5..b14ad4b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,4 +16,5 @@ set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/x86-64-luna) +add_subdirectory(luna) add_subdirectory(kernel) \ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index fbe0b719..c9eddc8e 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -26,7 +26,7 @@ add_library(moon-asm STATIC ${ASM_SOURCES}) add_executable(moon ${SOURCES}) -target_link_libraries(moon moon-asm) +target_link_libraries(moon moon-asm luna-freestanding) target_compile_definitions(moon PRIVATE IN_MOON) @@ -51,7 +51,6 @@ target_link_options(moon PRIVATE -mno-red-zone) set_target_properties(moon PROPERTIES CXX_STANDARD 20) -target_include_directories(moon PUBLIC ${LUNA_ROOT}/luna) target_include_directories(moon PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) target_link_options(moon PRIVATE LINKER:-T ${CMAKE_CURRENT_LIST_DIR}/moon.ld -nostdlib -nodefaultlibs) diff --git a/luna/CMakeLists.txt b/luna/CMakeLists.txt new file mode 100644 index 00000000..bfb5d3f7 --- /dev/null +++ b/luna/CMakeLists.txt @@ -0,0 +1,35 @@ +set(FREESTANDING_SOURCES + Format.cpp + NumberParsing.cpp + String.cpp +) + +set(SOURCES + ${FREESTANDING_SOURCES} +) + +add_library(luna-freestanding ${FREESTANDING_SOURCES}) +target_compile_definitions(luna-freestanding PRIVATE USE_FREESTANDING) +target_compile_options(luna-freestanding PRIVATE -Wall -Wextra -Werror -Wvla) +target_compile_options(luna-freestanding PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) +target_compile_options(luna-freestanding PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(luna-freestanding PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(luna-freestanding PRIVATE -fno-rtti -ffreestanding -fno-exceptions) +target_compile_options(luna-freestanding PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer) +target_compile_options(luna-freestanding PRIVATE -nostdlib -mcmodel=kernel) + +# x86-64 specific +target_compile_options(luna-freestanding PRIVATE -mno-red-zone) +target_compile_options(luna-freestanding PRIVATE -mno-80387 -mno-mmx -mno-sse -mno-sse2) + +target_include_directories(luna-freestanding PUBLIC ${LUNA_ROOT}/luna) +set_target_properties(luna-freestanding PROPERTIES CXX_STANDARD 20) + +add_library(luna ${SOURCES}) +target_compile_options(luna PRIVATE -Wall -Wextra -Werror -Wvla) +target_compile_options(luna PRIVATE -Wdisabled-optimization -Wformat=2 -Winit-self) +target_compile_options(luna PRIVATE -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef) +target_compile_options(luna PRIVATE -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion) +target_compile_options(luna PRIVATE -fno-asynchronous-unwind-tables -fno-omit-frame-pointer) +target_include_directories(luna PUBLIC ${LUNA_ROOT}/luna) +set_target_properties(luna PROPERTIES CXX_STANDARD 20) \ No newline at end of file diff --git a/luna/Format.cpp b/luna/Format.cpp new file mode 100644 index 00000000..c16ff222 --- /dev/null +++ b/luna/Format.cpp @@ -0,0 +1,480 @@ +#include +#include + +extern "C" usize strlen(const char*); + +typedef int flags_t; +#define FLAG_ZERO_PAD 1 << 0 +#define FLAG_LEFT_ALIGN 1 << 1 +#define FLAG_BLANK_SIGNED 1 << 2 +#define FLAG_ALTERNATE 1 << 3 +#define FLAG_SIGN 1 << 4 +#define FLAG_USE_PRECISION 1 << 5 +#define FLAG_LONG 1 << 6 +#define FLAG_LONG_LONG 1 << 7 +#define FLAG_SHORT 1 << 8 +#define FLAG_CHAR 1 << 9 + +struct format_state +{ + usize count; + callback_t callback; + void* arg; +}; + +struct conv_state +{ + flags_t flags; + usize width; + usize precision; +}; + +static inline int cstyle_format_putchar(char c, format_state& state) +{ + state.count++; + return state.callback(c, state.arg); +} + +static inline int cstyle_format_puts(const char* s, format_state& state) +{ + while (*s) + { + if (cstyle_format_putchar(*s, state)) return -1; + s++; + } + + return 0; +} + +#define TRY_PUTCHAR(c, state) \ + if (cstyle_format_putchar(c, state)) return -1; + +#define TRY_PUTS(s, state) \ + if (cstyle_format_puts(s, state)) return -1; + +static int start_pad(const conv_state& vstate, format_state& state, usize start) +{ + if (!(vstate.flags & FLAG_LEFT_ALIGN)) + { + while (start++ < vstate.width) TRY_PUTCHAR(' ', state); + } + + return 0; +} + +#define TRY_START_PAD(vstate, state, start) \ + if (start_pad(vstate, state, start)) return -1; + +static int end_pad(const conv_state& vstate, format_state& state, usize start) +{ + if (vstate.flags & FLAG_LEFT_ALIGN) + { + while (start++ < vstate.width) TRY_PUTCHAR(' ', state); + } + + return 0; +} + +#define TRY_END_PAD(vstate, state, start) \ + if (end_pad(vstate, state, start)) return -1; + +static flags_t parse_flags(const char** format) +{ + flags_t result = 0; + + while (true) + { + switch (**format) + { + case '#': + result |= FLAG_ALTERNATE; + (*format)++; + break; + case '0': + result |= FLAG_ZERO_PAD; + (*format)++; + break; + case ' ': + result |= FLAG_BLANK_SIGNED; + (*format)++; + break; + case '-': + result |= FLAG_LEFT_ALIGN; + (*format)++; + break; + case '+': + result |= FLAG_SIGN; + (*format)++; + break; + default: return result; + } + } +} + +static usize parse_width(const char** format, flags_t& flags, va_list ap) +{ + usize result = 0; + + if (_isdigit(**format)) result = _atou(format); + else if (**format == '*') + { + const int width = va_arg(ap, int); + if (width >= 0) result = (usize)width; + else + { + flags |= FLAG_LEFT_ALIGN; + result = (usize)-width; + } + } + + return result; +} + +static usize parse_precision(const char** format, flags_t& flags, va_list ap) +{ + usize result = 0; + + if (**format == '.') + { + (*format)++; + + flags |= FLAG_USE_PRECISION; + + if (_isdigit(**format)) result = _atou(format); + else if (**format == '*') + { + const int precision = va_arg(ap, int); + if (precision >= 0) result = (usize)precision; + else + result = 0; + } + } + + return result; +} + +static void parse_length(const char** format, flags_t& flags) +{ + // FIXME: Support %j (intmax_t/uintmax_t) + switch (**format) + { + case 'h': + flags |= FLAG_SHORT; + (*format)++; + if (**format == 'h') + { + flags |= FLAG_CHAR; + (*format)++; + } + break; + case 'l': + flags |= FLAG_LONG; + (*format)++; + if (**format == 'l') + { + flags |= FLAG_LONG_LONG; + (*format)++; + } + break; + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; + (*format)++; + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; + (*format)++; + break; + default: break; + } +} + +static bool is_integer_format_specifier(char c) +{ + return (c == 'd') || (c == 'i') || (c == 'u') || (c == 'x') || (c == 'X') || (c == 'o') || (c == 'b'); +} + +static usize to_string(usize value, usize base, char* buf, usize max, bool uppercase) +{ + usize i = 0; + if (!value && max) + { + buf[i] = '0'; + return 1; + } + do { + int digit = (int)(value % base); + char c = (char)(digit < 10 ? '0' + digit : ((uppercase ? 'A' : 'a') + (digit - 10))); + buf[i++] = c; + value /= base; + } while (value && i < max); + return i; +} + +static int output_integer(char specifier, conv_state& vstate, format_state& state, usize value, bool negative) +{ + usize base = 10; + bool uppercase = false; + + switch (specifier) + { + case 'p': + case 'x': + case 'X': base = 16; break; + case 'o': base = 8; break; + case 'b': base = 2; break; + default: break; + } + if (specifier == 'X') uppercase = true; + + if (base == 10) vstate.flags &= ~FLAG_ALTERNATE; // decimal doesn't have an alternate form + + char buf[1024]; + usize buflen = to_string(value, base, buf, sizeof(buf), uppercase); + + if (!(vstate.flags & FLAG_LEFT_ALIGN) && + (vstate.flags & FLAG_ZERO_PAD)) // we're padding with zeroes from the beginning + { + bool extra_char = + negative || ((vstate.flags & FLAG_SIGN) || + (vstate.flags & FLAG_BLANK_SIGNED)); // are we adding an extra character after the buffer? + if (vstate.width && extra_char) vstate.width--; + + if (vstate.width && (vstate.flags & FLAG_ALTERNATE)) // fit in the characters we're using for the alternate form + { + vstate.width--; + if (vstate.width && (base == 2 || base == 16)) vstate.width--; + } + + while (buflen < vstate.width && buflen < sizeof(buf)) buf[buflen++] = '0'; + } + + while (buflen < vstate.precision && buflen < sizeof(buf)) buf[buflen++] = '0'; + + if (vstate.flags & FLAG_ALTERNATE) + { + if (base == 16 && !uppercase && buflen < sizeof(buf)) buf[buflen++] = 'x'; + if (base == 16 && uppercase && buflen < sizeof(buf)) buf[buflen++] = 'X'; + if (base == 2 && buflen < sizeof(buf)) buf[buflen++] = 'b'; + if (buflen < sizeof(buf)) buf[buflen++] = '0'; + } + + if (buflen < sizeof(buf)) + { + if (negative) buf[buflen++] = '-'; + else if (vstate.flags & FLAG_SIGN) + buf[buflen++] = '+'; + else if (vstate.flags & FLAG_BLANK_SIGNED) + buf[buflen++] = ' '; + } + + if (!(vstate.flags & FLAG_ZERO_PAD)) TRY_START_PAD(vstate, state, buflen); + + usize i = buflen; + + while (i--) TRY_PUTCHAR(buf[i], state); + + TRY_END_PAD(vstate, state, buflen); + + return 0; +} + +static int va_output_integer(char specifier, conv_state& vstate, format_state& state, va_list ap) +{ + bool is_signed = false; + bool negative = false; + + if (specifier == 'd' || specifier == 'i') is_signed = true; + + if (!is_signed) vstate.flags &= ~(FLAG_SIGN | FLAG_BLANK_SIGNED); + + if (vstate.flags & FLAG_CHAR) + { + if (is_signed) + { + char v = (char)va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return output_integer(specifier, vstate, state, v, negative); + } + else + { + unsigned char v = (unsigned char)va_arg(ap, unsigned int); + return output_integer(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_SHORT) + { + if (is_signed) + { + short v = (short)va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return output_integer(specifier, vstate, state, v, negative); + } + else + { + unsigned short v = (unsigned short)va_arg(ap, unsigned int); + return output_integer(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_LONG_LONG) + { + if (is_signed) + { + long long v = va_arg(ap, long long); + if (v < 0) + { + v = -v; + negative = true; + } + return output_integer(specifier, vstate, state, v, negative); + } + else + { + unsigned long long v = va_arg(ap, unsigned long long); + return output_integer(specifier, vstate, state, v, false); + } + } + else if (vstate.flags & FLAG_LONG) + { + if (is_signed) + { + long v = va_arg(ap, long); + if (v < 0) + { + v = -v; + negative = true; + } + return output_integer(specifier, vstate, state, v, negative); + } + else + { + unsigned long v = va_arg(ap, unsigned long); + return output_integer(specifier, vstate, state, v, false); + } + } + else + { + if (is_signed) + { + int v = va_arg(ap, int); + if (v < 0) + { + v = -v; + negative = true; + } + return output_integer(specifier, vstate, state, v, negative); + } + else + { + unsigned int v = va_arg(ap, unsigned int); + return output_integer(specifier, vstate, state, v, false); + } + } +} + +isize cstyle_format(const char* format, callback_t callback, void* arg, va_list ap) +{ + format_state state; + state.callback = callback; + state.arg = arg; + state.count = 0; + + while (*format) + { + if (*format != '%') + { + TRY_PUTCHAR(*format, state); + format++; + continue; + } + + format++; + + if (*format == '%') + { + TRY_PUTCHAR('%', state); + continue; + } + + // %[flags][width][.precision][length]conversion + + flags_t flags = parse_flags(&format); + usize width = parse_width(&format, flags, ap); + usize precision = parse_precision(&format, flags, ap); + parse_length(&format, flags); + + conv_state vstate = {flags, width, precision}; + + char specifier = *format; + format++; + + if (is_integer_format_specifier(specifier)) + { + if (va_output_integer(specifier, vstate, state, ap)) return -1; + continue; + } + else if (specifier == 'p') + { + void* ptr = va_arg(ap, void*); + if (ptr == nullptr) + { + TRY_START_PAD(vstate, state, 5); + TRY_PUTS("(nil)", state); + TRY_END_PAD(vstate, state, 5); + continue; + } + vstate.width = (sizeof(void*) * 2) + 2; + vstate.flags |= (FLAG_ZERO_PAD | FLAG_ALTERNATE); + if (output_integer('p', vstate, state, (usize)ptr, false)) return -1; + continue; + } + else if (specifier == 'c') + { + const char c = (char)va_arg(ap, int); + + TRY_START_PAD(vstate, state, 1); + TRY_PUTCHAR(c, state); + TRY_END_PAD(vstate, state, 1); + + continue; + } + else if (specifier == 's') + { + const char* str = va_arg(ap, const char*); + if (str == nullptr) + { + TRY_START_PAD(vstate, state, 6); + TRY_PUTS("(null)", state); + TRY_END_PAD(vstate, state, 6); + continue; + } + else + { + usize len = strlen(str); + + bool use_precision = (flags & FLAG_USE_PRECISION); + if (use_precision && len > precision) len = precision; + + TRY_START_PAD(vstate, state, len); + while (*str && (!use_precision || precision)) + { + TRY_PUTCHAR(*str, state); + precision--; + str++; + } + TRY_END_PAD(vstate, state, len); + continue; + } + } + else { continue; } + } + + return (isize)state.count; +} \ No newline at end of file diff --git a/luna/Format.h b/luna/Format.h index 10f43c30..71ad0659 100644 --- a/luna/Format.h +++ b/luna/Format.h @@ -5,489 +5,4 @@ typedef int (*callback_t)(char, void*); -#ifdef _LUNA_IMPLEMENTATION -#include - -extern "C" usize strlen(const char*); - -typedef int flags_t; -#define FLAG_ZERO_PAD 1 << 0 -#define FLAG_LEFT_ALIGN 1 << 1 -#define FLAG_BLANK_SIGNED 1 << 2 -#define FLAG_ALTERNATE 1 << 3 -#define FLAG_SIGN 1 << 4 -#define FLAG_USE_PRECISION 1 << 5 -#define FLAG_LONG 1 << 6 -#define FLAG_LONG_LONG 1 << 7 -#define FLAG_SHORT 1 << 8 -#define FLAG_CHAR 1 << 9 - -struct format_state -{ - usize count; - callback_t callback; - void* arg; -}; - -struct conv_state -{ - flags_t flags; - usize width; - usize precision; -}; - -static inline int cstyle_format_putchar(char c, format_state& state) -{ - state.count++; - return state.callback(c, state.arg); -} - -static inline int cstyle_format_puts(const char* s, format_state& state) -{ - while (*s) - { - if (cstyle_format_putchar(*s, state)) return -1; - s++; - } - - return 0; -} - -#define TRY_PUTCHAR(c, state) \ - if (cstyle_format_putchar(c, state)) return -1; - -#define TRY_PUTS(s, state) \ - if (cstyle_format_puts(s, state)) return -1; - -static int start_pad(const conv_state& vstate, format_state& state, usize start) -{ - if (!(vstate.flags & FLAG_LEFT_ALIGN)) - { - while (start++ < vstate.width) TRY_PUTCHAR(' ', state); - } - - return 0; -} - -#define TRY_START_PAD(vstate, state, start) \ - if (start_pad(vstate, state, start)) return -1; - -static int end_pad(const conv_state& vstate, format_state& state, usize start) -{ - if (vstate.flags & FLAG_LEFT_ALIGN) - { - while (start++ < vstate.width) TRY_PUTCHAR(' ', state); - } - - return 0; -} - -#define TRY_END_PAD(vstate, state, start) \ - if (end_pad(vstate, state, start)) return -1; - -static flags_t parse_flags(const char** format) -{ - flags_t result = 0; - - while (true) - { - switch (**format) - { - case '#': - result |= FLAG_ALTERNATE; - (*format)++; - break; - case '0': - result |= FLAG_ZERO_PAD; - (*format)++; - break; - case ' ': - result |= FLAG_BLANK_SIGNED; - (*format)++; - break; - case '-': - result |= FLAG_LEFT_ALIGN; - (*format)++; - break; - case '+': - result |= FLAG_SIGN; - (*format)++; - break; - default: return result; - } - } -} - -static usize parse_width(const char** format, flags_t& flags, va_list ap) -{ - usize result = 0; - - if (_isdigit(**format)) result = _atou(format); - else if (**format == '*') - { - const int width = va_arg(ap, int); - if (width >= 0) result = (usize)width; - else - { - flags |= FLAG_LEFT_ALIGN; - result = (usize)-width; - } - } - - return result; -} - -static usize parse_precision(const char** format, flags_t& flags, va_list ap) -{ - usize result = 0; - - if (**format == '.') - { - (*format)++; - - flags |= FLAG_USE_PRECISION; - - if (_isdigit(**format)) result = _atou(format); - else if (**format == '*') - { - const int precision = va_arg(ap, int); - if (precision >= 0) result = (usize)precision; - else - result = 0; - } - } - - return result; -} - -static void parse_length(const char** format, flags_t& flags) -{ - // FIXME: Support %j (intmax_t/uintmax_t) - switch (**format) - { - case 'h': - flags |= FLAG_SHORT; - (*format)++; - if (**format == 'h') - { - flags |= FLAG_CHAR; - (*format)++; - } - break; - case 'l': - flags |= FLAG_LONG; - (*format)++; - if (**format == 'l') - { - flags |= FLAG_LONG_LONG; - (*format)++; - } - break; - case 't': - flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; - (*format)++; - break; - case 'z': - flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG; - (*format)++; - break; - default: break; - } -} - -static bool is_integer_format_specifier(char c) -{ - return (c == 'd') || (c == 'i') || (c == 'u') || (c == 'x') || (c == 'X') || (c == 'o') || (c == 'b'); -} - -static usize to_string(usize value, usize base, char* buf, usize max, bool uppercase) -{ - usize i = 0; - if (!value && max) - { - buf[i] = '0'; - return 1; - } - do { - int digit = (int)(value % base); - char c = (char)(digit < 10 ? '0' + digit : ((uppercase ? 'A' : 'a') + (digit - 10))); - buf[i++] = c; - value /= base; - } while (value && i < max); - return i; -} - -static int output_integer(char specifier, conv_state& vstate, format_state& state, usize value, bool negative) -{ - usize base = 10; - bool uppercase = false; - - switch (specifier) - { - case 'p': - case 'x': - case 'X': base = 16; break; - case 'o': base = 8; break; - case 'b': base = 2; break; - default: break; - } - if (specifier == 'X') uppercase = true; - - if (base == 10) vstate.flags &= ~FLAG_ALTERNATE; // decimal doesn't have an alternate form - - char buf[1024]; - usize buflen = to_string(value, base, buf, sizeof(buf), uppercase); - - if (!(vstate.flags & FLAG_LEFT_ALIGN) && - (vstate.flags & FLAG_ZERO_PAD)) // we're padding with zeroes from the beginning - { - bool extra_char = - negative || ((vstate.flags & FLAG_SIGN) || - (vstate.flags & FLAG_BLANK_SIGNED)); // are we adding an extra character after the buffer? - if (vstate.width && extra_char) vstate.width--; - - if (vstate.width && (vstate.flags & FLAG_ALTERNATE)) // fit in the characters we're using for the alternate form - { - vstate.width--; - if (vstate.width && (base == 2 || base == 16)) vstate.width--; - } - - while (buflen < vstate.width && buflen < sizeof(buf)) buf[buflen++] = '0'; - } - - while (buflen < vstate.precision && buflen < sizeof(buf)) buf[buflen++] = '0'; - - if (vstate.flags & FLAG_ALTERNATE) - { - if (base == 16 && !uppercase && buflen < sizeof(buf)) buf[buflen++] = 'x'; - if (base == 16 && uppercase && buflen < sizeof(buf)) buf[buflen++] = 'X'; - if (base == 2 && buflen < sizeof(buf)) buf[buflen++] = 'b'; - if (buflen < sizeof(buf)) buf[buflen++] = '0'; - } - - if (buflen < sizeof(buf)) - { - if (negative) buf[buflen++] = '-'; - else if (vstate.flags & FLAG_SIGN) - buf[buflen++] = '+'; - else if (vstate.flags & FLAG_BLANK_SIGNED) - buf[buflen++] = ' '; - } - - if (!(vstate.flags & FLAG_ZERO_PAD)) TRY_START_PAD(vstate, state, buflen); - - usize i = buflen; - - while (i--) TRY_PUTCHAR(buf[i], state); - - TRY_END_PAD(vstate, state, buflen); - - return 0; -} - -static int va_output_integer(char specifier, conv_state& vstate, format_state& state, va_list ap) -{ - bool is_signed = false; - bool negative = false; - - if (specifier == 'd' || specifier == 'i') is_signed = true; - - if (!is_signed) vstate.flags &= ~(FLAG_SIGN | FLAG_BLANK_SIGNED); - - if (vstate.flags & FLAG_CHAR) - { - if (is_signed) - { - char v = (char)va_arg(ap, int); - if (v < 0) - { - v = -v; - negative = true; - } - return output_integer(specifier, vstate, state, v, negative); - } - else - { - unsigned char v = (unsigned char)va_arg(ap, unsigned int); - return output_integer(specifier, vstate, state, v, false); - } - } - else if (vstate.flags & FLAG_SHORT) - { - if (is_signed) - { - short v = (short)va_arg(ap, int); - if (v < 0) - { - v = -v; - negative = true; - } - return output_integer(specifier, vstate, state, v, negative); - } - else - { - unsigned short v = (unsigned short)va_arg(ap, unsigned int); - return output_integer(specifier, vstate, state, v, false); - } - } - else if (vstate.flags & FLAG_LONG_LONG) - { - if (is_signed) - { - long long v = va_arg(ap, long long); - if (v < 0) - { - v = -v; - negative = true; - } - return output_integer(specifier, vstate, state, v, negative); - } - else - { - unsigned long long v = va_arg(ap, unsigned long long); - return output_integer(specifier, vstate, state, v, false); - } - } - else if (vstate.flags & FLAG_LONG) - { - if (is_signed) - { - long v = va_arg(ap, long); - if (v < 0) - { - v = -v; - negative = true; - } - return output_integer(specifier, vstate, state, v, negative); - } - else - { - unsigned long v = va_arg(ap, unsigned long); - return output_integer(specifier, vstate, state, v, false); - } - } - else - { - if (is_signed) - { - int v = va_arg(ap, int); - if (v < 0) - { - v = -v; - negative = true; - } - return output_integer(specifier, vstate, state, v, negative); - } - else - { - unsigned int v = va_arg(ap, unsigned int); - return output_integer(specifier, vstate, state, v, false); - } - } -} - -#endif - -isize cstyle_format(const char* format, callback_t callback, void* arg, va_list ap) -#ifdef _LUNA_IMPLEMENTATION -{ - format_state state; - state.callback = callback; - state.arg = arg; - state.count = 0; - - while (*format) - { - if (*format != '%') - { - TRY_PUTCHAR(*format, state); - format++; - continue; - } - - format++; - - if (*format == '%') - { - TRY_PUTCHAR('%', state); - continue; - } - - // %[flags][width][.precision][length]conversion - - flags_t flags = parse_flags(&format); - usize width = parse_width(&format, flags, ap); - usize precision = parse_precision(&format, flags, ap); - parse_length(&format, flags); - - conv_state vstate = {flags, width, precision}; - - char specifier = *format; - format++; - - if (is_integer_format_specifier(specifier)) - { - if (va_output_integer(specifier, vstate, state, ap)) return -1; - continue; - } - else if (specifier == 'p') - { - void* ptr = va_arg(ap, void*); - if (ptr == nullptr) - { - TRY_START_PAD(vstate, state, 5); - TRY_PUTS("(nil)", state); - TRY_END_PAD(vstate, state, 5); - continue; - } - vstate.width = (sizeof(void*) * 2) + 2; - vstate.flags |= (FLAG_ZERO_PAD | FLAG_ALTERNATE); - if (output_integer('p', vstate, state, (usize)ptr, false)) return -1; - continue; - } - else if (specifier == 'c') - { - const char c = (char)va_arg(ap, int); - - TRY_START_PAD(vstate, state, 1); - TRY_PUTCHAR(c, state); - TRY_END_PAD(vstate, state, 1); - - continue; - } - else if (specifier == 's') - { - const char* str = va_arg(ap, const char*); - if (str == nullptr) - { - TRY_START_PAD(vstate, state, 6); - TRY_PUTS("(null)", state); - TRY_END_PAD(vstate, state, 6); - continue; - } - else - { - usize len = strlen(str); - - bool use_precision = (flags & FLAG_USE_PRECISION); - if (use_precision && len > precision) len = precision; - - TRY_START_PAD(vstate, state, len); - while (*str && (!use_precision || precision)) - { - TRY_PUTCHAR(*str, state); - precision--; - str++; - } - TRY_END_PAD(vstate, state, len); - continue; - } - } - else { continue; } - } - - return (isize)state.count; -} -#else - ; -#endif \ No newline at end of file +isize cstyle_format(const char* format, callback_t callback, void* arg, va_list ap); \ No newline at end of file diff --git a/luna/NumberParsing.cpp b/luna/NumberParsing.cpp new file mode 100644 index 00000000..4387407e --- /dev/null +++ b/luna/NumberParsing.cpp @@ -0,0 +1,153 @@ +#include + +usize _atou(const char** str) +{ + usize val = 0; + + while (_isdigit(**str)) + { + val = (10 * val) + (**str - '0'); + (*str)++; + } + + return val; +} + +isize _atos(const char** str) +{ + bool neg = false; + isize val = 0; + + switch (**str) + { + case '-': + neg = true; + (*str)++; + break; + case '+': (*str)++; break; + default: break; + } + + while (_isdigit(**str)) + { + val = (10 * val) + (**str - '0'); + (*str)++; + } + + return neg ? -val : val; +} + +usize _strtou(const char* str, const char** endptr, int base) +{ + usize val = 0; + + auto valid_digit = [](int _base, char c) -> bool { + if (_base <= 10) + { + if (!_isdigit(c)) return false; + if ((c - '0') < _base) return true; + return false; + } + else + { + if (!_isalnum(c)) return false; + if (_isdigit(c)) return true; + bool lower = _islower(c); + if (((c - lower ? 'a' : 'A') + 10) < _base) return true; + return false; + } + }; + + auto to_digit = [](char c) -> usize { + if (_isdigit(c)) return c - '0'; + if (_islower(c)) return (c - 'a') + 10; + return (c - 'A') + 10; + }; + + while (_isspace(*str)) str++; + + if ((base == 0 || base == 16) && *str == '0') + { + str++; + if (_tolower(*str) == 'x') + { + base = 16; + str++; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + while (valid_digit(base, *str)) + { + val = (base * val) + to_digit(*str); + str++; + } + + if (endptr) *endptr = str; + + return val; +} + +isize _strtoi(const char* str, const char** endptr, int base) +{ + isize val = 0; + bool negative = false; + + auto valid_digit = [](int _base, char c) -> bool { + if (_base <= 10) + { + if (!_isdigit(c)) return false; + if ((c - '0') < _base) return true; + return false; + } + else + { + if (!_isalnum(c)) return false; + if (_isdigit(c)) return true; + bool lower = _islower(c); + if (((c - lower ? 'a' : 'A') + 10) < _base) return true; + return false; + } + }; + + auto to_digit = [](char c) -> isize { + if (_isdigit(c)) return c - '0'; + if (_islower(c)) return (c - 'a') + 10; + return (c - 'A') + 10; + }; + + while (_isspace(*str)) str++; + + if (*str == '-' || *str == '+') + { + if (*str == '-') negative = true; + str++; + } + + if ((base == 0 || base == 16) && *str == '0') + { + str++; + if (_tolower(*str) == 'x') + { + base = 16; + str++; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + while (valid_digit(base, *str)) + { + val = (base * val) + to_digit(*str); + str++; + } + + if (endptr) *endptr = str; + + return negative ? -val : val; +} diff --git a/luna/NumberParsing.h b/luna/NumberParsing.h index a0fca6f2..c3c83fce 100644 --- a/luna/NumberParsing.h +++ b/luna/NumberParsing.h @@ -2,152 +2,7 @@ #include #include -inline usize _atou(const char** str) -{ - usize val = 0; - - while (_isdigit(**str)) - { - val = (10 * val) + (**str - '0'); - (*str)++; - } - - return val; -} - -inline isize _atos(const char** str) -{ - bool neg = false; - isize val = 0; - - switch (**str) - { - case '-': - neg = true; - (*str)++; - break; - case '+': (*str)++; break; - default: break; - } - - while (_isdigit(**str)) - { - val = (10 * val) + (**str - '0'); - (*str)++; - } - - return neg ? -val : val; -} - -inline usize _strtou(const char* str, const char** endptr, int base) -{ - usize val = 0; - - auto valid_digit = [](int _base, char c) -> bool { - if (_base <= 10) - { - if (!_isdigit(c)) return false; - if ((c - '0') < _base) return true; - } - else - { - if (!_isalnum(c)) return false; - if (_isdigit(c)) return true; - bool lower = _islower(c); - if (((c - lower ? 'a' : 'A') + 10) < _base) return true; - return false; - } - }; - - auto to_digit = [](char c) -> usize { - if (_isdigit(c)) return c - '0'; - if (_islower(c)) return (c - 'a') + 10; - return (c - 'A') + 10; - }; - - while (_isspace(*str)) str++; - - if ((base == 0 || base == 16) && *str == '0') - { - str++; - if (_tolower(*str) == 'x') - { - base = 16; - str++; - } - else if (base == 0) - base = 8; - } - else if (base == 0) - base = 10; - - while (valid_digit(base, *str)) - { - val = (base * val) + to_digit(*str); - str++; - } - - if (endptr) *endptr = str; - - return val; -} - -inline isize _strtoi(const char* str, const char** endptr, int base) -{ - isize val = 0; - bool negative = false; - - auto valid_digit = [](int _base, char c) -> bool { - if (_base <= 10) - { - if (!_isdigit(c)) return false; - if ((c - '0') < _base) return true; - } - else - { - if (!_isalnum(c)) return false; - if (_isdigit(c)) return true; - bool lower = _islower(c); - if (((c - lower ? 'a' : 'A') + 10) < _base) return true; - return false; - } - }; - - auto to_digit = [](char c) -> isize { - if (_isdigit(c)) return c - '0'; - if (_islower(c)) return (c - 'a') + 10; - return (c - 'A') + 10; - }; - - while (_isspace(*str)) str++; - - if (*str == '-' || *str == '+') - { - if (*str == '-') negative = true; - str++; - } - - if ((base == 0 || base == 16) && *str == '0') - { - str++; - if (_tolower(*str) == 'x') - { - base = 16; - str++; - } - else if (base == 0) - base = 8; - } - else if (base == 0) - base = 10; - - while (valid_digit(base, *str)) - { - val = (base * val) + to_digit(*str); - str++; - } - - if (endptr) *endptr = str; - - return negative ? -val : val; -} +usize _atou(const char** str); +isize _atos(const char** str); +usize _strtou(const char* str, const char** endptr, int base); +isize _strtoi(const char* str, const char** endptr, int base); diff --git a/luna/String.cpp b/luna/String.cpp new file mode 100644 index 00000000..2b2113b4 --- /dev/null +++ b/luna/String.cpp @@ -0,0 +1,47 @@ +#include + +extern "C" +{ + void* memcpy(void* dest, const void* src, size_t n) + { + for (size_t i = 0; i < n; ++i) { *((u8*)dest + i) = *((const u8*)src + i); } + return dest; + } + + void* memset(void* buf, int c, size_t n) + { + for (size_t i = 0; i < n; ++i) { *((u8*)buf + i) = (u8)c; } + return buf; + } + + int memcmp(const void* a, const void* b, size_t n) + { + if (!n) return 0; + const u8* ap = (const u8*)a; + const u8* bp = (const u8*)b; + while (--n && *ap == *bp) + { + ap++; + bp++; + } + return *ap - *bp; + } + + void* memmove(void* dest, const void* src, size_t n) + { + if (dest == src) return dest; + if (dest > src) + for (long i = n - 1; i >= 0; i++) { *((u8*)dest + i) = *((const u8*)src + i); } + else + for (long i = 0; i < (long)n; i++) { *((u8*)dest + i) = *((const u8*)src + i); } + return dest; + } + + size_t strlen(const char* str) + { + const char* i = str; + for (; *i; ++i) + ; + return (i - str); + } +} \ No newline at end of file diff --git a/luna/String.h b/luna/String.h index 9bfc8230..b11961f6 100644 --- a/luna/String.h +++ b/luna/String.h @@ -1,74 +1,11 @@ #pragma once #include -#ifndef NO_EXTERN_C extern "C" { -#endif - - void* memcpy(void* dest, const void* src, size_t n) -#ifdef _LUNA_IMPLEMENTATION - { - for (size_t i = 0; i < n; ++i) { *((u8*)dest + i) = *((const u8*)src + i); } - return dest; - } -#else - ; -#endif - - void* memset(void* buf, int c, size_t n) -#ifdef _LUNA_IMPLEMENTATION - { - for (size_t i = 0; i < n; ++i) { *((u8*)buf + i) = (u8)c; } - return buf; - } -#else - ; -#endif - - int memcmp(const void* a, const void* b, size_t n) -#ifdef _LUNA_IMPLEMENTATION - { - if (!n) return 0; - const u8* ap = (const u8*)a; - const u8* bp = (const u8*)b; - while (--n && *ap == *bp) - { - ap++; - bp++; - } - return *ap - *bp; - } -#else - ; -#endif - - void* memmove(void* dest, const void* src, size_t n) -#ifdef _LUNA_IMPLEMENTATION - { - if (dest == src) return dest; - if (dest > src) - for (long i = n - 1; i >= 0; i++) { *((u8*)dest + i) = *((const u8*)src + i); } - else - for (long i = 0; i < (long)n; i++) { *((u8*)dest + i) = *((const u8*)src + i); } - return dest; - } -#else - ; -#endif - - size_t strlen(const char* str) -#ifdef _LUNA_IMPLEMENTATION - { - const char* i = str; - for (; *i; ++i) - ; - return (i - str); - } -#else - ; -#endif - -#ifndef NO_EXTERN_C -} -#endif \ No newline at end of file + void* memcpy(void* dest, const void* src, size_t n); + void* memset(void* buf, int c, size_t n); + int memcmp(const void* a, const void* b, size_t n); + void* memmove(void* dest, const void* src, size_t n); + size_t strlen(const char* str); +} \ No newline at end of file