Compare commits
51 Commits
growing_ar
...
8a91a0ec6b
Author | SHA1 | Date | |
---|---|---|---|
8a91a0ec6b | |||
802b70f5ee | |||
92c2439b56 | |||
781a46713b | |||
7c4725edef | |||
4fc99f76a5 | |||
25ab75f74f | |||
f6dd7e7aa8 | |||
8f5bee45c6 | |||
25964d9a3c | |||
d9cf98da73 | |||
8c153b5321 | |||
3c4112d080 | |||
aa28dd481b | |||
42187beee5 | |||
8cc17f1490 | |||
b4c1301600 | |||
2c556e12f1 | |||
6c82898225 | |||
a85508e0a4 | |||
cd78913e83 | |||
a0acada9b4 | |||
8eaa4afed1 | |||
1ce07e9e4e | |||
162b255e1b | |||
99a9cd10f5 | |||
7e1c25b649 | |||
9008e10651 | |||
d27fc14b31 | |||
dbdab01a2c | |||
cf12144230 | |||
ccc86342cd | |||
|
8d89695fcc | ||
|
6499dd7be9 | ||
75bbb82058 | |||
7fb13f2439 | |||
0b63bc746d | |||
6ee3c762df | |||
59f1c3eb58 | |||
55d0c25c90 | |||
cfc98e0137 | |||
|
32877cdeaa | ||
|
7e2d7b28b7 | ||
23886f40e8 | |||
57de75c1f8 | |||
9807334ac9 | |||
18448dd7c1 | |||
62fdef8601 | |||
61c29ee564 | |||
36bc8ab54a | |||
a8e5913254 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,4 +1,10 @@
|
|||||||
.cache
|
.cache
|
||||||
.vscode
|
.vscode
|
||||||
|
test
|
||||||
|
test.*
|
||||||
|
*.dSYM
|
||||||
|
*.pdb
|
||||||
|
*.obj
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
libwapp-build
|
||||||
libwapp.so
|
libwapp.so
|
||||||
|
58
build.ps1
Normal file
58
build.ps1
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
Param(
|
||||||
|
[switch]$Release
|
||||||
|
)
|
||||||
|
|
||||||
|
$Compiler = "cl.exe"
|
||||||
|
|
||||||
|
$GeneralFlags = "/Wall /WX /wd4996"
|
||||||
|
$LibraryFlags = "/LD"
|
||||||
|
|
||||||
|
$IncludeDirs = Get-ChildItem -Path src -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
|
||||||
|
$SrcFiles = Get-ChildItem -Path src -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||||
|
|
||||||
|
$TestIncludeDirs = Get-ChildItem -Path tests -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
|
||||||
|
$TestSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||||
|
|
||||||
|
If ($Release -eq $True) {
|
||||||
|
$GeneralFlags += " /O2 /Og"
|
||||||
|
$BuildType = "release"
|
||||||
|
} Else {
|
||||||
|
$GeneralFlags += " /Zi /Od /fsanitize=address"
|
||||||
|
$BuildType = "debug"
|
||||||
|
}
|
||||||
|
|
||||||
|
$BuildDir = "./libwapp-build/windows-$BuildType"
|
||||||
|
$ObjDir = "$BuildDir/objects"
|
||||||
|
$OutDir = "$BuildDir/output"
|
||||||
|
$TestsDir = "$BuildDir/tests"
|
||||||
|
|
||||||
|
$OutBasename = "libwapp"
|
||||||
|
$Objects = "/Fo:$ObjDir/"
|
||||||
|
$Outputs = "/Fd:$OutDir/$OutBasename /Fe:$OutDir/$OutBasename"
|
||||||
|
|
||||||
|
$TestOutBasename = "wapptest"
|
||||||
|
$TestOutputs = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestOutBasename"
|
||||||
|
|
||||||
|
If (Test-Path $BuildDir) {
|
||||||
|
Remove-Item $BuildDir -Recurse -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p $ObjDir > $null
|
||||||
|
mkdir -p $OutDir > $null
|
||||||
|
mkdir -p $TestsDir > $null
|
||||||
|
|
||||||
|
# Build and run tests
|
||||||
|
Invoke-Expression "$Compiler $GeneralFlags $IncludeDirs $TestIncludeDirs $SrcFiles $TestSrcFiles $TestOutputs" -ErrorAction Stop
|
||||||
|
|
||||||
|
Invoke-Expression "$TestsDir/$TestOutBasename.exe"
|
||||||
|
$Status = $LASTEXITCODE
|
||||||
|
|
||||||
|
Remove-Item $TestsDir -Recurse -Force
|
||||||
|
|
||||||
|
If ($Status -ne 0) {
|
||||||
|
Write-Error "Tests failed"
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build library
|
||||||
|
Invoke-Expression "$Compiler $GeneralFlags $LibraryFlags $IncludeDirs $SrcFiles $Objects $Outputs"
|
68
compile
68
compile
@@ -1,13 +1,61 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
CC=clang
|
BUILD_TYPE="debug"
|
||||||
INCLUDE="\
|
|
||||||
$(find src -type d | xargs -I{} echo -n "-I{} ") \
|
|
||||||
"
|
|
||||||
SRC="\
|
|
||||||
$(find src -type f -name *.c | xargs -I{} echo -n "{} ") \
|
|
||||||
"
|
|
||||||
CFLAGS="-O3 -shared -fPIC -Wall -Werror -pedantic"
|
|
||||||
OUT="libwapp.so"
|
|
||||||
|
|
||||||
(set -x ; $CC $CFLAGS $INCLUDE $SRC -o $OUT)
|
while [[ $# > 0 ]];do
|
||||||
|
case $1 in
|
||||||
|
--release)
|
||||||
|
BUILD_TYPE="release"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*|-*|--*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
CC=clang
|
||||||
|
CFLAGS="-Wall -Werror -pedantic "
|
||||||
|
LIBFLAGS="-fPIC -shared"
|
||||||
|
|
||||||
|
INCLUDE="$(find src -type d | xargs -I{} echo -n "-I{} ")"
|
||||||
|
SRC="$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ")"
|
||||||
|
|
||||||
|
TEST_INCLUDE="$(find tests -type d | xargs -I{} echo -n "-I{} ")"
|
||||||
|
TEST_SRC="$(find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")"
|
||||||
|
|
||||||
|
BUILD_DIR="libwapp-build/posix-$BUILD_TYPE"
|
||||||
|
if [[ -d $BUILD_DIR ]]; then
|
||||||
|
rm -rf $BUILD_DIR
|
||||||
|
fi
|
||||||
|
mkdir -p $BUILD_DIR
|
||||||
|
|
||||||
|
if [[ $BUILD_TYPE == "release" ]]; then
|
||||||
|
CFLAGS+="-O3"
|
||||||
|
else
|
||||||
|
CFLAGS+="-g -fsanitize=address -fsanitize=undefined"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUT="$BUILD_DIR/libwapp.so"
|
||||||
|
TEST_OUT="$BUILD_DIR/wapptest"
|
||||||
|
|
||||||
|
# Compile tests
|
||||||
|
if [[ $(echo $TEST_SRC | xargs) != "" ]]; then
|
||||||
|
(set -x ; $CC $CFLAGS $INCLUDE $TEST_INCLUDE $SRC $TEST_SRC -o $TEST_OUT)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run tests and exit on failure
|
||||||
|
if [[ -f $TEST_OUT ]]; then
|
||||||
|
$TEST_OUT
|
||||||
|
STATUS="$?"
|
||||||
|
|
||||||
|
rm $TEST_OUT
|
||||||
|
|
||||||
|
if [[ $STATUS != "0" ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compile library
|
||||||
|
(set -x ; $CC $CFLAGS $LIBFLAGS $INCLUDE $SRC -o $OUT)
|
||||||
|
115
src/common/mem_utils/mem_utils.c
Normal file
115
src/common/mem_utils/mem_utils.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include "mem_utils.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <memoryapi.h>
|
||||||
|
|
||||||
|
internal const i32 access_types[] = {
|
||||||
|
[WAPP_MEM_ACCESS_NONE] = PAGE_NOACCESS,
|
||||||
|
[WAPP_MEM_ACCESS_READ_ONLY] = PAGE_READONLY,
|
||||||
|
[WAPP_MEM_ACCESS_EXEC_ONLY] = PAGE_EXECUTE,
|
||||||
|
[WAPP_MEM_ACCESS_READ_WRITE] = PAGE_READWRITE,
|
||||||
|
[WAPP_MEM_ACCESS_READ_EXEC] = PAGE_EXECUTE_READ,
|
||||||
|
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal inline void *alloc_windows(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags);
|
||||||
|
#elif defined(WAPP_PLATFORM_POSIX)
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
internal const i32 access_types[] = {
|
||||||
|
[WAPP_MEM_ACCESS_NONE] = PROT_NONE,
|
||||||
|
[WAPP_MEM_ACCESS_READ_ONLY] = PROT_READ,
|
||||||
|
[WAPP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC,
|
||||||
|
[WAPP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE,
|
||||||
|
[WAPP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC,
|
||||||
|
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal inline void *alloc_posix(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags);
|
||||||
|
#else
|
||||||
|
#error "Unrecognised platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||||
|
|
||||||
|
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||||
|
if (!ptr) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(is_power_of_two(alignment));
|
||||||
|
|
||||||
|
uptr p = (uptr)ptr;
|
||||||
|
uptr align = (uptr)alignment;
|
||||||
|
|
||||||
|
// Similar to p % align, but it's a faster implementation that works fine
|
||||||
|
// because align is guaranteed to be a power of 2
|
||||||
|
uptr modulo = p & (align - 1);
|
||||||
|
|
||||||
|
if (modulo != 0) {
|
||||||
|
p += align - modulo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags, MemInitType type) {
|
||||||
|
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||||
|
// Ensure memory is committed if it's meant to be initialised
|
||||||
|
if (type == WAPP_MEM_INIT_INITIALISED) {
|
||||||
|
flags |= WAPP_MEM_ALLOC_COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *output = alloc_windows(addr, size, access, flags);
|
||||||
|
#elif defined(WAPP_PLATFORM_POSIX)
|
||||||
|
void *output = alloc_posix(addr, size, access, flags);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (type == WAPP_MEM_INIT_INITIALISED) {
|
||||||
|
memset(output, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wapp_mem_util_free(void *ptr, u64 size) {
|
||||||
|
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||||
|
VirtualFree(ptr, size, MEM_RELEASE);
|
||||||
|
#elif defined(WAPP_PLATFORM_POSIX)
|
||||||
|
munmap(ptr, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
internal inline void *alloc_windows(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags) {
|
||||||
|
return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WAPP_PLATFORM_POSIX)
|
||||||
|
internal inline void *alloc_posix(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags) {
|
||||||
|
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
|
||||||
|
|
||||||
|
#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) || \
|
||||||
|
defined(WAPP_PLATFORM_NET_BSD)
|
||||||
|
alloc_flags |= MAP_NORESERVE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return mmap(addr, size, access_types[access], alloc_flags, -1, 0);
|
||||||
|
}
|
||||||
|
#endif
|
61
src/common/mem_utils/mem_utils.h
Normal file
61
src/common/mem_utils/mem_utils.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef MEM_UTILS_H
|
||||||
|
#define MEM_UTILS_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <memoryapi.h>
|
||||||
|
#elif defined(WAPP_PLATFORM_POSIX)
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#else
|
||||||
|
#error "Unrecognised platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
typedef enum mem_access {
|
||||||
|
WAPP_MEM_ACCESS_NONE,
|
||||||
|
WAPP_MEM_ACCESS_READ_ONLY,
|
||||||
|
WAPP_MEM_ACCESS_EXEC_ONLY,
|
||||||
|
WAPP_MEM_ACCESS_READ_WRITE,
|
||||||
|
WAPP_MEM_ACCESS_READ_EXEC,
|
||||||
|
WAPP_MEM_ACCESS_READ_WRITE_EXEC,
|
||||||
|
} MemAccess;
|
||||||
|
|
||||||
|
typedef enum mem_alloc_flags {
|
||||||
|
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||||
|
WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE,
|
||||||
|
WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT,
|
||||||
|
#elif defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU)
|
||||||
|
WAPP_MEM_ALLOC_RESERVE = 0,
|
||||||
|
WAPP_MEM_ALLOC_COMMIT = MAP_POPULATE,
|
||||||
|
#elif defined(WAPP_PLATFORM_FREE_BSD)
|
||||||
|
WAPP_MEM_ALLOC_RESERVE = 0,
|
||||||
|
WAPP_MEM_ALLOC_COMMIT = MAP_PREFAULT_READ,
|
||||||
|
#elif defined(WAPP_PLATFORM_BSD) || defined(WAPP_PLATFORM_UNIX) || \
|
||||||
|
defined(WAPP_PLATFORM_APPLE)
|
||||||
|
WAPP_MEM_ALLOC_RESERVE = 0,
|
||||||
|
WAPP_MEM_ALLOC_COMMIT = 0,
|
||||||
|
#endif
|
||||||
|
} MemAllocFlags;
|
||||||
|
|
||||||
|
typedef enum mem_init_type {
|
||||||
|
WAPP_MEM_INIT_UNINITIALISED,
|
||||||
|
WAPP_MEM_INIT_INITIALISED,
|
||||||
|
} MemInitType;
|
||||||
|
|
||||||
|
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
|
||||||
|
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access,
|
||||||
|
MemAllocFlags flags, MemInitType type);
|
||||||
|
void wapp_mem_util_free(void *ptr, u64 size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !MEM_UTILS_H
|
9
src/common/misc/misc_utils.h
Normal file
9
src/common/misc/misc_utils.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef MISC_UTILS_H
|
||||||
|
#define MISC_UTILS_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
|
||||||
|
#define wapp_misc_utils_padding_size(SIZE) \
|
||||||
|
u8 reserved_padding[sizeof(void *) - ((SIZE) % sizeof(void *))]
|
||||||
|
|
||||||
|
#endif // !MISC_UTILS_H
|
63
src/common/platform/platform.h
Normal file
63
src/common/platform/platform.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef PLATFORM_H
|
||||||
|
#define PLATFORM_H
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#define WAPP_PLATFORM_ANDROID
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
#define WAPP_PLATFORM_FREE_BSD
|
||||||
|
#define WAPP_PLATFORM_BSD
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
#define WAPP_PLATFORM_NET_BSD
|
||||||
|
#define WAPP_PLATFORM_BSD
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
#define WAPP_PLATFORM_OPEN_BSD
|
||||||
|
#define WAPP_PLATFORM_BSD
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__DragonFly__)
|
||||||
|
#define WAPP_PLATFORM_DRAGON_FLY
|
||||||
|
#define WAPP_PLATFORM_BSD
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__bsdi__)
|
||||||
|
#define WAPP_PLATFORM_BSD
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__gnu_linux__)
|
||||||
|
#define WAPP_PLATFORM_LINUX
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__GNU__) || defined(__gnu_hurd__)
|
||||||
|
#define WAPP_PLATFORM_GNU
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif defined(__APPLE__) || defined(__MACH__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#if TARGET_OS_IPHONE
|
||||||
|
#define WAPP_PLATFORM_IOS
|
||||||
|
#define WAPP_PLATFORM_APPLE
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#elif TARGET_OS_MAC
|
||||||
|
#define WAPP_PLATFORM_MACOS
|
||||||
|
#define WAPP_PLATFORM_APPLE
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#else
|
||||||
|
#error "Unrecognised Apple platform"
|
||||||
|
#endif
|
||||||
|
#elif defined(_WIN64)
|
||||||
|
#define WAPP_PLATFORM_WINDOWS64
|
||||||
|
#define WAPP_PLATFORM_WINDOWS
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define WAPP_PLATFORM_WINDOWS32
|
||||||
|
#define WAPP_PLATFORM_WINDOWS
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
#define WAPP_PLATFORM_CYGWIN
|
||||||
|
#define WAPP_PLATFORM_WINDOWS
|
||||||
|
#elif defined(__unix__) || defined(__unix)
|
||||||
|
#define WAPP_PLATFORM_UNIX
|
||||||
|
#define WAPP_PLATFORM_POSIX
|
||||||
|
#else
|
||||||
|
#error "Unrecognised platform"
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // !PLATFORM_H
|
132
src/common/shell/commander/commander.c
Normal file
132
src/common/shell/commander/commander.c
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
#include "commander.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "shell_utils.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define CMD_BUF_LEN 8192
|
||||||
|
#define OUT_BUF_LEN 4096
|
||||||
|
|
||||||
|
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len,
|
||||||
|
va_list args);
|
||||||
|
internal inline CMDResult execute_command(const char *cmd,
|
||||||
|
CMDOutHandling out_handling,
|
||||||
|
char *out_buf, u64 buf_size);
|
||||||
|
internal inline CMDError get_command_output(FILE *fp,
|
||||||
|
CMDOutHandling out_handling,
|
||||||
|
char *out_buf, u64 buf_size);
|
||||||
|
internal inline CMDError get_output_status(FILE *fp, i32 *status_out);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...) { // clang-format on
|
||||||
|
va_list args;
|
||||||
|
va_start(args, buf_size);
|
||||||
|
|
||||||
|
char cmd[CMD_BUF_LEN] = {0};
|
||||||
|
CMDError err = build_command_from_args(cmd, CMD_BUF_LEN, args);
|
||||||
|
if (err > SHELL_ERR_NO_ERROR) {
|
||||||
|
va_end(args);
|
||||||
|
return CMD_NO_EXIT(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return execute_command(cmd, out_handling, out_buf, buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len,
|
||||||
|
va_list args) {
|
||||||
|
u64 size = 0;
|
||||||
|
u64 arg_len = 0;
|
||||||
|
|
||||||
|
const char *arg;
|
||||||
|
while ((arg = va_arg(args, const char *))) {
|
||||||
|
arg_len = strlen(arg);
|
||||||
|
if (arg_len >= buf_len - size) {
|
||||||
|
return SHELL_ERR_CMD_BUF_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(cmd, arg);
|
||||||
|
cmd[size + arg_len] = ' ';
|
||||||
|
|
||||||
|
size += arg_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHELL_ERR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline CMDResult execute_command(const char *cmd,
|
||||||
|
CMDOutHandling out_handling,
|
||||||
|
char *out_buf, u64 buf_size) {
|
||||||
|
FILE *fp = wapp_shell_utils_popen(cmd, "r");
|
||||||
|
if (!fp) {
|
||||||
|
return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMDError err = get_command_output(fp, out_handling, out_buf, buf_size);
|
||||||
|
if (err > SHELL_ERR_NO_ERROR) {
|
||||||
|
// Ensure process is closed on failure
|
||||||
|
wapp_shell_utils_pclose(fp);
|
||||||
|
return CMD_NO_EXIT(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 st = EXIT_SUCCESS;
|
||||||
|
err = get_output_status(fp, &st);
|
||||||
|
if (err > SHELL_ERR_NO_ERROR) {
|
||||||
|
return CMD_NO_EXIT(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CMDResult){
|
||||||
|
.exited = true,
|
||||||
|
.exit_code = st,
|
||||||
|
.error = SHELL_ERR_NO_ERROR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline CMDError get_command_output(FILE *fp,
|
||||||
|
CMDOutHandling out_handling,
|
||||||
|
char *out_buf, u64 buf_size) {
|
||||||
|
char out[OUT_BUF_LEN] = {0};
|
||||||
|
u64 max_out_length = OUT_BUF_LEN - 1;
|
||||||
|
|
||||||
|
u64 buf_filled = 0;
|
||||||
|
while (fgets(out, max_out_length, fp)) {
|
||||||
|
if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) {
|
||||||
|
buf_filled += strlen(out);
|
||||||
|
if (buf_filled >= buf_size) {
|
||||||
|
return SHELL_ERR_OUT_BUF_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(out_buf, out);
|
||||||
|
} else if (out_handling == SHELL_OUTPUT_PRINT) {
|
||||||
|
printf("%s", out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHELL_ERR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline CMDError get_output_status(FILE *fp, i32 *status_out) {
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
if (!feof(fp)) {
|
||||||
|
// Ensure process is closed on failure
|
||||||
|
wapp_shell_utils_pclose(fp);
|
||||||
|
return SHELL_ERR_PROC_EXIT_FAIL;
|
||||||
|
}
|
||||||
|
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||||
|
|
||||||
|
*status_out = wapp_shell_utils_pclose(fp);
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_POSIX
|
||||||
|
if (!WIFEXITED(*status_out)) {
|
||||||
|
return SHELL_ERR_PROC_EXIT_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*status_out = WEXITSTATUS(*status_out);
|
||||||
|
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||||
|
|
||||||
|
return SHELL_ERR_NO_ERROR;
|
||||||
|
}
|
46
src/common/shell/commander/commander.h
Normal file
46
src/common/shell/commander/commander.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef COMMANDER_H
|
||||||
|
#define COMMANDER_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#define CMD_NO_EXIT(ERR) \
|
||||||
|
((CMDResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR})
|
||||||
|
#define wapp_shell_commander_execute(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, ...) \
|
||||||
|
run_command(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, __VA_ARGS__, NULL)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHELL_OUTPUT_DISCARD,
|
||||||
|
SHELL_OUTPUT_PRINT,
|
||||||
|
SHELL_OUTPUT_CAPTURE,
|
||||||
|
} CMDOutHandling;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHELL_ERR_NO_ERROR,
|
||||||
|
SHELL_ERR_CMD_BUF_FULL,
|
||||||
|
SHELL_ERR_PROC_START_FAIL,
|
||||||
|
SHELL_ERR_OUT_BUF_FULL,
|
||||||
|
SHELL_ERR_PROC_EXIT_FAIL,
|
||||||
|
} CMDError;
|
||||||
|
|
||||||
|
typedef struct commander_result CMDResult;
|
||||||
|
struct commander_result {
|
||||||
|
bool exited;
|
||||||
|
int exit_code;
|
||||||
|
CMDError error;
|
||||||
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !COMMANDER_H
|
101
src/common/shell/termcolour/termcolour.c
Normal file
101
src/common/shell/termcolour/termcolour.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#include "termcolour.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
internal void print_coloured_text(const TerminalColourist *colourist,
|
||||||
|
const char *text);
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
internal WORD colours[COUNT_TERM_COLOUR] = {
|
||||||
|
[WAPP_TERM_COLOUR_FG_BLACK] = 0,
|
||||||
|
[WAPP_TERM_COLOUR_FG_RED] = FOREGROUND_RED,
|
||||||
|
[WAPP_TERM_COLOUR_FG_GREEN] = FOREGROUND_GREEN,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BLUE] = FOREGROUND_BLUE,
|
||||||
|
[WAPP_TERM_COLOUR_FG_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE,
|
||||||
|
[WAPP_TERM_COLOUR_FG_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE,
|
||||||
|
[WAPP_TERM_COLOUR_FG_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN,
|
||||||
|
[WAPP_TERM_COLOUR_FG_WHITE] =
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_BLACK] = FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_CYAN] =
|
||||||
|
FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] =
|
||||||
|
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_YELLOW] =
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN |
|
||||||
|
FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
internal const char *colours[COUNT_TERM_COLOUR] = {
|
||||||
|
[WAPP_TERM_COLOUR_FG_BLACK] = "\033[30m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_RED] = "\033[31m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_GREEN] = "\033[32m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BLUE] = "\033[34m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_CYAN] = "\033[36m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_MAGENTA] = "\033[35m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_YELLOW] = "\033[33m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_WHITE] = "\033[37m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_BLACK] = "\033[90m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_RED] = "\033[91m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_GREEN] = "\033[92m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_BLUE] = "\033[94m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_CYAN] = "\033[96m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = "\033[95m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = "\033[93m",
|
||||||
|
[WAPP_TERM_COLOUR_FG_BR_WHITE] = "\033[97m",
|
||||||
|
};
|
||||||
|
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||||
|
|
||||||
|
TerminalColourist wapp_shell_termcolour_get_colourist(void) {
|
||||||
|
TerminalColourist colourist;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
// create handle
|
||||||
|
colourist.handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
// get console colour information
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
GetConsoleScreenBufferInfo(colourist.handle, &csbi);
|
||||||
|
colourist.default_colour = csbi.wAttributes;
|
||||||
|
#else
|
||||||
|
colourist.default_colour = "\033[0m";
|
||||||
|
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
colourist.current_colour = colourist.default_colour;
|
||||||
|
|
||||||
|
return colourist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wapp_shell_termcolour_print_text(TerminalColourist *colourist,
|
||||||
|
const char *text, TerminalColour colour) {
|
||||||
|
if (colour < WAPP_TERM_COLOUR_FG_BLACK ||
|
||||||
|
colour > WAPP_TERM_COLOUR_FG_BR_WHITE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
colourist->current_colour = colours[colour];
|
||||||
|
print_coloured_text(colourist, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wapp_shell_termcolour_clear_colour(TerminalColourist *colourist) {
|
||||||
|
colourist->current_colour = colourist->default_colour;
|
||||||
|
print_coloured_text(colourist, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void print_coloured_text(const TerminalColourist *colourist,
|
||||||
|
const char *text) {
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
SetConsoleTextAttribute(colourist->handle, colourist->current_colour);
|
||||||
|
printf("%s", text);
|
||||||
|
#else
|
||||||
|
printf("%s%s", colourist->current_colour, text);
|
||||||
|
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
}
|
64
src/common/shell/termcolour/termcolour.h
Normal file
64
src/common/shell/termcolour/termcolour.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef TERM_COLOUR_H
|
||||||
|
#define TERM_COLOUR_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "misc_utils.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WAPP_TERM_COLOUR_FG_BLACK,
|
||||||
|
WAPP_TERM_COLOUR_FG_RED,
|
||||||
|
WAPP_TERM_COLOUR_FG_GREEN,
|
||||||
|
WAPP_TERM_COLOUR_FG_BLUE,
|
||||||
|
WAPP_TERM_COLOUR_FG_CYAN,
|
||||||
|
WAPP_TERM_COLOUR_FG_MAGENTA,
|
||||||
|
WAPP_TERM_COLOUR_FG_YELLOW,
|
||||||
|
WAPP_TERM_COLOUR_FG_WHITE,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_BLACK,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_RED,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_GREEN,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_BLUE,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_CYAN,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_MAGENTA,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_YELLOW,
|
||||||
|
WAPP_TERM_COLOUR_FG_BR_WHITE,
|
||||||
|
|
||||||
|
COUNT_TERM_COLOUR,
|
||||||
|
} TerminalColour;
|
||||||
|
|
||||||
|
typedef struct terminal_colourist TerminalColourist;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <WinCon.h>
|
||||||
|
|
||||||
|
struct terminal_colourist {
|
||||||
|
HANDLE handle;
|
||||||
|
WORD default_colour;
|
||||||
|
WORD current_colour;
|
||||||
|
wapp_misc_utils_padding_size(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
struct terminal_colourist {
|
||||||
|
const char *default_colour;
|
||||||
|
const char *current_colour;
|
||||||
|
};
|
||||||
|
#endif // WAPP_PLATFORM_WINDOWS
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
TerminalColourist wapp_shell_termcolour_get_colourist(void);
|
||||||
|
void wapp_shell_termcolour_print_text(TerminalColourist *colourist,
|
||||||
|
const char *text, TerminalColour colour);
|
||||||
|
void wapp_shell_termcolour_clear_colour(TerminalColourist *colourist);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !TERM_COLOUR_H
|
16
src/common/shell/utils/shell_utils.h
Normal file
16
src/common/shell/utils/shell_utils.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef SHELL_UTILS_H
|
||||||
|
#define SHELL_UTILS_H
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
#define wapp_shell_utils_popen _popen
|
||||||
|
#define wapp_shell_utils_pclose _pclose
|
||||||
|
#else
|
||||||
|
#define wapp_shell_utils_popen popen
|
||||||
|
#define wapp_shell_utils_pclose pclose
|
||||||
|
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // !SHELL_UTILS_H
|
@@ -40,7 +40,7 @@ void dirup(char *dst, u64 levels, const char *path) {
|
|||||||
--length;
|
--length;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u64 i = length - 1; i >= 0; --i) {
|
for (i64 i = length - 1; i >= 0; --i) {
|
||||||
if (path[i] == path_sep) {
|
if (path[i] == path_sep) {
|
||||||
++sep_count;
|
++sep_count;
|
||||||
end_index = i;
|
end_index = i;
|
119
src/core/mem/arena/mem_arena.c
Normal file
119
src/core/mem/arena/mem_arena.c
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#include "mem_arena.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "mem_utils.h"
|
||||||
|
#include "misc_utils.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef DEFAULT_ALIGNMENT
|
||||||
|
// Why 2 * sizeof(void *) instead of sizeof(void *)
|
||||||
|
// https://handmade.network/forums/t/6860-alignment_arena_allocator
|
||||||
|
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
|
||||||
|
#endif /* ifndef DEFAULT_ALIGNMENT */
|
||||||
|
|
||||||
|
#define ARENA_MINIMUM_CAPACITY 1024
|
||||||
|
|
||||||
|
struct arena {
|
||||||
|
u8 *buf;
|
||||||
|
u8 *offset;
|
||||||
|
u64 capacity;
|
||||||
|
bool committed;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
wapp_misc_utils_padding_size(sizeof(u8 *) * 2 + sizeof(u64) + sizeof(bool));
|
||||||
|
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
};
|
||||||
|
|
||||||
|
// PUBLIC API
|
||||||
|
|
||||||
|
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||||
|
bool zero_buffer) {
|
||||||
|
if (!arena || *arena || base_capacity == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*arena = (Arena *)calloc(1, sizeof(Arena));
|
||||||
|
Arena *arena_ptr = *arena;
|
||||||
|
if (!arena_ptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 arena_capacity = base_capacity >= ARENA_MINIMUM_CAPACITY
|
||||||
|
? base_capacity
|
||||||
|
: ARENA_MINIMUM_CAPACITY;
|
||||||
|
|
||||||
|
arena_ptr->buf = (u8 *)wapp_mem_util_alloc(
|
||||||
|
NULL, arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags,
|
||||||
|
zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED);
|
||||||
|
|
||||||
|
if (!(arena_ptr->buf)) {
|
||||||
|
wapp_mem_arena_destroy(arena);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_ptr->capacity = arena_capacity;
|
||||||
|
arena_ptr->offset = arena_ptr->buf;
|
||||||
|
arena_ptr->committed =
|
||||||
|
(flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
|
||||||
|
return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
|
||||||
|
if (!arena) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *alloc_start = arena->offset;
|
||||||
|
|
||||||
|
u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment);
|
||||||
|
if (output + size >= arena->buf + arena->capacity) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
arena->offset = output + size;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
if (!(arena->committed)) {
|
||||||
|
output = (u8 *)wapp_mem_util_alloc(
|
||||||
|
alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start),
|
||||||
|
WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT,
|
||||||
|
WAPP_MEM_INIT_INITIALISED);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
memset(output, 0, size);
|
||||||
|
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
return (void *)output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wapp_mem_arena_clear(Arena *arena) {
|
||||||
|
if (!arena) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(arena->buf, 0, arena->offset - arena->buf);
|
||||||
|
arena->offset = arena->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wapp_mem_arena_destroy(Arena **arena) {
|
||||||
|
if (!arena) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena *arena_ptr = *arena;
|
||||||
|
if (arena_ptr->buf) {
|
||||||
|
wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_ptr->buf = arena_ptr->offset = NULL;
|
||||||
|
arena_ptr->capacity = 0;
|
||||||
|
|
||||||
|
free(*arena);
|
||||||
|
*arena = NULL;
|
||||||
|
}
|
37
src/core/mem/arena/mem_arena.h
Normal file
37
src/core/mem/arena/mem_arena.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef MEM_ARENA_H
|
||||||
|
#define MEM_ARENA_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "mem_utils.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
typedef struct arena Arena;
|
||||||
|
|
||||||
|
#define wapp_mem_arena_init_default(arena_dptr, base_capacity) \
|
||||||
|
(wapp_mem_arena_init(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, \
|
||||||
|
false))
|
||||||
|
#define wapp_mem_arena_init_commit(arena_dptr, base_capacity) \
|
||||||
|
(wapp_mem_arena_init(arena_dptr, base_capacity, \
|
||||||
|
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
|
||||||
|
#define wapp_mem_arena_init_zero(arena_dptr, base_capacity) \
|
||||||
|
(wapp_mem_arena_init(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
|
||||||
|
#define wapp_mem_arena_init_commit_and_zero(arena_dptr, base_capacity) \
|
||||||
|
(wapp_mem_arena_init(arena_dptr, base_capacity, \
|
||||||
|
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
|
||||||
|
|
||||||
|
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||||
|
bool zero_buffer);
|
||||||
|
void *wapp_mem_arena_alloc(Arena *arena, u64 size);
|
||||||
|
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment);
|
||||||
|
void wapp_mem_arena_clear(Arena *arena);
|
||||||
|
void wapp_mem_arena_destroy(Arena **arena);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !MEM_ARENA_H
|
@@ -1,6 +1,7 @@
|
|||||||
#include "dstr.h"
|
#include "dstr.h"
|
||||||
#include "aliases.h"
|
#include "aliases.h"
|
||||||
#include "mem_arena.h"
|
#include "mem_arena.h"
|
||||||
|
#include "platform.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -13,7 +14,12 @@
|
|||||||
struct dstr {
|
struct dstr {
|
||||||
u64 capacity;
|
u64 capacity;
|
||||||
u64 size;
|
u64 size;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
char *buf;
|
||||||
|
#else
|
||||||
char buf[];
|
char buf[];
|
||||||
|
#endif // WAPP_PLATFORM_WINDOWS
|
||||||
};
|
};
|
||||||
|
|
||||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena) {
|
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena) {
|
||||||
@@ -97,8 +103,19 @@ StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena) {
|
|||||||
|
|
||||||
u64 new_length = (*dst)->size + src_length;
|
u64 new_length = (*dst)->size + src_length;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
char *str =
|
||||||
|
wapp_mem_util_alloc(NULL, new_length + 1, WAPP_MEM_ACCESS_READ_WRITE,
|
||||||
|
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT,
|
||||||
|
WAPP_MEM_INIT_INITIALISED);
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
return (StringUpdate){.updated = false, .str = *dst};
|
||||||
|
}
|
||||||
|
#else
|
||||||
char str[new_length + 1];
|
char str[new_length + 1];
|
||||||
memset(str, 0, new_length + 1);
|
memset(str, 0, new_length + 1);
|
||||||
|
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||||
|
|
||||||
strncpy(str, (*dst)->buf, (*dst)->size);
|
strncpy(str, (*dst)->buf, (*dst)->size);
|
||||||
strncat(str, src, new_length + 1 - (*dst)->size);
|
strncat(str, src, new_length + 1 - (*dst)->size);
|
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "aliases.h"
|
#include "aliases.h"
|
||||||
#include "mem_arena.h"
|
#include "mem_arena.h"
|
||||||
|
#include "misc_utils.h"
|
||||||
|
#include "platform.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -13,8 +15,12 @@ typedef struct dstr String;
|
|||||||
|
|
||||||
typedef struct string_update StringUpdate;
|
typedef struct string_update StringUpdate;
|
||||||
struct string_update {
|
struct string_update {
|
||||||
bool updated;
|
|
||||||
String *str;
|
String *str;
|
||||||
|
bool updated;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
wapp_misc_utils_padding_size(sizeof(bool) + sizeof(String *));
|
||||||
|
#endif // WAPP_PLATFORM_WINDOWS
|
||||||
};
|
};
|
||||||
|
|
||||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena);
|
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena);
|
@@ -1,233 +0,0 @@
|
|||||||
#include "mem_arena.h"
|
|
||||||
#include "aliases.h"
|
|
||||||
#include "mem_utils.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef DEFAULT_ALIGNMENT
|
|
||||||
// Why 2 * sizeof(void *) instead of sizeof(void *)
|
|
||||||
// https://handmade.network/forums/t/6860-alignment_arena_allocator
|
|
||||||
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
|
|
||||||
#endif /* ifndef DEFAULT_ALIGNMENT */
|
|
||||||
|
|
||||||
#define ARENA_MINIMUM_CAPACITY 1024
|
|
||||||
|
|
||||||
typedef struct base_arena BaseArena;
|
|
||||||
struct base_arena {
|
|
||||||
u8 *buf;
|
|
||||||
u8 *offset;
|
|
||||||
u64 capacity;
|
|
||||||
BaseArena *prev;
|
|
||||||
BaseArena *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct growing_arena {
|
|
||||||
BaseArena *active_arena;
|
|
||||||
u64 count;
|
|
||||||
u64 initial_capacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal bool base_arena_init(BaseArena *arena, u64 capacity);
|
|
||||||
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
|
|
||||||
u64 alignment);
|
|
||||||
internal void base_arena_clear(BaseArena *arena);
|
|
||||||
internal void base_arena_destroy(BaseArena *arena);
|
|
||||||
|
|
||||||
// PUBLIC API
|
|
||||||
|
|
||||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
|
|
||||||
if (!arena || *arena || base_capacity == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*arena = (Arena *)calloc(1, sizeof(Arena));
|
|
||||||
Arena *arena_ptr = *arena;
|
|
||||||
if (!arena_ptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena));
|
|
||||||
if (!(arena_ptr->active_arena)) {
|
|
||||||
wapp_mem_arena_destroy(arena);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!base_arena_init(arena_ptr->active_arena, base_capacity)) {
|
|
||||||
wapp_mem_arena_destroy(arena);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_ptr->count = 1;
|
|
||||||
arena_ptr->initial_capacity = base_capacity;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
|
|
||||||
return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
|
|
||||||
if (!arena || !(arena->active_arena)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
|
|
||||||
if (!output) {
|
|
||||||
if (arena->active_arena->next) {
|
|
||||||
arena->active_arena = arena->active_arena->next;
|
|
||||||
} else {
|
|
||||||
arena->active_arena->next = (BaseArena *)calloc(1, sizeof(BaseArena));
|
|
||||||
if (!(arena->active_arena->next)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!base_arena_init(arena->active_arena->next,
|
|
||||||
arena->initial_capacity)) {
|
|
||||||
free(arena->active_arena->next);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->active_arena->next->prev = arena->active_arena;
|
|
||||||
arena->active_arena = arena->active_arena->next;
|
|
||||||
|
|
||||||
++(arena->count);
|
|
||||||
}
|
|
||||||
|
|
||||||
output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
|
|
||||||
if (!output) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(output, 0, size);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wapp_mem_arena_clear(Arena *arena) {
|
|
||||||
if (!arena) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseArena *last_active = NULL;
|
|
||||||
while (arena->active_arena) {
|
|
||||||
base_arena_clear(arena->active_arena);
|
|
||||||
|
|
||||||
last_active = arena->active_arena;
|
|
||||||
|
|
||||||
arena->active_arena = arena->active_arena->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->active_arena = last_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wapp_mem_arena_destroy(Arena **arena) {
|
|
||||||
if (!arena) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Arena *arena_ptr = *arena;
|
|
||||||
if (!arena_ptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseArena *current;
|
|
||||||
BaseArena *next;
|
|
||||||
BaseArena *prev;
|
|
||||||
|
|
||||||
current = arena_ptr->active_arena->next;
|
|
||||||
while (current) {
|
|
||||||
next = current->next;
|
|
||||||
|
|
||||||
base_arena_destroy(current);
|
|
||||||
free(current);
|
|
||||||
|
|
||||||
current = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = arena_ptr->active_arena->prev;
|
|
||||||
while (current) {
|
|
||||||
prev = current->prev;
|
|
||||||
|
|
||||||
base_arena_destroy(current);
|
|
||||||
free(current);
|
|
||||||
|
|
||||||
current = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_arena_destroy(arena_ptr->active_arena);
|
|
||||||
|
|
||||||
free(arena_ptr->active_arena);
|
|
||||||
arena_ptr->active_arena = NULL;
|
|
||||||
|
|
||||||
arena_ptr->count = 0;
|
|
||||||
arena_ptr->initial_capacity = 0;
|
|
||||||
|
|
||||||
free(*arena);
|
|
||||||
*arena = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// INTERNAL FUNCTIONS
|
|
||||||
|
|
||||||
internal bool base_arena_init(BaseArena *arena, u64 capacity) {
|
|
||||||
if (!arena || arena->buf || capacity == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 arena_capacity =
|
|
||||||
capacity >= ARENA_MINIMUM_CAPACITY ? capacity : ARENA_MINIMUM_CAPACITY;
|
|
||||||
|
|
||||||
arena->buf = (u8 *)calloc(arena_capacity, sizeof(u8));
|
|
||||||
if (!(arena->buf)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->capacity = arena_capacity;
|
|
||||||
arena->offset = arena->buf;
|
|
||||||
arena->prev = arena->next = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
|
|
||||||
u64 alignment) {
|
|
||||||
if (!arena) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *alloc_start = arena->offset;
|
|
||||||
|
|
||||||
u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment);
|
|
||||||
if (output + size >= arena->buf + arena->capacity) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->offset = output + size;
|
|
||||||
|
|
||||||
return (void *)output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void base_arena_clear(BaseArena *arena) {
|
|
||||||
if (!arena) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(arena->buf, 0, arena->offset - arena->buf);
|
|
||||||
arena->offset = arena->buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void base_arena_destroy(BaseArena *arena) {
|
|
||||||
if (!arena) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arena->buf) {
|
|
||||||
free(arena->buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
arena->buf = arena->offset = NULL;
|
|
||||||
arena->capacity = 0;
|
|
||||||
arena->prev = arena->next = NULL;
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
#ifndef MEM_ARENA_H
|
|
||||||
#define MEM_ARENA_H
|
|
||||||
|
|
||||||
#include "aliases.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
typedef struct growing_arena Arena;
|
|
||||||
|
|
||||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity);
|
|
||||||
void *wapp_mem_arena_alloc(Arena *arena, u64 size);
|
|
||||||
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment);
|
|
||||||
void wapp_mem_arena_clear(Arena *arena);
|
|
||||||
void wapp_mem_arena_destroy(Arena **arena);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif // !MEM_ARENA_H
|
|
@@ -1,28 +0,0 @@
|
|||||||
#include "mem_utils.h"
|
|
||||||
#include "aliases.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
|
||||||
|
|
||||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
|
||||||
if (!ptr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(is_power_of_two(alignment));
|
|
||||||
|
|
||||||
uptr p = (uptr)ptr;
|
|
||||||
uptr align = (uptr)alignment;
|
|
||||||
|
|
||||||
// Similar to p % align, but it's a faster implementation that works fine
|
|
||||||
// because align is guaranteed to be a power of 2
|
|
||||||
uptr modulo = p & (align - 1);
|
|
||||||
|
|
||||||
if (modulo != 0) {
|
|
||||||
p += align - modulo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void *)p;
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
#ifndef MEM_UTILS_H
|
|
||||||
#define MEM_UTILS_H
|
|
||||||
|
|
||||||
#include "aliases.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif // !MEM_UTILS_H
|
|
57
src/tester/tester.c
Normal file
57
src/tester/tester.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "tester.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "termcolour.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
internal void handle_test_result(TerminalColourist *colourist,
|
||||||
|
TestFuncResult result);
|
||||||
|
|
||||||
|
void run_tests(TestFunc *func1, ...) {
|
||||||
|
TerminalColourist colourist = wapp_shell_termcolour_get_colourist();
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
handle_test_result(&colourist, func1());
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, func1);
|
||||||
|
|
||||||
|
TestFunc *func = va_arg(args, TestFunc *);
|
||||||
|
|
||||||
|
while (func) {
|
||||||
|
TestFuncResult result = func();
|
||||||
|
handle_test_result(&colourist, result);
|
||||||
|
|
||||||
|
func = va_arg(args, TestFunc *);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void handle_test_result(TerminalColourist *colourist,
|
||||||
|
TestFuncResult result) {
|
||||||
|
TerminalColour colour;
|
||||||
|
const char *result_text;
|
||||||
|
|
||||||
|
if (result.passed) {
|
||||||
|
colour = WAPP_TERM_COLOUR_FG_BR_GREEN;
|
||||||
|
result_text = "PASSED";
|
||||||
|
} else {
|
||||||
|
colour = WAPP_TERM_COLOUR_FG_BR_RED;
|
||||||
|
result_text = "FAILED";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[");
|
||||||
|
wapp_shell_termcolour_print_text(colourist, result_text, colour);
|
||||||
|
wapp_shell_termcolour_clear_colour(colourist);
|
||||||
|
printf("] %s\n", result.name);
|
||||||
|
|
||||||
|
if (!result.passed) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
34
src/tester/tester.h
Normal file
34
src/tester/tester.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef TESTER_H
|
||||||
|
#define TESTER_H
|
||||||
|
|
||||||
|
#include "misc_utils.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#define wapp_tester_result(PASSED) \
|
||||||
|
((TestFuncResult){.name = __func__, .passed = PASSED})
|
||||||
|
#define wapp_tester_run_tests(...) run_tests(__VA_ARGS__, NULL)
|
||||||
|
|
||||||
|
typedef struct test_func_result TestFuncResult;
|
||||||
|
struct test_func_result {
|
||||||
|
const char *name;
|
||||||
|
bool passed;
|
||||||
|
|
||||||
|
#ifdef WAPP_PLATFORM_WINDOWS
|
||||||
|
wapp_misc_utils_padding_size(sizeof(const char *) + sizeof(bool));
|
||||||
|
#endif // WAPP_PLATFORM_WINDOWS
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef TestFuncResult(TestFunc)(void);
|
||||||
|
|
||||||
|
void run_tests(TestFunc *func1, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !TESTER_H
|
69
tests/arena/test_arena.c
Normal file
69
tests/arena/test_arena.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "test_arena.h"
|
||||||
|
#include "aliases.h"
|
||||||
|
#include "mem_arena.h"
|
||||||
|
#include "tester.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ARENA_CAPACITY 1024
|
||||||
|
|
||||||
|
internal Arena *arena = NULL;
|
||||||
|
internal i32 count = 20;
|
||||||
|
internal i32 *array = NULL;
|
||||||
|
|
||||||
|
TestFuncResult test_arena_init(void) {
|
||||||
|
bool result = wapp_mem_arena_init_default(&arena, ARENA_CAPACITY);
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void) {
|
||||||
|
Arena *large_arena = NULL;
|
||||||
|
u64 capacity = 512ull * 1024ull * 1024ull * 1024ull;
|
||||||
|
bool result = wapp_mem_arena_init(&large_arena, capacity,
|
||||||
|
WAPP_MEM_ALLOC_RESERVE, false);
|
||||||
|
if (result) {
|
||||||
|
wapp_mem_arena_destroy(&large_arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void) {
|
||||||
|
array = wapp_mem_arena_alloc(arena, count * sizeof(i32));
|
||||||
|
bool result = array != NULL;
|
||||||
|
|
||||||
|
for (i32 i = 0; i < count; ++i) {
|
||||||
|
array[i] = i * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_arena_alloc_fails_when_over_capacity(void) {
|
||||||
|
u8 *bytes = wapp_mem_arena_alloc(arena, ARENA_CAPACITY * 2);
|
||||||
|
bool result = bytes == NULL;
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_arena_clear(void) {
|
||||||
|
wapp_mem_arena_clear(arena);
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
for (i32 i = 0; i < count; ++i) {
|
||||||
|
if (array[i] != 0) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_arena_destroy(void) {
|
||||||
|
wapp_mem_arena_destroy(&arena);
|
||||||
|
bool result = arena == NULL;
|
||||||
|
|
||||||
|
return wapp_tester_result(result);
|
||||||
|
}
|
21
tests/arena/test_arena.h
Normal file
21
tests/arena/test_arena.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef TEST_ARENA_H
|
||||||
|
#define TEST_ARENA_H
|
||||||
|
|
||||||
|
#include "tester.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
TestFuncResult test_arena_init(void);
|
||||||
|
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void);
|
||||||
|
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void);
|
||||||
|
TestFuncResult test_arena_alloc_fails_when_over_capacity(void);
|
||||||
|
TestFuncResult test_arena_clear(void);
|
||||||
|
TestFuncResult test_arena_destroy(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !TEST_ARENA_H
|
55
tests/shell_commander/test_shell_commander.c
Normal file
55
tests/shell_commander/test_shell_commander.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include "test_shell_commander.h"
|
||||||
|
#include "commander.h"
|
||||||
|
#include "tester.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
TestFuncResult test_commander_cmd_success(void) {
|
||||||
|
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0,
|
||||||
|
"echo", "hello world");
|
||||||
|
|
||||||
|
bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
|
||||||
|
result.error == SHELL_ERR_NO_ERROR;
|
||||||
|
|
||||||
|
return wapp_tester_result(succeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_commander_cmd_failure(void) {
|
||||||
|
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0,
|
||||||
|
"grep", "2>&1");
|
||||||
|
|
||||||
|
bool failed = result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||||
|
result.error == SHELL_ERR_NO_ERROR;
|
||||||
|
|
||||||
|
return wapp_tester_result(failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_commander_cmd_out_buf_success(void) {
|
||||||
|
char buf[64] = {0};
|
||||||
|
char expected_output[64] = {0};
|
||||||
|
const char *msg = "hello world";
|
||||||
|
sprintf(expected_output, "%s\n", msg);
|
||||||
|
|
||||||
|
CMDResult result =
|
||||||
|
wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 64, "echo", msg);
|
||||||
|
|
||||||
|
bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
|
||||||
|
result.error == SHELL_ERR_NO_ERROR &&
|
||||||
|
strcmp(buf, expected_output) == 0;
|
||||||
|
|
||||||
|
return wapp_tester_result(succeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFuncResult test_commander_cmd_out_buf_failure(void) {
|
||||||
|
char buf[4] = {0};
|
||||||
|
const char *msg = "hello world";
|
||||||
|
CMDResult result =
|
||||||
|
wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 4, "echo", msg);
|
||||||
|
|
||||||
|
bool failed = !result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||||
|
result.error == SHELL_ERR_OUT_BUF_FULL && strcmp(buf, msg) != 0;
|
||||||
|
|
||||||
|
return wapp_tester_result(failed);
|
||||||
|
}
|
19
tests/shell_commander/test_shell_commander.h
Normal file
19
tests/shell_commander/test_shell_commander.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef TEST_SHELL_COMMANDER_H
|
||||||
|
#define TEST_SHELL_COMMANDER_H
|
||||||
|
|
||||||
|
#include "tester.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
TestFuncResult test_commander_cmd_success(void);
|
||||||
|
TestFuncResult test_commander_cmd_failure(void);
|
||||||
|
TestFuncResult test_commander_cmd_out_buf_success(void);
|
||||||
|
TestFuncResult test_commander_cmd_out_buf_failure(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !TEST_SHELL_COMMANDER_H
|
16
tests/wapptest.c
Normal file
16
tests/wapptest.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "test_arena.h"
|
||||||
|
#include "test_shell_commander.h"
|
||||||
|
#include "tester.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
wapp_tester_run_tests(
|
||||||
|
test_arena_init, test_arena_init_succeeds_when_reserving_very_large_size,
|
||||||
|
test_arena_alloc_succeeds_when_within_capacity,
|
||||||
|
test_arena_alloc_fails_when_over_capacity, test_arena_clear,
|
||||||
|
test_arena_destroy, test_commander_cmd_success,
|
||||||
|
test_commander_cmd_failure, test_commander_cmd_out_buf_success,
|
||||||
|
test_commander_cmd_out_buf_failure);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Reference in New Issue
Block a user