Compare commits
34 Commits
0b5c556f84
...
master
Author | SHA1 | Date | |
---|---|---|---|
0bb85e6364 | |||
0fb0160b5e | |||
fdb22819b4 | |||
6f79fb9c44 | |||
ef5e3e1706 | |||
8e247c7a0b | |||
ec3bf6061d | |||
41badf33d9 | |||
8c1694d3d9 | |||
055f0bc2f5 | |||
b1e03148b7 | |||
da1725982c | |||
75c2f27f8b | |||
570a5fab88 | |||
296e6467c6 | |||
1d40c785f8 | |||
80af330d1b | |||
3d8f2270ef | |||
2ec675a320 | |||
1a2b697349 | |||
92eefe800b | |||
e8f34b341e | |||
f1e4804167 | |||
a8ea92dd5c | |||
dbaf6d16ce | |||
3bc6e879d8 | |||
8b0463c94a | |||
5fcbb97f7a | |||
93ddf7738c | |||
12d8930b2b | |||
20ce36924e | |||
ade3939e17 | |||
874a2e234b | |||
e49654efb1 |
@@ -14,13 +14,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
shared: ["ON", "OFF"]
|
shared: ["ON", "OFF"]
|
||||||
pthread_support: ["ON", "OFF"]
|
|
||||||
posix_support: ["ON", "OFF"]
|
posix_support: ["ON", "OFF"]
|
||||||
exclude:
|
exclude:
|
||||||
- posix_support: "OFF"
|
- posix_support: "OFF"
|
||||||
pthread_support: "ON"
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
name: ${{ matrix.os }} - shared=${{ matrix.shared }}, pthread=${{ matrix.pthread_support }}, posix=${{ matrix.posix_support }}
|
name: ${{ matrix.os }} - shared=${{ matrix.shared }}, posix=${{ matrix.posix_support }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -31,7 +29,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake -Bbuild -S . \
|
cmake -Bbuild -S . \
|
||||||
-DDCFG_BUILD_SHARED=${{ matrix.shared }} \
|
-DDCFG_BUILD_SHARED=${{ matrix.shared }} \
|
||||||
-DDCFG_PTHREAD_SUPPORT=${{ matrix.pthread_support }} \
|
|
||||||
-DDCFG_POSIX_SUPPORT=${{ matrix.posix_support }}
|
-DDCFG_POSIX_SUPPORT=${{ matrix.posix_support }}
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
|||||||
*.a
|
*.a
|
||||||
BUILD
|
BUILD
|
||||||
install
|
install
|
||||||
|
result
|
||||||
|
106
CMakeLists.txt
106
CMakeLists.txt
@@ -2,55 +2,85 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
|
|
||||||
project(DCFG C)
|
project(DCFG C)
|
||||||
|
|
||||||
|
option(DCFG_POSIX_SUPPORT "Enable POSIX support" ON)
|
||||||
|
option(DCFG_BUILD_PROGRAMS "Build DCFG example programs" ON)
|
||||||
|
option(DCFG_ASAN "Enable AddressSanitizer" OFF)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_C_EXTENSIONS ON) # Would've done OFF but I need typeof (for now)
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
option(DCFG_BUILD_SHARED "Build DCFG as a shared library" ON)
|
|
||||||
option(DCFG_PTHREAD_SUPPORT "Enable pthreads support" ON)
|
|
||||||
option(DCFG_POSIX_SUPPORT "Enable POSIX support" ON)
|
|
||||||
|
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
|
||||||
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
if(DCFG_BUILD_SHARED)
|
if(DCFG_ASAN)
|
||||||
add_library(${PROJECT_NAME} SHARED ${SRC_DIR}/dcfg.c)
|
if(MSVC)
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR})
|
set(ASAN_COMPILE_FLAGS /fsanitize=address)
|
||||||
|
set(ASAN_LINK_FLAGS /fsanitize=address)
|
||||||
if(DCFG_PTHREAD_SUPPORT)
|
else()
|
||||||
find_package(Threads REQUIRED)
|
set(ASAN_COMPILE_FLAGS -fsanitize=address -fno-omit-frame-pointer)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads)
|
set(ASAN_LINK_FLAGS -fsanitize=address)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE DCFG_PTHREAD_SUPPORT)
|
|
||||||
endif()
|
endif()
|
||||||
if (DCFG_POSIX_SUPPORT)
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE DCFG_POSIX_SUPPORT)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "dcfg")
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
|
|
||||||
else()
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SRC_DIR}/dcfg.c)
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR})
|
|
||||||
|
|
||||||
if(DCFG_PTHREAD_SUPPORT)
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads)
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE DCFG_PTHREAD_SUPPORT)
|
|
||||||
endif()
|
|
||||||
if (DCFG_POSIX_SUPPORT)
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE DCFG_POSIX_SUPPORT)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "dcfg")
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Shared library
|
||||||
|
add_library(${PROJECT_NAME}_shared SHARED ${SRC_DIR}/dcfg.c)
|
||||||
|
target_include_directories(${PROJECT_NAME}_shared PUBLIC ${INCLUDE_DIR})
|
||||||
|
set_target_properties(${PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME "dcfg")
|
||||||
|
|
||||||
|
# Static library
|
||||||
|
add_library(${PROJECT_NAME}_static STATIC ${SRC_DIR}/dcfg.c)
|
||||||
|
target_include_directories(${PROJECT_NAME}_static PUBLIC ${INCLUDE_DIR})
|
||||||
|
set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME "dcfg")
|
||||||
|
|
||||||
|
foreach(TARGET ${PROJECT_NAME}_shared ${PROJECT_NAME}_static)
|
||||||
|
if(DCFG_POSIX_SUPPORT)
|
||||||
|
target_compile_definitions(${TARGET} PRIVATE DCFG_POSIX_SUPPORT)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${TARGET} PRIVATE /W4 /permissive-)
|
||||||
|
else()
|
||||||
|
target_compile_options(${TARGET} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_link_libraries(${TARGET} PRIVATE m)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# AddressSanitizer
|
||||||
|
if(DCFG_ASAN)
|
||||||
|
target_compile_options(${TARGET} PRIVATE ${ASAN_COMPILE_FLAGS})
|
||||||
|
target_link_libraries(${TARGET} PRIVATE ${ASAN_LINK_FLAGS})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME}_shared ${PROJECT_NAME}_static DESTINATION lib)
|
||||||
install(DIRECTORY ${INCLUDE_DIR}/ DESTINATION include)
|
install(DIRECTORY ${INCLUDE_DIR}/ DESTINATION include)
|
||||||
|
|
||||||
if(MSVC)
|
if(DCFG_BUILD_PROGRAMS)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /permissive-)
|
set(PROGRAMS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/programs)
|
||||||
else()
|
file(GLOB PROGRAM_SOURCES "${PROGRAMS_DIR}/*.c")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
|
|
||||||
|
foreach(PROG_SRC ${PROGRAM_SOURCES})
|
||||||
|
get_filename_component(PROG_NAME ${PROG_SRC} NAME_WE)
|
||||||
|
add_executable(${PROG_NAME} ${PROG_SRC})
|
||||||
|
target_include_directories(${PROG_NAME} PRIVATE ${INCLUDE_DIR})
|
||||||
|
target_link_libraries(${PROG_NAME} PRIVATE ${PROJECT_NAME}_static)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${PROG_NAME} PRIVATE /W4 /permissive-)
|
||||||
|
else()
|
||||||
|
target_compile_options(${PROG_NAME} PRIVATE -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DCFG_ASAN)
|
||||||
|
target_compile_options(${PROG_NAME} PRIVATE ${ASAN_COMPILE_FLAGS})
|
||||||
|
target_link_libraries(${PROG_NAME} PRIVATE ${ASAN_LINK_FLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS ${PROG_NAME} DESTINATION bin)
|
||||||
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
60
build.sh
60
build.sh
@@ -1,54 +1,84 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
BUILD_DIR="BUILD"
|
BUILD_DIR="BUILD"
|
||||||
INSTALL_DIR="$(pwd)/install"
|
INSTALL_DIR=$PWD/install
|
||||||
CFLAGS="-std=gnu99 -Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token"
|
CFLAGS="-Wall -Wextra -pedantic -Werror -Wno-newline-eof -Wno-language-extension-token -Wno-unused-command-line-argument"
|
||||||
BUILD_SHARED=1
|
BUILD_SHARED=1
|
||||||
PTHREAD_SUPPORT=1
|
|
||||||
POSIX_SUPPORT=1
|
POSIX_SUPPORT=1
|
||||||
|
BUILD_PROGRAMS=1
|
||||||
SRC_DIR="src"
|
SRC_DIR="src"
|
||||||
INCLUDE_DIR="include"
|
INCLUDE_DIR="include"
|
||||||
|
PROGRAMS_DIR="programs"
|
||||||
OUTPUT_NAME="libdcfg"
|
OUTPUT_NAME="libdcfg"
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case $arg in
|
case $arg in
|
||||||
--debug) CFLAGS="$CFLAGS -g -O0" ;;
|
--debug) CFLAGS="$CFLAGS -g -O0" ;;
|
||||||
--release) CFLAGS="$CFLAGS -O2" ;;
|
--release) CFLAGS="$CFLAGS -O2" ;;
|
||||||
--no-pthread) PTHREAD_SUPPORT=0 ;;
|
|
||||||
--no-posix) POSIX_SUPPORT=0 ;;
|
--no-posix) POSIX_SUPPORT=0 ;;
|
||||||
|
--no-programs) BUILD_PROGRAMS=0 ;;
|
||||||
--clean) rm -rf "$BUILD_DIR" "$INSTALL_DIR"; echo "Cleaned."; exit 0 ;;
|
--clean) rm -rf "$BUILD_DIR" "$INSTALL_DIR"; echo "Cleaned."; exit 0 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Detect SunOS
|
||||||
|
OS=`uname`
|
||||||
|
echo "Detected os:" $OS
|
||||||
|
SHARED_FLAG="-shared"
|
||||||
|
PIC_FLAG="-fPIC"
|
||||||
|
if [ "$OS" = "SunOS" ]; then
|
||||||
|
SHARED_FLAG="-G"
|
||||||
|
PIC_FLAG="-KPIC"
|
||||||
|
CFLAGS=`echo "$CFLAGS" | sed 's/-pedantic//g'`
|
||||||
|
fi
|
||||||
|
|
||||||
# Setup directories
|
# Setup directories
|
||||||
mkdir -p "$BUILD_DIR" "$INSTALL_DIR/lib" "$INSTALL_DIR/include"
|
mkdir -p "$BUILD_DIR" "$INSTALL_DIR/lib" "$INSTALL_DIR/include" "$INSTALL_DIR/bin"
|
||||||
|
|
||||||
# Compiler and linker
|
# Compiler and linker
|
||||||
CC=${CC:-cc}
|
CC=${CC:-cc}
|
||||||
|
|
||||||
if [ "$PTHREAD_SUPPORT" -eq 1 ]; then
|
if [ "$OS" = "SunOS" ] && [ "$CC" = "cc" ]; then
|
||||||
CFLAGS="$CFLAGS -DDCFG_PTHREAD_SUPPORT"
|
CFLAGS="$CFLAGS -xc99"
|
||||||
LIBS="$LIBS -lpthread"
|
else
|
||||||
|
CFLAGS="$CFLAGS -std=c99"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$POSIX_SUPPORT" -eq 1 ]; then
|
if [ "$POSIX_SUPPORT" -eq 1 ]; then
|
||||||
CFLAGS="$CFLAGS -DDCFG_POSIX_SUPPORT"
|
CFLAGS="$CFLAGS -DDCFG_POSIX_SUPPORT=1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
CFLAGS="$CFLAGS $PIC_FLAG -lm"
|
||||||
|
|
||||||
echo "Building DCFG..."
|
echo "Building DCFG..."
|
||||||
cd "$BUILD_DIR"
|
cd "$BUILD_DIR"
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
$CC $CFLAGS -fPIC -shared "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR" -o "$OUTPUT_NAME.so" $LIBS
|
|
||||||
|
|
||||||
$CC $CFLAGS -c "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR"
|
# Shared library
|
||||||
ar rcs "$OUTPUT_NAME.a" dcfg.o
|
$CC $CFLAGS $SHARED_FLAG "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR" -o "$OUTPUT_NAME.so" $LIBS
|
||||||
|
|
||||||
|
# Static library
|
||||||
|
$CC -c $CFLAGS "../$SRC_DIR/dcfg.c" -I"../$INCLUDE_DIR" -o dcfg.o
|
||||||
|
if [ "$OS" = "SunOS" ]; then
|
||||||
|
CC -xar -o "$OUTPUT_NAME.a" dcfg.o
|
||||||
|
else
|
||||||
|
ar rcs "$OUTPUT_NAME.a" dcfg.o
|
||||||
|
fi
|
||||||
|
|
||||||
set +x
|
|
||||||
|
|
||||||
echo "Installing..."
|
|
||||||
cp -r "../$INCLUDE_DIR/"* "$INSTALL_DIR/include/"
|
|
||||||
cp "$OUTPUT_NAME.so" "$INSTALL_DIR/lib/"
|
cp "$OUTPUT_NAME.so" "$INSTALL_DIR/lib/"
|
||||||
cp "$OUTPUT_NAME.a" "$INSTALL_DIR/lib/"
|
cp "$OUTPUT_NAME.a" "$INSTALL_DIR/lib/"
|
||||||
|
cp -r "../$INCLUDE_DIR/"* "$INSTALL_DIR/include/"
|
||||||
|
|
||||||
|
if [ "$BUILD_PROGRAMS" -eq 1 ]; then
|
||||||
|
for prog in ../"$PROGRAMS_DIR"/*.c; do
|
||||||
|
prog_name=`basename "$prog" .c`
|
||||||
|
$CC $CFLAGS "$prog" -I"../$INCLUDE_DIR" $OUTPUT_NAME.a $LIBS -o "$prog_name"
|
||||||
|
cp "$prog_name" "$INSTALL_DIR/bin/"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Done. Installed to $INSTALL_DIR"
|
echo "Done. Installed to $INSTALL_DIR"
|
||||||
|
15
flake.nix
15
flake.nix
@@ -20,7 +20,7 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.default = pkgs.mkShell.override { stdenv = pkgs.llvmPackages_20.libcxxStdenv; } {
|
devShells.default = pkgs.mkShell {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
cmake
|
cmake
|
||||||
ninja
|
ninja
|
||||||
@@ -28,8 +28,21 @@
|
|||||||
lldb
|
lldb
|
||||||
pkg-config
|
pkg-config
|
||||||
tokei
|
tokei
|
||||||
|
valgrind
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
packages.default = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "dcfg";
|
||||||
|
version = "master";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.pkg-config
|
||||||
|
];
|
||||||
|
buildInputs = [ ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the “Software”), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef DCFG_H
|
#ifndef DCFG_H
|
||||||
#define DCFG_H
|
#define DCFG_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -17,6 +40,7 @@ typedef struct dcfg_StringView {
|
|||||||
char const *data;
|
char const *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
} dcfg_StringView;
|
} dcfg_StringView;
|
||||||
|
#define dcfg_SV(cstr) ((dcfg_StringView) { .data = cstr, .size = strlen(cstr) })
|
||||||
|
|
||||||
typedef void *(*dcfg_AllocFn)(size_t); // This should automatically zero memory.
|
typedef void *(*dcfg_AllocFn)(size_t); // This should automatically zero memory.
|
||||||
typedef void (*dcfg_FreeFn)(void *);
|
typedef void (*dcfg_FreeFn)(void *);
|
||||||
@@ -47,9 +71,19 @@ typedef enum dcfg_ValueKind {
|
|||||||
dcfg_ValueType_Object,
|
dcfg_ValueType_Object,
|
||||||
dcfg_ValueType_Array,
|
dcfg_ValueType_Array,
|
||||||
dcfg_ValueType_Function,
|
dcfg_ValueType_Function,
|
||||||
|
dcfg_ValueType_MemberAccess,
|
||||||
dcfg_ValueType_FunctionCall,
|
dcfg_ValueType_FunctionCall,
|
||||||
} dcfg_ValueType;
|
} dcfg_ValueType;
|
||||||
|
|
||||||
|
typedef dcfg_Value *(*dcfg_BuiltIn)(dcfg_Value **argv, size_t argc);
|
||||||
|
|
||||||
|
typedef uint64_t dcfg_Version;
|
||||||
|
#define DCFG_GET_MAJOR(v) (((v) >> 48) & 0xFFFF)
|
||||||
|
#define DCFG_GET_MINOR(v) (((v) >> 32) & 0xFFFF)
|
||||||
|
#define DCFG_GET_PATCH(v) ((v) & 0xFFFFFFFF)
|
||||||
|
|
||||||
|
dcfg_Version dcfg_get_version(void);
|
||||||
|
|
||||||
dcfg_Instance *dcfg_make_instance(dcfg_InstanceCreateInfo const *create_info);
|
dcfg_Instance *dcfg_make_instance(dcfg_InstanceCreateInfo const *create_info);
|
||||||
void dcfg_destroy_instance(dcfg_Instance *instance);
|
void dcfg_destroy_instance(dcfg_Instance *instance);
|
||||||
|
|
||||||
@@ -75,6 +109,8 @@ bool dcfg_Value_get_object_field_ex(dcfg_Value *value,
|
|||||||
dcfg_StringView const key, dcfg_Value **out_value, bool const evaluate);
|
dcfg_StringView const key, dcfg_Value **out_value, bool const evaluate);
|
||||||
bool dcfg_Value_get_array_item_ex(dcfg_Value *value, size_t const index,
|
bool dcfg_Value_get_array_item_ex(dcfg_Value *value, size_t const index,
|
||||||
dcfg_Value **out_value, bool const evaluate);
|
dcfg_Value **out_value, bool const evaluate);
|
||||||
|
bool dcfg_Value_get_function_body_ex(
|
||||||
|
dcfg_Value *value, dcfg_Value **out_value, bool evaluate);
|
||||||
|
|
||||||
bool dcfg_Value_get_boolean(dcfg_Value *value, bool *out_value);
|
bool dcfg_Value_get_boolean(dcfg_Value *value, bool *out_value);
|
||||||
bool dcfg_Value_get_integer(dcfg_Value *value, int64_t *out_value);
|
bool dcfg_Value_get_integer(dcfg_Value *value, int64_t *out_value);
|
||||||
@@ -95,10 +131,21 @@ static inline bool dcfg_Value_get_array_item(
|
|||||||
{
|
{
|
||||||
return dcfg_Value_get_array_item_ex(value, index, out_value, true);
|
return dcfg_Value_get_array_item_ex(value, index, out_value, true);
|
||||||
}
|
}
|
||||||
|
static inline bool dcfg_Value_get_function_body(
|
||||||
|
dcfg_Value *value, dcfg_Value **out_value)
|
||||||
|
{
|
||||||
|
return dcfg_Value_get_function_body_ex(value, out_value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates new values
|
||||||
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
|
bool dcfg_call_function(dcfg_Value *function, dcfg_Value **args,
|
||||||
size_t arg_count, dcfg_Value **out_value);
|
size_t arg_count, dcfg_Value **out_value);
|
||||||
|
// Allocates new values
|
||||||
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value);
|
bool dcfg_Value_evaluate(dcfg_Value *value, dcfg_Value **out_value);
|
||||||
|
// Allocates new values
|
||||||
|
bool dcfg_Value_evaluate_toplevel(dcfg_Value *top, dcfg_Value **out_value,
|
||||||
|
dcfg_StringView *function_names, dcfg_BuiltIn *functions,
|
||||||
|
size_t function_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
179
programs/dcfg_dump.c
Normal file
179
programs/dcfg_dump.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#include <dcfg.h>
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void walk_value(dcfg_Value *value, bool evaluate, int indent, bool first);
|
||||||
|
#define WALK(v, e, i) walk_value((v), (e), (i), true)
|
||||||
|
|
||||||
|
static void print_indent(int indent)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < indent; ++i)
|
||||||
|
putchar('\t');
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool evaluate = false;
|
||||||
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "e")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'e':
|
||||||
|
evaluate = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Usage: %s [-e] <dcfg file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optind >= argc) {
|
||||||
|
fprintf(stderr, "Usage: %s [-e] <dcfg file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *path = argv[optind];
|
||||||
|
|
||||||
|
dcfg_InstanceCreateInfo ci = { 0 };
|
||||||
|
dcfg_Instance *instance = dcfg_make_instance(&ci);
|
||||||
|
if (!instance) {
|
||||||
|
printf("Failed to create DCFG instance. Error: %s\n",
|
||||||
|
dcfg_last_error(instance));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcfg_Value *value = dcfg_parse(instance, dcfg_SV(path));
|
||||||
|
if (!value) {
|
||||||
|
printf("Failed to parse DCFG file. Error: %s\n",
|
||||||
|
dcfg_last_error(instance));
|
||||||
|
dcfg_destroy_instance(instance);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WALK(value, evaluate, 0);
|
||||||
|
|
||||||
|
dcfg_destroy(value);
|
||||||
|
dcfg_destroy_instance(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void walk_value(dcfg_Value *value, bool evaluate, int indent, bool first)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
print_indent(indent);
|
||||||
|
|
||||||
|
dcfg_ValueType type = dcfg_Value_type_ex(value, evaluate);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case dcfg_ValueType_Nil:
|
||||||
|
printf("null");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Boolean: {
|
||||||
|
bool b;
|
||||||
|
dcfg_Value_get_boolean(value, &b);
|
||||||
|
printf("%s", b ? "true" : "false");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Integer: {
|
||||||
|
int64_t v;
|
||||||
|
dcfg_Value_get_integer(value, &v);
|
||||||
|
printf("%" PRId64, v);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Real: {
|
||||||
|
double v;
|
||||||
|
dcfg_Value_get_real(value, &v);
|
||||||
|
printf("%g", v);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_String: {
|
||||||
|
dcfg_StringView sv;
|
||||||
|
dcfg_Value_get_string(value, &sv);
|
||||||
|
printf("\"%.*s\"", (int)sv.size, sv.data);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Path: {
|
||||||
|
dcfg_StringView sv;
|
||||||
|
dcfg_Value_get_path(value, &sv);
|
||||||
|
printf("<path \"%.*s\">", (int)sv.size, sv.data);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Object: {
|
||||||
|
size_t n = 0;
|
||||||
|
dcfg_Value_get_object_keys(value, 0, &n, NULL);
|
||||||
|
dcfg_StringView *keys
|
||||||
|
= n ? (dcfg_StringView *)calloc(1, n * sizeof(*keys)) : NULL;
|
||||||
|
dcfg_Value_get_object_keys(value, n, &n, keys);
|
||||||
|
|
||||||
|
printf("{\n");
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
dcfg_Value *child;
|
||||||
|
if (!dcfg_Value_get_object_field_ex(
|
||||||
|
value, keys[i], &child, evaluate))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
print_indent(indent + 1);
|
||||||
|
printf("\"%.*s\": ", (int)keys[i].size, keys[i].data);
|
||||||
|
walk_value(child, evaluate, indent + 1, false);
|
||||||
|
if (i + 1 < n)
|
||||||
|
printf(",");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
print_indent(indent);
|
||||||
|
printf("}");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Array: {
|
||||||
|
size_t sz = 0;
|
||||||
|
dcfg_Value_get_array_size(value, &sz);
|
||||||
|
|
||||||
|
printf("[\n");
|
||||||
|
for (size_t i = 0; i < sz; ++i) {
|
||||||
|
dcfg_Value *item;
|
||||||
|
if (!dcfg_Value_get_array_item_ex(value, i, &item, evaluate))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
print_indent(indent + 1);
|
||||||
|
walk_value(item, evaluate, indent + 1, false);
|
||||||
|
if (i + 1 < sz)
|
||||||
|
printf(",");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
print_indent(indent);
|
||||||
|
printf("]");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_Function: {
|
||||||
|
dcfg_Value *body = NULL;
|
||||||
|
|
||||||
|
if (dcfg_Value_get_function_body_ex(value, &body, evaluate) && body) {
|
||||||
|
printf("<fn>\t");
|
||||||
|
walk_value(body, evaluate, indent + 1, false);
|
||||||
|
} else {
|
||||||
|
printf("<builtin-fn>");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dcfg_ValueType_FunctionCall:
|
||||||
|
if (evaluate) {
|
||||||
|
dcfg_Value *res;
|
||||||
|
if (dcfg_Value_evaluate(value, &res))
|
||||||
|
walk_value(res, evaluate, indent, first);
|
||||||
|
else
|
||||||
|
printf("<error-evaluating-call>");
|
||||||
|
} else {
|
||||||
|
printf("<function-call>");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("<unknown>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indent == 0) {
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
143
programs/dcfgq.c
Normal file
143
programs/dcfgq.c
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#include <dcfg.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
T_FIELD,
|
||||||
|
T_INDEX,
|
||||||
|
} TokenType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TokenType type;
|
||||||
|
union {
|
||||||
|
dcfg_StringView field;
|
||||||
|
size_t index;
|
||||||
|
} v;
|
||||||
|
} Token;
|
||||||
|
|
||||||
|
#define MAX_TOKENS 256
|
||||||
|
|
||||||
|
static size_t tokenize(char const *query, Token *out)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
if (query[i] == '.')
|
||||||
|
i++;
|
||||||
|
while (query[i] && count < MAX_TOKENS) {
|
||||||
|
if (query[i] == '.') {
|
||||||
|
i++;
|
||||||
|
size_t start = i;
|
||||||
|
while (query[i] && query[i] != '.' && query[i] != '[')
|
||||||
|
i++;
|
||||||
|
out[count].type = T_FIELD;
|
||||||
|
out[count].v.field.data = query + start;
|
||||||
|
out[count].v.field.size = i - start;
|
||||||
|
count++;
|
||||||
|
} else if (query[i] == '[') {
|
||||||
|
i++;
|
||||||
|
char *end;
|
||||||
|
size_t idx = strtoul(query + i, &end, 10);
|
||||||
|
if (*end != ']') {
|
||||||
|
fprintf(stderr, "invalid index\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
i = (size_t)(end - query) + 1;
|
||||||
|
out[count].type = T_INDEX;
|
||||||
|
out[count].v.index = idx;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
size_t start = i;
|
||||||
|
while (query[i] && query[i] != '.' && query[i] != '[')
|
||||||
|
i++;
|
||||||
|
out[count].type = T_FIELD;
|
||||||
|
out[count].v.field.data = query + start;
|
||||||
|
out[count].v.field.size = i - start;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_value(dcfg_Value *v)
|
||||||
|
{
|
||||||
|
dcfg_StringView sv;
|
||||||
|
if (dcfg_serialize_value(v, &sv)) {
|
||||||
|
fwrite(sv.data, 1, sv.size, stdout);
|
||||||
|
free((void *)sv.data);
|
||||||
|
putchar('\n');
|
||||||
|
} else {
|
||||||
|
puts("null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "usage: %s <query> <file>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char const *query = argv[1];
|
||||||
|
char const *file = argv[2];
|
||||||
|
|
||||||
|
dcfg_Instance *inst = dcfg_make_instance(&(dcfg_InstanceCreateInfo) { 0 });
|
||||||
|
if (!inst) {
|
||||||
|
fprintf(stderr, "failed to create instance\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dcfg_Value *root = dcfg_parse(inst, dcfg_SV(file));
|
||||||
|
if (!root) {
|
||||||
|
fprintf(stderr, "parse error: %s\n", dcfg_last_error(inst));
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token toks[MAX_TOKENS];
|
||||||
|
size_t n = tokenize(query, toks);
|
||||||
|
|
||||||
|
dcfg_Value *evaled;
|
||||||
|
if (!dcfg_Value_evaluate_toplevel(root, &evaled, NULL, NULL, 0)) {
|
||||||
|
fprintf(stderr, "evaluation error: %s\n", dcfg_last_error(inst));
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcfg_Value *cur = evaled;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
Token *t = &toks[i];
|
||||||
|
dcfg_Value *next = NULL;
|
||||||
|
|
||||||
|
if (t->type == T_FIELD) {
|
||||||
|
if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) {
|
||||||
|
fprintf(stderr, "no such field\n");
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
|
||||||
|
fprintf(stderr, "index out of bounds\n");
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur != evaled)
|
||||||
|
dcfg_destroy(cur);
|
||||||
|
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
print_value(cur);
|
||||||
|
if (cur != evaled)
|
||||||
|
dcfg_destroy(cur);
|
||||||
|
|
||||||
|
dcfg_destroy(evaled);
|
||||||
|
dcfg_destroy(root);
|
||||||
|
dcfg_destroy_instance(inst);
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -8,6 +8,6 @@ fn lib = {
|
|||||||
partitions = {
|
partitions = {
|
||||||
automount = [ 'boot' 'root' ]
|
automount = [ 'boot' 'root' ]
|
||||||
swap.enable = true
|
swap.enable = true
|
||||||
swap.size = 2g
|
swap.size = 2_000_000_000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
samples/invalid_block.dcfg
Normal file
5
samples/invalid_block.dcfg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
test = 123
|
||||||
|
test.field = 456 # This should be invalid. `test` is an int, not an object.
|
||||||
|
}
|
||||||
|
|
12
samples/testing.dcfg
Normal file
12
samples/testing.dcfg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
fn lib = [
|
||||||
|
123
|
||||||
|
"string"
|
||||||
|
./path
|
||||||
|
80085.3
|
||||||
|
{
|
||||||
|
key1 = 123
|
||||||
|
key2.member = "str"
|
||||||
|
key2.another_member = ./amazing
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
11
samples/utf8.dcfg
Normal file
11
samples/utf8.dcfg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fn lib = {
|
||||||
|
english = "The quick brown fox jumps over the lazy dog."
|
||||||
|
日本語 = "はじめまして!"
|
||||||
|
Română = "Salutare! ĂÂÎȘȚăâîșț"
|
||||||
|
😀 = "👋🌍😊🚀🤖"
|
||||||
|
diacritics = "ŠĐĆŽšđž"
|
||||||
|
français = "Ça déjà vu?"
|
||||||
|
español = "¡El pingüino Wenceslao bebe whisky y zumo de piña!"
|
||||||
|
русский = "Съешь же ещё этих мягких французских булок, да выпей чаю."
|
||||||
|
}
|
||||||
|
|
@@ -1,8 +1,8 @@
|
|||||||
fn lib = {
|
fn lib = {
|
||||||
keybindings = [
|
keybindings = [
|
||||||
{ key = 'Main-Shift-Escape' action = lib.quit_wm }
|
{ key = 'Main-Shift-Escape' action = (lib.quit_wm) }
|
||||||
{ key = 'Main-Shift-Q' action = lib.kill_application }
|
{ key = 'Main-Shift-Q' action = (lib.kill_application) }
|
||||||
{ key = 'Main-Shift-C' action = lib.close_application }
|
{ key = 'Main-Shift-C' action = (lib.close_application) }
|
||||||
{ key = 'Main-Space' action = (lib.execute 'alacritty') }
|
{ key = 'Main-Space' action = (lib.execute 'alacritty') }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
1203
src/dcfg.c
1203
src/dcfg.c
File diff suppressed because it is too large
Load Diff
30
src/meta.h
Normal file
30
src/meta.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Slendi <slendi@socopon.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the “Software”), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_H
|
||||||
|
#define META_H
|
||||||
|
|
||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 1
|
||||||
|
#define VERSION_PATCH 0
|
||||||
|
|
||||||
|
#endif // META_H
|
66
src/vendor/vec.c
vendored
66
src/vendor/vec.c
vendored
@@ -33,18 +33,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
vec_size_t size;
|
vec_size_t size;
|
||||||
vec_size_t capacity;
|
vec_size_t capacity;
|
||||||
unsigned char data[];
|
unsigned char data[];
|
||||||
} vector_header;
|
} vector_header;
|
||||||
|
|
||||||
vector_header* vector_get_header(vector vec) { return &((vector_header*)vec)[-1]; }
|
vector_header *vector_get_header(vector vec)
|
||||||
|
{
|
||||||
|
return &((vector_header *)vec)[-1];
|
||||||
|
}
|
||||||
|
|
||||||
vector vector_create(void)
|
vector vector_create(void)
|
||||||
{
|
{
|
||||||
vector_header* h = (vector_header*)malloc(sizeof(vector_header));
|
vector_header *h = (vector_header *)malloc(sizeof(vector_header));
|
||||||
h->capacity = 0;
|
h->capacity = 0;
|
||||||
h->size = 0;
|
h->size = 0;
|
||||||
|
|
||||||
@@ -55,28 +57,28 @@ void vector_free(vector vec) { free(vector_get_header(vec)); }
|
|||||||
|
|
||||||
vec_size_t vector_size(vector vec) { return vector_get_header(vec)->size; }
|
vec_size_t vector_size(vector vec) { return vector_get_header(vec)->size; }
|
||||||
|
|
||||||
vec_size_t vector_capacity(vector vec) { return vector_get_header(vec)->capacity; }
|
vec_size_t vector_capacity(vector vec)
|
||||||
|
{
|
||||||
|
return vector_get_header(vec)->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
vector_header* vector_realloc(vector_header* h, vec_type_t type_size)
|
vector_header *vector_realloc(vector_header *h, vec_type_t type_size)
|
||||||
{
|
{
|
||||||
vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2;
|
vec_size_t new_capacity = (h->capacity == 0) ? 1 : h->capacity * 2;
|
||||||
vector_header* new_h = (vector_header*)realloc(h, sizeof(vector_header) + new_capacity * type_size);
|
vector_header *new_h = (vector_header *)realloc(
|
||||||
|
h, sizeof(vector_header) + new_capacity * type_size);
|
||||||
new_h->capacity = new_capacity;
|
new_h->capacity = new_capacity;
|
||||||
|
|
||||||
return new_h;
|
return new_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vector_has_space(vector_header* h)
|
bool vector_has_space(vector_header *h) { return h->capacity - h->size > 0; }
|
||||||
{
|
|
||||||
return h->capacity - h->size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
|
void *_vector_add_dst(vector *vec_addr, vec_type_t type_size)
|
||||||
{
|
{
|
||||||
vector_header* h = vector_get_header(*vec_addr);
|
vector_header *h = vector_get_header(*vec_addr);
|
||||||
|
|
||||||
if (!vector_has_space(h))
|
if (!vector_has_space(h)) {
|
||||||
{
|
|
||||||
h = vector_realloc(h, type_size);
|
h = vector_realloc(h, type_size);
|
||||||
*vec_addr = h->data;
|
*vec_addr = h->data;
|
||||||
}
|
}
|
||||||
@@ -84,21 +86,19 @@ void* _vector_add_dst(vector* vec_addr, vec_type_t type_size)
|
|||||||
return &h->data[type_size * h->size++];
|
return &h->data[type_size * h->size++];
|
||||||
}
|
}
|
||||||
|
|
||||||
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
|
void *_vector_insert_dst(vector *vec_addr, vec_type_t type_size, vec_size_t pos)
|
||||||
{
|
{
|
||||||
vector_header* h = vector_get_header(*vec_addr);
|
vector_header *h = vector_get_header(*vec_addr);
|
||||||
|
|
||||||
vec_size_t new_length = h->size + 1;
|
vec_size_t new_length = h->size + 1;
|
||||||
|
|
||||||
// make sure there is enough room for the new element
|
// make sure there is enough room for the new element
|
||||||
if (!vector_has_space(h))
|
if (!vector_has_space(h)) {
|
||||||
{
|
|
||||||
h = vector_realloc(h, type_size);
|
h = vector_realloc(h, type_size);
|
||||||
*vec_addr = h->data;
|
*vec_addr = h->data;
|
||||||
}
|
}
|
||||||
// move trailing elements
|
// move trailing elements
|
||||||
memmove(&h->data[(pos + 1) * type_size],
|
memmove(&h->data[(pos + 1) * type_size], &h->data[pos * type_size],
|
||||||
&h->data[pos * type_size],
|
|
||||||
(h->size - pos) * type_size);
|
(h->size - pos) * type_size);
|
||||||
|
|
||||||
h->size = new_length;
|
h->size = new_length;
|
||||||
@@ -106,11 +106,11 @@ void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos)
|
|||||||
return &h->data[pos * type_size];
|
return &h->data[pos * type_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t len)
|
void _vector_erase(
|
||||||
|
vector vec, vec_type_t type_size, vec_size_t pos, vec_size_t len)
|
||||||
{
|
{
|
||||||
vector_header* h = vector_get_header(vec);
|
vector_header *h = vector_get_header(vec);
|
||||||
memmove(&h->data[pos * type_size],
|
memmove(&h->data[pos * type_size], &h->data[(pos + len) * type_size],
|
||||||
&h->data[(pos + len) * type_size],
|
|
||||||
(h->size - pos - len) * type_size);
|
(h->size - pos - len) * type_size);
|
||||||
|
|
||||||
h->size -= len;
|
h->size -= len;
|
||||||
@@ -123,26 +123,28 @@ void _vector_remove(vector vec, vec_type_t type_size, vec_size_t pos)
|
|||||||
|
|
||||||
void vector_pop(vector vec) { --vector_get_header(vec)->size; }
|
void vector_pop(vector vec) { --vector_get_header(vec)->size; }
|
||||||
|
|
||||||
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity)
|
void _vector_reserve(
|
||||||
|
vector *vec_addr, vec_type_t type_size, vec_size_t capacity)
|
||||||
{
|
{
|
||||||
vector_header* h = vector_get_header(*vec_addr);
|
vector_header *h = vector_get_header(*vec_addr);
|
||||||
if (h->capacity >= capacity)
|
if (h->capacity >= capacity) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
h = (vector_header*)realloc(h, sizeof(vector_header) + capacity * type_size);
|
h = (vector_header *)realloc(
|
||||||
|
h, sizeof(vector_header) + capacity * type_size);
|
||||||
h->capacity = capacity;
|
h->capacity = capacity;
|
||||||
*vec_addr = &h->data;
|
*vec_addr = &h->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector _vector_copy(vector vec, vec_type_t type_size)
|
vector _vector_copy(vector vec, vec_type_t type_size)
|
||||||
{
|
{
|
||||||
vector_header* h = vector_get_header(vec);
|
vector_header *h = vector_get_header(vec);
|
||||||
size_t alloc_size = sizeof(vector_header) + h->size * type_size;
|
size_t alloc_size = sizeof(vector_header) + h->size * type_size;
|
||||||
vector_header* copy_h = (vector_header*)malloc(alloc_size);
|
vector_header *copy_h = (vector_header *)malloc(alloc_size);
|
||||||
memcpy(copy_h, h, alloc_size);
|
memcpy(copy_h, h, alloc_size);
|
||||||
copy_h->capacity = copy_h->size;
|
copy_h->capacity = copy_h->size;
|
||||||
|
|
||||||
return ©_h->data;
|
return ©_h->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
src/vendor/vec.h
vendored
65
src/vendor/vec.h
vendored
@@ -33,11 +33,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#ifndef vec_h
|
#ifndef vec_h
|
||||||
#define vec_h
|
#define vec_h
|
||||||
|
|
||||||
#ifdef __cpp_decltype
|
|
||||||
#include <type_traits>
|
|
||||||
#define typeof(T) std::remove_reference<std::add_lvalue_reference<decltype(T)>::type>::type
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -46,72 +41,50 @@ extern "C" {
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
// generic type for internal use
|
// generic type for internal use
|
||||||
typedef void* vector;
|
typedef void *vector;
|
||||||
// number of elements in a vector
|
// number of elements in a vector
|
||||||
typedef size_t vec_size_t;
|
typedef size_t vec_size_t;
|
||||||
// number of bytes for a type
|
// number of bytes for a type
|
||||||
typedef size_t vec_type_t;
|
typedef size_t vec_type_t;
|
||||||
|
|
||||||
// TODO: more rigorous check for typeof support with different compilers
|
#define vector_add_dst(vec_addr, type) \
|
||||||
#if _MSC_VER == 0 || __STDC_VERSION__ >= 202311L || defined __cpp_decltype
|
((type *)_vector_add_dst((vector *)vec_addr, sizeof(type)))
|
||||||
|
#define vector_insert_dst(vec_addr, type, pos) \
|
||||||
|
((type *)_vector_insert_dst((vector *)vec_addr, sizeof(type), pos))
|
||||||
|
|
||||||
// shortcut defines
|
#define vector_add(vec_addr, type, value) \
|
||||||
|
|
||||||
// vec_addr is a vector* (aka type**)
|
|
||||||
#define vector_add_dst(vec_addr)\
|
|
||||||
((typeof(*vec_addr))(\
|
|
||||||
_vector_add_dst((vector*)vec_addr, sizeof(**vec_addr))\
|
|
||||||
))
|
|
||||||
#define vector_insert_dst(vec_addr, pos)\
|
|
||||||
((typeof(*vec_addr))(\
|
|
||||||
_vector_insert_dst((vector*)vec_addr, sizeof(**vec_addr), pos)))
|
|
||||||
|
|
||||||
#define vector_add(vec_addr, value)\
|
|
||||||
(*vector_add_dst(vec_addr) = value)
|
|
||||||
#define vector_insert(vec_addr, pos, value)\
|
|
||||||
(*vector_insert_dst(vec_addr, pos) = value)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define vector_add_dst(vec_addr, type)\
|
|
||||||
((type*)_vector_add_dst((vector*)vec_addr, sizeof(type)))
|
|
||||||
#define vector_insert_dst(vec_addr, type, pos)\
|
|
||||||
((type*)_vector_insert_dst((vector*)vec_addr, sizeof(type), pos))
|
|
||||||
|
|
||||||
#define vector_add(vec_addr, type, value)\
|
|
||||||
(*vector_add_dst(vec_addr, type) = value)
|
(*vector_add_dst(vec_addr, type) = value)
|
||||||
#define vector_insert(vec_addr, type, pos, value)\
|
#define vector_insert(vec_addr, type, pos, value) \
|
||||||
(*vector_insert_dst(vec_addr, type, pos) = value)
|
(*vector_insert_dst(vec_addr, type, pos) = value)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// vec is a vector (aka type*)
|
// vec is a vector (aka type*)
|
||||||
#define vector_erase(vec, pos, len)\
|
#define vector_erase(vec, pos, len) \
|
||||||
(_vector_erase((vector)vec, sizeof(*vec), pos, len))
|
(_vector_erase((vector)vec, sizeof(*vec), pos, len))
|
||||||
#define vector_remove(vec, pos)\
|
#define vector_remove(vec, pos) (_vector_remove((vector)vec, sizeof(*vec), pos))
|
||||||
(_vector_remove((vector)vec, sizeof(*vec), pos))
|
|
||||||
|
|
||||||
#define vector_reserve(vec_addr, capacity)\
|
#define vector_reserve(vec_addr, capacity) \
|
||||||
(_vector_reserve((vector*)vec_addr, sizeof(**vec_addr), capacity))
|
(_vector_reserve((vector *)vec_addr, sizeof(**vec_addr), capacity))
|
||||||
|
|
||||||
#define vector_copy(vec)\
|
#define vector_copy(vec) (_vector_copy((vector)vec, sizeof(*vec)))
|
||||||
(_vector_copy((vector)vec, sizeof(*vec)))
|
|
||||||
|
|
||||||
vector vector_create(void);
|
vector vector_create(void);
|
||||||
|
|
||||||
void vector_free(vector vec);
|
void vector_free(vector vec);
|
||||||
|
|
||||||
void* _vector_add_dst(vector* vec_addr, vec_type_t type_size);
|
void *_vector_add_dst(vector *vec_addr, vec_type_t type_size);
|
||||||
|
|
||||||
void* _vector_insert_dst(vector* vec_addr, vec_type_t type_size, vec_size_t pos);
|
void *_vector_insert_dst(
|
||||||
|
vector *vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||||
|
|
||||||
void _vector_erase(vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len);
|
void _vector_erase(
|
||||||
|
vector vec_addr, vec_type_t type_size, vec_size_t pos, vec_size_t len);
|
||||||
|
|
||||||
void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos);
|
void _vector_remove(vector vec_addr, vec_type_t type_size, vec_size_t pos);
|
||||||
|
|
||||||
void vector_pop(vector vec);
|
void vector_pop(vector vec);
|
||||||
|
|
||||||
void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t capacity);
|
void _vector_reserve(
|
||||||
|
vector *vec_addr, vec_type_t type_size, vec_size_t capacity);
|
||||||
|
|
||||||
vector _vector_copy(vector vec, vec_type_t type_size);
|
vector _vector_copy(vector vec, vec_type_t type_size);
|
||||||
|
|
||||||
|
4
tools/clean.sh
Executable file
4
tools/clean.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
rm -rf install build BUILD result
|
||||||
|
|
Reference in New Issue
Block a user