commit 7c1b0ab290ab8962be4b549aa3e8e226671637e2 Author: Randy Jordan Date: Sat Jun 6 18:15:42 2026 -0500 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9135206 --- /dev/null +++ b/Makefile @@ -0,0 +1,152 @@ +# Compiler Flags +CC := gcc +CFLAGS := -g -Wall -Wextra -Werror -pedantic -fno-omit-frame-pointer +DEPFLAGS = -MMD -MP + +# Directory Variables +LIBDIR := lib +OBJ := obj +INC := include +SRC := src +TEST := tests + +# Install Paths (override with: make install PREFIX=/usr/local) +PREFIX ?= /usr/local +INSTALL_LIB = $(PREFIX)/lib +INSTALL_INC = $(PREFIX)/include + +# Platform Detection and Library Linking +ifeq ($(OS), Windows_NT) + PLATFORM := win32 + PLATFORM_SRCS := $(wildcard $(SRC)/win32_*.c) + PLATFORM_OBJS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(PLATFORM_SRCS)) + PLATFORM_FLAGS := -D WIN32 + PLATFORM_LIBS := -mwindows +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S), Linux) + PLATFORM := linux + PLATFORM_SRCS := $(wildcard $(SRC)/linux_*.c) + PLATFORM_OBJS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(PLATFORM_SRCS)) + PLATFORM_FLAGS := -D LINUX + PLATFORM_LIBS := -lX11 +else ifeq ($(UNAME_S), Darwin) + PLATFORM := mac + PLATFORM_SRCS := $(wildcard $(SRC)/mac_*.c) + PLATFORM_OBJS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(PLATFORM_SRCS)) + PLATFORM_FLAGS := -D MACOS + PLATFORM_LIBS := +else + $(error Unsupported platform: $(UNAME_S)) +endif +endif + +# Add platform flags +CFLAGS += $(PLATFORM_FLAGS) + +# Filepath Pattern Matching +LIB := $(LIBDIR)/lib.a + +# Filter out ALL platform-prefixed files, then add back the correct platform's +SRCS := $(filter-out \ + $(wildcard $(SRC)/win32_*.c) \ + $(wildcard $(SRC)/linux_*.c) \ + $(wildcard $(SRC)/macos_*.c), \ + $(wildcard $(SRC)/*.c)) \ + $(PLATFORM_SRCS) + +OBJS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) +TESTS := $(wildcard $(TEST)/*.c) +TESTBINS := $(patsubst $(TEST)/%.c, $(TEST)/bin/%, $(TESTS)) + +# Commands must be labeled PHONY +.PHONY: all release clean test install uninstall + +# Compiler Release Flags (no sanitizers — those belong in CI/debug builds) +release: CFLAGS := -Wall -Wextra -Werror -pedantic -fno-omit-frame-pointer -O2 -DNDEBUG $(PLATFORM_FLAGS) +release: clean $(LIB) + @echo "\nRelease build complete for platform: $(PLATFORM)\n" + +# Target for compilation +all: $(LIB) + @echo "\nBuilt for platform: $(PLATFORM)\n" + +# Target / Dependencies +$(LIB): $(OBJS) | $(LIBDIR) + ar -cvrs $@ $^ + +# Compile with automatic dependency tracking +$(OBJ)/%.o: $(SRC)/%.c $(SRC)/%.h | $(OBJ) + $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ + +$(OBJ)/%.o: $(SRC)/%.c | $(OBJ) + $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ + +$(TEST)/bin/%: $(TEST)/%.c $(LIB) | $(TEST)/bin + $(CC) $(CFLAGS) $< $(LIB) $(PLATFORM_LIBS) -o $@ + +# Make directories if none +$(LIBDIR): + mkdir $@ +$(OBJ): + mkdir $@ +$(TEST)/bin: + mkdir -p $@ + +# Run the tests in the bin folder and track results +# Uses perl for nanosecond timing — portable across Linux and macOS +test: $(LIB) $(TESTBINS) + @SUCCESS=0; FAILURE=0; \ + RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'; \ + for t in $(TESTBINS); do \ + NAME=$$(basename $$t); \ + START=$$(perl -MTime::HiRes=time -e 'printf "%d\n", time()*1000'); \ + if $$t; then \ + RET=0; \ + else \ + RET=$$?; \ + fi; \ + END=$$(perl -MTime::HiRes=time -e 'printf "%d\n", time()*1000'); \ + ELAPSED_MS=$$((END - START)); \ + if [ $$RET -eq 0 ]; then \ + printf "%-20s %bPASS%b (%b%4d ms%b)\n" "$$NAME" "$$GREEN" "$$NC" "$$YELLOW" "$$ELAPSED_MS" "$$NC"; \ + SUCCESS=$$((SUCCESS + 1)); \ + else \ + printf "%-20s %bFAIL%b (%b%4d ms%b)\n" "$$NAME" "$$RED" "$$NC" "$$YELLOW" "$$ELAPSED_MS" "$$NC"; \ + FAILURE=$$((FAILURE + 1)); \ + fi; \ + done; \ + printf "\nTests completed\n"; \ + printf "SUCCESS: %b%d%b\n" "$$GREEN" "$$SUCCESS" "$$NC"; \ + printf "FAILURE: %b%d%b\n" "$$RED" "$$FAILURE" "$$NC"; \ + test $$FAILURE -eq 0 + +# Install library and public headers +install: $(LIB) + @echo "Installing to $(PREFIX)..." + install -d $(INSTALL_LIB) + install -d $(INSTALL_INC) + install -m 644 $(LIB) $(INSTALL_LIB)/ + @if [ -d $(INC) ]; then \ + install -m 644 $(INC)/*.h $(INSTALL_INC)/; \ + echo "Installed headers from $(INC)/"; \ + else \ + echo "Warning: no $(INC)/ directory found — skipping header install"; \ + fi + @echo "Install complete: lib -> $(INSTALL_LIB) headers -> $(INSTALL_INC)" + +uninstall: + @echo "Removing installed files from $(PREFIX)..." + $(RM) $(INSTALL_LIB)/lib.a + @if [ -d $(INC) ]; then \ + for h in $(INC)/*.h; do \ + $(RM) $(INSTALL_INC)/$$(basename $$h); \ + done; \ + fi + @echo "Uninstall complete" + +clean: + $(RM) -r $(LIBDIR) $(OBJ) $(TEST)/bin/ + +# Pull in generated dependency files (silently ignored if absent) +-include $(DEPS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a886a6 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# ci2 + +## Description +Inspired by all in the acknowledgments, this is my own personal C codebase. + + +## Table of Contents + +* [Features](#features) +* [Todos](#todos) +* [Usage](#usage) +* [Acknowledgments](#acknowledgments) +* [License](#license) + + +## Features + +## Todos + +## Usage + +```bash +# Example installation +git clone https://myrepos.dev/Randy-Jordan/ci2.git + +# Navigate into the directory +cd ci2 + +# Build the project +make + +# Build and run tests. +make test + +``` + +## Acknowledgments +[C Interfaces and Implementations](https://github.com/drh/cii)
+[Unix Networking Programming Sockets Networking API](https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551)
+[Advanced Programming in the UNIX Environment](https://www.amazon.com/Advanced-Programming-UNIX-Environment-3rd/dp/0321637739/146-5615695-5426958)
+[stsaz - ffsys](https://github.com/stsaz/ffsys)
+[nothings - stb](https://github.com/nothings/stb)
+[Sean Barret - Advice for writing small programs](https://youtu.be/eAhWIO1Ra6M)
+[Eskil Steenberg - How I program C](https://www.youtube.com/watch?v=443UNeGrFoM)
+[Ginger Bill](https://www.gingerbill.org/)
+[GingerGill gb](https://github.com/gingerBill/gb)
+[Chris Wellons](https://nullprogram.com/)
+[Skeeto - W64devkit](https://github.com/skeeto/w64devkit)
+[Mongoose Webserver](https://github.com/cesanta/mongoose)
+[Tsoding Daily](https://www.youtube.com/c/TsodingDaily)
+[Jacob Sorber](https://www.youtube.com/@JacobSorber)
+[Crafting Interpreters](https://craftinginterpreters.com/)
+ + +## License + +This project is licensed under the MIT License - see the [MIT License](LICENSE) file for details. + diff --git a/include/ci2.h b/include/ci2.h new file mode 100644 index 0000000..24fa70c --- /dev/null +++ b/include/ci2.h @@ -0,0 +1,32 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_H +#define CI2_H + +#include "./platform/ci2_platform.h" + +#include "./platform/error/ci2_exception.h" +#include "./platform/mem/ci2_mem.h" +#include "./platform/mem/ci2_arena.h" + +#endif // ci2.h diff --git a/include/platform/base/ci2_assert.h b/include/platform/base/ci2_assert.h new file mode 100644 index 0000000..e37b99c --- /dev/null +++ b/include/platform/base/ci2_assert.h @@ -0,0 +1,126 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_ASSERT_H +#define CI2_ASSERT_H + +#include + +/* Force Inline */ +#if defined(_MSC_VER) || defined(__INTEL__LLVM_COMPILER) + #define CI2_INLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) + #define CI2_INLINE __attribute__((always_inline)) inline +#else + #define CI2_INLINE inline +#endif + +/* Use __has_builtin if available (Clang and newer GCC). */ +#if defined(__has_builtin) + /* Check builtins in preferred order */ + #if __has_builtin(__builtin_debugtrap) + #define CI2_DEBUG_TRAP() __builtin_debugtrap() + #elif __has_builtin(__builtin_trap) + #define CI2_DEBUG_TRAP() __builtin_trap() + #elif __has_builtin(__builtin_break) + #define CI2_DEBUG_TRAP() __builtin_break() + #endif +#elif defined(_MSC_VER) || defined(__INTEL__LLVM_COMPILER) + #define CI2_DEBUG_TRAP() __debugbreak() +#else + #define CI2_DEBUG_TRAP() (*(volatile int*)0 = 0) +#endif + +/* Static Asserts */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) + /* C11 */ + #define CI2_STATIC_ASSERT(expr) _Static_assert((expr), #expr) +#else + /* Abuse a typedef of a negative-size array */ + #define CI2_STATIC_ASSERT(expr) typedef char _static_assert_[(expr) ? 1 : -1] +#endif + +/* Current __func__ */ +#if defined(__FUNC__) + #define CI2_FUNC __FUNCTION__ +#else + #define CI2_FUNC __func__ +#endif + +/* Assert Fail */ +static CI2_INLINE void +ci2_assert_fail(const char* expr, + const char* msg, /* may be NULL */ + const char* file, + int line, + const char* func) +{ + if (msg) + fprintf(stderr, + "\n[ASSERT FAILED]\n" + " Expression : %s\n" + " Message : %s\n" + " Location : %s:%d\n" + " Function : %s\n\n", + expr, + msg, + file, + line, + func); + else + fprintf(stderr, + "\n[ASSERT FAILED]\n" + " Expression : %s\n" + " Location : %s:%d\n" + " Function : %s\n\n", + expr, + file, + line, + func); + + /* Flush so the message is visible before we halt */ + fflush(stderr); + + CI2_DEBUG_TRAP(); +} + +#ifndef NDEBUG + #define CI2_ASSERT(expr) \ + do { \ + if (!(expr)) { \ + ci2_assert_fail(#expr, NULL, __FILE__, __LINE__, CI2_FUNC); \ + } \ + } while (0) + + #define CI2_ASSERT_MSG(expr, msg) \ + do { \ + if (!(expr)) { \ + ci2_assert_fail(#expr, (msg), __FILE__, __LINE__, CI2_FUNC); \ + } \ + } while (0) +#else /* NDEBUG — strip all runtime checks */ + + #define ASSERT(expr) ((void)(expr)) + #define ASSERT_MSG(expr, msg) ((void)(expr)) +#endif /* NDEBUG */ + +#endif // ci2_assert.h diff --git a/include/platform/base/ci2_base.h b/include/platform/base/ci2_base.h new file mode 100644 index 0000000..8b4cca8 --- /dev/null +++ b/include/platform/base/ci2_base.h @@ -0,0 +1,49 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_BASE_H +#define CI2_BASE_H + +#include "ci2_assert.h" +#include "ci2_compiler.h" +#include "ci2_os.h" +#include "ci2_thread.h" +#include "ci2_win_env.h" + +#include "ci2_macros.h" +#include "ci2_syntax.h" + +/* Here is where we abstract away the differnces between Operating Systems */ +#if defined CI2_UNIX + #define CI2_INVALID_FD -1 +typedef int ci2_fd; +typedef char ci2_sys_char; + +#else // Windows: + + #define CI2_INVALID_FD NULL +typedef HANDLE ci2_fd; +typedef wchar_t ci2_sys_char; + +#endif + +#endif // ci2_base.h diff --git a/include/platform/base/ci2_compiler.h b/include/platform/base/ci2_compiler.h new file mode 100644 index 0000000..86154f2 --- /dev/null +++ b/include/platform/base/ci2_compiler.h @@ -0,0 +1,38 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_COMPILER_H +#define CI2_COMPILER_H + +#if defined(__INTEL_LLVM_COMPILER) + #define CI2_INTEL_ICX +#elif defined(__GNUC__) && !defined(__clang__) + #define CI2_GCC +#elif defined(__clang__) + #define CI2_CLANG +#elif define(_MSC_VER) && !defined(__clang__) + #define CI2_MSVC +#else + #error "Compiler is unkown and unsupported." +#endif + +#endif // ci2_compiler.h diff --git a/include/platform/base/ci2_macros.h b/include/platform/base/ci2_macros.h new file mode 100644 index 0000000..21178ba --- /dev/null +++ b/include/platform/base/ci2_macros.h @@ -0,0 +1,101 @@ +/* - | Copyright | +-------------------------------------------------------------- Copyright (c) +2026 Randy Jordan + +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 CI2_MACROS_H +#define CI2_MACROS_H + +#define UNUSED(x) (void)(x) +#define STR2(s) #s +#define STR(s) STR2(s) + +#define U8_MIN 0u +#define U8_MAX 0xffu +#define I8_MIN (-0x7f - 1) +#define I8_MAX 0x7f + +#define U16_MIN 0u +#define U16_MAX 0xffffu +#define I16_MIN (-0x7fff - 1) +#define I16_MAX 0x7fff + +#define U32_MIN 0u +#define U32_MAX 0xffffffffu +#define I32_MIN (-0x7fffffff - 1) +#define I32_MAX 0x7fffffff + +#define U64_MIN 0ull +#define U64_MAX 0xffffffffffffffffull +#define I64_MIN (-0x7fffffffffffffffll - 1) +#define I64_MAX 0x7fffffffffffffffll + +#define F32_MIN 1.17549435e-38f +#define F32_MAX 3.40282347e+38f + +#define F64_MIN 2.2250738585072014e-308 +#define F64_MAX 1.7976931348623157e+308 + +#define PI 3.14159265 +#define RAD2DEG(x) ((x) / PI * 180) +#define DEG2RAD(x) ((x) * PI / 180) +#define ALIGNB(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) +#define ALIGN(x, align) ((((x) + ((align) - 1)) / (align)) * (align)) +#define FLOORB(x, align) ((x) & ~((align) - 1)) +#define FLOOR(x, align) (((x) / (align)) * (align)) +#define CEILB(x, align) ALIGNB(x, align) +#define CEIL(x, align) ALIGN(x, align) +#define CLIP(x, min, max) \ + (((x) < (min)) ? (min) : (((x) > (max)) ? (max) : (x))) +#define UCLIP(x, max) (((x) > (max)) ? (max) : (x)) +#define LCLIP(x, min) (((x) < (min)) ? (min) : (x)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define ABS(x) (((x) < 0) ? -(x) : (x)) +#define DIFF(a, b) ABS((a) - (b)) +#define IS_NAN(x) ((x) != (x)) +#define IMPLIES(x, y) (!(x) || (y)) +#define COMPARE(x, y) (((x) > (y)) - ((x) < (y))) +#define SIGN(x) COMPARE(x, 0) +#define IS_ODD(num) ((num) & 1) +#define IS_EVEN(num) (!IS_ODD((num))) +#define IS_BETWEEN(n, L, H) ((unsigned char)((n) >= (L) && (n) <= (H))) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define SET(d, n, v) \ + do { \ + size_t i_, n_; \ + for (n_ = (n), i_ = 0; n_ > 0; --n_, ++i_) \ + (d)[i_] = (v); \ + } while (0) +#define ZERO(d, n) SET(d, n, 0) +#define SWAP(a, b) \ + do { \ + a ^= b; \ + b ^= a; \ + a ^= b; \ + } while (0) +#define SORT(a, b) \ + do { \ + if ((a) > (b)) \ + SWAP((a), (b)); \ + } while (0) +#endif // ci2_macros.h diff --git a/include/platform/base/ci2_os.h b/include/platform/base/ci2_os.h new file mode 100644 index 0000000..6f91a58 --- /dev/null +++ b/include/platform/base/ci2_os.h @@ -0,0 +1,81 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_OS_H +#define CI2_OS_H + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + /* Entire windows platform */ + #define CI2_WIN_APIVER 0x0600 // Vista + #define NOMINMAX // Don't define min/max macros + #define _CRT_SECURE_NO_WARNINGS // No unsafe C warnings + #define _CRT_RAND_S // TODO + #define OEMRESOURCE // GUI must be before windows.h + #include // haha + #define CI2_WINDOWS + + #ifdef _WIN64 + /* Windows (64-bit only) */ + #define CI2_WINDOWS_64 + #else + /* Windows (32-bit only) */ + #define CI2_WINDOWS_32 + #endif + +#elif __APPLE__ + #define CI2_UNIX + #define CI2_APPLE + #include + #if TARGET_IPHONE_SIMULATOR + // iOS, tvOS, or watchOS Simulator + #define CI2_IOS + #elif TARGET_OS_MACCATALYST + // Mac's Catalyst (ports iOS API into Mac, like UIKit). + #define CI2_IOS + #elif TARGET_OS_IPHONE + // iOS, tvOS, or watchOS device + #define CI2_IOS + #elif TARGET_OS_MAC + // Other kinds of Apple platforms + #define CI2_OSX + #else + #error "Unknown Apple platform" + #endif + +#elif __ANDROID__ + #define CI2_UNIX + #define CI2_ANDROID + +#elif __linux__ + #define CI2_UNIX + +#elif __unix__ // TODO BSD Variants + #define CI2_UNIX + +#elif defined(_POSIX_VERSION) + #define CI2_POSIX + +#else + #error "Unknown and unsupported operating system." +#endif + +#endif // ci2_os.h diff --git a/include/platform/base/ci2_syntax.h b/include/platform/base/ci2_syntax.h new file mode 100644 index 0000000..b5cb33a --- /dev/null +++ b/include/platform/base/ci2_syntax.h @@ -0,0 +1,68 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_SYNTAX_H +#define CI2_SYNTAX_H + +/* Floating Points */ +typedef float ci2_f32; // IEEE 754 +typedef double ci2_f64; // IEE 754 + +/* Characters */ +typedef signed char ci2_char; // [−127, +127] +typedef unsigned char ci2_uchar; // [0, 255] +typedef unsigned char ci2_byte; // [0, 255] +typedef unsigned char* ci2_bytes; // Pointer + +/* Integers */ +typedef signed short ci2_short; // [−32,767, 32,767] +typedef unsigned short ci2_ushort; // [0, 65,535] +typedef signed int ci2_int; // [−32,767, 32,767] +typedef unsigned int ci2_uint; // [0, 65,535] +typedef signed long int ci2_long; // [−2,147,483,647, 2,147,483,647] +typedef unsigned long int ci2_ulong; // [0, 4,294,967,295] + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #include + #include + #include + // −9223372036854775807 +typedef unsigned long long int ci2_ull; // +9223372036854775807 range. +typedef signed long long int ci2_ll; //[0, 18446744073709551615] range. + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef ptrdiff_t size; +typedef size_t usize; + +#endif + +#endif // ci2_syntax.h diff --git a/include/platform/base/ci2_thread.h b/include/platform/base/ci2_thread.h new file mode 100644 index 0000000..29dcc18 --- /dev/null +++ b/include/platform/base/ci2_thread.h @@ -0,0 +1,37 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_THREAD_H +#define CI2_THREAD_H + +#if !defined(ci2_thread_local) + #if defined(_MSC_VER) && _MSC_VER >= 1300 + #define ci2_thread_local __declspec(thread) + #elif defined(__GNUC__) + #define ci2_thread_local __thread + #else + #define ci2_thread_local thread_local + #endif +#endif + +#endif // ci2_thread.h + diff --git a/include/platform/base/ci2_win_env.h b/include/platform/base/ci2_win_env.h new file mode 100644 index 0000000..e7589f0 --- /dev/null +++ b/include/platform/base/ci2_win_env.h @@ -0,0 +1,37 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_WIN_ENV_H +#define CI2_WIN_ENV_H + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + #if defined __MINGW32__ || defined __MINGW64__ + #define CI2_WIN_ENV + #define CI2_MINGW + #elif defined __CYGWIN__ + #define CI2_WIN_ENV + #define CI2_CYGWIN + #endif +#endif + +#endif // ci2_win_env.h + diff --git a/include/platform/ci2_platform.h b/include/platform/ci2_platform.h new file mode 100644 index 0000000..7544f2d --- /dev/null +++ b/include/platform/ci2_platform.h @@ -0,0 +1,94 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_PLATFORM_H +#define CI2_PLATFORM_H + +#include "./base/ci2_base.h" + +/* No name mangling for declarations---------------------------------------- */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* CI2_EXTERN: plain extern with C++ aware linkage token for macros if needed */ +#if defined(__cplusplus) + #define CI2_EXTERN extern "C" +#else + #define CI2_EXTERN extern +#endif + +/* CI2_API: platform/compiler-aware import/export/visibility */ +#if defined(_WIN32) || defined(__CYGWIN__) + #if defined(CI2_BUILD_DLL) + #define CI2_API CI2_EXTERN __declspec(dllexport) + #elif defined(CI2_USE_DLL) + #define CI2_API CI2_EXTERN __declspec(dllimport) + #else + #define CI2_API CI2_EXTERN + #endif +#else + /* Non-Windows: use visibility if supported */ + #if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_LLVM_COMPILER) + #if defined(CI2_BUILD_DLL) + #define CI2_API CI2_EXTERN __attribute__((visibility("default"))) + #else + #define CI2_API CI2_EXTERN + #endif + #else + #define CI2_API CI2_EXTERN + #endif +#endif + +/* CI2_DEF: internal vs external linkage */ +#ifndef CI2_DEF + #ifdef CI2_STATIC + #define CI2_DEF static + #else + #define CI2_DEF CI2_API + #endif +#endif + +#define CI2_SUCCESS 0 +#define CI2_FAILURE -1 + +#define CI2_TRUE 1 +#define CI2_FALSE 0 + +#define CI2_SIZE(x) (ptrdiff_t)sizeof(x) +#define CI2_COUNT(a) (sizeof(a) / sizeof(*(a))) +#define CI2_LEN(s) (countof(s) - 1) +#define CI2_KB(x) ((x) * (size_t)(1024)) +#define CI2_MB(x) (CI2_KB(x) * (size_t)(1024)) +#define CI2_GB(x) (CI2_MB(x) * (size_t)(1024)) +#define CI2_TB(x) (CI2_GB(x) * (size_t)(1024)) + + CI2_API ci2_thread_local int ci2_errno; + CI2_API int* ci2_errno_location(void); + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif // c++ + +#endif // ci2_platform.h diff --git a/include/platform/error/ci2_exception.h b/include/platform/error/ci2_exception.h new file mode 100644 index 0000000..f0adab4 --- /dev/null +++ b/include/platform/error/ci2_exception.h @@ -0,0 +1,188 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_EXCEPTION_H +#define CI2_EXCEPTION_H + +#include "../ci2_platform.h" +#include + +struct Exception +{ + const char* msg; +}; +typedef struct Exception Exception; + +struct Exception_Frame +{ + struct Exception_Frame* prev; + jmp_buf env; + const char* file; + const char* func; + int line; + const struct Exception* exception; +}; +typedef struct Exception_Frame Exception_Frame; + +enum +{ + EXCEPTION_ENTERED = 0, + EXCEPTION_RAISED, + EXCEPTION_HANDLED, + EXCEPTION_FINALIZED +}; + +CI2_API const struct Exception assertion_failed; +CI2_API void +ci2_try_assert(int cond); + +CI2_API void +ci2_raise_exception(const struct Exception* e, + const char* file, + const char* func, + int line); + +#if defined(CI2_WINDOWS) +CI2_DEF DWORD exception_stack; +CI2_DEF void +ci2_exception_init(void); +CI2_DEF void +ci2_exception_push(struct Exception_Frame* fp); +CI2_DEF void +ci2_exception_pop(void); + + #define CI2_RAISE(e) ci2_raise_exception(&(e), __FILE__, CI2_FUNC, __LINE__) + + #define CI2_RERAISE \ + ci2_raise_exception(exception_frame.exception, \ + exception_frame.file, \ + exception_frame.func, \ + exception_frame.line) + + #define CI2_RETURN \ + switch (ci2_exception_pop(), 0) \ + default: \ + return + + #define CI2_TRY \ + do { \ + volatile int exception_flag; \ + Exception_Frame exception_frame; \ + if (exception_stack == TLS_OUT_OF_INDEXES) \ + ci2_exception_init(); \ + ci2_exception_push(&exception_frame); \ + exception_flag = setjmp(exception_frame.env); \ + if (exception_flag == EXCEPTION_ENTERED) { + + #define CI2_EXCEPT(e) \ + if (exception_flag == EXCEPTION_ENTERED) \ + ci2_exception_pop(); \ + } \ + else if (exception_frame.exception == &(e)) \ + { \ + exception_flag = EXCEPTION_HANDLED; + + #define CI2_ELSE \ + if (exception_flag == EXCEPTION_ENTERED) \ + ci2_exception_pop(); \ + } \ + else \ + { \ + exception_flag = EXCEPTION_HANDLED; + + #define CI2_FINALLY \ + if (exception_flag == EXCEPTION_ENTERED) \ + ci2_exception_pop(); \ + } \ + { \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_flag = EXCEPTION_FINALIZED; + + #define CI2_END_TRY \ + if (exception_flag == EXCEPTION_ENTERED) \ + ci2_exception_pop(); \ + } \ + if (exception_flag == EXCEPTION_RAISED) \ + CI2_RERAISE; \ + } \ + while (0) + +#else // UNIX +CI2_DEF struct Exception_Frame* exception_stack; + + #define CI2_RAISE(e) ci2_raise_exception(&(e), __FILE__, CI2_FUNC, __LINE__) + + #define CI2_RERAISE \ + ci2_raise_exception(exception_frame.exception, \ + exception_frame.file, \ + exception_frame.func, \ + exception_frame.line) + + #define CI2_RETURN \ + switch (exception_stack = exception_stack->prev, 0) \ + default: \ + return + + #define CI2_TRY \ + do { \ + volatile int exception_flag; \ + Exception_Frame exception_frame; \ + exception_frame.prev = exception_stack; \ + exception_stack = &exception_frame; \ + exception_flag = setjmp(exception_frame.env); \ + if (exception_flag == EXCEPTION_ENTERED) { + + #define CI2_EXCEPT(e) \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_stack = exception_stack->prev; \ + } \ + else if (exception_frame.exception == &(e)) \ + { \ + exception_flag = EXCEPTION_HANDLED; + + #define CI2_ELSE \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_stack = exception_stack->prev; \ + } \ + else \ + { \ + exception_flag = EXCEPTION_HANDLED; + + #define CI2_FINALLY \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_stack = exception_stack->prev; \ + } \ + { \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_flag = EXCEPTION_FINALIZED; + + #define CI2_END_TRY \ + if (exception_flag == EXCEPTION_ENTERED) \ + exception_stack = exception_stack->prev; \ + } \ + if (exception_flag == EXCEPTION_RAISED) \ + CI2_RERAISE; \ + } \ + while (0) +#endif + +#endif // ci2_exception.h diff --git a/include/platform/mem/ci2_arena.h b/include/platform/mem/ci2_arena.h new file mode 100644 index 0000000..9579da1 --- /dev/null +++ b/include/platform/mem/ci2_arena.h @@ -0,0 +1,67 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_ARENA_H +#define CI2_ARENA_H + +#include "../ci2_platform.h" +#include "../error/ci2_exception.h" + +enum +{ + DEFAULT = 0, /* default: fail-handler (throws) + zero */ + SOFT_FAIL = 1u << 0, /* on failure return NULL */ + HARD_FAIL = 1u << 1, /* on failure call abort() */ + NO_ZERO = 1u << 2, /* do not zero memory on success */ +}; + +struct Arena +{ + char* beg; + char* end; +}; +typedef struct Arena Arena; + +/* Forward definition of an exception */ +CI2_API struct Exception arena_oom; + +/* Initialize an Arena from a buffer. */ +CI2_API void +arena_init(struct Arena* a, void* buf, ptrdiff_t len); + +/* Dynamically allocate an Arena */ +CI2_API struct Arena +arena_new(ptrdiff_t cap); + +/* Get the remaining capicity of an arena. */ +CI2_API ptrdiff_t +arena_size(struct Arena a); + +/* Make an allocation from an Arena. */ +CI2_API void* +arena_alloc(struct Arena* a, + int flags, + ptrdiff_t size, + ptrdiff_t align, + ptrdiff_t count); + +#endif // ci2_arena.h diff --git a/include/platform/mem/ci2_mem.h b/include/platform/mem/ci2_mem.h new file mode 100644 index 0000000..9c4d16e --- /dev/null +++ b/include/platform/mem/ci2_mem.h @@ -0,0 +1,69 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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 CI2_MEM_H +#define CI2_MEM_H + +#include "../error/ci2_exception.h" +#include + +/* Out of memory exception forward declaration. */ +CI2_API const struct Exception oom; + +/* Allocate an object and do not zero. May throw exception. */ +CI2_API void* +ci2_malloc(size_t nbytes, const char* file, const char* func, int line); + +/* Allocate an object and zero ci2ory. May throw exception. */ +CI2_API void* +ci2_calloc(size_t count, + size_t nbytes, + const char* file, + const char* func, + int line); + +/* Free and null a pointer */ +CI2_API void +ci2_free(void** ptr, const char* file, const char* func, int line); + +/* Resize a non-null pointer */ +CI2_API void* +ci2_resize(void* ptr, + size_t nbytes, + const char* file, + const char* func, + int line); + +#define CI2_MALLOC(nbytes) ci2_malloc((nbytes), __FILE__, CI2_FUNC, __LINE__) +#define CI2_CALLOC(count, nbytes) \ + ci2_calloc((count), (nbytes), __FILE__, CI2_FUNC, __LINE__) + +#define CI2_NEW(p) ((p) = CI2_MALLOC((size_t)sizeof *(p))) +#define CI2_NEW0(p) ((p) = CI2_CALLOC(1, (size_t)sizeof *(p))) + +#define CI2_FREE(ptr) \ + ((void)(ci2_free((ptr), __FILE__, CI2_FUNC, __LINE__), (ptr) = 0)) + +#define CI2_RESIZE(ptr, nbytes) \ + ((ptr) = ci2_resize((ptr), (nbytes), __FILE__, CI2_FUNC, __LINE__)) + +#endif // ci2_mem.h diff --git a/src/ci2_arena.c b/src/ci2_arena.c new file mode 100644 index 0000000..5f317bf --- /dev/null +++ b/src/ci2_arena.c @@ -0,0 +1,80 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#include "../include/platform/mem/ci2_arena.h" +#include +#include +struct Exception arena_oom = {"Arena is out of memory!"}; + +/* Initialize an Arena from a buffer. */ +void +arena_init(struct Arena* a, void* buf, ptrdiff_t len) +{ + CI2_ASSERT(buf != NULL); + CI2_ASSERT(len > 0); + a->beg = (char*)buf; + a->end = (char*)buf + len; +} + +/* Dynamically allocate an Arena */ +struct Arena +arena_new(ptrdiff_t cap) +{ + struct Arena a = { 0 }; + a.beg = malloc(cap); + a.end = a.beg ? a.beg + cap : 0; + return a; +} + +/* Get the remaining capicity of an arena. */ +ptrdiff_t +arena_size(struct Arena a) +{ + ptrdiff_t res = a.end - a.beg; + return res; +} + +/* Make an allocation from an Arena. */ +void* +arena_alloc(struct Arena* a, + int flags, + ptrdiff_t size, + ptrdiff_t align, + ptrdiff_t count) +{ + ptrdiff_t padding = -(uintptr_t)a->beg & (align - 1); + ptrdiff_t available = a->end - a->beg - padding; + if (available < 0 || count > available / size) { + if (flags & SOFT_FAIL) + return 0; + + if (flags & HARD_FAIL) + CI2_DEBUG_TRAP(); + + CI2_RAISE(arena_oom); + } + void* p = a->beg + padding; + ptrdiff_t total = padding + count * size; + a->beg += total; + return flags & NO_ZERO ? p : memset(p, 0, total); +} + diff --git a/src/ci2_mem.c b/src/ci2_mem.c new file mode 100644 index 0000000..ca6814e --- /dev/null +++ b/src/ci2_mem.c @@ -0,0 +1,94 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#include "../include/platform/mem/ci2_mem.h" + +#include + +const struct Exception oom = { "Out of Memory!" }; + +void* +ci2_malloc(size_t nbytes, const char* file, const char* func, int line) +{ + void* ptr; + ci2_try_assert(nbytes > 0); + ptr = malloc(nbytes); + if (ptr == NULL) { + if (file == NULL) + CI2_RAISE(oom); + else + ci2_raise_exception(&oom, file, func, line); + } + return ptr; +} + +void* +ci2_calloc(size_t count, + size_t nbytes, + const char* file, + const char* func, + int line) +{ + void* ptr; + ci2_try_assert(count > 0); + ci2_try_assert(nbytes > 0); + ptr = calloc(count, nbytes); + if (ptr == NULL) { + if (file == NULL) + CI2_RAISE(oom); + else + ci2_raise_exception(&oom, file, func, line); + } + return ptr; +} +void +ci2_free(void** ptr, const char* file, const char* func, int line) +{ + UNUSED(file); + UNUSED(func); + UNUSED(line); + if (ptr && *ptr) { + free(*ptr); + *ptr = NULL; + } +} + +void* +ci2_resize(void* ptr, + size_t nbytes, + const char* file, + const char* func, + int line) +{ + ci2_try_assert(ptr != NULL); + ci2_try_assert(nbytes > 0); + void* temp = realloc(ptr, nbytes); + if (temp == NULL) { + if (file == NULL) + CI2_RAISE(oom); + else + ci2_raise_exception(&oom, file, func, line); + } + + ptr = temp; + return ptr; +} diff --git a/src/linux_exception.c b/src/linux_exception.c new file mode 100644 index 0000000..d9c7a07 --- /dev/null +++ b/src/linux_exception.c @@ -0,0 +1,66 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#include "../include/platform/error/ci2_exception.h" + +struct Exception_Frame *exception_stack = NULL; + +const struct Exception assertion_failed = {"CI2 Assertion Failed"}; + +void ci2_try_assert(int cond) +{ + if(!cond){ + CI2_RAISE(assertion_failed); + } +} + +void ci2_raise_exception( + const struct Exception *e, + const char *file, + const char *func, + int line) +{ + + struct Exception_Frame *p = exception_stack; + ci2_try_assert(e != NULL); + if (p == NULL) { + fprintf(stderr, "Uncaught exception"); + if (e->msg) + fprintf(stderr, " %s", e->msg); + else + fprintf(stderr, " at 0x%p", (void*)e); + if (file && line > 0) + fprintf(stderr, " raised at %s:%d", file, line); + if (func != NULL) + fprintf(stderr,":%s",func); + fprintf(stderr, "\ninitiating debug trap...\n"); + fflush(stderr); + CI2_DEBUG_TRAP(); + } + p->exception = e; + p->file = file; + p->func = func; + p->line = line; + + exception_stack = exception_stack->prev; + longjmp(p->env, EXCEPTION_RAISED); +} diff --git a/src/win32_exception.c b/src/win32_exception.c new file mode 100644 index 0000000..aa82214 --- /dev/null +++ b/src/win32_exception.c @@ -0,0 +1,94 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#include "../include/platform/error/ci2_exception.h" + +DWORD exception_stack = -1; + +const struct Exception assertion_failed = {"CI2 Assertion Failed"}; +void ci2_try_assert(int cond) +{ + if(!cond){ + CI2_RAISE(assertion_failed); + } +} + +void ci2_raise_exception( + const struct Exception *e, + const char *file, + const char *func, + int line) +{ + struct Exception_Frame *p; + + if (exception_stack == TLS_OUT_OF_INDEXES) + ci2_exception_init(); + + p = TlsGetValue(exception_stack); + + ci2_try_assert(e != NULL); + if (p == NULL) { + fprintf(stderr, "Uncaught exception"); + if (e->msg) + fprintf(stderr, " %s", e->msg); + else + fprintf(stderr, " at 0x%p", (void *)e); + if (file && line > 0) + fprintf(stderr, " raised at %s:%d", file, line); + if(func != NULL) + fprintf(stderr,":%s",func); + fprintf(stderr, "\nInitiating debug trap/break...\n"); + fflush(stderr); + CI2_DEBUG_TRAP(); + } + p->exception = e; + p->file = file; + p->func = func; + p->line = line; + + ci2_exception_pop(); + + longjmp(p->env, EXCEPTION_RAISED); +} + +void ci2_exception_init(void) { + BOOL cond; + + exception_stack = TlsAlloc(); + ci2_try_assert(exception_stack != TLS_OUT_OF_INDEXES); + cond = TlsSetValue(exception_stack, NULL); + ci2_try_assert(cond == TRUE); +} + +void ci2_exception_push(struct Exception_Frame *fp) { + BOOL cond; + fp->prev = TlsGetValue(exception_stack); + cond = TlsSetValue(exception_stack, fp); + ci2_try_assert(cond == TRUE); +} + +void ci2_exception_pop(void) { + BOOL cond; + struct Exception_Frame *tos = TlsGetValue(exception_stack); + cond = TlsSetValue(exception_stack, tos->prev); + ci2_try_assert(cond == TRUE); +} diff --git a/tests/01_static_asserts.c b/tests/01_static_asserts.c new file mode 100644 index 0000000..06bae40 --- /dev/null +++ b/tests/01_static_asserts.c @@ -0,0 +1,60 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/ci2.h" + +#include +#include +#include /* INT_MAX, CHAR_BIT — C standard */ +#include /* FLT_MANT_DIG — C standard */ +int main(int argc, char *argv[]){ + (void) argc; + (void) argv; + + /* Fundamental type sizes that almost all C code silently assumes. */ + CI2_STATIC_ASSERT(CHAR_BIT == 8); + CI2_STATIC_ASSERT(sizeof(char) == 1); + CI2_STATIC_ASSERT(sizeof(short) == 2); + CI2_STATIC_ASSERT(sizeof(int) == 4); + CI2_STATIC_ASSERT(sizeof(float) == 4); + CI2_STATIC_ASSERT(sizeof(double) == 8); + + /* Pointer and size_t width — catches ILP64 oddities. */ + CI2_STATIC_ASSERT(sizeof(void *) == sizeof(size_t)); + + /* Fixed-width types from */ + CI2_STATIC_ASSERT(sizeof(uint8_t) == 1); + CI2_STATIC_ASSERT(sizeof(uint16_t) == 2); + CI2_STATIC_ASSERT(sizeof(uint32_t) == 4); + CI2_STATIC_ASSERT(sizeof(uint64_t) == 8); + + CI2_STATIC_ASSERT(sizeof(int8_t) == 1); + CI2_STATIC_ASSERT(sizeof(int16_t) == 2); + CI2_STATIC_ASSERT(sizeof(int32_t) == 4); + CI2_STATIC_ASSERT(sizeof(int64_t) == 8); + + /* IEEE-754 single precision: 24 significand bits. */ + CI2_STATIC_ASSERT(FLT_MANT_DIG == 24); + + return EXIT_SUCCESS; +} diff --git a/tests/02_ci2_os.c b/tests/02_ci2_os.c new file mode 100644 index 0000000..d5ec4fb --- /dev/null +++ b/tests/02_ci2_os.c @@ -0,0 +1,107 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/ci2.h" + +#include +#include +#include + +/* Platform-specific verification headers */ +#if defined(CI2_WINDOWS) + #include /* GetSystemInfo, SYSTEM_INFO */ +#elif defined(CI2_UNIX) + #include /* uname() — POSIX */ + #include /* sysconf, _SC_* constants — POSIX */ +#endif + +int +main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + +#if defined(CI2_WINDOWS) + printf(" Detected platform : Windows\n"); + + /* + * GetSystemInfo() is a Win32 API that fills SYSTEM_INFO. + * If _WIN32 were wrong this wouldn't compile or link. + */ + SYSTEM_INFO si; + GetSystemInfo(&si); + + printf(" Page size : %lu bytes\n", (unsigned long)si.dwPageSize); + printf(" Processor count : %lu\n", (unsigned long)si.dwNumberOfProcessors); + printf(" Processor arch : %u\n", (unsigned)si.wProcessorArchitecture); + + CI2_ASSERT(si.dwPageSize > 0); + CI2_ASSERT(si.dwNumberOfProcessors > 0); + +#elif defined(CI2_UNIX) + /* + * uname() fills a struct utsname with kernel name, release, machine, etc. + * This is a POSIX function — available on Linux, macOS, and all BSDs. + * It won't compile on Windows, proving our platform guard is correct. + */ + struct utsname uts; + int ret = uname(&uts); + CI2_ASSERT(ret == 0); + + printf(" Detected platform : Unix-like\n"); + printf(" OS / sysname : %s\n", uts.sysname); + printf(" Kernel release : %s\n", uts.release); + printf(" Machine arch : %s\n", uts.machine); + printf(" Node name : %s\n", uts.nodename); + + /* + * sysconf() is another POSIX function. + * _SC_PAGESIZE and _SC_NPROCESSORS_ONLN are available on Linux & macOS. + */ + long page_size = sysconf(_SC_PAGESIZE); + long n_cpus = sysconf(_SC_NPROCESSORS_ONLN); + + printf(" Page size : %ld bytes\n", page_size); + printf(" CPUs online : %ld\n", n_cpus); + + CI2_ASSERT(page_size > 0); + CI2_ASSERT(n_cpus > 0); + + /* Sanity: page size is always a power of two */ + CI2_ASSERT((page_size & (page_size - 1)) == 0); + + #if defined(CI2_LINUX) + printf(" Sub-platform : Linux\n"); + CI2_ASSERT(strlen(uts.sysname) > 0); + #elif defined(CI2_MACOS) + printf(" Sub-platform : macOS\n"); + CI2_ASSERT(strlen(uts.sysname) > 0); + #endif + +#else + printf(" [FAIL] No platform macro was defined!\n"); + return EXIT_FAILURE; +#endif + + return EXIT_SUCCESS; +} diff --git a/tests/03_ci2_compiler.c b/tests/03_ci2_compiler.c new file mode 100644 index 0000000..675a4fc --- /dev/null +++ b/tests/03_ci2_compiler.c @@ -0,0 +1,57 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/ci2.h" + +#include +#include +#include + +int main(int argc, char *argv[]){ + (void) argc; + (void) argv; + +#if defined(CI2_INTEL_ICX) + printf(" Detected compiler : INTEL-IXC\n"); + printf(" __INTEL_LLVM_COMPILER VER: %d\n", __INTEL_LLVM_COMPILER); + CI2_ASSERT(__INTEL_LLVM_COMPILER > 0); +#elif defined(CI2_GCC) + printf(" Detected compiler : GCC\n"); + printf(" GCC __VERSION__: %s\n", __VERSION__); + CI2_ASSERT(strlen(__VERSION__) > 0); +#elif defined(CI2_CLANG) + printf(" Detected compiler : CLANG\n"); + printf(" __clang_version__: %s\n", __clang_version__); + CI2_ASSERT(strlen(__clang_version__) > 0); +#elif defined(CI2_MSVC) + printf(" Detected compiler : MSVC\n"); + printf(" _MSC_VER : %d\n", _MSC_VER); + CI2_ASSERT(_MSC_VER > 0); + +#else + printf(" [FAIL] No compiler macro was defined!\n"); + return EXIT_FAILURE; +#endif + + return EXIT_SUCCESS; +} diff --git a/tests/04_ci2_assert.c b/tests/04_ci2_assert.c new file mode 100644 index 0000000..4e81afe --- /dev/null +++ b/tests/04_ci2_assert.c @@ -0,0 +1,109 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/ci2.h" + +#include +#include +#include /* bool, true, false — C99 */ +#include /* strcmp — C standard */ +static void test_assert_passing(void){ + /* Basic truthy values */ + CI2_ASSERT(1); + CI2_ASSERT(1 == 1); + + /* Pointer non-null */ + const char *str = "hello"; + CI2_ASSERT(str != NULL); + + /* Arithmetic */ + int x = 42; + CI2_ASSERT(x > 0); + CI2_ASSERT(x * 2 == 84); + + /* CI2_ASSERT_MSG variants */ + CI2_ASSERT_MSG(x == 42, "x must be 42"); + CI2_ASSERT_MSG(sizeof(int) == 4, "int must be 4 bytes on this platform"); + + /* Boolean */ + bool flag = true; + CI2_ASSERT(flag); +} + + +static void test_assert_failing(void){ + printf(" Triggering CI2_ASSERT(0) failure now...\n"); + fflush(stdout); + CI2_ASSERT(0); /* <-- should break/trap here */ + /* Should never reach here */ + printf(" [FAIL] Execution continued past a failing CI2_ASSERT!\n"); +} + +static void test_assert_msg_failing(void){ + printf("CI2_ASSERT_MSG — Deliberate Failure (triggering a debug break...)\n"); + fflush(stdout); + + CI2_ASSERT_MSG(0, "This failure is intentional — testing the message path"); + + printf(" [FAIL] Execution continued past a failing CI2_ASSERT_MSG!\n"); +} + +static void test_ndebug_status(void){ + printf("NDEBUG / Release Mode"); + +#ifdef NDEBUG + printf(" NDEBUG is DEFINED — asserts are compiled out.\n"); + CI2_ASSERT(0); /* harmless in release */ + printf(" Confirmed: CI2_ASSERT(0) was a no-op.\n"); +#else + printf(" NDEBUG is NOT defined — asserts are active (debug build).\n"); +#endif +} + +int main(int argc, char *argv[]){ + (void) argc; + (void) argv; +/* Determine whether the user wants to trigger a deliberate failure */ + bool run_fail = false; + bool run_fail_msg = false; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--fail") == 0) run_fail = true; + if (strcmp(argv[i], "--fail-msg") == 0) run_fail_msg = true; + } + + /* --- Run the safe tests --- */ + test_assert_passing(); + test_ndebug_status(); + + /* --- Optional deliberate-failure tests --- */ + if (run_fail) test_assert_failing(); + if (run_fail_msg) test_assert_msg_failing(); + + + if (!run_fail && !run_fail_msg) { + printf("Tip: run with --fail or --fail-msg to test the"); + printf(" debug-break path (attach a debugger first).\n"); + } + return EXIT_SUCCESS; +} diff --git a/tests/05_ci2_exception.c b/tests/05_ci2_exception.c new file mode 100644 index 0000000..6c27068 --- /dev/null +++ b/tests/05_ci2_exception.c @@ -0,0 +1,90 @@ +/* - | Copyright | ------------------------------------------------------------ + Copyright (c) 2026 Randy Jordan + +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. + + * --------------------------------------------------------------------------*/ +#define DEBUG +#include "../include/ci2.h" + +#include +#include +#include /* bool, true, false — C99 */ +#include /* strcmp — C standard */ +static void test_assert_passing(void){ + /* Basic truthy values */ + ci2_try_assert(1); + ci2_try_assert(1 == 1); + + /* Pointer non-null */ + const char *str = "hello"; + ci2_try_assert(str != NULL); + + /* Arithmetic */ + int x = 42; + ci2_try_assert(x > 0); + ci2_try_assert(x * 2 == 84); + + /* Boolean */ + bool flag = true; + ci2_try_assert(flag); +} + +static void test_assert_failing(void){ + printf(" Triggering ci2_try_assert(0) failure now...\n"); + fflush(stdout); + ci2_try_assert(0); /* <-- should break/trap here */ + /* Should never reach here */ + printf(" [FAIL] Execution continued past a failing ci2_try_assert!\n"); +} + +static void test_ndebug_status(void){ + printf("NDEBUG / Release Mode"); + +#ifdef NDEBUG + printf(" NDEBUG is DEFINED — asserts are compiled out.\n"); + ci2_try_assert(0); /* harmless in release */ + printf(" Confirmed: ci2_try_assert(0) was a no-op.\n"); +#else + printf(" NDEBUG is NOT defined — asserts are active (debug build).\n"); +#endif +} + +int main(int argc, char *argv[]){ + (void) argc; + (void) argv; +/* Determine whether the user wants to trigger a deliberate failure */ + bool run_fail = false; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--fail") == 0) run_fail = true; + } + + /* --- Run the safe tests --- */ + test_assert_passing(); + test_ndebug_status(); + + /* --- Optional deliberate-failure tests --- */ + if (run_fail) test_assert_failing(); + + if (!run_fail) { + printf("Tip: run with --fail to test the exceptions"); + } + return EXIT_SUCCESS; +}