Move a few functions out of line
This commit is contained in:
parent
56c2ca3381
commit
dadc3e570b
@ -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)
|
@ -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)
|
||||
|
35
luna/CMakeLists.txt
Normal file
35
luna/CMakeLists.txt
Normal file
@ -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)
|
480
luna/Format.cpp
Normal file
480
luna/Format.cpp
Normal file
@ -0,0 +1,480 @@
|
||||
#include <Format.h>
|
||||
#include <NumberParsing.h>
|
||||
|
||||
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;
|
||||
}
|
487
luna/Format.h
487
luna/Format.h
@ -5,489 +5,4 @@
|
||||
|
||||
typedef int (*callback_t)(char, void*);
|
||||
|
||||
#ifdef _LUNA_IMPLEMENTATION
|
||||
#include <NumberParsing.h>
|
||||
|
||||
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
|
||||
isize cstyle_format(const char* format, callback_t callback, void* arg, va_list ap);
|
153
luna/NumberParsing.cpp
Normal file
153
luna/NumberParsing.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
#include <NumberParsing.h>
|
||||
|
||||
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;
|
||||
}
|
@ -2,152 +2,7 @@
|
||||
#include <CType.h>
|
||||
#include <Types.h>
|
||||
|
||||
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);
|
||||
|
47
luna/String.cpp
Normal file
47
luna/String.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <String.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,74 +1,11 @@
|
||||
#pragma once
|
||||
#include <Types.h>
|
||||
|
||||
#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;
|
||||
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);
|
||||
}
|
||||
#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
|
Loading…
Reference in New Issue
Block a user